Пример #1
0
        /// <summary>
        /// Converts all <see cref="DelaunayEdges"/> to a planar <see cref="Subdivision"/>, using
        /// the specified clipping bounds.</summary>
        /// <param name="bounds">
        /// A <see cref="RectD"/> that indicates the clipping bounds for all <see
        /// cref="DelaunayEdges"/>.</param>
        /// <param name="addRegions">
        /// <c>true</c> to add all <see cref="VoronoiRegions"/> with the corresponding <see
        /// cref="GeneratorSites"/> to the <see cref="Subdivision.VertexRegions"/> collection of the
        /// new <see cref="Subdivision"/>; otherwise, <c>false</c>.</param>
        /// <returns>
        /// A new <see cref="Subdivision"/> whose <see cref="Subdivision.Edges"/> correspond to the
        /// <see cref="DelaunayEdges"/> of the <see cref="VoronoiResults"/>.</returns>
        /// <remarks><para>
        /// The specified <paramref name="bounds"/> determine the subset of <see
        /// cref="GeneratorSites"/> and <see cref="DelaunayEdges"/> that is stored in the new <see
        /// cref="Subdivision"/>, as described in <see cref="ClipDelaunayEdges"/>.
        /// </para><para>
        /// If <paramref name="addRegions"/> is <c>true</c>, the polygons added to the <see
        /// cref="Subdivision.VertexRegions"/> collection are also clipped the specified <paramref
        /// name="bounds"/>.</para></remarks>

        public Subdivision ToDelaunySubdivision(RectD bounds, bool addRegions = false)
        {
            LineD[]     edges    = ClipDelaunayEdges(bounds);
            Subdivision division = Subdivision.FromLines(edges);

            if (addRegions)
            {
                for (int i = 0; i < GeneratorSites.Length; i++)
                {
                    PointD site = GeneratorSites[i];
                    if (!bounds.Contains(site))
                    {
                        continue;
                    }

                    PointD[] region;
                    if (bounds.Intersect(VoronoiRegions[i], out region))
                    {
                        division.VertexRegions.Add(site, region);
                    }
                }
            }

            return(division);
        }
Пример #2
0
        public static Subdivision CreateSquareStar(bool test)
        {
            PointD[] points =
            {
                new PointD(), new PointD(-1, -2), new PointD(-1, 2), new PointD(1, 2), new PointD(1, -2)
            };
            LineD[] lines =
            {
                new LineD(points[1], points[2]), new LineD(points[2], points[3]),
                new LineD(points[4], points[3]), new LineD(points[1], points[4]),
                new LineD(points[0], points[1]), new LineD(points[0], points[2]),
                new LineD(points[0], points[3]), new LineD(points[0], points[4])
            };
            var division = Subdivision.FromLines(lines);

            division.Validate();
            if (!test)
            {
                return(division);
            }

            var edges = division.Edges.Values;
            var faces = division.Faces.Values;

            Assert.AreEqual(16, edges.Count);
            Assert.AreEqual(5, faces.Count);

            CollectionAssert.AreEqual(new[] {
                new SubdivisionEdge(0, points[1], edges[1], faces[0], edges[2], edges[7]),
                new SubdivisionEdge(1, points[2], edges[0], faces[1], edges[9], edges[10]),
                new SubdivisionEdge(2, points[2], edges[3], faces[0], edges[5], edges[0]),
                new SubdivisionEdge(3, points[3], edges[2], faces[2], edges[11], edges[12]),
                new SubdivisionEdge(4, points[4], edges[5], faces[3], edges[13], edges[14]),
                new SubdivisionEdge(5, points[3], edges[4], faces[0], edges[7], edges[2]),
                new SubdivisionEdge(6, points[1], edges[7], faces[4], edges[15], edges[8]),
                new SubdivisionEdge(7, points[4], edges[6], faces[0], edges[0], edges[5]),

                new SubdivisionEdge(8, points[0], edges[9], faces[4], edges[6], edges[15]),
                new SubdivisionEdge(9, points[1], edges[8], faces[1], edges[10], edges[1]),
                new SubdivisionEdge(10, points[0], edges[11], faces[1], edges[1], edges[9]),
                new SubdivisionEdge(11, points[2], edges[10], faces[2], edges[12], edges[3]),
                new SubdivisionEdge(12, points[0], edges[13], faces[2], edges[3], edges[11]),
                new SubdivisionEdge(13, points[3], edges[12], faces[3], edges[14], edges[4]),
                new SubdivisionEdge(14, points[0], edges[15], faces[3], edges[4], edges[13]),
                new SubdivisionEdge(15, points[4], edges[14], faces[4], edges[8], edges[6]),
            }, edges);


            var cycles = division.GetZeroAreaCycles();

            Assert.AreEqual(0, cycles.Count);
            return(division);
        }
Пример #3
0
        /// <overloads>
        /// Converts all <see cref="DelaunayEdges"/> to a planar <see cref="Subdivision"/>.
        /// </overloads>
        /// <summary>
        /// Converts all <see cref="DelaunayEdges"/> to a planar <see cref="Subdivision"/>, using
        /// the default <see cref="ClippingBounds"/>.</summary>
        /// <param name="addRegions">
        /// <c>true</c> to add all <see cref="VoronoiRegions"/> with the corresponding <see
        /// cref="GeneratorSites"/> to the <see cref="Subdivision.VertexRegions"/> collection of the
        /// new <see cref="Subdivision"/>; otherwise, <c>false</c>.</param>
        /// <returns>
        /// A new <see cref="Subdivision"/> whose <see cref="Subdivision.Edges"/> correspond to the
        /// <see cref="DelaunayEdges"/> of the <see cref="VoronoiResults"/>.</returns>

        public Subdivision ToDelaunySubdivision(bool addRegions = false)
        {
            Subdivision division = Subdivision.FromLines(DelaunayEdges);

            if (addRegions)
            {
                for (int i = 0; i < GeneratorSites.Length; i++)
                {
                    division.VertexRegions.Add(GeneratorSites[i], VoronoiRegions[i]);
                }
            }

            return(division);
        }
Пример #4
0
        public void IGraph2DTest()
        {
            PointD[] points =
            {
                new PointD(0,  0), new PointD(-1, -2),
                new PointD(-1, 2), new PointD(1,   2),new PointD(1, -2)
            };
            LineD[] lines =
            {
                new LineD(points[0], points[1]), new LineD(points[0], points[2]),
                new LineD(points[0], points[3]), new LineD(points[4], points[0])
            };
            var division = Subdivision.FromLines(lines);

            division.Validate();
            var graph = division as IGraph2D <PointD>;

            Assert.AreEqual(4, graph.Connectivity);
            Assert.AreEqual(5, graph.NodeCount);
            foreach (PointD node in graph.Nodes)
            {
                CollectionAssert.Contains(points, node);
            }

            foreach (PointD point in points)
            {
                Assert.IsTrue(graph.Contains(point));
                Assert.AreEqual(point, graph.GetWorldLocation(point));

                PointD near = new PointD(point.X + 0.1, point.Y - 0.1);
                Assert.IsFalse(graph.Contains(near));
                Assert.AreEqual(point, graph.GetNearestNode(near));
            }

            var    center    = new[] { points[0] };
            var    neighbors = new PointD[points.Length - 1];
            double distance  = Math.Sqrt(5.0);

            for (int i = 1; i < points.Length; i++)
            {
                Assert.AreEqual(distance, graph.GetDistance(points[0], points[i]));
                CollectionAssert.AreEquivalent(center, graph.GetNeighbors(points[i]));
                neighbors[i - 1] = points[i];
            }

            CollectionAssert.AreEquivalent(neighbors, graph.GetNeighbors(points[0]));
        }
        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);
        }
Пример #6
0
        public void FindEdgeEpsilon()
        {
            PointD[] points =
            {
                new PointD(0,  0), new PointD(-1, -2),
                new PointD(-1, 2), new PointD(1,   2),new PointD(1, -2)
            };
            LineD[] lines =
            {
                new LineD(points[1], points[0]), new LineD(points[0], points[2]),
                new LineD(points[0], points[3]), new LineD(points[4], points[0])
            };
            var division = Subdivision.FromLines(lines, 0.2);

            division.Validate();

            // check all existing half-edges
            PointD offset = new PointD(0.1, -0.1);

            foreach (SubdivisionEdge edge in division.Edges.Values)
            {
                Assert.AreSame(edge, division.FindEdge(edge.Origin, edge.Destination));
                Assert.AreSame(edge, division.FindEdge(
                                   edge.Origin.Add(offset), edge.Destination.Add(offset)));
            }

            for (int i = 0; i < points.Length; i++)
            {
                // check half-edges including one non-existing vertex
                Assert.IsNull(division.FindEdge(points[i], new PointD(1, 0)));
                Assert.IsNull(division.FindEdge(new PointD(1, 0), points[i]));

                // check nonexistent half-edges between vertices
                if (i == 0)
                {
                    continue;
                }
                for (int j = 1; j < points.Length; j++)
                {
                    if (j != i)
                    {
                        Assert.IsNull(division.FindEdge(points[i], points[j]));
                    }
                }
            }
        }
Пример #7
0
        public void FromLinesVertical()
        {
            PointD[] points =
            {
                new PointD(-1, -2), new PointD(-1, 2), new PointD(1, -2), new PointD(1, 2)
            };
            LineD[] lines =
            {
                new LineD(points[0], points[1]), new LineD(points[2], points[3])
            };
            var division = Subdivision.FromLines(lines);

            division.Validate();

            CollectionAssert.AreEquivalent(lines, division.ToLines());
            var edges = division.Edges.Values;
            var faces = division.Faces.Values;

            CollectionAssert.AreEqual(new[] {
                new VertexPair(points[0], edges[0]),
                new VertexPair(points[2], edges[2]),
                new VertexPair(points[1], edges[1]),
                new VertexPair(points[3], edges[3]),
            }, division.Vertices);

            CollectionAssert.AreEqual(new[] {
                new SubdivisionEdge(0, points[0], edges[1], faces[0], edges[1], edges[1]),
                new SubdivisionEdge(1, points[1], edges[0], faces[0], edges[0], edges[0]),
                new SubdivisionEdge(2, points[2], edges[3], faces[0], edges[3], edges[3]),
                new SubdivisionEdge(3, points[3], edges[2], faces[0], edges[2], edges[2]),
            }, edges);

            CollectionAssert.AreEqual(new[] {
                new SubdivisionFace(division, 0, null, new[] { edges[0], edges[2] }),
            }, faces);

            CheckFace(edges[0], new[] { points[0], points[1] }, 0, PointD.Empty);
            CheckFace(edges[2], new[] { points[2], points[3] }, 0, PointD.Empty);

            var cycles = division.GetZeroAreaCycles();

            Assert.AreEqual(2, cycles.Count);
            Assert.AreEqual(edges[0], cycles[0]);
            Assert.AreEqual(edges[2], cycles[1]);
        }
Пример #8
0
        public void FromLinesSquare()
        {
            PointD[] points =
            {
                new PointD(-1, -2), new PointD(-1, 2), new PointD(1, 2), new PointD(1, -2)
            };
            LineD[] lines =
            {
                new LineD(points[0], points[1]), new LineD(points[1], points[2]),
                new LineD(points[3], points[2]), new LineD(points[0], points[3])
            };
            var division = Subdivision.FromLines(lines);

            division.Validate();

            CollectionAssert.AreEquivalent(lines, division.ToLines());
            CheckLinesSquare(points, division);
        }
Пример #9
0
        private void PasteCommandExecuted(object sender, ExecutedRoutedEventArgs args)
        {
            args.Handled = true;

            try {
                string      text     = Clipboard.GetText();
                LineD[]     lines    = XmlSerialization.Deserialize <LineD[]>(text);
                Subdivision division = Subdivision.FromLines(lines);
                DrawSubdivision(division);
            }
            catch (Exception e) {
                MessageDialog.Show(this,
                                   "An error occurred while attempting to\n" +
                                   "paste a new subdivision from the clipboard.",
                                   Strings.ClipboardPasteError, e, MessageBoxButton.OK,
                                   WindowsUtility.GetSystemBitmap(MessageBoxImage.Error));
            }
        }
Пример #10
0
        public void FromLinesSquareEpsilon()
        {
            PointD[] points =
            {
                new PointD(-1, -2), new PointD(-1, 2), new PointD(1, 2), new PointD(1, -2)
            };
            LineD[] lines =
            {
                new LineD(points[0],       points[1]),
                new LineD(new PointD(-1.1,           1.9),points[2]),
                new LineD(points[3],       new PointD(0.9,          2.1)),
                new LineD(new PointD(-0.9,          -2.1),new PointD(1.1, -1.9))
            };
            var division = Subdivision.FromLines(lines, 0.2);

            division.Validate();

            CollectionAssert.AreNotEquivalent(lines, division.ToLines());
            CheckLinesSquare(points, division);
        }
Пример #11
0
        /// <summary>
        /// Creates a random <see cref="Subdivision"/> with the specified number of full edges and
        /// comparison epsilon.</summary>
        /// <param name="size">
        /// The number of full edges, i.e. half the number of <see cref="Subdivision.Edges"/>, in
        /// the returned <see cref="Subdivision"/>.</param>
        /// <param name="epsilon">
        /// The maximum absolute difference at which two coordinates should be considered equal.
        /// </param>
        /// <returns>
        /// A new random <see cref="Subdivision"/> with the specified <paramref name="size"/> and
        /// <paramref name="epsilon"/>.</returns>

        private static Subdivision CreateSubdivision(int size, double epsilon)
        {
            LineD[] lines = new LineD[size];
            for (int i = 0; i < size; i++)
            {
                lines[i] = GeoAlgorithms.RandomLine(0, 0, 1000, 1000);
            }

            // split random set into non-intersecting line segments
            var crossings  = MultiLineIntersection.FindSimple(lines, epsilon);
            var splitLines = MultiLineIntersection.Split(lines, crossings);

            Array.Copy(splitLines, lines, size);

            // re-randomize lines to eliminate split ordering
            CollectionsUtility.Randomize(lines);
            Subdivision division = Subdivision.FromLines(lines);

            division.Validate();
            return(division);
        }
Пример #12
0
        private void OnIntersect(object sender, RoutedEventArgs args)
        {
            args.Handled = true;

            RectD  bounds = OutputBounds;
            double x      = bounds.Left + (double)LeftUpDown.Value;
            double y      = bounds.Top + (double)TopUpDown.Value;
            double dx     = (double)WidthUpDown.Value;
            double dy     = (double)HeightUpDown.Value;

            Subdivision rectangle;

            if (sender == RectangleButton)
            {
                rectangle = Subdivision.FromLines(new LineD[] {
                    new LineD(x, y, x + dx, y),
                    new LineD(x + dx, y, x + dx, y + dy),
                    new LineD(x + dx, y + dy, x, y + dy),
                    new LineD(x, y + dy, x, y)
                });
            }
            else if (sender == DiamondButton)
            {
                rectangle = Subdivision.FromLines(new LineD[] {
                    new LineD(x + dx / 2, y, x + dx, y + dy / 2),
                    new LineD(x + dx, y + dy / 2, x + dx / 2, y + dy),
                    new LineD(x + dx / 2, y + dy, x, y + dy / 2),
                    new LineD(x, y + dy / 2, x + dx / 2, y)
                });
            }
            else
            {
                return;
            }

            rectangle.Validate();
            _division = Subdivision.Intersection(_division, rectangle, out _faceKeys);
            _division.Validate();
            SubdivisionTest.DrawSubdivision(OutputBox, FontSize, _division);
        }
Пример #13
0
        public void FromLinesDiamond()
        {
            PointD[] points =
            {
                new PointD(0, -4), new PointD(-6, 0), new PointD(-3, 0),
                new PointD(3,  0), new PointD(6,  0), new PointD(0, 4)
            };
            LineD[] lines =
            {
                new LineD(points[0], points[1]), new LineD(points[1], points[5]),
                new LineD(points[0], points[2]), new LineD(points[2], points[5]),
                new LineD(points[0], points[3]), new LineD(points[3], points[5]),
                new LineD(points[0], points[4]), new LineD(points[4], points[5])
            };
            var division = Subdivision.FromLines(lines);

            division.Validate();

            CollectionAssert.AreEquivalent(lines, division.ToLines());
            var edges = division.Edges.Values;
            var faces = division.Faces.Values;

            CollectionAssert.AreEqual(new[] {
                new VertexPair(points[0], edges[0]),
                new VertexPair(points[1], edges[1]),
                new VertexPair(points[2], edges[5]),
                new VertexPair(points[3], edges[9]),
                new VertexPair(points[4], edges[13]),
                new VertexPair(points[5], edges[3]),
            }, division.Vertices);

            CollectionAssert.AreEqual(new[] {
                new SubdivisionEdge(0, points[0], edges[1], faces[0], edges[2], edges[13]),
                new SubdivisionEdge(1, points[1], edges[0], faces[1], edges[4], edges[3]),
                new SubdivisionEdge(2, points[1], edges[3], faces[0], edges[15], edges[0]),
                new SubdivisionEdge(3, points[5], edges[2], faces[1], edges[1], edges[6]),
                new SubdivisionEdge(4, points[0], edges[5], faces[1], edges[6], edges[1]),
                new SubdivisionEdge(5, points[2], edges[4], faces[2], edges[8], edges[7]),
                new SubdivisionEdge(6, points[2], edges[7], faces[1], edges[3], edges[4]),
                new SubdivisionEdge(7, points[5], edges[6], faces[2], edges[5], edges[10]),
                new SubdivisionEdge(8, points[0], edges[9], faces[2], edges[10], edges[5]),
                new SubdivisionEdge(9, points[3], edges[8], faces[3], edges[12], edges[11]),
                new SubdivisionEdge(10, points[3], edges[11], faces[2], edges[7], edges[8]),
                new SubdivisionEdge(11, points[5], edges[10], faces[3], edges[9], edges[14]),
                new SubdivisionEdge(12, points[0], edges[13], faces[3], edges[14], edges[9]),
                new SubdivisionEdge(13, points[4], edges[12], faces[0], edges[0], edges[15]),
                new SubdivisionEdge(14, points[4], edges[15], faces[3], edges[11], edges[12]),
                new SubdivisionEdge(15, points[5], edges[14], faces[0], edges[13], edges[2]),
            }, edges);

            CollectionAssert.AreEqual(new[] {
                new SubdivisionFace(division, 0, null, new[] { edges[0] }),
                new SubdivisionFace(division, 1, edges[1], null),
                new SubdivisionFace(division, 2, edges[5], null),
                new SubdivisionFace(division, 3, edges[9], null),
            }, faces);

            CheckFace(edges[0], new[] { points[0], points[1], points[5], points[4] }, -48, PointD.Empty);
            CheckFace(edges[1], new[] { points[1], points[0], points[2], points[5] }, +12, new PointD(-3, 0));
            CheckFace(edges[5], new[] { points[2], points[0], points[3], points[5] }, +24, PointD.Empty);
            CheckFace(edges[9], new[] { points[3], points[0], points[4], points[5] }, +12, new PointD(3, 0));

            var cycles = division.GetZeroAreaCycles();

            Assert.AreEqual(0, cycles.Count);
        }
Пример #14
0
        public static Subdivision CreateTriforce(bool test)
        {
            PointD[] points =
            {
                new PointD(-5, -4), new PointD(0,  6), new PointD(5, -4),
                new PointD(0,   0), new PointD(-1, 2), new PointD(1, 2)
            };
            LineD[] lines =
            {
                new LineD(points[0], points[1]), new LineD(points[2], points[1]),
                new LineD(points[0], points[2]), new LineD(points[3], points[4]),
                new LineD(points[3], points[5]), new LineD(points[4], points[5])
            };

            Subdivision division = Subdivision.FromLines(lines);

            division.Validate();
            if (!test)
            {
                return(division);
            }

            CollectionAssert.AreEquivalent(lines, division.ToLines());
            var edges = division.Edges.Values;
            var faces = division.Faces.Values;

            CollectionAssert.AreEqual(new[] {
                new VertexPair(points[0], edges[0]),
                new VertexPair(points[2], edges[2]),
                new VertexPair(points[3], edges[6]),
                new VertexPair(points[4], edges[7]),
                new VertexPair(points[5], edges[9]),
                new VertexPair(points[1], edges[1]),
            }, division.Vertices);

            CollectionAssert.AreEqual(new[] {
                new SubdivisionEdge(0, points[0], edges[1], faces[0], edges[3], edges[5]),
                new SubdivisionEdge(1, points[1], edges[0], faces[1], edges[4], edges[2]),
                new SubdivisionEdge(2, points[2], edges[3], faces[1], edges[1], edges[4]),
                new SubdivisionEdge(3, points[1], edges[2], faces[0], edges[5], edges[0]),
                new SubdivisionEdge(4, points[0], edges[5], faces[1], edges[2], edges[1]),
                new SubdivisionEdge(5, points[2], edges[4], faces[0], edges[0], edges[3]),
                new SubdivisionEdge(6, points[3], edges[7], faces[1], edges[10], edges[9]),
                new SubdivisionEdge(7, points[4], edges[6], faces[2], edges[8], edges[11]),
                new SubdivisionEdge(8, points[3], edges[9], faces[2], edges[11], edges[7]),
                new SubdivisionEdge(9, points[5], edges[8], faces[1], edges[6], edges[10]),
                new SubdivisionEdge(10, points[4], edges[11], faces[1], edges[9], edges[6]),
                new SubdivisionEdge(11, points[5], edges[10], faces[2], edges[7], edges[8]),
            }, edges);

            CollectionAssert.AreEqual(new[] {
                new SubdivisionFace(division, 0, null, new[] { edges[0] }),
                new SubdivisionFace(division, 1, edges[1], new[] { edges[6] }),
                new SubdivisionFace(division, 2, edges[7], null),
            }, faces);

            PointD centroid = new PointD(0, -2 / 3.0);

            CheckFace(edges[0], new[] { points[0], points[1], points[2] }, -50, centroid);
            CheckFace(edges[1], new[] { points[1], points[0], points[2] }, +50, centroid);

            centroid = new PointD(0, 4 / 3.0);
            CheckFace(edges[6], new[] { points[3], points[4], points[5] }, -2, centroid);
            CheckFace(edges[7], new[] { points[4], points[3], points[5] }, +2, centroid);

            var cycles = division.GetZeroAreaCycles();

            Assert.AreEqual(0, cycles.Count);
            return(division);
        }