コード例 #1
0
        /// <summary>
        /// Gets the silhouette of a solid along a given normal.
        /// </summary>
        /// <param name="faces"></param>
        /// <param name="normal"></param>
        /// <param name="minAngle"></param>
        /// <param name="minPathAreaToConsider"></param>
        /// <param name="depthOfPart"></param>
        /// <returns></returns>
        public static List <List <PointLight> > Slow(IList <PolygonalFace> faces, double[] normal, double minAngle = 0.1,
                                                     double minPathAreaToConsider = 0.0, double depthOfPart = 0.0)
        {
            var angleTolerance = Math.Cos((90 - minAngle) * Math.PI / 180);

            //Get the positive faces (defined as face normal along same direction as the silhoutte normal).
            var positiveFaces = new HashSet <PolygonalFace>();
            var vertices      = new HashSet <Vertex>();

            foreach (var face in faces)
            {
                var dot = normal.dotProduct(face.Normal, 3);
                if (dot.IsGreaterThanNonNegligible(angleTolerance))
                {
                    positiveFaces.Add(face);
                    //face.Color = new Color(KnownColors.Blue);
                    foreach (var vertex in face.Vertices)
                    {
                        vertices.Add(vertex);
                    }
                }
            }

            //Project all the vertices into points
            //The vertex is saved as a reference in the point
            var transform       = MiscFunctions.TransformToXYPlane(normal, out _);
            var projectedPoints = new Dictionary <int, PointLight>();

            foreach (var vertex in vertices)
            {
                projectedPoints.Add(vertex.IndexInList, MiscFunctions.Get2DProjectionPointAsLight(vertex, transform));
            }

            //Build a dictionary of faces to polygons
            //var projectedFacePolygons = positiveFaces.ToDictionary(f => f, f => GetPolygonFromFace(f, projectedPoints, true));
            //Use GetPolygonFromFace and force to be positive faces with true"
            var projectedFacePolygons2 = positiveFaces.Select(f => GetPolygonFromFace(f, projectedPoints, true)).ToList().Where(p => p.Area > minPathAreaToConsider).ToList();
            var solution = PolygonOperations.Union(projectedFacePolygons2, false).Select(p => p.Path).ToList();

            //Offset by enough to account for minimum angle
            var scale = Math.Tan(minAngle * Math.PI / 180) * depthOfPart;

            //Remove tiny polygons and slivers
            solution = PolygonOperations.SimplifyFuzzy(solution);
            var offsetPolygons      = PolygonOperations.OffsetMiter(solution, scale);
            var significantSolution = PolygonOperations.OffsetMiter(offsetPolygons, -scale);

            //Presenter.ShowAndHang(significantSolution);
            return(significantSolution); //.Select(p => p.Path).ToList();
        }
コード例 #2
0
        /// <summary>
        /// Gets the silhouette of a solid along a given normal. Depth of part is only used if removing tiny polygons.
        /// </summary>
        /// <param name="faces"></param>
        /// <param name="normal"></param>
        /// <param name="originalSolid"></param>
        /// <param name="minAngle"></param>
        /// <param name="minPathAreaToConsider"></param>
        /// <param name="depthOfPart"></param>
        /// <returns></returns>
        public static List <List <PointLight> > Run(IList <PolygonalFace> faces, double[] normal, TessellatedSolid originalSolid, double minAngle = 0.1,
                                                    double minPathAreaToConsider = 0.0, double depthOfPart = 0.0)
        {
            //Get the positive faces into a dictionary
            if (minAngle > 4.999)
            {
                minAngle = 4.999;                   //min angle must be between 0 and 5 degrees. 0.1 degree has proven to be good.
            }
            //Note also that the offset is based on the min angle.
            var angleTolerance  = Math.Cos((90 - minAngle) * Math.PI / 180); //Angle of 89.9 Degrees from normal
            var angleTolerance2 = Math.Cos((90 - 5) * Math.PI / 180);        //Angle of 85 Degrees from normal

            var positiveFaces     = new HashSet <PolygonalFace>();
            var smallFaces        = new List <PolygonalFace>();
            var allPositives      = new Dictionary <int, PolygonalFace>();
            var allVertices       = new HashSet <Vertex>();
            var positiveEdgeFaces = new HashSet <PolygonalFace>();

            foreach (var face in faces)
            {
                if (face.Area.IsNegligible())
                {
                    continue;
                }
                var dot = normal.dotProduct(face.Normal, 3);
                if (dot.IsGreaterThanNonNegligible(angleTolerance2))
                {
                    allPositives.Add(face.IndexInList, face);
                    positiveFaces.Add(face);
                }
                else if (dot.IsGreaterThanNonNegligible(angleTolerance))
                {
                    //allPositives.Add(face.IndexInList, face);
                    positiveEdgeFaces.Add(face);
                }
                else if (Math.Sign(dot) > 0 && face.Area < 1.0)
                {
                    smallFaces.Add(face);
                }
                foreach (var vertex in face.Vertices)
                {
                    allVertices.Add(vertex);
                }
            }
            //Add any small sliver faces that are sandwinched between two positive faces.
            foreach (var smallFace in smallFaces)
            {
                var largerEdges    = smallFace.Edges.OrderBy(e => e.Length).Take(2).ToList();
                var addToPositives = true;
                foreach (var edge in largerEdges)
                {
                    if (edge.OwnedFace == smallFace && allPositives.ContainsKey(edge.OtherFace.IndexInList))
                    {
                    }
                    else if (edge.OtherFace == smallFace && allPositives.ContainsKey(edge.OwnedFace.IndexInList))
                    {
                    }
                    else
                    {
                        addToPositives = false;
                    }
                }
                if (addToPositives)
                {
                    //allPositives.Add(smallFace.IndexInList, smallFace);
                    positiveEdgeFaces.Add(smallFace);
                }
            }

            //Get the polygons of all the positive faces. Force the polygons to be positive CCW
            var vertices = new HashSet <Vertex>();

            foreach (var face in allPositives.Values)
            {
                foreach (var vertex in face.Vertices)
                {
                    vertices.Add(vertex);
                }
            }
            var transform       = MiscFunctions.TransformToXYPlane(normal, out _);
            var projectedPoints = new Dictionary <int, PointLight>();

            foreach (var vertex in vertices)
            {
                projectedPoints.Add(vertex.IndexInList, MiscFunctions.Get2DProjectionPointAsLight(vertex, transform));
            }
            var projectedFacePolygons = positiveFaces.ToDictionary(f => f.IndexInList, f => GetPathFromFace(f, projectedPoints, true));

            //Get all the surfaces
            var allSurfaces = SeperateIntoSurfaces(allPositives);
            //var colors = new List<Color>()
            //{
            //    new Color(KnownColors.Blue),
            //    new Color(KnownColors.Red),
            //    new Color(KnownColors.Green),
            //    new Color(KnownColors.Yellow),
            //    new Color(KnownColors.Purple),
            //    new Color(KnownColors.Pink),
            //    new Color(KnownColors.Orange),
            //    new Color(KnownColors.Turquoise),
            //    new Color(KnownColors.White),
            //    new Color(KnownColors.Tan)
            //};
            //originalSolid.HasUniformColor = false;
            //var i = 0;
            //foreach (var surface in allSurfaces)
            //{
            //    if (i == colors.Count) i = 0;
            //    var color = colors[i];
            //    i++;
            //    foreach (var face in surface)
            //    {
            //        face.Color = color;
            //    }
            //}
            //Presenter.ShowAndHang(originalSolid);

            //Get the surface paths from all the surfaces and union them together
            var solution = GetSurfacePaths(allSurfaces, normal, minPathAreaToConsider, originalSolid, projectedFacePolygons).ToList();

            var positiveEdgeFacePolygons = new List <List <PointLight> >();

            foreach (var face in positiveEdgeFaces)
            {
                var polygon = new PolygonLight(MiscFunctions.Get2DProjectionPointsAsLight(face.Vertices, normal));
                if (!polygon.IsPositive)
                {
                    polygon.Path.Reverse();
                }
                positiveEdgeFacePolygons.Add(polygon.Path);
            }

            try //Try to merge them all at once
            {
                solution = PolygonOperations.Union(solution, positiveEdgeFacePolygons, false, PolygonFillType.NonZero);
            }
            catch
            {
                //Do them one at a time, skipping those that fail
                foreach (var face in positiveEdgeFacePolygons)
                {
                    try
                    {
                        solution = PolygonOperations.Union(solution, face, false, PolygonFillType.NonZero);
                    }
                    catch
                    {
                        continue;
                    }
                }
            }


            //Offset by enough to account for minimum angle
            var scale = Math.Tan(minAngle * Math.PI / 180) * depthOfPart;

            //Remove tiny polygons and slivers
            //First, Offset out and then perform a quick check for overhang polygons.
            //This is helpful when the polygon is nearly self-intersecting.
            //Then offset back out.

            solution = PolygonOperations.SimplifyFuzzy(solution, Math.Min(scale / 1000, Constants.LineLengthMinimum),
                                                       Math.Min(angleTolerance / 1000, Constants.LineSlopeTolerance));
            var offsetPolygons = PolygonOperations.OffsetMiter(solution, scale);

            offsetPolygons = EliminateOverhangPolygons(offsetPolygons, projectedFacePolygons);
            var significantSolution = PolygonOperations.OffsetMiter(offsetPolygons, -scale);

            return(significantSolution);
        }