different large refactorings (subdirectores, removed obsolete stuff) and

bug fixes
This commit is contained in:
2020-08-31 21:25:41 +02:00
parent 7aeae6fc55
commit ffcb5ed744
2250 changed files with 764 additions and 142723 deletions

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Contour Scanner</name>
<id>fablabchemnitz.de.contour_scanner</id>
<param name="main_tabs" type="notebook">
<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>
<param name="help_general" type="description" appearance="header">General</param>
<param name="breakapart" type="bool" gui-text="Break apart contours">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="help_highlight" type="description" appearance="header">Highlight paths</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="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="highlight_selfintersecting" type="bool" gui-text="Highlight self-intersecting contours">true</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="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="help_remove" type="description" appearance="header">Remove paths</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_selfintersecting" type="bool" gui-text="Remove self-intersecting contours">false</param>
</page>
<page name="tab_info" gui-text="License/Version">
<param name="desc1" type="description">Written by Mario Voigt (Stadtfabrikanten e.V. / FabLab Chemnitz) (https://gitea.fablabchemnitz.de)</param>
<param name="desc2" type="description">Last update: 09.08.2020</param>
<param name="desc3" type="description">This piece of software is part of the MightyScape for InkScape 1.0/1.1dev Extension Collection</param>
<param name="desc4" type="description" appearance="header">you found a bug or got some fresh code? Just report to mario.voigt@stadtfabrikanten.org. Thanks!</param>
</page>
</param>
<effect>
<object-type>path</object-type>
<effects-menu>
<submenu name="FabLab Chemnitz">
<submenu name="Nesting/Cut Optimization"/>
</submenu>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">fablabchemnitz_contour_scanner.py</command>
</script>
</inkscape-extension>

View File

@ -0,0 +1,203 @@
#!/usr/bin/env python3
"""
Extension for InkScape 1.0
Features
- helps to find contours which are closed or not. Good for repairing contours, closing contours,...
- works for paths which are packed into groups or groups of groups. #
- can break contours apart like in "Path -> Break Apart"
- implements Bentley-Ottmann algorithm from https://github.com/ideasman42/isect_segments-bentley_ottmann to scan for self-intersecting paths. You might get "assert(event.in_sweep == False) AssertionError". Don't know how to fix rgis
- colorized paths respective to their type
- can add dots to intersection points you'd like to fix
Author: Mario Voigt / FabLab Chemnitz
Mail: mario.voigt@stadtfabrikanten.org
Date: 09.08.2020
Last patch: 19.08.2020
License: GNU GPL v3
"""
from math import *
import inkex
from inkex.paths import Path, CubicSuperPath
from inkex import Style, Color, Circle
from lxml import etree
import fablabchemnitz_poly_point_isect
import copy
def adjustStyle(self, node):
if node.attrib.has_key('style'):
style = node.get('style')
if style:
declarations = style.split(';')
for i,decl in enumerate(declarations):
parts = decl.split(':', 2)
if len(parts) == 2:
(prop, val) = parts
prop = prop.strip().lower()
if prop == 'stroke-width':
declarations[i] = prop + ':' + str(self.svg.unittouu(str(self.options.strokewidth) +"px"))
if prop == 'fill':
declarations[i] = prop + ':none'
node.set('style', ';'.join(declarations) + ';stroke:#000000;stroke-opacity:1.0')
class ContourScanner(inkex.Effect):
def __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("--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("--highlight_opened", type=inkex.Boolean, default=True, help="Highlight opened contours")
self.arg_parser.add_argument("--color_opened", type=Color, default='4012452351', help="Color opened contours")
self.arg_parser.add_argument("--highlight_closed", type=inkex.Boolean, default=True, help="Highlight closed contours")
self.arg_parser.add_argument("--color_closed", type=Color, default='2330080511', help="Color closed contours")
self.arg_parser.add_argument("--highlight_selfintersecting", type=inkex.Boolean, default=True, help="Highlight self-intersecting contours")
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_intersectionpoints", type=Color, default='4239343359', help="Color closed contours")
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_closed", type=inkex.Boolean, default=False, help="Remove closed contours")
self.arg_parser.add_argument("--remove_selfintersecting", type=inkex.Boolean, default=False, help="Remove self-intersecting contours")
self.arg_parser.add_argument("--main_tabs")
#split combined contours into single contours if enabled - this is exactly the same as "Path -> Break Apart"
def breakContours(self, node):
replacedNodes = []
if node.tag == inkex.addNS('path','svg'):
parent = node.getparent()
idx = parent.index(node)
idSuffix = 0
raw = Path(node.get("d")).to_arrays()
subpaths, prev = [], 0
for i in range(len(raw)): # Breaks compound paths into simple paths
if raw[i][0] == 'M' and i != 0:
subpaths.append(raw[prev:i])
prev = i
subpaths.append(raw[prev:])
for subpath in subpaths:
replacedNode = copy.copy(node)
oldId = replacedNode.get('id')
replacedNode.set('d', CubicSuperPath(subpath))
replacedNode.set('id', oldId + str(idSuffix).zfill(5))
parent.insert(idx, replacedNode)
idSuffix += 1
replacedNodes.append(replacedNode)
parent.remove(node)
for child in node:
self.breakContours(child)
return replacedNodes
def scanContours(self, node):
if node.tag == inkex.addNS('path','svg'):
if self.options.removefillsetstroke:
adjustStyle(self, node)
dot_group = node.getparent().add(inkex.Group())
raw = (Path(node.get('d')).to_arrays())
subpaths, prev = [], 0
for i in range(len(raw)): # Breaks compound paths into simple paths
if raw[i][0] == 'M' and i != 0:
subpaths.append(raw[prev:i])
prev = i
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:
closed = False
if simpath[-1][0] == 'Z':
closed = True
if simpath[-2][0] == 'L': simpath[-1][1] = simpath[0][1]
else: simpath.pop()
nodes = []
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
simpath[i][0]='L' #overwrite V with regular L command
add=simpath[i-1][1][0] #read the X value from previous segment
simpath[i][1].append(simpath[i][1][0]) #add the second (missing) argument by taking argument from previous segment
simpath[i][1][0]=add #replace with recent X after Y was appended
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][1].append(simpath[i-1][1][1]) #add the second (missing) argument by taking argument from previous segment
nodes.append(simpath[i][1][-2:])
#if one of the options is activated we also check for self-intersecting
if self.options.highlight_selfintersecting or self.options.highlight_intersectionpoints:
try:
if len(nodes) > 0: #try to find self-intersecting /overlapping polygons
isect = fablabchemnitz_poly_point_isect.isect_polygon(nodes) #TODO: FIND OUT HOW TO HANDLE OPEN CONTOURS TO OMIT VIRTUALLY CROSSING LINES (WHICH DO NOT INTERSECT)
if len(isect) > 0:
#make dot markings at the intersection points
if self.options.highlight_intersectionpoints:
for xy in isect:
#Add a dot label for this path element
style = inkex.Style({'stroke': 'none', 'fill': self.options.color_intersectionpoints})
circle = dot_group.add(Circle(cx=str(xy[0]), cy=str(xy[1]), r=str(self.svg.unittouu(str(self.options.dotsize/2) + "px"))))
circle.style = style
if self.options.highlight_selfintersecting:
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_selfintersecting, 'stroke-linecap': 'butt', 'fill': 'none'}
node.attrib['style'] = Style(style).to_str()
if self.options.remove_selfintersecting:
if node.getparent() is not None: #might be already been deleted by previously checked settings so check again
node.getparent().remove(node)
except Exception as e: # we skip AssertionError
#inkex.utils.debug("Accuracy Error. Try to reduce the precision of the paths using the extension called Rounder to cutoff unrequired decimals.")
print(str(e))
for child in node:
self.scanContours(child)
def effect(self):
if self.options.breakapart:
if len(self.svg.selected) == 0:
self.breakContours(self.document.getroot())
self.scanContours(self.document.getroot())
else:
newContourSet = []
for id, item in self.svg.selected.items():
newContourSet.append(self.breakContours(item))
for newContours in newContourSet:
for newContour in newContours:
self.scanContours(newContour)
else:
if len(self.svg.selected) == 0:
self.scanContours(self.document.getroot())
else:
for id, item in self.svg.selected.items():
self.scanContours(item)
if __name__ == '__main__':
ContourScanner().run()

File diff suppressed because it is too large Load Diff