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;
 }