Graph-Maker-Other
view release on metacpan or search on metacpan
devel/lib/MyPlanar.pm view on Meta::CPAN
# Return true if segment $p1,$p2 contains point $p3.
sub segment_contains_point {
my ($points) = @_;
my ($p1,$p2, $p3) = @$points;
return abs(Math::Geometry::Planar::DistanceToSegment([$p1,$p2,$p3])) < $delta;
}
sub segments_are_colinear {
my ($points) = @_;
my ($p1,$p2, $p3,$p4) = @$points;
return Math::Geometry::Planar::Colinear([$p1,$p2,$p3])
&& Math::Geometry::Planar::Colinear([$p1,$p2,$p4]);
}
# segment_intersection_segment([$p1,$p2, $p3,$p4])
# Return a segment [$ps,$pe] which is the intersection of segments $p1,$p2
# and $p3,$p4. If they do not intersect then return 0;
# If they are colinear and overlapping then return the portion where they
# overlap.
# If they touch or cross at a single point then return [$p,$p] which is that
# point (like SegmentIntersection() does).
#
sub segment_intersection_segment {
my ($points) = @_;
my ($p1,$p2, $p3,$p4) = @$points;
### segment_intersection_segment(): $points
# p1------p2 p1---p2 p1------p2
# p3------p4 p3-----------p4 p3------p4
#
# p1------p2 p3---p4 p1------p2
# p4------p3 p1-----------p2 p4------p3
#
my $c1 = segment_contains_point([$p3,$p4, $p1]);
my $c2 = segment_contains_point([$p3,$p4, $p2]);
### $c1
### $c2
if ($c1 && $c2) {
### p1,p2 entirely within p3,p4 ...
return [$p1,$p2];
}
my $c3 = segment_contains_point([$p1,$p2, $p3]);
my $c4 = segment_contains_point([$p1,$p2, $p4]);
### $c3
### $c4
if ($c3 && $c4) {
### p3,p4 entirely within p1,p2 ...
return [$p3,$p4];
}
if (($c1||$c2) && ($c3||$c4)) {
### partial overlap ...
return [$c1 ? $p1 : $p2,
$c3 ? $p3 : $p4];
}
foreach my $a ($p1,$p2) {
foreach my $b ($p3,$p4) {
if ($a->[0]==$b->[0] && $a->[1]==$b->[1]) {
### endpoint in common ...
return [$a,$a];
}
}
}
### try point intersection ...
if (my $p = Math::Geometry::Planar::SegmentIntersection($points)) {
return [$p,$p];
}
return 0;
}
sub distance_segment_to_segment {
my ($points) = @_;
my ($p1,$p2, $p3,$p4) = @$points;
# DistanceToSegment() is +ve on the left and -ve on the right.
# Here want absolute value.
#
# Shortest distance is always attained going to the endpoint of one
# segment, since straight lines.
my $ret;
foreach (0,1) {
foreach my $i (2,3) {
my $d = abs(DistanceToSegment([$points->[0],$points->[1],$points->[$i]]));
$ret = min($ret // $d, $d)
or return $ret; # if 0
}
$points = [reverse @$points];
}
return $ret;
}
# $points1 and $points2 are arrayrefs of points [ [x,y], [x,y], ...]
# which are simple polygons.
# Return the shortest distance between a point on the boundary of $points1
# and a point on the boundary of $points2.
# If their boundaries touch or cross then the return is 0.
# One polygon can be within the other. The distance is still between their
# boundaries.
sub poly_distance_boundary_to_boundary {
my ($points1, $points2) = @_;
my $ret;
OUTER: foreach my $i (0 .. $#$points1) {
foreach my $j (0 .. $#$points2) {
my $d = distance_segment_to_segment([$points1->[$i-1],$points1->[$i],
$points2->[$j-1],$points2->[$j]]);
if (defined $ret) {
$ret = min($ret, $d);
} else {
$ret = $d;
}
$ret or last OUTER;
}
}
return $ret;
}
sub poly_union {
my ($points1, $points2) = @_;
my $gpc = Math::Geometry::Planar::GpcClip('UNION',
points_to_gpc($points1),
points_to_gpc($points2));
if (defined $gpc) {
return gpc_to_points_list($gpc);
}
return;
}
sub poly_intersection {
my ($points1, $points2) = @_;
my $gpc = Math::Geometry::Planar::GpcClip('INTERSECTION',
points_to_gpc($points1),
points_to_gpc($points2));
if (defined $gpc) {
return gpc_to_points_list($gpc);
}
return undef;
( run in 2.134 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )