From 060d2da7fe0eaef472da9adcc0aed1871026c86c Mon Sep 17 00:00:00 2001 From: Jesse Vincent <jesse@bestpractical.com> Date: Sun, 7 Apr 2013 18:01:15 -0400 Subject: [PATCH 1/5] Small optimization on an incredibly hot codepath. --- lib/Slic3r/Geometry.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index 0d2d9df4d..dc30b3472 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -116,8 +116,7 @@ sub distance_between_points { } sub comparable_distance_between_points { - my ($p1, $p2) = @_; - return (($p1->[X] - $p2->[X])**2) + (($p1->[Y] - $p2->[Y])**2); + return (($_[0]->[X] - $_[1]->[X])**2) + (($_[0]->[Y] - $_[1]->[Y])**2); } sub point_line_distance { From 3e8c5804fe03296de07054294bccb187f8c39be3 Mon Sep 17 00:00:00 2001 From: Jesse Vincent <jesse@bestpractical.com> Date: Sun, 7 Apr 2013 18:13:40 -0400 Subject: [PATCH 2/5] Inline comparable_distance_between_points It was called on an incredibly hot codepath from a single place. At 12313276 calls on my test .stl, the sub call overhead alone was a significant perf hit. --- lib/Slic3r/Geometry.pm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index dc30b3472..c6744a200 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -7,7 +7,7 @@ our @ISA = qw(Exporter); our @EXPORT_OK = qw( PI X Y Z A B X1 Y1 X2 Y2 MIN MAX epsilon slope line_atan lines_parallel line_point_belongs_to_segment points_coincide distance_between_points - comparable_distance_between_points chained_path_items chained_path_points + chained_path_items chained_path_points line_length midpoint point_in_polygon point_in_segment segment_in_segment point_is_on_left_of_segment polyline_lines polygon_lines nearest_point point_along_segment polygon_segment_having_point polygon_has_subsegment @@ -115,10 +115,6 @@ sub distance_between_points { return sqrt((($p1->[X] - $p2->[X])**2) + ($p1->[Y] - $p2->[Y])**2); } -sub comparable_distance_between_points { - return (($_[0]->[X] - $_[1]->[X])**2) + (($_[0]->[Y] - $_[1]->[Y])**2); -} - sub point_line_distance { my ($point, $line) = @_; return distance_between_points($point, $line->[A]) @@ -248,7 +244,7 @@ sub nearest_point_index { my ($nearest_point_index, $distance) = (); for my $i (0..$#$points) { - my $d = comparable_distance_between_points($point, $points->[$i]); + my $d = (($point->[X] - $points->[$i]->[X])**2) + (($point->[Y] - $points->[$i]->[Y])**2); if (!defined $distance || $d < $distance) { $nearest_point_index = $i; $distance = $d; From da0e67a891c76b1eccd090e01089c52394fdbbab Mon Sep 17 00:00:00 2001 From: Jesse Vincent <jesse@bestpractical.com> Date: Sun, 7 Apr 2013 18:28:08 -0400 Subject: [PATCH 3/5] Only look up $point's X and Y once, rather than once on every pass through the loop. (Those lookups are expensive) --- lib/Slic3r/Geometry.pm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index c6744a200..d21cff330 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -243,8 +243,12 @@ sub nearest_point_index { my ($point, $points) = @_; my ($nearest_point_index, $distance) = (); + + my $point_x = $point->[X]; + my $point_y = $point->[Y]; + for my $i (0..$#$points) { - my $d = (($point->[X] - $points->[$i]->[X])**2) + (($point->[Y] - $points->[$i]->[Y])**2); + my $d = (($point_x - $points->[$i]->[X])**2) + (($point_y - $points->[$i]->[Y])**2); if (!defined $distance || $d < $distance) { $nearest_point_index = $i; $distance = $d; From e8ca1e59a6bd9df0407c151e24f5d3273625a958 Mon Sep 17 00:00:00 2001 From: Jesse Vincent <jesse@bestpractical.com> Date: Sun, 7 Apr 2013 19:44:32 -0400 Subject: [PATCH 4/5] no functional change. only return from one place for clarity --- lib/Slic3r/Geometry.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index d21cff330..e1a591025 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -252,7 +252,7 @@ sub nearest_point_index { if (!defined $distance || $d < $distance) { $nearest_point_index = $i; $distance = $d; - return $i if $distance < epsilon; + last if $distance < epsilon; } } return $nearest_point_index; From 7ec63321413f10f68f389140c7488b2bb7d14fac Mon Sep 17 00:00:00 2001 From: Jesse Vincent <jesse@bestpractical.com> Date: Sun, 7 Apr 2013 19:53:15 -0400 Subject: [PATCH 5/5] split apart the math in nearest_point_index and short-circuit if we know the candidate is no good --- lib/Slic3r/Geometry.pm | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index e1a591025..9f0a631f4 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -248,13 +248,22 @@ sub nearest_point_index { my $point_y = $point->[Y]; for my $i (0..$#$points) { - my $d = (($point_x - $points->[$i]->[X])**2) + (($point_y - $points->[$i]->[Y])**2); - if (!defined $distance || $d < $distance) { - $nearest_point_index = $i; - $distance = $d; - last if $distance < epsilon; - } + my $d = ($point_x - $points->[$i]->[X])**2; + # If the X distance of the candidate is > than the total distance of the + # best previous candidate, we know we don't want it + next if (defined $distance && $d > $distance); + + # If the total distance of the candidate is > than the total distance of the + # best previous candidate, we know we don't want it + $d += ($point_y - $points->[$i]->[Y])**2; + next if (defined $distance && $d > $distance); + + $nearest_point_index = $i; + $distance = $d; + + last if $distance < epsilon; } + return $nearest_point_index; }