Skip to content

Instantly share code, notes, and snippets.

@oliverheilig
Last active December 25, 2015 19:49
Show Gist options
  • Save oliverheilig/7030577 to your computer and use it in GitHub Desktop.
Save oliverheilig/7030577 to your computer and use it in GitHub Desktop.
PointNearLinestring
// This snippet shows how to check whether a point is near a
// polyline. For a given polyline you can check if the
// distance of a point to the line string is not greater
// a certain value.
// 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 are more than 10 pixels away from the lines string.");
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 linestring = new List<Point> {
new Point(20,30), new Point(50, 50),
new Point(60, 45), new Point(100, 50), new Point(50, 100), new Point(20,30) };
DrawLinestring(ctx, linestring, "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 = PointInRangeOfLinestring(linestring, point, 10)? "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 DrawLinestring(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.stroke();
}
public static bool PointInRangeOfLinestring(List<Point> lineString, Point p, double range)
{
double range2 = range * range; // square of range
for (int i = 0; i < lineString.Count - 1; i++)
{
Point c = ClosestPointOnSegment(lineString[i], lineString[i + 1], p);
Point d = new Point(c.X - p.X, c.Y - p.Y); // distance vector
if (d.X * d.X + d.Y * d.Y <= range2)
return true;
}
return false;
}
public static Point ClosestPointOnSegment(Point a, Point b, Point p)
{
var d = new Point(b.X - a.X, b.Y - a.Y);
double number = (p.X - a.X) * d.X + (p.Y - a.Y) * d.Y;
if (number <= 0.0)
return a;
double denom = d.X * d.X + d.Y * d.Y;
if (number >= denom)
return b;
return new Point(a.X + (number / denom) * d.X, a.Y + (number / denom) * d.Y);
}
}
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