예제 #1
0
        /// <summary>
        /// Merges the with hole.
        /// </summary>
        public Polygon2D MergeWithHole(Polygon2D actHole, Polygon2DMergeOptions mergeOptions, List <Vector2>?cutPoints)
        {
            //This algorithm uses the method described in http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf

            //Find the hole vertex with the highest x value
            var holeVertexWithHighestX      = new Vector2(float.MinValue, 0f);
            var holeVertexIndexWithHighestX = -1;

            for (var loopVertex = 0; loopVertex < actHole._vertices.Length; loopVertex++)
            {
                if (actHole._vertices[loopVertex].X > holeVertexWithHighestX.X)
                {
                    holeVertexWithHighestX      = actHole._vertices[loopVertex];
                    holeVertexIndexWithHighestX = loopVertex;
                }
            }
            cutPoints?.Add(holeVertexWithHighestX);

            //Define a ray from the found vertex pointing in x direction
            var ray2D = new Ray2D(holeVertexWithHighestX, new Vector2(1f, 0f));

            //Find the line on current filling polygon with intersects first with the created ray
            Tuple <int, float, Vector2>?foundLine = null;
            var actLineIndex = 0;

            foreach (var actLine in this.Lines)
            {
                var actIntersection = actLine.Intersect(ray2D);
                if (actIntersection.Item1)
                {
                    var rayToIntersectionPoint = new Ray2D(
                        ray2D.Origin,
                        Vector2.Normalize(actIntersection.Item2 - ray2D.Origin));
                    var lengthToIntersectionPoint = Vector2.Distance(actIntersection.Item2, ray2D.Origin);
                    if (lengthToIntersectionPoint > 0f &&
                        rayToIntersectionPoint.EqualsWithTolerance(ray2D))
                    {
                        if (foundLine == null)
                        {
                            //First found intersection
                            foundLine = Tuple.Create(actLineIndex, lengthToIntersectionPoint, actIntersection.Item2);
                        }
                        else if (lengthToIntersectionPoint < foundLine.Item2)
                        {
                            //More intersections found.. take the one with smallest distance to intersection point
                            foundLine = Tuple.Create(actLineIndex, lengthToIntersectionPoint, actIntersection.Item2);
                        }
                    }
                }
                actLineIndex++;
            }
            if (cutPoints != null && foundLine != null)
            {
                cutPoints.Add(foundLine.Item3);
            }

            // Check for found intersection
            // Return a duplicate of this polygon as the result if no intersection found
            if (foundLine == null)
            {
                var newPolygonVertices = new Vector2[_vertices.Length];
                Array.Copy(_vertices, newPolygonVertices, _vertices.Length);
                return(new Polygon2D(newPolygonVertices));
            }

            //Now generate result polygon
            var resultBuilder = new List <Vector2>(_vertices.Length + actHole._vertices.Length + 2);

            for (var loopFillVertex = 0; loopFillVertex < _vertices.Length; loopFillVertex++)
            {
                //Add current vertex from filling polygon first
                resultBuilder.Add(_vertices[loopFillVertex]);

                //Do special logic on cut point
                if (loopFillVertex == foundLine.Item1)
                {
                    //Cut point.. place here the hole polygon
                    if (!_vertices[loopFillVertex].Equals(foundLine.Item3))
                    {
                        resultBuilder.Add(foundLine.Item3);
                    }

                    //Add all vertices from the hole polygon
                    resultBuilder.Add(actHole._vertices[holeVertexIndexWithHighestX]);
                    var loopHoleVertex = holeVertexIndexWithHighestX + 1;
                    while (loopHoleVertex != holeVertexIndexWithHighestX)
                    {
                        if (loopHoleVertex >= actHole._vertices.Length)
                        {
                            loopHoleVertex = 0;
                        }

                        resultBuilder.Add(actHole._vertices[loopHoleVertex]);

                        loopHoleVertex++;
                        if (loopHoleVertex >= actHole._vertices.Length)
                        {
                            loopHoleVertex = 0;
                        }
                    }

                    //Add cutpoints again to continue with main polygon
                    if (mergeOptions.MakeMergepointSpaceForTriangulation)
                    {
                        resultBuilder.Add(actHole._vertices[holeVertexIndexWithHighestX] + new Vector2(0f, 0.001f));

                        //Add the cutpoint again
                        resultBuilder.Add(foundLine.Item3 + new Vector2(0f, 0.001f));
                    }
                    else
                    {
                        resultBuilder.Add(actHole._vertices[holeVertexIndexWithHighestX]);

                        //Add the cutpoint again
                        resultBuilder.Add(foundLine.Item3);
                    }

                    //Handle the case in which next vertex would equal current cut point
                    if (_vertices.Length > loopFillVertex + 1 &&
                        _vertices[loopFillVertex + 1].Equals(foundLine.Item3))
                    {
                        loopFillVertex++;
                    }
                }
            }

            //Return new generate polygon
            return(new Polygon2D(resultBuilder.ToArray()));
        }
예제 #2
0
 /// <summary>
 /// Merges this polygon with the given one defining a hole. The result is a new polygon.
 /// </summary>
 public Polygon2D MergeWithHole(Polygon2D actHole, Polygon2DMergeOptions mergeOptions)
 {
     return(this.MergeWithHole(actHole, mergeOptions, null));
 }