/// <summary> /// Partitions a polygon by triangles. /// </summary> public void Compute() { this.result = new List <Coordinate[]>(); List <Coordinate> shell = new List <Coordinate>(this.Source); List <Coordinate> nextShell = new List <Coordinate>(this.Source); Coordinate[] triangle; Int32 coordinateCount = shell.Count - 1; Int32 coordinateIndex = 1; while (shell.Count != 4) { Coordinate centroid = LineAlgorithms.Centroid(shell[(shell.Count + coordinateIndex - 1) % coordinateCount], shell[(shell.Count + coordinateIndex + 1) % coordinateCount], this.PrecisionModel); nextShell.Remove(nextShell[coordinateIndex]); if (!WindingNumberAlgorithm.InExterior(shell, centroid, this.PrecisionModel) && !ShamosHoeyAlgorithm.Intersects(nextShell, this.PrecisionModel)) { triangle = new Coordinate[3] { shell[(coordinateCount + coordinateIndex - 1) % coordinateCount], shell[coordinateIndex], shell[(coordinateCount + coordinateIndex + 1) % coordinateCount] }; this.result.Add(triangle); shell.Remove(shell[coordinateIndex]); coordinateIndex = 1; coordinateCount--; } else { coordinateIndex = (coordinateIndex + 1) % (shell.Count - 1); nextShell = new List <Coordinate>(shell); } } triangle = new Coordinate[3] { shell[0], shell[1], shell[2] }; this.result.Add(triangle); this.hasResult = true; }
/// <summary> /// Determines whether the specified polygon is valid. /// </summary> /// <param name="shell">The coordinates of the polygon shell.</param> /// <param name="holes">The coordinates of the polygon holes.</param> /// <param name="validateIntersections">A value indicating whether to validate for intersections.</param> /// <param name="precisionModel">The precision model.</param> /// <returns><c>true</c> if the polygon is valid; otherwise false.</returns> /// <exception cref="System.ArgumentNullException">The shell is null.</exception> public static Boolean IsValid(IEnumerable <Coordinate> shell, IEnumerable <IEnumerable <Coordinate> > holes, Boolean validateIntersections, PrecisionModel precisionModel) { if (shell == null) { throw new ArgumentNullException(nameof(shell)); } if (precisionModel == null) { precisionModel = PrecisionModel.Default; } // shell and holes existence IEnumerator <Coordinate> shellEnumerator = shell.GetEnumerator(); if (!shellEnumerator.MoveNext()) { // shell has no coordinates if (holes == null) { return(true); } return(holes.Any(hole => holes.AnyElement())); } Int32 count = 1; Coordinate first = shellEnumerator.Current, previous = first, current = first; if (first == null || !first.IsValid) { return(false); } while (shellEnumerator.MoveNext()) { current = shellEnumerator.Current; if (current == null || !current.IsValid || current.Z != first.Z || precisionModel.AreEqual(current, previous)) { return(false); } previous = current; count++; } if (count < 4 || !precisionModel.AreEqual(first, current)) { return(false); } List <IEnumerable <Coordinate> > ringList = new List <IEnumerable <Coordinate> >(); ringList.Add(shell); // holes if (holes != null) { foreach (IEnumerable <Coordinate> hole in holes) { if (hole == null) { continue; } IEnumerator <Coordinate> holeEnumerator = hole.GetEnumerator(); if (!holeEnumerator.MoveNext()) { continue; } count = 1; first = holeEnumerator.Current; if (first == null || !first.IsValid) { return(false); } while (holeEnumerator.MoveNext()) { current = holeEnumerator.Current; if (current == null || !current.IsValid || current.Z != first.Z || precisionModel.AreEqual(current, previous)) { return(false); } previous = current; count++; } if (count < 4 || !precisionModel.AreEqual(first, current)) { return(false); } ringList.Add(hole); } } // check for any intersection if (validateIntersections && ShamosHoeyAlgorithm.Intersects(ringList, precisionModel)) { return(false); } return(true); }