public PrismHoleStaticMetadata(Rectangle localBoundary, IReadOnlyList <Polygon2> localIncludedContours, IReadOnlyList <Polygon2> localExcludedContours = null)
        {
            this.LocalBoundary         = localBoundary;
            this.LocalIncludedContours = localIncludedContours;
            this.LocalExcludedContours = localExcludedContours ?? new List <Polygon2>();

            punchResult = PolygonOperations.Punch()
                          .Include(LocalIncludedContours)
                          .Exclude(LocalExcludedContours)
                          .Execute();
            Trace.Assert(punchResult.Childs.Count > 0);
        }
 private Polygon2 ClipHoleContour(Polygon2 polygon)
 {
     PolygonOperations.TryConvexClip(polygon, ClipperExtentsHoleClipPolygon, out var result);
     if (result != null)
     {
         for (var i = 0; i < result.Points.Count; i++)
         {
             var t = true;
             ClipperBase.RangeTest(result.Points[i], ref t);
         }
     }
     return(result);
 }
        public bool ContainsPoint(HoleInstanceMetadata instanceMetadata, DoubleVector3 pointWorld, double agentRadius)
        {
            var pointLocal3 = Vector3.Transform(pointWorld.ToDotNetVector(), instanceMetadata.WorldTransformInv);
            var pointLocal  = new IntVector2((int)pointLocal3.X, (int)pointLocal3.Y);

            if (!dilatedPunchResultByAgentRadius.TryGetValue(agentRadius, out var dilatedPunchedLand))
            {
                dilatedPunchedLand = PolygonOperations.Offset()
                                     .Include(punchResult.FlattenToPolygonAndIsHoles())
                                     .Dilate(agentRadius)
                                     .Execute();
                dilatedPunchResultByAgentRadius[agentRadius] = dilatedPunchedLand;
            }

            return(dilatedPunchedLand.PointInPolytree(pointLocal, out var _));
        }
Example #4
0
        private static void RenderSomething(int canvasIndex, Polygon2 subject, Polygon2 clip)
        {
            var canvas = host.CreateAndAddCanvas(canvasIndex);

            canvas.Transform = Matrix4x4.CreateTranslation(150, 150, 0) * Matrix4x4.CreateScale(2);
            canvas.DrawLineStrip(subject.Points.Concat(new[] { subject.Points[0] }).ToArray(), StrokeStyle.CyanThick3Solid);
            canvas.DrawLineStrip(clip.Points.Concat(new[] { clip.Points[0] }).ToArray(), StrokeStyle.RedThick3Solid);

            canvas.Transform = Matrix4x4.CreateTranslation(450, 150, 0) * Matrix4x4.CreateScale(2);
            canvas.DrawLineStrip(subject.Points.Concat(new[] { subject.Points[0] }).ToArray(), StrokeStyle.CyanHairLineSolid);
            canvas.DrawLineStrip(clip.Points.Concat(new[] { clip.Points[0] }).ToArray(), StrokeStyle.RedHairLineSolid);

            if (PolygonOperations.TryConvexClip(subject, clip, out var result))
            {
                canvas.DrawLineStrip(result.Points.Concat(new[] { result.Points[0] }).ToArray(), StrokeStyle.LimeThick5Solid);
            }
        }
Example #5
0
        public static IntLineSegment2[] FindContourAndChildHoleBarriers(this PolyNode node)
        {
            if (node.visibilityGraphNodeData.ContourAndChildHoleBarriers != null)
            {
                return(node.visibilityGraphNodeData.ContourAndChildHoleBarriers);
            }

            var nodeAndChildrenContours = new[] { node.Contour }.Concat(node.Childs.Select(c => c.Contour));
            var dilatedNodeAndChildrenPolytree = PolygonOperations.Offset()
                                                 .Include(nodeAndChildrenContours)
                                                 .Dilate(kBarrierPolyTreeDilationFactor + kBarrierOverDilationFactor)
                                                 .Cleanup()
                                                 .Erode(kBarrierOverDilationFactor)
                                                 .Execute();

            var results = new List <IntLineSegment2>();

            foreach (var(polygon, isHole) in dilatedNodeAndChildrenPolytree.FlattenToPolygonAndIsHoles())
            {
                var pointCount = polygon.IsClosed ? polygon.Points.Count - 1 : polygon.Points.Count;

                // skip last point as it's a duplicate of the first.
                for (var i = 0; i < pointCount; i++)
                {
                    var a = polygon.Points[i];
                    var b = polygon.Points[(i + 1) % pointCount];

                    var dx  = b.X - a.X;
                    var dy  = b.Y - a.Y;
                    var mag = (cInt)Math.Sqrt(dx * dx + dy * dy); // normalizing on xy plane.
                    dx = dx * kBarrierSegmentExpansionFactor / mag;
                    dy = dy * kBarrierSegmentExpansionFactor / mag;

                    var p1 = new IntVector2(a.X - dx, a.Y - dy);
                    var p2 = new IntVector2(b.X + dx, b.Y + dy);

                    results.Add(isHole ? new IntLineSegment2(p2, p1) : new IntLineSegment2(p1, p2));
                }
            }
            return(node.visibilityGraphNodeData.ContourAndChildHoleBarriers = results.ToArray());
        }
Example #6
0
        /// <summary>
        /// This function gets cuts shape [List(Polygon)] with a give direction and distance. If returnFurtherThanSlice = false,
        /// it will return the partial shape before the cutting line, otherwise those beyond the cutting line.
        /// The returned partial shape is properly closed and ordered CCW+, CW-.
        /// OffsetAtLine allows the use to offset the intersection line a given distance in a direction opposite to the
        /// returned partial shape (i.e., if returnFurtherThanSlice == true, a positive offsetAtLine value moves the
        /// intersection points before the line).
        /// </summary>
        public static List <PolygonLight> OnLine(List <PolygonLight> shape, double[] direction2D, double distanceAlongDirection,
                                                 bool returnFurtherThanSlice, out List <Point> intersectionPoints,
                                                 double offsetAtLine = 0.0, List <Tuple <Point, double> > sortedPoints = null)
        {
            var partialShape = new List <PolygonLight>();

            intersectionPoints = new List <Point>();
            var shallowPolygonsTrees = PolygonOperations.GetShallowPolygonTrees(shape);

            foreach (var shallowPolygonTree in shallowPolygonsTrees) //There is usually only one, but do them all
            {
                //Set the lines in all the polygons. These are needed for Slice.OnLine()
                foreach (var polygon in shallowPolygonTree.AllPolygons)
                {
                    polygon.SetPathLines();
                }

                //Get the sorted points
                var allPoints = new List <Point>();
                foreach (var path in shallowPolygonTree.AllPaths)
                {
                    allPoints.AddRange(path);
                }

                if (sortedPoints == null)
                {
                    MiscFunctions.SortAlongDirection(direction2D, allPoints, out sortedPoints);
                }

                //Get the paths for each partial shape and add them together. The paths should not overlap, given
                //that they are from non-overlapping shallow polygon trees.
                var localSortedIntersectionOffsetPoints = new List <Point>();
                var paths = OnLine(shallowPolygonTree, direction2D, distanceAlongDirection, returnFurtherThanSlice, sortedPoints,
                                   out localSortedIntersectionOffsetPoints, offsetAtLine);
                partialShape.AddRange(paths);
                intersectionPoints.AddRange(localSortedIntersectionOffsetPoints);
            }

            return(partialShape);
        }
Example #7
0
        private void FillInFromTessellation(TessellatedSolid ts)
        {
            var yBegin = Bounds[0][1] + VoxelSideLength / 2;
            var zBegin = Bounds[0][2] + VoxelSideLength / 2;
            var decomp = ts.GetUniformlySpacedCrossSections(CartesianDirections.ZPositive, zBegin, numVoxelsZ, VoxelSideLength);
            var inverseVoxelSideLength = 1 / VoxelSideLength; // since its quicker to multiple then to divide, maybe doing this once at the top will save some time

            //Parallel.For(0, numVoxelsZ, k =>
            for (var k = 0; k < numVoxelsZ; k++)
            {
                var loops = decomp[k];
                if (loops.Count == 0)
                {
                    continue;
                }

                var intersections = PolygonOperations.AllPolygonIntersectionPointsAlongHorizontalLines(loops, yBegin, numVoxelsY,
                                                                                                       VoxelSideLength, out var yStartIndex);
                var numYlines = intersections.Count;
                for (int j = 0; j < numYlines; j++)
                {
                    var intersectionPoints   = intersections[j];
                    var numXRangesOnThisLine = intersectionPoints.Length;
                    for (var m = 0; m < numXRangesOnThisLine; m += 2)
                    {
                        var sp = (ushort)((intersectionPoints[m] - Bounds[0][0]) * inverseVoxelSideLength);
                        var ep = (ushort)((intersectionPoints[m + 1] - Bounds[0][0]) * inverseVoxelSideLength);
                        if (ep >= numVoxelsX)
                        {
                            ep = (ushort)(numVoxelsX - 1);
                        }
                        ((VoxelRowSparse)voxels[k * zMultiplier + yStartIndex + j]).indices.Add(sp);
                        ((VoxelRowSparse)voxels[k * zMultiplier + yStartIndex + j]).indices.Add(ep);
                    }
                }
            }
            //);
        }
        //public IntLineSegment2?[] ErodedBoundaryCrossoverSegments =>
        //   _erodedCrossoverSegments ?? (_erodedCrossoverSegments =
        //      Job.CrossoverSegments.Select(segment =>
        //         segment.TryErode(CrossoverErosionRadius, out IntLineSegment2 erosionResult)
        //            ? erosionResult
        //            : (IntLineSegment2?)null).ToArray());

        public PolyTree ComputeErodedOuterContour() =>
        PolygonOperations.Offset()
        .Include(Job.TerrainStaticMetadata.LocalIncludedContours)
        .Erode(HoleDilationRadius)
        .Cleanup()
        .Execute();
Example #9
0
        private static void X()
        {
            var mapDimensions = new Size(1000, 1000);
            var holes         = new[] {
                Polygon2.CreateRect(100, 100, 300, 300),
                Polygon2.CreateRect(400, 200, 100, 100),
                Polygon2.CreateRect(200, -50, 100, 150),
                Polygon2.CreateRect(600, 600, 300, 300),
                Polygon2.CreateRect(700, 500, 100, 100),
                Polygon2.CreateRect(200, 700, 100, 100),
                Polygon2.CreateRect(600, 100, 300, 50),
                Polygon2.CreateRect(600, 150, 50, 200),
                Polygon2.CreateRect(850, 150, 50, 200),
                Polygon2.CreateRect(600, 350, 300, 50),
                Polygon2.CreateRect(700, 200, 100, 100)
            };

            var holeSquiggle = PolylineOperations.ExtrudePolygon(
                new[] {
                new IntVector2(100, 50),
                new IntVector2(100, 100),
                new IntVector2(200, 100),
                new IntVector2(200, 150),
                new IntVector2(200, 200),
                new IntVector2(400, 250),
                new IntVector2(200, 300),
                new IntVector2(400, 315),
                new IntVector2(200, 330),
                new IntVector2(210, 340),
                new IntVector2(220, 350),
                new IntVector2(220, 400),
                new IntVector2(221, 400)
            }.Select(iv => new IntVector2(iv.X + 160, iv.Y + 200)).ToArray(), 10).FlattenToPolygonAndIsHoles().Map(t => t.polygon);

            holes = holes.Concat(holeSquiggle).ToArray();

            var landPoly         = Polygon2.CreateRect(0, 0, 1000, 1000);
            var holesUnionResult = PolygonOperations.Offset()
                                   .Include(holes)
                                   .Include(holeSquiggle)
                                   .Dilate(15)
                                   .Execute();
            var landHolePunchResult = PolygonOperations.Punch()
                                      .Include(landPoly)
                                      .IncludeOrExclude(holesUnionResult.FlattenToPolygonAndIsHoles(), true)
                                      .Execute();
            var visibilityGraph = landHolePunchResult.ComputeVisibilityGraph();
//         var debugCanvas = DebugCanvasHost.CreateAndShowCanvas();
//         debugCanvas.DrawPolygons(holes, Color.Red);
//         debugCanvas.DrawVisibilityGraph(visibilityGraph);
//         var testPathFindingQueries = new[] {
//            Tuple.Create(new IntVector2(60, 40), new IntVector2(930, 300)),
//            Tuple.Create(new IntVector2(675, 175), new IntVector2(825, 300)),
//            Tuple.Create(new IntVector2(50, 900), new IntVector2(950, 475)),
//            Tuple.Create(new IntVector2(50, 500), new IntVector2(80, 720))
//         };

//         using (var pen = new Pen(Color.Lime, 2)) {
//            foreach (var query in testPathFindingQueries) {
//               Path path;
//               if (visibilityGraph.TryFindPath(query.Item1, query.Item2, out path))
//                  debugCanvas.DrawLineStrip(path.Points, pen);
//            }
//         }
        }
Example #10
0
        /// <summary>
        /// Creates the 2D Medial Axis from a part's Silhouette. Currently ignores holes.
        /// Best way to show is using "Presenter.ShowAndHang(silhouette, medialAxis, "", Plot2DType.Line, false);"
        /// </summary>
        /// <param name="silhouette"></param>
        public static List <List <PointLight> > Run(IEnumerable <List <PointLight> > silhouette)
        {
            //To Get the 2D Medial Axis:
            //The first four steps create a medial axis and the next three steps sort the axis lines into branches
            //1) Sample the silhouette to get more points
            //2) Get the Delaunay triangulation of the sampled silhouette
            //3) For every triangle in the Delaunay, keep all the edges that have a center point inside the sampled silhouette
            //4) If all three edges are inside, collapse one of the edges
            //5) Merge the points from the lines. Note: there seems to be an error with duplicate edges and disconnected branches
            //6) Get all the nodes (3+ lines)
            //7) Connect all the nodes to form branches with the lines
            var allBranches = new List <List <PointLight> >();

            foreach (var positivePolygon in silhouette.Where(p => MiscFunctions.AreaOfPolygon(p) > 0))
            {
                var sampled = PolygonOperations.SampleWithEdgeLength(positivePolygon, MiscFunctions.Perimeter(positivePolygon) / 600);
                var smaller = PolygonOperations.OffsetRound(sampled, -0.001 * MiscFunctions.Perimeter(positivePolygon)).Select(p => new PolygonLight(p)).First();

                //Delaunay Medial Axis
                var delaunay = MIConvexHull.Triangulation.CreateDelaunay(sampled);
                var lines    = new List <List <Point> >();
                foreach (var triangle in delaunay.Cells)
                {
                    var triangleCenterLineVertices = new List <Point>();
                    var edge1Center = new Point(triangle.Vertices[0].Position.add(triangle.Vertices[1].Position)
                                                .divide(2));
                    if (MiscFunctions.IsPointInsidePolygon(smaller, edge1Center.Light))
                    {
                        triangleCenterLineVertices.Add(edge1Center);
                    }

                    var edge2Center = new Point(triangle.Vertices[1].Position.add(triangle.Vertices[2].Position)
                                                .divide(2));
                    if (MiscFunctions.IsPointInsidePolygon(smaller, edge2Center.Light))
                    {
                        triangleCenterLineVertices.Add(edge2Center);
                    }

                    var edge3Center = new Point(triangle.Vertices[2].Position.add(triangle.Vertices[0].Position)
                                                .divide(2));
                    if (MiscFunctions.IsPointInsidePolygon(smaller, edge3Center.Light))
                    {
                        triangleCenterLineVertices.Add(edge3Center);
                    }

                    if (triangleCenterLineVertices.Any())
                    {
                        if (triangleCenterLineVertices.Count == 1)
                        {
                            continue; // This vertex has no line associated with it.
                                      //If the vertex should be attached to a line, it will show up again for another triangle.
                        }
                        if (triangleCenterLineVertices.Count == 3)
                        {
                            //If there are two long edges with one short, collapse the long edges to the middle
                            //of the short edge.
                            //If
                            //Order the points, such that the larger edge is not included
                            var d0 = edge1Center.Position.subtract(edge2Center.Position).norm2();
                            var d1 = edge2Center.Position.subtract(edge3Center.Position).norm2();
                            var d2 = edge3Center.Position.subtract(edge1Center.Position).norm2();
                            var ds = new List <double>()
                            {
                                d0, d1, d2
                            };
                            ds.Sort();
                            if (ds[0] - ds[1] > ds[1] - ds[2])
                            {
                                //There is a bigger difference in length between the longest edge than the other two
                                //Therefore, remove the longest edge.
                                if (d0 > d1 && d0 > d2)
                                {
                                    //If d0 is the largest edge, it should be point 2,3,1
                                    lines.Add(new List <Point> {
                                        edge2Center, edge3Center
                                    });
                                    lines.Add(new List <Point> {
                                        edge3Center, edge1Center
                                    });
                                }
                                else if (d1 > d2)
                                {
                                    lines.Add(new List <Point> {
                                        edge3Center, edge1Center
                                    });
                                    lines.Add(new List <Point> {
                                        edge1Center, edge2Center
                                    });
                                }
                                else
                                {
                                    lines.Add(new List <Point> {
                                        edge1Center, edge2Center
                                    });
                                    lines.Add(new List <Point> {
                                        edge2Center, edge3Center
                                    });
                                }
                            }
                            else
                            {
                                Point newPoint;
                                //Create a new center point on the shortest line and set three point sets
                                if (d0 < d1 && d0 < d2)
                                {
                                    newPoint = new Point(
                                        edge1Center.Position.add(edge2Center.Position).divide(2, 2));
                                }
                                else if (d1 < d2)
                                {
                                    newPoint = new Point(
                                        edge2Center.Position.add(edge3Center.Position).divide(2, 2));
                                }
                                else
                                {
                                    newPoint = new Point(
                                        edge3Center.Position.add(edge1Center.Position).divide(2, 2));
                                }

                                lines.Add(new List <Point> {
                                    edge1Center, newPoint
                                });
                                lines.Add(new List <Point> {
                                    edge2Center, newPoint
                                });
                                lines.Add(new List <Point> {
                                    edge3Center, newPoint
                                });
                            }
                        }
                        else
                        {
                            lines.Add(triangleCenterLineVertices);
                        }
                    }
                }

                //Merge all the points
                var mergerTolerance = 0.0001;
                for (var j = 0; j < lines.Count - 1; j++)
                {
                    var l1          = lines[j];
                    var sameLineInt = -1;
                    for (var k = j + 1; k < lines.Count; k++)
                    {
                        var sameLineCount = 0;
                        var l2            = lines[k];
                        if (MiscFunctions.DistancePointToPoint(l1[0], l2[0]).IsNegligible(mergerTolerance))
                        {
                            l2[0] = l1[0];
                            sameLineCount++;
                        }
                        else if (MiscFunctions.DistancePointToPoint(l1[0], l2[1]).IsNegligible(mergerTolerance))
                        {
                            l2[1] = l1[0];
                            sameLineCount++;
                        }
                        if (MiscFunctions.DistancePointToPoint(l1[1], l2[0]).IsNegligible(mergerTolerance))
                        {
                            l2[0] = l1[1];
                            sameLineCount++;
                        }
                        else if (MiscFunctions.DistancePointToPoint(l1[1], l2[1]).IsNegligible(mergerTolerance))
                        {
                            l2[1] = l1[1];
                            sameLineCount++;
                        }
                        if (sameLineCount == 2)
                        {
                            sameLineInt = k;
                        }
                    }
                    if (sameLineInt != -1)
                    {
                        //lines.RemoveAt(sameLineInt);
                    }
                }

                //Get all the points
                var points = new HashSet <Point>();
                foreach (var line in lines)
                {
                    points.Add(line[0]);
                    points.Add(line[1]);
                }

                //Get all the node points
                //Also create a new branch for each line that attached to this node
                var nodes    = new HashSet <Point>();
                var branches = new List <List <Point> >();
                foreach (var p1 in points)
                {
                    var adjacentLineCount        = 0;
                    var adjacentLinesOtherPoints = new List <Point>();
                    foreach (var line in lines)
                    {
                        for (var p = 0; p < 2; p++)
                        {
                            var p2 = line[p];
                            if (p1 != p2)
                            {
                                continue;
                            }
                            adjacentLineCount++;
                            adjacentLinesOtherPoints.Add(p == 0 ? line[1] : line[0]);
                        }
                    }
                    if (adjacentLineCount > 2)
                    {
                        nodes.Add(p1);
                        //Add a new branch for each adjacent line
                        foreach (var p2 in adjacentLinesOtherPoints)
                        {
                            branches.Add(new List <Point> {
                                p1, p2
                            });
                        }
                    }
                }

                while (branches.Any())
                {
                    //Pop off the first branch
                    var branch = branches.First();
                    branches.RemoveAt(0);

                    //Continue adding points to this branch until it reaches another node
                    //Or the branch reaches its end
                    var hitEndOfBranch = false;
                    var hitNode        = false;
                    while (!hitEndOfBranch && !hitNode)
                    {
                        //Search until we find the next line (2-points) that attaches to this branch
                        //Once it is added, remove it from the list of lines to make future searching faster
                        var p0 = branch.First();
                        var p1 = branch.Last();

                        //Check if we reached a node
                        //If we reached a node, then we need to remove a branch from that node
                        foreach (var node in nodes)
                        {
                            if (p1 != node || branch[0] == node)
                            {
                                continue;
                            }
                            hitNode = true;
                            //Get the branch that has this node and the prior point
                            var p2 = branch[branch.Count - 2];
                            for (var j = 0; j < branches.Count; j++)
                            {
                                if (branches[j][0].Position.subtract(p1.Position).norm2().IsNegligible(0.0001) &&
                                    branches[j][1].Position.subtract(p2.Position).norm2().IsNegligible(0.0001))
                                {
                                    branches.RemoveAt(j);
                                    break;
                                }
                            }
                            break;
                        }
                        if (hitNode)
                        {
                            continue;
                        }

                        hitEndOfBranch = true;
                        for (var j = 0; j < lines.Count; j++)
                        {
                            var line = lines[j];
                            if (line[0] == p1) //.Position.subtract(p1.Position).norm2().IsNegligible(0.0001))
                            {
                                if (line[1] == p0)
                                {
                                    //This line is the starting line for the branch.
                                    continue;
                                }
                                branch.Add(line[1]);
                                hitEndOfBranch = false;
                                lines.RemoveAt(j);
                                break;
                            }
                            if (line[1] == p1) // .Position.subtract(p1.Position).norm2().IsNegligible(0.0001))
                            {
                                if (line[0] == p0)
                                {
                                    //This line is the starting line for the branch.
                                    continue;
                                }
                                branch.Add(line[0]);
                                hitEndOfBranch = false;
                                lines.RemoveAt(j);
                                break;
                            }
                        }
                    }
                    allBranches.Add(branch.Select(p => p.Light).ToList());
                }
            }
            return(allBranches);
        }