/// <summary> /// Sets the number of intersections for one of the polygon link points. /// </summary> /// <param name="index">The array index of the link point to process.</param> /// <returns>The number of intersections assigned.</returns> uint SetIntersectionCount(uint index) { // No intersections so far uint nx = 0; // Point to the thing we want to set the count for. PolygonLink link = m_Links[index]; // Go through all link points searching for intersections. for (uint i = 0; i < m_Links.Length; i++) { if (link.IsIntersected(m_Links[i])) { nx++; } } // Set the intersect count. link.NumIntersect = nx; return(nx); }
/// <summary> /// Constructor (that does a lot of stuff) /// </summary> /// <param name="polygon">The polygon being subdivided.</param> internal PolygonSub(Polygon polygon) { m_Polygon = polygon; m_Faces = null; m_Links = null; // Get the boundaries defining the exterior edge of the polygon IDivider[] lines = polygon.Edge; if (lines == null || lines.Length == 0) { return; } // Allocate an array for holding info on each polygon face, // and associate each one with the divider that acts as the primary face. uint numLink = 0; m_Faces = new PolygonFace[lines.Length]; for (int i = 0; i < lines.Length; i++) { m_Faces[i] = new PolygonFace(); numLink += m_Faces[i].SetDivider(m_Polygon, lines[i]); } // Create an array of link objects (one for each point) if (numLink == 0) { return; } m_Links = new PolygonLink[numLink]; // Initialize the links for first face int nDone = 0; PolygonLink[] links = m_Faces[0].CreateLinks(m_Faces[m_Faces.Length - 1]); Array.Copy(links, m_Links, links.Length); nDone += links.Length; // Initialize links for each subsequent face for (int i = 1; i < m_Faces.Length; i++) { links = m_Faces[i].CreateLinks(m_Faces[i - 1]); for (int j = 0; j < links.Length; j++) { m_Links[nDone + j] = links[j]; } nDone += links.Length; } Debug.Assert(nDone == m_Links.Length); // Assign a side number to each link position uint nside = 0; // No side number assigned so far. uint ncorn = 0; // Number of corners for (int i = 0; i < m_Links.Length; i++) { // Skip if we are dealing with a corner. if (m_Links[i].IsCorner()) { ncorn++; continue; } // Skip if the side number has already been assigned. if (m_Links[i].Side != 0) { continue; } // Assign next side number. nside++; // Continue till we reach a corner, assigning intermediate // faces the same side number. for (int j = i; j < m_Links.Length; j++) { if (m_Links[j].IsCorner()) { break; } m_Links[j].Side = nside; } // If we just assigned a side number to the very first face, // loop back from the end of the array. if (i == 0) { for (int k = m_Links.Length - 1; k > 0; k--) { if (m_Links[k].IsCorner()) { break; } m_Links[k].Side = nside; } } } // Return if we only have one side (or less) // if ( nside<2 ) return; // Define the max angular difference (10 degrees, but in radians) double ANGTOL = (10.0 * Constants.DEGTORAD); // Process all the radial faces first. for (uint i = 0; i < m_Links.Length; i++) { if (m_Links[i].IsRadial) { this.SetLink(i, ANGTOL); } } // For each point that is not a corner or a curve end, cycle // through all the subsequent points, looking for a point to // connect to. Don't try to do curve end points just yet. for (uint i = 0; i < m_Links.Length; i++) { if (!m_Links[i].IsRadial && !m_Links[i].IsCurveEnd) { this.SetLink(i, ANGTOL); } } // Process any points at the end of curves. for (uint i = 0; i < m_Links.Length; i++) { if (m_Links[i].IsCurveEnd) { this.SetLink(i, ANGTOL); } } // Eliminate self-intersections ... // Start by counting the number of intersections each link has. uint maxnx = 0; for (uint i = 0; i < m_Links.Length; i++) { uint nx = this.SetIntersectionCount(i); maxnx = Math.Max(maxnx, nx); } uint nloop = 0; // Number of loops (just in case of infinite loop). while (maxnx > 0) { // Find a link with the max number of intersections. int rem = -1; for (int i = 0; i < m_Links.Length; i++) { if (m_Links[i].NumIntersect == maxnx) { rem = i; break; } } // We SHOULD have found something. if (rem < 0) { throw new Exception("PolygonSub: Unexpected intersection count"); } // If the count was greater than one, just remove the link. Otherwise get the // thing that was intersected. If one is a radial or a curve end, & the other isn't, // drop the radial. Otherwise drop the one with the poorer link angle. if (maxnx > 1) { m_Links[rem].SetLink(null); } else { PolygonLink pLink1 = m_Links[rem]; PolygonLink pLink2 = null; for (int i = 0; pLink2 != null && i < m_Links.Length; i++) { if (pLink1.IsIntersected(m_Links[i])) { pLink2 = m_Links[i]; } } if (pLink2 == null) { throw new Exception("PolygonSub: Intersection not found"); } // Check if radial. bool rad1 = pLink1.IsRadial || pLink1.Link.IsRadial; bool rad2 = pLink2.IsRadial || pLink2.Link.IsRadial; // Check if end of curves. bool end1 = pLink1.IsCurveEnd || pLink1.Link.IsCurveEnd; bool end2 = pLink2.IsCurveEnd || pLink2.Link.IsCurveEnd; // We treat radials and end of curves the same. bool curve1 = (rad1 || end1); bool curve2 = (rad2 || end2); // If one is a curve-related and the other isn't, drop // the one that's curve-related. if (curve1 != curve2) { if (curve1) { pLink1.SetLink(null); } else { pLink2.SetLink(null); } } else { // Neither is curve related, or both are. Drop the // one with the poorer link angle. if (pLink1.LinkAngle > pLink2.LinkAngle) { pLink1.SetLink(null); } else { pLink2.SetLink(null); } } } // Rework the intersect counts where necessary. maxnx = 0; for (uint i = 0; i < m_Links.Length; i++) { if (m_Links[i].NumIntersect > 0) { maxnx = Math.Max(maxnx, this.SetIntersectionCount(i)); } } // Make sure we don't go into an infinite loop. nloop++; if (nloop > m_Links.Length) { throw new Exception("PolygonSub: Breaking from infinite loop"); } } // end while }