/// <summary> /// Computes the planar orientation of a polygon. /// </summary> /// <param name="shell">The coordinates of the polygon shell.</param> /// <param name="precisionModel">The precision model.</param> /// <returns>The orientation of the polygon. If the polygon is invalid <see cref="AEGIS.Orientation.Undefined" /> is returned.</returns> /// <exception cref="System.ArgumentNullException">The shell is null.</exception> public static Orientation Orientation(IEnumerable <Coordinate> shell, PrecisionModel precisionModel) { if (shell == null) { throw new ArgumentNullException(nameof(shell)); } // check for polygon properties IEnumerator <Coordinate> enumerator = shell.GetEnumerator(); Double sum = 0; Int32 count = 1; if (!enumerator.MoveNext()) { return(AEGIS.Orientation.Undefined); } Coordinate first = enumerator.Current, previous = first, current = first; while (enumerator.MoveNext()) { current = enumerator.Current; sum += (current.X - previous.X) * (current.Y + previous.Y); count++; previous = current; } if (count < 3) { return(AEGIS.Orientation.Undefined); } if (precisionModel == null) { precisionModel = PrecisionModel.Default; } if (!precisionModel.AreEqual(first, current)) { sum += (first.X - current.X) * (first.Y + current.Y); } if (Math.Abs(sum) <= precisionModel.Tolerance(shell)) { return(AEGIS.Orientation.Collinear); } return((sum > 0) ? AEGIS.Orientation.Clockwise : AEGIS.Orientation.Counterclockwise); }
/// <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); }