def addTailoredLoopPath(self, line): "Add a clipped loop path." if self.clipLength > 0.0: removeTable = {} euclidean.addLoopToPixelTable(self.loopPath.path, removeTable, self.layerPixelWidth) euclidean.removePixelTableFromPixelTable(removeTable, self.layerPixelTable) self.loopPath.path = euclidean.getClippedSimplifiedLoopPath( self.clipLength, self.loopPath.path, self.perimeterWidth ) euclidean.addLoopToPixelTable(self.loopPath.path, self.layerPixelTable, self.layerPixelWidth) if self.oldWiddershins is None: self.addGcodeFromThreadZ(self.loopPath.path, self.loopPath.z) else: if self.oldWiddershins != euclidean.isWiddershins(self.loopPath.path): self.loopPath.path.reverse() for point in self.loopPath.path: self.distanceFeedRate.addGcodeMovementZWithFeedRate(self.feedRateMinute, point, self.loopPath.z) if self.getNextThreadIsACloseLoop(self.loopPath.path): self.oldConnectionPoint = self.loopPath.path[-1] self.oldWiddershins = euclidean.isWiddershins(self.loopPath.path) else: self.oldConnectionPoint = None self.oldWiddershins = None self.distanceFeedRate.addLine(line) self.loopPath = None
def getBoundarySegments(self, begin, boundaries, end): 'Get the path broken into boundary segments whenever a different boundary is crossed.' boundarySegments = [] boundarySegment = BoundarySegment(begin) boundarySegments.append(boundarySegment) points = [] boundaryIndexes = self.getBoundaryIndexes(begin, boundaries, end, points) boundaryIndexesIndex = 0 while boundaryIndexesIndex < len(boundaryIndexes) - 1: if boundaryIndexes[boundaryIndexesIndex + 1] != boundaryIndexes[boundaryIndexesIndex]: boundarySegment.boundary = boundaries[ boundaryIndexes[boundaryIndexesIndex]] nextBoundary = boundaries[boundaryIndexes[boundaryIndexesIndex + 1]] if euclidean.isWiddershins( boundarySegment.boundary) and euclidean.isWiddershins( nextBoundary): boundarySegment.segment.append( points[boundaryIndexesIndex + 1]) boundarySegment = BoundarySegment( points[boundaryIndexesIndex + 2]) boundarySegment.boundary = nextBoundary boundarySegments.append(boundarySegment) boundaryIndexesIndex += 1 boundaryIndexesIndex += 1 boundarySegment.segment.append(points[-1]) return boundarySegments
def addTailoredLoopPath(self, line): "Add a clipped loop path." if self.clipLength > 0.0: removeTable = {} euclidean.addLoopToPixelTable(self.loopPath.path, removeTable, self.layerPixelWidth) euclidean.removePixelTableFromPixelTable(removeTable, self.layerPixelTable) self.loopPath.path = euclidean.getClippedLoopPath( self.clipLength, self.loopPath.path) self.loopPath.path = euclidean.getSimplifiedPath( self.loopPath.path, self.perimeterWidth) euclidean.addLoopToPixelTable(self.loopPath.path, self.layerPixelTable, self.layerPixelWidth) if self.oldWiddershins == None: self.addGcodeFromThreadZ(self.loopPath.path, self.loopPath.z) else: if self.oldWiddershins != euclidean.isWiddershins( self.loopPath.path): self.loopPath.path.reverse() # self.addGcodeFromThreadZ( self.loopPath.path, self.loopPath.z ) for point in self.loopPath.path: self.distanceFeedRate.addGcodeMovementZWithFeedRate( self.feedRateMinute, point, self.loopPath.z) if self.getNextThreadIsACloseLoop( self.loopPath.path) and self.maximumConnectionDistance > 0.0: self.oldWiddershins = euclidean.isWiddershins(self.loopPath.path) else: self.oldWiddershins = None self.distanceFeedRate.addLine(line) self.loopPath = None
def getInsetLoopsFromLoop(loop, radius, thresholdRatio=0.9,outsetInnerMagic=1.0): 'Get the inset loops, which might overlap.' if radius == 0.0: return [loop] # figureout cw or ccw sum = 0; for index,v in enumerate(loop): sum+=(loop[(index+1)%len(loop)].imag-v.imag)*(loop[(index+1)%len(loop)].real+v.real) isInner = sum<0 innerMagic = 1.0 if isInner: innerMagic = outsetInnerMagic; #if isInner: # arounds = getAroundsFromLoop(loop, radius, thresholdRatio) #else: # arounds = getAroundsFromLoop(loop, radius, thresholdRatio) isInset = radius > 0 insetLoops = [] isLoopWiddershins = euclidean.isWiddershins(loop) arounds = getAroundsFromLoop(loop, radius, thresholdRatio,innerMagic) for around in arounds: leftPoint = euclidean.getLeftPoint(around) shouldBeWithin = (isInset == isLoopWiddershins) if euclidean.isPointInsideLoop(loop, leftPoint) == shouldBeWithin: if isLoopWiddershins != euclidean.isWiddershins(around): around.reverse() insetLoops.append(around) return insetLoops
def getInsetLoopsFromLoop(loop, radius, thresholdRatio=0.9): 'Get the inset loops, which might overlap.' isInset = radius > 0 insetLoops = [] isLoopWiddershins = euclidean.isWiddershins(loop) arounds = getAroundsFromLoop(loop, radius, thresholdRatio) for around in arounds: leftPoint = euclidean.getLeftPoint(around) shouldBeWithin = (isInset == isLoopWiddershins) if euclidean.isPointInsideLoop(loop, leftPoint) == shouldBeWithin: if isLoopWiddershins != euclidean.isWiddershins(around): around.reverse() insetLoops.append(around) return insetLoops
def getInsetLoopsFromLoop(inset, loop, thresholdRatio=0.9): "Get the inset loops, which might overlap." isInset = inset > 0 insetLoops = [] isLoopWiddershins = euclidean.isWiddershins(loop) arounds = getAroundsFromLoop(loop, inset, thresholdRatio) for around in arounds: leftPoint = euclidean.getLeftPoint(around) shouldBeWithin = (isInset == isLoopWiddershins) if euclidean.isPointInsideLoop(loop, leftPoint) == shouldBeWithin: if isLoopWiddershins != euclidean.isWiddershins(around): around.reverse() insetLoops.append(around) return insetLoops
def getLoopsFromLoopsDirection(isWiddershins, loops): "Get the loops going round in a given direction." directionalLoops = [] for loop in loops: if euclidean.isWiddershins(loop) == isWiddershins: directionalLoops.append(loop) return directionalLoops
def addWiden(self, rotatedBoundaryLayer): "Add widen to the layer." loops = triangle_mesh.getLoopsInOrderOfArea( triangle_mesh.compareAreaAscending, rotatedBoundaryLayer.loops) widdershinsLoops = [] clockwiseInsetLoops = [] for loopIndex in xrange(len(loops)): loop = loops[loopIndex] if euclidean.isWiddershins(loop): otherLoops = loops[:loopIndex] + loops[loopIndex + 1:] leftPoint = euclidean.getLeftPoint(loop) if euclidean.isPointInsideLoops(otherLoops, leftPoint): self.distanceFeedRate.addGcodeFromLoop( loop, rotatedBoundaryLayer.z) else: widdershinsLoops.append(loop) else: clockwiseInsetLoops += intercircle.getInsetLoopsFromLoop( self.doublePerimeterWidth, loop) self.distanceFeedRate.addGcodeFromLoop(loop, rotatedBoundaryLayer.z) for widdershinsLoop in widdershinsLoops: outsetLoop = intercircle.getLargestInsetLoopFromLoop( widdershinsLoop, -self.doublePerimeterWidth) widenedLoop = getWidenedLoop(widdershinsLoop, clockwiseInsetLoops, outsetLoop, self.perimeterWidth, self.tinyRadius) self.distanceFeedRate.addGcodeFromLoop(widenedLoop, rotatedBoundaryLayer.z)
def addWiden(self, rotatedLoopLayer): "Add widen to the layer." trianglemesh.sortLoopsInOrderOfArea(False, rotatedLoopLayer.loops) widdershinsLoops = [] clockwiseInsetLoops = [] for loopIndex in xrange(len(rotatedLoopLayer.loops)): loop = rotatedLoopLayer.loops[loopIndex] if euclidean.isWiddershins(loop): otherLoops = rotatedLoopLayer.loops[: loopIndex] + rotatedLoopLayer.loops[ loopIndex + 1:] leftPoint = euclidean.getLeftPoint(loop) if getIsPointInsideALoop(otherLoops, leftPoint): self.distanceFeedRate.addGcodeFromLoop( loop, rotatedLoopLayer.z) else: widdershinsLoops.append(loop) else: # clockwiseInsetLoop = intercircle.getLargestInsetLoopFromLoop(loop, self.doublePerimeterWidth) # clockwiseInsetLoop.reverse() # clockwiseInsetLoops.append(clockwiseInsetLoop) clockwiseInsetLoops += intercircle.getInsetLoopsFromLoop( loop, self.doublePerimeterWidth) self.distanceFeedRate.addGcodeFromLoop(loop, rotatedLoopLayer.z) for widdershinsLoop in widdershinsLoops: outsetLoop = intercircle.getLargestInsetLoopFromLoop( widdershinsLoop, -self.doublePerimeterWidth) widenedLoop = getWidenedLoop(widdershinsLoop, clockwiseInsetLoops, outsetLoop, self.perimeterWidth) self.distanceFeedRate.addGcodeFromLoop(widenedLoop, rotatedLoopLayer.z)
def getGeometryOutputByLoops(derivation, loops): 'Get geometry output by sorted, nested loops.' loops.sort(key=euclidean.getAreaVector3LoopAbsolute, reverse=True) complexLoops = euclidean.getComplexPaths(loops) nestedRings = [] for loopIndex, loop in enumerate(loops): complexLoop = complexLoops[loopIndex] leftPoint = euclidean.getLeftPoint(complexLoop) isInFilledRegion = euclidean.getIsInFilledRegion(complexLoops[: loopIndex] + complexLoops[loopIndex + 1 :], leftPoint) if isInFilledRegion == euclidean.isWiddershins(complexLoop): loop.reverse() nestedRing = euclidean.NestedRing() nestedRing.boundary = complexLoop nestedRing.vector3Loop = loop nestedRings.append(nestedRing) nestedRings = euclidean.getOrderedNestedRings(nestedRings) nestedRings = euclidean.getFlattenedNestedRings(nestedRings) portionDirections = getSpacedPortionDirections(derivation.interpolationDictionary) if len(nestedRings) < 1: return {} if len(nestedRings) == 1: geometryOutput = getGeometryOutputByNestedRing(derivation, nestedRings[0], portionDirections) return solid.getGeometryOutputByManipulation(derivation.elementNode, geometryOutput) shapes = [] for nestedRing in nestedRings: shapes.append(getGeometryOutputByNestedRing(derivation, nestedRing, portionDirections)) return solid.getGeometryOutputByManipulation(derivation.elementNode, {'union' : {'shapes' : shapes}})
def getLoopsFromLoopsDirection( isWiddershins, loops ): 'Get the loops going round in a given direction.' directionalLoops = [] for loop in loops: if euclidean.isWiddershins(loop) == isWiddershins: directionalLoops.append(loop) return directionalLoops
def parseBoundaries(self): "Parse the boundaries and add them to the boundary layers." boundaryLoop = None boundaryLayer = None for line in self.lines[self.lineIndex :]: splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line) firstWord = gcodec.getFirstWord(splitLine) if len(self.shutdownLines) > 0: self.shutdownLines.append(line) if firstWord == "(</boundaryPerimeter>)": boundaryLoop = None elif firstWord == "(<boundaryPoint>": location = gcodec.getLocationFromSplitLine(None, splitLine) if boundaryLoop == None: boundaryLoop = [] boundaryLayer.loops.append(boundaryLoop) boundaryLoop.append(location.dropAxis()) elif firstWord == "(<layer>": boundaryLayer = euclidean.LoopLayer(float(splitLine[1])) self.boundaryLayers.append(boundaryLayer) elif firstWord == "(</crafting>)": self.shutdownLines = [line] for boundaryLayer in self.boundaryLayers: if not euclidean.isWiddershins(boundaryLayer.loops[0]): boundaryLayer.loops[0].reverse() self.boundaryReverseLayers = self.boundaryLayers[:] self.boundaryReverseLayers.reverse()
def parseBoundaries(self): "Parse the boundaries and add them to the boundary layers." boundaryLoop = None boundaryLayer = None for line in self.lines[self.lineIndex:]: splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line) firstWord = gcodec.getFirstWord(splitLine) if len(self.shutdownLines) > 0: self.shutdownLines.append(line) if firstWord == '(</boundaryPerimeter>)': boundaryLoop = None elif firstWord == '(<boundaryPoint>': location = gcodec.getLocationFromSplitLine(None, splitLine) if boundaryLoop == None: boundaryLoop = [] boundaryLayer.loops.append(boundaryLoop) boundaryLoop.append(location.dropAxis()) elif firstWord == '(<layer>': boundaryLayer = euclidean.LoopLayer(float(splitLine[1])) self.boundaryLayers.append(boundaryLayer) elif firstWord == '(</crafting>)': self.shutdownLines = [line] for boundaryLayer in self.boundaryLayers: if not euclidean.isWiddershins(boundaryLayer.loops[0]): boundaryLayer.loops[0].reverse() self.boundaryReverseLayers = self.boundaryLayers[:] self.boundaryReverseLayers.reverse()
def getGeometryOutputByLoops(derivation, loops): 'Get geometry output by sorted, nested loops.' loops.sort(key=euclidean.getAreaVector3LoopAbsolute, reverse=True) complexLoops = euclidean.getComplexPaths(loops) nestedRings = [] for loopIndex, loop in enumerate(loops): complexLoop = complexLoops[loopIndex] leftPoint = euclidean.getLeftPoint(complexLoop) isInFilledRegion = euclidean.getIsInFilledRegion(complexLoops[: loopIndex] + complexLoops[loopIndex + 1 :], leftPoint) if isInFilledRegion == euclidean.isWiddershins(complexLoop): loop.reverse() nestedRing = euclidean.NestedRing() nestedRing.boundary = complexLoop nestedRing.vector3Loop = loop nestedRings.append(nestedRing) nestedRings = euclidean.getOrderedNestedRings(nestedRings) nestedRings = euclidean.getFlattenedNestedRings(nestedRings) portionDirections = getSpacedPortionDirections(derivation.interpolationDictionary) if len(nestedRings) < 1: return {} if len(nestedRings) == 1: geometryOutput = getGeometryOutputByNestedRing(derivation, nestedRings[0], portionDirections) return solid.getGeometryOutputByManipulation(geometryOutput, derivation.xmlElement) shapes = [] for nestedRing in nestedRings: shapes.append(getGeometryOutputByNestedRing(derivation, nestedRing, portionDirections)) return solid.getGeometryOutputByManipulation({'union' : {'shapes' : shapes}}, derivation.xmlElement)
def addWiden(self, loopLayer): 'Add widen to the layer.' triangle_mesh.sortLoopsInOrderOfArea(False, loopLayer.loops) widdershinsLoops = [] clockwiseInsetLoops = [] for loopIndex in xrange(len(loopLayer.loops)): loop = loopLayer.loops[loopIndex] if euclidean.isWiddershins(loop): otherLoops = loopLayer.loops[:loopIndex] + loopLayer.loops[ loopIndex + 1:] leftPoint = euclidean.getLeftPoint(loop) if getIsPointInsideALoop(otherLoops, leftPoint): self.distanceFeedRate.addGcodeFromLoop(loop, loopLayer.z) else: widdershinsLoops.append(loop) else: # clockwiseInsetLoop = intercircle.getLargestInsetLoopFromLoop(loop, self.widenEdgeWidth) # clockwiseInsetLoop.reverse() # clockwiseInsetLoops.append(clockwiseInsetLoop) clockwiseInsetLoops += intercircle.getInsetLoopsFromLoop( loop, self.widenEdgeWidth) self.distanceFeedRate.addGcodeFromLoop(loop, loopLayer.z) for widdershinsLoop in widdershinsLoops: outsetLoop = intercircle.getLargestInsetLoopFromLoop( widdershinsLoop, -self.widenEdgeWidth) for widenedLoop in getWidenedLoops(widdershinsLoop, clockwiseInsetLoops, outsetLoop, self.lessThanHalfEdgeWidth): self.distanceFeedRate.addGcodeFromLoop(widenedLoop, loopLayer.z)
def getLargestCenterOutsetLoopFromLoop(loop, radius, thresholdRatio=0.9): 'Get the largest circle outset loop from the loop.' if radius == 0.0: return loop radius = abs(radius) points = getPointsFromLoop(loop, radius, thresholdRatio) centers = getCentersFromPoints(points, globalIntercircleMultiplier * radius) largestCenterOutset = None largestOutsetArea = -987654321.0 for center in centers: outset = getSimplifiedInsetFromClockwiseLoop(center, radius) if isLargeSameDirection(outset, center, radius): if euclidean.isPathInsideLoop( loop, outset) != euclidean.isWiddershins(loop): centerOutset = CenterOutset(center, outset) outsetArea = abs(euclidean.getAreaLoop(outset)) if outsetArea > largestOutsetArea: largestOutsetArea = outsetArea largestCenterOutset = centerOutset if largestCenterOutset == None: return None largestCenterOutset.center = euclidean.getSimplifiedLoop( largestCenterOutset.center, radius) return largestCenterOutset
def getOrientedLoops(loops): 'Orient the loops which must be in descending order.' for loopIndex, loop in enumerate(loops): leftPoint = euclidean.getLeftPoint(loop) isInFilledRegion = euclidean.getIsInFilledRegion(loops[: loopIndex] + loops[loopIndex + 1 :], leftPoint) if isInFilledRegion == euclidean.isWiddershins(loop): loop.reverse() return loops
def getAroundsFromPathPoints(points, radius, thresholdRatio=0.9): 'Get the arounds from the path.' centers = getCentersFromPoints(points, 0.8 * radius) arounds = [] for center in centers: if euclidean.isWiddershins(center): arounds.append(euclidean.getSimplifiedPath(center, radius)) return arounds
def getWiddershins(self): "Get widdershins for the layer." if self.layerZ in self.widdershinTable: return self.widdershinTable[self.layerZ] self.widdershinTable[self.layerZ] = [] for boundary in self.getBoundaries(): if euclidean.isWiddershins(boundary): self.widdershinTable[self.layerZ].append(boundary) return self.widdershinTable[self.layerZ]
def getWiddershins(self): 'Get widdershins for the layer.' if self.layerZ in self.widdershinTable: return self.widdershinTable[self.layerZ] self.widdershinTable[self.layerZ] = [] for boundary in self.getBoundaries(): if euclidean.isWiddershins(boundary): self.widdershinTable[self.layerZ].append(boundary) return self.widdershinTable[self.layerZ]
def addPerimeterBlock(self, loop, z): "Add the edge gcode block for the loop." if len(loop) < 2: return if euclidean.isWiddershins(loop): # Indicate that an edge is beginning. self.addLine("(<edge> outer )") else: self.addLine("(<edge> inner )") self.addGcodeFromThreadZ(loop + [loop[0]], z) self.addLine("(</edge>)") # Indicate that an edge is beginning.
def addPerimeterBlock(self, loop, z): 'Add the perimeter gcode block for the loop.' if len(loop) < 2: return if euclidean.isWiddershins(loop): # Indicate that a perimeter is beginning. self.addLine('(<perimeter> outer )') else: self.addLine('(<perimeter> inner )') self.addGcodeFromThreadZ(loop + [loop[0]], z) self.addLine('(</perimeter>)') # Indicate that a perimeter is beginning.
def getBoundarySegments(self, begin, boundaries, end): "Get the path broken into boundary segments whenever a different boundary is crossed." boundarySegments = [] boundarySegment = BoundarySegment(begin) boundarySegments.append(boundarySegment) points = [] boundaryIndexes = self.getBoundaryIndexes(begin, boundaries, end, points) boundaryIndexesIndex = 0 while boundaryIndexesIndex < len(boundaryIndexes) - 1: if boundaryIndexes[boundaryIndexesIndex + 1] != boundaryIndexes[boundaryIndexesIndex]: boundarySegment.boundary = boundaries[boundaryIndexes[boundaryIndexesIndex]] nextBoundary = boundaries[boundaryIndexes[boundaryIndexesIndex + 1]] if euclidean.isWiddershins(boundarySegment.boundary) and euclidean.isWiddershins(nextBoundary): boundarySegment.segment.append(points[boundaryIndexesIndex + 1]) boundarySegment = BoundarySegment(points[boundaryIndexesIndex + 2]) boundarySegment.boundary = nextBoundary boundarySegments.append(boundarySegment) boundaryIndexesIndex += 1 boundaryIndexesIndex += 1 boundarySegment.segment.append(points[-1]) return boundarySegments
def getBridgeLoops( layerThickness, loop ): "Get the inset bridge loops from the loop." halfWidth = 1.5 * layerThickness slightlyGreaterThanHalfWidth = 1.1 * halfWidth extrudateLoops = [] centers = intercircle.getCentersFromLoop( loop, slightlyGreaterThanHalfWidth ) for center in centers: extrudateLoop = intercircle.getSimplifiedInsetFromClockwiseLoop( center, halfWidth ) if intercircle.isLargeSameDirection( extrudateLoop, center, halfWidth ): if euclidean.isPathInsideLoop( loop, extrudateLoop ) == euclidean.isWiddershins( loop ): extrudateLoop.reverse() extrudateLoops.append( extrudateLoop ) return extrudateLoops
def getBridgeLoops( layerThickness, loop ): 'Get the inset bridge loops from the loop.' halfWidth = 1.5 * layerThickness slightlyGreaterThanHalfWidth = 1.1 * halfWidth extrudateLoops = [] centers = intercircle.getCentersFromLoop( loop, slightlyGreaterThanHalfWidth ) for center in centers: extrudateLoop = intercircle.getSimplifiedInsetFromClockwiseLoop( center, halfWidth ) if intercircle.isLargeSameDirection( extrudateLoop, center, halfWidth ): if euclidean.isPathInsideLoop( loop, extrudateLoop ) == euclidean.isWiddershins(loop): extrudateLoop.reverse() extrudateLoops.append( extrudateLoop ) return extrudateLoops
def addPerimeterInner(self, extrusionHalfWidth, oldOrderedLocation, threadSequence): 'Add to the perimeter and the inner island.' for loop in self.extraLoops: innerPerimeterLoop = Loop(self.runtimeParameters) if euclidean.isWiddershins(loop + [loop[0]]): innerPerimeterLoop.type = 'outer' else: innerPerimeterLoop.type = 'inner' innerPerimeterLoop.addPath(loop + [loop[0]]) self.loops.append(innerPerimeterLoop) for innerNestedRing in self.innerNestedRings: innerNestedRing.addToThreads(extrusionHalfWidth, oldOrderedLocation, threadSequence)
def getPathBetween(self, loop, points): "Add a path between the edge and the fill." paths = getPathsByIntersectedLoop(points[1], points[2], loop) shortestPath = paths[int( euclidean.getPathLength(paths[1]) < euclidean.getPathLength( paths[0]))] if len(shortestPath) < 2: return shortestPath if abs(points[1] - shortestPath[0]) > abs(points[1] - shortestPath[-1]): shortestPath.reverse() loopWiddershins = euclidean.isWiddershins(loop) pathBetween = [] for pointIndex in xrange(len(shortestPath)): center = shortestPath[pointIndex] centerPerpendicular = None beginIndex = pointIndex - 1 if beginIndex >= 0: begin = shortestPath[beginIndex] # with "self.edgeWidth*2.0" better "combed". See calibration file comb_test.stl . centerPerpendicular = intercircle.getWiddershinsByLength( center, begin, self.edgeWidth * 2.0) centerEnd = None endIndex = pointIndex + 1 if endIndex < len(shortestPath): end = shortestPath[endIndex] # with "self.edgeWidth*2.0" better "combed". See calibration file comb_test.stl . centerEnd = intercircle.getWiddershinsByLength( end, center, self.edgeWidth * 2.0) if centerPerpendicular == None: centerPerpendicular = centerEnd elif centerEnd != None: centerPerpendicular = 0.5 * (centerPerpendicular + centerEnd) between = None if centerPerpendicular == None: between = center if between == None: centerSideWiddershins = center + centerPerpendicular if euclidean.isPointInsideLoop( loop, centerSideWiddershins) == loopWiddershins: between = centerSideWiddershins if between == None: centerSideClockwise = center - centerPerpendicular if euclidean.isPointInsideLoop( loop, centerSideClockwise) == loopWiddershins: between = centerSideClockwise if between == None: between = center pathBetween.append(between) return pathBetween
def getLoopsFromMesh( self, z ): "Get loops from a carve of a mesh." originalLoops = [] if self.isCorrectMesh: originalLoops = getLoopsFromCorrectMesh( self.edges, self.faces, self.getTransformedVertexes(), z ) if len( originalLoops ) < 1: originalLoops = getLoopsFromUnprovenMesh( self.edges, self.faces, self.importRadius, self.getTransformedVertexes(), z ) loops = getLoopsInOrderOfArea( compareAreaDescending, euclidean.getSimplifiedLoops( originalLoops, self.importRadius ) ) for loopIndex in xrange( len(loops) ): loop = loops[loopIndex] leftPoint = euclidean.getLeftPoint(loop) isInFilledRegion = euclidean.getIsInFilledRegion( loops[ : loopIndex ] + loops[loopIndex + 1 :], leftPoint ) if isInFilledRegion == euclidean.isWiddershins(loop): loop.reverse() return loops
def getLoopsFromMesh( self, z ): "Get loops from a carve of a mesh." originalLoops = [] if self.isCorrectMesh: originalLoops = getLoopsFromCorrectMesh( self.edges, self.faces, self.getVertices(), z ) if len( originalLoops ) < 1: originalLoops = getLoopsFromUnprovenMesh( self.edges, self.faces, self.importRadius, self.getVertices(), z ) loops = getLoopsInOrderOfArea( compareAreaDescending, euclidean.getSimplifiedLoops( originalLoops, self.importRadius ) ) for loopIndex in xrange( len( loops ) ): loop = loops[ loopIndex ] leftPoint = euclidean.getLeftPoint( loop ) isInFilledRegion = euclidean.isInFilledRegion( loops[ : loopIndex ] + loops[ loopIndex + 1 : ], leftPoint ) if isInFilledRegion == euclidean.isWiddershins( loop ): loop.reverse() return loops
def getPathBetween( self, loop, points ): "Add a path between the perimeter and the fill." paths = getPathsByIntersectedLoop( points[ 1 ], points[ 2 ], loop ) shortestPath = paths[ int( euclidean.getPathLength( paths[ 1 ] ) < euclidean.getPathLength( paths[ 0 ] ) ) ] if not euclidean.isWiddershins( shortestPath ): shortestPath.reverse() loopAround = intercircle.getLargestInsetLoopFromLoopNoMatterWhat( shortestPath, - self.combInset ) endMinusBegin = points[ 3 ] - points[ 0 ] endMinusBegin = 1.3 * self.combInset * euclidean.getNormalized( endMinusBegin ) aroundPaths = getPathsByIntersectedLoop( points[ 0 ] - endMinusBegin, points[ 3 ] + endMinusBegin, loopAround ) insidePath = aroundPaths[ int( getInsideness( aroundPaths[ 1 ], loop ) > getInsideness( aroundPaths[ 0 ], loop ) ) ] pathBetween = [] for point in insidePath: if euclidean.isPointInsideLoop( loop, point ): pathBetween.append(point ) return pathBetween
def setBoundaryPerimeter(self, boundaryPointsLoop, perimeterLoop=None): self.perimeter = BoundaryPerimeter(self.runtimeParameters) for point in boundaryPointsLoop: self.perimeter.boundaryPoints.append(Vector3(point.real, point.imag, 0)) if len(boundaryPointsLoop) < 2: return if perimeterLoop == None: perimeterLoop = boundaryPointsLoop if euclidean.isWiddershins(perimeterLoop): self.perimeter.type = 'outer' else: self.perimeter.type = 'inner' path = perimeterLoop + [perimeterLoop[0]] self.perimeter.addPath(path)
def getLargestCenterOutsetLoopFromLoop(loop, radius, thresholdRatio=0.9): 'Get the largest circle outset loop from the loop.' radius = abs(radius) points = getPointsFromLoop(loop, radius, thresholdRatio) centers = getCentersFromPoints(points, globalIntercircleMultiplier * radius) largestCenterOutset = None largestOutsetArea = -987654321.0 for center in centers: outset = getSimplifiedInsetFromClockwiseLoop(center, radius) if isLargeSameDirection(outset, center, radius): if euclidean.isPathInsideLoop(loop, outset) != euclidean.isWiddershins(loop): centerOutset = CenterOutset(center, outset) outsetArea = abs(euclidean.getAreaLoop(outset)) if outsetArea > largestOutsetArea: largestOutsetArea = outsetArea largestCenterOutset = centerOutset if largestCenterOutset == None: return None largestCenterOutset.center = euclidean.getSimplifiedLoop(largestCenterOutset.center, radius) return largestCenterOutset
def getPathBetween(self, loop, points): "Add a path between the edge and the fill." paths = getPathsByIntersectedLoop(points[1], points[2], loop) shortestPath = paths[int(euclidean.getPathLength(paths[1]) < euclidean.getPathLength(paths[0]))] if len(shortestPath) < 2: return shortestPath if abs(points[1] - shortestPath[0]) > abs(points[1] - shortestPath[-1]): shortestPath.reverse() loopWiddershins = euclidean.isWiddershins(loop) pathBetween = [] for pointIndex in xrange(len(shortestPath)): center = shortestPath[pointIndex] centerPerpendicular = None beginIndex = pointIndex - 1 if beginIndex >= 0: begin = shortestPath[beginIndex] centerPerpendicular = intercircle.getWiddershinsByLength(center, begin, self.edgeWidth) centerEnd = None endIndex = pointIndex + 1 if endIndex < len(shortestPath): end = shortestPath[endIndex] centerEnd = intercircle.getWiddershinsByLength(end, center, self.edgeWidth) if centerPerpendicular == None: centerPerpendicular = centerEnd elif centerEnd != None: centerPerpendicular = 0.5 * (centerPerpendicular + centerEnd) between = None if centerPerpendicular == None: between = center if between == None: centerSideWiddershins = center + centerPerpendicular if euclidean.isPointInsideLoop(loop, centerSideWiddershins) == loopWiddershins: between = centerSideWiddershins if between == None: centerSideClockwise = center - centerPerpendicular if euclidean.isPointInsideLoop(loop, centerSideClockwise) == loopWiddershins: between = centerSideClockwise if between == None: between = center pathBetween.append(between) return pathBetween
def addWiden( self, rotatedBoundaryLayer ): "Add widen to the layer." loops = triangle_mesh.getLoopsInOrderOfArea( triangle_mesh.compareAreaAscending, rotatedBoundaryLayer.loops ) widdershinsLoops = [] clockwiseInsetLoops = [] for loopIndex in xrange( len( loops ) ): loop = loops[ loopIndex ] if euclidean.isWiddershins( loop ): otherLoops = loops[ : loopIndex ] + loops[ loopIndex + 1 : ] leftPoint = euclidean.getLeftPoint( loop ) if euclidean.isPointInsideLoops( otherLoops, leftPoint ): self.distanceFeedRate.addGcodeFromLoop( loop, rotatedBoundaryLayer.z ) else: widdershinsLoops.append( loop ) else: clockwiseInsetLoops += intercircle.getInsetLoopsFromLoop( self.doublePerimeterWidth, loop ) self.distanceFeedRate.addGcodeFromLoop( loop, rotatedBoundaryLayer.z ) for widdershinsLoop in widdershinsLoops: outsetLoop = intercircle.getLargestInsetLoopFromLoop( widdershinsLoop, - self.doublePerimeterWidth ) widenedLoop = getWidenedLoop( widdershinsLoop, clockwiseInsetLoops, outsetLoop, self.perimeterWidth, self.tinyRadius ) self.distanceFeedRate.addGcodeFromLoop( widenedLoop, rotatedBoundaryLayer.z )
def getLargestCenterOutsetLoopFromLoop( loop, radius, thresholdRatio = 0.9 ): "Get the largest circle outset loop from the loop." radius = abs(radius) slightlyGreaterThanRadius = 1.01 * radius points = getPointsFromLoop( loop, slightlyGreaterThanRadius, thresholdRatio ) centers = getCentersFromPoints( points, radius ) largestCenterOutset = None largestOutsetArea = - 999999999.0 for center in centers: outset = getSimplifiedInsetFromClockwiseLoop( center, radius ) if isLargeSameDirection( outset, center, radius ): if euclidean.isPathInsideLoop( loop, outset ) != euclidean.isWiddershins(loop): centerOutset = CenterOutset( center, outset ) outsetArea = abs( euclidean.getPolygonArea( outset ) ) if outsetArea > largestOutsetArea: outsetArea = largestOutsetArea largestCenterOutset = centerOutset if largestCenterOutset == None: return None largestCenterOutset.center = euclidean.getSimplifiedLoop( largestCenterOutset.center, radius ) return largestCenterOutset
def getPathBetween(self, loop, points): "Add a path between the perimeter and the fill." paths = getPathsByIntersectedLoop(points[1], points[2], loop) shortestPath = paths[int( euclidean.getPathLength(paths[1]) < euclidean.getPathLength( paths[0]))] if not euclidean.isWiddershins(shortestPath): shortestPath.reverse() loopAround = intercircle.getLargestInsetLoopFromLoopNoMatterWhat( shortestPath, -self.combInset) endMinusBegin = points[3] - points[0] endMinusBegin = 1.3 * self.combInset * euclidean.getNormalized( endMinusBegin) aroundPaths = getPathsByIntersectedLoop(points[0] - endMinusBegin, points[3] + endMinusBegin, loopAround) insidePath = aroundPaths[int( getInsideness(aroundPaths[1], loop) > getInsideness( aroundPaths[0], loop))] pathBetween = [] for point in insidePath: if euclidean.isPointInsideLoop(loop, point): pathBetween.append(point) return pathBetween
def addWiden(self, rotatedLoopLayer): 'Add widen to the layer.' triangle_mesh.sortLoopsInOrderOfArea(False, rotatedLoopLayer.loops) widdershinsLoops = [] clockwiseInsetLoops = [] for loopIndex in xrange(len(rotatedLoopLayer.loops)): loop = rotatedLoopLayer.loops[loopIndex] if euclidean.isWiddershins(loop): otherLoops = rotatedLoopLayer.loops[: loopIndex] + rotatedLoopLayer.loops[loopIndex + 1 :] leftPoint = euclidean.getLeftPoint(loop) if getIsPointInsideALoop(otherLoops, leftPoint): self.distanceFeedRate.addGcodeFromLoop(loop, rotatedLoopLayer.z) else: widdershinsLoops.append(loop) else: # clockwiseInsetLoop = intercircle.getLargestInsetLoopFromLoop(loop, self.doublePerimeterWidth) # clockwiseInsetLoop.reverse() # clockwiseInsetLoops.append(clockwiseInsetLoop) clockwiseInsetLoops += intercircle.getInsetLoopsFromLoop(loop, self.doublePerimeterWidth) self.distanceFeedRate.addGcodeFromLoop(loop, rotatedLoopLayer.z) for widdershinsLoop in widdershinsLoops: outsetLoop = intercircle.getLargestInsetLoopFromLoop(widdershinsLoop, -self.doublePerimeterWidth) widenedLoop = getWidenedLoop(widdershinsLoop, clockwiseInsetLoops, outsetLoop, self.perimeterWidth) self.distanceFeedRate.addGcodeFromLoop(widenedLoop, rotatedLoopLayer.z)
def fill(self, layer): 'Add fill to the carve layer.' layerIndex = layer.index alreadyFilledArounds = [] pixelTable = {} arounds = [] betweenWidth = self.extrusionWidth / 1.7594801994 # this really sucks I cant find hwe#(self.repository.infillWidthOverThickness.value * self.extrusionWidth *(0.7853))/1.5 #- 0.0866#todo todo TODO *0.5 is the distance between the outer loops.. self.layerExtrusionWidth = self.infillWidth # spacing between fill lines layerFillInset = self.infillWidth # the distance between perimeter incl loops and the fill pattern layerRotation = self.getLayerRotation(layerIndex, layer) reverseRotation = complex(layerRotation.real, -layerRotation.imag) surroundingCarves = [] layerRemainder = layerIndex % self.diaphragmPeriod extraShells = self.extraShellsSparseLayer if layerRemainder >= self.diaphragmThickness and layer.bridgeRotation == None: for surroundingIndex in xrange(1, self.solidSurfaceThickness + 1): self.addRotatedCarve(layerIndex, -surroundingIndex, reverseRotation, surroundingCarves) self.addRotatedCarve(layerIndex, surroundingIndex, reverseRotation, surroundingCarves) if len(surroundingCarves) < self.doubleSolidSurfaceThickness: extraShells = self.extraShellsAlternatingSolidLayer if self.previousExtraShells != self.extraShellsBase: extraShells = self.extraShellsBase if layer.bridgeRotation != None: extraShells = 0 betweenWidth *= self.bridgeWidthMultiplier #/0.7853 #todo check what is better with or without the normalizer self.layerExtrusionWidth *= self.bridgeWidthMultiplier layerFillInset *= self.bridgeWidthMultiplier aroundInset = 0.25 * self.layerExtrusionWidth aroundWidth = 0.25 * self.layerExtrusionWidth self.previousExtraShells = extraShells gridPointInsetX = 0.5 * layerFillInset doubleExtrusionWidth = 2.0 * self.layerExtrusionWidth endpoints = [] infillPaths = [] layerInfillSolidity = self.infillSolidity self.isDoubleJunction = True self.isJunctionWide = True rotatedLoops = [] nestedRings = layer.nestedRings createFillForSurroundings(nestedRings, betweenWidth, False) for extraShellIndex in xrange(extraShells): createFillForSurroundings(nestedRings, self.layerExtrusionWidth, True) fillLoops = euclidean.getFillOfSurroundings(nestedRings, None) slightlyGreaterThanFill = 1.001 * layerFillInset #todo was 1.01 ACT 0.95 How much the parallel fill is filled for loop in fillLoops: alreadyFilledLoop = [] alreadyFilledArounds.append(alreadyFilledLoop) planeRotatedPerimeter = euclidean.getPointsRoundZAxis( reverseRotation, loop) rotatedLoops.append(planeRotatedPerimeter) centers = intercircle.getCentersFromLoop(planeRotatedPerimeter, slightlyGreaterThanFill) euclidean.addLoopToPixelTable(planeRotatedPerimeter, pixelTable, aroundWidth) for center in centers: alreadyFilledInset = intercircle.getSimplifiedInsetFromClockwiseLoop( center, layerFillInset) if intercircle.isLargeSameDirection(alreadyFilledInset, center, layerFillInset): alreadyFilledLoop.append(alreadyFilledInset) around = intercircle.getSimplifiedInsetFromClockwiseLoop( center, aroundInset) if euclidean.isPathInsideLoop( planeRotatedPerimeter, around) == euclidean.isWiddershins( planeRotatedPerimeter): around.reverse() arounds.append(around) euclidean.addLoopToPixelTable(around, pixelTable, aroundWidth) if len(arounds) < 1: self.addThreadsBridgeLayer(layerIndex, nestedRings, layer) return back = euclidean.getBackOfLoops(arounds) front = euclidean.getFrontOfLoops(arounds) front = math.ceil( front / self.layerExtrusionWidth) * self.layerExtrusionWidth fillWidth = back - front numberOfLines = int(math.ceil(fillWidth / self.layerExtrusionWidth)) self.frontOverWidth = 0.0 self.horizontalSegmentLists = euclidean.getHorizontalSegmentListsFromLoopLists( alreadyFilledArounds, front, numberOfLines, rotatedLoops, self.layerExtrusionWidth) self.surroundingXIntersectionLists = [] self.yList = [] removedEndpoints = [] if len(surroundingCarves) >= self.doubleSolidSurfaceThickness: xIntersectionIndexLists = [] self.frontOverWidth = euclidean.getFrontOverWidthAddXListYList( front, surroundingCarves, numberOfLines, xIntersectionIndexLists, self.layerExtrusionWidth, self.yList) for fillLine in xrange(len(self.horizontalSegmentLists)): xIntersectionIndexList = xIntersectionIndexLists[fillLine] surroundingXIntersections = euclidean.getIntersectionOfXIntersectionIndexes( self.doubleSolidSurfaceThickness, xIntersectionIndexList) self.surroundingXIntersectionLists.append( surroundingXIntersections) addSparseEndpoints(doubleExtrusionWidth, endpoints, fillLine, self.horizontalSegmentLists, layerInfillSolidity, removedEndpoints, self.solidSurfaceThickness, surroundingXIntersections) else: for fillLine in xrange(len(self.horizontalSegmentLists)): addSparseEndpoints(doubleExtrusionWidth, endpoints, fillLine, self.horizontalSegmentLists, layerInfillSolidity, removedEndpoints, self.solidSurfaceThickness, None) paths = euclidean.getPathsFromEndpoints(endpoints, 5.0 * self.layerExtrusionWidth, pixelTable, aroundWidth) oldRemovedEndpointLength = len(removedEndpoints) + 1 while oldRemovedEndpointLength - len(removedEndpoints) > 0: oldRemovedEndpointLength = len(removedEndpoints) removeEndpoints(pixelTable, self.layerExtrusionWidth, paths, removedEndpoints, aroundWidth) paths = euclidean.getConnectedPaths(paths, pixelTable, aroundWidth) for path in paths: addPathToInfillPaths(self.layerExtrusionWidth, infillPaths, path, layerRotation) for nestedRing in nestedRings: nestedRing.transferPaths(infillPaths) self.addThreadsBridgeLayer(layerIndex, nestedRings, layer)
def isLargeSameDirection( inset, loop, radius ): "Determine if the inset is in the same direction as the loop and it is large enough." if euclidean.isWiddershins( inset ) != euclidean.isWiddershins( loop ): return False return euclidean.getMaximumSpan( inset ) > 2.01 * abs( radius )
def directLoop(isWiddershins, loop): 'Direct the loop.' if euclidean.isWiddershins(loop) != isWiddershins: loop.reverse()
def fill(self, layer): 'Add fill to the carve layer.' layerIndex = layer.index alreadyFilledArounds = [] pixelTable = {} arounds = [] betweenWidth = self.extrusionWidth / 1.7594801994 # this really sucks I cant find hwe#(self.repository.infillWidthOverThickness.value * self.extrusionWidth *(0.7853))/1.5 #- 0.0866#todo todo TODO *0.5 is the distance between the outer loops.. self.layerExtrusionWidth = self.infillWidth # spacing between fill lines layerFillInset = self.infillWidth # the distance between perimeter incl loops and the fill pattern layerRotation = self.getLayerRotation(layerIndex, layer) reverseRotation = complex(layerRotation.real, -layerRotation.imag) surroundingCarves = [] layerRemainder = layerIndex % self.diaphragmPeriod extraShells = self.extraShellsSparseLayer if layerRemainder >= self.diaphragmThickness and layer.bridgeRotation == None: for surroundingIndex in xrange(1, self.solidSurfaceThickness + 1): self.addRotatedCarve(layerIndex, -surroundingIndex, reverseRotation, surroundingCarves) self.addRotatedCarve(layerIndex, surroundingIndex, reverseRotation, surroundingCarves) if len(surroundingCarves) < self.doubleSolidSurfaceThickness: extraShells = self.extraShellsAlternatingSolidLayer if self.previousExtraShells != self.extraShellsBase: extraShells = self.extraShellsBase if layer.bridgeRotation != None: extraShells = 0 betweenWidth *= self.bridgeWidthMultiplier#/0.7853 #todo check what is better with or without the normalizer self.layerExtrusionWidth *= self.bridgeWidthMultiplier layerFillInset *= self.bridgeWidthMultiplier aroundInset = 0.25 * self.layerExtrusionWidth aroundWidth = 0.25 * self.layerExtrusionWidth self.previousExtraShells = extraShells gridPointInsetX = 0.5 * layerFillInset doubleExtrusionWidth = 2.0 * self.layerExtrusionWidth endpoints = [] infillPaths = [] layerInfillSolidity = self.infillSolidity self.isDoubleJunction = True self.isJunctionWide = True rotatedLoops = [] nestedRings = layer.nestedRings createFillForSurroundings(nestedRings, betweenWidth, False) for extraShellIndex in xrange(extraShells): createFillForSurroundings(nestedRings, self.layerExtrusionWidth, True) fillLoops = euclidean.getFillOfSurroundings(nestedRings, None) slightlyGreaterThanFill = 1.001 * layerFillInset #todo was 1.01 ACT 0.95 How much the parallel fill is filled for loop in fillLoops: alreadyFilledLoop = [] alreadyFilledArounds.append(alreadyFilledLoop) planeRotatedPerimeter = euclidean.getPointsRoundZAxis(reverseRotation, loop) rotatedLoops.append(planeRotatedPerimeter) centers = intercircle.getCentersFromLoop(planeRotatedPerimeter, slightlyGreaterThanFill) euclidean.addLoopToPixelTable(planeRotatedPerimeter, pixelTable, aroundWidth) for center in centers: alreadyFilledInset = intercircle.getSimplifiedInsetFromClockwiseLoop(center, layerFillInset) if intercircle.isLargeSameDirection(alreadyFilledInset, center, layerFillInset): alreadyFilledLoop.append(alreadyFilledInset) around = intercircle.getSimplifiedInsetFromClockwiseLoop(center, aroundInset) if euclidean.isPathInsideLoop(planeRotatedPerimeter, around) == euclidean.isWiddershins(planeRotatedPerimeter): around.reverse() arounds.append(around) euclidean.addLoopToPixelTable(around, pixelTable, aroundWidth) if len(arounds) < 1: self.addThreadsBridgeLayer(layerIndex, nestedRings, layer) return back = euclidean.getBackOfLoops(arounds) front = euclidean.getFrontOfLoops(arounds) front = math.ceil(front / self.layerExtrusionWidth) * self.layerExtrusionWidth fillWidth = back - front numberOfLines = int(math.ceil(fillWidth / self.layerExtrusionWidth)) self.frontOverWidth = 0.0 self.horizontalSegmentLists = euclidean.getHorizontalSegmentListsFromLoopLists(alreadyFilledArounds, front, numberOfLines, rotatedLoops, self.layerExtrusionWidth) self.surroundingXIntersectionLists = [] self.yList = [] removedEndpoints = [] if len(surroundingCarves) >= self.doubleSolidSurfaceThickness: xIntersectionIndexLists = [] self.frontOverWidth = euclidean.getFrontOverWidthAddXListYList(front, surroundingCarves, numberOfLines, xIntersectionIndexLists, self.layerExtrusionWidth, self.yList) for fillLine in xrange(len(self.horizontalSegmentLists)): xIntersectionIndexList = xIntersectionIndexLists[fillLine] surroundingXIntersections = euclidean.getIntersectionOfXIntersectionIndexes(self.doubleSolidSurfaceThickness, xIntersectionIndexList) self.surroundingXIntersectionLists.append(surroundingXIntersections) addSparseEndpoints(doubleExtrusionWidth, endpoints, fillLine, self.horizontalSegmentLists, layerInfillSolidity, removedEndpoints, self.solidSurfaceThickness, surroundingXIntersections) else: for fillLine in xrange(len(self.horizontalSegmentLists)): addSparseEndpoints(doubleExtrusionWidth, endpoints, fillLine, self.horizontalSegmentLists, layerInfillSolidity, removedEndpoints, self.solidSurfaceThickness, None) paths = euclidean.getPathsFromEndpoints(endpoints, 5.0 * self.layerExtrusionWidth, pixelTable, aroundWidth) oldRemovedEndpointLength = len(removedEndpoints) + 1 while oldRemovedEndpointLength - len(removedEndpoints) > 0: oldRemovedEndpointLength = len(removedEndpoints) removeEndpoints(pixelTable, self.layerExtrusionWidth, paths, removedEndpoints, aroundWidth) paths = euclidean.getConnectedPaths(paths, pixelTable, aroundWidth) for path in paths: addPathToInfillPaths(self.layerExtrusionWidth, infillPaths, path, layerRotation) for nestedRing in nestedRings: nestedRing.transferPaths(infillPaths) self.addThreadsBridgeLayer(layerIndex, nestedRings, layer)
def isLargeSameDirection(inset, loop, radius): "Determine if the inset is in the same direction as the loop and it is large enough." if euclidean.isWiddershins(inset) != euclidean.isWiddershins(loop): return False return euclidean.getMaximumSpan(inset) > 2.01 * abs(radius)
def directLoops(isWiddershins, loops): "Directed the loops." for loop in loops: if euclidean.isWiddershins(loop) != isWiddershins: loop.reverse()
def directLoops( isWiddershins, loops ): "Directed the loops." for loop in loops: if euclidean.isWiddershins( loop ) != isWiddershins: loop.reverse()
def isLargeSameDirection(inset, loop, radius): 'Determine if the inset is in the same direction as the loop and it is large enough.' if euclidean.isWiddershins(inset) != euclidean.isWiddershins(loop): return False return getIsLarge(inset, radius) and len(inset) > 2