diff --git a/extensions/fablabchemnitz/contourscannerandtrimmer/contour_scanner_and_trimmer.py b/extensions/fablabchemnitz/contourscannerandtrimmer/contour_scanner_and_trimmer.py index 6003c436..24a79d66 100644 --- a/extensions/fablabchemnitz/contourscannerandtrimmer/contour_scanner_and_trimmer.py +++ b/extensions/fablabchemnitz/contourscannerandtrimmer/contour_scanner_and_trimmer.py @@ -83,11 +83,13 @@ class ContourScannerAndTrimmer(inkex.EffectExtension): for subpath in subPaths: replacedelement = copy.copy(element) oldId = replacedelement.get('id') - replacedelement.set('d', CubicSuperPath(subpath)) - replacedelement.set('id', oldId + str(idSuffix).zfill(5)) - parent.insert(idx, replacedelement) - idSuffix += 1 - breakelements.append(replacedelement) + csp = CubicSuperPath(subpath) + 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) + idSuffix += 1 + breakelements.append(replacedelement) parent.remove(element) for child in element.getchildren(): self.breakContours(child, breakelements) diff --git a/extensions/fablabchemnitz/create_links/create_links.py b/extensions/fablabchemnitz/create_links/create_links.py index f550a000..775d677a 100644 --- a/extensions/fablabchemnitz/create_links/create_links.py +++ b/extensions/fablabchemnitz/create_links/create_links.py @@ -80,11 +80,13 @@ class LinksCreator(inkex.EffectExtension): for subpath in subPaths: replacedelement = copy.copy(element) oldId = replacedelement.get('id') - replacedelement.set('d', CubicSuperPath(subpath)) - replacedelement.set('id', oldId + str(idSuffix).zfill(5)) - parent.insert(idx, replacedelement) - idSuffix += 1 - breakelements.append(replacedelement) + csp = CubicSuperPath(subpath) + 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) + idSuffix += 1 + breakelements.append(replacedelement) parent.remove(element) for child in element.getchildren(): self.breakContours(child, breakelements) @@ -298,25 +300,6 @@ class LinksCreator(inkex.EffectExtension): breakApartGroup.append(breakOutputelement) #self.msg(replacedelement.get('id')) #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: for element in self.svg.selection.values(): diff --git a/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py index 050368ae..9909120c 100644 --- a/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py +++ b/extensions/fablabchemnitz/purge_pointy_paths/purge_pointy_paths.py @@ -34,11 +34,11 @@ class PurgeInvalidPaths(inkex.EffectExtension): elif len(commandsCoords) == 2 and commandsCoords[0][1] == commandsCoords[1][1]: element.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 + # but the first and second coordinate are the same. It will render as point elif len(commandsCoords) == 2 and commandsCoords[-1][0] == 'Z': element.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 + # 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': element.delete() else: diff --git a/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.inx b/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.inx index 074c2fc4..d8366b70 100644 --- a/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.inx +++ b/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.inx @@ -2,9 +2,23 @@ Split And Break Bezier At t fablabchemnitz.de.split_and_break_bezier_at_t + + + + + + + + + + + + + + 0.5000 0.5000 - + path @@ -16,4 +30,4 @@ Applies independently for each sub path in selection. - + \ No newline at end of file diff --git a/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py b/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py index 87e85db0..2d6e475c 100644 --- a/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py +++ b/extensions/fablabchemnitz/split_and_break_bezier_at_t/split_and_break_bezier_at_t.py @@ -17,7 +17,7 @@ class SplitAndBreakBezierAtT(inkex.EffectExtension): idSuffix = 0 raw = element.path.to_arrays() 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: subPaths.append(raw[prev:i]) prev = i @@ -25,55 +25,76 @@ class SplitAndBreakBezierAtT(inkex.EffectExtension): for subpath in subPaths: replacedelement = copy.copy(element) oldId = replacedelement.get('id') - replacedelement.set('d', CubicSuperPath(subpath)) - replacedelement.set('id', oldId + str(idSuffix).zfill(5)) - parent.insert(idx, replacedelement) - idSuffix += 1 - breakelements.append(replacedelement) + csp = CubicSuperPath(subpath) + 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) + idSuffix += 1 + breakelements.append(replacedelement) parent.remove(element) for child in element.getchildren(): self.breakContours(child, breakelements) return breakelements 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) def effect(self): breakApartElements = None for element in self.svg.selection.filter(PathElement): breakApartElements = self.breakContours(element, breakApartElements) - for element in breakApartElements: - csp = element.path.to_superpath() - slengths, totalLength = csplength(csp) - length_at_target_t = self.options.target_t * totalLength - new = [] - lengthSum = 0 - segOfTOccurence = None - for seg in csp: - new.append([seg[0][:]]) - for i in range(1,len(seg)): - segLength = bezier.cspseglength(new[-1][-1], seg[i]) - lengthSum += segLength - current_t = lengthSum / totalLength - #insert a new breaking node in case we are at the desired t parameter - if current_t >= self.options.target_t: - if segOfTOccurence is None: - segOfTOccurence = i - t_dist = 1 - ((lengthSum - length_at_target_t) / segLength) - result = bezier.cspbezsplitatlength(new[-1][-1], seg[i], t_dist) - better_result = [[list(el) for el in elements] for elements in result] - new[-1][-1], nxt, seg[i] = better_result - new[-1].append(nxt[:]) - new[-1].append(seg[i]) - newpath = CubicSuperPath(new).to_path(curves_only=True).to_arrays() - #insert the splitting at the occurence (we add "m 0,0") to break the path - newpath.insert(segOfTOccurence + 1, ['m', [0, 0]]) - element.path = Path(newpath) - breakApartElements = self.breakContours(element) - - #print the breaking point coordinate - #for step, (x, y) in enumerate(breakApartElements[1].path.end_points): - # self.msg("x={},y={}".format(x, y)) - # break + + if breakApartElements is not None: + for element in breakApartElements: + csp = element.path.to_superpath() + 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 + 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 = [] + lengthSum = 0 + segOfTOccurence = None + for seg in csp: + new.append([seg[0][:]]) + for i in range(1,len(seg)): + segLength = bezier.cspseglength(new[-1][-1], seg[i]) + lengthSum += segLength + current_t = lengthSum / totalLength + #insert a new breaking node in case we are at the desired t parameter + if current_t >= self.options.target_t: + if segOfTOccurence is None: + segOfTOccurence = i + t_dist = 1 - ((lengthSum - length_at_target_t) / segLength) + result = bezier.cspbezsplitatlength(new[-1][-1], seg[i], t_dist) + better_result = [[list(el) for el in elements] for elements in result] + new[-1][-1], nxt, seg[i] = better_result + new[-1].append(nxt[:]) + new[-1].append(seg[i]) + newpath = CubicSuperPath(new).to_path(curves_only=True).to_arrays() + #insert the splitting at the occurence (we add "m 0,0") to break the path + newpath.insert(segOfTOccurence + 1, ['m', [0, 0]]) + element.path = Path(newpath) + breakAparts = self.breakContours(element) + + #print the breaking point coordinate + #for step, (x, y) in enumerate(breakAparts[1].path.end_points): + # self.msg("x={},y={}".format(x, y)) + # break + else: + inkex.utils.debug("Selection seems to be empty!") + return if __name__ == '__main__': SplitAndBreakBezierAtT().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/unwind_paths/unwind_paths.py b/extensions/fablabchemnitz/unwind_paths/unwind_paths.py index 04134448..85dfb564 100644 --- a/extensions/fablabchemnitz/unwind_paths/unwind_paths.py +++ b/extensions/fablabchemnitz/unwind_paths/unwind_paths.py @@ -70,11 +70,13 @@ class UnwindPaths(inkex.EffectExtension): for subpath in subPaths: replacedelement = copy.copy(element) oldId = replacedelement.get('id') - replacedelement.set('d', CubicSuperPath(subpath)) - replacedelement.set('id', oldId + str(idSuffix).zfill(5)) - parent.insert(idx, replacedelement) - idSuffix += 1 - breakelements.append(replacedelement) + csp = CubicSuperPath(subpath) + 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) + idSuffix += 1 + breakelements.append(replacedelement) parent.remove(element) else: breakelements.append(element)