Subject: | [PATCH] Add distance method |
Hi Mark,
would you mind taking this patch to add a distance method?
I hope you like it. Let me know if I can improve on it.
Thanks && Kind Regards,
Subject: | 0001-Add-distance-method.patch |
From 7b7dd285e7aed74848c9fae1d1e82ef3daf71a53 Mon Sep 17 00:00:00 2001
From: Andreas Koenig <andk@cpan.org>
Date: Wed, 28 Dec 2016 06:12:51 +0100
Subject: [PATCH] Add distance method
---
MANIFEST | 1 +
lib/Math/Polygon.pm | 5 +++++
lib/Math/Polygon.pod | 6 ++++++
lib/Math/Polygon/Calc.pm | 45 +++++++++++++++++++++++++++++++++++++++++++++
t/15distance.t | 29 +++++++++++++++++++++++++++++
5 files changed, 86 insertions(+)
create mode 100644 t/15distance.t
diff --git a/MANIFEST b/MANIFEST
index 26b8f88..8e92ced 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -20,6 +20,7 @@ t/11size.t
t/12beauty.t
t/13rot.t
t/14inside.t
+t/15distance.t
t/30cross.t
t/31clipl.t
t/32clipf1.t
diff --git a/lib/Math/Polygon.pm b/lib/Math/Polygon.pm
index 5ed9152..230a984 100644
--- a/lib/Math/Polygon.pm
+++ b/lib/Math/Polygon.pm
@@ -153,6 +153,11 @@ sub contains($)
polygon_contains_point($point, $self->points);
}
+sub distance($)
+{ my ($self, $point) = @_;
+ polygon_distance($point, $self->points);
+}
+
sub isClosed() { polygon_is_closed(shift->points) }
diff --git a/lib/Math/Polygon.pod b/lib/Math/Polygon.pod
index 235a1be..1c05134 100644
--- a/lib/Math/Polygon.pod
+++ b/lib/Math/Polygon.pod
@@ -192,6 +192,12 @@ example:
$poly->counterClockwise
+=item $obj-E<gt>B<distance>($point)
+
+Returns a numeric value indicating the distance of the point to the
+closest point on the border of the polygon, zero if the point is on an
+edge.
+
=item $obj-E<gt>B<equal>( <$other | ARRAY,[$tolerance]> | $points )
Compare two polygons, on the level of points. When the polygons are
diff --git a/lib/Math/Polygon/Calc.pm b/lib/Math/Polygon/Calc.pm
index 2e62d4c..a05d8e1 100644
--- a/lib/Math/Polygon/Calc.pm
+++ b/lib/Math/Polygon/Calc.pm
@@ -20,6 +20,7 @@ our @EXPORT = qw/
polygon_is_closed
polygon_clockwise
polygon_counter_clockwise
+ polygon_distance
polygon_perimeter
polygon_same
polygon_start_minxy
@@ -332,4 +333,48 @@ sub polygon_is_closed(@)
$first->[0]==$last->[0] && $first->[1]==$last->[1];
}
+sub polygon_distance($@)
+{ my $p = shift;
+
+ my ($x, $y) = @$p;
+ # http://stackoverflow.com/questions/10983872/distance-from-a-point-to-a-polygon#10984080 with correction from
+ # http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
+ my $minDist;
+ for my $i (0..$#_-1) { # closed!
+ my $j = $i+1;
+ my($x1,$y1,$x2,$y2) = map { $_->[0], $_->[1] } @_[$i,$j];
+ my $A = $x - $x1;
+ my $B = $y - $y1;
+ my $C = $x2 - $x1;
+ my $D = $y2 - $y1;
+ my $dot = $A * $C + $B * $D;
+ my $len_sq = $C * $C + $D * $D;
+ my $param = -1;
+ if ($len_sq != 0) { #in case of 0 length line
+ $param = $dot / $len_sq;
+ }
+ my($xx, $yy);
+
+ if ($param < 0) {
+ $xx = $x1;
+ $yy = $y1;
+ }
+ elsif ($param > 1) {
+ $xx = $x2;
+ $yy = $y2;
+ }
+ else {
+ $xx = $x1 + $param * $C;
+ $yy = $y1 + $param * $D;
+ }
+
+ my $dx = $x - $xx;
+ my $dy = $y - $yy;
+ my $dist = sqrt($dx * $dx + $dy * $dy);
+ $minDist = $dist unless defined $minDist;
+ $minDist = $dist if $dist < $minDist;
+ }
+ return $minDist;
+}
+
1;
diff --git a/t/15distance.t b/t/15distance.t
new file mode 100644
index 0000000..50b16e0
--- /dev/null
+++ b/t/15distance.t
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 13;
+
+use lib '../lib';
+use Math::Polygon::Calc;
+
+my @p = ([1,1], [3,1], [3,3], [1,3], [1,1]);
+
+is( polygon_distance([1,1], @p), 0);
+is( polygon_distance([1,0], @p), 1);
+is( polygon_distance([0,1], @p), 1);
+is( polygon_distance([2,0], @p), 1);
+is( polygon_distance([2,2], @p), 1);
+is( polygon_distance([0,2], @p), 1);
+is( polygon_distance([3,0], @p), 1);
+is( polygon_distance([0,3], @p), 1);
+is( polygon_distance([0,0], @p), polygon_distance([4,4], @p));
+is( polygon_distance([4,0], @p), polygon_distance([0,4], @p));
+
+@p = ([6,2],[7,1],[8,2],[7,3],[6,2]);
+
+is( polygon_distance([5,1], @p), polygon_distance([5,3], @p));
+is( polygon_distance([6,0], @p), polygon_distance([6,4], @p));
+is( polygon_distance([7,2], @p), polygon_distance([8,3], @p));
+
--
2.9.3