Skip to content

Instantly share code, notes, and snippets.

@oliverheilig
Last active March 19, 2020 15:17
Show Gist options
  • Save oliverheilig/7031590 to your computer and use it in GitHub Desktop.
Save oliverheilig/7031590 to your computer and use it in GitHub Desktop.
PointInsidePolygon
// This snippet shows how to check whether a point is
// contained in a polygon. Works for all polygons, even for
// OGC-invalid ones, corresponding to "fill mode" alternate.
// You can use this for geo-fencing or UI hit-testing.
using System;
using System.Collections.Generic;
using JSIL;
using JSIL.Meta;
public class Program
{
public static void Main()
{
Console.WriteLine("The red points are outside, " +
"the blue points are inside the polygon");
dynamic document = Builtins.Global["document"];
dynamic window = Builtins.Global["window"];
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);
var polygon = new List<Point> {
new Point(20,30), new Point(50, 50),
new Point(60, 45), new Point(100, 50), new Point(50, 100) };
DrawPolygon(ctx, polygon, "black", 2);
var pointsToCheck = new List<Point> {
new Point(60, 70), new Point(80, 60), new Point(60, 20), new Point(80, 80) };
foreach (var point in pointsToCheck)
{
var color = (PolyContainsPoint(polygon, point)) ? "blue" : "red";
DrawPoint(ctx, point, color);
}
}
public static void DrawPoint(dynamic ctx, Point p, string color)
{
ctx.fillStyle = color;
ctx.fillRect(p.X - 2, p.Y - 2, 4, 4);
}
public static void DrawPolygon(dynamic ctx, IList<Point> lineString, string color, double width)
{
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(lineString[0].X, lineString[0].Y);
for (int i = 1; i < lineString.Count; i++)
ctx.lineTo(lineString[i].X, lineString[i].Y);
ctx.lineTo(lineString[0].X, lineString[0].Y); // close polygon
ctx.stroke();
}
public static bool PolyContainsPoint(List<Point> points, Point p)
{
bool inside = false;
// An imaginary closing segment is implied,
// so begin testing with that.
Point v1 = points[points.Count - 1];
foreach (Point v0 in points)
{
double d1 = (p.Y - v0.Y) * (v1.X - v0.X);
double d2 = (p.X - v0.X) * (v1.Y - v0.Y);
if (p.Y < v1.Y)
{
// V1 below ray
if (v0.Y <= p.Y)
{
// V0 on or above ray
// Perform intersection test
if (d1 > d2)
{
inside = !inside; // Toggle state
}
}
}
else if (p.Y < v0.Y)
{
// V1 is on or above ray, V0 is below ray
// Perform intersection test
if (d1 < d2)
{
inside = !inside; // Toggle state
}
}
v1 = v0; //Store previous endpoint as next startpoint
}
return inside;
}
}
public class Point
{
public Point(double x, double y)
{
this.X = x;
this.Y = y;
}
public double X { get; set; }
public double Y { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment