//===================================================================== // GetTriangulation() : ElementSet //===================================================================== /// <summary> /// Returns an ArrayList of triangles of type XYPolygon describing the /// triangalation of the polygon. /// </summary> /// <param></param> /// <returns> /// A triangulation of the polygon. /// </returns> public ArrayList GetTriangulation() { XYPolygon LocalPolygon = new XYPolygon(this); ArrayList TriangleList = new ArrayList(); while (LocalPolygon.Points.Count > 3) { int i = LocalPolygon.FindEar(); int n = LocalPolygon.Points.Count; int im1 = i - 1; int ip1 = i + 1; if (i == 0) { im1 = n - 1; } else if (i == n - 1) { ip1 = 0; } XYPoint Nodeim1 = new XYPoint((XYPoint)LocalPolygon.Points[im1]); XYPoint Nodei = new XYPoint((XYPoint)LocalPolygon.Points[i]); XYPoint Nodeip1 = new XYPoint((XYPoint)LocalPolygon.Points[ip1]); XYPolygon Triangle = new XYPolygon(); Triangle.Points.Add(Nodeim1); Triangle.Points.Add(Nodei); Triangle.Points.Add(Nodeip1); TriangleList.Add(Triangle); LocalPolygon.Points.RemoveAt(i); } TriangleList.Add(LocalPolygon); return(TriangleList); }
//===================================================================== // XYPolygon(XYPolygon xyPolygon): void //===================================================================== /// <summary> /// Constructor. Copies the contents of the xyPolygon parameter. /// </summary> /// <param name="xyPolygon">Polygon to copy.</param> /// <returns>None</returns> public XYPolygon(XYPolygon xyPolygon) { // Points = new ArrayList(); foreach (XYPoint xypoint in xyPolygon.Points) { Points.Add(new XYPoint(xypoint.X, xypoint.Y)); } }
//===================================================================== // IsPointInPolygon (double x, double y, XYPolygon polygon) : bool //===================================================================== /// <summary> /// Determines if a point in inside or outside a polygon. /// Works for both convex and concave polygons (Winding number test) /// </summary> /// <param name="x">x-coordinate for the point</param> /// <param name="y">y-coordiante for the point</param> /// <param name="polygon">Polygon</param> /// <returns> /// <p>true: If the point is inside the polygon</p> /// <p>false: If the point is outside the polygon.</p> /// </returns> public static bool IsPointInPolygon(double x, double y, XYPolygon polygon) { bool isInside = false; int n = polygon.Points.Count; for (int i = 0; i < n; i++) { double x1; double x2; double y2; double y1; if (i < n - 1) { x1 = ((XYPoint)polygon.Points[i]).X; x2 = ((XYPoint)polygon.Points[i + 1]).X; y1 = ((XYPoint)polygon.Points[i]).Y; y2 = ((XYPoint)polygon.Points[i + 1]).Y; } else { x1 = ((XYPoint)polygon.Points[n - 1]).X; x2 = ((XYPoint)polygon.Points[0]).X; y1 = ((XYPoint)polygon.Points[n - 1]).Y; y2 = ((XYPoint)polygon.Points[0]).Y; } if (y > Math.Min(y1, y2)) { if (y <= Math.Max(y1, y2)) { if (x <= Math.Max(x1, x2)) { if (y1 != y2) { double xinters = (y - y1) * (x2 - x1) / (y2 - y1) + x1; if (x1 == x2 || x <= xinters) { isInside = !isInside; } } } } } } return(isInside); }
//===================================================================== // CalculateSharedArea (XYPolygon polygonA, XYPolygon polygonB) : double //===================================================================== /// <summary> /// The methods calculates the shared area of two arbitrarily shaped /// polygons. /// </summary> /// <param name="polygonA">Polygon</param> /// <param name="polygonB">Polygon</param> /// <returns> /// <p>The shared area.</p> /// </returns> public static double CalculateSharedArea(XYPolygon polygonA, XYPolygon polygonB) { ArrayList triangleListA = polygonA.GetTriangulation(); ArrayList triangleListB = polygonB.GetTriangulation(); double area = 0; for (int ia = 0; ia < triangleListA.Count; ia++) { XYPolygon triangleA = new XYPolygon((XYPolygon)triangleListA[ia]); for (int ib = 0; ib < triangleListB.Count; ib++) { XYPolygon triangleB = new XYPolygon((XYPolygon)triangleListB[ib]); area = area + TriangleIntersectionArea(triangleA, triangleB); } } return(area); }
//===================================================================== // IsIntersected(integer i) : bool //===================================================================== /// <summary> /// The method decides if the triangle formed by P(i-1), P(i) and /// P(i+1) from Polygon are intersected by any of the other points /// of the polygon. /// </summary> /// <param name="i">Middle index for the three points that forms the triangle</param> /// <returns> /// <p>true: If the triangle P(i-1), P(i), P(i+1) is intersected by other parts of Polygon</p> /// <p>false: otherwise</p> /// </returns> protected bool IsIntersected(int i) { int n = Points.Count; int im1 = i - 1; int ip1 = i + 1; if (i == 0) { im1 = n - 1; } else if (i == n - 1) { ip1 = 0; } XYPoint nodeim1 = new XYPoint((XYPoint)Points[im1]); XYPoint nodei = new XYPoint((XYPoint)Points[i]); XYPoint nodeip1 = new XYPoint((XYPoint)Points[ip1]); XYPolygon localPolygon = new XYPolygon(); localPolygon.Points.Add(nodeim1); localPolygon.Points.Add(nodei); localPolygon.Points.Add(nodeip1); int j = 0; while (((j < n - 1))) { double x = ((XYPoint)Points[j]).X; double y = ((XYPoint)Points[j]).Y; if (((((j != im1) && (j != i)) && (j != ip1)) && XYGeometryTools.IsPointInPolygon(x, y, localPolygon))) { return(true); } else { j++; } } return(false); }
//===================================================================== // IsPointInPolygonOrOnEdge (double x, double y, XYPolygon polygon) : bool //===================================================================== /// <summary> /// Determines if a point in inside or outside a polygon. Inside /// includes on the edge for this method. /// Works for both convex and concave polygons (Winding number test) /// </summary> /// <param name="x">x-coordinate for the point</param> /// <param name="y">y-coordiante for the point</param> /// <param name="polygon">Polygon</param> /// <returns> /// <p>true: If the point is inside the polygon</p> /// <p>false: If the point is outside the polygon.</p> /// </returns> protected static bool IsPointInPolygonOrOnEdge(double x, double y, XYPolygon polygon) { bool result = IsPointInPolygon(x, y, polygon); if (result) { return(result); } else { int iLine = 0; while ((!result) && (iLine < polygon.Points.Count)) { XYLine line; line = polygon.GetLine(iLine); result = IsPointInLine(x, y, line); iLine++; } } return(result); }
//=============================================================================================== //CheckElementSet(IElementSet elementSet): void static //=============================================================================================== /// <summary> /// Static method that validates an object with an IElementSet interface. The method /// raises an Exception in case IElementSet does not describe a valid ElementSet. /// The checks made are: /// <p>ElementType: Check</p> /// <p>XYPoint: Only one vertex in each element.</p> /// <p>XYPolyline: At least two vertices in each element.</p> /// <p> All line segments in each element has length > 0</p> /// <p>XYPolygon: At least three vertices in each element.</p> /// <p> Area of each element is larger than 0</p> /// <p> All line segments in each element has length > 0</p> /// <p> No line segments within an element crosses.</p> /// </summary> /// /// <param name="elementSet">Object that implement the IElementSet interface</param> /// /// <returns> /// The method has no return value. /// </returns> public static void CheckElementSet(IElementSet elementSet) { try { if (elementSet.ElementType == ElementType.Point) { for (int i = 0; i < elementSet.ElementCount; i++) { try { if (elementSet.GetVertexCount(i) != 1) { throw new System.Exception("Number of vertices in point element is different from 1."); } } catch (System.Exception e) { throw new System.Exception("ElementID = " + elementSet.GetElementId(i), e); } } } else if (elementSet.ElementType == ElementType.PolyLine) { for (int i = 0; i < elementSet.ElementCount; i++) { try { XYPolyline xypolyline = new XYPolyline(); for (int j = 0; j < elementSet.GetVertexCount(i); j++) { XYPoint xypoint = new XYPoint(elementSet.GetVertexXCoordinate(i, j), elementSet.GetVertexYCoordinate(i, j)); xypolyline.Points.Add(xypoint); } xypolyline.Validate(); } catch (System.Exception e) { throw new System.Exception("ElementID = " + elementSet.GetElementId(i), e); } } } else if (elementSet.ElementType == ElementType.Polygon) { for (int i = 0; i < elementSet.ElementCount; i++) { try { XYPolygon xypolygon = new XYPolygon(); for (int j = 0; j < elementSet.GetVertexCount(i); j++) { XYPoint xypoint = new XYPoint(elementSet.GetVertexXCoordinate(i, j), elementSet.GetVertexYCoordinate(i, j)); xypolygon.Points.Add(xypoint); } xypolygon.Validate(); } catch (System.Exception e) { throw new System.Exception("ElementID = " + elementSet.GetElementId(i), e); } } } } catch (System.Exception e) { throw new System.Exception("ElementSet with ID = " + elementSet.Caption + " is invalid", e); } }
//===================================================================== // IsPointInPolygon (XYPoint point, XYPolygon polygon) : bool //===================================================================== /// <summary> /// Determines if a point in inside or outside a polygon. /// Works for both convex and concave polygons (Winding number test) /// </summary> /// <param name="point">Point</param> /// <param name="polygon">Polygon</param> /// <returns> /// <p>true: If the point is inside the polygon</p> /// <p>false: Otherwise.</p> /// </returns> public static bool IsPointInPolygon(XYPoint point, XYPolygon polygon) { return(IsPointInPolygon(point.X, point.Y, polygon)); }
//===================================================================== // Intersect(XYPolygon triangleA, XYPolygon triangleB, // ref XYPoint p, ref int i, ref int j, // ref XYPolygon intersectionPolygon) : void //===================================================================== /// <summary> /// The method calculates the intersection points of triangle a and b both /// of type XYPolygon. /// </summary> /// <param name="triangleA">triangle. The search is started along triangleA.</param> /// <param name="triangleB">triangle. Intersection with this triangle are sought.</param> /// <param name="p">Starting point for the search. p must be part of triangleA.</param> /// <param name="i">on input: End index for the first line segment of triangleA in the search. /// on output: End index for the last intersected line segment in triangleA.</param> /// <param name="j">on input: -1 if vertices before intersection is not to be added to list. /// on output: End index for last intersected line segment of triangleB.</param> /// <param name="intersectionPolygon">polygon eventuallu describing the /// intersection area between triangleA and triangleB</param> /// <returns> /// The p, i, j and intersectionPolygon are called by reference and modified in the method. /// </returns> private static void Intersect(XYPolygon triangleA, XYPolygon triangleB, ref XYPoint p, ref int i, ref int j, ref XYPolygon intersectionPolygon) { XYLine lineA; XYLine lineB; int im1 = Decrease(i, 2); // "i-1" int count1 = 0; bool found = false; while ((count1 < 3) && (!found)) { lineA = triangleA.GetLine(im1); if (count1 == 0) { lineA.P1.X = p.X; lineA.P1.Y = p.Y; } double MinDist = -1; // Distance used when a line is crossed more than once int jm1 = 0; // "j-1" int jm1Store = -1; while (jm1 < 3) { lineB = triangleB.GetLine(jm1); found = IntersectionPoint(lineA, lineB, ref p); double Dist = CalculatePointToPointDistance(lineA.P1, p); if (Dist < EPSILON) { found = false; } if (found) { if ((MinDist < 0) || (Dist < MinDist)) { MinDist = Dist; jm1Store = jm1; } } jm1++; } if (jm1Store > -1) { lineB = triangleB.GetLine(jm1Store); found = IntersectionPoint(lineA, lineB, ref p); XYPoint HelpCoordinate = new XYPoint(p.X, p.Y); XYPoint HelpNode = new XYPoint(HelpCoordinate); intersectionPolygon.Points.Add(HelpNode); j = Increase(jm1Store, 2); } if (!found) { count1++; im1 = Increase(im1, 2); i = Increase(i, 2); if (j != -1) { XYPoint HelpCoordinate = new XYPoint(lineA.P2.X, lineA.P2.Y); XYPoint HelpNode = new XYPoint(HelpCoordinate); intersectionPolygon.Points.Add(HelpNode); } } } lineA = triangleA.GetLine(Decrease(i, 2)); if (CalculatePointToPointDistance(p, lineA.P2) < EPSILON) { i = Increase(i, 2); } lineB = triangleB.GetLine(Decrease(j, 2)); if (CalculatePointToPointDistance(p, lineB.P2) < EPSILON) { j = Increase(j, 2); } }
//===================================================================== // TriangleIntersectionArea(XYPolygon triangleA, XYPolygon triangleB) : double //===================================================================== /// <summary> /// The method calculates the intersection area of triangle a and b both /// of type XYPolygon. /// </summary> /// <param name="triangleA">Triangle of type XYPolygon</param> /// <param name="triangleB">Triangle of type XYPolygon</param> /// <returns> /// Intersection area between the triangles triangleA and triAngleB. /// </returns> protected static double TriangleIntersectionArea(XYPolygon triangleA, XYPolygon triangleB) { try { if (triangleA.Points.Count != 3 || triangleB.Points.Count != 3) { throw new Exception("Argument must be a polygon with 3 points"); } int i = 1; // Index for "next" node in polygon a. int j = -1; // Index for "next" node in polygon b. // -1 indicates that the first has not yet been found. double area; // Intersection area. Returned. XYPolygon intersectionPolygon = new XYPolygon(); // Intersection polygon. XYPoint pFirst; // First intersection point between triangles XYPoint p = new XYPoint(); // Latest intersection node found p.X = ((XYPoint)triangleA.Points[0]).X; p.Y = ((XYPoint)triangleA.Points[0]).Y; Intersect(triangleA, triangleB, ref p, ref i, ref j, ref intersectionPolygon); pFirst = p; if (j != -1) { bool complete = false; int count = 0; while (!complete) { // coordinates for vectors pointing to next triangleA and triangleB point respectively double vax = ((XYPoint)triangleA.Points[i]).X - p.X; double vay = ((XYPoint)triangleA.Points[i]).Y - p.Y; double vbx = ((XYPoint)triangleB.Points[j]).X - p.X; double vby = ((XYPoint)triangleB.Points[j]).Y - p.Y; if (IsPointInPolygonOrOnEdge(p.X + EPSILON * vax, p.Y + EPSILON * vay, triangleB)) { Intersect(triangleA, triangleB, ref p, ref i, ref j, ref intersectionPolygon); } else if (IsPointInPolygonOrOnEdge(p.X + EPSILON * vbx, p.Y + EPSILON * vby, triangleA)) { Intersect(triangleB, triangleA, ref p, ref j, ref i, ref intersectionPolygon); } else // triangleA and triangleB only touches one another but do not intersect { area = 0; return(area); } if (intersectionPolygon.Points.Count > 1) { complete = (CalculatePointToPointDistance(p, pFirst) < EPSILON); } count++; if (count > 20) { throw new Exception("Failed to find intersection polygon"); } } area = intersectionPolygon.GetArea(); } else { XYPoint pa = new XYPoint(); // internal point in triangle a XYPoint pb = new XYPoint(); // internal point in triangle b pa.X = (triangleA.GetX(0) + triangleA.GetX(1) + triangleA.GetX(2)) / 3; pa.Y = (triangleA.GetY(0) + triangleA.GetY(1) + triangleA.GetY(2)) / 3; pb.X = (triangleB.GetX(0) + triangleB.GetX(1) + triangleB.GetX(2)) / 3; pb.Y = (triangleB.GetY(0) + triangleB.GetY(1) + triangleB.GetY(2)) / 3; if (IsPointInPolygon(pa, triangleB) || IsPointInPolygon(pb, triangleA)) // triangleA is completely inside triangleB { area = Math.Min(triangleA.GetArea(), triangleB.GetArea()); } else // triangleA and triangleB do dot intersect { area = 0; } } return(area); } catch (Exception e) { throw new Exception("TriangleIntersectionArea failed", e); } }
//===================================================================================== //CalculateLengthOfLineInsidePolygon(XYLine line, XYPolygon polygon): double //===================================================================================== /// <summary> /// Calculates length of line inside polygon. Parts of the line that is on the edge of /// the polygon only counts with half their length. /// </summary> /// <param name="line">Line</param> /// <param name="polygon">Polygon</param> /// <returns> /// Length of line inside polygon. /// </returns> protected static double CalculateLengthOfLineInsidePolygon(XYLine line, XYPolygon polygon) { ArrayList lineList = new ArrayList(); lineList.Add(new XYLine(line)); for (int i = 0; i < polygon.Points.Count; i++) // For all lines in the polygon { for (int n = 0; n < lineList.Count; n++) { if (lineList.Count > 1000) { throw new Exception("Problems in ElementMapper, line has been cut in more than 1000 pieces !!!"); } if (DoLineSegmentsIntersect((XYLine)lineList[n], polygon.GetLine(i))) { // Split the intersecting line into two lines XYPoint IntersectionPoint = new XYPoint(CalculateIntersectionPoint((XYLine)lineList[n], polygon.GetLine(i))); lineList.Add(new XYLine(IntersectionPoint, ((XYLine)lineList[n]).P2)); ((XYLine)lineList[n]).P2.X = IntersectionPoint.X; ((XYLine)lineList[n]).P2.Y = IntersectionPoint.Y; break; } } } for (int i = 0; i < lineList.Count; i++) { if (lineList.Count > 1000) { throw new Exception("Problems in ElementMapper, line has been cuttes in more than 100 pieces !!!"); } for (int j = 0; j < polygon.Points.Count; j++) { if (IsPointInLineInterior(polygon.GetLine(j).P1, ((XYLine)lineList[i]))) { lineList.Add(new XYLine(polygon.GetLine(j).P1, ((XYLine)lineList[i]).P2)); ((XYLine)lineList[i]).P2.X = polygon.GetLine(j).P1.X; ((XYLine)lineList[i]).P2.Y = polygon.GetLine(j).P1.Y; } } } double lengthInside = 0; for (int i = 0; i < lineList.Count; i++) { double sharedLength = 0; for (int j = 0; j < polygon.Points.Count; j++) { sharedLength += CalculateSharedLength(((XYLine)lineList[i]), polygon.GetLine(j)); } if (sharedLength > EPSILON) { lengthInside += sharedLength / 2; } else if (IsPointInPolygon(((XYLine)lineList[i]).GetMidpoint(), polygon)) { lengthInside += ((XYLine)lineList[i]).GetLength(); } } return(lengthInside); }
//========================================================================================= //CalculateLengthOfPolylineInsidePolygon(XYPolyline polyline, XYPolygon polygon) : double //========================================================================================= /// <summary> /// Calculates the length of polyline inside polygon. Lines segments on the edges of /// polygons are included with half their length. /// </summary> /// <param name="polyline">Polyline</param> /// <param name="polygon">Polygon</param> /// <returns> /// Length of polyline inside polygon. /// </returns> public static double CalculateLengthOfPolylineInsidePolygon(XYPolyline polyline, XYPolygon polygon) { double lengthInside = 0; int numberOfLineSegments = polyline.Points.Count - 1; for (int i = 0; i < numberOfLineSegments; i++) { XYLine line = new XYLine(polyline.GetLine(i)); lengthInside += CalculateLengthOfLineInsidePolygon(line, polygon); } return(lengthInside); }