several enhancements for path handlings when breaking apart
This commit is contained in:
parent
5ebc7db481
commit
abdc94eb00
@ -83,8 +83,10 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
|||||||
for subpath in subPaths:
|
for subpath in subPaths:
|
||||||
replacedelement = copy.copy(element)
|
replacedelement = copy.copy(element)
|
||||||
oldId = replacedelement.get('id')
|
oldId = replacedelement.get('id')
|
||||||
replacedelement.set('d', CubicSuperPath(subpath))
|
csp = CubicSuperPath(subpath)
|
||||||
replacedelement.set('id', oldId + str(idSuffix).zfill(5))
|
if len(subpath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
|
||||||
|
replacedelement.set('d', csp)
|
||||||
|
replacedelement.set('id', oldId + str(idSuffix))
|
||||||
parent.insert(idx, replacedelement)
|
parent.insert(idx, replacedelement)
|
||||||
idSuffix += 1
|
idSuffix += 1
|
||||||
breakelements.append(replacedelement)
|
breakelements.append(replacedelement)
|
||||||
|
@ -80,8 +80,10 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
for subpath in subPaths:
|
for subpath in subPaths:
|
||||||
replacedelement = copy.copy(element)
|
replacedelement = copy.copy(element)
|
||||||
oldId = replacedelement.get('id')
|
oldId = replacedelement.get('id')
|
||||||
replacedelement.set('d', CubicSuperPath(subpath))
|
csp = CubicSuperPath(subpath)
|
||||||
replacedelement.set('id', oldId + str(idSuffix).zfill(5))
|
if len(subpath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
|
||||||
|
replacedelement.set('d', csp)
|
||||||
|
replacedelement.set('id', oldId + str(idSuffix))
|
||||||
parent.insert(idx, replacedelement)
|
parent.insert(idx, replacedelement)
|
||||||
idSuffix += 1
|
idSuffix += 1
|
||||||
breakelements.append(replacedelement)
|
breakelements.append(replacedelement)
|
||||||
@ -299,25 +301,6 @@ class LinksCreator(inkex.EffectExtension):
|
|||||||
#self.msg(replacedelement.get('id'))
|
#self.msg(replacedelement.get('id'))
|
||||||
#self.svg.selection.set(replacedelement.get('id')) #update selection to split paths segments (does not work, so commented out)
|
#self.svg.selection.set(replacedelement.get('id')) #update selection to split paths segments (does not work, so commented out)
|
||||||
|
|
||||||
#cleanup useless points
|
|
||||||
p = breakOutputelement.path
|
|
||||||
commandsCoords = p.to_arrays()
|
|
||||||
# "m 45.250809,91.692739" - this path contains onyl one command - a single point
|
|
||||||
if len(commandsCoords) == 1:
|
|
||||||
breakOutputelement.delete()
|
|
||||||
# "m 45.250809,91.692739 z" - this path contains two commands, but only one coordinate.
|
|
||||||
# It's a single point, the path is closed by a Z command
|
|
||||||
elif len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]:
|
|
||||||
breakOutputelement.delete()
|
|
||||||
# "m 45.250809,91.692739 l 45.250809,91.692739" - this path contains two commands,
|
|
||||||
# but the first and second coordinate are the same. It will render als point
|
|
||||||
elif len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z':
|
|
||||||
breakOutputelement.delete()
|
|
||||||
# "m 45.250809,91.692739 l 45.250809,91.692739 z" - this path contains three commands,
|
|
||||||
# but the first and second coordinate are the same. It will render als point, the path is closed by a Z command
|
|
||||||
elif len(commandsCoords) == 3 and commandsCoords[0][1] == commandsCoords[1][1] and commandsCoords[2][1] == 'Z':
|
|
||||||
breakOutputelement.delete()
|
|
||||||
|
|
||||||
if len(self.svg.selected) > 0:
|
if len(self.svg.selected) > 0:
|
||||||
for element in self.svg.selection.values():
|
for element in self.svg.selection.values():
|
||||||
#at first we need to break down combined elements to single path, otherwise dasharray cannot properly be applied
|
#at first we need to break down combined elements to single path, otherwise dasharray cannot properly be applied
|
||||||
|
@ -34,11 +34,11 @@ class PurgeInvalidPaths(inkex.EffectExtension):
|
|||||||
elif len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]:
|
elif len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]:
|
||||||
element.delete()
|
element.delete()
|
||||||
# "m 45.250809,91.692739 l 45.250809,91.692739" - this path contains two commands,
|
# "m 45.250809,91.692739 l 45.250809,91.692739" - this path contains two commands,
|
||||||
# but the first and second coordinate are the same. It will render als point
|
# but the first and second coordinate are the same. It will render as point
|
||||||
elif len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z':
|
elif len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z':
|
||||||
element.delete()
|
element.delete()
|
||||||
# "m 45.250809,91.692739 l 45.250809,91.692739 z" - this path contains three commands,
|
# "m 45.250809,91.692739 l 45.250809,91.692739 z" - this path contains three commands,
|
||||||
# but the first and second coordinate are the same. It will render als point, the path is closed by a Z command
|
# but the first and second coordinate are the same. It will render as point, the path is closed by a Z command
|
||||||
elif len(commandsCoords) == 3 and commandsCoords[0][1] == commandsCoords[1][1] and commandsCoords[2][1] == 'Z':
|
elif len(commandsCoords) == 3 and commandsCoords[0][1] == commandsCoords[1][1] and commandsCoords[2][1] == 'Z':
|
||||||
element.delete()
|
element.delete()
|
||||||
else:
|
else:
|
||||||
|
@ -2,9 +2,23 @@
|
|||||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
<name>Split And Break Bezier At t</name>
|
<name>Split And Break Bezier At t</name>
|
||||||
<id>fablabchemnitz.de.split_and_break_bezier_at_t</id>
|
<id>fablabchemnitz.de.split_and_break_bezier_at_t</id>
|
||||||
|
<param name="split_select" type="optiongroup" appearance="radio" gui-text="Split by" gui-description="Choose to split by length or percentage">
|
||||||
|
<option value="length">length</option>
|
||||||
|
<option value="t">percentage (t)</option>
|
||||||
|
</param>
|
||||||
|
<param name="unit" type="optiongroup" appearance="combo" gui-text="Units">
|
||||||
|
<option value="mm">mm</option>
|
||||||
|
<option value="cm">cm</option>
|
||||||
|
<option value="m">m</option>
|
||||||
|
<option value="in">in</option>
|
||||||
|
<option value="pt">pt</option>
|
||||||
|
<option value="px">px</option>
|
||||||
|
<option value="pc">pc</option>
|
||||||
|
</param>
|
||||||
|
<param name="target_length" type="float" min="0.0" precision="4" gui-text="Length">0.5000</param>
|
||||||
<param name="target_t" type="float" min="0.0000" max="1.0000" precision="4" appearance="full" gui-text="t">0.5000</param>
|
<param name="target_t" type="float" min="0.0000" max="1.0000" precision="4" appearance="full" gui-text="t">0.5000</param>
|
||||||
<label xml:space="preserve">Splits a path at value t=0..1 (t=0.5 means 50%)
|
<label xml:space="preserve">Splits a path at value t=0..1 (t=0.5 means 50%) or at a defined length with unit.
|
||||||
Applies independently for each sub path in selection.</label>
|
Applies independently for each sub path in selection. Use 'Path > Reverse' to change the cutting direction.</label>
|
||||||
<effect>
|
<effect>
|
||||||
<object-type>path</object-type>
|
<object-type>path</object-type>
|
||||||
<effects-menu>
|
<effects-menu>
|
||||||
|
@ -17,7 +17,7 @@ class SplitAndBreakBezierAtT(inkex.EffectExtension):
|
|||||||
idSuffix = 0
|
idSuffix = 0
|
||||||
raw = element.path.to_arrays()
|
raw = element.path.to_arrays()
|
||||||
subPaths, prev = [], 0
|
subPaths, prev = [], 0
|
||||||
for i in range(len(raw)): # Breaks compound paths into simple paths
|
for i in range(len(raw)): #breaks compound paths into sub paths
|
||||||
if raw[i][0] == 'M' and i != 0:
|
if raw[i][0] == 'M' and i != 0:
|
||||||
subPaths.append(raw[prev:i])
|
subPaths.append(raw[prev:i])
|
||||||
prev = i
|
prev = i
|
||||||
@ -25,8 +25,10 @@ class SplitAndBreakBezierAtT(inkex.EffectExtension):
|
|||||||
for subpath in subPaths:
|
for subpath in subPaths:
|
||||||
replacedelement = copy.copy(element)
|
replacedelement = copy.copy(element)
|
||||||
oldId = replacedelement.get('id')
|
oldId = replacedelement.get('id')
|
||||||
replacedelement.set('d', CubicSuperPath(subpath))
|
csp = CubicSuperPath(subpath)
|
||||||
replacedelement.set('id', oldId + str(idSuffix).zfill(5))
|
if len(subpath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
|
||||||
|
replacedelement.set('d', csp)
|
||||||
|
replacedelement.set('id', oldId + str(idSuffix))
|
||||||
parent.insert(idx, replacedelement)
|
parent.insert(idx, replacedelement)
|
||||||
idSuffix += 1
|
idSuffix += 1
|
||||||
breakelements.append(replacedelement)
|
breakelements.append(replacedelement)
|
||||||
@ -36,16 +38,32 @@ class SplitAndBreakBezierAtT(inkex.EffectExtension):
|
|||||||
return breakelements
|
return breakelements
|
||||||
|
|
||||||
def add_arguments(self, pars):
|
def add_arguments(self, pars):
|
||||||
|
pars.add_argument('--split_select', default="t")
|
||||||
|
pars.add_argument('--unit', default="mm")
|
||||||
|
pars.add_argument('--target_length', type=float, default=0.5)
|
||||||
pars.add_argument('--target_t', type=float, default=0.5)
|
pars.add_argument('--target_t', type=float, default=0.5)
|
||||||
|
|
||||||
def effect(self):
|
def effect(self):
|
||||||
breakApartElements = None
|
breakApartElements = None
|
||||||
for element in self.svg.selection.filter(PathElement):
|
for element in self.svg.selection.filter(PathElement):
|
||||||
breakApartElements = self.breakContours(element, breakApartElements)
|
breakApartElements = self.breakContours(element, breakApartElements)
|
||||||
|
|
||||||
|
if breakApartElements is not None:
|
||||||
for element in breakApartElements:
|
for element in breakApartElements:
|
||||||
csp = element.path.to_superpath()
|
csp = element.path.to_superpath()
|
||||||
slengths, totalLength = csplength(csp)
|
slengths, totalLength = csplength(csp)
|
||||||
|
if totalLength == 0:
|
||||||
|
inkex.utils.debug("{} is invalid: zero length (path d='{}'). Skipping ...".format(element.get('id'), element.path))
|
||||||
|
continue
|
||||||
|
if self.options.split_select == "t":
|
||||||
length_at_target_t = self.options.target_t * totalLength
|
length_at_target_t = self.options.target_t * totalLength
|
||||||
|
elif self.options.split_select == "length":
|
||||||
|
length_at_target_t = self.svg.unittouu(str(self.options.target_length) + self.options.unit)
|
||||||
|
if length_at_target_t > totalLength:
|
||||||
|
inkex.utils.debug("Entered length is larger than length of {}. Skipping ...".format(element.get('id')))
|
||||||
|
continue
|
||||||
|
self.options.target_t = length_at_target_t / totalLength #override
|
||||||
|
|
||||||
new = []
|
new = []
|
||||||
lengthSum = 0
|
lengthSum = 0
|
||||||
segOfTOccurence = None
|
segOfTOccurence = None
|
||||||
@ -69,11 +87,14 @@ class SplitAndBreakBezierAtT(inkex.EffectExtension):
|
|||||||
#insert the splitting at the occurence (we add "m 0,0") to break the path
|
#insert the splitting at the occurence (we add "m 0,0") to break the path
|
||||||
newpath.insert(segOfTOccurence + 1, ['m', [0, 0]])
|
newpath.insert(segOfTOccurence + 1, ['m', [0, 0]])
|
||||||
element.path = Path(newpath)
|
element.path = Path(newpath)
|
||||||
breakApartElements = self.breakContours(element)
|
breakAparts = self.breakContours(element)
|
||||||
|
|
||||||
#print the breaking point coordinate
|
#print the breaking point coordinate
|
||||||
#for step, (x, y) in enumerate(breakApartElements[1].path.end_points):
|
#for step, (x, y) in enumerate(breakAparts[1].path.end_points):
|
||||||
# self.msg("x={},y={}".format(x, y))
|
# self.msg("x={},y={}".format(x, y))
|
||||||
# break
|
# break
|
||||||
|
else:
|
||||||
|
inkex.utils.debug("Selection seems to be empty!")
|
||||||
|
return
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
SplitAndBreakBezierAtT().run()
|
SplitAndBreakBezierAtT().run()
|
@ -70,8 +70,10 @@ class UnwindPaths(inkex.EffectExtension):
|
|||||||
for subpath in subPaths:
|
for subpath in subPaths:
|
||||||
replacedelement = copy.copy(element)
|
replacedelement = copy.copy(element)
|
||||||
oldId = replacedelement.get('id')
|
oldId = replacedelement.get('id')
|
||||||
replacedelement.set('d', CubicSuperPath(subpath))
|
csp = CubicSuperPath(subpath)
|
||||||
replacedelement.set('id', oldId + str(idSuffix).zfill(5))
|
if len(subpath) > 1 and csp[0][0] != csp[0][1]: #avoids pointy paths like M "31.4794 57.6024 Z"
|
||||||
|
replacedelement.set('d', csp)
|
||||||
|
replacedelement.set('id', oldId + str(idSuffix))
|
||||||
parent.insert(idx, replacedelement)
|
parent.insert(idx, replacedelement)
|
||||||
idSuffix += 1
|
idSuffix += 1
|
||||||
breakelements.append(replacedelement)
|
breakelements.append(replacedelement)
|
||||||
|
Reference in New Issue
Block a user