예제 #1
0
        public static bool HaveSameVertices(
            WKSPointZ[] coords1, WKSPointZ[] coords2,
            double xyTolerance, double zTolerance,
            bool ignoreDuplicateVertices = true)
        {
            Assert.ArgumentNotNull(coords1, nameof(coords1));
            Assert.ArgumentNotNull(coords2, nameof(coords2));

            IComparer <WKSPointZ> comparer = new WKSPointZComparer();

            Array.Sort(coords1, comparer);
            Array.Sort(coords2, comparer);

            var i1 = 0;
            var i2 = 0;

            while (i1 < coords1.Length && i2 < coords2.Length)
            {
                WKSPointZ a = coords1[i1];
                WKSPointZ b = coords2[i2];

                if (!GeometryUtils.IsSamePoint(a, b, xyTolerance, zTolerance))
                {
                    return(false);
                }

                // Advance to next set of coordinates:
                ++i1;
                ++i2;

                // Skip identical points in sequence!
                while (ignoreDuplicateVertices && ArePointsEqual(coords1, i1, i1 - 1,
                                                                 xyTolerance,
                                                                 zTolerance))
                {
                    ++i1;
                }

                while (ignoreDuplicateVertices && ArePointsEqual(coords2, i2, i2 - 1,
                                                                 xyTolerance,
                                                                 zTolerance))
                {
                    ++i2;
                }
            }

            return((i1 == coords1.Length) && (i2 == coords2.Length));
        }
예제 #2
0
        private Dictionary <WKSPointZ, VertexIndex> CreateCoordinateDictionary(
            [NotNull] IGeometry geometry,
            bool compare3D,
            out Dictionary <WKSPointZ, List <VertexIndex> > duplicateCoordinates)
        {
            double zTolerance = compare3D
                                                    ? _zTolerance
                                                    : double.NaN;

            var comparer = new WKSPointZComparer(_xyTolerance, zTolerance,
                                                 geometry.SpatialReference);

            var coordinateDictionary =
                new Dictionary <WKSPointZ, VertexIndex>(((IPointCollection)geometry).PointCount,
                                                        comparer);

            WKSPointZ[] pointArray = GeometryUtils.GetWKSPointZs(geometry, true);

            // NOTE: there can be ambiguity if two different segments have the same point (rings, boundary loops)
            //		 or in the 2D case if two points differ only in Z. Hence duplicates must be explicitly managed.
            var currentPartIdx     = 0;
            var currentIndexInPart = 0;
            var geometryCollection = geometry as IGeometryCollection;

            int partCount = geometryCollection?.GeometryCount ?? 1;

            duplicateCoordinates = new Dictionary <WKSPointZ, List <VertexIndex> >(partCount);
            // one duplicate for each ring

            IPointCollection currentPartPoints =
                geometryCollection == null
                                        ? (IPointCollection)geometry
                                        : null;

            foreach (WKSPointZ wksPointZ in pointArray)
            {
                if (currentPartPoints == null && geometryCollection != null)
                {
                    currentPartPoints =
                        geometryCollection.get_Geometry(currentPartIdx) as IPointCollection;
                }

                bool isLastInPart = currentPartPoints != null &&
                                    currentIndexInPart == currentPartPoints.PointCount - 1;

                var currentVertexIndex = new VertexIndex(currentPartIdx, currentIndexInPart,
                                                         isLastInPart);

                if (!coordinateDictionary.ContainsKey(wksPointZ))
                {
                    coordinateDictionary.Add(wksPointZ, currentVertexIndex);
                }
                else if (!compare3D && !double.IsNaN(_zTolerance))
                {
                    VertexIndex alreadyAdded = coordinateDictionary[wksPointZ];

                    List <VertexIndex> duplicateIndices;
                    if (!duplicateCoordinates.TryGetValue(wksPointZ, out duplicateIndices))
                    {
                        duplicateIndices = new List <VertexIndex>(2)
                        {
                            alreadyAdded
                        };
                        duplicateCoordinates.Add(wksPointZ, duplicateIndices);
                    }

                    duplicateIndices.Add(currentVertexIndex);
                }

                if (isLastInPart)
                {
                    currentPartIdx++;
                    currentPartPoints  = null;
                    currentIndexInPart = 0;
                }
                else
                {
                    currentIndexInPart++;
                }
            }

            return(coordinateDictionary);
        }
예제 #3
0
        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);
        }
예제 #4
0
        public static IList <KeyValuePair <WKSPointZ, List <WKSPointZ> > > GroupPoints(
            [NotNull] WKSPointZ[] coords,
            double xyTolerance,
            double zTolerance)
        {
            Assert.ArgumentNotNull(coords, nameof(coords));

            IComparer <WKSPointZ> comparer = new WKSPointZComparer();

            Array.Sort(coords, comparer);

            var toleranceGroups = new List <List <WKSPointZ> >();
            var currentGroup    = new List <WKSPointZ> {
                coords[0]
            };

            for (var i = 1; i < coords.Length; i++)
            {
                if (!ArePointsEqual(coords, i - 1, i, xyTolerance, zTolerance))
                {
                    toleranceGroups.Add(currentGroup);
                    currentGroup = new List <WKSPointZ> {
                        coords[i]
                    };

                    continue;
                }

                currentGroup.Add(coords[i]);
            }

            if (currentGroup.Count > 0)
            {
                toleranceGroups.Add(currentGroup);
            }

            var result =
                new List <KeyValuePair <WKSPointZ, List <WKSPointZ> > >();

            // For strict interpretation of tolerance: Consider splitting clusters that are too large (Divisive Hierarchical clustering)
            foreach (List <WKSPointZ> groupedPoints in toleranceGroups)
            {
                if (groupedPoints.Count == 1)
                {
                    result.Add(new KeyValuePair <WKSPointZ, List <WKSPointZ> >(groupedPoints[0],
                                                                               groupedPoints));
                }
                else
                {
                    var center = new WKSPointZ
                    {
                        X = groupedPoints.Average(p => p.X),
                        Y = groupedPoints.Average(p => p.Y),
                        Z = groupedPoints.Average(p => p.Z)
                    };

                    result.Add(new KeyValuePair <WKSPointZ, List <WKSPointZ> >(center, groupedPoints));
                }
            }

            return(result);
        }