Polygon.pm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package Slic3r::Polygon;
  2. use strict;
  3. use warnings;
  4. # a polygon is a closed polyline.
  5. use parent 'Slic3r::Polyline';
  6. use Slic3r::Geometry qw(polygon_lines polygon_remove_parallel_continuous_edges
  7. polygon_remove_acute_vertices polygon_segment_having_point point_in_polygon
  8. X1 X2 Y1 Y2);
  9. use Slic3r::Geometry::Clipper qw(JT_MITER);
  10. sub lines {
  11. my $self = shift;
  12. return polygon_lines($self);
  13. }
  14. sub wkt {
  15. my $self = shift;
  16. return sprintf "POLYGON((%s))", join ',', map "$_->[0] $_->[1]", @$self;
  17. }
  18. sub is_counter_clockwise {
  19. my $self = shift;
  20. return Slic3r::Geometry::Clipper::is_counter_clockwise($self);
  21. }
  22. sub make_counter_clockwise {
  23. my $self = shift;
  24. if (!$self->is_counter_clockwise) {
  25. $self->reverse;
  26. return 1;
  27. }
  28. return 0;
  29. }
  30. sub make_clockwise {
  31. my $self = shift;
  32. if ($self->is_counter_clockwise) {
  33. $self->reverse;
  34. return 1;
  35. }
  36. return 0;
  37. }
  38. sub merge_continuous_lines {
  39. my $self = shift;
  40. polygon_remove_parallel_continuous_edges($self);
  41. bless $_, 'Slic3r::Point' for @$self;
  42. }
  43. sub remove_acute_vertices {
  44. my $self = shift;
  45. polygon_remove_acute_vertices($self);
  46. bless $_, 'Slic3r::Point' for @$self;
  47. }
  48. sub encloses_point {
  49. my $self = shift;
  50. my ($point) = @_;
  51. return Boost::Geometry::Utils::point_covered_by_polygon($point, [$self]);
  52. }
  53. sub area {
  54. my $self = shift;
  55. return Slic3r::Geometry::Clipper::area($self);
  56. }
  57. sub grow {
  58. my $self = shift;
  59. return $self->split_at_first_point->grow(@_);
  60. }
  61. sub simplify {
  62. my $self = shift;
  63. return Slic3r::Geometry::Clipper::simplify_polygon( $self->SUPER::simplify(@_) );
  64. }
  65. # this method subdivides the polygon segments to that no one of them
  66. # is longer than the length provided
  67. sub subdivide {
  68. my $self = shift;
  69. my ($max_length) = @_;
  70. for (my $i = 0; $i <= $#$self; $i++) {
  71. my $len = Slic3r::Geometry::line_length([ $self->[$i-1], $self->[$i] ]);
  72. my $num_points = int($len / $max_length) - 1;
  73. $num_points++ if $len % $max_length;
  74. # $num_points is the number of points to add between $i-1 and $i
  75. next if $num_points == -1;
  76. my $spacing = $len / ($num_points + 1);
  77. my @new_points = map Slic3r::Point->new($_),
  78. map Slic3r::Geometry::point_along_segment($self->[$i-1], $self->[$i], $spacing * $_),
  79. 1..$num_points;
  80. splice @$self, $i, 0, @new_points;
  81. $i += @new_points;
  82. }
  83. }
  84. # returns false if the polygon is too tight to be printed
  85. sub is_printable {
  86. my $self = shift;
  87. my ($width) = @_;
  88. # try to get an inwards offset
  89. # for a distance equal to half of the extrusion width;
  90. # if no offset is possible, then polyline is not printable.
  91. # we use flow_width here because this has to be consistent
  92. # with the thin wall detection in Layer->make_surfaces,
  93. # otherwise we could lose surfaces as that logic wouldn't
  94. # detect them and we would be discarding them.
  95. my $p = $self->clone;
  96. $p->make_counter_clockwise;
  97. return Slic3r::Geometry::Clipper::offset([$p], -$width / 2) ? 1 : 0;
  98. }
  99. sub is_valid {
  100. my $self = shift;
  101. return @$self >= 3;
  102. }
  103. sub split_at_index {
  104. my $self = shift;
  105. my ($index) = @_;
  106. return Slic3r::Polyline->new(
  107. @$self[$index .. $#$self],
  108. @$self[0 .. $index],
  109. );
  110. }
  111. sub split_at {
  112. my $self = shift;
  113. my ($point) = @_;
  114. # find index of point
  115. my $i = -1;
  116. for (my $n = 0; $n <= $#$self; $n++) {
  117. if (Slic3r::Geometry::same_point($point, $self->[$n])) {
  118. $i = $n;
  119. last;
  120. }
  121. }
  122. die "Point not found" if $i == -1;
  123. return $self->split_at_index($i);
  124. }
  125. sub split_at_first_point {
  126. my $self = shift;
  127. return $self->split_at_index(0);
  128. }
  129. 1;