fix several bugs in contour scanner and trimmer extension

This commit is contained in:
Mario Voigt 2021-06-22 00:09:11 +02:00
parent b347187ff9
commit 7f5069387d
2 changed files with 32 additions and 20 deletions

View File

@ -22,7 +22,7 @@ Extension for InkScape 1.0+
- maybe option: convert rel path to abs path - maybe option: convert rel path to abs path
replacedelement.path = replacedelement.path.to_absolute().to_superpath().to_path() replacedelement.path = replacedelement.path.to_absolute().to_superpath().to_path()
- maybe option: break apart while keeping relative/absolute commands (more complex and not sure if we have a great advantage having this) - maybe option: break apart while keeping relative/absolute commands (more complex and not sure if we have a great advantage having this)
- if calculation of trim lines fails (bentley ottmann) we could try to sort out the lines where slope is nearly identical and then we try again
- important to notice - important to notice
- this algorithm might be really slow. Reduce flattening quality to speed up - this algorithm might be really slow. Reduce flattening quality to speed up
@ -51,7 +51,7 @@ Extension for InkScape 1.0+
Author: Mario Voigt / FabLab Chemnitz Author: Mario Voigt / FabLab Chemnitz
Mail: mario.voigt@stadtfabrikanten.org Mail: mario.voigt@stadtfabrikanten.org
Date: 09.08.2020 (extension originally called "Contour Scanner") Date: 09.08.2020 (extension originally called "Contour Scanner")
Last patch: 11.06.2021 Last patch: 22.06.2021
License: GNU GPL v3 License: GNU GPL v3
''' '''
@ -73,8 +73,9 @@ if speedups.available:
speedups.enable() speedups.enable()
idPrefix = "subsplit" idPrefixSubSplit = "subsplit"
intersectedVerb = "-intersected-" idPrefixTrimming = "shapely"
intersectedVerb = "intersected"
class ContourScannerAndTrimmer(inkex.EffectExtension): class ContourScannerAndTrimmer(inkex.EffectExtension):
@ -252,10 +253,10 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
trimLineStyle = {'stroke': str(self.options.color_trimmed), 'fill': 'none', 'stroke-width': self.options.strokewidth} trimLineStyle = {'stroke': str(self.options.color_trimmed), 'fill': 'none', 'stroke-width': self.options.strokewidth}
linesWithSnappedIntersectionPoints = snap(ls, globalIntersectionPoints, self.options.snap_tolerance) linesWithSnappedIntersectionPoints = snap(ls, globalIntersectionPoints, self.options.snap_tolerance)
trimGroupId = 'shapely-' + subSplitLineArray[subSplitIndex].attrib['id'].split("_")[0] #split at "_" (_ from subSplitId) trimGroupParentId = subSplitLineArray[subSplitIndex].attrib['originalPathId']
trimGroupParentId = subSplitLineArray[subSplitIndex].attrib['id'].split(idPrefix+"-")[1].split("_")[0] trimGroupId = '{}-{}-{}'.format(idPrefixTrimming, idPrefixSubSplit, trimGroupParentId)
trimGroupParent = self.svg.getElementById(trimGroupParentId) trimGroupParent = self.svg.getElementById(trimGroupParentId)
trimGroupParentTransform = trimGroupParent.composed_transform() #trimGroupParentTransform = trimGroupParent.composed_transform()
trimGroup = self.find_group(trimGroupId) trimGroup = self.find_group(trimGroupId)
if trimGroup is None: if trimGroup is None:
trimGroup = trimGroupParent.getparent().add(inkex.Group(id=trimGroupId)) trimGroup = trimGroupParent.getparent().add(inkex.Group(id=trimGroupId))
@ -273,19 +274,19 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
trimLineId = "{}-{}".format(trimGroupId, subSplitIndex) trimLineId = "{}-{}".format(trimGroupId, subSplitIndex)
splitAt.append(trimGroupId) splitAt.append(trimGroupId)
if splitAt.count(trimGroupId) > 1: #we detected a lines with intersection on if splitAt.count(trimGroupId) > 1: #we detected a lines with intersection on
trimLineId = trimLineId + self.svg.get_unique_id(intersectedVerb) trimLineId = "{}-{}".format(trimLineId, self.svg.get_unique_id(intersectedVerb + "-"))
''' '''
so the previous lines was an intersection lines too. so we change the id to include the intersected verb so the previous lines was an intersection lines too. so we change the id to include the intersected verb
(left side and right side of cut) - note: updating element (left side and right side of cut) - note: updating element
id sometimes seems not to work if the id was used before in Inkscape id sometimes seems not to work if the id was used before in Inkscape
''' '''
prevLine.attrib['id'] = trimGroupId + "-" + str(subSplitIndex) + self.svg.get_unique_id(intersectedVerb) prevLine.attrib['id'] = "{}-{}".format(trimGroupId, str(subSplitIndex) + "-" + self.svg.get_unique_id(intersectedVerb + "-"))
prevLine.attrib['intersected'] = 'True' #some dirty flag we need prevLine.attrib['intersected'] = 'True' #some dirty flag we need
prevLine = trimLine = inkex.PathElement(id=trimLineId) prevLine = trimLine = inkex.PathElement(id=trimLineId)
x, y = trimLines[j].coords.xy x, y = trimLines[j].coords.xy
trimLine.path = [['M', [x[0],y[0]]], ['L', [x[1],y[1]]]] trimLine.path = [['M', [x[0],y[0]]], ['L', [x[1],y[1]]]]
if trimGroupParentTransform is not None: #if trimGroupParentTransform is not None:
trimLine.path = trimLine.path.transform(-trimGroupParentTransform) # trimLine.path = trimLine.path.transform(-trimGroupParentTransform)
if self.options.apply_style_to_trimmed is False: if self.options.apply_style_to_trimmed is False:
trimLine.style = trimLineStyle trimLine.style = trimLineStyle
else: else:
@ -301,15 +302,16 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
allTrimGroups = allTrimGroups[::-1] allTrimGroups = allTrimGroups[::-1]
for trimGroup in allTrimGroups: for trimGroup in allTrimGroups:
for element in trimGroup: for element in trimGroup:
if element.path not in totalTrimPaths: path = element.path.transform(element.composed_transform())
totalTrimPaths.append(element.path) if path not in totalTrimPaths:
totalTrimPaths.append(path)
else: else:
if self.options.show_debug is True: if self.options.show_debug is True:
self.msg("Deleting {}".format(element.get('id'))) self.msg("Deleting path {}".format(element.get('id')))
element.delete() element.delete()
if len(trimGroup) == 0: if len(trimGroup) == 0:
if self.options.show_debug is True: if self.options.show_debug is True:
self.msg("Deleting {}".format(trimGroup.get('id'))) self.msg("Deleting group {}".format(trimGroup.get('id')))
trimGroup.delete() trimGroup.delete()
@ -564,7 +566,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
continue #skip this loop iteration continue #skip this loop iteration
if so.draw_subsplit is True: if so.draw_subsplit is True:
subSplitLineGroup = pathElement.getparent().add(inkex.Group(id="{}-{}".format(idPrefix, originalPathId))) subSplitLineGroup = pathElement.getparent().add(inkex.Group(id="{}-{}".format(idPrefixSubSplit, originalPathId)))
#get all sub paths for the path of the element #get all sub paths for the path of the element
subPaths, prev = [], 0 subPaths, prev = [], 0
@ -601,7 +603,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
for i in range(len(segs) - 1): #we could do the same routine to build up polylines using "for x, y in node.path.end_points". See "number nodes" extension for i in range(len(segs) - 1): #we could do the same routine to build up polylines using "for x, y in node.path.end_points". See "number nodes" extension
x1, y1, x2, y2 = self.line_from_segments(segs, i, so.decimals) x1, y1, x2, y2 = self.line_from_segments(segs, i, so.decimals)
#self.msg("(y1 = {},y2 = {},x1 = {},x2 = {})".format(x1, y1, x2, y2)) #self.msg("(y1 = {},y2 = {},x1 = {},x2 = {})".format(x1, y1, x2, y2))
subSplitId = "{}-{}_{}".format(idPrefix, originalPathId, i) subSplitId = "{}-{}-{}".format(idPrefixSubSplit, originalPathId, i)
line = inkex.PathElement(id=subSplitId) line = inkex.PathElement(id=subSplitId)
#apply line path with composed negative transform from parent element #apply line path with composed negative transform from parent element
line.path = [['M', [x1, y1]], ['L', [x2, y2]]] line.path = [['M', [x1, y1]], ['L', [x2, y2]]]
@ -721,8 +723,18 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
allSubSplitLineStrings = [] allSubSplitLineStrings = []
for subSplitLine in subSplitLineArray: for subSplitLine in subSplitLineArray:
csp = subSplitLine.path.to_arrays() csp = subSplitLine.path.to_arrays()
allSubSplitLineStrings.append([(csp[0][1][0], csp[0][1][1]), (csp[1][1][0], csp[1][1][1])]) lineString = [(csp[0][1][0], csp[0][1][1]), (csp[1][1][0], csp[1][1][1])]
if so.remove_duplicates is True:
if lineString not in allSubSplitLineStrings:
allSubSplitLineStrings.append(lineString)
else:
if so.show_debug is True:
self.msg("line {} already in sub split line collection. Dropping ...".format(lineString))
else: #if false we append all segments without filtering duplicate ones
allSubSplitLineStrings.append(lineString)
# Very small step sizes over near-vertical lines can cause errors. We hide exceptions with try-catch, thus we disabled the debugging in poly_point_isect:
# by setting USE_DEBUG = False (True was default setting)
globalIntersectionPoints = MultiPoint(isect_segments(allSubSplitLineStrings, validate=True)) globalIntersectionPoints = MultiPoint(isect_segments(allSubSplitLineStrings, validate=True))
if so.show_debug is True: if so.show_debug is True:

View File

@ -26,7 +26,7 @@ __all__ = (
# their end points form the intersection point. # their end points form the intersection point.
USE_IGNORE_SEGMENT_ENDINGS = True USE_IGNORE_SEGMENT_ENDINGS = True
USE_DEBUG = True USE_DEBUG = False
USE_VERBOSE = False USE_VERBOSE = False