Skip to content

Commit

Permalink
Move goslice to the root
Browse files Browse the repository at this point in the history
  • Loading branch information
aligator committed Mar 25, 2021
1 parent a5ffdc6 commit ae412c1
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 2 deletions.
4 changes: 2 additions & 2 deletions cmd/goslice/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package main

import (
"GoSlice"
"GoSlice/data"
"GoSlice/goslice"
"fmt"
"io"
"os"
Expand All @@ -26,7 +26,7 @@ func main() {
os.Exit(1)
}

p := goslice.NewGoSlice(o)
p := GoSlice.NewGoSlice(o)
err := p.Process()

if err != nil {
Expand Down
180 changes: 180 additions & 0 deletions goslice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package GoSlice

import (
"GoSlice/clip"
"GoSlice/data"
"GoSlice/gcode"
"GoSlice/gcode/renderer"
"GoSlice/handler"
"GoSlice/modifier"
"GoSlice/optimizer"
"GoSlice/reader"
"GoSlice/slicer"
"GoSlice/writer"
"fmt"
"time"
)

// GoSlice combines all logic needed to slice
// a model and generate a GCode file.
type GoSlice struct {
Options data.GoSliceOptions
Reader handler.ModelReader
Optimizer handler.ModelOptimizer
Slicer handler.ModelSlicer
Modifiers []handler.LayerModifier
Generator handler.GCodeGenerator
Writer handler.GCodeWriter
}

// NewGoSlice provides a GoSlice with all built in implementations.
func NewGoSlice(options data.Options) *GoSlice {
s := &GoSlice{
Options: options.GoSlice,
}

// create handlers
topBottomPatternFactory := func(min data.MicroPoint, max data.MicroPoint) clip.Pattern {
return clip.NewLinearPattern(options.Printer.ExtrusionWidth, options.Printer.ExtrusionWidth, min, max, options.Print.InfillRotationDegree, true, false)
}

s.Reader = reader.Reader(&options)
s.Optimizer = optimizer.NewOptimizer(&options)
s.Slicer = slicer.NewSlicer(&options)
s.Modifiers = []handler.LayerModifier{
modifier.NewPerimeterModifier(&options),
modifier.NewInfillModifier(&options),
modifier.NewInternalInfillModifier(&options),
modifier.NewBrimModifier(&options),
modifier.NewSupportDetectorModifier(&options),
modifier.NewSupportGeneratorModifier(&options),
}

patternSpacing := options.Print.Support.PatternSpacing.ToMicrometer()

s.Generator = gcode.NewGenerator(
&options,
gcode.WithRenderer(renderer.PreLayer{}),
gcode.WithRenderer(renderer.Skirt{}),
gcode.WithRenderer(renderer.Brim{}),
gcode.WithRenderer(renderer.Perimeter{}),

// Add infill for support generation.
gcode.WithRenderer(&renderer.Infill{
PatternSetup: func(min data.MicroPoint, max data.MicroPoint) clip.Pattern {
// make bounding box bigger to allow generation of support which has always at least two lines
min.SetX(min.X() - patternSpacing)
min.SetY(min.Y() - patternSpacing)
max.SetX(max.X() + patternSpacing)
max.SetY(max.Y() + patternSpacing)
return clip.NewLinearPattern(options.Printer.ExtrusionWidth, patternSpacing, min, max, 90, false, true)
},
AttrName: "support",
Comments: []string{"TYPE:SUPPORT"},
}),
// Interface pattern for support generation is generated by rotating 90° to the support and no spaces between the lines.
gcode.WithRenderer(&renderer.Infill{
PatternSetup: func(min data.MicroPoint, max data.MicroPoint) clip.Pattern {
// make bounding box bigger to allow generation of support which has always at least two lines
min.SetX(min.X() - patternSpacing)
min.SetY(min.Y() - patternSpacing)
max.SetX(max.X() + patternSpacing)
max.SetY(max.Y() + patternSpacing)
return clip.NewLinearPattern(options.Printer.ExtrusionWidth, options.Printer.ExtrusionWidth, min, max, 0, false, true)
},
AttrName: "supportInterface",
Comments: []string{"TYPE:SUPPORT"},
}),

gcode.WithRenderer(&renderer.Infill{
PatternSetup: topBottomPatternFactory,
AttrName: "bottom",
Comments: []string{"TYPE:FILL", "BOTTOM-FILL"},
}),
gcode.WithRenderer(&renderer.Infill{
PatternSetup: topBottomPatternFactory,
AttrName: "top",
Comments: []string{"TYPE:FILL", "TOP-FILL"},
}),
gcode.WithRenderer(&renderer.Infill{
PatternSetup: func(min data.MicroPoint, max data.MicroPoint) clip.Pattern {
// TODO: the calculation of the percentage is currently very basic and may not be correct.

if options.Print.InfillPercent != 0 {
mm10 := data.Millimeter(10).ToMicrometer()
linesPer10mmFor100Percent := mm10 / options.Printer.ExtrusionWidth
linesPer10mmForInfillPercent := float64(linesPer10mmFor100Percent) * float64(options.Print.InfillPercent) / 100.0

lineWidth := data.Micrometer(float64(mm10) / linesPer10mmForInfillPercent)

return clip.NewLinearPattern(options.Printer.ExtrusionWidth, lineWidth, min, max, options.Print.InfillRotationDegree, true, options.Print.InfillZigZag)
}

return nil
},
AttrName: "infill",
Comments: []string{"TYPE:FILL", "INTERNAL-FILL"},
}),
gcode.WithRenderer(renderer.PostLayer{}),
)
s.Writer = writer.Writer()

return s
}

func (s *GoSlice) Process() error {
startTime := time.Now()

// 1. Load model
models, err := s.Reader.Read(s.Options.InputFilePath)
if err != nil {
return err
}

// 2. Optimize model
var optimizedModel data.OptimizedModel

optimizedModel, err = s.Optimizer.Optimize(models)
if err != nil {
return err
}

//err = optimizedModel.SaveDebugSTL("test.stl")
//if err != nil {
// return err
//}

// 3. Slice model into layers
layers, err := s.Slicer.Slice(optimizedModel)
if err != nil {
return err
}

// 4. Modify the layers
// e.g. generate perimeter paths,
// generate the parts which should be filled in, ...
for _, m := range s.Modifiers {
m.Init(optimizedModel)
err = m.Modify(layers)
if err != nil {
return err
}
}

// 5. generate gcode from the layers
s.Generator.Init(optimizedModel)
finalGcode, err := s.Generator.Generate(layers)
if err != nil {
return err
}

outputPath := s.Options.OutputFilePath
if outputPath == "" {
outputPath = s.Options.InputFilePath + ".gcode"
}

err = s.Writer.Write(finalGcode, outputPath)
fmt.Println("full processing time:", time.Now().Sub(startTime))

return err
}
51 changes: 51 additions & 0 deletions goslice_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package GoSlice

import (
"GoSlice/data"
"GoSlice/util/test"
"testing"
)

const (
folder = "./test_stl/"

// The models are copied to the project just to avoid downloading them for each test.

// 3DBenchy is the unmodified model from here:
// https://www.thingiverse.com/thing:763622
// using the following license
// https://creativecommons.org/licenses/by-nd/4.0/
benchy = "3DBenchy.stl"

// Go Gopher mascot is the unmodified model from here:
// https://www.thingiverse.com/thing:3413597
// using the following license
// https://creativecommons.org/licenses/by/4.0/
gopher = "gopher_union.stl"
)

func TestWholeSlicer(t *testing.T) {
o := data.DefaultOptions()
// enable support so that it is tested also
o.Print.Support.Enabled = true
o.Print.BrimSkirt.BrimCount = 3
s := NewGoSlice(o)

var tests = []struct {
path string
}{
{
path: benchy,
},
{
path: gopher,
},
}

for _, testCase := range tests {
t.Log("slice " + testCase.path)
s.Options.InputFilePath = folder + testCase.path
err := s.Process()
test.Ok(t, err)
}
}

0 comments on commit ae412c1

Please sign in to comment.