private void CheckEdges(SubdivisionSearch search)
        {
            foreach (SubdivisionEdge edge in search.Source.Edges.Values)
            {
                var edgeElement = new SubdivisionElement(edge);
                var twinElement = new SubdivisionElement(edge._twin);

                // SubdivisionSearch always returns lexicographically increasing half-edges
                PointD start = edge._origin, end = edge._twin._origin;
                int    result  = PointDComparerX.CompareEpsilon(start, end, search.Source.Epsilon);
                var    element = (result < 0 ? edgeElement : twinElement);

                PointD q = new PointD((start.X + end.X) / 2, (start.Y + end.Y) / 2);
                Assert.AreEqual(element, search.Find(q));

                // brute force search may return half-edge or its twin
                var found = search.Source.Find(q, 1e-10);
                Assert.IsTrue(found == edgeElement || found == twinElement);

                // brute force search also supports comparison epsilon
                PointD offset = GeoAlgorithms.RandomPoint(-0.1, -0.1, 0.2, 0.2);
                found = search.Source.Find(q + offset, 0.25);
                Assert.IsTrue(found == edgeElement || found == twinElement);
            }
        }
        private void CheckVertices(SubdivisionSearch search)
        {
            foreach (PointD vertex in search.Source.Vertices.Keys)
            {
                var element = new SubdivisionElement(vertex);
                Assert.AreEqual(element, search.Find(vertex));
                Assert.AreEqual(element, search.Source.Find(vertex));

                // brute force search also supports comparison epsilon
                PointD offset = GeoAlgorithms.RandomPoint(-0.1, -0.1, 0.2, 0.2);
                Assert.AreEqual(element, search.Source.Find(vertex + offset, 0.25));
            }
        }
        public void Empty()
        {
            var search = new SubdivisionSearch(new Subdivision());

            search.Validate();

            for (int i = 0; i < 10; i++)
            {
                PointD q = GeoAlgorithms.RandomPoint(-100, -100, 200, 200);
                Assert.IsTrue(search.Find(q).IsUnboundedFace);
                Assert.IsTrue(search.Source.Find(q).IsUnboundedFace);
            }
        }
        private SubdivisionSearch CheckSearch(params LineD[] lines)
        {
            Subdivision division = Subdivision.FromLines(lines);

            division.Validate();
            SubdivisionSearch search = new SubdivisionSearch(division);

            search.Validate();
            CheckVertices(search);
            CheckEdges(search);

            PointD[] points = new[] {
                new PointD(+1, +1), new PointD(+1, -1),
                new PointD(-1, +1), new PointD(-1, -1)
            };

            if (division.Faces.Count == 1)
            {
                foreach (PointD point in points)
                {
                    Assert.IsTrue(search.Find(point).IsUnboundedFace);
                    Assert.IsTrue(division.Find(point).IsUnboundedFace);
                }
            }
            else
            {
                var element = new SubdivisionElement(division.Faces[1]);
                foreach (PointD point in points)
                {
                    Assert.AreEqual(element, search.Find(point));
                    Assert.AreEqual(element, division.Find(point));
                }
            }

            points = new[] {
                new PointD(+10, +10), new PointD(+10, -10),
                new PointD(-10, +10), new PointD(-10, -10)
            };

            foreach (PointD point in points)
            {
                Assert.IsTrue(search.Find(point).IsUnboundedFace);
                Assert.IsTrue(division.Find(point).IsUnboundedFace);
            }
            return(search);
        }
        private SubdivisionSearch CheckSearch(Subdivision division)
        {
            division.Validate();
            SubdivisionSearch search = new SubdivisionSearch(division);

            search.Validate();
            CheckVertices(search);
            CheckEdges(search);

            foreach (SubdivisionFace face in division.Faces.Values)
            {
                if (face.OuterEdge == null)
                {
                    continue;
                }
                PointD centroid = face.OuterEdge.CycleCentroid;
                var    element  = new SubdivisionElement(face);
                Assert.AreEqual(element, search.Find(centroid));
                Assert.AreEqual(element, division.Find(centroid));
            }

            return(search);
        }
Example #6
0
        private void SubdivisionSearchTest(bool random)
        {
            Stopwatch timer     = new Stopwatch();
            var       testCases = _subdivSearchTestCases;

            Output(String.Format("{0,6}", " "));
            foreach (TestCase test in testCases)
            {
                Output(String.Format("{0,12}", test.Name));
            }
            Output("\n");

            const int outerLoop = 100, innerLoop = 200;
            const int iterations = outerLoop * innerLoop;

            PointD[] query = new PointD[innerLoop];

            PolygonGrid grid = null;
            int         sizeMin, sizeMax, sizeStep;

            if (random)
            {
                sizeMin = 100; sizeMax = 1200; sizeStep = 100;
            }
            else
            {
                sizeMin = 6; sizeMax = 30; sizeStep = 2;
                RegularPolygon polygon = new RegularPolygon(10, 4, PolygonOrientation.OnEdge);
                grid = new PolygonGrid(polygon);
            }

            for (int size = sizeMin; size <= sizeMax; size += sizeStep)
            {
                Subdivision division;
                if (random)
                {
                    // create subdivision from random lines (few faces)
                    division = CreateSubdivision(size, 1e-10);
                }
                else
                {
                    // create subdivision from grid of diamonds (many faces)
                    grid.Element = new RegularPolygon(900 / size, 4, PolygonOrientation.OnEdge);
                    grid.Size    = new SizeI(size, size);
                    division     = grid.ToSubdivision(PointD.Empty).Source;
                }
                var ordered    = new SubdivisionSearch(division, true);
                var randomized = new SubdivisionSearch(division, false);

                // test cases: BruteForce, Ordered, Randomized
                testCases[0].FindSubdivision = (q) => division.Find(q, division.Epsilon);
                testCases[1].FindSubdivision = (q) => ordered.Find(q);
                testCases[2].FindSubdivision = (q) => randomized.Find(q);

                // trigger JIT compilation and reset ticks
                foreach (TestCase test in testCases)
                {
                    test.FindSubdivision(PointD.Empty);
                    test.Ticks = 0;
                }

                for (int j = 0; j < outerLoop; j++)
                {
                    for (int k = 0; k < query.Length; k++)
                    {
                        query[k] = GeoAlgorithms.RandomPoint(0, 0, 1000, 1000);
                    }

                    foreach (TestCase test in testCases)
                    {
                        timer.Restart();
                        for (int k = 0; k < query.Length; k++)
                        {
                            test.FindSubdivision(query[k]);
                        }

                        timer.Stop();
                        test.Ticks += timer.ElapsedTicks;
                    }
                }

                Output(String.Format("{0,6:N0}", division.Edges.Count / 2));
                foreach (TestCase test in testCases)
                {
                    Output(String.Format("{0,12:N2}", AverageMicrosecs(test.Ticks, iterations)));
                }
                Output("\n");
            }

            Output("\nTimes are µsec averages for subdivisions of the indicated edge count,\n");
            if (random)
            {
                Output("based on random line sets (few faces, completely random edges).\n");
            }
            else
            {
                Output("based on grids of squares (many faces, strictly ordered edges).\n");
            }
        }