def getBridgeDirection( self, layerLoops ): "Get span direction for the majority of the overhanging extrusion perimeter, if any." if not self.slicePreferences.infillDirectionBridge.value: return None if self.belowLoops == None: return None belowOutsetLoops = [] overhangInset = 1.25 * self.extrusionWidth greaterThanOverhang = 1.1 * overhangInset for loop in self.belowLoops: centers = intercircle.getCentersFromLoopDirection( euclidean.isWiddershins( loop ), loop, greaterThanOverhang ) # centers = intercircle.getCentersFromOutside( not euclidean.isWiddershins( loop ), loop, greaterThanOverhang ) for center in centers: outset = intercircle.getInsetFromClockwiseLoop( center, overhangInset ) if euclidean.isWiddershins( center ) == euclidean.isWiddershins( outset ): if euclidean.getMaximumSpan( outset ) > self.extrusionWidth: belowOutsetLoops.append( outset ) bridgeDirection = complex() for loop in layerLoops: for pointIndex in range( len( loop ) ): previousIndex = ( pointIndex + len( loop ) - 1 ) % len( loop ) bridgeDirection += getOverhangDirection( belowOutsetLoops, loop[ previousIndex ], loop[ pointIndex ] ) if abs( bridgeDirection ) < self.halfExtrusionWidth: return None else: bridgeDirection /= abs( bridgeDirection ) return cmath.sqrt( bridgeDirection )
def getOutsetBoundingLoop( self, outsetDistance ): "Outset the bounding rectangle and loop by a distance." outsetBoundingLoop = BoundingLoop() outsetBoundingLoop.maximum = self.maximum + complex( outsetDistance, outsetDistance ) outsetBoundingLoop.minimum = self.minimum - complex( outsetDistance, outsetDistance ) greaterThanOutsetDistance = 1.1 * outsetDistance centers = intercircle.getCentersFromLoopDirection( True, self.loop, greaterThanOutsetDistance ) outsetBoundingLoop.loop = intercircle.getInsetFromClockwiseLoop( centers[ 0 ], outsetDistance ) return outsetBoundingLoop
def setBetweens( self ): "Set betweens for the layer." halfFillInset = 0.5 * self.fillInset self.layerIndex += 1 self.betweens = [] for loop in self.layers[ self.layerIndex ]: centers = intercircle.getCentersfromLoopDirection( euclidean.isWiddershins( loop ), loop, self.fillInset ) for center in centers: inset = intercircle.getInsetFromClockwiseLoop( center, halfFillInset ) if euclidean.isWiddershins( center ) == euclidean.isWiddershins( inset ): if euclidean.getMaximumSpan( inset ) > self.fillInset: self.betweens.append( inset )
def getOutsetBoundingLoop(self, outsetDistance): "Outset the bounding rectangle and loop by a distance." outsetBoundingLoop = BoundingLoop() outsetBoundingLoop.maximum = self.maximum + complex( outsetDistance, outsetDistance) outsetBoundingLoop.minimum = self.minimum - complex( outsetDistance, outsetDistance) greaterThanOutsetDistance = 1.1 * outsetDistance centers = intercircle.getCentersFromLoopDirection( True, self.loop, greaterThanOutsetDistance) outsetBoundingLoop.loop = intercircle.getInsetFromClockwiseLoop( centers[0], outsetDistance) return outsetBoundingLoop
def setBetweens(self): "Set betweens for the layer." halfFillInset = 0.5 * self.fillInset self.layerIndex += 1 self.betweens = [] for loop in self.layers[self.layerIndex]: centers = intercircle.getCentersfromLoopDirection( euclidean.isWiddershins(loop), loop, self.fillInset) for center in centers: inset = intercircle.getInsetFromClockwiseLoop( center, halfFillInset) if euclidean.isWiddershins(center) == euclidean.isWiddershins( inset): if euclidean.getMaximumSpan(inset) > self.fillInset: self.betweens.append(inset)
def getBetweens( self ): "Set betweens for the layer." if self.betweens != None: return self.betweens halfFillInset = 0.5 * self.layerFillInset self.betweens = [] for loop in self.layerTable[ self.layerZ ]: circleNodes = intercircle.getCircleNodesFromLoop( loop, self.layerFillInset ) centers = intercircle.getCentersFromCircleNodes( circleNodes ) for center in centers: inset = intercircle.getInsetFromClockwiseLoop( center, halfFillInset ) if euclidean.isWiddershins( center ) == euclidean.isWiddershins( inset ): if euclidean.getMaximumSpan( inset ) > self.layerFillInset: if euclidean.isPathInsideLoop( loop, inset ) != euclidean.isWiddershins( loop ): self.betweens.append( inset ) return self.betweens
def getExtraFillLoops( insideLoops, outsideLoop, radius ): "Get extra loops between inside and outside loops." slightlyGreaterThanRadius = 1.05 * radius tripleSlightlyGreaterThanRadius = 3.0 * slightlyGreaterThanRadius extraFillLoops = [] circleNodes = intercircle.getCircleNodesFromLoop( outsideLoop, slightlyGreaterThanRadius ) for inside in insideLoops: circleNodes += intercircle.getCircleNodesFromLoop( inside, slightlyGreaterThanRadius ) centers = intercircle.getCentersFromCircleNodes( circleNodes ) for center in centers: inset = intercircle.getInsetFromClockwiseLoop( center, radius ) if euclidean.isWiddershins( center ) == euclidean.isWiddershins( inset ): if isPathAlwaysInsideLoop( outsideLoop, inset ): if isPathAlwaysOutsideLoops( insideLoops, inset ): if euclidean.getMaximumSpan( inset ) > tripleSlightlyGreaterThanRadius: extraFillLoops.append( inset ) return extraFillLoops
def getBetweens(self): "Set betweens for the layer." if self.betweens != None: return self.betweens halfFillInset = 0.5 * self.layerFillInset self.betweens = [] for loop in self.layerTable[self.layerZ]: circleNodes = intercircle.getCircleNodesFromLoop( loop, self.layerFillInset) centers = intercircle.getCentersFromCircleNodes(circleNodes) for center in centers: inset = intercircle.getInsetFromClockwiseLoop( center, halfFillInset) if euclidean.isWiddershins(center) == euclidean.isWiddershins( inset): if euclidean.getMaximumSpan(inset) > self.layerFillInset: if euclidean.isPathInsideLoop( loop, inset) != euclidean.isWiddershins(loop): self.betweens.append(inset) return self.betweens
def getExtraFillLoops(insideLoops, outsideLoop, radius): "Get extra loops between inside and outside loops." slightlyGreaterThanRadius = 1.05 * radius tripleSlightlyGreaterThanRadius = 3.0 * slightlyGreaterThanRadius extraFillLoops = [] circleNodes = intercircle.getCircleNodesFromLoop( outsideLoop, slightlyGreaterThanRadius) for inside in insideLoops: circleNodes += intercircle.getCircleNodesFromLoop( inside, slightlyGreaterThanRadius) centers = intercircle.getCentersFromCircleNodes(circleNodes) for center in centers: inset = intercircle.getInsetFromClockwiseLoop(center, radius) if euclidean.isWiddershins(center) == euclidean.isWiddershins(inset): if isPathAlwaysInsideLoop(outsideLoop, inset): if isPathAlwaysOutsideLoops(insideLoops, inset): if euclidean.getMaximumSpan( inset) > tripleSlightlyGreaterThanRadius: extraFillLoops.append(inset) return extraFillLoops
def getZAddExtruderPaths( self, z ): "Get next z and add extruder loops." zoneArray = [] for point in self.triangleMesh.vertices: self.addToZoneArray( point, zoneArray, z ) lowestZoneIndex = getLowestZoneIndex( zoneArray, z ) halfAround = int( math.ceil( float( lowestZoneIndex ) / 2.0 ) ) zAround = float( halfAround ) * self.zZoneInterval if lowestZoneIndex % 2 == 1: zAround = - zAround loops = self.getLoopsFromMesh( z + zAround ) centers = [] doubleExtrusionWidth = 2.0 * self.extrusionWidth extruderPaths = [] bridgeDirection = self.getBridgeDirection( loops ) self.belowLoops = loops halfWidth = self.halfExtrusionWidth if bridgeDirection != None: halfWidth = 0.5 * self.bridgeExtrusionWidth extrudateLoops = [] for loop in loops: circleNodes = intercircle.getCircleNodesFromLoop( loop, self.extrusionWidth ) centers = intercircle.getCentersFromCircleNodes( circleNodes ) for center in centers: extrudateLoop = intercircle.getInsetFromClockwiseLoop( center, halfWidth ) if euclidean.isWiddershins( extrudateLoop ) == euclidean.isWiddershins( center ): if euclidean.getMaximumSpan( extrudateLoop ) > doubleExtrusionWidth: if euclidean.isPathInsideLoop( loop, extrudateLoop ) == euclidean.isWiddershins( loop ): extrudateLoops.append( extrudateLoop ) self.addLine( '(<layerStart> ' + str( z ) + ' )' ) # Indicate that a new layer is starting. if bridgeDirection != None: self.addLine( '(<bridgeDirection> ' + str( bridgeDirection ) + ' )' ) # Indicate the bridge direction. halfBridgeMinusLayer = 0.5 * ( self.bridgeLayerThickness - self.layerThickness ) for extrudateLoop in extrudateLoops: for point in extrudateLoop: point.z += halfBridgeMinusLayer for extrudateLoop in extrudateLoops: self.addGcodeFromThread( extrudateLoop + [ extrudateLoop[ 0 ] ] ) if bridgeDirection == None: return z + self.layerThickness return z + self.bridgeLayerThickness
def addFill(self, layerIndex): "Add fill to the slice layer." # if layerIndex > 5: # return alreadyFilledArounds = [] arounds = [] back = -999999999.0 layerExtrusionWidth = self.extrusionWidth layerFillInset = self.fillInset layer = self.rotatedLayers[layerIndex].toBeginningLoops self.addLine('(<layerStart> ' + str(layer[0][0].z) + ' )') # Indicate that a new layer is starting. if self.rotatedLayers[layerIndex].rotation != None: layerExtrusionWidth = self.extrusionWidth * self.bridgeExtrusionWidthOverSolid layerFillInset = self.fillInset * self.bridgeExtrusionWidthOverSolid self.addLine( '(<bridgeLayer> )') # Indicate that this is a bridge layer. doubleExtrusionWidth = 2.0 * layerExtrusionWidth muchGreaterThanLayerFillInset = 3.0 * layerFillInset endpoints = [] fill = [] aroundInset = 0.7 * layerFillInset front = -back slightlyGreaterThanFill = 1.01 * layerFillInset layerRotationAroundZAngle = self.getLayerRoundZ(layerIndex) reverseRotationAroundZAngle = complex(layerRotationAroundZAngle.real, -layerRotationAroundZAngle.imag) rotatedExtruderLoops = [] stretch = 0.5 * layerExtrusionWidth loops = [] for thread in layer: loops.append(thread[1:]) surroundingSlices = [] layerRemainder = layerIndex % int( round(self.fillPreferences.diaphragmPeriod.value)) if layerRemainder >= int( round(self.fillPreferences.diaphragmThickness.value)): for surroundingIndex in range(1, self.solidSurfaceThickness + 1): self.addRotatedSlice(layerIndex - surroundingIndex, reverseRotationAroundZAngle, surroundingSlices) self.addRotatedSlice(layerIndex + surroundingIndex, reverseRotationAroundZAngle, surroundingSlices) extraShells = self.fillPreferences.extraShellsSparseLayer.value if len(surroundingSlices) < self.doubleSolidSurfaceThickness: if self.lastExtraShells != self.fillPreferences.extraShellsBase.value: extraShells = self.fillPreferences.extraShellsBase.value self.lastExtraShells = extraShells surroundingLoops = euclidean.getSurroundingLoops( layerExtrusionWidth, loops) for extraShellIndex in range(extraShells): createFillForSurroundings(surroundingLoops) fillLoops = euclidean.getFillOfSurroundings(surroundingLoops) for loop in fillLoops: alreadyFilledLoop = [] alreadyFilledArounds.append(alreadyFilledLoop) planeRotatedPerimeter = euclidean.getPathRoundZAxisByPlaneAngle( reverseRotationAroundZAngle, loop) rotatedExtruderLoops.append(planeRotatedPerimeter) circleNodes = intercircle.getCircleNodesFromLoop( planeRotatedPerimeter, slightlyGreaterThanFill) centers = intercircle.getCentersFromCircleNodes(circleNodes) for center in centers: alreadyFilledInset = intercircle.getInsetFromClockwiseLoop( center, layerFillInset) # if euclidean.isWiddershins( alreadyFilledInset ) == euclidean.isWiddershins( center ): if euclidean.getMaximumSpan( alreadyFilledInset ) > muchGreaterThanLayerFillInset or euclidean.isWiddershins( alreadyFilledInset): alreadyFilledLoop.append(alreadyFilledInset) around = intercircle.getInsetFromClockwiseLoop( center, aroundInset) if euclidean.isPathInsideLoop( planeRotatedPerimeter, around ) != euclidean.isWiddershins(planeRotatedPerimeter): arounds.append(around) for point in around: back = max(back, point.y) front = min(front, point.y) fillWidth = back - front numberOfIntervals = int(math.floor(fillWidth / layerExtrusionWidth)) fillRemainder = fillWidth - float( numberOfIntervals) * layerExtrusionWidth halfFillRemainder = 0.5 * fillRemainder back -= halfFillRemainder front += halfFillRemainder horizontalSegments = [] for fillLine in range(numberOfIntervals + 1): y = front + float(fillLine) * layerExtrusionWidth lineSegments = getHorizontalSegments(rotatedExtruderLoops, alreadyFilledArounds, y) horizontalSegments.append(lineSegments) removedEndpoints = [] for fillLine in range(len(horizontalSegments)): y = front + float(fillLine) * layerExtrusionWidth horizontalEndpoints = horizontalSegments[fillLine] surroundingXIntersections = getSurroundingXIntersections( len(alreadyFilledArounds), self.doubleSolidSurfaceThickness, surroundingSlices, y) addSparseEndpoints(doubleExtrusionWidth, endpoints, self.fillDensity, fillLine, horizontalSegments, removedEndpoints, surroundingXIntersections) if len(endpoints) < 1: euclidean.addToThreadsRemoveFromSurroundings( self.oldOrderedLocation, surroundingLoops, self) return stretchedXSegments = [] for beginningEndpoint in endpoints[::2]: beginningPoint = beginningEndpoint.point stretchedXSegment = StretchedXSegment().getFromXYStretch( beginningPoint.x, beginningPoint.y, beginningEndpoint.otherEndpoint.point.x, stretch) stretchedXSegments.append(stretchedXSegment) endpointFirst = endpoints[0] endpoints.remove(endpointFirst) otherEndpoint = endpointFirst.otherEndpoint endpoints.remove(otherEndpoint) nextEndpoint = None path = [] paths = [] if len(endpoints) > 1: nextEndpoint = otherEndpoint.getNearestMiss( arounds, endpoints, layerExtrusionWidth, path, stretchedXSegments) if nextEndpoint != None: if nextEndpoint.point.distance2( endpointFirst.point) < nextEndpoint.point.distance2( otherEndpoint.point): endpointFirst = endpointFirst.otherEndpoint otherEndpoint = endpointFirst.otherEndpoint path.append(endpointFirst.point) path.append(otherEndpoint.point) while len(endpoints) > 1: nextEndpoint = otherEndpoint.getNearestMiss( arounds, endpoints, layerExtrusionWidth, path, stretchedXSegments) if nextEndpoint == None: paths.append(path) path = [] nextEndpoint = otherEndpoint.getNearestEndpoint(endpoints) path.append(nextEndpoint.point) endpoints.remove(nextEndpoint) if nextEndpoint.isOtherEndpointExtrudable(path): otherEndpoint = nextEndpoint.otherEndpoint path.append(otherEndpoint.point) endpoints.remove(otherEndpoint) else: otherEndpoint = nextEndpoint paths.append(path) for removedEndpoint in removedEndpoints: addAroundClosest(arounds, layerExtrusionWidth, paths, removedEndpoint) for path in paths: addPath(layerFillInset, fill, path, layerRotationAroundZAngle) euclidean.transferPathsToSurroundingLoops(fill, surroundingLoops) euclidean.addToThreadsRemoveFromSurroundings(self.oldOrderedLocation, surroundingLoops, self)
def addFill( self, layerIndex ): "Add fill to the slice layer." # if layerIndex > 5: # return alreadyFilledArounds = [] arounds = [] back = - 999999999.0 layerExtrusionWidth = self.extrusionWidth layerFillInset = self.fillInset layer = self.rotatedLayers[ layerIndex ].toBeginningLoops self.addLine( '(<layerStart> ' + str( layer[ 0 ][ 0 ].z ) + ' )' ) # Indicate that a new layer is starting. if self.rotatedLayers[ layerIndex ].rotation != None: layerExtrusionWidth = self.extrusionWidth * self.bridgeExtrusionWidthOverSolid layerFillInset = self.fillInset * self.bridgeExtrusionWidthOverSolid self.addLine( '(<bridgeLayer> )' ) # Indicate that this is a bridge layer. doubleExtrusionWidth = 2.0 * layerExtrusionWidth muchGreaterThanLayerFillInset = 3.0 * layerFillInset endpoints = [] fill = [] aroundInset = 0.7 * layerFillInset front = - back slightlyGreaterThanFill = 1.01 * layerFillInset layerRotationAroundZAngle = self.getLayerRoundZ( layerIndex ) reverseRotationAroundZAngle = complex( layerRotationAroundZAngle.real, - layerRotationAroundZAngle.imag ) rotatedExtruderLoops = [] stretch = 0.5 * layerExtrusionWidth loops = [] for thread in layer: loops.append( thread[ 1 : ] ) surroundingSlices = [] layerRemainder = layerIndex % int( round( self.fillPreferences.diaphragmPeriod.value ) ) if layerRemainder >= int( round( self.fillPreferences.diaphragmThickness.value ) ): for surroundingIndex in range( 1, self.solidSurfaceThickness + 1 ): self.addRotatedSlice( layerIndex - surroundingIndex, reverseRotationAroundZAngle, surroundingSlices ) self.addRotatedSlice( layerIndex + surroundingIndex, reverseRotationAroundZAngle, surroundingSlices ) extraShells = self.fillPreferences.extraShellsSparseLayer.value if len( surroundingSlices ) < self.doubleSolidSurfaceThickness: if self.lastExtraShells != self.fillPreferences.extraShellsBase.value: extraShells = self.fillPreferences.extraShellsBase.value self.lastExtraShells = extraShells surroundingLoops = euclidean.getSurroundingLoops( layerExtrusionWidth, loops ) for extraShellIndex in range( extraShells ): createFillForSurroundings( surroundingLoops ) fillLoops = euclidean.getFillOfSurroundings( surroundingLoops ) for loop in fillLoops: alreadyFilledLoop = [] alreadyFilledArounds.append( alreadyFilledLoop ) planeRotatedPerimeter = euclidean.getPathRoundZAxisByPlaneAngle( reverseRotationAroundZAngle, loop ) rotatedExtruderLoops.append( planeRotatedPerimeter ) circleNodes = intercircle.getCircleNodesFromLoop( planeRotatedPerimeter, slightlyGreaterThanFill ) centers = intercircle.getCentersFromCircleNodes( circleNodes ) for center in centers: alreadyFilledInset = intercircle.getInsetFromClockwiseLoop( center, layerFillInset ) # if euclidean.isWiddershins( alreadyFilledInset ) == euclidean.isWiddershins( center ): if euclidean.getMaximumSpan( alreadyFilledInset ) > muchGreaterThanLayerFillInset or euclidean.isWiddershins( alreadyFilledInset ): alreadyFilledLoop.append( alreadyFilledInset ) around = intercircle.getInsetFromClockwiseLoop( center, aroundInset ) if euclidean.isPathInsideLoop( planeRotatedPerimeter, around ) != euclidean.isWiddershins( planeRotatedPerimeter ): arounds.append( around ) for point in around: back = max( back, point.y ) front = min( front, point.y ) fillWidth = back - front numberOfIntervals = int( math.floor( fillWidth / layerExtrusionWidth ) ) fillRemainder = fillWidth - float( numberOfIntervals ) * layerExtrusionWidth halfFillRemainder = 0.5 * fillRemainder back -= halfFillRemainder front += halfFillRemainder horizontalSegments = [] for fillLine in range( numberOfIntervals + 1 ): y = front + float( fillLine ) * layerExtrusionWidth lineSegments = getHorizontalSegments( rotatedExtruderLoops, alreadyFilledArounds, y ) horizontalSegments.append( lineSegments ) removedEndpoints = [] for fillLine in range( len( horizontalSegments ) ): y = front + float( fillLine ) * layerExtrusionWidth horizontalEndpoints = horizontalSegments[ fillLine ] surroundingXIntersections = getSurroundingXIntersections( len( alreadyFilledArounds ), self.doubleSolidSurfaceThickness, surroundingSlices, y ) addSparseEndpoints( doubleExtrusionWidth, endpoints, self.fillDensity, fillLine, horizontalSegments, removedEndpoints, surroundingXIntersections ) if len( endpoints ) < 1: euclidean.addToThreadsRemoveFromSurroundings( self.oldOrderedLocation, surroundingLoops, self ) return stretchedXSegments = [] for beginningEndpoint in endpoints[ : : 2 ]: beginningPoint = beginningEndpoint.point stretchedXSegment = StretchedXSegment().getFromXYStretch( beginningPoint.x, beginningPoint.y, beginningEndpoint.otherEndpoint.point.x, stretch ) stretchedXSegments.append( stretchedXSegment ) endpointFirst = endpoints[ 0 ] endpoints.remove( endpointFirst ) otherEndpoint = endpointFirst.otherEndpoint endpoints.remove( otherEndpoint ) nextEndpoint = None path = [] paths = [] if len( endpoints ) > 1: nextEndpoint = otherEndpoint.getNearestMiss( arounds, endpoints, layerExtrusionWidth, path, stretchedXSegments ) if nextEndpoint != None: if nextEndpoint.point.distance2( endpointFirst.point ) < nextEndpoint.point.distance2( otherEndpoint.point ): endpointFirst = endpointFirst.otherEndpoint otherEndpoint = endpointFirst.otherEndpoint path.append( endpointFirst.point ) path.append( otherEndpoint.point ) while len( endpoints ) > 1: nextEndpoint = otherEndpoint.getNearestMiss( arounds, endpoints, layerExtrusionWidth, path, stretchedXSegments ) if nextEndpoint == None: paths.append( path ) path = [] nextEndpoint = otherEndpoint.getNearestEndpoint( endpoints ) path.append( nextEndpoint.point ) endpoints.remove( nextEndpoint ) if nextEndpoint.isOtherEndpointExtrudable( path ): otherEndpoint = nextEndpoint.otherEndpoint path.append( otherEndpoint.point ) endpoints.remove( otherEndpoint ) else: otherEndpoint = nextEndpoint paths.append( path ) for removedEndpoint in removedEndpoints: addAroundClosest( arounds, layerExtrusionWidth, paths, removedEndpoint ) for path in paths: addPath( layerFillInset, fill, path, layerRotationAroundZAngle ) euclidean.transferPathsToSurroundingLoops( fill, surroundingLoops ) euclidean.addToThreadsRemoveFromSurroundings( self.oldOrderedLocation, surroundingLoops, self )