Polygon.pm 4.1 KB

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