/// <summary> /// Advances the vertex index of coordsToAdvance starting at currentIndex until /// the point at the index matches coordinateToMatch. All intermediate points are /// added to changedCoords. /// </summary> /// <param name="coordsToAdvance">The list of coordinates (sorted) to go through /// until a coordinate matches <paramref name="coordinateToMatch"/>.</param> /// <param name="index">The index to start at which shall be incremented unit the coordinates match.</param> /// <param name="coordinateToMatch">The target coordinate.</param> /// <param name="comparer">The comparer.</param> /// <param name="changedCoords">The list of coordinates that do not match.</param> /// <param name="addChangesToResult">Whether the changed points should be added to changedCoords</param> /// <param name="reportDuplicateVertices">Whether duplicate vertices in the coordsToAdvance should be reported or not.</param> /// <returns>Whether a match was found or not.</returns> private bool AdvanceIndexUntilMatch( [NotNull] WKSPointZ[] coordsToAdvance, ref int index, WKSPointZ coordinateToMatch, [NotNull] IComparer <WKSPointZ> comparer, [NotNull] ICollection <WKSPointZ> changedCoords, bool addChangesToResult, bool reportDuplicateVertices) { WKSPointZ currentCoord = coordsToAdvance[index]; while (comparer.Compare(coordinateToMatch, currentCoord) >= 0 && index < coordsToAdvance.Length) { // check if within the tolerance - performance could be improved if comparer could directly handle // the tolerance. bool useTolerance = Math.Abs(_xyTolerance) > double.Epsilon || (!double.IsNaN(_zTolerance) && Math.Abs(_zTolerance) > double.Epsilon); if (useTolerance && GeometryUtils.IsSamePoint(currentCoord, coordinateToMatch, _xyTolerance, _zTolerance)) { return(true); } if (addChangesToResult) { // except if it's a duplicate that should not be reported bool sameAsPrevious = WKSPointZUtils.ArePointsEqual( coordsToAdvance, index, index - 1, _xyTolerance, _zTolerance); if (!sameAsPrevious || reportDuplicateVertices) { changedCoords.Add(currentCoord); } } ++index; if (index < coordsToAdvance.Length) { currentCoord = coordsToAdvance[index]; } } return(false); }
/// <summary> /// Adds the remaining points starting from baseIndexStart for baseCoords and from /// compareIndexStart for compareCoords. /// </summary> /// <param name="baseCoords"></param> /// <param name="compareCoords"></param> /// <param name="baseIndexStart"></param> /// <param name="compareIndexStart"></param> /// <param name="result"></param> /// <param name="reportDuplicateVertices"></param> /// <param name="baseInsertsOnly"></param> private void AddRemainingPoints( WKSPointZ[] baseCoords, WKSPointZ[] compareCoords, int baseIndexStart, int compareIndexStart, List <WKSPointZ> result, bool reportDuplicateVertices, bool baseInsertsOnly) { // add all remaining points from baseCoords for (int i = baseIndexStart; i < baseCoords.Length; i++) { bool sameAsPrevious = WKSPointZUtils.ArePointsEqual( baseCoords, i, i - 1, _xyTolerance, _zTolerance); if (sameAsPrevious && !reportDuplicateVertices) { continue; } result.Add(baseCoords[i]); } if (!baseInsertsOnly) { // add all remaining points from baseCoords for (int i = compareIndexStart; i < compareCoords.Length; i++) { bool sameAsPrevious = WKSPointZUtils.ArePointsEqual(compareCoords, i, i - 1, _xyTolerance, _zTolerance); if (sameAsPrevious && !reportDuplicateVertices) { continue; } result.Add(compareCoords[i]); } } }
private IList <WKSPointZ> GetChangedVertices( WKSPointZ[] baseCoords, WKSPointZ[] compareCoords, bool reportDuplicateVertices, bool baseInsertsOnly) { Assert.ArgumentNotNull(baseCoords, nameof(baseCoords)); Assert.ArgumentNotNull(compareCoords, nameof(compareCoords)); var comparer = new WKSPointZComparer(_xyTolerance, _zTolerance, 0, 0, 0); Array.Sort(baseCoords, comparer); Array.Sort(compareCoords, comparer); var result = new List <WKSPointZ>(); var i1 = 0; var i2 = 0; while (i1 < baseCoords.Length && i2 < compareCoords.Length) { WKSPointZ a = baseCoords[i1]; WKSPointZ b = compareCoords[i2]; bool inSync = GeometryUtils.IsSamePoint(a, b, _xyTolerance, _zTolerance); if (!inSync) { // a is greater than b, advance b until in sync with a bool matchAdvanceCompareCoords = AdvanceIndexUntilMatch( compareCoords, ref i2, a, comparer, result, !baseInsertsOnly, reportDuplicateVertices); // b is greater than a, advance a until in sync with b bool matchAdvanceBaseCoords = AdvanceIndexUntilMatch( baseCoords, ref i1, b, comparer, result, true, reportDuplicateVertices); if (matchAdvanceCompareCoords || matchAdvanceBaseCoords) { inSync = true; } } // Advance to next set of coordinates only if in sync to make sure no difference points are missed if (inSync) { ++i1; ++i2; } // Skip identical points in sequence otherwise From/To points in rotated ring get reported as changes // NOTE: SameCoords tolerates index out of bounds! while (WKSPointZUtils.ArePointsEqual(baseCoords, i1, i1 - 1, _xyTolerance, _zTolerance)) { bool compareCoordsHasDuplicateToo = inSync && WKSPointZUtils.ArePointsEqual(compareCoords, i2, i2 - 1, _xyTolerance, _zTolerance); if (compareCoordsHasDuplicateToo) { // in sync and both have a duplicate at the same location -> unchanged, do not report // but increment both indexes ++i2; } else { // not in sync or compare geometry has no duplicate -> changed, report on request if (reportDuplicateVertices) { result.Add(baseCoords[i1]); } } // eventually landing at the next non-identical point: ++i1; } // process remaining duplicates at current location (or at original location if not in sync) while (WKSPointZUtils.ArePointsEqual(compareCoords, i2, i2 - 1, _xyTolerance, _zTolerance)) { if (reportDuplicateVertices && !baseInsertsOnly) { result.Add(compareCoords[i2]); } ++i2; } } AddRemainingPoints(baseCoords, compareCoords, i1, i2, result, reportDuplicateVertices, baseInsertsOnly); return(result); }