private void Initialize(double distance) { m_dDistance = distance; maxCurveSegmentError = distance * (1 - Math.Cos(filletAngleQuantum / 2.0)); ptList = new CoordinateCollection(); }
protected void AddPoints(Edge edge, bool isForward, bool isFirstEdge) { ICoordinateList edgePts = edge.Coordinates; if (isForward) { int startIndex = 1; if (isFirstEdge) { startIndex = 0; } for (int i = startIndex; i < edgePts.Count; i++) { pts.Add(edgePts[i]); } } else { // is backward int startIndex = edgePts.Count - 2; if (isFirstEdge) { startIndex = edgePts.Count - 1; } for (int i = startIndex; i >= 0; i--) { pts.Add(edgePts[i]); } } }
/// <summary> /// Returns true if the two arrays are identical, both null, or pointwise /// equal (as compared using <see cref="Coordinate.Equals"/>). /// </summary> /// <seealso cref="Coordinate.Equals">Coordinate.Equals</seealso> private static bool Equals(ICoordinateList coord1, ICoordinateList coord2) { if (coord1 == coord2) { return(true); } if (coord1 == null || coord2 == null) { return(false); } if (coord1.Count != coord2.Count) { return(false); } for (int i = 0; i < coord1.Count; i++) { if (!coord1[i].Equals(coord2[i])) { return(false); } } return(true); }
private int depthDelta; // the change in area depth from the R to L side of this edge #endregion #region Constructors and Destructor public Edge(ICoordinateList pts, Label label) { eiList = new EdgeIntersectionList(this); depth = new Depth(); this.pts = pts; this.m_objLabel = label; }
private void ComputeLineBufferCurve(ICoordinateList inputPts) { int n = inputPts.Count - 1; // compute points for left side of line InitSideSegments(inputPts[0], inputPts[1], Position.Left); for (int i = 2; i <= n; i++) { AddNextSegment(inputPts[i], true); } AddLastSegment(); // Add line cap for end of line AddLineEndCap(inputPts[n - 1], inputPts[n]); // compute points for right side of line InitSideSegments(inputPts[n], inputPts[n - 1], Position.Left); for (int i = n - 2; i >= 0; i--) { AddNextSegment(inputPts[i], true); } AddLastSegment(); // Add line cap for start of line AddLineEndCap(inputPts[1], inputPts[0]); ClosePoints(); }
private void ComputeMinDistance(LineString line, Point pt, DistanceLocation[] locGeom) { if (line.Bounds.Distance(pt.Bounds) > minDistance) { return; } ICoordinateList coord0 = line.Coordinates; Coordinate coord = pt.Coordinate; // brute force approach! int nCount0 = coord0.Count; for (int i = 0; i < nCount0 - 1; i++) { double dist = CGAlgorithms.DistancePointLine(coord, coord0[i], coord0[i + 1]); if (dist < minDistance) { minDistance = dist; LineSegment seg = new LineSegment(m_objFactory, coord0[i], coord0[i + 1]); Coordinate segClosestPoint = seg.ClosestPoint(coord); locGeom[0] = new DistanceLocation(line, i, segClosestPoint); locGeom[1] = new DistanceLocation(pt, 0, coord); } if (minDistance <= terminateDistance) { return; } } }
private void AddLineString(LineString line) { ICoordinateList coord = CoordinateCollection.RemoveRepeatedCoordinates(line.Coordinates); if (coord.Count < 2) { m_bHasTooFewPoints = true; invalidPoint = coord[0]; return; } // Add the edge for the LineString // line edges do not have locations for their left and right sides Edge e = new Edge(coord, new Label(argIndex, LocationType.Interior)); // object tempObject; // tempObject = e; lineEdgeMap[line] = e; // lineEdgeMap[line] = tempObject; // object generatedAux = tempObject; InsertEdge(e); // Add the boundary points of the LineString, if any. // Even if the LineString is closed, Add both points as if they were endpoints. // This allows for the case that the node already exists and is a boundary point. Debug.Assert(coord.Count >= 2, "found LineString with single point"); InsertBoundaryPoint(argIndex, coord[0]); InsertBoundaryPoint(argIndex, coord[coord.Count - 1]); }
/// <summary> /// Calculates the signed area for a ring. /// </summary> /// <remarks> /// Note that the sign of the returned area can be determined using /// the <see cref="Math.Sign"/> method. /// </remarks> /// <param name="ring"> /// The array of coordinates of the points defining the ring. /// </param> /// <returns> /// The signed area for a ring. The area is positive if the ring /// is oriented clockwise. /// </returns> public static double SignedArea(ICoordinateList ring) { if (ring == null) { throw new ArgumentNullException("ring"); } int nCount = ring.Count; if (nCount < 3) { return(0.0); } double sum = 0.0; for (int i = 0; i < nCount - 1; i++) { double bx = ring[i].X; double by = ring[i].Y; double cx = ring[i + 1].X; double cy = ring[i + 1].Y; sum += (bx + cx) * (cy - by); } return((-sum) / 2.0); }
/// <summary> /// This method handles single points as well as lines. Lines are assumed /// to not be closed (the function will not fail for closed lines, but /// will generate superfluous line caps). /// </summary> /// <returns>A List of <see cref="ICoordinateList"/>.</returns> public IList GetLineCurve(ICoordinateList inputPts, double distance) { ArrayList lineList = new ArrayList(); // a zero or negative width Buffer of a line/point is empty if (distance <= 0.0) { return(lineList); } Initialize(distance); if (inputPts.Count <= 1) { switch (endCapStyle) { case BufferCapType.Round: AddCircle(inputPts[0], distance); break; case BufferCapType.Square: AddSquare(inputPts[0], distance); break; // default is for Buffer to be empty (e.g. for a butt line cap); } } else { ComputeLineBufferCurve(inputPts); } lineList.Add(this.Coordinates); return(lineList); }
/// <summary> /// Generates the WKT for a N-point <see cref="LineString"/>. /// </summary> /// <param name="seq">The sequence to outpout</param> /// <returns> /// A string containing the WKT of the LineString. /// </returns> public static string ToLineString(ICoordinateList seq) { StringBuilder buf = new StringBuilder(); buf.Append("LINESTRING "); if (seq == null || seq.Count == 0) { buf.Append(" EMPTY"); } else { buf.Append(WktLParan); int nCount = seq.Count; for (int i = 0; i < nCount; i++) { if (i > 0) { buf.Append(WktComma); } Coordinate coord = seq[i]; buf.Append(coord.X + " " + coord.Y); } buf.Append(WktRParan); } return(buf.ToString()); }
/// <summary> /// Converts the List of Coordinates to WKT format and appends it to output stream. /// </summary> /// <param name="coordinates">The list of coordinates to be converted.</param> /// <param name="writer">The output stream.</param> /// <param name="wrap">bool value indicating whether the list of coordinates should be enclosed in parathenes.</param> private static void AppendCoordinates(ICoordinateList coordinates, TextWriter writer, bool wrap) { if (coordinates.Count == 0) { return; } if (wrap) { writer.Write("("); } WktWriter.AppendCoordinate(coordinates[0], writer); for (int i = 1; i < coordinates.Count; i++) { writer.Write(", "); WktWriter.AppendCoordinate(coordinates[i], writer); } if (wrap) { writer.Write(")"); } }
private void FindRightmostEdgeAtVertex() { /// <summary> The rightmost point is an interior vertex, so it has a segment on either side of it. /// If these segments are both above or below the rightmost point, we need to /// determine their relative orientation to decide which is rightmost. /// </summary> ICoordinateList pts = minDe.Edge.Coordinates; Debug.Assert(minIndex > 0 && minIndex < pts.Count, "rightmost point expected to be interior vertex of edge"); Coordinate pPrev = pts[minIndex - 1]; Coordinate pNext = pts[minIndex + 1]; OrientationType orientation = CGAlgorithms.ComputeOrientation(minCoord, pNext, pPrev); bool usePrev = false; // both segments are below min point if (pPrev.Y < minCoord.Y && pNext.Y < minCoord.Y && orientation == OrientationType.CounterClockwise) { usePrev = true; } else if (pPrev.Y > minCoord.Y && pNext.Y > minCoord.Y && orientation == OrientationType.Clockwise) { usePrev = true; } // if both segments are on the same side, do nothing - either is safe // to select as a rightmost segment if (usePrev) { minIndex = minIndex - 1; } }
private int FindMaxPerpDistance(ICoordinateList pts, LineSegment seg, int startIndex) { double maxPerpDistance = seg.DistancePerpendicular(pts[startIndex]); double nextPerpDistance = maxPerpDistance; int maxIndex = startIndex; int NextIndex = maxIndex; while (nextPerpDistance >= maxPerpDistance) { maxPerpDistance = nextPerpDistance; maxIndex = NextIndex; NextIndex = MinimumDiameter.NextIndex(pts, maxIndex); nextPerpDistance = seg.DistancePerpendicular(pts[NextIndex]); } // found maximum width for this segment - update global min dist if appropriate if (maxPerpDistance < minWidth) { minPtIndex = maxIndex; minWidth = maxPerpDistance; minWidthPt = pts[minPtIndex]; minBaseSeg = new LineSegment(seg, seg.Factory); } return(maxIndex); }
private void AddInterior(ICoordinateList pts) { for (int i = 1; i < pts.Count - 1; i++) { Add(pts[i]); } }
/// <summary> /// The left and right topological location arguments assume that the ring is oriented CW. /// If the ring is in the opposite orientation, /// the left and right locations must be interchanged. /// </summary> private void AddPolygonRing(LinearRing lr, int cwLeft, int cwRight) { ICoordinateList coord = CoordinateCollection.RemoveRepeatedCoordinates(lr.Coordinates); if (coord.Count < 4) { m_bHasTooFewPoints = true; invalidPoint = coord[0]; return; } int left = cwLeft; int right = cwRight; if (CGAlgorithms.IsCCW(coord)) { left = cwRight; right = cwLeft; } Edge e = new Edge(coord, new Label(argIndex, LocationType.Boundary, left, right)); // object tempObject; // tempObject = e; // lineEdgeMap[lr] = tempObject; // object generatedAux = tempObject; lineEdgeMap[lr] = e; InsertEdge(e); // insert the endpoint as a node, to mark that it is on the boundary InsertPoint(argIndex, coord[0], LocationType.Boundary); }
/// <summary> /// This routine checks to see if a shell is properly contained in a hole. /// It assumes that the edges of the shell and hole do not /// properly intersect. /// </summary> /// <param name="shell"></param> /// <param name="hole"></param> /// <param name="graph"></param> /// <returns> /// null if the shell is properly contained, or a Coordinate which /// is not inside the hole if it is not /// </returns> private Coordinate CheckShellInsideHole(LinearRing shell, LinearRing hole, GeometryGraph graph) { ICoordinateList shellPts = shell.Coordinates; ICoordinateList holePts = hole.Coordinates; // TODO: improve performance of this - by sorting pointlists for instance? Coordinate shellPt = FindPointNotNode(shellPts, hole, graph); // if point is on shell but not hole, check that the shell is inside the hole if (shellPt != null) { bool insideHole = CGAlgorithms.IsPointInRing(shellPt, holePts); if (!insideHole) { return(shellPt); } } Coordinate holePt = FindPointNotNode(holePts, shell, graph); // if point is on hole but not shell, check that the hole is outside the shell if (holePt != null) { bool insideShell = CGAlgorithms.IsPointInRing(holePt, shellPts); if (insideShell) { return(holePt); } return(null); } Debug.Assert(false, "Should never reach here: points in shell and hole appear to be equal"); return(null); }
private Stack GrahamScan(ICoordinateList c) { Coordinate p; Stack ps = new Stack(); ps.Push(c[0]); ps.Push(c[1]); ps.Push(c[2]); for (int i = 3; i < c.Count; i++) { p = (Coordinate)ps.Pop(); while (CGAlgorithms.ComputeOrientation( (Coordinate)ps.Peek(), p, c[i]) > 0) { p = (Coordinate)ps.Pop(); } ps.Push(p); ps.Push(c[i]); p = c[i]; } ps.Push(c[0]); return(ps); }
/// <param name="original"> the vertices of a linear ring, which may or may not be /// flattened (i.e. vertices collinear) /// </param> /// <returns> the coordinates with unnecessary (collinear) vertices /// removed /// </returns> private ICoordinateList CleanRing(ICoordinateList original) { CoordinateCollection cleanedRing = new CoordinateCollection(); Coordinate previousDistinctCoordinate = null; for (int i = 0; i <= original.Count - 2; i++) { Coordinate currentCoordinate = original[i]; Coordinate nextCoordinate = original[i + 1]; if (currentCoordinate.Equals(nextCoordinate)) { continue; } if (previousDistinctCoordinate != null && IsBetween(previousDistinctCoordinate, currentCoordinate, nextCoordinate)) { continue; } cleanedRing.Add(currentCoordinate); previousDistinctCoordinate = currentCoordinate; } cleanedRing.Add(original[original.Count - 1]); return(cleanedRing); }
// private ICoordinateList ReduceQuad(ICoordinateList pts) // { // ConvexHull.BigQuad bigQuad = this.GetBigQuad(pts); // // // Build a linear ring defining a big poly. // CoordinateCollection bigPoly = new CoordinateCollection(); // // bigPoly.Add(bigQuad.westmost); // if (!bigPoly.Contains(bigQuad.northmost)) // { // bigPoly.Add(bigQuad.northmost); // } // if (!bigPoly.Contains(bigQuad.eastmost)) // { // bigPoly.Add(bigQuad.eastmost); // } // if (!bigPoly.Contains(bigQuad.southmost)) // { // bigPoly.Add(bigQuad.southmost); // } // // if (bigPoly.Count < 3) // { // return pts; // } // // bigPoly.Add(bigQuad.westmost); // // LinearRing bQ = m_objFactory.CreateLinearRing(bigPoly); // // // load an array with all points not in the big poly // // and the defining points. // CoordinateCollection reducedSet = new CoordinateCollection(bigPoly); // for (int i = 0; i < pts.Count; i++) // { // if (pointLocator.Locate(pts[i], bQ) == LocationType.Exterior) // { // reducedSet.Add(pts[i]); // } // } // // // Return this array as the reduced problem. // return reducedSet; // } private ICoordinateList PreSort(ICoordinateList pts) { Coordinate t; // find the lowest point in the set. If two or more points have // the same minimum y coordinate choose the one with the minimu x. // This focal point is put in array location pts[0]. for (int i = 1; i < pts.Count; i++) { if ((pts[i].Y < pts[0].Y) || ((pts[i].Y == pts[0].Y) && (pts[i].X < pts[0].X))) { t = pts[0]; pts[0] = pts[i]; pts[i] = t; } } // sort the points radially around the focal point. CoordinateCollection coordPts = (CoordinateCollection)pts; coordPts.Sort(1, coordPts.Count - 1, new RadialComparator(coordPts[0])); // sort the points radially around the focal point. //RadialSort(pts); return(pts); }
protected override Envelope ComputeEnvelope() { if (IsEmpty) { return(new Envelope()); } //Convert to array, then access array directly, to avoid the function-call overhead //of calling #get millions of times. #toArray may be inefficient for //non-BasicCoordinateSequence CoordinateSequences. [Jon Aquino] ICoordinateList coordinates = points; double minx = coordinates[0].X; double miny = coordinates[0].Y; double maxx = coordinates[0].X; double maxy = coordinates[0].Y; //OptimizeIt shows that Math#min and Math#max here are a bottleneck. //Replace with direct comparisons. [Jon Aquino] for (int i = 1; i < coordinates.Count; i++) { minx = minx < coordinates[i].X ? minx:coordinates[i].X; maxx = maxx > coordinates[i].X ? maxx:coordinates[i].X; miny = miny < coordinates[i].Y ? miny:coordinates[i].Y; maxy = maxy > coordinates[i].Y ? maxy:coordinates[i].Y; } return(new Envelope(minx, maxx, miny, maxy)); }
public Triangle(Coordinate p0, Coordinate p1, Coordinate p2, GeometryFactory factory) : base(factory) { if (p0 == null) { throw new ArgumentNullException("p0"); } if (p1 == null) { throw new ArgumentNullException("p1"); } if (p2 == null) { throw new ArgumentNullException("p2"); } m_objPoint1 = p0; m_objPoint2 = p1; m_objPoint3 = p2; m_objCoordinates = new CoordinateCollection(); m_objCoordinates.Add(p0); m_objCoordinates.Add(p1); m_objCoordinates.Add(p2); }
private void Normalize(LinearRing ring, bool clockwise) { if (ring.IsEmpty) { return; } CoordinateCollection uniqueCoordinates = new CoordinateCollection(); for (int i = 0; i < ring.NumPoints - 1; i++) { uniqueCoordinates.Add(ring.GetCoordinate(i)); // copy all but last one into uniquecoordinates } Coordinate minCoordinate = CoordinateCollection.MinimumCoordinate(ring.Coordinates); uniqueCoordinates.Scroll(minCoordinate); ICoordinateList ringCoordinates = ring.Coordinates; ringCoordinates.Clear(); ringCoordinates.AddRange(uniqueCoordinates); ringCoordinates.Add(uniqueCoordinates[0].Clone()); // add back in the closing point. if (CGAlgorithms.IsCCW(ringCoordinates) == clockwise) { ringCoordinates.Reverse(); } }
/// <summary> /// This algorithm does not attempt to first check the point against the envelope /// of the ring. /// /// </summary> /// <param name="ring">assumed to have first point identical to last point /// </param> public bool IsPointInRing(Coordinate p, ICoordinateList ring) { if (p == null) { throw new ArgumentNullException("p"); } if (ring == null) { throw new ArgumentNullException("ring"); } /* * For each segment l = (i-1, i), see if it crosses ray from test point in positive x direction. */ int crossings = 0; // number of segment/ray crossings int nCount = ring.Count; for (int i = 1; i < nCount; i++) { int i1 = i - 1; Coordinate p1 = ring[i]; Coordinate p2 = ring[i1]; if (((p1.Y > p.Y) && (p2.Y <= p.Y)) || ((p2.Y > p.Y) && (p1.Y <= p.Y))) { double x1 = p1.X - p.X; double y1 = p1.Y - p.Y; double x2 = p2.X - p.X; double y2 = p2.Y - p.Y; /* * segment straddles x axis, so compute intersection with x-axis. */ double xInt = RobustDeterminant.SignOfDeterminant(x1, y1, x2, y2) / (y2 - y1); //xsave = xInt; /* * crosses ray if strictly positive intersection. */ if (xInt > 0.0) { crossings++; } } } /* * p is inside if number of crossings is odd. */ if ((crossings % 2) == 1) { return(true); } else { return(false); } }
private int id; // useful for optimizing chain comparisons #endregion #region Constructors and Destructor public MonotoneChain(ICoordinateList pts, int start, int end, object context) { this.pts = pts; this.start = start; this.end = end; this.context = context; }
private void AddCurves(IList lineList, int leftLoc, int rightLoc) { for (IEnumerator i = lineList.GetEnumerator(); i.MoveNext();) { ICoordinateList coords = (ICoordinateList)i.Current; AddCurve(coords, leftLoc, rightLoc); } }
private void CompareCoordinateLists(ICoordinateList list, ICoordinateList expected) { Assert.Equal(expected.Count, list.Count); for (int i = 0; i < expected.Count; i++) { Assert.Equal(expected[i], list[i]); } }
public SimplePointInRing(LinearRing ring) { if (ring == null) { throw new ArgumentNullException("ring"); } pts = ring.Coordinates; }
private void CompareCoordinates(Coordinate[] expected, ICoordinateList actual) { Assert.Equal(expected.Length, actual.Count); for (int i = 0; i < expected.Length; i++) { Assert.Equal(expected[i], actual[i]); } }
/// <summary> /// Writes list of Coordinates to the output using specified writer. /// </summary> /// <param name="coordinates">The list od Coordinates to write.</param> /// <param name="writer">The BinaryWriter used to write geometry to the output.</param> private static void WriteCoordinates(ICoordinateList coordinates, BinaryWriter writer) { writer.Write((uint)coordinates.Count); for (int i = 0; i < coordinates.Count; i++) { WkbWriter.WriteCoordinate(coordinates[i], writer); } }
/// <summary> /// Assumes input is valid (e.g. start <= end) /// </summary> /// <param name="start"> /// </param> /// <param name="end"> /// </param> /// <returns>A linear geometry.</returns> private LineString ComputeLine(LinearLocation start, LinearLocation end) { ICoordinateList coordinates = line.Coordinates; CoordinateCollection newCoordinates = new CoordinateCollection(); int startSegmentIndex = start.SegmentIndex; if (start.SegmentFraction > 0.0) { startSegmentIndex += 1; } int lastSegmentIndex = end.SegmentIndex; if (end.SegmentFraction == 1.0) { lastSegmentIndex += 1; } if (lastSegmentIndex >= coordinates.Count) { lastSegmentIndex = coordinates.Count - 1; } // not needed - LinearLocation values should always be correct //Assert.isTrue(end.getSegmentFraction() <= 1.0, "invalid segment fraction value"); if (!start.Vertex) { newCoordinates.Add(start.GetCoordinate(line)); } for (int i = startSegmentIndex; i <= lastSegmentIndex; i++) { newCoordinates.Add(coordinates[i]); } if (!end.Vertex) { newCoordinates.Add(end.GetCoordinate(line)); } // ensure there is at least one coordinate in the result if (newCoordinates.Count <= 0) { newCoordinates.Add(start.GetCoordinate(line)); } Coordinate[] newCoordinateArray = newCoordinates.ToArray(); // Ensure there is enough coordinates to build a valid line. // Make a 2-point line with duplicate coordinates, if necessary. // There will always be at least one coordinate in the coordList. if (newCoordinateArray.Length <= 1) { newCoordinateArray = new Coordinate[] { newCoordinateArray[0], newCoordinateArray[0] }; } return(line.Factory.CreateLineString(newCoordinateArray)); }
/// <summary> /// Determines whether two polylines defined by series of coordinates intersects /// </summary> /// <param name="line1">The first polyline to test</param> /// <param name="line2">The second polyline to test</param> /// <returns>true if polylines intersets, otherwise false</returns> public bool Intersects(ICoordinateList line1, ICoordinateList line2) { //TODO implement more efficient algorithm for (int i = 1; i < line1.Count; i++) { for (int ii = 1; ii < line2.Count; ii++) { if (this.Intersects(line1[i - 1], line1[i], LineMode.LineSegment, line2[ii - 1], line2[ii], LineMode.LineSegment)) { return true; } } } return false; }
/// <summary> /// Calculates area of the polygon specified by given vertices /// </summary> /// <param name="vertices">The vertices of the polygon</param> /// <returns>The area of the polygon in squareed coordinate's units</returns> /// <remarks>Polygon is expected to be simple. ComputeArea method handles correctly CoordinateList from Polygon class, where first and last vertices are the same.</remarks> public double CalculateArea(ICoordinateList vertices) { if (vertices.Count < 3) { throw new ArgumentException("List must contain at least 3 vertices.", "vertices"); } double area = 0; int maxIndex = vertices.Count - 1; if (vertices[0] != vertices[maxIndex]) { maxIndex++; } for (int i = 0; i < maxIndex; i++) { area += (vertices[(i + 1) % vertices.Count].X + vertices[i % vertices.Count].X) * (vertices[(i + 1) % vertices.Count].Y - vertices[i % vertices.Count].Y); } return area / 2.0; }
/// <summary> /// Calculates area of the polygon on the surface of a sphere specified by given vertices. /// </summary> /// <param name="vertices">The vertices of the polygon.</param> /// <returns>The area of the polygon in squared units of the <see cref="Sphere2DCalculator.Radius"/> property.</returns> /// <remarks>Polygon is expected to be simple.</remarks> public double CalculateArea(ICoordinateList vertices) { if (vertices.Count < 3) { throw new ArgumentException("List must contain at least 3 vertices.", "vertices"); } double area = 0; int maxIndex = vertices.Count - 1; if (vertices[0] != vertices[maxIndex]) { maxIndex++; } for (int i = 0; i <= maxIndex; i++) { area += (this.ToRadians(vertices[(i + 1) % maxIndex].X) - this.ToRadians(vertices[(i - 1) % maxIndex].X)) * Math.Sin(this.ToRadians(vertices[i % maxIndex].Y)); } return Math.Abs(area * Sphere2DCalculator.EarthRadius * Sphere2DCalculator.EarthRadius); }
/// <summary> /// Determines if specific point is in ring /// </summary> /// <param name="c">The coordinate to be tested</param> /// <param name="ring">The ring to locate point in</param> /// <returns>True if point lies inside ring, otherwise false</returns> public bool IsInRing(Coordinate c, ICoordinateList ring) { if (ring.Count < 3) { throw new ArgumentException("Ring must contain at least 3 points", "ring"); } if (ring[0].Equals2D(ring[ring.Count - 1]) == false) { throw new ArgumentException("Ring does not have the same endpoints", "ring"); } // determine if point is in ring using ray-tracing algorithm // ray is casted from c in the direction of positive x-axis int crossings = 0; for (int i = 0; i < ring.Count; i++) { Coordinate p1 = ring[i]; Coordinate p2 = ring[(i + 1) % ring.Count]; double y1 = p1.Y - c.Y; double y2 = p2.Y - c.Y; // check there can be crossing - c lies between P1 and P2 on y-axis if (((y1 > 0) && (y2 <= 0)) || ((y2 > 0) && (y1 <= 0))) { double x1 = p1.X - c.X; double x2 = p2.X - c.X; // compute intersection double intersection = (x1 * y2 - x2 * y1) / (y2 - y1); if (intersection > 0) { crossings++; } } } // p is inside if an odd number of crossings if ((crossings % 2) == 1) { return true; } else { return false; } }
/// <summary> /// Determines whether specific coordinate is on the given polyline /// </summary> /// <param name="c">The coordinate to be tested</param> /// <param name="line">The polyline</param> /// <returns>true if coordinate C is on the line, otherwise false</returns> public bool IsOnLine(Coordinate c, ICoordinateList line) { for (int i = 1; i < line.Count; i++) { if (this.IsOnLine(c, line[i - 1], line[i], LineMode.LineSegment)) { return true; } } return false; }
/// <summary> /// Initializes a new instance of the <c>Polygon</c> class with the given exterior boundary in WSG84 coordinate reference system. /// </summary> /// <param name="exteriorRing">The exterior boundary of the polygon.</param> public Polygon(ICoordinateList exteriorRing) { this.ExteriorRing = exteriorRing; this.InteriorRings = new List<ICoordinateList>(0); }