Skip to content

Instantly share code, notes, and snippets.

@royratcliffe
Created April 2, 2018 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save royratcliffe/29fb6d65580419cbd330536bd43f86fa to your computer and use it in GitHub Desktop.
Save royratcliffe/29fb6d65580419cbd330536bd43f86fa to your computer and use it in GitHub Desktop.
Point in Polygon
% Tail-recurse through the list until the last one. Replace the last with an
% empty list.
without_last([_], []).
without_last([Head|Tail], [Head|List]) :- without_last(Tail, List).
% Appends the tail of a list to its head. The old head becomes the new last
% element of the list. The new head is the previous second element.
rotate_left([Head|Tail], List) :- append(Tail, [Head], List).
rotate_right(List, [Head|Tail]) :-
last(List, Head),
without_last(List, Tail),
!.
zip([], [], []).
zip([H1|T1], [H2|T2], [[H1, H2]|T]) :- zip(T1, T2, T).
% Succeeds if the given point [X, Y] lies inside the polygon described by the
% given list of point pairs (XYs); fails if the point lies outside.
%
% First pairs up each point with the preceeding point by rotating the list
% right and zipping up the point-pairs. Then tests each point pair against the
% given [X, Y]. An odd number of successful tests means inside; even means outside.
%
% https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
point_in_polygon(XYs, [X, Y]) :-
rotate_right(XYs, Rotated),
zip(XYs, Rotated, Zipped),
convlist({X, Y}/[[[X1, Y1], [X2, Y2]], Test]
>>((Y1 > Y, Y2 =< Y; Y1 =< Y, Y2 > Y),
Test is (X2 - X1) * (Y - Y1) / (Y2 - Y1) + X1,
X < Test),
Zipped,
Tests),
length(Tests, NumberOfTests),
0 =\= NumberOfTests mod 2.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment