mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			182 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| package Slic3r::Geometry;
 | |
| use strict;
 | |
| use warnings;
 | |
| 
 | |
| use Slic3r::Geometry::DouglasPeucker;
 | |
| use XXX;
 | |
| 
 | |
| use constant PI => 4 * atan2(1, 1);
 | |
| use constant A => 0;
 | |
| use constant B => 1;
 | |
| use constant X => 0;
 | |
| use constant Y => 1;
 | |
| use constant epsilon => 1E-6;
 | |
| use constant epsilon2 => epsilon**2;
 | |
| our $parallel_degrees_limit = abs(deg2rad(3));
 | |
| 
 | |
| sub slope {
 | |
|     my ($line) = @_;
 | |
|     return undef if abs($line->[B][X] - $line->[A][X]) < epsilon;  # line is vertical
 | |
|     return ($line->[B][Y] - $line->[A][Y]) / ($line->[B][X] - $line->[A][X]);
 | |
| }
 | |
| 
 | |
| sub line_atan {
 | |
|     my ($line) = @_;
 | |
|     return atan2($line->[B][Y] - $line->[A][Y], $line->[B][X] - $line->[A][X]);
 | |
| }
 | |
| 
 | |
| sub lines_parallel {
 | |
|     my ($line1, $line2) = @_;
 | |
|     
 | |
|     return abs(line_atan($line1) - line_atan($line2)) < $parallel_degrees_limit;
 | |
| }
 | |
| 
 | |
| # this subroutine checks whether a given point may belong to a given
 | |
| # segment given the hypothesis that it belongs to the line containing
 | |
| # the segment
 | |
| sub line_point_belongs_to_segment {
 | |
|     my ($point, $segment) = @_;
 | |
|     
 | |
|     #printf "   checking whether %f,%f may belong to segment %f,%f - %f,%f\n",
 | |
|     #    @$point, map @$_, @$segment;
 | |
|     
 | |
|     my @segment_extents = (
 | |
|         [ sort { $a <=> $b } map $_->[X], @$segment ],
 | |
|         [ sort { $a <=> $b } map $_->[Y], @$segment ],
 | |
|     );
 | |
|     
 | |
|     return 0 if $point->[X] < ($segment_extents[X][0] - epsilon) || $point->[X] > ($segment_extents[X][1] + epsilon);
 | |
|     return 0 if $point->[Y] < ($segment_extents[Y][0] - epsilon) || $point->[Y] > ($segment_extents[Y][1] + epsilon);
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| sub points_coincide {
 | |
|     my ($p1, $p2) = @_;
 | |
|     return 1 if abs($p2->[X] - $p1->[X]) < epsilon && abs($p2->[Y] - $p1->[Y]) < epsilon;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| sub distance_between_points {
 | |
|     my ($p1, $p2) = @_;
 | |
|     return sqrt(($p1->[X] - $p2->[X])**2 + ($p1->[Y] - $p2->[Y])**2);
 | |
| }
 | |
| 
 | |
| sub point_in_polygon {
 | |
|     my ($point, $polygon) = @_;
 | |
|     
 | |
|     my ($x, $y) = @$point;
 | |
|     my @xy = map @$_, @$polygon;
 | |
|     
 | |
|     # Derived from the comp.graphics.algorithms FAQ,
 | |
|     # courtesy of Wm. Randolph Franklin
 | |
|     my $n = @xy / 2;                        # Number of points in polygon
 | |
|     my @i = map { 2*$_ } 0..(@xy/2);        # The even indices of @xy
 | |
|     my @x = map { $xy[$_]     } @i;         # Even indices: x-coordinates
 | |
|     my @y = map { $xy[$_ + 1] } @i;         # Odd indices:  y-coordinates
 | |
|     
 | |
|     my ($i, $j);
 | |
|     my $side = 0;                           # 0 = outside; 1 = inside
 | |
|     for ($i = 0, $j = $n - 1; $i < $n; $j = $i++) {
 | |
|         if (
 | |
|             # If the y is between the (y-) borders...
 | |
|             ($y[$i] <= $y && $y < $y[$j]) || ($y[$j] <= $y && $y < $y[$i])
 | |
|             and
 | |
|             # ...the (x,y) to infinity line crosses the edge
 | |
|             # from the ith point to the jth point...
 | |
|             ($x < ($x[$j] - $x[$i]) * ($y - $y[$i]) / ($y[$j] - $y[$i]) + $x[$i])
 | |
|         ) {
 | |
|             $side = not $side;  # Jump the fence
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     # if point is not in polygon, let's check whether it belongs to the contour
 | |
|     if (!$side && 0) {
 | |
|         foreach my $line (polygon_lines($polygon)) {
 | |
|             # calculate the Y in line at X of the point
 | |
|             if ($line->[A][X] == $line->[B][X]) {
 | |
|                 return 1 if abs($x - $line->[A][X]) < epsilon;
 | |
|                 next;
 | |
|             }
 | |
|             my $y3 = $line->[A][Y] + ($line->[B][Y] - $line->[A][Y])
 | |
|                 * ($x - $line->[A][X]) / ($line->[B][X] - $line->[A][X]);
 | |
|             return 1 if abs($y3 - $y) < epsilon2;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     return $side;
 | |
| }
 | |
| 
 | |
| sub polygon_lines {
 | |
|     my ($polygon) = @_;
 | |
|     
 | |
|     my @lines = ();
 | |
|     my $last_point = $polygon->[-1];
 | |
|     foreach my $point (@$polygon) {
 | |
|         push @lines, [ $last_point, $point ];
 | |
|         $last_point = $point;
 | |
|     }
 | |
|     
 | |
|     return @lines;
 | |
| }
 | |
| 
 | |
| sub nearest_point {
 | |
|     my ($point, $points) = @_;
 | |
|     
 | |
|     my ($nearest_point, $distance);
 | |
|     foreach my $p (@$points) {
 | |
|         my $d = distance_between_points($point, $p);
 | |
|         if (!defined $distance || $d < $distance) {
 | |
|             $nearest_point = $p;
 | |
|             $distance = $d;
 | |
|             return $p if $distance < epsilon;
 | |
|         }
 | |
|     }
 | |
|     return $nearest_point;
 | |
| }
 | |
| 
 | |
| sub point_along_segment {
 | |
|     my ($p1, $p2, $distance) = @_;
 | |
|     
 | |
|     my $point = [ @$p1 ];
 | |
|     
 | |
|     my $line_length = sqrt( (($p2->[X] - $p1->[X])**2) + (($p2->[Y] - $p1->[Y])**2) );
 | |
|     for (X, Y) {
 | |
|         if ($p1->[$_] != $p2->[$_]) {
 | |
|             $point->[$_] = $p1->[$_] + ($p2->[$_] - $p1->[$_]) * $distance / $line_length;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     return $point;
 | |
| }
 | |
| 
 | |
| sub deg2rad {
 | |
|     my ($degrees) = @_;
 | |
|     return PI() * $degrees / 180;
 | |
| }
 | |
| 
 | |
| sub rotate_points {
 | |
|     my ($radians, $center, @points) = @_;
 | |
|     $center ||= [0,0];
 | |
|     return map {
 | |
|         [
 | |
|             $center->[X] + cos($radians) * ($_->[X] - $center->[X]) - sin($radians) * ($_->[Y] - $center->[Y]),
 | |
|             $center->[Y] + cos($radians) * ($_->[Y] - $center->[Y]) + sin($radians) * ($_->[X] - $center->[X]),
 | |
|         ]
 | |
|     } @points;
 | |
| }
 | |
| 
 | |
| sub move_points {
 | |
|     my ($shift, @points) = @_;
 | |
|     return map [ $shift->[X] + $_->[X], $shift->[Y] + $_->[Y] ], @points;
 | |
| }
 | |
| 
 | |
| # preserves order
 | |
| sub remove_coinciding_points {
 | |
|     my ($points) = @_;
 | |
|     
 | |
|     my %p = map { sprintf('%f,%f', @$_) => "$_" } @$points;
 | |
|     %p = reverse %p;
 | |
|     @$points = grep $p{"$_"}, @$points;
 | |
| }
 | |
| 
 | |
| 1;
 | 
