Polyline.pm 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package Slic3r::Polyline;
  2. use Moo;
  3. use Math::Clipper qw();
  4. use Sub::Quote;
  5. # arrayref of ordered points
  6. has 'points' => (
  7. is => 'rw',
  8. required => 1,
  9. default => sub { [] },
  10. isa => quote_sub q{ use Carp; confess "invalid points" if grep ref $_ ne 'Slic3r::Point', @{$_[0]} },
  11. );
  12. sub id {
  13. my $self = shift;
  14. return join ' - ', sort map $_->id, @{$self->points};
  15. }
  16. sub cast {
  17. my $class = shift;
  18. my ($points) = @_;
  19. $points = [ map { ref $_ eq 'ARRAY' ? Slic3r::Point->cast($_) : $_ } @$points ];
  20. return $class->new(points => $points);
  21. }
  22. sub lines {
  23. my $self = shift;
  24. my @lines = ();
  25. my $previous_point;
  26. foreach my $point (@{ $self->points }) {
  27. if ($previous_point) {
  28. push @lines, Slic3r::Line->new(points => [ $previous_point, $point ]);
  29. }
  30. $previous_point = $point;
  31. }
  32. return @lines;
  33. }
  34. sub p {
  35. my $self = shift;
  36. return [ map $_->p, @{$self->points} ];
  37. }
  38. sub merge_continuous_lines {
  39. my $self = shift;
  40. my $finished = 0;
  41. CYCLE: while (!$finished) {
  42. my $last_line;
  43. foreach my $line ($self->lines) {
  44. if (defined $last_line && $line->parallel_to($last_line)) {
  45. # $line and $last_line are parallel and continuous,
  46. # so we can remove their common point from our polyline
  47. # find common point
  48. my ($common_point) = grep $_ eq $line->a || $_ eq $line->b, @{$last_line->points};
  49. # remove point from polyline
  50. @{$self->points} = grep $_ ne $common_point, @{$self->points};
  51. $finished = 0;
  52. }
  53. $last_line = $line;
  54. }
  55. $finished = 1;
  56. }
  57. }
  58. sub cleanup {
  59. my $self = shift;
  60. my $tolerance = shift || (1 / $Slic3r::resolution);
  61. @{$self->points} = map Slic3r::Point->cast($_),
  62. Slic3r::Geometry::Douglas_Peucker($self->p, $tolerance);
  63. }
  64. sub reverse_points {
  65. my $self = shift;
  66. @{$self->points} = reverse @{$self->points};
  67. }
  68. sub is_counter_clockwise {
  69. my $self = shift;
  70. return Math::Clipper::is_counter_clockwise($self->p);
  71. }
  72. sub make_counter_clockwise {
  73. my $self = shift;
  74. $self->reverse_points if !$self->is_counter_clockwise;
  75. }
  76. sub make_clockwise {
  77. my $self = shift;
  78. $self->reverse_points if $self->is_counter_clockwise;
  79. }
  80. sub nearest_point_to {
  81. my $self = shift;
  82. my ($point) = @_;
  83. # get point as arrayref
  84. $point = ref $point eq 'ARRAY' ? $point : $point->p;
  85. $point = Slic3r::Geometry::nearest_point($point, $self->p);
  86. return Slic3r::Point->cast($point);
  87. }
  88. 1;