/// <summary> /// Determines if the point is to the left of the horizontally projected segment intersection. /// </summary> /// <param name="xPtN">The x-coordinate of pt n.</param> /// <param name="xIntersection">The x-coordinate of the intersection of the projected line.</param> /// <param name="vertexI">The vertex i.</param> /// <param name="vertexJ">The vertex j.</param> /// <param name="includeEnds">if set to <c>true</c> [include ends].</param> /// <returns><c>true</c> if the point is to the left of the horizontally projected segment intersection, <c>false</c> otherwise.</returns> public static bool PointIsLeftOfSegmentIntersection( double xPtN, double xIntersection, Point vertexI, Point vertexJ, bool includeEnds = true) { return(xPtN < xIntersection && ProjectionVertical.PointIsWithinSegmentWidth(xIntersection, vertexI, vertexJ, includeEnds: includeEnds)); }
/// <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); }