예제 #1
0
        public async void BuildAllSlices()
        {
            // Main task is run on another thread,
            // so that the UI thread does not block and we can update progress bar
            // and display current built slice.

            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                this.data.SlicingProgressValue = 0;
                this.data.SlicingInProgress    = true;
                this.data.ProgressBarColor     = SliceModel.StateBrushes[0];
            });

            this.Original = SliceModel.GeometrizeModel(this.data.CurrentModel);
            var bounds    = this.data.CurrentModel.Bounds;
            var transform = this.data.CurrentModel.Transform;

            var min   = Math.Min(bounds.X, bounds.Y);
            var max   = Math.Max(bounds.X + bounds.SizeX, bounds.Y + bounds.SizeY);
            var size  = Math.Min(this.data.SliceCanvas.ActualWidth, this.data.SliceCanvas.ActualHeight);
            var scale = size / (max - min);

            var dense_spacing = this.data.NozzleDiameter * 2.375;  // Default dense_spacing == 0.95

            this.SliceStore = Enumerable.Repeat <Slice>(null, this.data.MaxSliceIdx + 1).ToList();

            Construct obj = Construct.Create(this.Original, transform);

            // Genarate infills
            var infill_struct = Polygon2D.GenerateInfill(
                bounds.X, bounds.Y,
                bounds.X + bounds.SizeX, bounds.Y + bounds.SizeY,
                this.data.NozzleDiameter, this.data.InfillSpacing, this.data.UseInfill
                );

            var surface_struct = Polygon2D.GenerateInfill(
                bounds.X, bounds.Y,
                bounds.X + bounds.SizeX, bounds.Y + bounds.SizeY,
                this.data.NozzleDiameter, dense_spacing, InfillType.SINGLE
                );

            var surface_struct_alt = Polygon2D.GenerateInfill(
                bounds.X, bounds.Y,
                bounds.X + bounds.SizeX, bounds.Y + bounds.SizeY,
                this.data.NozzleDiameter, dense_spacing, InfillType.SINGLE_ROTATED
                );

            var support_struct = Polygon2D.GenerateInfill(
                bounds.X, bounds.Y,
                bounds.X + bounds.SizeX, bounds.Y + bounds.SizeY,
                this.data.NozzleDiameter, this.data.SupportSpacing, this.data.UseSupport
                );

            await Task.Run(() =>
            {
                //// For debug, set `opt` to 1, else -1 for unlimited
                var opt = new ParallelOptions()
                {
                    MaxDegreeOfParallelism = -1
                };

                // Execute slicing
                // Step 1: Find contours by slicing with Z plane and Erode
                Parallel.For(0, this.data.MaxSliceIdx + 1, opt, (i) => {
                    // Construct slice
                    var slice = obj.Slice(bounds.Z + i *data.NozzleThickness,
                                          data.NozzleThickness);
                    slice.SetNozzleHeight((i + 1) * data.NozzleThickness);
                    slice.Erode(data.NozzleDiameter / 2.0);
                    this.SliceStore[i] = slice;

                    System.Windows.Application.Current.Dispatcher.Invoke(() =>
                    {
                        this.data.SlicingProgressValue++;
                    });
                });

                // Adjust Nozzle height to ignore empty bottom layers
                var first_index = this.SliceStore.FindIndex(s => s.Polygons.Count > 0);
                if (first_index > 0)
                {
                    for (int i = 0; i < this.data.MaxSliceIdx + 1 - first_index; i++)
                    {
                        this.SliceStore[i + first_index].SetNozzleHeight((i + 1) * data.NozzleThickness);
                    }
                }

                System.Windows.Application.Current.Dispatcher.Invoke(() =>
                {
                    this.data.SlicingProgressValue = 0;
                    this.data.ProgressBarColor     = SliceModel.StateBrushes[1];
                });


                // Step 2: Generate Support
                for (int i = 0; i < this.data.MaxSliceIdx + 1; i++)
                {
                    var j = this.data.MaxSliceIdx - i;

                    var current = this.SliceStore.ElementAtOrDefault(j);
                    var above   = this.SliceStore.ElementAtOrDefault(j + 1);

                    current.GenerateSupport(above, this.data.NozzleThickness);

                    System.Windows.Application.Current.Dispatcher.Invoke(() =>
                    {
                        this.data.SlicingProgressValue++;
                    });
                }
                ;

                System.Windows.Application.Current.Dispatcher.Invoke(() =>
                {
                    this.data.SlicingProgressValue = 0;
                    this.data.ProgressBarColor     = SliceModel.StateBrushes[2];
                });


                // Step 3: Determine surfaces
                //         Compare with layer above and below to find and add floor/roofs.
                Parallel.For(0, this.data.MaxSliceIdx + 1, opt, (i) => {
                    var slice = this.SliceStore[i];

                    // Determine surfaces
                    slice.DetermineSurfaces(this.SliceStore.ElementAtOrDefault(i - 1),
                                            this.SliceStore.ElementAtOrDefault(i + 1));

                    System.Windows.Application.Current.Dispatcher.Invoke(() =>
                    {
                        this.data.SlicingProgressValue++;
                    });
                });

                Parallel.For(0, this.data.MaxSliceIdx + 1, opt, (i) =>
                {
                    this.SliceStore[i].AddFoundSurfaces();
                });

                System.Windows.Application.Current.Dispatcher.Invoke(() =>
                {
                    this.data.SlicingProgressValue = 0;
                    this.data.ProgressBarColor     = SliceModel.StateBrushes[3];
                });


                // Step 4: Propagate roof/floors
                var floors = new List <Polygon2D>();
                var roofs  = new List <Polygon2D>();

                for (int i = 0; i < this.data.MaxSliceIdx + 1; i++)
                {
                    var from_below = this.SliceStore.ElementAtOrDefault(i);
                    var from_above = this.SliceStore.ElementAtOrDefault(this.data.MaxSliceIdx - i);

                    if (from_below != null && from_below.Polygons.Count > 0)
                    {
                        // Get floors that need to be propagated
                        var propagate = from_below.Polygons
                                        .Where(p => p.IsSurface && p.IsFloor)
                                        .Select(p => { p.Shell = this.data.NumberOfShells - 1; return(p); })
                                        .ToList();      // To list, else enumerator will select floors added in next statement

                        // Add floor polies from current that need to go up
                        from_below.Polygons.AddRange(
                            floors.Where(p => p.Shell > 0)
                            .Select(p => { p.Shell--; return(p); }));

                        floors.AddRange(propagate);
                    }

                    if (from_above != null && from_above.Polygons.Count > 0)
                    {
                        // Get roofs that need to be propagated
                        var propagate = from_above.Polygons
                                        .Where(p => p.IsSurface && p.IsRoof)
                                        .Select(p => { p.Shell = this.data.NumberOfShells - 1; return(p); })
                                        .ToList();      // To list, else enumerator will select roofs added in next statement

                        // Add roof polies from current that need to go down
                        from_above.Polygons.AddRange(
                            roofs.Where(p => p.Shell > 0)
                            .Select(p => { p.Shell--; return(p); }));

                        roofs.AddRange(propagate);
                    }

                    floors = floors.Where(p => p.Shell > 0).ToList();
                    roofs  = roofs.Where(p => p.Shell > 0).ToList();

                    System.Windows.Application.Current.Dispatcher.Invoke(() =>
                    {
                        this.data.SlicingProgressValue++;
                    });
                }

                System.Windows.Application.Current.Dispatcher.Invoke(() =>
                {
                    this.data.SlicingProgressValue = 0;
                    this.data.ProgressBarColor     = SliceModel.StateBrushes[4];
                });


                // Step 5: Add shells and infill
                Parallel.For(0, this.data.MaxSliceIdx + 1, opt, (i) => {
                    // Check for floor/roofs
                    var slice = this.SliceStore[i];

                    // Add shells
                    slice.AddShells(data.NumberOfShells, data.NozzleDiameter *dense_spacing);

                    // Add infill for surfaces
                    slice.AddDenseInfill(i % 2 == 0 ? surface_struct : surface_struct_alt);
                    slice.AddSupportInfill(support_struct, this.data.NozzleDiameter *dense_spacing,
                                           this.data.UseSupport == InfillType.ZIGZAG || this.data.UseSupport < InfillType.RECTANGLE);
                    slice.AddInfill(infill_struct);

                    // Reverse order polies
                    slice.SortPolygons();

                    // Add shapes
                    System.Windows.Application.Current.Dispatcher.Invoke(() =>
                    {
                        if (i > 0)
                        {
                            slice.ToShapes(bounds.X, bounds.Y, scale, this.data.PreviewArrowThickness, this.data.PreviewStrokeThickness);
                        }
                        this.data.SlicingProgressValue++;
                    });
                });


                // Step 6: Add adhesion to ground plane
                // WARNING Polies need to be sorted first (see slice.SortPolygons() above == OK)
                first_index = this.SliceStore.FindIndex(s => s.Polygons.Count > 0);
                if (first_index >= 0)
                {
                    this.SliceStore[first_index].AddAdhesion(
                        this.data.UseAdhesion,
                        data.NozzleDiameter *dense_spacing,
                        true, this.data.AdhesionDistance);
                }
                else
                {
                    first_index = this.SliceStore.FindIndex(s => s.FillPolygons.Count > 0);
                    if (first_index >= 0)
                    {
                        this.SliceStore[first_index].AddAdhesion(
                            this.data.UseAdhesion,
                            data.NozzleDiameter *dense_spacing,
                            false, this.data.AdhesionDistance);
                    }
                }


                System.Windows.Application.Current.Dispatcher.Invoke(() =>
                {
                    this.Slice            = this.SliceStore[0];
                    this.data.SliceShapes = this.Slice.ToShapes(bounds.X, bounds.Y, scale, this.data.PreviewArrowThickness, this.data.PreviewStrokeThickness);;

                    this.data.SliceCanvas.Children.Clear();
                    this.data.SliceShapes.ForEach(x => this.data.SliceCanvas.Children.Add(x));

                    this.data.SlicingProgressValue = 0;
                    this.data.ProgressBarColor     = SliceModel.StateBrushes[0];
                    this.data.SlicingInProgress    = false;
                    this.data.CurrentSliceIdx      = 0;
                });
            });
        }