public void CanSearchSinglePoint()
        {
            var points =
                new[]
            {
                new Pnt3D(1200000, 2600000, 10),
            };

            SpatialHashSearcher <Pnt3D> searcher;

            Assert.Throws <ArgumentException>(
                () =>
            {
                searcher =
                    SpatialHashSearcher <Pnt3D> .CreateSpatialSearcher(
                        points, p => new EnvelopeXY(p));
            });

            searcher =
                SpatialHashSearcher <Pnt3D> .CreateSpatialSearcher(
                    points, p => new EnvelopeXY(p), 10);

            var foundPoints = searcher.Search(1200050, 2600000, 1200060, 2600010, 0.0).ToList();

            Assert.AreEqual(0, foundPoints.Count);

            foundPoints = searcher.Search(1200000, 2600000, 1200000, 2600000, 0.1).ToList();
            Assert.AreEqual(1, foundPoints.Count);
        }
        public void CanSearchPoints()
        {
            var points =
                new[]
            {
                new Pnt3D(1200000, 2600000, 10),
                new Pnt3D(1200010, 2600000, 20),
                new Pnt3D(1200020, 2600000, 30),
                new Pnt3D(1200030, 2600000, 40),
                new Pnt3D(1200040, 2600000, 50),
                new Pnt3D(1200050, 2600000, 60),
                new Pnt3D(1200060, 2600000, 70),
                new Pnt3D(1200070, 2600000, 80),
                new Pnt3D(1200080, 2600000, 90),
                new Pnt3D(1200090, 2600000, 100),
                new Pnt3D(1200100, 2600000, 110),
                new Pnt3D(1200000, 2600010, 120),
                new Pnt3D(1200000, 2600020, 130),
                new Pnt3D(1200000, 2600030, 140),
            };

            SpatialHashSearcher <Pnt3D> searcher =
                SpatialHashSearcher <Pnt3D> .CreateSpatialSearcher(points, p => new EnvelopeXY(p));

            var foundPoints = searcher.Search(1200050, 2600000, 1200060, 2600010, 0.0).ToList();

            Assert.AreEqual(2, foundPoints.Count);
        }
        public void SearchBetweenVeryDifferentExtentsSizes()
        {
            Linestring l1 = new Linestring(
                new[]
            {
                new Pnt3D(1200000, 2600000, 10),
                new Pnt3D(1200000, 2600000, 20),
                new Pnt3D(1200000, 2600000, 30),
                new Pnt3D(1200000, 2600000, 40),
                new Pnt3D(1200000, 2600000, 50),
                new Pnt3D(1200000, 2600000, 60),
                new Pnt3D(1200000, 2600000, 70),
                new Pnt3D(1200000, 2600000, 80),
                new Pnt3D(1200000, 2600000, 90),
                new Pnt3D(1200000, 2600000, 100),
                new Pnt3D(1200000, 2600000, 110),
                new Pnt3D(1200000, 2600000, 120),
                new Pnt3D(1200000, 2600000, 130),
                new Pnt3D(1200000, 2600000, 140),
            });

            l1.SpatialIndex = SpatialHashSearcher <int> .CreateSpatialSearcher(l1, 0.01);

            Stopwatch watch = Stopwatch.StartNew();

            List <KeyValuePair <int, Line3D> > found =
                l1.FindSegments(1000000, 2400000, 1400000, 2800000, 0.01).ToList();

            watch.Stop();

            Assert.AreEqual(l1.SegmentCount, found.Count);

            Assert.Less(watch.ElapsedMilliseconds, 50);
        }
예제 #4
0
        public void InsertLinestring(int index, Linestring linestring)
        {
            Linestrings.Insert(index, linestring);

            UpdateBounds(linestring);

            SpatialIndex = null;

            CacheStartIndexes();
        }
예제 #5
0
        public void SetEmpty()
        {
            Linestrings.Clear();

            XMin = double.NaN;
            YMin = double.NaN;
            XMax = double.NaN;
            YMax = double.NaN;

            SpatialIndex = null;
        }
예제 #6
0
        public int?FindPointIdx([NotNull] Pnt3D point, bool inXY,
                                double tolerance   = double.Epsilon,
                                bool allowIndexing = true)
        {
            if (SpatialIndex == null && allowIndexing &&
                SegmentCount > AllowIndexingThreshold)
            {
                SpatialIndex = SpatialHashSearcher <int> .CreateSpatialSearcher(this);
            }

            if (SpatialIndex != null)
            {
                foreach (int foundSegmentIdx in SpatialIndex.Search(point, tolerance))
                {
                    Line3D segment = this[foundSegmentIdx];

                    bool found = inXY
                                                             ? segment.StartPoint.EqualsXY(point, tolerance)
                                                             : segment.StartPoint.Equals(point, tolerance);

                    if (found)
                    {
                        return(foundSegmentIdx);
                    }
                }
            }
            else
            {
                for (var i = 0; i < SegmentCount; i++)
                {
                    bool found = inXY
                                                             ? _segments[i].StartPoint.EqualsXY(point, tolerance)
                                                             : _segments[i].StartPoint.Equals(point, tolerance);

                    if (found)
                    {
                        return(i);
                    }
                }
            }

            bool isEndPoint = inXY
                                                  ? EndPoint.EqualsXY(point, tolerance)
                                                  : EndPoint.Equals(point, tolerance);

            if (isEndPoint)
            {
                return(PointCount - 1);
            }

            return(null);
        }
예제 #7
0
        public bool RemoveLinestring(Linestring linestring)
        {
            bool result = Linestrings.Remove(linestring);

            foreach (Linestring l in Linestrings)
            {
                UpdateBounds(l);
            }

            SpatialIndex = null;

            CacheStartIndexes();

            return(result);
        }
예제 #8
0
        public static Overlaps GetSelectableOverlaps(
            [NotNull] IEnumerable <IFeature> sourceFeatures,
            [NotNull] IList <IFeature> overlappingFeatures,
            [CanBeNull] ITrackCancel trackCancel = null)
        {
            var result = new Overlaps();

            Stopwatch watch = Stopwatch.StartNew();

            var sourceCount = 0;

            if (overlappingFeatures.Count == 0)
            {
                return(result);
            }

            SpatialHashSearcher <IFeature> targetIndex =
                SpatialHashSearcher <IFeature> .CreateSpatialSearcher(
                    overlappingFeatures, GetEnvelope);

            foreach (IFeature sourceFeature in sourceFeatures)
            {
                if (trackCancel != null && !trackCancel.Continue())
                {
                    _msg.Debug("Overlaps calculation was cancelled.");
                    return(result);
                }

                result.AddGeometries(
                    new GdbObjectReference(sourceFeature),
                    GetSelectableOverlaps(sourceFeature, targetIndex, result.Notifications,
                                          trackCancel).ToList());

                _msg.DebugFormat(
                    "Calculated overlaps for source feature {0}. Current overlaps count: {1}",
                    GdbObjectUtils.ToString(sourceFeature), result.OverlapCount);

                sourceCount++;
            }

            _msg.DebugStopTiming(watch,
                                 "Calculated {0} overlaps between {1} source and {2} target features.",
                                 result.OverlapCount, sourceCount, overlappingFeatures.Count);

            return(result);
        }
예제 #9
0
        public IEnumerable <int> FindPointIndexes([NotNull] IPnt searchPoint,
                                                  double tolerance     = double.Epsilon,
                                                  bool useSearchCircle = false,
                                                  bool allowIndexing   = true)
        {
            if (SpatialIndex == null && allowIndexing &&
                PointCount > AllowIndexingThreshold)
            {
                SpatialIndex = SpatialHashSearcher <int> .CreateSpatialSearcher(this);
            }

            if (SpatialIndex != null)
            {
                // No need to add the tolerance to the search box, it is added by the index
                foreach (int foundPointIdx in SpatialIndex.Search(
                             searchPoint.X, searchPoint.Y, searchPoint.X, searchPoint.Y, tolerance))
                {
                    T foundPoint = _points[foundPointIdx];

                    bool withinTolerance =
                        IsWithinTolerance(foundPoint, searchPoint, tolerance, useSearchCircle);

                    if (withinTolerance)
                    {
                        yield return(foundPointIdx);
                    }
                }
            }
            else
            {
                for (var i = 0; i < PointCount; i++)
                {
                    bool withinTolerance =
                        IsWithinTolerance(_points[i], searchPoint, tolerance, useSearchCircle);

                    if (withinTolerance)
                    {
                        yield return(i);
                    }
                }
            }
        }
예제 #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FeatureCutter"/> class.
        /// </summary>
        /// <param name="featuresToCut">The features that shall be cut.</param>
        /// <param name="networkFeatureCutter">An optional legacy geometric network edge cutter
        /// implementation.</param>
        public FeatureCutter(IList <IFeature> featuresToCut,
                             [CanBeNull] INetworkFeatureCutter networkFeatureCutter = null)
        {
            Assert.ArgumentNotNull(featuresToCut, nameof(featuresToCut));

            _featuresToCut        = featuresToCut;
            _networkFeatureCutter = networkFeatureCutter;

            if (featuresToCut.Count > 100)
            {
                _spatialIndex =
                    SpatialHashSearcher <IFeature> .CreateSpatialSearcher(
                        _featuresToCut, GetEnvelopeXY);
            }

            RefreshArea = new EnvelopeClass();
            ResultGeometriesByFeature  = new Dictionary <IFeature, IList <IGeometry> >();
            ResultFeatures             = new List <IFeature>();
            InsertedFeaturesByOriginal =
                new List <KeyValuePair <IFeature, IList <IFeature> > >(featuresToCut.Count);
        }
예제 #11
0
        public static Linestring CreateLinestring([NotNull] IGeometry path,
                                                  int createSpatialIndexThreshold = 300)
        {
            Assert.ArgumentCondition(!GeometryUtils.HasNonLinearSegments(path),
                                     "Non-linear segments");

            List <Pnt3D> path2Pnts3D = GetPntList(path);

            var linestring = new Linestring(path2Pnts3D);

            if (linestring.SegmentCount > createSpatialIndexThreshold)
            {
                double gridSize = ((ICurve)path).Length / linestring.SegmentCount;

                linestring.SpatialIndex =
                    SpatialHashSearcher <int> .CreateSpatialSearcher(linestring, gridSize);

                //linestring.SpatialIndex = BoxTreeSearcher<int>.CreateSpatialSearcher(linestring);
            }

            return(linestring);
        }
예제 #12
0
        public IEnumerable <KeyValuePair <int, Line3D> > FindSegments(
            double xMin, double yMin, double xMax, double yMax,
            double tolerance, bool allowIndexing = true, Predicate <int> predicate = null)
        {
            if (SpatialIndex == null && allowIndexing &&
                SegmentCount > AllowIndexingThreshold)
            {
                SpatialIndex = SpatialHashSearcher <int> .CreateSpatialSearcher(this);
            }

            if (SpatialIndex != null)
            {
                foreach (int index in SpatialIndex.Search(
                             xMin, yMin, xMax, yMax, this, tolerance, predicate))
                {
                    Line3D segment = _segments[index];
                    if (segment.ExtentIntersectsXY(xMin, yMin, xMax, yMax, tolerance))
                    {
                        yield return(new KeyValuePair <int, Line3D>(index, segment));
                    }
                }
            }
            else
            {
                for (int i = 0; i < SegmentCount; i++)
                {
                    if (predicate != null && !predicate(i))
                    {
                        continue;
                    }

                    Line3D segment = this[i];
                    if (segment.ExtentIntersectsXY(xMin, yMin, xMax, yMax, tolerance))
                    {
                        yield return(new KeyValuePair <int, Line3D>(i, segment));
                    }
                }
            }
        }
예제 #13
0
        private static ISpatialSearcher <int> CreateSpatialHash(Linestring linestring)
        {
            MemoryUsageInfo memUsageHash = new MemoryUsageInfo();
            var             watch        = Stopwatch.StartNew();

            var gridSize =
                SpatialHashSearcher <int> .EstimateOptimalGridSize(new[] { linestring });

            watch.Stop();
            Console.WriteLine(
                $"Linestring ({linestring.PointCount}) - Spatial hash: calculated grid size: {watch.ElapsedMilliseconds}ms. PB: {memUsageHash.Refresh().PrivateBytesDelta:N0}");

            watch = Stopwatch.StartNew();

            var result =
                SpatialHashSearcher <int> .CreateSpatialSearcher(linestring, gridSize);

            watch.Stop();
            Console.WriteLine(
                $"Linestring ({linestring.PointCount}) - Spatial hash created: {watch.ElapsedMilliseconds}ms. PB: {memUsageHash.Refresh().PrivateBytesDelta:N0}");

            return(result);
        }
예제 #14
0
        public static IEnumerable <IGeometry> GetSelectableOverlaps(
            [NotNull] IFeature sourceFeature,
            [NotNull] SpatialHashSearcher <IFeature> overlappingFeatures,
            [CanBeNull] NotificationCollection notifications = null,
            [CanBeNull] ITrackCancel trackCancel             = null)
        {
            IGeometry sourceGeometry = sourceFeature.Shape;

            if (sourceGeometry == null || sourceGeometry.IsEmpty)
            {
                yield break;
            }

            IEnvelope sourceEnvelope = sourceGeometry.Envelope;

            double tolerance = GeometryUtils.GetXyTolerance(sourceGeometry);

            foreach (IFeature targetFeature in overlappingFeatures.Search(
                         sourceEnvelope.XMin, sourceEnvelope.YMin,
                         sourceEnvelope.XMax, sourceEnvelope.YMax, tolerance))
            {
                if (trackCancel != null && !trackCancel.Continue())
                {
                    yield break;
                }

                _msg.VerboseDebugFormat("Calculating overlap from {0}",
                                        GdbObjectUtils.ToString(targetFeature));

                IGeometry targetGeometry = targetFeature.Shape;

                if (GeometryUtils.Disjoint(targetGeometry, sourceGeometry))
                {
                    continue;
                }

                if (GeometryUtils.Contains(targetGeometry, sourceGeometry))
                {
                    // Idea for the future: Optionally allow also deleting features (probably using a black display feedback)
                    NotificationUtils.Add(notifications,
                                          "Source feature {0} is completely within target {1} and would become empty if the overlap was removed. The overlap is supressed.",
                                          RowFormat.Format(sourceFeature),
                                          RowFormat.Format(targetFeature));
                    continue;
                }

                if (sourceGeometry.GeometryType == esriGeometryType.esriGeometryMultiPatch)
                {
                    sourceGeometry = GeometryFactory.CreatePolygon(sourceGeometry);
                }

                IGeometry intersection = TryGetIntersection(sourceGeometry, targetGeometry);

                if (intersection == null)
                {
                    continue;
                }

                if (GeometryUtils.GetPartCount(intersection) > 1)
                {
                    foreach (var part in GeometryUtils.Explode(intersection))
                    {
                        yield return(part);
                    }
                }
                else
                {
                    yield return(intersection);
                }
            }
        }
예제 #15
0
        public void CompareSpatialIndexPerformance()
        {
            const int pointCount = 100000;

            Linestring linestring1 =
                new Linestring(CreateRandomPoints(pointCount, 2600000, 1200000, 400));

            Linestring linestring2 =
                new Linestring(CreateRandomPoints(pointCount, 2600000, 1200000, 400));

            Stopwatch watch;
            int       foundCountBoxtree;
            int       foundSpatialHash;
            int       envelopeIntersections;
            double    tolerance = 0.01;

            MemoryUsageInfo memUsageBox = new MemoryUsageInfo();

            watch = Stopwatch.StartNew();

            linestring2.SpatialIndex =
                BoxTreeSearcher <int> .CreateSpatialSearcher(linestring2);

            watch.Stop();

            Console.WriteLine(
                $"Linestring ({pointCount}) - Box tree created: {watch.ElapsedMilliseconds}ms. PB: {memUsageBox.Refresh().PrivateBytesDelta:N0}");

            watch                 = Stopwatch.StartNew();
            foundCountBoxtree     = 0;
            envelopeIntersections = 0;
            foreach (Line3D line3D in linestring1)
            {
                int foundInEnv = linestring2.FindSegments(
                    line3D.XMin, line3D.YMin, line3D.XMax,
                    line3D.YMax, tolerance).Count();

                if (foundInEnv > 0)
                {
                    envelopeIntersections++;
                }

                foundCountBoxtree += foundInEnv;
            }

            watch.Stop();

            Console.WriteLine(
                $"Linestring ({pointCount}) - Box tree ({foundCountBoxtree} segments found): {watch.ElapsedMilliseconds}ms");

            MemoryUsageInfo memUsageHash = new MemoryUsageInfo();

            watch = Stopwatch.StartNew();

            linestring2.SpatialIndex = CreateSpatialHash(linestring2);

            watch.Stop();
            Console.WriteLine(
                $"Linestring ({pointCount}) - spatial hash created: {watch.ElapsedMilliseconds}ms. PB: {memUsageHash.Refresh().PrivateBytesDelta:N0}");

            watch                 = Stopwatch.StartNew();
            foundSpatialHash      = 0;
            envelopeIntersections = 0;
            foreach (Line3D line3D in linestring1)
            {
                int foundInEnv = linestring2.FindSegments(
                    line3D.XMin, line3D.YMin, line3D.XMax,
                    line3D.YMax, tolerance).Count();

                if (foundInEnv > 0)
                {
                    envelopeIntersections++;
                }

                foundSpatialHash += foundInEnv;
            }

            watch.Stop();

            Console.WriteLine(
                $"Linestring ({pointCount}) - Spatial hash ({foundSpatialHash} segments found): {watch.ElapsedMilliseconds}ms");

            Assert.AreEqual(foundCountBoxtree, foundSpatialHash);

            MultiPolycurve poly2 = new MultiPolycurve(new List <Linestring> {
                linestring2
            });

            memUsageHash.Refresh();
            watch = Stopwatch.StartNew();

            poly2.SpatialIndex =
                SpatialHashSearcher <SegmentIndex> .CreateSpatialSearcher(poly2);

            watch.Stop();

            Console.WriteLine(
                $"Linestring ({pointCount}) - spatial hash (using multi-part index) created: {watch.ElapsedMilliseconds}ms. PB: {memUsageHash.Refresh().PrivateBytesDelta:N0}");

            watch                 = Stopwatch.StartNew();
            foundSpatialHash      = 0;
            envelopeIntersections = 0;
            foreach (Line3D line3D in linestring1)
            {
                int foundInEnv = poly2.FindSegments(
                    line3D.XMin, line3D.YMin, line3D.XMax,
                    line3D.YMax, tolerance).Count();

                if (foundInEnv > 0)
                {
                    envelopeIntersections++;
                }

                foundSpatialHash += foundInEnv;
            }

            watch.Stop();

            Console.WriteLine(
                $"Linestring ({pointCount}) - Spatial hash on poly ({foundSpatialHash} segments found): {watch.ElapsedMilliseconds}ms");
            Assert.AreEqual(foundCountBoxtree, foundSpatialHash);
        }
예제 #16
0
        public IEnumerable <KeyValuePair <int, Line3D> > FindSegments(
            double xMin, double yMin, double xMax, double yMax,
            double tolerance, bool allowIndexing = true, Predicate <int> predicate = null)
        {
            if (SpatialIndex == null && allowIndexing &&
                SegmentCount > AllowIndexingThreshold)
            {
                SpatialIndex = SpatialHashSearcher <SegmentIndex> .CreateSpatialSearcher(this);
            }

            Predicate <SegmentIndex> multipartIndexPredicate = null;

            if (predicate != null)
            {
                multipartIndexPredicate =
                    found =>
                {
                    int globalIdx = GetGlobalSegmentIndex(found.PartIndex, found.LocalIndex);

                    return(predicate(globalIdx));
                };
            }

            // NOTE: Using SpatialHashSearcher<int> and converting to local segment indexes is much slower!
            //       -> consider optimized MultiLinestring that is based off one long array of points (WKSPoint structs?)
            if (SpatialIndex != null)
            {
                foreach (SegmentIndex segmentIndex in SpatialIndex.Search(
                             xMin, yMin, xMax, yMax, this, tolerance, multipartIndexPredicate))
                {
                    Line3D segment = GetSegment(segmentIndex.PartIndex, segmentIndex.LocalIndex);

                    if (segment.ExtentIntersectsXY(
                            xMin, yMin, xMax, yMax, tolerance))
                    {
                        yield return(new KeyValuePair <int, Line3D>(
                                         GetGlobalSegmentIndex(segmentIndex.PartIndex, segmentIndex.LocalIndex),
                                         segment));
                    }
                }
            }
            else
            {
                int i = 0;
                foreach (Line3D segment in this)
                {
                    if (predicate != null && !predicate(i))
                    {
                        continue;
                    }

                    if (segment.ExtentIntersectsXY(
                            xMin, yMin, xMax, yMax, tolerance))
                    {
                        //var identifier = new SegmentIndex(p, s);
                        yield return(new KeyValuePair <int, Line3D>(i, segment));
                    }

                    i++;
                }
            }
        }