public void Calculate(Vector3d vStartPos, double fStartA, bool alreadyInRetract = false)
        {
            double   curA    = fStartA;
            Vector3d curPos  = vStartPos;
            double   curRate = 0;

            bool inRetract = alreadyInRetract;

            // filter paths
            List <IToolpath> allPaths = new List <IToolpath>();

            foreach (IToolpath p in Paths)
            {
                if (p is LinearToolpath3 <T> || p is ResetExtruderPathHack)
                {
                    allPaths.Add(p);
                }
            }

            int N = allPaths.Count;

            LinearToolpath3 <T> prev_path = null;

            for (int pi = 0; pi < N; ++pi)
            {
                if (allPaths[pi] is ResetExtruderPathHack)
                {
                    curA = 0;
                    continue;
                }
                var path = allPaths[pi] as LinearToolpath3 <T>;

                if (path == null)
                {
                    throw new Exception("Invalid path type!");
                }
                if (!(path.Type == ToolpathTypes.Deposition || path.Type == ToolpathTypes.PlaneChange || path.Type == ToolpathTypes.Travel))
                {
                    throw new Exception("Unknown path type!");
                }

                // if we are travelling between two extrusion paths, and neither is support,
                // and the travel distance is very short,then we will skip the retract.
                // [TODO] should only do this on interior travels. We should determine that upstream and set a flag on travel path.
                bool skip_retract = false;
                if (path.Type == ToolpathTypes.Travel && path.Length < MinRetractTravelLength)
                {
                    bool prev_is_model_deposition =
                        (prev_path != null) && (prev_path.Type == ToolpathTypes.Deposition) && prev_path.FillType.IsPart();
                    var  next_path = (pi < N - 1) ? (allPaths[pi + 1] as LinearToolpath3 <T>) : null;
                    bool next_is_model_deposition =
                        (next_path != null) && (next_path.Type == ToolpathTypes.Deposition) && next_path.FillType.IsPart();
                    skip_retract = prev_is_model_deposition && next_is_model_deposition;
                }
                if (EnableRetraction == false)
                {
                    skip_retract = true;
                }

                // figure out volume scaling based on path type
                double vol_scale = 1.0;
                vol_scale = path.FillType.AdjustVolume(vol_scale);

                for (int i = 0; i < path.VertexCount; ++i)
                {
                    bool last_vtx = (i == path.VertexCount - 1);

                    Vector3d newPos  = path[i].Position;
                    double   newRate = path[i].FeedRate;

                    // default line thickness and height
                    double path_width  = Settings.Machine.NozzleDiamMM;
                    double path_height = Settings.Part.LayerHeightMM;

                    // override with custom dimensions if provided
                    Vector2d vtx_dims = path[i].Dimensions;
                    if (vtx_dims.x > 0 && vtx_dims.x < 1000.0)
                    {
                        path_width = vtx_dims.x;
                    }
                    if (vtx_dims.y > 0 && vtx_dims.y < 1000.0)
                    {
                        path_height = vtx_dims.y;
                    }

                    if (path.Type != ToolpathTypes.Deposition)
                    {
                        // [RMS] if we switched to a travel move we retract, unless we don't
                        if (skip_retract == false)
                        {
                            if (!inRetract)
                            {
                                curA     -= FixedRetractDistance;
                                inRetract = true;
                            }
                        }

                        curPos  = newPos;
                        curRate = newRate;
                    }
                    else
                    {
                        // for i == 0 this dist is always 0 !!
                        double dist = (newPos - curPos).Length;

                        if (i == 0)
                        {
                            Util.gDevAssert(dist < 1e-12);     // next path starts at end of previous!!
                            if (inRetract)
                            {
                                curA     += FixedRetractDistance;
                                inRetract = false;
                            }
                        }
                        else
                        {
                            curPos  = newPos;
                            curRate = newRate;

                            double segment_width = (path[i].Dimensions.x != GCodeUtil.UnspecifiedValue) ?
                                                   path[i].Dimensions.x : path_width;

                            double segment_height = (path[i].Dimensions.y != GCodeUtil.UnspecifiedValue) ?
                                                    path[i].Dimensions.y : path_height;

                            double feed = ExtrusionMath.PathLengthToFilamentLength(
                                segment_height, segment_width, Settings.Material.FilamentDiamMM,
                                dist, vol_scale);

                            // Change the extrusion amount if a modifier is present.
                            // TODO: This is a bit of a hack since the modifier acts on a Vector3d
                            //       and we're ignoring data in the second & third positions.
                            var modifier = path[i]?.ExtendedData?.ExtrusionModifierF;
                            if (modifier != null)
                            {
                                feed = modifier(new Vector3d(feed, 0, 0))[0];
                            }

                            curA += feed;
                        }
                    }

                    T v = path[i];
                    v.Extrusion = GCodeUtil.Extrude(curA);
                    path.UpdateVertex(i, v);
                }

                prev_path = path;
            }

            NumPaths        = N;
            ExtrusionLength = curA;
        } // Calculate()
Exemple #2
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);
        }
        public void Calculate(Vector3d vStartPos, double fStartA, bool alreadyInRetract = false)
        {
            double   curA    = fStartA;
            Vector3d curPos  = vStartPos;
            double   curRate = 0;

            bool inRetract = alreadyInRetract;

            // filter paths
            List <IToolpath> allPaths = new List <IToolpath>();

            foreach (IToolpath ipath in Paths)
            {
                ToolpathUtil.ApplyToLeafPaths(ipath, (p) => {
                    if (p is LinearToolpath3 <PrintVertex> || p is ResetExtruderPathHack)
                    {
                        allPaths.Add(p);
                    }
                });
            }
            int N = allPaths.Count;


            LinearToolpath3 <PrintVertex> prev_path = null;

            for (int pi = 0; pi < N; ++pi)
            {
                if (allPaths[pi] is ResetExtruderPathHack)
                {
                    curA = 0;
                    continue;
                }
                LinearToolpath3 <PrintVertex> path = allPaths[pi] as LinearToolpath3 <PrintVertex>;

                if (path == null)
                {
                    throw new Exception("Invalid path type!");
                }
                if (!(path.Type == ToolpathTypes.Deposition || path.Type == ToolpathTypes.PlaneChange || path.Type == ToolpathTypes.Travel))
                {
                    throw new Exception("Unknown path type!");
                }

                // if we are travelling between two extrusion paths, and neither is support,
                // and the travel distance is very short,then we will skip the retract.
                // [TODO] should only do this on interior travels. We should determine that upstream and set a flag on travel path.
                bool skip_retract = false;
                if (path.Type == ToolpathTypes.Travel && path.Length < MinRetractTravelLength)
                {
                    bool prev_is_model_deposition =
                        (prev_path != null) && (prev_path.Type == ToolpathTypes.Deposition) && ((prev_path.TypeModifiers & FillTypeFlags.SupportMaterial) == 0);
                    LinearToolpath3 <PrintVertex> next_path = (pi < N - 1) ? (allPaths[pi + 1] as LinearToolpath3 <PrintVertex>) : null;
                    bool next_is_model_deposition           =
                        (next_path != null) && (next_path.Type == ToolpathTypes.Deposition) && ((next_path.TypeModifiers & FillTypeFlags.SupportMaterial) == 0);
                    skip_retract = prev_is_model_deposition && next_is_model_deposition;
                }
                if (EnableRetraction == false)
                {
                    skip_retract = true;
                }

                // figure out volume scaling based on path type
                double vol_scale = 1.0;
                if ((path.TypeModifiers & FillTypeFlags.SupportMaterial) != 0)
                {
                    vol_scale *= SupportExtrudeScale;
                }
                else if ((path.TypeModifiers & FillTypeFlags.BridgeSupport) != 0)
                {
                    vol_scale *= Settings.BridgeVolumeScale;
                }

                for (int i = 0; i < path.VertexCount; ++i)
                {
                    bool last_vtx = (i == path.VertexCount - 1);

                    Vector3d newPos  = path[i].Position;
                    double   newRate = path[i].FeedRate;

                    // default line thickness and height
                    double path_width  = Settings.Machine.NozzleDiamMM;
                    double path_height = Settings.LayerHeightMM;

                    // override with custom dimensions if provided
                    Vector2d vtx_dims = path[i].Dimensions;
                    if (vtx_dims.x > 0 && vtx_dims.x < 1000.0)
                    {
                        path_width = vtx_dims.x;
                    }
                    if (vtx_dims.y > 0 && vtx_dims.y < 1000.0)
                    {
                        path_height = vtx_dims.y;
                    }

                    if (path.Type != ToolpathTypes.Deposition)
                    {
                        // [RMS] if we switched to a travel move we retract, unless we don't
                        if (skip_retract == false)
                        {
                            if (!inRetract)
                            {
                                curA     -= FixedRetractDistance;
                                inRetract = true;
                            }
                        }

                        curPos  = newPos;
                        curRate = newRate;
                    }
                    else
                    {
                        // for i == 0 this dist is always 0 !!
                        double dist = (newPos - curPos).Length;

                        if (i == 0)
                        {
                            Util.gDevAssert(dist == 0);     // next path starts at end of previous!!
                            if (inRetract)
                            {
                                curA     += FixedRetractDistance;
                                inRetract = false;
                            }
                        }
                        else
                        {
                            curPos  = newPos;
                            curRate = newRate;

                            double feed = ExtrusionMath.PathLengthToFilamentLength(
                                path_height, path_width, Settings.Machine.FilamentDiamMM,
                                dist, vol_scale);
                            curA += feed;
                        }
                    }

                    PrintVertex v = path[i];
                    v.Extrusion = GCodeUtil.Extrude(curA);
                    path.UpdateVertex(i, v);
                }

                prev_path = path;
            }

            NumPaths        = N;
            ExtrusionLength = curA;
        }         // Calculate()