Bug fixing and more features for Contour Scanner
This commit is contained in:
parent
91c25713b7
commit
4b009f75e8
@ -4,22 +4,23 @@
|
|||||||
<id>fablabchemnitz.de.contour_scanner</id>
|
<id>fablabchemnitz.de.contour_scanner</id>
|
||||||
<param name="main_tabs" type="notebook">
|
<param name="main_tabs" type="notebook">
|
||||||
<page name="tab_active" gui-text="Active">
|
<page name="tab_active" gui-text="Active">
|
||||||
<param name="desc" type="description">This tool helps you to find nasty contours which might bug you and prevent your work from being ready for production. You can find the complete documentation at the Wiki space of https://fablabchemnitz.de</param>
|
<label>This tool helps you to find nasty contours which might bug you and prevent your work from being ready for production. You can find the complete documentation at the Wiki space of https://fablabchemnitz.de</label>
|
||||||
<param name="help_general" type="description" appearance="header">General</param>
|
<label appearance="header">General</label>
|
||||||
<param name="breakapart" type="bool" gui-text="Break apart contours and groups">false</param>
|
<param name="breakapart" type="bool" gui-text="Break apart selection into single contours" gui-description="(with ignoring the group hirarchy by taking all children elements)">false</param>
|
||||||
<param name="removefillsetstroke" type="bool" gui-text="Remove fill and define stroke">false</param>
|
<param name="removefillsetstroke" type="bool" gui-text="Remove fill and define stroke">false</param>
|
||||||
<param name="strokewidth" min="0.0" max="10000.0" gui-text="Stroke width (px)" type="float">1.0</param>
|
<param name="strokewidth" min="0.0" max="10000.0" gui-text="Stroke width (px)" type="float">1.0</param>
|
||||||
<param name="help_highlight" type="description" appearance="header">Highlight paths</param>
|
<label appearance="header">Highlight paths</label>
|
||||||
<param name="highlight_opened" type="bool" gui-text="Highlight opened contours">true</param>
|
<param name="highlight_opened" type="bool" gui-text="Highlight opened contours">true</param>
|
||||||
<param name="color_opened" type="color" appearance="colorbutton" gui-text="Color opened contours">4012452351</param>
|
<param name="color_opened" type="color" appearance="colorbutton" gui-text="Color opened contours">4012452351</param>
|
||||||
<param name="highlight_closed" type="bool" gui-text="Highlight closed contours">true</param>
|
<param name="highlight_closed" type="bool" gui-text="Highlight closed contours">true</param>
|
||||||
<param name="color_closed" type="color" appearance="colorbutton" gui-text="Color closed contours">2330080511</param>
|
<param name="color_closed" type="color" appearance="colorbutton" gui-text="Color closed contours">2330080511</param>
|
||||||
<param name="highlight_selfintersecting" type="bool" gui-text="Highlight self-intersecting contours">true</param>
|
<param name="highlight_selfintersecting" type="bool" gui-text="Highlight self-intersecting contours" gui-description="Due to the nature of the algorithm this might detect non-closed contours too.">true</param>
|
||||||
<param name="color_selfintersecting" type="color" appearance="colorbutton" gui-text="Color self-intersecting contours">1923076095</param>
|
<param name="color_selfintersecting" type="color" appearance="colorbutton" gui-text="Color self-intersecting contours">1923076095</param>
|
||||||
<param name="highlight_intersectionpoints" type="bool" gui-text="Highlight self-intersecting points">true</param>
|
<param name="highlight_intersectionpoints" type="bool" gui-text="Highlight self-intersecting points">true</param>
|
||||||
<param name="color_intersectionpoints" type="color" appearance="colorbutton" gui-text="Color self-intersecting points">4239343359</param>
|
<param name="color_intersectionpoints" type="color" appearance="colorbutton" gui-text="Color self-intersecting points">4239343359</param>
|
||||||
<param name="dotsize" type="int" min="0" max="10000" gui-text="Dot size (px) for self-intersecting points">10</param>
|
<param name="dotsize" type="int" min="0" max="10000" gui-text="Dot size (px) for self-intersecting points">10</param>
|
||||||
<param name="help_remove" type="description" appearance="header">Remove paths</param>
|
<param name="addlines" type="bool" gui-text="Add closing lines for open self-crossing contours" gui-description="They will have the same color as the intersection points and help to better visualize possible virtual crossings. The algorithm can only detect intersections for closed contours by it's nature, but we handle open contours like they were closed. This may put put too much intersection points.">true</param>
|
||||||
|
<label appearance="header">Remove paths</label>
|
||||||
<param name="remove_opened" type="bool" gui-text="Remove opened contours">false</param>
|
<param name="remove_opened" type="bool" gui-text="Remove opened contours">false</param>
|
||||||
<param name="remove_closed" type="bool" gui-text="Remove closed contours">false</param>
|
<param name="remove_closed" type="bool" gui-text="Remove closed contours">false</param>
|
||||||
<param name="remove_selfintersecting" type="bool" gui-text="Remove self-intersecting contours">false</param>
|
<param name="remove_selfintersecting" type="bool" gui-text="Remove self-intersecting contours">false</param>
|
||||||
|
@ -13,7 +13,7 @@ Features
|
|||||||
Author: Mario Voigt / FabLab Chemnitz
|
Author: Mario Voigt / FabLab Chemnitz
|
||||||
Mail: mario.voigt@stadtfabrikanten.org
|
Mail: mario.voigt@stadtfabrikanten.org
|
||||||
Date: 09.08.2020
|
Date: 09.08.2020
|
||||||
Last patch: 19.08.2020
|
Last patch: 05.09.2020
|
||||||
License: GNU GPL v3
|
License: GNU GPL v3
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -40,12 +40,14 @@ def adjustStyle(self, node):
|
|||||||
if prop == 'fill':
|
if prop == 'fill':
|
||||||
declarations[i] = prop + ':none'
|
declarations[i] = prop + ':none'
|
||||||
node.set('style', ';'.join(declarations) + ';stroke:#000000;stroke-opacity:1.0')
|
node.set('style', ';'.join(declarations) + ';stroke:#000000;stroke-opacity:1.0')
|
||||||
|
else:
|
||||||
|
node.set('style', 'stroke:#000000;stroke-opacity:1.0')
|
||||||
|
|
||||||
class ContourScanner(inkex.Effect):
|
class ContourScanner(inkex.Effect):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
inkex.Effect.__init__(self)
|
inkex.Effect.__init__(self)
|
||||||
self.arg_parser.add_argument("--breakapart", type=inkex.Boolean, default=False, help="Break apart contours")
|
self.arg_parser.add_argument("--breakapart", type=inkex.Boolean, default=False, help="Break apart selection into single contours")
|
||||||
self.arg_parser.add_argument("--removefillsetstroke", type=inkex.Boolean, default=False, help="Remove fill and define stroke")
|
self.arg_parser.add_argument("--removefillsetstroke", type=inkex.Boolean, default=False, help="Remove fill and define stroke")
|
||||||
self.arg_parser.add_argument("--strokewidth", type=float, default=1.0, help="Stroke width (px)")
|
self.arg_parser.add_argument("--strokewidth", type=float, default=1.0, help="Stroke width (px)")
|
||||||
self.arg_parser.add_argument("--highlight_opened", type=inkex.Boolean, default=True, help="Highlight opened contours")
|
self.arg_parser.add_argument("--highlight_opened", type=inkex.Boolean, default=True, help="Highlight opened contours")
|
||||||
@ -56,6 +58,7 @@ class ContourScanner(inkex.Effect):
|
|||||||
self.arg_parser.add_argument("--highlight_intersectionpoints", type=inkex.Boolean, default=True, help="Highlight self-intersecting points")
|
self.arg_parser.add_argument("--highlight_intersectionpoints", type=inkex.Boolean, default=True, help="Highlight self-intersecting points")
|
||||||
self.arg_parser.add_argument("--color_selfintersecting", type=Color, default='1923076095', help="Color closed contours")
|
self.arg_parser.add_argument("--color_selfintersecting", type=Color, default='1923076095', help="Color closed contours")
|
||||||
self.arg_parser.add_argument("--color_intersectionpoints", type=Color, default='4239343359', help="Color closed contours")
|
self.arg_parser.add_argument("--color_intersectionpoints", type=Color, default='4239343359', help="Color closed contours")
|
||||||
|
self.arg_parser.add_argument("--addlines", type=inkex.Boolean, default=True, help="Add closing lines for self-crossing contours")
|
||||||
self.arg_parser.add_argument("--dotsize", type=int, default=10, help="Dot size (px) for self-intersecting points")
|
self.arg_parser.add_argument("--dotsize", type=int, default=10, help="Dot size (px) for self-intersecting points")
|
||||||
self.arg_parser.add_argument("--remove_opened", type=inkex.Boolean, default=False, help="Remove opened contours")
|
self.arg_parser.add_argument("--remove_opened", type=inkex.Boolean, default=False, help="Remove opened contours")
|
||||||
self.arg_parser.add_argument("--remove_closed", type=inkex.Boolean, default=False, help="Remove closed contours")
|
self.arg_parser.add_argument("--remove_closed", type=inkex.Boolean, default=False, help="Remove closed contours")
|
||||||
@ -105,42 +108,13 @@ class ContourScanner(inkex.Effect):
|
|||||||
prev = i
|
prev = i
|
||||||
subpaths.append(raw[prev:])
|
subpaths.append(raw[prev:])
|
||||||
|
|
||||||
for simpath in subpaths:
|
|
||||||
if len(simpath) > 0:
|
|
||||||
closed = False
|
|
||||||
if simpath[-1][0] == 'Z':
|
|
||||||
closed = True
|
|
||||||
|
|
||||||
if not closed:
|
|
||||||
if self.options.highlight_opened:
|
|
||||||
style = {'stroke-linejoin': 'miter', 'stroke-width': str(self.svg.unittouu(str(self.options.strokewidth) +"px")),
|
|
||||||
'stroke-opacity': '1.0', 'fill-opacity': '1.0',
|
|
||||||
'stroke': self.options.color_opened, 'stroke-linecap': 'butt', 'fill': 'none'}
|
|
||||||
node.attrib['style'] = Style(style).to_str()
|
|
||||||
if self.options.remove_opened:
|
|
||||||
try:
|
|
||||||
node.getparent().remove(node)
|
|
||||||
except AttributeError:
|
|
||||||
pass #we ignore that parent can be None
|
|
||||||
if closed:
|
|
||||||
if self.options.highlight_closed:
|
|
||||||
style = {'stroke-linejoin': 'miter', 'stroke-width': str(self.svg.unittouu(str(self.options.strokewidth) +"px")),
|
|
||||||
'stroke-opacity': '1.0', 'fill-opacity': '1.0',
|
|
||||||
'stroke': self.options.color_closed, 'stroke-linecap': 'butt', 'fill': 'none'}
|
|
||||||
node.attrib['style'] = Style(style).to_str()
|
|
||||||
if self.options.remove_closed:
|
|
||||||
try:
|
|
||||||
node.getparent().remove(node)
|
|
||||||
except AttributeError:
|
|
||||||
pass #we ignore that parent can be None
|
|
||||||
|
|
||||||
for simpath in subpaths:
|
for simpath in subpaths:
|
||||||
closed = False
|
closed = False
|
||||||
if simpath[-1][0] == 'Z':
|
if simpath[-1][0] == 'Z':
|
||||||
closed = True
|
closed = True
|
||||||
if simpath[-2][0] == 'L': simpath[-1][1] = simpath[0][1]
|
if simpath[-2][0] == 'L': simpath[-1][1] = simpath[0][1]
|
||||||
else: simpath.pop()
|
else: simpath.pop()
|
||||||
nodes = []
|
points = []
|
||||||
for i in range(len(simpath)):
|
for i in range(len(simpath)):
|
||||||
if simpath[i][0] == 'V': # vertical and horizontal lines only have one point in args, but 2 are required
|
if simpath[i][0] == 'V': # vertical and horizontal lines only have one point in args, but 2 are required
|
||||||
simpath[i][0]='L' #overwrite V with regular L command
|
simpath[i][0]='L' #overwrite V with regular L command
|
||||||
@ -150,14 +124,50 @@ class ContourScanner(inkex.Effect):
|
|||||||
if simpath[i][0] == 'H': # vertical and horizontal lines only have one point in args, but 2 are required
|
if simpath[i][0] == 'H': # vertical and horizontal lines only have one point in args, but 2 are required
|
||||||
simpath[i][0]='L' #overwrite H with regular L command
|
simpath[i][0]='L' #overwrite H with regular L command
|
||||||
simpath[i][1].append(simpath[i-1][1][1]) #add the second (missing) argument by taking argument from previous segment
|
simpath[i][1].append(simpath[i-1][1][1]) #add the second (missing) argument by taking argument from previous segment
|
||||||
nodes.append(simpath[i][1][-2:])
|
points.append(simpath[i][1][-2:])
|
||||||
|
if points[0] == points[-1]: #if first is last point the path is also closed. The "Z" command is not required
|
||||||
|
closed = True
|
||||||
|
|
||||||
|
if closed == False:
|
||||||
|
if self.options.highlight_opened:
|
||||||
|
style = {'stroke-linejoin': 'miter', 'stroke-width': str(self.svg.unittouu(str(self.options.strokewidth) +"px")),
|
||||||
|
'stroke-opacity': '1.0', 'fill-opacity': '1.0',
|
||||||
|
'stroke': self.options.color_opened, 'stroke-linecap': 'butt', 'fill': 'none'}
|
||||||
|
node.attrib['style'] = Style(style).to_str()
|
||||||
|
if self.options.remove_opened:
|
||||||
|
try:
|
||||||
|
node.getparent().remove(node)
|
||||||
|
except AttributeError:
|
||||||
|
pass #we ignore that parent can be None
|
||||||
|
if closed == True:
|
||||||
|
if self.options.highlight_closed:
|
||||||
|
style = {'stroke-linejoin': 'miter', 'stroke-width': str(self.svg.unittouu(str(self.options.strokewidth) +"px")),
|
||||||
|
'stroke-opacity': '1.0', 'fill-opacity': '1.0',
|
||||||
|
'stroke': self.options.color_closed, 'stroke-linecap': 'butt', 'fill': 'none'}
|
||||||
|
node.attrib['style'] = Style(style).to_str()
|
||||||
|
if self.options.remove_closed:
|
||||||
|
try:
|
||||||
|
node.getparent().remove(node)
|
||||||
|
except AttributeError:
|
||||||
|
pass #we ignore that parent can be None
|
||||||
|
|
||||||
#if one of the options is activated we also check for self-intersecting
|
#if one of the options is activated we also check for self-intersecting
|
||||||
if self.options.highlight_selfintersecting or self.options.highlight_intersectionpoints:
|
if self.options.highlight_selfintersecting or self.options.highlight_intersectionpoints:
|
||||||
try:
|
try:
|
||||||
if len(nodes) > 0: #try to find self-intersecting /overlapping polygons
|
if len(points) > 0: #try to find self-intersecting /overlapping polygons
|
||||||
isect = poly_point_isect.isect_polygon(nodes) #TODO: FIND OUT HOW TO HANDLE OPEN CONTOURS TO OMIT VIRTUALLY CROSSING LINES (WHICH DO NOT INTERSECT)
|
isect = poly_point_isect.isect_polygon(points)
|
||||||
if len(isect) > 0:
|
if len(isect) > 0:
|
||||||
|
if closed == False and self.options.addlines == True: #if contour is open and we found intersection points those points might be not relevant
|
||||||
|
line = dot_group.add(inkex.PathElement())
|
||||||
|
line.path = [
|
||||||
|
['M', [points[0][0],points[0][1]]],
|
||||||
|
['L', [points[-1][0],points[-1][1]]],
|
||||||
|
['Z', []]
|
||||||
|
]
|
||||||
|
style = {'stroke-linejoin': 'miter', 'stroke-width': str(self.svg.unittouu(str(self.options.strokewidth) +"px")),
|
||||||
|
'stroke-opacity': '1.0', 'fill-opacity': '1.0',
|
||||||
|
'stroke': self.options.color_intersectionpoints, 'stroke-linecap': 'butt', 'fill': 'none'}
|
||||||
|
line.attrib['style'] = Style(style).to_str()
|
||||||
#make dot markings at the intersection points
|
#make dot markings at the intersection points
|
||||||
if self.options.highlight_intersectionpoints:
|
if self.options.highlight_intersectionpoints:
|
||||||
for xy in isect:
|
for xy in isect:
|
||||||
@ -179,11 +189,16 @@ class ContourScanner(inkex.Effect):
|
|||||||
print(str(e))
|
print(str(e))
|
||||||
#if the dot_group was created but nothing attached we delete it again to prevent messing the SVG XML tree
|
#if the dot_group was created but nothing attached we delete it again to prevent messing the SVG XML tree
|
||||||
if len(dot_group.getchildren()) == 0:
|
if len(dot_group.getchildren()) == 0:
|
||||||
dot_group.getparent().remove(dot_group)
|
dot_parent = dot_group.getparent()
|
||||||
else: #put the node into the dot_group to bundle the path with it's error markers
|
if dot_parent is not None:
|
||||||
|
dot_group.getparent().remove(dot_group)
|
||||||
|
#put the node into the dot_group to bundle the path with it's error markers. If removal is selected we need to avoid dot_group.insert(), because it will break the removal
|
||||||
|
elif self.options.remove_selfintersecting == False:
|
||||||
dot_group.insert(0, node)
|
dot_group.insert(0, node)
|
||||||
for child in node:
|
children = node.getchildren()
|
||||||
self.scanContours(child)
|
if children is not None:
|
||||||
|
for child in children:
|
||||||
|
self.scanContours(child)
|
||||||
|
|
||||||
def effect(self):
|
def effect(self):
|
||||||
if self.options.breakapart:
|
if self.options.breakapart:
|
||||||
|
Reference in New Issue
Block a user