massive efforts in contour scanner and trimmer
This commit is contained in:
parent
a2c079d8c9
commit
0513eb888f
@ -2,96 +2,21 @@
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Contour Scanner And Trimmer</name>
|
||||
<id>fablabchemnitz.de.contour_scanner_and_trimmer</id>
|
||||
<param name="tab" type="notebook">
|
||||
<page name="tab_settings" gui-text="Settings">
|
||||
<label appearance="header">General</label>
|
||||
<param name="show_debug" type="bool" gui-text="Show debug infos">false</param>
|
||||
<param name="break_apart" type="bool" gui-text="Break apart input" gui-description="Break apart input paths into sub paths. Modifies original paths: converts to absolute paths and might create additional new path elements.">false</param>
|
||||
<param name="handle_groups" type="bool" gui-text="Handle groups" gui-description="Also looks for paths in groups which are in the current selection. Note: The generated results have a different structure (less granularity due to grouping and conversion of absolute paths to relative paths) than directly selected paths. The colorization for non-intersected paths will be different too.">false</param>
|
||||
<param name="flattenbezier" type="bool" gui-text="Quantization (flatten bezier curves to polylines)" gui-description="Convert bezier curves to polylines.">true</param>
|
||||
<param name="flatness" type="float" min="0.001" max="99999.000" precision="3" gui-text="Flatness (tolerance)" gui-description="Minimum flatness = 0.001. The smaller the value the more fine segments you will get (quantization). Large values might destroy the line continuity.">0.100</param>
|
||||
<param name="decimals" type="int" min="0" max="16" gui-text="Decimals" gui-description="Accuracy for sub split lines / lines trimmed by shapely (default: 3)">3</param>
|
||||
<param name="snap_tolerance" type="float" min="0.01" max="10.0" gui-text="Snap tolerance" gui-description="Snap tolerance for intersection points on paths (default: 0.1)">0.1</param>
|
||||
<param name="draw_subsplit" type="bool" gui-text="Draw sub split lines (for debugging purposes)" gui-description="Draws polylines. Will be automatically enabled if any highlighting is activated.">false</param>
|
||||
<param name="remove_subsplit_collinear" type="bool" gui-text="Remove collinear overlapping lines (experimental)" gui-description="Removes any duplicates by merging (multiple) overlapping line segments into longer lines. Not possible to apply for original paths because this routine does not support bezier type paths.">true</param>
|
||||
<param name="keep_original_after_split_trim" type="bool" gui-text="Keep original paths after sub splitting / trimming">false</param>
|
||||
</page>
|
||||
<page name="tab_scanning" gui-text="Scanning and Trimming">
|
||||
<hbox>
|
||||
<vbox>
|
||||
<label appearance="header">Removing Original Paths</label>
|
||||
<param name="remove_relative" type="bool" gui-text="relative cmd">false</param>
|
||||
<param name="remove_absolute" type="bool" gui-text="absolute cmd">false</param>
|
||||
<param name="remove_mixed" type="bool" gui-text="mixed cmd" gui-description="combined relative and absolute">false</param>
|
||||
<param name="remove_polylines" type="bool" gui-text="polylines">false</param>
|
||||
<param name="remove_beziers" type="bool" gui-text="beziers">false</param>
|
||||
<param name="remove_opened" type="bool" gui-text="opened">false</param>
|
||||
<param name="remove_closed" type="bool" gui-text="closed">false</param>
|
||||
<param name="remove_self_intersecting" type="bool" gui-text="self-intersecting">false</param>
|
||||
<separator/>
|
||||
<label appearance="header">Highlighting</label>
|
||||
<param name="highlight_relative" type="bool" gui-text="relative cmd paths">false</param>
|
||||
<param name="highlight_absolute" type="bool" gui-text="absolute cmd paths">false</param>
|
||||
<param name="highlight_mixed" type="bool" gui-text="mixed cmd paths" gui-description="combined relative and absolute">false</param>
|
||||
<param name="highlight_polylines" type="bool" gui-text="polyline paths">false</param>
|
||||
<param name="highlight_beziers" type="bool" gui-text="bezier paths">false</param>
|
||||
<param name="highlight_opened" type="bool" gui-text="opened paths">false</param>
|
||||
<param name="highlight_closed" type="bool" gui-text="closed paths">false</param>
|
||||
<param name="highlight_self_intersecting" type="bool" gui-text="self-intersecting paths" gui-description="Requires to draw sub split lines. Will override highlighting colors for open and closed paths (if those options are enabled)">false</param>
|
||||
<param name="visualize_self_intersections" type="bool" gui-text="self-intersecting path points">false</param>
|
||||
<param name="visualize_global_intersections" type="bool" gui-text="global intersection points" gui-description="Will also contain self-intersecting points! Global intersections will only show if 'Draw trimmed lines' is enabled!">false</param>
|
||||
</vbox>
|
||||
<separator/>
|
||||
<vbox>
|
||||
<label appearance="header">Trimming</label>
|
||||
<param name="trimming_path_types" type="optiongroup" appearance="combo" gui-text="Trimming selection" gui-description="Process open paths by other open paths, closed paths by other closed paths, or all paths by all other paths. This selection does not apply for paths which intersect themselves!">
|
||||
<option value="both">all:all paths</option>
|
||||
<option value="open_paths">open:open paths</option>
|
||||
<option value="closed_paths">closed:closed paths</option>
|
||||
</param>
|
||||
<param name="draw_trimmed" type="bool" gui-text="Draw trimmed lines">false</param>
|
||||
<param name="combine_nonintersects" type="bool" gui-text="Chain + combine non-intersected lines" gui-description="This will colorize all paths segments which were not intersected ('non-intersected lines'). If the whole path was not intersected at all, it will get another color ('non-intersected paths').">true</param>
|
||||
<param name="remove_duplicates" type="bool" gui-text="Remove duplicate trim lines">true</param>
|
||||
<param name="reverse_removal_order" type="bool" gui-text="Reverse removal order" gui-description="Reverses the order of removal. Relevant for keeping certain styles of elements">false</param>
|
||||
<param name="bezier_trimming" type="bool" gui-text="Trim original beziers (not working yet)" gui-description="If enabled we try to split the original bezier paths at the intersections points by finding the correct bezier segments and calculating t parameters from trimmed sub split lines. Not working yet. Will just print debug info if debug is enabled.">true</param>
|
||||
<label appearance="header">Bentley Ottmann Sweep Line Settings</label>
|
||||
<param name="bent_ott_use_ignore_segment_endings" type="bool" gui-text="Ignore segment endings" gui-description="Whether to ignore intersections of line segments when both their end points form the intersection point">true</param>
|
||||
<param name="bent_ott_use_debug" type="bool" gui-text="Debug">false</param>
|
||||
<param name="bent_ott_use_verbose" type="bool" gui-text="Verbose">false</param>
|
||||
<param name="bent_ott_use_paranoid" type="bool" gui-text="Paranoid checks">false</param>
|
||||
<param name="bent_ott_use_vertical" type="bool" gui-text="Support vertical segments">true</param>
|
||||
<param name="bent_ott_number_type" type="optiongroup" appearance="combo" gui-text="Number type">
|
||||
<option value="native">native (default)</option>
|
||||
<option value="numpy">numpy</option>
|
||||
</param>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</page>
|
||||
<page name="tab_style" gui-text="Style">
|
||||
<hbox>
|
||||
<vbox>
|
||||
<label appearance="header">Scanning Colors</label>
|
||||
<param name="color_subsplit" type="color" appearance="colorbutton" gui-text="sub split lines">1630897151</param>
|
||||
<param name="color_relative" type="color" appearance="colorbutton" gui-text="relative cmd paths">3419879935</param>
|
||||
<param name="color_absolute" type="color" appearance="colorbutton" gui-text="absolute cmd paths">1592519679</param>
|
||||
<param name="color_mixed" type="color" appearance="colorbutton" gui-text="mixed cmd paths" gui-description="combined relative and absolute">3351636735</param>
|
||||
<param name="color_polyline" type="color" appearance="colorbutton" gui-text="polyline paths">4289703935</param>
|
||||
<param name="color_bezier" type="color" appearance="colorbutton" gui-text="bezier paths">258744063</param>
|
||||
<param name="color_opened" type="color" appearance="colorbutton" gui-text="opened paths">4012452351</param>
|
||||
<param name="color_closed" type="color" appearance="colorbutton" gui-text="closed paths">2330080511</param>
|
||||
<param name="color_self_intersecting_paths" type="color" appearance="colorbutton" gui-text="self-intersecting paths">2593756927</param>
|
||||
<param name="color_self_intersections" type="color" appearance="colorbutton" gui-text="self-intersecting paths points">6320383</param>
|
||||
<param name="color_global_intersections" type="color" appearance="colorbutton" gui-text="global intersection points">4239343359</param>
|
||||
</vbox>
|
||||
<separator/>
|
||||
<vbox>
|
||||
<label appearance="header">Trimming Colors</label>
|
||||
<param name="color_trimmed" type="color" appearance="colorbutton" gui-text="trimmed lines">3227634687</param>
|
||||
<param name="color_combined" type="color" appearance="colorbutton" gui-text="non-intersected lines" gui-description="Colorize non-trimmed lines differently than the trimmed ones. Does not apply if 'Original style for trimmed lines' is enabled">1923076095</param>
|
||||
<param name="color_nonintersected" type="color" appearance="colorbutton" gui-text="non-intersected paths" gui-description="Colorize the complete path in case it does not contain any trim. Does not apply if 'Original style for trimmed lines' is enabled">3045284607</param>
|
||||
<label appearance="header">General Style</label>
|
||||
<param name="nb_main" type="notebook">
|
||||
<page name="tab_settings_and_actions" gui-text="Settings and Actions">
|
||||
<param name="nb_settings_and_actions" type="notebook">
|
||||
<page name="tab_settings" gui-text="Settings">
|
||||
<label appearance="header">General input/output</label>
|
||||
<param name="show_debug" type="bool" gui-text="Show debug infos">false</param>
|
||||
<param name="break_apart" type="bool" gui-text="Break apart input" gui-description="Break apart input paths into sub paths. Modifies original paths: converts to absolute paths and might create additional new path elements.">false</param>
|
||||
<param name="handle_groups" type="bool" gui-text="Handle groups" gui-description="Also looks for paths in groups which are in the current selection. Note: The generated results have a different structure (less granularity due to grouping and conversion of absolute paths to relative paths) than directly selected paths. The colorization for non-intersected paths will be different too.">false</param>
|
||||
<param name="flattenbezier" type="bool" gui-text="Quantization (flatten bezier curves to polylines)" gui-description="Convert bezier curves to polylines.">true</param>
|
||||
<param name="flatness" type="float" min="0.001" max="99999.000" precision="3" gui-text="Flatness (tolerance)" gui-description="Minimum flatness = 0.001. The smaller the value the more fine segments you will get (quantization). Large values might destroy the line continuity.">0.100</param>
|
||||
<param name="decimals" type="int" min="0" max="16" gui-text="Decimals" gui-description="Accuracy for sub split lines / lines trimmed by shapely (default: 3)">3</param>
|
||||
<param name="snap_tolerance" type="float" min="0.01" max="10.0" gui-text="Snap tolerance" gui-description="Snap tolerance for intersection points on paths (default: 0.1)">0.1</param>
|
||||
<label appearance="header">General style</label>
|
||||
<param name="strokewidth" min="0.0" max="10000.0" precision="3" gui-text="Stroke width (px)" gui-description="Applies For sub split lines and trimmed lines" type="float">1.0</param>
|
||||
<param name="dotsize_intersections" type="int" min="0" max="10000" gui-text="Dot size (px)" gui-description="For self-intersecting and global intersection points">30</param>
|
||||
<param name="dotsize_intersections" type="int" min="0" max="10000" gui-text="Intersection dot size (px)" gui-description="For self-intersecting and global intersection points">30</param>
|
||||
<param name="removefillsetstroke" type="bool" gui-text="Remove fill and define stroke" gui-description="Modifies original path style">false</param>
|
||||
<param name="subsplit_style" type="optiongroup" appearance="combo" gui-text="Sub split line style">
|
||||
<option value="default">Use default sub split style</option>
|
||||
@ -101,17 +26,105 @@
|
||||
<param name="trimmed_style" type="optiongroup" appearance="combo" gui-text="Trimmed line style">
|
||||
<option value="apply_from_trimmed">Apply default trimming styles</option>
|
||||
<option value="apply_from_original">Apply original path styles</option>
|
||||
</param>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</param>
|
||||
</page>
|
||||
<page name="tab_removing" gui-text="Removing">
|
||||
<label appearance="header">Applying to original paths and sub split lines</label>
|
||||
<param name="remove_relative" type="bool" gui-text="relative cmd">false</param>
|
||||
<param name="remove_absolute" type="bool" gui-text="absolute cmd">false</param>
|
||||
<param name="remove_mixed" type="bool" gui-text="mixed cmd" gui-description="combined relative and absolute">false</param>
|
||||
<param name="remove_polylines" type="bool" gui-text="polylines">false</param>
|
||||
<param name="remove_beziers" type="bool" gui-text="beziers">false</param>
|
||||
<param name="remove_opened" type="bool" gui-text="opened">false</param>
|
||||
<param name="remove_closed" type="bool" gui-text="closed">false</param>
|
||||
<param name="remove_self_intersecting" type="bool" gui-text="self-intersecting">false</param>
|
||||
<label appearance="header">Applying to sub split lines only</label>
|
||||
<param name="filter_subsplit_collinear" type="bool" gui-text="Filter collinear overlapping lines" gui-description="Removes any duplicates by merging (multiple) overlapping line segments into longer lines. Not possible to apply for original paths because this routine does not support bezier type paths.">true</param>
|
||||
<param name="filter_subsplit_collinear_action" type="optiongroup" appearance="combo" gui-text="What to do with collinear overlapping lines?">
|
||||
<option value="remove">remove</option>
|
||||
<option value="separate_group">put to separate group</option>
|
||||
</param>
|
||||
<label appearance="header">Applying to original paths only</label>
|
||||
<param name="keep_original_after_split_trim" type="bool" gui-text="Keep original paths after sub splitting / trimming">false</param>
|
||||
</page>
|
||||
<page name="tab_highlighting" gui-text="Highlighting">
|
||||
<label appearance="header">Applying to original paths and sub split lines</label>
|
||||
<param name="highlight_relative" type="bool" gui-text="relative cmd">false</param>
|
||||
<param name="highlight_absolute" type="bool" gui-text="absolute cmd">false</param>
|
||||
<param name="highlight_mixed" type="bool" gui-text="mixed cmd" gui-description="combined relative and absolute">false</param>
|
||||
<param name="highlight_polylines" type="bool" gui-text="polylines">false</param>
|
||||
<param name="highlight_beziers" type="bool" gui-text="beziers">false</param>
|
||||
<param name="highlight_opened" type="bool" gui-text="opened">false</param>
|
||||
<param name="highlight_closed" type="bool" gui-text="closed">false</param>
|
||||
<param name="highlight_self_intersecting" type="bool" gui-text="self-intersecting" gui-description="Requires enabled 'Draw sub split lines' option (will auto-enable). Will override other highlighting colors (if those options are enabled)">false</param>
|
||||
<label appearance="header">Applying to sub split lines only</label>
|
||||
<param name="draw_subsplit" type="bool" gui-text="Draw sub split lines" gui-description="Draws polylines which are generated from all input paths">false</param>
|
||||
<param name="highlight_duplicates" type="bool" gui-text="duplicates">false</param>
|
||||
<param name="highlight_merges" type="bool" gui-text="merges" gui-description="Requires enabled 'Remove collinear overlapping lines' option (will auto-enable)">false</param>
|
||||
<label appearance="header">Intersection points</label>
|
||||
<param name="visualize_self_intersections" type="bool" gui-text="self-intersecting path points" gui-description="Will put into background (z-Index) by global intersection points and trimmed lines (if enabled)">false</param>
|
||||
<param name="visualize_global_intersections" type="bool" gui-text="global intersection points" gui-description="Will also contain self-intersecting points! Global intersections will only show if 'Draw trimmed lines' is enabled!">false</param>
|
||||
</page>
|
||||
<page name="tab_trimming" gui-text="Trimming">
|
||||
<label appearance="header">General trimming settings</label>
|
||||
<param name="trimming_path_types" type="optiongroup" appearance="combo" gui-text="Trimming selection" gui-description="Process open paths by other open paths, closed paths by other closed paths, or all paths by all other paths. This selection does not apply for paths which intersect themselves!">
|
||||
<option value="both">all:all paths</option>
|
||||
<option value="open_paths">open:open paths</option>
|
||||
<option value="closed_paths">closed:closed paths</option>
|
||||
</param>
|
||||
<param name="draw_trimmed" type="bool" gui-text="Draw trimmed lines">false</param>
|
||||
<param name="combine_nonintersects" type="bool" gui-text="Chain + combine non-intersected lines" gui-description="This will colorize all paths segments which were not intersected ('non-intersected lines'). If the whole path was not intersected at all, it will get another color ('non-intersected paths').">true</param>
|
||||
<param name="remove_trim_duplicates" type="bool" gui-text="Remove duplicate trim lines" gui-description="Has no effect if option 'Filter collinear overlapping lines' is enabled because duplicates get pre-filtered.">true</param>
|
||||
<param name="reverse_trim_removal_order" type="bool" gui-text="Reverse trim line removal order" gui-description="Reverses the order of removal. Relevant for keeping certain styles of elements">false</param>
|
||||
<param name="bezier_trimming" type="bool" gui-text="Trim original beziers (not working yet)" gui-description="If enabled we try to split the original bezier paths at the intersections points by finding the correct bezier segments and calculating t parameters from trimmed sub split lines. Not working yet. Will just print debug info if debug is enabled.">true</param>
|
||||
<label appearance="header">Bentley-Ottmann sweep line settings</label>
|
||||
<param name="bent_ott_use_ignore_segment_endings" type="bool" gui-text="Ignore segment endings" gui-description="Whether to ignore intersections of line segments when both their end points form the intersection point">true</param>
|
||||
<param name="bent_ott_use_debug" type="bool" gui-text="Debug">false</param>
|
||||
<param name="bent_ott_use_verbose" type="bool" gui-text="Verbose">false</param>
|
||||
<param name="bent_ott_use_paranoid" type="bool" gui-text="Paranoid checks">false</param>
|
||||
<param name="bent_ott_use_vertical" type="bool" gui-text="Support vertical segments">true</param>
|
||||
<param name="bent_ott_number_type" type="optiongroup" appearance="combo" gui-text="Number type">
|
||||
<option value="native">native (default)</option>
|
||||
<option value="numpy">numpy</option>
|
||||
</param>
|
||||
</page>
|
||||
<page name="tab_colors" gui-text="Colors">
|
||||
<hbox>
|
||||
<vbox>
|
||||
<label appearance="header">Sub split lines</label>
|
||||
<param name="color_subsplit" type="color" appearance="colorbutton" gui-text="sub split lines">1630897151</param>
|
||||
<label appearance="header">Path structure</label>
|
||||
<param name="color_relative" type="color" appearance="colorbutton" gui-text="relative cmd paths">3419879935</param>
|
||||
<param name="color_absolute" type="color" appearance="colorbutton" gui-text="absolute cmd paths">1592519679</param>
|
||||
<param name="color_mixed" type="color" appearance="colorbutton" gui-text="mixed cmd paths" gui-description="combined relative and absolute">3351636735</param>
|
||||
<param name="color_polyline" type="color" appearance="colorbutton" gui-text="polyline paths">4289703935</param>
|
||||
<param name="color_bezier" type="color" appearance="colorbutton" gui-text="bezier paths">258744063</param>
|
||||
<param name="color_opened" type="color" appearance="colorbutton" gui-text="opened paths">4012452351</param>
|
||||
<param name="color_closed" type="color" appearance="colorbutton" gui-text="closed paths">2330080511</param>
|
||||
</vbox>
|
||||
<separator/>
|
||||
<vbox>
|
||||
<label appearance="header">Duplicates and merges</label>
|
||||
<param name="color_duplicates" type="color" appearance="colorbutton" gui-text="duplicates" gui-description="Color for overlapping line segments / duplicated lines)">897901823</param>
|
||||
<param name="color_merges" type="color" appearance="colorbutton" gui-text="merges" gui-description="Color for replaced merges">869366527</param>
|
||||
<label appearance="header">Intersections</label>
|
||||
<param name="color_self_intersecting_paths" type="color" appearance="colorbutton" gui-text="self-intersecting paths">2593756927</param>
|
||||
<param name="color_self_intersections" type="color" appearance="colorbutton" gui-text="self-intersecting paths points">6320383</param>
|
||||
<param name="color_global_intersections" type="color" appearance="colorbutton" gui-text="global intersection points">4239343359</param>
|
||||
<label appearance="header">Trimming</label>
|
||||
<param name="color_trimmed" type="color" appearance="colorbutton" gui-text="trimmed lines">3227634687</param>
|
||||
<param name="color_combined" type="color" appearance="colorbutton" gui-text="non-intersected lines" gui-description="Colorize non-trimmed lines differently than the trimmed ones. Does not apply if 'Original style for trimmed lines' is enabled">1923076095</param>
|
||||
<param name="color_nonintersected" type="color" appearance="colorbutton" gui-text="non-intersected paths" gui-description="Colorize the complete path in case it does not contain any trim. Does not apply if 'Original style for trimmed lines' is enabled">3045284607</param>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</page>
|
||||
</param>
|
||||
</page>
|
||||
<page name="tab_tips" gui-text="Tips">
|
||||
<label xml:space="preserve"> - Helps to find duplicate lines and to visualize intersections
|
||||
- Works for self-intersecting paths too
|
||||
- Uses Bentley-Ottmann algorithm to detect intersections
|
||||
- Allows to separate different contour types by colors
|
||||
<label xml:space="preserve"> - Allows to separate different contour types by colors
|
||||
- Finds overlapping / collinear / (self-)intersecting
|
||||
(using Bentley-Ottmann algorithm) lines
|
||||
- Works with paths which have Live Path Effects (LPE)
|
||||
- Finds overlapping / collinear lines
|
||||
|
||||
Tips:
|
||||
- If nothings is selected, the whole document will be processed, regardless of groups. In contrast, if you made a custom selection, check to handle or not to handle groups.
|
||||
|
@ -3,16 +3,21 @@
|
||||
'''
|
||||
Extension for InkScape 1.0+
|
||||
- WARNING: HORRIBLY SLOW CODE. PLEASE HELP TO MAKE IT USEFUL FOR LARGE AMOUNT OF PATHS
|
||||
- add options:
|
||||
- replace trimmed paths by bezier paths (calculating lengths and required t parameter)
|
||||
- filter/remove overlapping/duplicates in
|
||||
- in original selection (not working bezier but for straight line segments!) We can use another extension for it
|
||||
- split bezier
|
||||
- ...
|
||||
- maybe option: convert abs path to rel path
|
||||
- maybe option: convert rel path to abs path
|
||||
replacedelement.path = replacedelement.path.to_absolute().to_superpath().to_path()
|
||||
- maybe option: break apart while keeping relative/absolute commands (more complex and not sure if we have a great advantage having this)
|
||||
- ToDo:
|
||||
- add more comments
|
||||
- add more debug output
|
||||
- add documentation at online page
|
||||
- add statistics about type counts and path lengths (before/after sub splitting/trimming)
|
||||
- add options:
|
||||
- replace trimmed paths by bezier paths (calculating lengths and required t parameter)
|
||||
- filter/remove overlapping/duplicates in
|
||||
- in original selection (not working bezier but for straight line segments!) We can use another extension for it
|
||||
- split bezier
|
||||
- ...
|
||||
- maybe option: convert abs path to rel path
|
||||
- maybe option: convert rel path to abs path
|
||||
replacedelement.path = replacedelement.path.to_absolute().to_superpath().to_path()
|
||||
- maybe option: break apart while keeping relative/absolute commands (more complex and not sure if we have a great advantage having this)
|
||||
|
||||
- important to notice
|
||||
- this algorithm might be really slow. Reduce flattening quality to speed up
|
||||
@ -68,10 +73,11 @@ from shapely import speedups
|
||||
if speedups.available:
|
||||
speedups.enable()
|
||||
|
||||
|
||||
idPrefixSubSplit = "subsplit"
|
||||
idPrefixTrimming = "shapely"
|
||||
intersectedVerb = "intersected"
|
||||
collinearVerb = "collinear"
|
||||
|
||||
EPS_M = 0.01
|
||||
|
||||
class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
@ -216,6 +222,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
selfIntersectionPointCircle.set('id', self.svg.get_unique_id('selfIntersectionPoint-'))
|
||||
selfIntersectionPointCircle.style = selfIntersectionPointStyle
|
||||
selfIntersectionGroup.add(selfIntersectionPointCircle)
|
||||
return selfIntersectionGroup
|
||||
|
||||
|
||||
def visualize_global_intersections(self, globalIntersectionPoints):
|
||||
@ -368,7 +375,10 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
def filter_collinear(self, lineArray):
|
||||
'''
|
||||
Loop through a set of lines and find + fiter all overlapping segments / duplicate segments
|
||||
finally returns a set of merged-like lines and a set of original items which should be dropped
|
||||
finally returns a set of merged-like lines and a set of original items which should be dropped.
|
||||
Based on the style of the algorithm we have no good influence on the z-index of the items because
|
||||
it is scanned by slope and point coordinates. That's why we have a more special
|
||||
'remove_trim_duplicates()' function for trimmed duplicates!
|
||||
'''
|
||||
input_set = []
|
||||
input_ids = []
|
||||
@ -463,10 +473,14 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
return output_set, dropped_ids
|
||||
|
||||
|
||||
def remove_duplicates(self, allTrimGroups):
|
||||
''' find duplicate lines in a given array [] of groups '''
|
||||
def remove_trim_duplicates(self, allTrimGroups):
|
||||
'''
|
||||
find duplicate lines in a given array [] of groups
|
||||
note: this function is similar to filter_collinear but we keep it because we have a 'reverse_trim_removal_order' option.
|
||||
We can use this option in some special situations where we work without the function 'filter_collinear()'.
|
||||
'''
|
||||
totalTrimPaths = []
|
||||
if self.options.reverse_removal_order is True:
|
||||
if self.options.reverse_trim_removal_order is True:
|
||||
allTrimGroups = allTrimGroups[::-1]
|
||||
for trimGroup in allTrimGroups:
|
||||
for element in trimGroup:
|
||||
@ -526,7 +540,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
self.msg("trim group {} has {} combinable segments:".format(trimGroup.get('id'), len(newPathData)))
|
||||
self.msg("{}".format(newPathData))
|
||||
combinedPath.path = Path(newPathData)
|
||||
if self.options.trimmed_style is False:
|
||||
if self.options.trimmed_style == "apply_from_trimmed":
|
||||
combinedPath.style = trimNonIntersectedStyle
|
||||
if totalIntersectionsAtPath == 0:
|
||||
combinedPath.style = nonTrimLineStyle
|
||||
@ -578,9 +592,10 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
|
||||
|
||||
def add_arguments(self, pars):
|
||||
pars.add_argument("--tab")
|
||||
pars.add_argument("--nb_main")
|
||||
pars.add_argument("--nb_settings_and_actions")
|
||||
|
||||
#Settings - General
|
||||
#Settings - General Input/Output
|
||||
pars.add_argument("--show_debug", type=inkex.Boolean, default=False, help="Show debug infos")
|
||||
pars.add_argument("--break_apart", type=inkex.Boolean, default=False, help="Break apart input paths into sub paths")
|
||||
pars.add_argument("--handle_groups", type=inkex.Boolean, default=False, help="Also looks for paths in groups which are in the current selection")
|
||||
@ -589,11 +604,15 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
pars.add_argument("--flatness", type=float, default=0.1, help="Minimum flatness = 0.001. The smaller the value the more fine segments you will get (quantization). Large values might destroy the line continuity.")
|
||||
pars.add_argument("--decimals", type=int, default=3, help="Accuracy for sub split lines / lines trimmed by shapely")
|
||||
pars.add_argument("--snap_tolerance", type=float, default=0.1, help="Snap tolerance for intersection points")
|
||||
pars.add_argument("--draw_subsplit", type=inkex.Boolean, default=False, help="Draw sub split lines (polylines)")
|
||||
pars.add_argument("--remove_subsplit_collinear", type=inkex.Boolean, default=True, help="Removes any duplicates by merging (multiple) overlapping line segments into longer lines. Not possible to apply for original paths because this routine does not support bezier type paths.")
|
||||
pars.add_argument("--keep_original_after_split_trim", type=inkex.Boolean, default=False, help="Keep original paths after sub splitting / trimming")
|
||||
#Settings - General Style
|
||||
pars.add_argument("--strokewidth", type=float, default=1.0, help="Stroke width (px)")
|
||||
pars.add_argument("--dotsize_intersections", type=int, default=30, help="Dot size (px) for self-intersecting and global intersection points")
|
||||
pars.add_argument("--removefillsetstroke", type=inkex.Boolean, default=False, help="Remove fill and define stroke for original paths")
|
||||
pars.add_argument("--bezier_trimming", type=inkex.Boolean, default=False, help="If true we try to use the calculated t parameters from intersection points to receive splitted bezier curves")
|
||||
pars.add_argument("--subsplit_style", default="default", help="Sub split line style")
|
||||
pars.add_argument("--trimmed_style", default="apply_from_trimmed", help="Trimmed line style")
|
||||
|
||||
#Scanning - Removing of original paths
|
||||
#Removing - Applying to original paths and sub split lines
|
||||
pars.add_argument("--remove_relative", type=inkex.Boolean, default=False, help="relative cmd")
|
||||
pars.add_argument("--remove_absolute", type=inkex.Boolean, default=False, help="absolute cmd")
|
||||
pars.add_argument("--remove_mixed", type=inkex.Boolean, default=False, help="mixed cmd (relative + absolute)")
|
||||
@ -602,8 +621,13 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
pars.add_argument("--remove_opened", type=inkex.Boolean, default=False, help="opened")
|
||||
pars.add_argument("--remove_closed", type=inkex.Boolean, default=False, help="closed")
|
||||
pars.add_argument("--remove_self_intersecting", type=inkex.Boolean, default=False, help="self-intersecting")
|
||||
#Removing - Applying to sub split lines only
|
||||
pars.add_argument("--filter_subsplit_collinear", type=inkex.Boolean, default=True, help="Removes any duplicates by merging (multiple) overlapping line segments into longer lines. Not possible to apply for original paths because this routine does not support bezier type paths.")
|
||||
pars.add_argument("--filter_subsplit_collinear_action", default="remove", help="What to do with collinear overlapping lines?")
|
||||
#Removing - Applying to original paths only
|
||||
pars.add_argument("--keep_original_after_split_trim", type=inkex.Boolean, default=False, help="Keep original paths after sub splitting / trimming")
|
||||
|
||||
#Scanning - Highlighting of original paths (and sub split lines)
|
||||
#Highlighting - Applying to original paths and sub split lines
|
||||
pars.add_argument("--highlight_relative", type=inkex.Boolean, default=False, help="relative cmd paths")
|
||||
pars.add_argument("--highlight_absolute", type=inkex.Boolean, default=False, help="absolute cmd paths")
|
||||
pars.add_argument("--highlight_mixed", type=inkex.Boolean, default=False, help="mixed cmd (relative + absolute) paths")
|
||||
@ -611,16 +635,21 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
pars.add_argument("--highlight_beziers", type=inkex.Boolean, default=False, help="bezier paths")
|
||||
pars.add_argument("--highlight_opened", type=inkex.Boolean, default=False, help="opened paths")
|
||||
pars.add_argument("--highlight_closed", type=inkex.Boolean, default=False, help="closed paths")
|
||||
#Highlighting - Applying to sub split lines only
|
||||
pars.add_argument("--draw_subsplit", type=inkex.Boolean, default=False, help="Draw sub split lines (polylines)")
|
||||
pars.add_argument("--highlight_duplicates", type=inkex.Boolean, default=False, help="duplicates (only applies to sub split lines)")
|
||||
pars.add_argument("--highlight_merges", type=inkex.Boolean, default=False, help="merges (only applies to sub split lines)")
|
||||
#Highlighting - Intersection points
|
||||
pars.add_argument("--highlight_self_intersecting", type=inkex.Boolean, default=False, help="self-intersecting paths")
|
||||
pars.add_argument("--visualize_self_intersections", type=inkex.Boolean, default=False, help="self-intersecting path points")
|
||||
pars.add_argument("--visualize_global_intersections", type=inkex.Boolean, default=False, help="global intersection points")
|
||||
|
||||
#Settings - Trimming of sub split lines
|
||||
#Trimming - General trimming settings
|
||||
pars.add_argument("--draw_trimmed", type=inkex.Boolean, default=False, help="Draw trimmed lines")
|
||||
pars.add_argument("--combine_nonintersects", type=inkex.Boolean, default=True, help="Combine non-intersected lines")
|
||||
pars.add_argument("--remove_duplicates", type=inkex.Boolean, default=True, help="Remove duplicate trim lines")
|
||||
pars.add_argument("--reverse_removal_order", type=inkex.Boolean, default=False, help="Reverses the order of removal. Relevant for keeping certain styles of elements")
|
||||
|
||||
pars.add_argument("--remove_trim_duplicates", type=inkex.Boolean, default=True, help="Remove duplicate trim lines")
|
||||
pars.add_argument("--reverse_trim_removal_order", type=inkex.Boolean, default=False, help="Reverses the order of removal. Relevant for keeping certain styles of elements")
|
||||
#Trimming - Bentley-Ottmann sweep line settings
|
||||
pars.add_argument("--bent_ott_use_ignore_segment_endings", type=inkex.Boolean, default=True, help="Whether to ignore intersections of line segments when both their end points form the intersection point")
|
||||
pars.add_argument("--bent_ott_use_debug", type=inkex.Boolean, default=False)
|
||||
pars.add_argument("--bent_ott_use_verbose", type=inkex.Boolean, default=False)
|
||||
@ -628,28 +657,24 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
pars.add_argument("--bent_ott_use_vertical", type=inkex.Boolean, default=True)
|
||||
pars.add_argument("--bent_ott_number_type", default="native")
|
||||
|
||||
#Style - General Style
|
||||
pars.add_argument("--strokewidth", type=float, default=1.0, help="Stroke width (px)")
|
||||
pars.add_argument("--dotsize_intersections", type=int, default=30, help="Dot size (px) for self-intersecting and global intersection points")
|
||||
pars.add_argument("--removefillsetstroke", type=inkex.Boolean, default=False, help="Remove fill and define stroke for original paths")
|
||||
pars.add_argument("--bezier_trimming", type=inkex.Boolean, default=False, help="If true we try to use the calculated t parameters from intersection points to receive splitted bezier curves")
|
||||
pars.add_argument("--subsplit_style", default="default", help="Sub split line style")
|
||||
pars.add_argument("--trimmed_style", default="apply_from_trimmed", help="Trimmed line style")
|
||||
|
||||
#Style - Scanning Colors (Highlighting things)
|
||||
pars.add_argument("--color_subsplit", type=Color, default='1630897151', help="sub split lines")
|
||||
#Colors
|
||||
pars.add_argument("--color_subsplit", type=Color, default='1630897151', help="sub split lines")
|
||||
#Colors - path structure
|
||||
pars.add_argument("--color_relative", type=Color, default='3419879935', help="relative cmd paths")
|
||||
pars.add_argument("--color_absolute", type=Color, default='1592519679', help="absolute cmd paths")
|
||||
pars.add_argument("--color_mixed", type=Color, default='3351636735', help="mixed cmd (relative + absolute) paths")
|
||||
pars.add_argument("--color_mixed", type=Color, default='3351636735', help="mixed cmd (relative + absolute) paths")
|
||||
pars.add_argument("--color_polyline", type=Color, default='4289703935', help="polyline paths")
|
||||
pars.add_argument("--color_bezier", type=Color, default='258744063', help="bezier paths")
|
||||
pars.add_argument("--color_opened", type=Color, default='4012452351', help="opened paths")
|
||||
pars.add_argument("--color_closed", type=Color, default='2330080511', help="closed paths")
|
||||
#Colors - duplicates and merges
|
||||
pars.add_argument("--color_duplicates", type=Color, default='897901823', help="duplicates")
|
||||
pars.add_argument("--color_merges", type=Color, default='869366527', help="merges")
|
||||
#Colors - intersections
|
||||
pars.add_argument("--color_self_intersecting_paths", type=Color, default='2593756927', help="self-intersecting paths")
|
||||
pars.add_argument("--color_self_intersections", type=Color, default='6320383', help="self-intersecting path points")
|
||||
pars.add_argument("--color_global_intersections", type=Color, default='4239343359', help="global intersection points")
|
||||
|
||||
#Style - Trimming Colors
|
||||
#Colors - trimming
|
||||
pars.add_argument("--color_trimmed", type=Color, default='1923076095', help="trimmed lines")
|
||||
pars.add_argument("--color_combined", type=Color, default='3227634687', help="non-intersected lines")
|
||||
pars.add_argument("--color_nonintersected", type=Color, default='3045284607', help="non-intersected paths")
|
||||
@ -662,6 +687,18 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
if so.break_apart is True and so.show_debug is True:
|
||||
self.msg("Warning: 'Break apart input' setting is enabled. Cannot check accordingly for relative, absolute or mixed paths for breaked elements (they are always absolute)!")
|
||||
|
||||
#some configuration dependecies
|
||||
if so.highlight_self_intersecting is True or \
|
||||
so.highlight_duplicates is True or \
|
||||
so.highlight_merges is True:
|
||||
so.draw_subsplit = True
|
||||
|
||||
if so.highlight_merges is True:
|
||||
so.filter_subsplit_collinear = True
|
||||
|
||||
if so.filter_subsplit_collinear_action == "separate_group":
|
||||
so.draw_subsplit = True
|
||||
|
||||
#some constant stuff / styles
|
||||
relativePathStyle = {'stroke': str(so.color_relative), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
absolutePathStyle = {'stroke': str(so.color_absolute), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
@ -670,6 +707,8 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
bezierPathStyle = {'stroke': str(so.color_bezier), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
openPathStyle = {'stroke': str(so.color_opened), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
closedPathStyle = {'stroke': str(so.color_closed), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
duplicatesPathStyle = {'stroke': str(so.color_duplicates), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
mergesPathStyle = {'stroke': str(so.color_merges), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
selfIntersectingPathStyle = {'stroke': str(so.color_self_intersecting_paths), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
basicSubSplitLineStyle = {'stroke': str(so.color_subsplit), 'fill': 'none', 'stroke-width': so.strokewidth}
|
||||
|
||||
@ -782,7 +821,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
subSplitId = "{}-{}-{}".format(idPrefixSubSplit, originalPathId, i)
|
||||
line = inkex.PathElement(id=subSplitId)
|
||||
#apply line path with composed negative transform from parent element
|
||||
line.attrib['d'] = 'M {},{} L {},{}'.format(x1, y1, x2, y2) #we set the path of trimLine using 'd' attribute because if we use trimLine.path the decimals get cut off unwantedly
|
||||
line.attrib['d'] = 'M {},{} L {},{}'.format(x1, y1, x2, y2) #we set the path of Line using 'd' attribute because if we use trimLine.path the decimals get cut off unwantedly
|
||||
#line.path = [['M', [x1, y1]], ['L', [x2, y2]]]
|
||||
if pathElement.getparent() != self.svg.root and pathElement.getparent() != None:
|
||||
line.path = line.path.transform(-pathElement.getparent().composed_transform())
|
||||
@ -836,15 +875,14 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
isSelfIntersecting = True
|
||||
if so.show_debug is True:
|
||||
self.msg("{} in {} intersects itself with {} intersections!".format(subSplitId, originalPathId, len(selfIntersectionPoints)))
|
||||
if so.draw_subsplit is True:
|
||||
if so.highlight_self_intersecting is True:
|
||||
for subSplitLine in subSplitLineGroup:
|
||||
subSplitLine.style = selfIntersectingPathStyle #adjusts line color
|
||||
if so.highlight_self_intersecting is True:
|
||||
for subSplitLine in subSplitLineGroup:
|
||||
subSplitLine.style = selfIntersectingPathStyle #adjusts line color
|
||||
#delete cosmetic sub split lines if desired
|
||||
if so.remove_self_intersecting:
|
||||
subSplitLineGroup.delete()
|
||||
if so.visualize_self_intersections is True: #draw points (circles)
|
||||
self.visualize_self_intersections(pathElement, selfIntersectionPoints)
|
||||
selfIntersectionGroup = self.visualize_self_intersections(pathElement, selfIntersectionPoints)
|
||||
|
||||
#delete self-intersecting sub split lines and orginal paths
|
||||
if so.remove_self_intersecting:
|
||||
@ -894,31 +932,81 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
if so.show_debug is True:
|
||||
self.msg("sub split line count: {}".format(len(subSplitLineArray)))
|
||||
|
||||
if so.remove_subsplit_collinear is True:
|
||||
'''
|
||||
check for collinear lines and apply filters to remove or regroup and to restyle them
|
||||
Run this action only if one of the options requires it (to avoid useless calculation cycles)
|
||||
'''
|
||||
if so.filter_subsplit_collinear is True or \
|
||||
so.highlight_duplicates is True or \
|
||||
so.highlight_merges is True:
|
||||
if so.show_debug is True: self.msg("filtering collinear overlapping lines / duplicate lines")
|
||||
if len(subSplitLineArray) > 0:
|
||||
output_set, dropped_ids = self.filter_collinear(subSplitLineArray)
|
||||
deleteIndices = []
|
||||
deleteIndice = 0
|
||||
for subSplitLine in subSplitLineArray:
|
||||
ssl_id = subSplitLine.get('id')
|
||||
if ssl_id in dropped_ids:
|
||||
ssl_parent = subSplitLine.getparent()
|
||||
subSplitLine.delete() #delete the line
|
||||
|
||||
#and delete the containg group if empty
|
||||
if ssl_parent is not None and len(ssl_parent) == 0:
|
||||
if self.options.show_debug is True:
|
||||
self.msg("Deleting group {}".format(ssl_parent.get('id')))
|
||||
ssl_parent.delete()
|
||||
# and now we replace the overlapping items with the new merged output
|
||||
'''
|
||||
Replace the overlapping items with the new merged output
|
||||
'''
|
||||
for output in output_set:
|
||||
if output['id'] == subSplitLine.attrib['id']:
|
||||
#self.msg(output['p0'])
|
||||
subSplitLine.attrib['d'] = 'M {},{} L {},{}'.format(
|
||||
output['p0'][0], output['p0'][1], output['p1'][0], output['p1'][1]) #we set the path of trimLine using 'd' attribute because if we use trimLine.path the decimals get cut off unwantedly
|
||||
originalSplitLinePath = subSplitLine.path
|
||||
output_line = 'M {},{} L {},{}'.format(
|
||||
output['p0'][0], output['p0'][1], output['p1'][0], output['p1'][1])
|
||||
output_line_reversed = 'M {},{} L {},{}'.format(
|
||||
output['p1'][0], output['p1'][1], output['p0'][0], output['p0'][1])
|
||||
subSplitLine.attrib['d'] = output_line #we set the path using 'd' attribute because if we use trimLine.path the decimals get cut off unwantedly
|
||||
mergedSplitLinePath = subSplitLine.path
|
||||
mergedSplitLinePathReversed = Path(output_line_reversed)
|
||||
#subSplitLine.path = [['M', output['p0']], ['L', output['p1']]]
|
||||
#self.msg("composed_transform = {}".format(output['composed_transform']))
|
||||
#subSplitLine.transform = Transform(-output['composed_transform']) * subSplitLine.transform
|
||||
|
||||
subSplitLine.path = subSplitLine.path.transform(-output['composed_transform'])
|
||||
if so.highlight_merges is True:
|
||||
if originalSplitLinePath != mergedSplitLinePath and \
|
||||
originalSplitLinePath != mergedSplitLinePathReversed: #if the path changed we are going to highlight it
|
||||
subSplitLine.style = mergesPathStyle
|
||||
|
||||
|
||||
'''
|
||||
Delete or move sub split lines which are overlapping
|
||||
'''
|
||||
ssl_id = subSplitLine.get('id')
|
||||
if ssl_id in dropped_ids:
|
||||
if so.highlight_duplicates is True:
|
||||
subSplitLine.style = duplicatesPathStyle
|
||||
|
||||
if so.filter_subsplit_collinear is True:
|
||||
ssl_parent = subSplitLine.getparent()
|
||||
if so.filter_subsplit_collinear_action == "remove":
|
||||
if self.options.show_debug is True:
|
||||
self.msg("Deleting sub split line {}".format(subSplitLine.get('id')))
|
||||
subSplitLine.delete() #delete the line from XML tree
|
||||
deleteIndices.append(deleteIndice) #store this id to remove it from stupid subSplitLineArray later
|
||||
elif so.filter_subsplit_collinear_action == "separate_group":
|
||||
if self.options.show_debug is True:
|
||||
self.msg("Moving sub split line {}".format(subSplitLine.get('id')))
|
||||
originalPathId = subSplitLine.attrib['originalPathId']
|
||||
collinearGroupId = '{}-{}'.format(collinearVerb, originalPathId)
|
||||
originalPathElement = self.svg.getElementById(originalPathId)
|
||||
collinearGroup = self.find_group(collinearGroupId)
|
||||
if collinearGroup is None:
|
||||
collinearGroup = originalPathElement.getparent().add(inkex.Group(id=collinearGroupId))
|
||||
collinearGroup.append(subSplitLine) #move to that group
|
||||
#and delete the containg group if empty (can happen in "remove" or "separate_group" constellation
|
||||
if ssl_parent is not None and len(ssl_parent) == 0:
|
||||
if self.options.show_debug is True:
|
||||
self.msg("Deleting group {}".format(ssl_parent.get('id')))
|
||||
ssl_parent.delete()
|
||||
|
||||
deleteIndice += 1 #end the loop by incrementing +1
|
||||
|
||||
#shrink the sub split line array to kick out all unrequired indices
|
||||
for deleteIndice in sorted(deleteIndices, reverse=True):
|
||||
if self.options.show_debug is True:
|
||||
self.msg("Deleting index {} from subSplitLineArray".format(deleteIndice))
|
||||
del subSplitLineArray[deleteIndice]
|
||||
|
||||
'''
|
||||
now we intersect the sub split lines to find the global intersection points using Bentley-Ottmann algorithm (contains self-intersections too!)
|
||||
@ -956,7 +1044,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
for subSplitLine in subSplitLineArray:
|
||||
csp = subSplitLine.path.to_arrays()
|
||||
lineString = [(csp[0][1][0], csp[0][1][1]), (csp[1][1][0], csp[1][1][1])]
|
||||
if so.remove_duplicates is True:
|
||||
if so.remove_trim_duplicates is True:
|
||||
if lineString not in allSubSplitLineStrings:
|
||||
allSubSplitLineStrings.append(lineString)
|
||||
else:
|
||||
@ -996,9 +1084,9 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
|
||||
if so.show_debug is True: self.msg("trimming beziers - not working yet")
|
||||
self.trim_bezier(allTrimGroups)
|
||||
|
||||
if so.remove_duplicates is True:
|
||||
if so.remove_trim_duplicates is True:
|
||||
if so.show_debug is True: self.msg("checking for duplicate trim lines and deleting them")
|
||||
self.remove_duplicates(allTrimGroups)
|
||||
self.remove_trim_duplicates(allTrimGroups)
|
||||
|
||||
if so.combine_nonintersects is True:
|
||||
if so.show_debug is True: self.msg("glueing together all non-intersected sub split lines to larger path structures again (cleaning up)")
|
||||
|
Reference in New Issue
Block a user