1 """
2 Fills a layer using a line pattern.
3
4 Credits:
5 Original Author: Enrique Perez (http://skeinforge.com)
6 Contributors: Please see the documentation in Skeinforge
7 Modifed as SFACT: Ahmet Cem Turan (github.com/ahmetcemturan/SFACT)
8
9 License:
10 GNU Affero General Public License http://www.gnu.org/licenses/agpl.html
11 """
12
13 from config import config
14 from fabmetheus_utilities import archive, euclidean, intercircle
15 from fabmetheus_utilities.vector3 import Vector3
16 import logging
17 import math
18 import sys
19 from utilities import memory_tracker
20
22 '''Returns an instance of the strategy'''
23 return LineFillStrategy(slicedModel)
24
27
28 self.slicedModel = slicedModel
29
30 self.infillSolidity = config.getfloat('fill', 'infill.solidity.ratio')
31 self.infillWidthOverThickness = config.getfloat('fill', 'extrusion.lines.extra.spacer.scaler')
32 self.infillPerimeterOverlap = config.getfloat('fill', 'infill.overlap.over.perimeter.scaler')
33 self.extraShellsAlternatingSolidLayer = config.getint('fill', 'shells.alternating.solid')
34 self.extraShellsBase = config.getint('fill', 'shells.base')
35 self.extraShellsSparseLayer = config.getint('fill', 'shells.sparse')
36 self.solidSurfaceThickness = config.getint('fill', 'fully.filled.layers')
37 self.doubleSolidSurfaceThickness = self.solidSurfaceThickness + self.solidSurfaceThickness
38 self.startFromChoice = config.get('fill', 'extrusion.sequence.start.layer')
39 self.threadSequenceChoice = config.get('fill', 'extrusion.sequence.print.order')
40 self.threadSequence = self.threadSequenceChoice.split(",")
41 self.diaphragmPeriod = config.getint('fill', 'diaphragm.every.n.layers')
42 self.diaphragmThickness = config.getint('fill', 'diaphragm.thickness')
43 self.infillBeginRotation = math.radians(config.getfloat('fill', 'infill.rotation.begin'))
44 self.infillBeginRotationRepeat = config.getint('fill', 'infill.rotation.repeat')
45 self.infillOddLayerExtraRotation = math.radians(config.getfloat('fill', 'infill.rotation.odd.layer'))
46 self.bridgeWidthMultiplier = config.getfloat('inset', 'bridge.width.multiplier.ratio')
47 self.extrusionWidth = config.getfloat('carve', 'extrusion.width')
48 self.infillWidth = self.extrusionWidth * self.infillWidthOverThickness * (0.7853)
49 self.betweenWidth = self.extrusionWidth * self.infillWidthOverThickness * (0.7853)
50 self.previousExtraShells = -1
51 self.oldOrderedLocation = None
52
53 - def fill(self, layer):
54 'Add fill to the carve layer.'
55 layerIndex = layer.index
56 alreadyFilledArounds = []
57 pixelTable = {}
58 arounds = []
59 betweenWidth = self.extrusionWidth / 1.7594801994
60 self.layerExtrusionWidth = self.infillWidth
61 layerFillInset = self.infillWidth
62
63 layerRotation = self.getLayerRotation(layerIndex, layer)
64 reverseRotation = complex(layerRotation.real, -layerRotation.imag)
65 surroundingCarves = []
66 layerRemainder = layerIndex % self.diaphragmPeriod
67 extraShells = self.extraShellsSparseLayer
68
69 if layerRemainder >= self.diaphragmThickness and layer.bridgeRotation == None:
70 for surroundingIndex in xrange(1, self.solidSurfaceThickness + 1):
71 self.addRotatedCarve(layerIndex, -surroundingIndex, reverseRotation, surroundingCarves)
72 self.addRotatedCarve(layerIndex, surroundingIndex, reverseRotation, surroundingCarves)
73
74 if len(surroundingCarves) < self.doubleSolidSurfaceThickness:
75 extraShells = self.extraShellsAlternatingSolidLayer
76 if self.previousExtraShells != self.extraShellsBase:
77 extraShells = self.extraShellsBase
78
79 if layer.bridgeRotation != None:
80 extraShells = 0
81 betweenWidth *= self.bridgeWidthMultiplier
82 self.layerExtrusionWidth *= self.bridgeWidthMultiplier
83 layerFillInset *= self.bridgeWidthMultiplier
84
85 aroundInset = 0.25 * self.layerExtrusionWidth
86 aroundWidth = 0.25 * self.layerExtrusionWidth
87 self.previousExtraShells = extraShells
88 gridPointInsetX = 0.5 * layerFillInset
89 doubleExtrusionWidth = 2.0 * self.layerExtrusionWidth
90 endpoints = []
91 infillPaths = []
92 layerInfillSolidity = self.infillSolidity
93
94 self.isDoubleJunction = True
95 self.isJunctionWide = True
96 rotatedLoops = []
97
98 nestedRings = layer.nestedRings
99
100 createFillForSurroundings(nestedRings, betweenWidth, False)
101
102 for extraShellIndex in xrange(extraShells):
103 createFillForSurroundings(nestedRings, self.layerExtrusionWidth, True)
104
105 fillLoops = euclidean.getFillOfSurroundings(nestedRings, None)
106
107 slightlyGreaterThanFill = 1.001 * layerFillInset
108
109 for loop in fillLoops:
110 alreadyFilledLoop = []
111 alreadyFilledArounds.append(alreadyFilledLoop)
112 planeRotatedPerimeter = euclidean.getPointsRoundZAxis(reverseRotation, loop)
113 rotatedLoops.append(planeRotatedPerimeter)
114 centers = intercircle.getCentersFromLoop(planeRotatedPerimeter, slightlyGreaterThanFill)
115 euclidean.addLoopToPixelTable(planeRotatedPerimeter, pixelTable, aroundWidth)
116 for center in centers:
117 alreadyFilledInset = intercircle.getSimplifiedInsetFromClockwiseLoop(center, layerFillInset)
118 if intercircle.isLargeSameDirection(alreadyFilledInset, center, layerFillInset):
119 alreadyFilledLoop.append(alreadyFilledInset)
120 around = intercircle.getSimplifiedInsetFromClockwiseLoop(center, aroundInset)
121 if euclidean.isPathInsideLoop(planeRotatedPerimeter, around) == euclidean.isWiddershins(planeRotatedPerimeter):
122 around.reverse()
123 arounds.append(around)
124 euclidean.addLoopToPixelTable(around, pixelTable, aroundWidth)
125
126 if len(arounds) < 1:
127 self.addThreadsBridgeLayer(layerIndex, nestedRings, layer)
128 return
129
130 back = euclidean.getBackOfLoops(arounds)
131 front = euclidean.getFrontOfLoops(arounds)
132 front = math.ceil(front / self.layerExtrusionWidth) * self.layerExtrusionWidth
133 fillWidth = back - front
134 numberOfLines = int(math.ceil(fillWidth / self.layerExtrusionWidth))
135 self.frontOverWidth = 0.0
136 self.horizontalSegmentLists = euclidean.getHorizontalSegmentListsFromLoopLists(alreadyFilledArounds, front, numberOfLines, rotatedLoops, self.layerExtrusionWidth)
137 self.surroundingXIntersectionLists = []
138 self.yList = []
139 removedEndpoints = []
140
141 if len(surroundingCarves) >= self.doubleSolidSurfaceThickness:
142 xIntersectionIndexLists = []
143 self.frontOverWidth = euclidean.getFrontOverWidthAddXListYList(front, surroundingCarves, numberOfLines, xIntersectionIndexLists, self.layerExtrusionWidth, self.yList)
144 for fillLine in xrange(len(self.horizontalSegmentLists)):
145 xIntersectionIndexList = xIntersectionIndexLists[fillLine]
146 surroundingXIntersections = euclidean.getIntersectionOfXIntersectionIndexes(self.doubleSolidSurfaceThickness, xIntersectionIndexList)
147 self.surroundingXIntersectionLists.append(surroundingXIntersections)
148 addSparseEndpoints(doubleExtrusionWidth, endpoints, fillLine, self.horizontalSegmentLists, layerInfillSolidity, removedEndpoints, self.solidSurfaceThickness, surroundingXIntersections)
149 else:
150 for fillLine in xrange(len(self.horizontalSegmentLists)):
151 addSparseEndpoints(doubleExtrusionWidth, endpoints, fillLine, self.horizontalSegmentLists, layerInfillSolidity, removedEndpoints, self.solidSurfaceThickness, None)
152
153 paths = euclidean.getPathsFromEndpoints(endpoints, 5.0 * self.layerExtrusionWidth, pixelTable, aroundWidth)
154
155 oldRemovedEndpointLength = len(removedEndpoints) + 1
156
157 while oldRemovedEndpointLength - len(removedEndpoints) > 0:
158 oldRemovedEndpointLength = len(removedEndpoints)
159 removeEndpoints(pixelTable, self.layerExtrusionWidth, paths, removedEndpoints, aroundWidth)
160
161 paths = euclidean.getConnectedPaths(paths, pixelTable, aroundWidth)
162
163 for path in paths:
164 addPathToInfillPaths(self.layerExtrusionWidth, infillPaths, path, layerRotation)
165
166 for nestedRing in nestedRings:
167 nestedRing.transferPaths(infillPaths)
168
169 self.addThreadsBridgeLayer(layerIndex, nestedRings, layer)
170
171 - def addRotatedCarve(self, currentLayer, layerDelta, reverseRotation, surroundingCarves):
172 'Add a rotated carve to the surrounding carves.'
173 layerIndex = currentLayer + layerDelta
174 if layerIndex < 0 or layerIndex >= len(self.slicedModel.layers):
175 return
176
177 layer = self.slicedModel.layers.values()[layerIndex]
178
179 nestedRings = layer.nestedRings
180 rotatedCarve = []
181 for nestedRing in nestedRings:
182 planeRotatedLoop = euclidean.getPointsRoundZAxis(reverseRotation, nestedRing.getXYBoundaries())
183 rotatedCarve.append(planeRotatedLoop)
184 outsetRadius = float(abs(layerDelta)) * self.extrusionWidth
185 rotatedCarve = intercircle.getInsetSeparateLoopsFromLoops(-outsetRadius, rotatedCarve)
186 surroundingCarves.append(rotatedCarve)
187
189 'Add the threads, add the bridge end & the layer end tag.'
190 if self.oldOrderedLocation == None or self.startFromChoice == "LowerLeft":
191 self.oldOrderedLocation = getLowerLeftCorner(nestedRings)
192 extrusionHalfWidth = 0.5 * self.layerExtrusionWidth
193 threadSequence = self.threadSequence
194 if layerIndex < 1:
195 threadSequence = ['perimeter', 'loops', 'infill']
196
197 for nestedRing in nestedRings:
198 nestedRing.addToThreads(extrusionHalfWidth, self.oldOrderedLocation, threadSequence)
199
201 'Get the layer rotation.'
202 rotation = rotatedLayer.bridgeRotation
203 if rotation != None:
204 return rotation
205 infillOddLayerRotationMultiplier = float(layerIndex % (self.infillBeginRotationRepeat + 1) == self.infillBeginRotationRepeat)
206 layerAngle = self.infillBeginRotation + infillOddLayerRotationMultiplier * self.infillOddLayerExtraRotation
207 return euclidean.getWiddershinsUnitPolar(layerAngle)
208
216
217 -def addPointOnPath(path, pathIndex, pixelTable, point, pointIndex, width):
218 'Add a point to a path and the pixel table.'
219 pointIndexMinusOne = pointIndex - 1
220 if pointIndex < len(path) and pointIndexMinusOne >= 0:
221 segmentTable = {}
222 begin = path[ pointIndexMinusOne ]
223 end = path[pointIndex]
224 euclidean.addValueSegmentToPixelTable(begin, end, segmentTable, pathIndex, width)
225 euclidean.removePixelTableFromPixelTable(segmentTable, pixelTable)
226 if pointIndexMinusOne >= 0:
227 begin = path[ pointIndexMinusOne ]
228 euclidean.addValueSegmentToPixelTable(begin, point, pixelTable, pathIndex, width)
229 if pointIndex < len(path):
230 end = path[pointIndex]
231 euclidean.addValueSegmentToPixelTable(point, end, pixelTable, pathIndex, width)
232 path.insert(pointIndex, point)
233
235 'Add the closest point to a path, if the point added to a path is free.'
236 if isAddedPointOnPathFree(path, pixelTable, point, pointIndex, width):
237 addPointOnPath(path, pathIndex, pixelTable, point, pointIndex, width)
238
239 -def addSparseEndpoints(doubleExtrusionWidth, endpoints, fillLine, horizontalSegmentLists, infillSolidity, removedEndpoints, solidSurfaceThickness, surroundingXIntersections):
240 'Add sparse endpoints.'
241 horizontalEndpoints = horizontalSegmentLists[fillLine]
242 for segment in horizontalEndpoints:
243 addSparseEndpointsFromSegment(doubleExtrusionWidth, endpoints, fillLine, horizontalSegmentLists, infillSolidity, removedEndpoints, segment, solidSurfaceThickness, surroundingXIntersections)
244
245 -def addSparseEndpointsFromSegment(doubleExtrusionWidth, endpoints, fillLine, horizontalSegmentLists, infillSolidity, removedEndpoints, segment, solidSurfaceThickness, surroundingXIntersections):
246 'Add sparse endpoints from a segment.'
247 endpointFirstPoint = segment[0].point
248 endpointSecondPoint = segment[1].point
249 if surroundingXIntersections == None:
250 endpoints += segment
251 return
252 if infillSolidity > 0.0:
253 if fillLine < 1 or fillLine >= len(horizontalSegmentLists) - 1:
254 endpoints += segment
255 return
256 if int(round(round(fillLine * infillSolidity) / infillSolidity)) == fillLine:
257 endpoints += segment
258 return
259 if abs(endpointFirstPoint - endpointSecondPoint) < doubleExtrusionWidth:
260 endpoints += segment
261 return
262 if not isSegmentAround(horizontalSegmentLists[ fillLine - 1 ], segment):
263 endpoints += segment
264 return
265 if not isSegmentAround(horizontalSegmentLists[ fillLine + 1 ], segment):
266 endpoints += segment
267 return
268 if solidSurfaceThickness == 0:
269 removedEndpoints += segment
270 return
271 if isSegmentCompletelyInAnIntersection(segment, surroundingXIntersections):
272 removedEndpoints += segment
273 return
274 endpoints += segment
275
277 'Create extra fill loops.'
278 for innerNestedRing in nestedRing.innerNestedRings:
279 createFillForSurroundings(innerNestedRing.innerNestedRings, radius, shouldExtraLoopsBeAdded)
280
281 loopsToBeFilled = nestedRing.getLoopsToBeFilled()
282 allFillLoops = getExtraFillLoops(loopsToBeFilled , radius)
283
284 if len(allFillLoops) < 1:
285 return
286 if shouldExtraLoopsBeAdded:
287 nestedRing.extraLoops += allFillLoops
288 nestedRing.penultimateFillLoops = nestedRing.lastFillLoops
289 nestedRing.lastFillLoops = allFillLoops
290
292 'Create extra fill loops for surrounding loops.'
293 for nestedRing in nestedRings:
294 createExtraFillLoops(nestedRing, radius, shouldExtraLoopsBeAdded)
295
297 'Get the additional length added by inserting a point into a path.'
298 if pointIndex == 0:
299 return abs(point - path[0])
300 if pointIndex == len(path):
301 return abs(point - path[-1])
302 return abs(point - path[pointIndex - 1]) + abs(point - path[pointIndex]) - abs(path[pointIndex] - path[pointIndex - 1])
303
305 'Get extra loops between inside and outside loops. Extra perimeters'
306 greaterThanRadius = radius / 0.7853
307 extraFillLoops = []
308 centers = intercircle.getCentersFromPoints(intercircle.getPointsFromLoops(loops, greaterThanRadius), greaterThanRadius)
309 for center in centers:
310 inset = intercircle.getSimplifiedInsetFromClockwiseLoop(center, radius)
311 if intercircle.isLargeSameDirection(inset, center, radius):
312 if euclidean.getIsInFilledRegion(loops, euclidean.getLeftPoint(inset)):
313 inset.reverse()
314 extraFillLoops.append(inset)
315 return extraFillLoops
316
318 'Get the lower left corner from the nestedRings.'
319 lowerLeftCorner = Vector3()
320 lowestRealPlusImaginary = 987654321.0
321 for nestedRing in nestedRings:
322 for point in nestedRing.getXYBoundaries():
323 realPlusImaginary = point.real + point.imag
324 if realPlusImaginary < lowestRealPlusImaginary:
325 lowestRealPlusImaginary = realPlusImaginary
326 lowerLeftCorner.setToXYZ(point.real, point.imag, nestedRing.z)
327 return lowerLeftCorner
328
330 'Insert a point into a path, at the index at which the path would be shortest.'
331 if len(path) < 1:
332 return 0
333 shortestPointIndex = None
334 shortestAdditionalLength = 999999999987654321.0
335 for pointIndex in xrange(len(path) + 1):
336 additionalLength = getAdditionalLength(path, point, pointIndex)
337 if additionalLength < shortestAdditionalLength:
338 shortestAdditionalLength = additionalLength
339 shortestPointIndex = pointIndex
340 return shortestPointIndex
341
343 'Determine if the point added to a path is intersecting the pixel table or the path.'
344 if pointIndex > 0 and pointIndex < len(path):
345 if isSharpCorner((path[pointIndex - 1]), point, (path[pointIndex])):
346 return False
347 pointIndexMinusOne = pointIndex - 1
348 if pointIndexMinusOne >= 0:
349 maskTable = {}
350 begin = path[ pointIndexMinusOne ]
351 if pointIndex < len(path):
352 end = path[pointIndex]
353 euclidean.addValueSegmentToPixelTable(begin, end, maskTable, None, width)
354 segmentTable = {}
355 euclidean.addSegmentToPixelTable(point, begin, segmentTable, 0.0, 2.0, width)
356 if euclidean.isPixelTableIntersecting(pixelTable, segmentTable, maskTable):
357 return False
358 if isAddedPointOnPathIntersectingPath(begin, path, point, pointIndexMinusOne):
359 return False
360 if pointIndex < len(path):
361 maskTable = {}
362 begin = path[pointIndex]
363 if pointIndexMinusOne >= 0:
364 end = path[ pointIndexMinusOne ]
365 euclidean.addValueSegmentToPixelTable(begin, end, maskTable, None, width)
366 segmentTable = {}
367 euclidean.addSegmentToPixelTable(point, begin, segmentTable, 0.0, 2.0, width)
368 if euclidean.isPixelTableIntersecting(pixelTable, segmentTable, maskTable):
369 return False
370 if isAddedPointOnPathIntersectingPath(begin, path, point, pointIndex):
371 return False
372 return True
373
375 'Determine if the point added to a path is intersecting the path by checking line intersection.'
376 segment = point - begin
377 segmentLength = abs(segment)
378 if segmentLength <= 0.0:
379 return False
380 normalizedSegment = segment / segmentLength
381 segmentYMirror = complex(normalizedSegment.real, -normalizedSegment.imag)
382 pointRotated = segmentYMirror * point
383 beginRotated = segmentYMirror * begin
384 if euclidean.isXSegmentIntersectingPath(path[ max(0, pointIndex - 20) : pointIndex ], pointRotated.real, beginRotated.real, segmentYMirror, pointRotated.imag):
385 return True
386 return euclidean.isXSegmentIntersectingPath(path[ pointIndex + 1 : pointIndex + 21 ], pointRotated.real, beginRotated.real, segmentYMirror, pointRotated.imag)
387
389 'Add the closest removed endpoint to the path, with minimal twisting.'
390 closestDistanceSquared = 999999999987654321.0
391 closestPathIndex = None
392 for pathIndex in xrange(len(paths)):
393 path = paths[ pathIndex ]
394 for pointIndex in xrange(len(path)):
395 point = path[pointIndex]
396 distanceSquared = abs(point - removedEndpointPoint)
397 if distanceSquared < closestDistanceSquared:
398 closestDistanceSquared = distanceSquared
399 closestPathIndex = pathIndex
400 if closestPathIndex == None:
401 return
402 if closestDistanceSquared < 0.8 * layerExtrusionWidth ** 2 :
403 return
404 closestPath = paths[ closestPathIndex ]
405 closestPointIndex = getWithLeastLength(closestPath, removedEndpointPoint)
406 if isAddedPointOnPathFree(closestPath, pixelTable, removedEndpointPoint, closestPointIndex, width):
407 addPointOnPath(closestPath, closestPathIndex, pixelTable, removedEndpointPoint, closestPointIndex, width)
408 return True
409 return isSidePointAdded(pixelTable, closestPath, closestPathIndex, closestPointIndex, layerExtrusionWidth, removedEndpointPoint, width)
410
412 'Determine if there is another segment around.'
413 for aroundSegment in aroundSegments:
414 endpoint = aroundSegment[0]
415 if isSegmentInX(segment, endpoint.point.real, endpoint.otherEndpoint.point.real):
416 return True
417 return False
418
420 'Add sparse endpoints from a segment.'
421 for xIntersectionIndex in xrange(0, len(xIntersections), 2):
422 surroundingXFirst = xIntersections[ xIntersectionIndex ]
423 surroundingXSecond = xIntersections[ xIntersectionIndex + 1 ]
424 if euclidean.isSegmentCompletelyInX(segment, surroundingXFirst, surroundingXSecond):
425 return True
426 return False
427
429 'Determine if the segment overlaps within x.'
430 segmentFirstX = segment[0].point.real
431 segmentSecondX = segment[1].point.real
432 if min(segmentFirstX, segmentSecondX) > max(xFirst, xSecond):
433 return False
434 return max(segmentFirstX, segmentSecondX) > min(xFirst, xSecond)
435
437 'Determine if the three complex points form a sharp corner.'
438 centerBeginComplex = beginComplex - centerComplex
439 centerEndComplex = endComplex - centerComplex
440 centerBeginLength = abs(centerBeginComplex)
441 centerEndLength = abs(centerEndComplex)
442 if centerBeginLength <= 0.0 or centerEndLength <= 0.0:
443 return False
444 centerBeginComplex /= centerBeginLength
445 centerEndComplex /= centerEndLength
446 return euclidean.getDotProduct(centerBeginComplex, centerEndComplex) > 0.9
447
448 -def isSidePointAdded(pixelTable, closestPath, closestPathIndex, closestPointIndex, layerExtrusionWidth, removedEndpointPoint, width):
449 'Add side point along with the closest removed endpoint to the path, with minimal twisting.'
450 if closestPointIndex <= 0 or closestPointIndex >= len(closestPath):
451 return False
452 pointBegin = closestPath[ closestPointIndex - 1 ]
453 pointEnd = closestPath[ closestPointIndex ]
454 removedEndpointPoint = removedEndpointPoint
455 closest = pointBegin
456 farthest = pointEnd
457 removedMinusClosest = removedEndpointPoint - pointBegin
458 removedMinusClosestLength = abs(removedMinusClosest)
459 if removedMinusClosestLength <= 0.0:
460 return False
461 removedMinusOther = removedEndpointPoint - pointEnd
462 removedMinusOtherLength = abs(removedMinusOther)
463 if removedMinusOtherLength <= 0.0:
464 return False
465 insertPointAfter = None
466 insertPointBefore = None
467 if removedMinusOtherLength < removedMinusClosestLength:
468 closest = pointEnd
469 farthest = pointBegin
470 removedMinusClosest = removedMinusOther
471 removedMinusClosestLength = removedMinusOtherLength
472 insertPointBefore = removedEndpointPoint
473 else:
474 insertPointAfter = removedEndpointPoint
475 removedMinusClosestNormalized = removedMinusClosest / removedMinusClosestLength
476 perpendicular = removedMinusClosestNormalized * complex(0.0, layerExtrusionWidth)
477 sidePoint = removedEndpointPoint + perpendicular
478
479 sidePointOther = removedEndpointPoint - perpendicular
480 if abs(sidePoint - farthest) > abs(sidePointOther - farthest):
481 perpendicular = -perpendicular
482 sidePoint = sidePointOther
483 maskTable = {}
484 closestSegmentTable = {}
485 toPerpendicularTable = {}
486 euclidean.addValueSegmentToPixelTable(pointBegin, pointEnd, maskTable, None, width)
487 euclidean.addValueSegmentToPixelTable(closest, removedEndpointPoint, closestSegmentTable, None, width)
488 euclidean.addValueSegmentToPixelTable(sidePoint, farthest, toPerpendicularTable, None, width)
489 if euclidean.isPixelTableIntersecting(pixelTable, toPerpendicularTable, maskTable) or euclidean.isPixelTableIntersecting(closestSegmentTable, toPerpendicularTable, maskTable):
490 sidePoint = removedEndpointPoint - perpendicular
491 toPerpendicularTable = {}
492 euclidean.addValueSegmentToPixelTable(sidePoint, farthest, toPerpendicularTable, None, width)
493 if euclidean.isPixelTableIntersecting(pixelTable, toPerpendicularTable, maskTable) or euclidean.isPixelTableIntersecting(closestSegmentTable, toPerpendicularTable, maskTable):
494 return False
495 if insertPointBefore != None:
496 addPointOnPathIfFree(closestPath, closestPathIndex, pixelTable, insertPointBefore, closestPointIndex, width)
497 addPointOnPathIfFree(closestPath, closestPathIndex, pixelTable, sidePoint, closestPointIndex, width)
498 if insertPointAfter != None:
499 addPointOnPathIfFree(closestPath, closestPathIndex, pixelTable, insertPointAfter, closestPointIndex, width)
500 return True
501
502 -def removeEndpoints(pixelTable, layerExtrusionWidth, paths, removedEndpoints, aroundWidth):
503 'Remove endpoints which are added to the path.'
504 for removedEndpointIndex in xrange(len(removedEndpoints) - 1, -1, -1):
505 removedEndpoint = removedEndpoints[ removedEndpointIndex ]
506 removedEndpointPoint = removedEndpoint.point
507 if isPointAddedAroundClosest(pixelTable, layerExtrusionWidth, paths, removedEndpointPoint, aroundWidth):
508 removedEndpoints.remove(removedEndpoint)
509