Thanks @Petras_Vestartas!
In the meantime I have implemented the winding number approach from this paper as suggested by @laurent_delrieu. It is almost 10 times faster than the Curve.Contains
method.
public static bool PointInPolygon(Point3d p, Point3d[] polylineArray) { int n = polylineArray.Length - 1; int windingNumber = 0; // the winding number counter // loop through all edges of the polygon for (int i = 0; i < n; i++) { // edge from V[i] to V[i+1] if (polylineArray[i].Y <= p.Y) { // start y <= P.y if (polylineArray[i + 1].Y > p.Y) // an upward crossing if (IsLeft(polylineArray[i], polylineArray[i + 1], p) > 0) // P left of edge ++windingNumber; // have a valid up intersect } else { // start y > P.y (no test needed) if (polylineArray[i + 1].Y <= p.Y) // a downward crossing if (IsLeft(polylineArray[i], polylineArray[i + 1], p) < 0) // P right of edge --windingNumber; // have a valid down intersect } } if (windingNumber != 0) return true; else return false; } private static int IsLeft(Point3d p0, Point3d p1, Point3d p2) { double calc = ((p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y)); if (calc > 0) return 1; else if (calc < 0) return -1; else return 0; }