/// <summary> /// The y-coordinate of the intersection of the vertically projected line with the provided segment. /// </summary> /// <param name="xPtN">The x-coordinate of pt n, where the projection starts.</param> /// <param name="ptI">Vertex i of the segment.</param> /// <param name="ptJ">Vertex j of the segment.</param> /// <returns>System.Double.</returns> /// <exception cref="System.ArgumentException">Segment is vertical, so intersection point is either infinity or NAN.</exception> public static double IntersectionPointY( double xPtN, Point ptI, Point ptJ) { if (Segment.IsVertical(ptI, ptJ)) { throw new ArgumentException("Segment is vertical, so intersection point is either infinity or NAN."); } return((xPtN - ptI.X) * ((ptJ.Y - ptI.Y) / (ptJ.X - ptI.X)) + ptI.Y); }
/// <summary> /// The numbers of shape boundary intersections a horizontal line makes when projecting to the right from the provided point. /// If the point is on a vertex or segment, the function returns either 0 or 1. /// </summary> /// <param name="coordinate">The coordinate.</param> /// <param name="shapeBoundary">The shape boundary composed of n points.</param> /// <param name="includePointOnSegment">if set to <c>true</c> [include point on segment].</param> /// <param name="includePointOnVertex">if set to <c>true</c> [include point on vertex].</param> /// <param name="tolerance">The tolerance.</param> /// <returns>System.Int32.</returns> /// <exception cref="System.ArgumentException">Shape boundary describes a shape. Closure to the shape boundary is needed.</exception> public static int NumberOfIntersections( Point coordinate, Point[] shapeBoundary, bool includePointOnSegment = true, bool includePointOnVertex = true, double tolerance = GeometryLibrary.ZeroTolerance) { if (shapeBoundary[0] != shapeBoundary[shapeBoundary.Length - 1]) { throw new ArgumentException("Shape boundary describes a shape. Closure to the shape boundary is needed."); } // 1. Check horizontal line projection from a pt. n to the right // 2. Count # of intersections of the line with shape edges // Note shape coordinates from XML already repeat starting node as an ending node. // No need to handle wrap-around below. int numberOfIntersections = 0; for (int i = 0; i < shapeBoundary.Length - 1; i++) { Point vertexI = shapeBoundary[i]; if (PointIntersection.PointsOverlap(coordinate, vertexI)) { return(includePointOnVertex ? 1 : 0); } Point vertexJ = shapeBoundary[i + 1]; if (!PointIsLeftOfSegmentEnd(coordinate.X, vertexI, vertexJ)) { // Pt is to the right of the segment. continue; } bool pointIsWithinSegmentHeight = PointIsWithinSegmentHeight( coordinate.Y, vertexI, vertexJ, includeEnds: includePointOnSegment); if (!pointIsWithinSegmentHeight) { // Point is out of vertical bounds of the segment extents. continue; } bool pointIsWithinSegmentWidth = ProjectionVertical.PointIsWithinSegmentWidth( coordinate.X, vertexI, vertexJ, includeEnds: includePointOnSegment); if (Segment.IsVertical(vertexI, vertexJ)) { if (pointIsWithinSegmentWidth) { // Point is on vertical segment return(includePointOnSegment ? 1 : 0); } // Point hits vertical segment numberOfIntersections++; continue; } if (Segment.IsHorizontal(vertexI, vertexJ)) { // Segment would be parallel to line projection. // Point is collinear since it is within segment height if (pointIsWithinSegmentWidth) { // Point is on horizontal segment return(includePointOnSegment ? 1 : 0); } continue; } double xIntersection = IntersectionPointX(coordinate.Y, vertexI, vertexJ); if (PointIsLeftOfSegmentIntersection(coordinate.X, xIntersection, vertexI, vertexJ)) { numberOfIntersections++; } else if (NMath.Abs(coordinate.X - xIntersection) < tolerance) { // Point is on sloped segment return(includePointOnSegment ? 1 : 0); } } return(numberOfIntersections); }