Beispiel #1
0
 public void Test_GetSectionLines()
 {
     List<Point> points = new List<Point> {new Point(0F,0F), new Point(100F,10F), new Point(10F,100F)};
       Polygon testPoly = new Polygon(points, 100, 100, 0, 0);
       Line[] sections = testPoly.GetSectionLines(4, false);
       foreach(Line line in sections)
       {
     Console.WriteLine("Point 1: "+line.P1.X.ToString()+", "+line.P1.Y.ToString());
     Console.WriteLine("Point 2: "+line.P2.X.ToString()+", "+line.P2.Y.ToString());
       }
       Point center = testPoly.GetCenter();
       Console.WriteLine("Center: "+center.X.ToString()+", "+center.Y.ToString());
       Assert.Equal(4, sections.Length);
 }
Beispiel #2
0
 public void Test_PartyPer()
 {
     List<Point> points = new List<Point> {new Point(0F,0F), new Point(100F,10F), new Point(10F,100F)};
       Polygon testPoly = new Polygon(points, 100F, 100F, 0F, 0F);
       List<Polygon> subs = testPoly.PartyPer("pale");
       foreach(Polygon sub in subs)
       {
     Console.WriteLine("Subdivision Points");
     foreach(Point vertex in sub.vertices)
     {
       Console.WriteLine(vertex.ToString());
     }
     Console.WriteLine("Width: "+sub.width.ToString());
     Console.WriteLine("Height: "+sub.height.ToString());
     Console.WriteLine("Offset X: "+sub.offsetX.ToString());
     Console.WriteLine("Offset Y: "+sub.offsetY.ToString());
       }
       Assert.Equal(2, subs.Count);
 }
Beispiel #3
0
 public void Test_Constructors()
 {
     List<Point> points = new List<Point> {new Point(0F,0F), new Point(100F,10F), new Point(10F,100F)};
       Polygon testPoly = new Polygon(points, 100, 100, 0, 0);
       Assert.Equal(3, testPoly.sides.Count);
 }
Beispiel #4
0
        // Creates a linked list of all vertices in the polygon, with the hole vertices joined to the hull at optimal points.
        LinkedList <Vertex> GenerateVertexList(Polygon polygon)
        {
            LinkedList <Vertex>     vertexList  = new LinkedList <Vertex>();
            LinkedListNode <Vertex> currentNode = null;

            // Add all hull points to the linked list
            for (int i = 0; i < polygon.numHullPoints; i++)
            {
                int prevPointIndex = (i - 1 + polygon.numHullPoints) % polygon.numHullPoints;
                int nextPointIndex = (i + 1) % polygon.numHullPoints;

                bool   vertexIsConvex    = IsConvex(polygon.points[prevPointIndex], polygon.points[i], polygon.points[nextPointIndex]);
                Vertex currentHullVertex = new Vertex(polygon.points[i], i, vertexIsConvex);

                if (currentNode == null)
                {
                    currentNode = vertexList.AddFirst(currentHullVertex);
                }
                else
                {
                    currentNode = vertexList.AddAfter(currentNode, currentHullVertex);
                }
            }

            // Process holes:
            List <HoleData> sortedHoleData = new List <HoleData>();

            for (int holeIndex = 0; holeIndex < polygon.numHoles; holeIndex++)
            {
                // Find index of rightmost point in hole. This 'bridge' point is where the hole will be connected to the hull.
                Vector2 holeBridgePoint = new Vector2(float.MinValue, 0);
                int     holeBridgeIndex = 0;
                for (int i = 0; i < polygon.numPointsPerHole[holeIndex]; i++)
                {
                    if (polygon.GetHolePoint(i, holeIndex).x > holeBridgePoint.x)
                    {
                        holeBridgePoint = polygon.GetHolePoint(i, holeIndex);
                        holeBridgeIndex = i;
                    }
                }
                sortedHoleData.Add(new HoleData(holeIndex, holeBridgeIndex, holeBridgePoint));
            }
            // Sort hole data so that holes furthest to the right are first
            sortedHoleData.Sort((x, y) => (x.bridgePoint.x > y.bridgePoint.x) ? -1 : 1);

            foreach (HoleData holeData in sortedHoleData)
            {
                // Find first edge which intersects with rightwards ray originating at the hole bridge point.
                Vector2 rayIntersectPoint = new Vector2(float.MaxValue, holeData.bridgePoint.y);
                List <LinkedListNode <Vertex> > hullNodesPotentiallyInBridgeTriangle = new List <LinkedListNode <Vertex> >();
                LinkedListNode <Vertex>         initialBridgeNodeOnHull = null;
                currentNode = vertexList.First;
                while (currentNode != null)
                {
                    LinkedListNode <Vertex> nextNode = (currentNode.Next == null) ? vertexList.First : currentNode.Next;
                    Vector2 p0 = currentNode.Value.position;
                    Vector2 p1 = nextNode.Value.position;

                    // at least one point must be to right of holeData.bridgePoint for intersection with ray to be possible
                    if (p0.x > holeData.bridgePoint.x || p1.x > holeData.bridgePoint.x)
                    {
                        // one point is above, one point is below
                        if (p0.y > holeData.bridgePoint.y != p1.y > holeData.bridgePoint.y)
                        {
                            float rayIntersectX = p1.x; // only true if line p0,p1 is vertical
                            if (!Mathf.Approximately(p0.x, p1.x))
                            {
                                float intersectY = holeData.bridgePoint.y;
                                float gradient   = (p0.y - p1.y) / (p0.x - p1.x);
                                float c          = p1.y - gradient * p1.x;
                                rayIntersectX = (intersectY - c) / gradient;
                            }

                            // intersection must be to right of bridge point
                            if (rayIntersectX > holeData.bridgePoint.x)
                            {
                                LinkedListNode <Vertex> potentialNewBridgeNode = (p0.x > p1.x) ? currentNode : nextNode;
                                // if two intersections occur at same x position this means is duplicate edge
                                // duplicate edges occur where a hole has been joined to the outer polygon
                                bool isDuplicateEdge = Mathf.Approximately(rayIntersectX, rayIntersectPoint.x);

                                // connect to duplicate edge (the one that leads away from the other, already connected hole, and back to the original hull) if the
                                // current hole's bridge point is higher up than the bridge point of the other hole (so that the new bridge connection doesn't intersect).
                                bool connectToThisDuplicateEdge = holeData.bridgePoint.y > potentialNewBridgeNode.Previous.Value.position.y;

                                if (!isDuplicateEdge || connectToThisDuplicateEdge)
                                {
                                    // if this is the closest ray intersection thus far, set bridge hull node to point in line having greater x pos (since def to right of hole).
                                    if (rayIntersectX < rayIntersectPoint.x || isDuplicateEdge)
                                    {
                                        rayIntersectPoint.x     = rayIntersectX;
                                        initialBridgeNodeOnHull = potentialNewBridgeNode;
                                    }
                                }
                            }
                        }
                    }

                    // Determine if current node might lie inside the triangle formed by holeBridgePoint, rayIntersection, and bridgeNodeOnHull
                    // We only need consider those which are reflex, since only these will be candidates for visibility from holeBridgePoint.
                    // A list of these nodes is kept so that in next step it is not necessary to iterate over all nodes again.
                    if (currentNode != initialBridgeNodeOnHull)
                    {
                        if (!currentNode.Value.isConvex && p0.x > holeData.bridgePoint.x)
                        {
                            hullNodesPotentiallyInBridgeTriangle.Add(currentNode);
                        }
                    }
                    currentNode = currentNode.Next;
                }

                // Check triangle formed by hullBridgePoint, rayIntersection, and bridgeNodeOnHull.
                // If this triangle contains any points, those points compete to become new bridgeNodeOnHull
                LinkedListNode <Vertex> validBridgeNodeOnHull = initialBridgeNodeOnHull;
                foreach (LinkedListNode <Vertex> nodePotentiallyInTriangle in hullNodesPotentiallyInBridgeTriangle)
                {
                    if (nodePotentiallyInTriangle.Value.index == initialBridgeNodeOnHull.Value.index)
                    {
                        continue;
                    }
                    // if there is a point inside triangle, this invalidates the current bridge node on hull.
                    if (Maths2D.PointInTriangle(holeData.bridgePoint, rayIntersectPoint, initialBridgeNodeOnHull.Value.position, nodePotentiallyInTriangle.Value.position))
                    {
                        // Duplicate points occur at hole and hull bridge points.
                        bool isDuplicatePoint = validBridgeNodeOnHull.Value.position == nodePotentiallyInTriangle.Value.position;

                        // if multiple nodes inside triangle, we want to choose the one with smallest angle from holeBridgeNode.
                        // if is a duplicate point, then use the one occurring later in the list
                        float currentDstFromHoleBridgeY    = Mathf.Abs(holeData.bridgePoint.y - validBridgeNodeOnHull.Value.position.y);
                        float pointInTriDstFromHoleBridgeY = Mathf.Abs(holeData.bridgePoint.y - nodePotentiallyInTriangle.Value.position.y);

                        if (pointInTriDstFromHoleBridgeY < currentDstFromHoleBridgeY || isDuplicatePoint)
                        {
                            validBridgeNodeOnHull = nodePotentiallyInTriangle;
                        }
                    }
                }

                // Insert hole points (starting at holeBridgeNode) into vertex list at validBridgeNodeOnHull
                currentNode = validBridgeNodeOnHull;
                for (int i = holeData.bridgeIndex; i <= polygon.numPointsPerHole[holeData.holeIndex] + holeData.bridgeIndex; i++)
                {
                    int previousIndex = currentNode.Value.index;
                    int currentIndex  = polygon.IndexOfPointInHole(i % polygon.numPointsPerHole[holeData.holeIndex], holeData.holeIndex);
                    int nextIndex     = polygon.IndexOfPointInHole((i + 1) % polygon.numPointsPerHole[holeData.holeIndex], holeData.holeIndex);

                    if (i == polygon.numPointsPerHole[holeData.holeIndex] + holeData.bridgeIndex) // have come back to starting point
                    {
                        nextIndex = validBridgeNodeOnHull.Value.index;                            // next point is back to the point on the hull
                    }

                    bool   vertexIsConvex = IsConvex(polygon.points[previousIndex], polygon.points[currentIndex], polygon.points[nextIndex]);
                    Vertex holeVertex     = new Vertex(polygon.points[currentIndex], currentIndex, vertexIsConvex);
                    currentNode = vertexList.AddAfter(currentNode, holeVertex);
                }

                // Add duplicate hull bridge vert now that we've come all the way around. Also set its concavity
                Vector2 nextVertexPos       = (currentNode.Next == null) ? vertexList.First.Value.position : currentNode.Next.Value.position;
                bool    isConvex            = IsConvex(holeData.bridgePoint, validBridgeNodeOnHull.Value.position, nextVertexPos);
                Vertex  repeatStartHullVert = new Vertex(validBridgeNodeOnHull.Value.position, validBridgeNodeOnHull.Value.index, isConvex);
                vertexList.AddAfter(currentNode, repeatStartHullVert);

                //Set concavity of initial hull bridge vert, since it may have changed now that it leads to hole vert
                LinkedListNode <Vertex> nodeBeforeStartBridgeNodeOnHull = (validBridgeNodeOnHull.Previous == null) ? vertexList.Last : validBridgeNodeOnHull.Previous;
                LinkedListNode <Vertex> nodeAfterStartBridgeNodeOnHull  = (validBridgeNodeOnHull.Next == null) ? vertexList.First : validBridgeNodeOnHull.Next;
                validBridgeNodeOnHull.Value.isConvex = IsConvex(nodeBeforeStartBridgeNodeOnHull.Value.position, validBridgeNodeOnHull.Value.position, nodeAfterStartBridgeNodeOnHull.Value.position);
            }
            return(vertexList);
        }