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 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 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(2)) elif firstWord == '(<layer>': boundaryLayer = euclidean.LoopLayer(float(splitLine[1])) self.boundaryLayers.append(boundaryLayer) elif firstWord == '(</extrusion>)': 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 moveColoredThreadToSkeinPane( self ): 'Move a colored thread to the skein pane.' if len( self.coloredThread ) <= 0: return layerZoneIndex = self.getLayerZoneIndex( self.coloredThread[ 0 ].z ) if not self.extruderActive: self.setColoredThread( ( 190.0, 190.0, 190.0 ), self.skeinPane.travelLines ) #gray return self.skeinPane.layerZoneIndex = layerZoneIndex if self.isPerimeter: perimeterComplex = getPolygonComplexFromColoredLines( self.coloredThread ) if euclidean.isWiddershins( perimeterComplex ): self.setColoredThread( ( 255.0, 0.0, 0.0 ), self.skeinPane.perimeterOutsideLines ) #red else: self.setColoredThread( ( 255.0, 165.0, 0.0 ), self.skeinPane.perimeterInsideLines ) #orange return if self.isLoop: self.setColoredThread( ( 255.0, 255.0, 0.0 ), self.skeinPane.loopLines ) #yellow return if not self.hasASurroundingLoopBeenReached: self.setColoredThread( ( 165.0, 42.0, 42.0 ), self.skeinPane.raftLines ) #brown return if layerZoneIndex < self.beholdPreferences.numberOfFillBottomLayers.value: self.setColoredThread( ( 128.0, 128.0, 0.0 ), self.skeinPane.fillBottomLines ) #olive return if layerZoneIndex >= self.firstTopLayer: self.setColoredThread( ( 0.0, 0.0, 255.0 ), self.skeinPane.fillTopLines ) #blue return self.setColoredThread( ( 0.0, 255.0, 0.0 ), self.skeinPane.extrudeLines ) #green
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 getLoopsFromLoopsDirection( isWiddershins, loops ): "Get the loops going round in a given direction." directionalLoopComplexes = [] for loop in loops: if euclidean.isWiddershins( loop ) == isWiddershins: directionalLoopComplexes.append( loop ) return directionalLoopComplexes
def getLoopsFromLoopsDirection( isWiddershins, loops ): "Get the loops going round in a given direction." directionalLoopComplexes = [] for loop in loops: if euclidean.isWiddershins( loop ) == isWiddershins: directionalLoopComplexes.append( loop ) return directionalLoopComplexes
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( 2 ) ) elif firstWord == '(<layer>': boundaryLayer = euclidean.LoopLayer( float( splitLine[ 1 ] ) ) self.boundaryLayers.append( boundaryLayer ) elif firstWord == '(</extrusion>)': 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 addPathBeforeEnd( self, aroundBetweenPath, location, loop ): "Add the path before the end of the loop." halfFillInset = 0.5 * self.fillInset if self.arrivalInsetFollowDistance < halfFillInset: return locationComplex = location.dropAxis( 2 ) closestInset = None closestDistanceIndex = euclidean.DistanceIndex( 999999999999999999.0, - 1 ) loop = euclidean.getAwayPoints( loop, self.extrusionWidth ) circleNodes = intercircle.getCircleNodesFromLoop( loop, self.fillInset ) centers = [] centers = intercircle.getCentersFromCircleNodes( circleNodes ) for center in centers: inset = intercircle.getInsetFromClockwiseLoop( center, halfFillInset ) if euclidean.isLargeSameDirection( inset, center, self.fillInset ): if euclidean.isPathInsideLoop( loop, inset ) == euclidean.isWiddershins( loop ): distanceIndex = euclidean.getNearestDistanceIndex( locationComplex, inset ) if distanceIndex.distance < closestDistanceIndex.distance: closestInset = inset closestDistanceIndex = distanceIndex if closestInset == None: return extrusionHalfWidth = 0.5 * self.extrusionWidth closestInset = euclidean.getLoopStartingNearest( extrusionHalfWidth, locationComplex, closestInset ) if euclidean.getPolygonLength( closestInset ) < 0.2 * self.arrivalInsetFollowDistance: return closestInset.append( closestInset[ 0 ] ) closestInset = euclidean.getSimplifiedPath( closestInset, self.extrusionWidth ) closestInset.reverse() pathBeforeArrival = euclidean.getClippedAtEndLoopPath( self.arrivalInsetFollowDistance, closestInset ) pointBeforeArrival = pathBeforeArrival[ - 1 ] aroundBetweenPath.append( pointBeforeArrival ) if self.arrivalInsetFollowDistance <= halfFillInset: return aroundBetweenPath += euclidean.getClippedAtEndLoopPath( halfFillInset, closestInset )[ len( pathBeforeArrival ) - 1 : ]
def addTailoredLoopPath( self, line ): "Add a clipped and jittered loop path." if self.clipLength > 0.0: self.loopPath.path = euclidean.getClippedLoopPath( self.clipLength, self.loopPath.path ) self.loopPath.path = euclidean.getSimplifiedPath( self.loopPath.path, self.perimeterWidth ) 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() for point in self.loopPath.path: self.distanceFeedRate.addGcodeMovementZWithFeedRate( self.feedRateMinute, point, self.loopPath.z ) if self.getNextThreadIsACloseLoop( self.loopPath.path ): self.oldWiddershins = euclidean.isWiddershins( self.loopPath.path ) else: self.oldWiddershins = None self.distanceFeedRate.addLine( line ) self.loopPath = None
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 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 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 addTailoredLoopPath(self, line): "Add a clipped and jittered loop path." if self.clipLength > 0.0: self.loopPath.path = euclidean.getClippedLoopPath( self.clipLength, self.loopPath.path) self.loopPath.path = euclidean.getSimplifiedPath( self.loopPath.path, self.perimeterWidth) 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() for point in self.loopPath.path: self.distanceFeedRate.addGcodeMovementZWithFeedRate( self.feedRateMinute, point, self.loopPath.z) if self.getNextThreadIsACloseLoop(self.loopPath.path): self.oldWiddershins = euclidean.isWiddershins(self.loopPath.path) else: self.oldWiddershins = None self.distanceFeedRate.addLine(line) self.loopPath = None
def getAroundBetweenPath( self, location ): "Insert paths around and between the perimeter and the fill." aroundBetweenPath = [] outerPerimeter = None if str( location ) in self.pointTable: perimeter = self.pointTable[ str( location ) ] if euclidean.isWiddershins( perimeter ): outerPerimeter = perimeter nextBeginning = self.getOutloopLocation( location ) pathEnd = self.getOutloopLocation( self.oldLocation ) self.insertPathsBetween( aroundBetweenPath, nextBeginning, pathEnd ) if outerPerimeter != None: self.addPathBeforeEnd( aroundBetweenPath, location, outerPerimeter ) return aroundBetweenPath
def getAroundBetweenPath(self, location): "Insert paths around and between the perimeter and the fill." aroundBetweenPath = [] outerPerimeter = None if str(location) in self.pointTable: perimeter = self.pointTable[str(location)] if euclidean.isWiddershins(perimeter): outerPerimeter = perimeter nextBeginning = self.getOutloopLocation(location) pathEnd = self.getOutloopLocation(self.oldLocation) self.insertPathsBetween(aroundBetweenPath, nextBeginning, pathEnd) if outerPerimeter != None: self.addPathBeforeEnd(aroundBetweenPath, location, outerPerimeter) return aroundBetweenPath
def addAlreadyFilledArounds( alreadyFilledArounds, loop, radius ): "Add already filled loops around loop to alreadyFilledArounds." radius = abs( radius ) alreadyFilledLoop = [] slightlyGreaterThanRadius = 1.01 * radius muchGreaterThanRadius = 2.5 * radius circleNodes = intercircle.getCircleNodesFromLoop( loop, slightlyGreaterThanRadius ) centers = intercircle.getCentersFromCircleNodes( circleNodes ) for center in centers: alreadyFilledInset = intercircle.getSimplifiedInsetFromClockwiseLoop( center, radius ) if euclidean.isLarge( alreadyFilledInset, muchGreaterThanRadius ) or euclidean.isWiddershins( alreadyFilledInset ): alreadyFilledLoop.append( alreadyFilledInset ) if len( alreadyFilledLoop ) > 0: alreadyFilledArounds.append( alreadyFilledLoop )
def getLoopsFromMesh( self, z ): "Get loops from a carve of a mesh." originalLoops = [] if self.isCorrectMesh: originalLoops = getLoopsFromCorrectMesh( self.edges, self.faces, self.vertices, z ) if len( originalLoops ) < 1: originalLoops = getLoopsFromUnprovenMesh( self.edges, self.faces, self.importRadius, self.vertices, 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 addAlreadyFilledArounds(alreadyFilledArounds, loop, radius): "Add already filled loops around loop to alreadyFilledArounds." radius = abs(radius) alreadyFilledLoop = [] slightlyGreaterThanRadius = 1.01 * radius muchGreaterThanRadius = 2.5 * radius circleNodes = intercircle.getCircleNodesFromLoop( loop, slightlyGreaterThanRadius) centers = intercircle.getCentersFromCircleNodes(circleNodes) for center in centers: alreadyFilledInset = intercircle.getSimplifiedInsetFromClockwiseLoop( center, radius) if euclidean.isLarge(alreadyFilledInset, muchGreaterThanRadius ) or euclidean.isWiddershins(alreadyFilledInset): alreadyFilledLoop.append(alreadyFilledInset) if len(alreadyFilledLoop) > 0: alreadyFilledArounds.append(alreadyFilledLoop)
def getBetweens( self ): "Set betweens for the layer." if self.layerZ in self.betweenTable: return self.betweenTable[ self.layerZ ] if self.layerZ not in self.layerTable: return [] halfFillInset = 0.5 * self.fillInset betweens = [] for boundaryLoop in self.layerTable[ self.layerZ ]: circleNodes = intercircle.getCircleNodesFromLoop( boundaryLoop, self.fillInset ) centers = intercircle.getCentersFromCircleNodes( circleNodes ) for center in centers: inset = intercircle.getSimplifiedInsetFromClockwiseLoop( center, halfFillInset ) if euclidean.isLargeSameDirection( inset, center, self.fillInset ): if euclidean.isPathInsideLoop( boundaryLoop, inset ) == euclidean.isWiddershins( boundaryLoop ): betweens.append( inset ) self.betweenTable[ self.layerZ ] = betweens return betweens
def getInsetLoopsFromLoop( inset, loop ): "Get the inset loops from a loop." absoluteInset = abs( inset ) insetLoops = [] slightlyGreaterThanInset = 1.1 * absoluteInset muchGreaterThanLayerInset = 2.5 * absoluteInset isInInsetDirection = euclidean.isWiddershins( loop ) if inset < 0.0: isInInsetDirection = not isInInsetDirection centers = getCentersFromLoopDirection( not isInInsetDirection, loop, slightlyGreaterThanInset ) for center in centers: insetLoop = getSimplifiedInsetFromClockwiseLoop( center, absoluteInset ) if euclidean.isLargeSameDirection( insetLoop, center, muchGreaterThanLayerInset ): if euclidean.isPathInsideLoop( loop, insetLoop ) == isInInsetDirection: if inset > 0.0: insetLoop.reverse() insetLoops.append( insetLoop ) return insetLoops
def addPathBeforeEnd(self, aroundBetweenPath, location, loop): "Add the path before the end of the loop." halfFillInset = 0.5 * self.fillInset if self.arrivalInsetFollowDistance < halfFillInset: return locationComplex = location.dropAxis(2) closestInset = None closestDistanceIndex = euclidean.DistanceIndex(999999999999999999.0, -1) loop = euclidean.getAwayPoints(loop, self.extrusionWidth) circleNodes = intercircle.getCircleNodesFromLoop(loop, self.fillInset) centers = [] centers = intercircle.getCentersFromCircleNodes(circleNodes) for center in centers: inset = intercircle.getInsetFromClockwiseLoop( center, halfFillInset) if euclidean.isLargeSameDirection(inset, center, self.fillInset): if euclidean.isPathInsideLoop( loop, inset) == euclidean.isWiddershins(loop): distanceIndex = euclidean.getNearestDistanceIndex( locationComplex, inset) if distanceIndex.distance < closestDistanceIndex.distance: closestInset = inset closestDistanceIndex = distanceIndex if closestInset == None: return extrusionHalfWidth = 0.5 * self.extrusionWidth closestInset = euclidean.getLoopStartingNearest( extrusionHalfWidth, locationComplex, closestInset) if euclidean.getPolygonLength( closestInset) < 0.2 * self.arrivalInsetFollowDistance: return closestInset.append(closestInset[0]) closestInset = euclidean.getSimplifiedPath(closestInset, self.extrusionWidth) closestInset.reverse() pathBeforeArrival = euclidean.getClippedAtEndLoopPath( self.arrivalInsetFollowDistance, closestInset) pointBeforeArrival = pathBeforeArrival[-1] aroundBetweenPath.append(pointBeforeArrival) if self.arrivalInsetFollowDistance <= halfFillInset: return aroundBetweenPath += euclidean.getClippedAtEndLoopPath( halfFillInset, closestInset)[len(pathBeforeArrival) - 1:]
def getIsThreadWiddershins( self ): "Determine if the thread is widdershins." oldThreadLocation = self.oldLocation thread = None for lineIndex in xrange( self.lineIndex + 1, len( self.lines ) ): line = self.lines[ lineIndex ] splitLine = line.split() firstWord = gcodec.getFirstWord( splitLine ) if firstWord == 'G1': location = gcodec.getLocationFromSplitLine( oldThreadLocation, splitLine ) if thread != None: thread.append( location.dropAxis( 2 ) ) oldThreadLocation = location if firstWord == 'M101': thread = [ oldThreadLocation.dropAxis( 2 ) ] if firstWord == 'M103': if thread != None: return euclidean.isWiddershins( thread ) else: return True
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 getLoopsFromMesh( self, z ): "Get loops from a carve of a mesh." originalLoops = [] if self.isCorrectMesh: originalLoops = getLoopsFromCorrectMesh( self.edges, self.faces, self.vertices, z ) if len( originalLoops ) < 1: originalLoops = getLoopsFromUnprovenMesh( self.edges, self.faces, self.importRadius, self.vertices, z ) simplifiedLoops = [] for originalLoop in originalLoops: simplifiedLoops.append( euclidean.getSimplifiedLoop( originalLoop, self.importRadius ) ) loops = getLoopsInDescendingOrderOfArea( simplifiedLoops ) for loopIndex in xrange( len( loops ) ): loop = loops[ loopIndex ] leftPoint = euclidean.getLeftPoint( loop ) totalNumberOfIntersectionsToLeft = 0 for otherLoop in loops[ : loopIndex ] + loops[ loopIndex + 1 : ]: totalNumberOfIntersectionsToLeft += euclidean.getNumberOfIntersectionsToLeft( leftPoint, otherLoop ) loopIsWiddershins = euclidean.isWiddershins( loop ) isEven = totalNumberOfIntersectionsToLeft % 2 == 0 if isEven != loopIsWiddershins: loop.reverse() return loops
def getBetweens(self): "Set betweens for the layer." if self.layerZ in self.betweenTable: return self.betweenTable[self.layerZ] if self.layerZ not in self.layerTable: return [] halfFillInset = 0.5 * self.fillInset betweens = [] for boundaryLoop in self.layerTable[self.layerZ]: circleNodes = intercircle.getCircleNodesFromLoop( boundaryLoop, self.fillInset) centers = intercircle.getCentersFromCircleNodes(circleNodes) for center in centers: inset = intercircle.getSimplifiedInsetFromClockwiseLoop( center, halfFillInset) if euclidean.isLargeSameDirection(inset, center, self.fillInset): if euclidean.isPathInsideLoop( boundaryLoop, inset) == euclidean.isWiddershins(boundaryLoop): betweens.append(inset) self.betweenTable[self.layerZ] = betweens return betweens
def isLargeSameDirection( inset, loop, requiredSize ): "Determine if the inset is in the same direction as the loop and if the inset is as large as the required size." if euclidean.isWiddershins( inset ) != euclidean.isWiddershins( loop ): return False return isLarge( inset, requiredSize )
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 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 )