コード例 #1
0
        protected FillCurveSet2d ComputeFillPaths(GeneralPolygon2d poly, SegmentSet2d polyCache)
        {
            List <List <Segment2d> > StepSpans = ComputeSegments(poly, polyCache);
            int N = StepSpans.Count;

            //double hard_max_dist = 5 * PathSpacing;

            // [TODO] need a pathfinder here, that can chain segments efficiently

            // (for now just do dumb things?)

            FillCurveSet2d paths = new FillCurveSet2d();

            //FillPolyline2d cur = new FillPolyline2d();

            foreach (var seglist in StepSpans)
            {
                foreach (Segment2d seg in seglist)
                {
                    FillPolyline2d fill_seg = new FillPolyline2d()
                    {
                        TypeFlags = FillTypeFlags.SolidInfill
                    };
                    fill_seg.AppendVertex(seg.P0);
                    fill_seg.AppendVertex(seg.P1);
                    paths.Append(fill_seg);
                }
            }

            return(paths);
        }
コード例 #2
0
        // extract set of spans from poly where clipped=false
        List <FillPolyline2d> find_polygon_spans(Vector2d[] poly, bool[] clipped)
        {
            // assumption: at least one vtx is clipped
            int iStart = 0;

            // handle no-wrap case
            if (clipped[iStart] == false && clipped[poly.Length - 1] == true)
            {
                iStart = 0;
            }
            else
            {
                while (clipped[iStart] == true)                     // find first non-clipped pt
                {
                    iStart++;
                }
            }

            List <FillPolyline2d> result = new List <FillPolyline2d>();
            int  iCur = iStart;
            bool done = false;

            while (done == false)
            {
                FillPolyline2d cur = new FillPolyline2d();
                do
                {
                    cur.AppendVertex(poly[iCur]);
                    iCur = (iCur + 1) % poly.Length;
                } while (clipped[iCur] == false && iCur != iStart);

                if (cur.VertexCount > 1)
                {
                    result.Add(cur);
                }

                while (clipped[iCur] && iCur != iStart)
                {
                    iCur++;
                }

                if (iCur == iStart)
                {
                    done = true;
                }
            }

            return(result);
        }
コード例 #3
0
        // (approximately) clip insetPoly to band around clipPoly.
        // vertices are discarded if outside clipPoly, or within clip_dist
        // remaining polylines are returned
        // In all-pass case currently returns polyline w/ explicit first==last vertices
        public List <FillPolyline2d> clip_to_band(Polygon2d insetpoly, GeneralPolygon2d clipPoly, double clip_dist)
        {
            double clipSqr = clip_dist * clip_dist;

            int N = insetpoly.VertexCount;

            Vector2d[] midline  = new Vector2d[N];
            bool[]     clipped  = new bool[N];
            int        nClipped = 0;

            for (int i = 0; i < N; ++i)
            {
                Vector2d po = insetpoly[i];
                if (clipPoly.Contains(po) == false)
                {
                    clipped[i] = true;
                    nClipped++;
                    continue;
                }

                int    iHole, iSeg; double segT;
                double distSqr = clipPoly.DistanceSquared(po, out iHole, out iSeg, out segT);
                if (distSqr < clipSqr)
                {
                    clipped[i] = true;
                    nClipped++;
                    continue;
                }

                // not ideal...
                midline[i] = po;
            }
            if (nClipped == N)
            {
                return(new List <FillPolyline2d>());
            }
            if (nClipped == 0)
            {
                FillPolyline2d all = new FillPolyline2d(midline);
                all.AppendVertex(all.Start);
                return(new List <FillPolyline2d>()
                {
                    all
                });
            }

            return(find_polygon_spans(midline, clipped));
        }
コード例 #4
0
 static Segment2d get_case(FillPolyline2d l0, FillPolyline2d l1, int which)
 {
     if (which == 0)
     {
         return(new Segment2d(l0.Start, l1.Start));
     }
     else if (which == 1)
     {
         return(new Segment2d(l0.Start, l1.End));
     }
     else if (which == 2)
     {
         return(new Segment2d(l0.End, l1.Start));
     }
     else
     {
         return(new Segment2d(l0.End, l1.End));
     }
 }
コード例 #5
0
        // [TODO] would it ever make sense to break polyline to avoid huge travel??
        public virtual void AppendPolyline2d(FillPolyline2d curve)
        {
            Vector3d currentPos  = Builder.Position;
            Vector2d currentPos2 = currentPos.xy;

            int N = curve.VertexCount;

            if (N < 2)
            {
                throw new Exception("PathScheduler.AppendPolyline2d: degenerate curve!");
            }

            int  iNearest = 0;
            bool bReverse = false;

            if (curve.Start.DistanceSquared(currentPos2) > curve.End.DistanceSquared(currentPos2))
            {
                iNearest = N - 1;
                bReverse = true;
            }

            Vector2d startPt = curve[iNearest];

            Builder.AppendTravel(startPt, Settings.RapidTravelSpeed);

            List <Vector2d>      loopV;
            List <TPVertexFlags> flags = null;

            if (bReverse)
            {
                loopV = new List <Vector2d>(N);
                for (int i = N - 1; i >= 0; --i)
                {
                    loopV.Add(curve[i]);
                }
                if (curve.HasFlags)
                {
                    flags = new List <TPVertexFlags>(N);
                    for (int i = N - 1; i >= 0; --i)
                    {
                        flags.Add(curve.GetFlag(i));
                    }
                }
            }
            else
            {
                loopV = new List <Vector2d>(curve);
                if (curve.HasFlags)
                {
                    flags = new List <TPVertexFlags>(curve.Flags());
                }
            }

            double useSpeed = select_speed(curve);

            Vector2d dimensions = GCodeUtil.UnspecifiedDimensions;

            if (curve.CustomThickness > 0)
            {
                dimensions.x = curve.CustomThickness;
            }

            Builder.AppendExtrude(loopV, useSpeed, dimensions, curve.TypeFlags, flags);
        }
コード例 #6
0
 public void Append(FillPolyline2d curve)
 {
     Curves.Add(curve);
 }
コード例 #7
0
        // DEPRECATED - remove?
        // this connects up the paths with small connectors? used in DenseLinesFillPolygon
        public void OptimizeCurves(double max_dist, Func <Segment2d, bool> ValidateF)
        {
            int[]    which = new int[4];
            double[] dists = new double[4];
            for (int ci = 0; ci < Curves.Count; ++ci)
            {
                FillPolyline2d l0 = Curves[ci];

                // find closest viable connection
                int iClosest     = -1;
                int iClosestCase = -1;
                for (int cj = ci + 1; cj < Curves.Count; ++cj)
                {
                    FillPolyline2d l1 = Curves[cj];
                    dists[0] = l0.Start.Distance(l1.Start);  which[0] = 0;
                    dists[1] = l0.Start.Distance(l1.End);  which[1] = 1;
                    dists[2] = l0.End.Distance(l1.Start);  which[2] = 2;
                    dists[3] = l0.End.Distance(l1.End);  which[3] = 3;
                    Array.Sort(dists, which);

                    for (int k = 0; k < 4 && iClosest != cj; ++k)
                    {
                        if (dists[k] > max_dist)
                        {
                            continue;
                        }
                        Segment2d connector = get_case(l0, l1, which[k]);
                        if (ValidateF(connector) == false)
                        {
                            continue;
                        }
                        iClosest     = cj;
                        iClosestCase = which[k];
                    }
                }

                if (iClosest == -1)
                {
                    continue;
                }

                // [TODO] it would be better to preserve start/direction of
                //   longest path, if possible. Maybe make that an option?

                // ok we will join ci w/ iClosest. May need reverse one
                FillPolyline2d ljoin = Curves[iClosest];
                if (iClosestCase == 0)
                {
                    l0.Reverse();
                }
                else if (iClosestCase == 1)
                {
                    l0.Reverse();
                    ljoin.Reverse();
                }
                else if (iClosestCase == 3)
                {
                    ljoin.Reverse();
                }

                // now we are in straight-append order
                l0.AppendVertices(ljoin);
                Curves.RemoveAt(iClosest);

                // force check again w/ this curve
                ci--;
            }
        }
コード例 #8
0
        /// <summary>
        /// fill poly w/ adjacent straight line segments, connected by connectors
        /// </summary>
        protected FillCurveSet2d ComputeFillPaths(GeneralPolygon2d poly)
        {
            FillCurveSet2d paths = new FillCurveSet2d();

            // smooth the input poly a little bit, this simplifies the filling
            // (simplify after?)
            //GeneralPolygon2d smoothed = poly.Duplicate();
            //CurveUtils2.LaplacianSmoothConstrained(smoothed, 0.5, 5, ToolWidth / 2, true, false);
            //poly = smoothed;

            // compute 2D non-manifold graph consisting of original polygon and
            // inserted line segments
            DGraph2 spanGraph = ComputeSpanGraph(poly);

            if (spanGraph == null || spanGraph.VertexCount == poly.VertexCount)
            {
                return(paths);
            }


            DGraph2 pathGraph = BuildPathGraph(spanGraph);

            // filter out self-overlaps from graph
            if (FilterSelfOverlaps)
            {
                PathOverlapRepair repair = new PathOverlapRepair(pathGraph);
                repair.OverlapRadius       = ToolWidth * SelfOverlapToolWidthX;
                repair.PreserveEdgeFilterF = (eid) => {
                    return(repair.Graph.GetEdgeGroup(eid) > 0);
                };
                repair.Compute();
                pathGraph = repair.GetResultGraph();
            }


            HashSet <int> boundaries = new HashSet <int>();

            foreach (int vid in pathGraph.VertexIndices())
            {
                if (pathGraph.IsBoundaryVertex(vid))
                {
                    boundaries.Add(vid);
                }
                if (pathGraph.IsJunctionVertex(vid))
                {
                    throw new Exception("DenseLinesFillPolygon: PathGraph has a junction???");
                }
            }

            // walk paths from boundary vertices
            while (boundaries.Count > 0)
            {
                int start_vid = boundaries.First();
                boundaries.Remove(start_vid);
                int vid = start_vid;
                int eid = pathGraph.GetVtxEdges(vid)[0];

                FillPolyline2d path = new FillPolyline2d()
                {
                    TypeFlags = this.TypeFlags
                };

                path.AppendVertex(pathGraph.GetVertex(vid));
                while (true)
                {
                    Index2i next = DGraph2Util.NextEdgeAndVtx(eid, vid, pathGraph);
                    eid = next.a;
                    vid = next.b;
                    int gid = pathGraph.GetEdgeGroup(eid);
                    if (gid < 0)
                    {
                        path.AppendVertex(pathGraph.GetVertex(vid), TPVertexFlags.IsConnector);
                    }
                    else
                    {
                        path.AppendVertex(pathGraph.GetVertex(vid));
                    }

                    if (boundaries.Contains(vid))
                    {
                        boundaries.Remove(vid);
                        break;
                    }
                }

                // discard paths that are too short
                if (path.ArcLength < MinPathLengthMM)
                {
                    continue;
                }


                // run polyline simplification to get rid of unneccesary detail in connectors
                // [TODO] we could do this at graph level...)
                // [TODO] maybe should be checkign for collisions? we could end up creating
                //  non-trivial overlaps here...
                if (SimplifyAmount != SimplificationLevel.None && path.VertexCount > 2)
                {
                    PolySimplification2 simp = new PolySimplification2(path);
                    switch (SimplifyAmount)
                    {
                    default:
                    case SimplificationLevel.Minor:
                        simp.SimplifyDeviationThreshold = ToolWidth / 4; break;

                    case SimplificationLevel.Aggressive:
                        simp.SimplifyDeviationThreshold = ToolWidth; break;

                    case SimplificationLevel.Moderate:
                        simp.SimplifyDeviationThreshold = ToolWidth / 2; break;
                    }
                    simp.Simplify();
                    path = new FillPolyline2d(simp.Result.ToArray())
                    {
                        TypeFlags = this.TypeFlags
                    };
                }

                paths.Append(path);
            }


            // Check to make sure that we are not putting way too much material in the
            // available volume. Computes extrusion volume from path length and if the
            // ratio is too high, scales down the path thickness
            // TODO: do we need to compute volume? If we just divide everything by
            // height we get the same scaling, no? Then we don't need layer height.
            if (MaxOverfillRatio > 0)
            {
                throw new NotImplementedException("this is not finished yet");
#if false
                double LayerHeight = 0.2;               // AAAHHH hardcoded nonono

                double len         = paths.TotalLength();
                double extrude_vol = ExtrusionMath.PathLengthToVolume(LayerHeight, ToolWidth, len);
                double polygon_vol = LayerHeight * Math.Abs(poly.Area);
                double ratio       = extrude_vol / polygon_vol;

                if (ratio > MaxOverfillRatio && PathSpacing == ToolWidth)
                {
                    double use_width = ExtrusionMath.WidthFromTargetVolume(LayerHeight, len, polygon_vol);
                    //System.Console.WriteLine("Extrusion volume: {0}   PolyVolume: {1}   % {2}   ScaledWidth: {3}",
                    //extrude_vol, polygon_vol, extrude_vol / polygon_vol, use_width);

                    foreach (var path in paths.Curves)
                    {
                        path.CustomThickness = use_width;
                    }
                }
#endif
            }

            return(paths);
        }