Skip to content

Commit

Permalink
add initial concurrency to the internal infill modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
aligator committed Aug 4, 2020
1 parent f2948d2 commit 46f45ab
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 196 deletions.
2 changes: 1 addition & 1 deletion handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ModelSlicer interface {
// LayerModifier can add new attributes to the layers or even alter the layer directly.
type LayerModifier interface {
Init(m data.OptimizedModel)
Modify(layerNr int, layers []data.PartitionedLayer) error
Modify(layers []data.PartitionedLayer) error
}

// GCodeGenerator generates the GCode out of the given layers.
Expand Down
241 changes: 121 additions & 120 deletions modifier/infill.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,154 +53,155 @@ func InfillParts(layer data.PartitionedLayer, typ string) ([]data.LayerPart, err
return nil, nil
}

func (m infillModifier) Modify(layerNr int, layers []data.PartitionedLayer) error {
overlappingPerimeters, err := OverlapPerimeters(layers[layerNr])
if err != nil || overlappingPerimeters == nil {
return err
}
func (m infillModifier) Modify(layers []data.PartitionedLayer) error {
for layerNr := range layers {
overlappingPerimeters, err := OverlapPerimeters(layers[layerNr])
if err != nil || overlappingPerimeters == nil {
return err
}

perimeters, err := Perimeters(layers[layerNr])
if err != nil || perimeters == nil {
return err
}
perimeters, err := Perimeters(layers[layerNr])
if err != nil || perimeters == nil {
return err
}

var bottomInfill []data.LayerPart
var topInfill []data.LayerPart

c := clip.NewClipper()

// Calculate the bottom/top parts for each inner perimeter part.
// It also takes into account the configured number of top/bottom layers.
for partNr, part := range perimeters {
// for the last (most inner) inset of each part
for _, insetPart := range part[len(part)-1] {
var bottomInfillParts, topInfillParts []data.LayerPart
// 1. Calculate the area which needs full infill for top and bottom layerS

// TODO: maybe merge these two loops in one function somehow?
// calculate the difference with the layers bellow.
for i := 0; i < m.options.Print.NumberBottomLayers; i++ {
var parts []data.LayerPart
if layerNr-i == 0 {
// if it's the first layer, use the whole layer
parts = []data.LayerPart{insetPart}
} else if i > layerNr {
// if we are below layer 0 stop calculation
break
} else {
// else calculate the difference and use it
parts, err = partDifference(insetPart, layers[layerNr-1-i])
if err != nil {
return err
var bottomInfill []data.LayerPart
var topInfill []data.LayerPart

c := clip.NewClipper()

// Calculate the bottom/top parts for each inner perimeter part.
// It also takes into account the configured number of top/bottom layers.
for partNr, part := range perimeters {
// for the last (most inner) inset of each part
for _, insetPart := range part[len(part)-1] {
var bottomInfillParts, topInfillParts []data.LayerPart
// 1. Calculate the area which needs full infill for top and bottom layerS

// TODO: maybe merge these two loops in one function somehow?
// calculate the difference with the layers bellow.
for i := 0; i < m.options.Print.NumberBottomLayers; i++ {
var parts []data.LayerPart
if layerNr-i == 0 {
// if it's the first layer, use the whole layer
parts = []data.LayerPart{insetPart}
} else if i > layerNr {
// if we are below layer 0 stop calculation
break
} else {
// else calculate the difference and use it
parts, err = partDifference(insetPart, layers[layerNr-1-i])
if err != nil {
return err
}
}
}

// union the parts if needed
if len(bottomInfillParts) == 0 {
bottomInfillParts = parts
} else {
var ok bool
bottomInfillParts, ok = c.Union(bottomInfillParts, parts)
if !ok {
return errors.New("could not union bottom parts")
// union the parts if needed
if len(bottomInfillParts) == 0 {
bottomInfillParts = parts
} else {
var ok bool
bottomInfillParts, ok = c.Union(bottomInfillParts, parts)
if !ok {
return errors.New("could not union bottom parts")
}
}
}
}

// calculate the difference with the layers above
for i := 0; i < m.options.Print.NumberTopLayers; i++ {
var parts []data.LayerPart
if layerNr+i == len(layers)-1 {
// if it's the last layer, use the whole layer
parts = []data.LayerPart{insetPart}
} else if layerNr+1+i >= len(layers) {
// if we are above the top layer stop calculation
break
} else {
// else calculate the difference and use it
parts, err = partDifference(insetPart, layers[layerNr+1+i])
if err != nil {
return err
// calculate the difference with the layers above
for i := 0; i < m.options.Print.NumberTopLayers; i++ {
var parts []data.LayerPart
if layerNr+i == len(layers)-1 {
// if it's the last layer, use the whole layer
parts = []data.LayerPart{insetPart}
} else if layerNr+1+i >= len(layers) {
// if we are above the top layer stop calculation
break
} else {
// else calculate the difference and use it
parts, err = partDifference(insetPart, layers[layerNr+1+i])
if err != nil {
return err
}
}
}

// union the parts if needed
if len(topInfillParts) == 0 {
topInfillParts = parts
} else {
var ok bool
topInfillParts, ok = c.Union(topInfillParts, parts)
if !ok {
return errors.New("could not union top parts")
// union the parts if needed
if len(topInfillParts) == 0 {
topInfillParts = parts
} else {
var ok bool
topInfillParts, ok = c.Union(topInfillParts, parts)
if !ok {
return errors.New("could not union top parts")
}
}
}
}

// 2. Exset the area which needs infill to generate the internal overlap of top and bottom layer.
var internalOverlappingBottomParts, internalOverlappingTopParts []data.LayerPart
for _, bottomPart := range bottomInfillParts {
overlappingParts, err := calculateOverlapPerimeter(bottomPart, m.options.Print.InfillOverlapPercent+m.options.Print.AdditionalInternalInfillOverlapPercent, m.options.Printer.ExtrusionWidth)
if err != nil {
return err
// 2. Exset the area which needs infill to generate the internal overlap of top and bottom layer.
var internalOverlappingBottomParts, internalOverlappingTopParts []data.LayerPart
for _, bottomPart := range bottomInfillParts {
overlappingParts, err := calculateOverlapPerimeter(bottomPart, m.options.Print.InfillOverlapPercent+m.options.Print.AdditionalInternalInfillOverlapPercent, m.options.Printer.ExtrusionWidth)
if err != nil {
return err
}

internalOverlappingBottomParts = append(internalOverlappingBottomParts, overlappingParts...)
}

internalOverlappingBottomParts = append(internalOverlappingBottomParts, overlappingParts...)
}
for _, topPart := range topInfillParts {
overlappingParts, err := calculateOverlapPerimeter(topPart, m.options.Print.InfillOverlapPercent+m.options.Print.AdditionalInternalInfillOverlapPercent, m.options.Printer.ExtrusionWidth)
if err != nil {
return err
}

for _, topPart := range topInfillParts {
overlappingParts, err := calculateOverlapPerimeter(topPart, m.options.Print.InfillOverlapPercent+m.options.Print.AdditionalInternalInfillOverlapPercent, m.options.Printer.ExtrusionWidth)
if err != nil {
return err
internalOverlappingTopParts = append(internalOverlappingTopParts, overlappingParts...)
}

internalOverlappingTopParts = append(internalOverlappingTopParts, overlappingParts...)
}
// 3. Clip the resulting areas by the overlappingPerimeters.
if internalOverlappingBottomParts != nil {
clippedParts, ok := c.Intersection(internalOverlappingBottomParts, overlappingPerimeters[partNr])
if !ok {
return errors.New("error while intersecting infill areas by the overlapping border")
}

// 3. Clip the resulting areas by the overlappingPerimeters.
if internalOverlappingBottomParts != nil {
clippedParts, ok := c.Intersection(internalOverlappingBottomParts, overlappingPerimeters[partNr])
if !ok {
return errors.New("error while intersecting infill areas by the overlapping border")
u, ok := c.Union(bottomInfill, clippedParts)
if !ok {
return errors.New("error while calculating the union of new infill with already existing one")
}
bottomInfill = u
}

u, ok := c.Union(bottomInfill, clippedParts)
if !ok {
return errors.New("error while calculating the union of new infill with already existing one")
if internalOverlappingTopParts != nil {
clippedParts, ok := c.Intersection(internalOverlappingTopParts, overlappingPerimeters[partNr])
if !ok {
return errors.New("error while intersecting infill areas by the overlapping border")
}
u, ok := c.Union(topInfill, clippedParts)
if !ok {
return errors.New("error while calculating the union of new infill with already existing one")
}
topInfill = u
}
bottomInfill = u
}
}

if internalOverlappingTopParts != nil {
clippedParts, ok := c.Intersection(internalOverlappingTopParts, overlappingPerimeters[partNr])
if !ok {
return errors.New("error while intersecting infill areas by the overlapping border")
}
u, ok := c.Union(topInfill, clippedParts)
if !ok {
return errors.New("error while calculating the union of new infill with already existing one")
}
topInfill = u
if len(topInfill) > 0 && len(bottomInfill) > 0 {
diff, ok := c.Difference(topInfill, bottomInfill)
if !ok {
return errors.New("error while calculating the difference of new top infill with the bottom infill to avoid duplicates")
}
topInfill = diff
}
}

if len(topInfill) > 0 && len(bottomInfill) > 0 {
diff, ok := c.Difference(topInfill, bottomInfill)
if !ok {
return errors.New("error while calculating the difference of new top infill with the bottom infill to avoid duplicates")
newLayer := newExtendedLayer(layers[layerNr])
if len(bottomInfill) > 0 {
newLayer.attributes["bottom"] = bottomInfill
}
if len(topInfill) > 0 {
newLayer.attributes["top"] = topInfill
}
topInfill = diff
}

newLayer := newExtendedLayer(layers[layerNr])
if len(bottomInfill) > 0 {
newLayer.attributes["bottom"] = bottomInfill
}
if len(topInfill) > 0 {
newLayer.attributes["top"] = topInfill
layers[layerNr] = newLayer
}

layers[layerNr] = newLayer

return nil
}
104 changes: 57 additions & 47 deletions modifier/internal_infill.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,54 +20,64 @@ func NewInternalInfillModifier(options *data.Options) handler.LayerModifier {
}
}

func (m internalInfillModifier) Modify(layerNr int, layers []data.PartitionedLayer) error {
overlappingPerimeters, err := OverlapPerimeters(layers[layerNr])
if err != nil || overlappingPerimeters == nil {
return err
}

bottomInfill, err := BottomInfill(layers[layerNr])
if err != nil {
return err
}

topInfill, err := TopInfill(layers[layerNr])
if err != nil {
return err
}

var internalInfill []data.LayerPart

c := clip.NewClipper()

// calculate the bottom parts for each inner perimeter part
for _, overlappingPart := range overlappingPerimeters {
// Calculate the difference between the overlappingPerimeters and the final top/bottom infills
// to get the internal infill areas.

// if no infill, just ignore the generation
if m.options.Print.InfillPercent == 0 {
continue
}

// calculating the difference would fail if both are nil so just ignore this
if overlappingPart == nil && bottomInfill == nil && topInfill == nil {
continue
}

if parts, ok := c.Difference(overlappingPart, append(bottomInfill, topInfill...)); !ok {
return errors.New("error while calculating the difference between the max overlap border and the bottom infill")
} else {
internalInfill = append(internalInfill, parts...)
func (m internalInfillModifier) Modify(layers []data.PartitionedLayer) error {
return modifyConcurrently(layers, func(layerCh <-chan enumeratedPartitionedLayer, outputCh chan<- enumeratedPartitionedLayer, errCh chan<- error) {
for layer := range layerCh {
overlappingPerimeters, err := OverlapPerimeters(layer.layer)
if err != nil || overlappingPerimeters == nil {
errCh <- err
return
}

bottomInfill, err := BottomInfill(layer.layer)
if err != nil {
errCh <- err
return
}

topInfill, err := TopInfill(layer.layer)
if err != nil {
errCh <- err
return
}

var internalInfill []data.LayerPart

c := clip.NewClipper()

// calculate the bottom parts for each inner perimeter part
for _, overlappingPart := range overlappingPerimeters {
// Calculate the difference between the overlappingPerimeters and the final top/bottom infills
// to get the internal infill areas.

// if no infill, just ignore the generation
if m.options.Print.InfillPercent == 0 {
continue
}

// calculating the difference would fail if both are nil so just ignore this
if overlappingPart == nil && bottomInfill == nil && topInfill == nil {
continue
}

if parts, ok := c.Difference(overlappingPart, append(bottomInfill, topInfill...)); !ok {
errCh <- errors.New("error while calculating the difference between the max overlap border and the bottom infill")
return
} else {
internalInfill = append(internalInfill, parts...)
}
}

newLayer := newExtendedLayer(layer.layer)
if len(internalInfill) > 0 {
newLayer.attributes["infill"] = internalInfill
}
outputCh <- enumeratedPartitionedLayer{
layer: newLayer,
layerNr: layer.layerNr,
}
}
}

newLayer := newExtendedLayer(layers[layerNr])
if len(internalInfill) > 0 {
newLayer.attributes["infill"] = internalInfill
}

return nil
})
}

func partDifference(part data.LayerPart, layerToRemove data.PartitionedLayer) ([]data.LayerPart, error) {
Expand Down
Loading

0 comments on commit 46f45ab

Please sign in to comment.