def isIntersectingLoopPathList(loopList, otherPaths, pointBegin, pointEnd): "Determine if the segment between the first and second point is intersecting the loop list." normalizedSegment = pointEnd.dropAxis(2) - pointBegin.dropAxis(2) normalizedSegmentLength = abs(normalizedSegment) if normalizedSegmentLength == 0.0: return False normalizedSegment /= normalizedSegmentLength segmentYMirror = complex(normalizedSegment.real, -normalizedSegment.imag) pointBeginRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, pointBegin) pointEndRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, pointEnd) if euclidean.isLoopListIntersectingInsideXSegment(loopList, pointBeginRotated.x, pointEndRotated.x, segmentYMirror, pointBeginRotated.y): return True for path in otherPaths: rotatedPath = euclidean.getPathRoundZAxisByPlaneAngle( segmentYMirror, path) for pointIndex in range(len(rotatedPath) - 1): pointFirst = rotatedPath[pointIndex] pointSecond = rotatedPath[pointIndex + 1] if euclidean.isLineIntersectingInsideXSegment( pointBeginRotated.x, pointEndRotated.x, pointFirst, pointSecond, pointBeginRotated.y): return True return False
def insertPathsBetween( self, nextBeginning, pathEnd ): "Insert paths between the perimeter and the fill." betweenX = [] switchX = [] segment = nextBeginning.minus( pathEnd ) segment.normalize() segmentXY = segment.dropAxis( 2 ) segmentYMirror = complex( segment.x, - segment.y ) pathEndRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, pathEnd ) nextBeginningRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, nextBeginning ) y = pathEndRotated.y z = pathEndRotated.z for betweenIndex in range( len( self.getBetweens() ) ): between = self.getBetweens()[ betweenIndex ] betweenRotated = euclidean.getPathRoundZAxisByPlaneAngle( segmentYMirror, between ) euclidean.addXIntersections( betweenRotated, betweenIndex, switchX, y ) switchX.sort( euclidean.compareSolidXByX ) maximumX = max( pathEndRotated.x, nextBeginningRotated.x ) minimumX = min( pathEndRotated.x, nextBeginningRotated.x ) for xIntersection in switchX: if xIntersection.real > minimumX and xIntersection.real < maximumX: betweenX.append( xIntersection ) betweenXIndex = 0 while betweenXIndex < len( betweenX ) - 1: betweenXFirst = betweenX[ betweenXIndex ] betweenXSecond = betweenX[ betweenXIndex + 1 ] if betweenXSecond.imag == betweenXFirst.imag: betweenXIndex += 1 betweenFirst = euclidean.getRoundZAxisByPlaneAngle( segmentXY, Vec3( betweenXFirst.real, y, z ) ) betweenSecond = euclidean.getRoundZAxisByPlaneAngle( segmentXY, Vec3( betweenXSecond.real, y, z ) ) loopFirst = self.getBetweens()[ int( betweenXFirst.imag ) ] self.addPathBetween( betweenFirst, betweenSecond, loopFirst ) betweenXIndex += 1
def addRotatedSlice( self, layerIndex, reverseRotationAroundZAngle, surroundingSlices ): "Add a rotated slice to the surrounding slices." if layerIndex < 0 or layerIndex >= len( self.rotatedLayers ): return layer = self.rotatedLayers[ layerIndex ].toBeginningLoops rotatedSlice = [] for thread in layer: planeRotatedLoop = euclidean.getPathRoundZAxisByPlaneAngle( reverseRotationAroundZAngle, thread[ 1 : ] ) rotatedSlice.append( planeRotatedLoop ) surroundingSlices.append( rotatedSlice )
def addRotatedSlice(self, layerIndex, reverseRotationAroundZAngle, surroundingSlices): "Add a rotated slice to the surrounding slices." if layerIndex < 0 or layerIndex >= len(self.rotatedLayers): return layer = self.rotatedLayers[layerIndex].toBeginningLoops rotatedSlice = [] for thread in layer: planeRotatedLoop = euclidean.getPathRoundZAxisByPlaneAngle( reverseRotationAroundZAngle, thread[1:]) rotatedSlice.append(planeRotatedLoop) surroundingSlices.append(rotatedSlice)
def isIntersectingLoopPathList( loopList, otherPaths, pointBegin, pointEnd ): "Determine if the segment between the first and second point is intersecting the loop list." normalizedSegment = pointEnd.dropAxis( 2 ) - pointBegin.dropAxis( 2 ) normalizedSegmentLength = abs( normalizedSegment ) if normalizedSegmentLength == 0.0: return False normalizedSegment /= normalizedSegmentLength segmentYMirror = complex( normalizedSegment.real, - normalizedSegment.imag ) pointBeginRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, pointBegin ) pointEndRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, pointEnd ) if euclidean.isLoopListIntersectingInsideXSegment( loopList, pointBeginRotated.x, pointEndRotated.x, segmentYMirror, pointBeginRotated.y ): return True for path in otherPaths: rotatedPath = euclidean.getPathRoundZAxisByPlaneAngle( segmentYMirror, path ) for pointIndex in range( len( rotatedPath ) - 1 ): pointFirst = rotatedPath[ pointIndex ] pointSecond = rotatedPath[ pointIndex + 1 ] if euclidean.isLineIntersectingInsideXSegment( pointBeginRotated.x, pointEndRotated.x, pointFirst, pointSecond, pointBeginRotated.y ): return True return False
def getOverhangDirection( belowOutsetLoops, segmentBegin, segmentEnd ): "Add to span direction from the endpoint segments which overhang the layer below." segment = segmentEnd.minus( segmentBegin ) normalizedSegment = complex( segment.x, segment.y ) normalizedSegment /= abs( normalizedSegment ) segmentYMirror = complex( normalizedSegment.real, - normalizedSegment.imag ) segmentBegin = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, segmentBegin ) segmentEnd = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, segmentEnd ) solidXIntersectionList = [] y = segmentBegin.y solidXIntersectionList.append( complex( segmentBegin.x, - 1.0 ) ) solidXIntersectionList.append( complex( segmentEnd.x, - 1.0 ) ) for belowLoopIndex in range( len( belowOutsetLoops ) ): belowLoop = belowOutsetLoops[ belowLoopIndex ] rotatedOutset = euclidean.getPathRoundZAxisByPlaneAngle( segmentYMirror, belowLoop ) euclidean.addXIntersections( rotatedOutset, belowLoopIndex, solidXIntersectionList, y ) overhangingSegments = euclidean.getSegmentsFromIntersections( solidXIntersectionList, y, segmentBegin.z ) overhangDirection = complex() for overhangingSegment in overhangingSegments: overhangDirection += getDoubledRoundZ( overhangingSegment, normalizedSegment ) return overhangDirection
def insertPathsBetween(self, nextBeginning, pathEnd): "Insert paths between the perimeter and the fill." betweenX = [] switchX = [] segment = nextBeginning.minus(pathEnd) segment.normalize() segmentXY = segment.dropAxis(2) segmentYMirror = complex(segment.x, -segment.y) pathEndRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, pathEnd) nextBeginningRotated = euclidean.getRoundZAxisByPlaneAngle( segmentYMirror, nextBeginning) y = pathEndRotated.y z = pathEndRotated.z for betweenIndex in range(len(self.getBetweens())): between = self.getBetweens()[betweenIndex] betweenRotated = euclidean.getPathRoundZAxisByPlaneAngle( segmentYMirror, between) euclidean.addXIntersections(betweenRotated, betweenIndex, switchX, y) switchX.sort(euclidean.compareSolidXByX) maximumX = max(pathEndRotated.x, nextBeginningRotated.x) minimumX = min(pathEndRotated.x, nextBeginningRotated.x) for xIntersection in switchX: if xIntersection.real > minimumX and xIntersection.real < maximumX: betweenX.append(xIntersection) betweenXIndex = 0 while betweenXIndex < len(betweenX) - 1: betweenXFirst = betweenX[betweenXIndex] betweenXSecond = betweenX[betweenXIndex + 1] if betweenXSecond.imag == betweenXFirst.imag: betweenXIndex += 1 betweenFirst = euclidean.getRoundZAxisByPlaneAngle( segmentXY, Vec3(betweenXFirst.real, y, z)) betweenSecond = euclidean.getRoundZAxisByPlaneAngle( segmentXY, Vec3(betweenXSecond.real, y, z)) loopFirst = self.getBetweens()[int(betweenXFirst.imag)] self.addPathBetween(betweenFirst, betweenSecond, loopFirst) betweenXIndex += 1
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 addPath(extrusionWidth, fill, path, rotationPlaneAngle): "Add simplified path to fill." planeRotated = euclidean.getPathRoundZAxisByPlaneAngle( rotationPlaneAngle, euclidean.getSimplifiedLoop(path, extrusionWidth)) fill.append(planeRotated)
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 addPath( extrusionWidth, fill, path, rotationPlaneAngle ): "Add simplified path to fill." planeRotated = euclidean.getPathRoundZAxisByPlaneAngle( rotationPlaneAngle, euclidean.getSimplifiedLoop( path, extrusionWidth ) ) fill.append( planeRotated )