From f98e9719ab54413b6df6502863d86dc8f03a4718 Mon Sep 17 00:00:00 2001 From: Mario Voigt Date: Tue, 2 Nov 2021 19:28:26 +0100 Subject: [PATCH] more features for filter by extension, add some outside canvas checker to lasercheck --- .../filter_by_length_area.inx | 15 +++-- .../filter_by_length_area.py | 47 +++++++++++----- .../laser_check/laser_check.inx | 1 + .../fablabchemnitz/laser_check/laser_check.py | 55 ++++++++++++++++++- 4 files changed, 97 insertions(+), 21 deletions(-) diff --git a/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.inx b/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.inx index 7d7d39a2..e0031021 100644 --- a/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.inx +++ b/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.inx @@ -3,6 +3,7 @@ Filter By Length/Area fablabchemnitz.de.filter_by_length_area + false @@ -11,14 +12,20 @@ + + 10.000 + false - 1.000 + 1.000 + 2 false - 10000000.000 - - + 10000000.000 + 10000000 + + + diff --git a/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py b/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py index 084c4df7..2056259e 100644 --- a/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py +++ b/extensions/fablabchemnitz/filter_by_length_area/filter_by_length_area.py @@ -18,23 +18,27 @@ from inkex.bezier import csplength, csparea class FilterByLengthArea(inkex.EffectExtension): def add_arguments(self, pars): + pars.add_argument('--debug', type=inkex.Boolean, default=False) pars.add_argument('--unit') pars.add_argument('--min_filter_enable', type=inkex.Boolean, default=True, help='Enable filtering min.') pars.add_argument('--min_threshold', type=float, default=0.000, help='Remove paths with an threshold smaller than this value') pars.add_argument('--max_filter_enable', type=inkex.Boolean, default=False, help='Enable filtering max.') pars.add_argument('--max_threshold', type=float, default=10000000.000, help='Remove paths with an threshold bigger than this value') + pars.add_argument('--min_nodes', type=int, default=0, help='Min. nodes/') + pars.add_argument('--max_nodes', type=int, default=10000000, help='Max. nodes/') + pars.add_argument('--nodes_interval', type=float, default=10000000.000, help='Interval') pars.add_argument('--measure', default="length") def effect(self): - - if self.options.min_filter_enable is False and self.options.max_filter_enable is False: + so = self.options + if so.min_filter_enable is False and so.max_filter_enable is False: inkex.utils.debug("You need to enabled at least one filter rule!") return - self.options.min_threshold = self.svg.unittouu(str(self.options.min_threshold) + self.svg.unit) - self.options.max_threshold = self.svg.unittouu(str(self.options.max_threshold) + self.svg.unit) - unit_factor = 1.0 / self.svg.uutounit(1.0,self.options.unit) - if self.options.min_threshold == 0 or self.options.max_threshold == 0: + so.min_threshold = self.svg.unittouu(str(so.min_threshold) + self.svg.unit) + so.max_threshold = self.svg.unittouu(str(so.max_threshold) + self.svg.unit) + unit_factor = 1.0 / self.svg.uutounit(1.0, so.unit) + if so.min_threshold == 0 or so.max_threshold == 0: inkex.utils.debug("One or both tresholds are zero. Please adjust.") return @@ -47,21 +51,36 @@ class FilterByLengthArea(inkex.EffectExtension): try: csp = element.path.transform(element.composed_transform()).to_superpath() - if self.options.measure == "area": - area = -csparea(csp) #is returned as negative value. we need to invert with - - if self.options.min_filter_enable is True and area < (self.options.min_threshold * (unit_factor * unit_factor)): + if so.measure == "area": + area = -csparea(csp) #is returned as negative value. we need to invert with + if so.debug is True: + inkex.utils.debug("id={}, area={:0.3f}{}^2".format(element.get('id'), area, so.unit)) + if so.min_filter_enable is True and area < (so.min_threshold * (unit_factor * unit_factor)): element.delete() - if self.options.max_filter_enable is True and area >= (self.options.max_threshold * (unit_factor * unit_factor)): + if so.max_filter_enable is True and area >= (so.max_threshold * (unit_factor * unit_factor)): element.delete() - elif self.options.measure == "length": + elif so.measure == "length": slengths, stotal = csplength(csp) #get segment lengths and total length of path in document's internal unit - if self.options.min_filter_enable is True and stotal < (self.options.min_threshold * unit_factor): + if so.debug is True: + inkex.utils.debug("id={}, length={:0.3f}{}".format(element.get('id'), self.svg.uutounit(str(stotal), so.unit), so.unit)) + if so.min_filter_enable is True and stotal < (so.min_threshold * unit_factor): element.delete() - if self.options.max_filter_enable is True and stotal >= (self.options.max_threshold * unit_factor): + if self.options.max_filter_enable is True and stotal >= (so.max_threshold * unit_factor): element.delete() - + + elif so.measure == "nodes": + slengths, stotal = csplength(csp) #get segment lengths and total length of path in document's internal unit + nodes = len(element.path) + if so.debug is True: + inkex.utils.debug("id={}, length={:0.3f}{}, nodes={}".format(element.get('id'), self.svg.uutounit(str(stotal), so.unit), so.unit, nodes)) + if so.min_filter_enable is True and nodes / stotal < so.min_nodes / self.svg.unittouu(str(so.nodes_interval) + so.unit): + element.delete() + if so.max_filter_enable is True and nodes / stotal < so.max_nodes / self.svg.unittouu(str(so.nodes_interval) + so.unit): + element.delete() + except Exception as e: + #self.msg(e) pass if __name__ == '__main__': diff --git a/extensions/fablabchemnitz/laser_check/laser_check.inx b/extensions/fablabchemnitz/laser_check/laser_check.inx index 1d019b76..d0a78fc3 100644 --- a/extensions/fablabchemnitz/laser_check/laser_check.inx +++ b/extensions/fablabchemnitz/laser_check/laser_check.inx @@ -23,6 +23,7 @@ + false false false false diff --git a/extensions/fablabchemnitz/laser_check/laser_check.py b/extensions/fablabchemnitz/laser_check/laser_check.py index 3fe16d5f..629a01aa 100644 --- a/extensions/fablabchemnitz/laser_check/laser_check.py +++ b/extensions/fablabchemnitz/laser_check/laser_check.py @@ -11,6 +11,7 @@ class LaserCheck(inkex.EffectExtension): ''' ToDos: - check for old styles which should be upgraded + - add some inkex.Desc to all elements which were checked and which have some issue. use special syntax to remove old stuff each time the check is applied again - this code is horrible ugly stuff ''' @@ -20,7 +21,8 @@ class LaserCheck(inkex.EffectExtension): pars.add_argument('--show_issues_only', type=inkex.Boolean, default=False) pars.add_argument('--bbox', type=inkex.Boolean, default=False) pars.add_argument('--bbox_offset', type=float, default=5.000) - pars.add_argument("--machine_size", default="812x508") + pars.add_argument('--machine_size', default="812x508") + pars.add_argument('--elements_outside_canvas', type=inkex.Boolean, default=False) pars.add_argument('--groups_and_layers', type=inkex.Boolean, default=False) pars.add_argument('--clones', type=inkex.Boolean, default=False) pars.add_argument('--clippaths', type=inkex.Boolean, default=False) @@ -538,9 +540,56 @@ class LaserCheck(inkex.EffectExtension): round(self.svg.uutounit(str(heavyPath[2]), "mm"), 3), round(heavyPath[1] / self.svg.uutounit(str(heavyPath[2]), "mm"), 3) ) - ) + ) - + ''' + Elements outside canvas or touching the border. These are critical because they won't be lasered + ''' + if so.checks == "check_all" or so.elements_outside_canvas is True: + inkex.utils.debug("\n---------- Elements outside canvas or touching the border") + elementsOutside = [] + for element in shapes: + if element.tag != inkex.addNS('g', 'svg'): + ebbox = element.bounding_box() + precision = 3 + #inkex.utils.debug("{} | bbox: left = {:0.3f} right = {:0.3f} top = {:0.3f} bottom = {:0.3f}".format(element.get('id'), ebbox.left, ebbox.right, ebbox.top, ebbox.bottom)) + pagew = round(self.svg.unittouu(self.svg.get('width')), precision) + pageh = round(self.svg.unittouu(self.svg.get('height')), precision) + if round(ebbox.right, precision) == 0 or \ + round(ebbox.left, precision) == pagew or \ + round(ebbox.top, precision) == 0 or \ + round(ebbox.bottom, precision) == pageh: + elementsOutside.append([element, "touching"]) + elif \ + round(ebbox.right, precision) < 0 or \ + round(ebbox.left, precision) > pagew or \ + round(ebbox.top, precision) < 0 or \ + round(ebbox.bottom, precision) > pageh: + elementsOutside.append([element, "fully outside"]) + else: #fully inside or partially inside/outside. we check if one or more corners is outside the canvas + rightOutside = False + leftOutside = False + topOutside = False + bottomOutside = False + if round(ebbox.right, precision) < 0 or round(ebbox.right, precision) > pagew: + rightOutside = True + if round(ebbox.left, precision) < 0 or round(ebbox.left, precision) > pagew: + leftOutside = True + if round(ebbox.top, precision) < 0 or round(ebbox.top, precision) > pageh: + topOutside = True + if round(ebbox.bottom, precision) < 0 or round(ebbox.bottom, precision) > pageh: + bottomOutside = True + if rightOutside is True or leftOutside is True or topOutside is True or bottomOutside is True: + elementsOutside.append([element, "partially outside"]) + if self.options.show_issues_only is False: + inkex.utils.debug("{} Elements outside canvas or touching the border in total".format(len(elementsOutside))) + for elementOutside in elementsOutside: + inkex.utils.debug("id={}, status={}".format( + elementOutside[0].get('id'), + elementOutside[1] + ) + ) + ''' Shapes like rectangles, ellipses, arcs, spirals should be converted to svg:path to have more