Beispiel #1
0
 public SLSPrintGenerator(PrintMeshAssembly meshes,
                          PlanarSliceStack slices,
                          SingleMaterialFFFSettings settings,
                          ThreeAxisLaserCompiler compiler)
 {
     Initialize(meshes, slices, settings, compiler);
 }
Beispiel #2
0
 public SingleMaterialFFFPrintGenPro(PrintMeshAssembly meshes,
                                     PlanarSliceStack slices,
                                     SingleMaterialFFFSettings settings,
                                     AssemblerFactoryF overrideAssemblerF = null)
     : base(meshes, slices, settings, overrideAssemblerF)
 {
 }
 public SingleMaterialFFFPrintGenerator(PrintMeshAssembly meshes,
                                        PlanarSliceStack slices,
                                        SingleMaterialFFFSettings settings,
                                        AssemblerFactoryF overrideAssemblerF = null)
 {
     Initialize(meshes, slices, settings, overrideAssemblerF);
 }
 public SLSPrintGenerator(PrintMeshAssembly meshes,
                          PlanarSliceStack slices,
                          PrintProfileFFF settings,
                          IThreeAxisLaserCompiler compiler)
 {
     Initialize(meshes, slices, settings, compiler);
 }
Beispiel #5
0
        public GCodeFile GCodeFromPrintMeshAssembly(PrintMeshAssembly printMeshAssembly, out IEnumerable <string> generationReport, TPrintSettings settings = null)
        {
            PlanarSliceStack slices = null;

            if (AcceptsParts)
            {
                SliceMesh(printMeshAssembly, out slices);
            }

            var globalSettings = settings ?? settingsBuilder.Settings;

            // Run the print generator
            logger.WriteLine("Running print generator...");
            var printGenerator = new TPrintGenerator();
            AssemblerFactoryF overrideAssemblerF = globalSettings.AssemblerType();

            printGenerator.Initialize(printMeshAssembly, slices, globalSettings, overrideAssemblerF);

            if (printGenerator.Generate())
            {
                generationReport = printGenerator.GenerationReport;
                return(printGenerator.Result);
            }
            else
            {
                throw new Exception("PrintGenerator failed to generate gcode!");
            }
        }
Beispiel #6
0
        public virtual GCodeFile GCodeFromPrintMeshAssembly(PrintMeshAssembly printMeshAssembly, out GCodeGenerationDetails details, TPrintSettings settings = null, CancellationToken?cancellationToken = null)
        {
            PlanarSliceStack slices = null;

            var globalSettings = settings ?? settingsBuilder.Settings;

            if (AcceptsParts)
            {
                SliceMesh(printMeshAssembly, out slices, globalSettings.Part.LayerHeightMM);
            }

            // Run the print generator
            logger.WriteLine("Running print generator...");
            var printGenerator = new TPrintGenerator();
            AssemblerFactoryF overrideAssemblerF = (globalSettings.MachineProfile as MachineProfileBase).AssemblerFactory();

            printGenerator.Initialize(printMeshAssembly, slices, globalSettings, overrideAssemblerF);

            if (printGenerator.Generate(cancellationToken))
            {
                details = new GCodeGenerationDetails(printGenerator.PrintTimeEstimate, printGenerator.MaterialUsageEstimate, printGenerator.Warnings);
                return(printGenerator.Result);
            }
            else
            {
                throw new Exception("PrintGenerator failed to generate gcode!");
            }
        }
Beispiel #7
0
 public void Initialize(PrintMeshAssembly meshes,
                        PlanarSliceStack slices,
                        SingleMaterialFFFSettings settings,
                        ThreeAxisLaserCompiler compiler)
 {
     PrintMeshes = meshes;
     Slices      = slices;
     Settings    = settings;
     Compiler    = compiler;
 }
 public void Initialize(PrintMeshAssembly meshes,
                        PlanarSliceStack slices,
                        PrintProfileFFF settings,
                        IThreeAxisLaserCompiler compiler)
 {
     PrintMeshes = meshes;
     Slices      = slices;
     Settings    = settings;
     Compiler    = compiler;
 }
        public GenericSLSPrintGenerator(PrintMeshAssembly meshes,
                                        PlanarSliceStack slices,
                                        SingleMaterialFFFSettings settings)
        {
            file_accumulator = new GCodeFileAccumulator();
            //builder = new GCodeBuilder(file_accumulator);
            //compiler = new SLSCompiler(builder, settings);
            compiler = new SLSCompiler(settings);

            base.Initialize(meshes, slices, settings, compiler);
        }
        public override void Initialize(PrintMeshAssembly meshes,
                                        PlanarSliceStack slices,
                                        SingleMaterialFFFSettings settings,
                                        AssemblerFactoryF overrideAssemblerF = null)
        {
            file_accumulator = new GCodeFileAccumulator();
            builder          = new GCodeBuilder(file_accumulator);
            AssemblerFactoryF useAssembler = overrideAssemblerF ?? settings.AssemblerType();

            compiler = new SingleMaterialFFFCompiler(builder, settings, useAssembler);
            Initialize(meshes, slices, settings, compiler);
        }
Beispiel #11
0
        private void SliceMesh(PrintMeshAssembly meshes, out PlanarSliceStack slices)
        {
            logger?.WriteLine("Slicing...");

            // Do slicing
            MeshPlanarSlicer slicer = new MeshPlanarSlicer()
            {
                LayerHeightMM = Settings.LayerHeightMM
            };

            slicer.Add(meshes);
            slices = slicer.Compute();
        }
Beispiel #12
0
        protected virtual void SliceMesh(PrintMeshAssembly meshes, out PlanarSliceStack slices, double layerHeight)
        {
            logger?.WriteLine("Slicing...");

            // Do slicing
            MeshPlanarSlicer slicer = new MeshPlanarSlicer()
            {
                LayerHeightMM = layerHeight,
            };

            slicer.Add(meshes);
            slices = slicer.Compute();
        }
Beispiel #13
0
        public GCodeFile GenerateGCode(IList <Tuple <DMesh3, TPrintSettings> > parts,
                                       TPrintSettings globalSettings,
                                       out IEnumerable <string> generationReport,
                                       Action <GCodeLine> gcodeLineReadyF = null,
                                       Action <string> progressMessageF   = null)
        {
            if (AcceptsParts == false && parts != null && parts.Count > 0)
            {
                throw new Exception("Must pass null or empty list of parts to generator that does not accept parts.");
            }

            // Create print mesh set
            PrintMeshAssembly meshes = new PrintMeshAssembly();

            foreach (var part in parts)
            {
                if (part.Item2 != null)
                {
                    throw new ArgumentException($"Entries for the `parts` arguments must have a null second item since this generator does not handle per-part settings.");
                }
                meshes.AddMesh(part.Item1, PrintMeshOptions.Default());
            }

            progressMessageF?.Invoke("Slicing...");

            // Do slicing
            MeshPlanarSlicer slicer = new MeshPlanarSlicer()
            {
                LayerHeightMM = globalSettings.LayerHeightMM
            };

            slicer.Add(meshes);
            PlanarSliceStack slices = slicer.Compute();

            // Run the print generator
            progressMessageF?.Invoke("Running print generator...");
            var printGenerator = new TPrintGenerator();
            AssemblerFactoryF overrideAssemblerF = globalSettings.AssemblerType();

            printGenerator.Initialize(meshes, slices, globalSettings, overrideAssemblerF);

            if (printGenerator.Generate())
            {
                generationReport = printGenerator.GenerationReport;
                return(printGenerator.Result);
            }
            else
            {
                throw new Exception("PrintGenerator failed to generate gcode!");
            }
        }
Beispiel #14
0
        /// <summary>
        /// Slice the meshes and return the slice stack.
        /// </summary>
        public PlanarSliceStack Compute()
        {
            if (Meshes.Count == 0)
            {
                return(new PlanarSliceStack());
            }

            Interval1d zrange = Interval1d.Empty;

            foreach (var meshinfo in Meshes)
            {
                zrange.Contain(meshinfo.bounds.Min.z);
                zrange.Contain(meshinfo.bounds.Max.z);
            }
            if (SetMinZValue != double.MinValue)
            {
                zrange.a = SetMinZValue;
            }

            // construct layers
            List <PlanarSlice> slice_list = new List <PlanarSlice>();

            double cur_layer_z = zrange.a;
            int    layer_i     = 0;

            while (cur_layer_z < zrange.b)
            {
                double     layer_height = get_layer_height(layer_i);
                double     z            = cur_layer_z;
                Interval1d zspan        = new Interval1d(z, z + layer_height);
                if (SliceLocation == SliceLocations.EpsilonBase)
                {
                    z += 0.01 * layer_height;
                }
                else if (SliceLocation == SliceLocations.MidLine)
                {
                    z += 0.5 * layer_height;
                }

                PlanarSlice slice = SliceFactoryF(zspan, z, layer_i);
                slice.EmbeddedPathWidth = OpenPathDefaultWidthMM;
                slice_list.Add(slice);

                layer_i++;
                cur_layer_z += layer_height;
            }
            int NH = slice_list.Count;

            if (NH > MaxLayerCount)
            {
                throw new Exception("MeshPlanarSlicer.Compute: exceeded layer limit. Increase .MaxLayerCount.");
            }

            PlanarSlice[] slices = slice_list.ToArray();

            // determine if we have crop objects
            bool have_crop_objects = false;

            foreach (var mesh in Meshes)
            {
                if (mesh.options.IsCropRegion)
                {
                    have_crop_objects = true;
                }
            }

            // assume Resolve() takes 2x as long as meshes...
            TotalCompute = (Meshes.Count * NH) + (2 * NH);
            Progress     = 0;

            // compute slices separately for each mesh
            for (int mi = 0; mi < Meshes.Count; ++mi)
            {
                if (Cancelled())
                {
                    break;
                }

                DMesh3           mesh         = Meshes[mi].mesh;
                PrintMeshOptions mesh_options = Meshes[mi].options;

                // [TODO] should we hang on to this spatial? or should it be part of assembly?
                DMeshAABBTree3   spatial = new DMeshAABBTree3(mesh, true);
                AxisAlignedBox3d bounds  = Meshes[mi].bounds;

                bool is_cavity   = mesh_options.IsCavity;
                bool is_crop     = mesh_options.IsCropRegion;
                bool is_support  = mesh_options.IsSupport;
                bool is_closed   = (mesh_options.IsOpen) ? false : mesh.IsClosed();
                var  useOpenMode = (mesh_options.OpenPathMode == OpenPathsModes.Default) ?
                                   DefaultOpenPathMode : mesh_options.OpenPathMode;

                // each layer is independent so we can do in parallel
                gParallel.ForEach(Interval1i.Range(NH), (i) =>
                {
                    if (Cancelled())
                    {
                        return;
                    }

                    double z = slices[i].Z;
                    if (z < bounds.Min.z || z > bounds.Max.z)
                    {
                        return;
                    }

                    // compute cut
                    Polygon2d[] polys; PolyLine2d[] paths;
                    compute_plane_curves(mesh, spatial, z, is_closed, out polys, out paths);

                    // if we didn't hit anything, try again with jittered plane
                    // [TODO] this could be better...
                    if ((is_closed && polys.Length == 0) || (is_closed == false && polys.Length == 0 && paths.Length == 0))
                    {
                        double jitterz = slices[i].LayerZSpan.Interpolate(0.75);
                        compute_plane_curves(mesh, spatial, jitterz, is_closed, out polys, out paths);
                    }

                    if (is_closed)
                    {
                        // construct planar complex and "solids"
                        // (ie outer polys and nested holes)
                        PlanarComplex complex = new PlanarComplex();
                        foreach (Polygon2d poly in polys)
                        {
                            complex.Add(poly);
                        }

                        PlanarComplex.FindSolidsOptions options
                            = PlanarComplex.FindSolidsOptions.Default;
                        options.WantCurveSolids            = false;
                        options.SimplifyDeviationTolerance = 0.001;
                        options.TrustOrientations          = true;
                        options.AllowOverlappingHoles      = true;

                        PlanarComplex.SolidRegionInfo solids   = complex.FindSolidRegions(options);
                        List <GeneralPolygon2d> solid_polygons = ApplyValidRegions(solids.Polygons);

                        if (is_support)
                        {
                            add_support_polygons(slices[i], solid_polygons, mesh_options);
                        }
                        else if (is_cavity)
                        {
                            add_cavity_polygons(slices[i], solid_polygons, mesh_options);
                        }
                        else if (is_crop)
                        {
                            add_crop_region_polygons(slices[i], solid_polygons, mesh_options);
                        }
                        else
                        {
                            add_solid_polygons(slices[i], solid_polygons, mesh_options);
                        }
                    }
                    else if (useOpenMode != OpenPathsModes.Ignored)
                    {
                        // [TODO]
                        //   - does not really handle clipped polygons properly, there will be an extra break somewhere...
                        List <PolyLine2d> all_paths = new List <PolyLine2d>(paths);
                        foreach (Polygon2d poly in polys)
                        {
                            all_paths.Add(new PolyLine2d(poly, true));
                        }

                        List <PolyLine2d> open_polylines = ApplyValidRegions(all_paths);
                        foreach (PolyLine2d pline in open_polylines)
                        {
                            if (useOpenMode == OpenPathsModes.Embedded)
                            {
                                slices[i].AddEmbeddedPath(pline);
                            }
                            else
                            {
                                slices[i].AddClippedPath(pline);
                            }
                        }
                    }

                    Interlocked.Increment(ref Progress);
                });  // end of parallel.foreach
            } // end mesh iter

            // resolve planar intersections, etc
            gParallel.ForEach(Interval1i.Range(NH), (i) =>
            {
                if (Cancelled())
                {
                    return;
                }

                if (have_crop_objects && slices[i].InputCropRegions.Count == 0)
                {
                    // don't resolve, we have fully cropped this layer
                }
                else
                {
                    slices[i].Resolve();
                }

                Interlocked.Add(ref Progress, 2);
            });

            // discard spurious empty slices
            int last = slices.Length - 1;

            while (slices[last].IsEmpty && last > 0)
            {
                last--;
            }
            int first = 0;

            if (DiscardEmptyBaseSlices || have_crop_objects)
            {
                while (slices[first].IsEmpty && first < slices.Length)
                {
                    first++;
                }
            }

            PlanarSliceStack stack = SliceStackFactoryF();

            for (int k = first; k <= last; ++k)
            {
                stack.Add(slices[k]);
            }

            if (SupportMinZTips)
            {
                stack.AddMinZTipSupportPoints(MinZTipMaxDiam, MinZTipExtraLayers);
            }

            return(stack);
        }
Beispiel #15
0
        /// <summary>
        /// Slice the meshes and return the slice stack.
        /// </summary>
        public PlanarSliceStack Compute()
        {
            if (Meshes.Count == 0)
            {
                return(new PlanarSliceStack());
            }

            Interval1d zrange = Interval1d.Empty;

            foreach (var meshinfo in Meshes)
            {
                zrange.Contain(meshinfo.bounds.Min.z);
                zrange.Contain(meshinfo.bounds.Max.z);
            }
            if (SetMinZValue != double.MinValue)
            {
                zrange.a = SetMinZValue;
            }

            int nLayers = (int)(zrange.Length / LayerHeightMM);

            if (nLayers > MaxLayerCount)
            {
                throw new Exception("MeshPlanarSlicer.Compute: exceeded layer limit. Increase .MaxLayerCount.");
            }

            // make list of slice heights (could be irregular)
            List <double> heights = new List <double>();

            for (int i = 0; i < nLayers + 1; ++i)
            {
                double t = zrange.a + (double)i * LayerHeightMM;
                if (SliceLocation == SliceLocations.EpsilonBase)
                {
                    t += 0.01 * LayerHeightMM;
                }
                else if (SliceLocation == SliceLocations.MidLine)
                {
                    t += 0.5 * LayerHeightMM;
                }
                heights.Add(t);
            }
            int NH = heights.Count;

            // process each *slice* in parallel
            PlanarSlice[] slices = new PlanarSlice[NH];
            for (int i = 0; i < NH; ++i)
            {
                slices[i] = SliceFactoryF(heights[i], i);
                slices[i].EmbeddedPathWidth = OpenPathDefaultWidthMM;
            }

            // assume Resolve() takes 2x as long as meshes...
            TotalCompute = (Meshes.Count * NH) + (2 * NH);
            Progress     = 0;


            // compute slices separately for each mesh
            for (int mi = 0; mi < Meshes.Count; ++mi)
            {
                if (Cancelled())
                {
                    break;
                }

                DMesh3           mesh         = Meshes[mi].mesh;
                PrintMeshOptions mesh_options = Meshes[mi].options;

                // [TODO] should we hang on to this spatial? or should it be part of assembly?
                DMeshAABBTree3   spatial = new DMeshAABBTree3(mesh, true);
                AxisAlignedBox3d bounds  = Meshes[mi].bounds;

                bool is_cavity   = mesh_options.IsCavity;
                bool is_crop     = mesh_options.IsCropRegion;
                bool is_support  = mesh_options.IsSupport;
                bool is_closed   = (mesh_options.IsOpen) ? false : mesh.IsClosed();
                var  useOpenMode = (mesh_options.OpenPathMode == PrintMeshOptions.OpenPathsModes.Default) ?
                                   DefaultOpenPathMode : mesh_options.OpenPathMode;

                // each layer is independent so we can do in parallel
                gParallel.ForEach(Interval1i.Range(NH), (i) => {
                    if (Cancelled())
                    {
                        return;
                    }

                    double z = heights[i];
                    if (z < bounds.Min.z || z > bounds.Max.z)
                    {
                        return;
                    }

                    // compute cut
                    Polygon2d[] polys; PolyLine2d[] paths;
                    compute_plane_curves(mesh, spatial, z, is_closed, out polys, out paths);

                    // if we didn't hit anything, try again with jittered plane
                    // [TODO] this could be better...
                    if ((is_closed && polys.Length == 0) || (is_closed == false && polys.Length == 0 && paths.Length == 0))
                    {
                        compute_plane_curves(mesh, spatial, z + LayerHeightMM * 0.25, is_closed, out polys, out paths);
                    }

                    if (is_closed)
                    {
                        // construct planar complex and "solids"
                        // (ie outer polys and nested holes)
                        PlanarComplex complex = new PlanarComplex();
                        foreach (Polygon2d poly in polys)
                        {
                            complex.Add(poly);
                        }

                        PlanarComplex.FindSolidsOptions options
                            = PlanarComplex.FindSolidsOptions.Default;
                        options.WantCurveSolids            = false;
                        options.SimplifyDeviationTolerance = 0.001;
                        options.TrustOrientations          = true;
                        options.AllowOverlappingHoles      = true;

                        PlanarComplex.SolidRegionInfo solids =
                            complex.FindSolidRegions(options);

                        if (is_support)
                        {
                            add_support_polygons(slices[i], solids.Polygons, mesh_options);
                        }
                        else if (is_cavity)
                        {
                            add_cavity_polygons(slices[i], solids.Polygons, mesh_options);
                        }
                        else if (is_crop)
                        {
                            add_crop_region_polygons(slices[i], solids.Polygons, mesh_options);
                        }
                        else
                        {
                            add_solid_polygons(slices[i], solids.Polygons, mesh_options);
                        }
                    }
                    else if (useOpenMode != PrintMeshOptions.OpenPathsModes.Ignored)
                    {
                        foreach (PolyLine2d pline in paths)
                        {
                            if (useOpenMode == PrintMeshOptions.OpenPathsModes.Embedded)
                            {
                                slices[i].AddEmbeddedPath(pline);
                            }
                            else
                            {
                                slices[i].AddClippedPath(pline);
                            }
                        }

                        // [TODO]
                        //   - does not really handle clipped polygons properly, there will be an extra break somewhere...
                        foreach (Polygon2d poly in polys)
                        {
                            PolyLine2d pline = new PolyLine2d(poly, true);
                            if (useOpenMode == PrintMeshOptions.OpenPathsModes.Embedded)
                            {
                                slices[i].AddEmbeddedPath(pline);
                            }
                            else
                            {
                                slices[i].AddClippedPath(pline);
                            }
                        }
                    }

                    Interlocked.Increment(ref Progress);
                });       // end of parallel.foreach
            }             // end mesh iter

            // resolve planar intersections, etc
            gParallel.ForEach(Interval1i.Range(NH), (i) => {
                if (Cancelled())
                {
                    return;
                }
                slices[i].Resolve();
                Interlocked.Add(ref Progress, 2);
            });

            // discard spurious empty slices
            int last = slices.Length - 1;

            while (slices[last].IsEmpty && last > 0)
            {
                last--;
            }
            int first = 0;

            if (DiscardEmptyBaseSlices)
            {
                while (slices[first].IsEmpty && first < slices.Length)
                {
                    first++;
                }
            }

            PlanarSliceStack stack = SliceStackFactoryF();

            for (int k = first; k <= last; ++k)
            {
                stack.Add(slices[k]);
            }

            if (SupportMinZTips)
            {
                stack.AddMinZTipSupportPoints(MinZTipMaxDiam, MinZTipExtraLayers);
            }

            return(stack);
        }
Beispiel #16
0
 public Result()
 {
     Clearing         = new PlanarSliceStack();
     HorizontalFinish = new PlanarSliceStack();
 }