This commit is contained in:
Mario Voigt 2021-07-04 10:58:20 +02:00
commit fa165a5717
4 changed files with 310 additions and 180 deletions

View File

@ -33,33 +33,15 @@ class AboutUpgradeMightyScape(inkex.EffectExtension):
try: try:
localCommit = local_repo.head.commit localCommit = local_repo.head.commit
remote_repo = git.remote.Remote(local_repo, 'origin') remote_repo = git.remote.Remote(local_repo, 'origin')
remoteCommit = remote_repo.fetch()[0].commit remoteCommit = remote_repo.fetch()[0].commit
self.msg("Latest remote commit is: " + str(remoteCommit)[:7])
authors = [] authors = []
# for every remote commit # for every remote commit
while remoteCommit.hexsha != localCommit.hexsha: while remoteCommit.hexsha != localCommit.hexsha:
authors.append(remoteCommit.author.email) authors.append(remoteCommit.author.email)
remoteCommit = remoteCommit.parents[0] remoteCommit = remoteCommit.parents[0]
#local_commits = list(local_repo.iter_commits("master", max_count=5))
local_commits = list(local_repo.iter_commits("master"))
self.msg("Local commit id is: " + str(localCommit)[:7])
self.msg("Latest remote commit is: " + str(remoteCommit)[:7])
self.msg("There are {} local commits at the moment.".format(len(local_commits)))
localCommitList = []
for local_commit in local_commits:
localCommitList.append(local_commit)
#localCommitList.reverse()
self.msg("*"*40)
self.msg("Latest 10 local commits are:")
for i in range(0, 10):
self.msg("{} | {} : {}".format(
datetime.utcfromtimestamp(localCommitList[i].committed_date).strftime('%Y-%m-%d %H:%M:%S'),
localCommitList[i].name_rev[:7],
localCommitList[i].message.strip())
)
#self.msg(" - {}: {}".format(localCommitList[i].newhexsha[:7], localCommitList[i].message))
self.msg("*"*40)
if localCommit.hexsha != remoteCommit.hexsha: if localCommit.hexsha != remoteCommit.hexsha:
ssh_executable = 'git' ssh_executable = 'git'
with local_repo.git.custom_environment(GIT_SSH=ssh_executable): with local_repo.git.custom_environment(GIT_SSH=ssh_executable):
@ -126,6 +108,26 @@ class AboutUpgradeMightyScape(inkex.EffectExtension):
remotes.append("https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X.git") #main remotes.append("https://gitea.fablabchemnitz.de/FabLab_Chemnitz/mightyscape-1.X.git") #main
remotes.append("https://github.com/vmario89/mightyscape-1.X.git") #copy/second remote remotes.append("https://github.com/vmario89/mightyscape-1.X.git") #copy/second remote
localCommit = local_repo.head.commit
#local_commits = list(local_repo.iter_commits("master", max_count=5))
localCommits = list(local_repo.iter_commits("master"))
self.msg("Local commit id is: " + str(localCommit)[:7])
self.msg("There are {} local commits at the moment.".format(len(localCommits)))
localCommitList = []
for local_commit in localCommits:
localCommitList.append(localCommit)
#localCommitList.reverse()
self.msg("*"*40)
self.msg("Latest 10 local commits are:")
for i in range(0, 10):
self.msg("{} | {} : {}".format(
datetime.utcfromtimestamp(localCommitList[i].committed_date).strftime('%Y-%m-%d %H:%M:%S'),
localCommitList[i].name_rev[:7],
localCommitList[i].message.strip())
)
#self.msg(" - {}: {}".format(localCommitList[i].newhexsha[:7], localCommitList[i].message))
self.msg("*"*40)
#finally run the update #finally run the update
success = self.update(local_repo, remotes[0]) success = self.update(local_repo, remotes[0])
if success is False: #try the second remote if first failed if success is False: #try the second remote if first failed

View File

@ -59,10 +59,6 @@ class AnimateOrder(inkex.EffectExtension):
target_html = os.path.join(extension_dir, "animate_order.html") target_html = os.path.join(extension_dir, "animate_order.html")
if os.path.exists(target_html) is False:
inkex.utils.debug("Error. Target file does not exist!")
exit(1)
docTitle = self.document.getroot().get("{http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}docname") docTitle = self.document.getroot().get("{http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}docname")
if docTitle is None: if docTitle is None:
title = "Animate Order - Vivus JS" title = "Animate Order - Vivus JS"
@ -96,6 +92,10 @@ class AnimateOrder(inkex.EffectExtension):
print( ' </body>' , file=text_file) print( ' </body>' , file=text_file)
print( '</html>' , file=text_file) print( '</html>' , file=text_file)
if os.path.exists(target_html) is False:
inkex.utils.debug("Error. Target file does not exist!")
exit(1)
#now open firefox #now open firefox
args = [self.options.browser, target_html] args = [self.options.browser, target_html]
try: try:

View File

@ -2,23 +2,34 @@
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Contour Scanner And Trimmer</name> <name>Contour Scanner And Trimmer</name>
<id>fablabchemnitz.de.contour_scanner_and_trimmer</id> <id>fablabchemnitz.de.contour_scanner_and_trimmer</id>
<param name="tab" type="notebook"> <param name="nb_main" type="notebook">
<page name="tab_settings" gui-text="Settings"> <page name="tab_settings_and_actions" gui-text="Settings and Actions">
<label appearance="header">General</label> <param name="nb_settings_and_actions" type="notebook">
<param name="show_debug" type="bool" gui-text="Show debug infos">false</param> <page name="tab_settings" gui-text="Settings">
<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> <label appearance="header">General input/output</label>
<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="show_debug" type="bool" gui-text="Show debug infos">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="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="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="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="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="flattenbezier" type="bool" gui-text="Quantization (flatten bezier curves to polylines)" gui-description="Convert bezier curves to polylines.">true</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="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="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="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="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="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>
</page> <label appearance="header">General style</label>
<page name="tab_scanning" gui-text="Scanning and Trimming"> <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>
<hbox> <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>
<vbox> <param name="removefillsetstroke" type="bool" gui-text="Remove fill and define stroke" gui-description="Modifies original path style">false</param>
<label appearance="header">Removing Original Paths</label> <param name="subsplit_style" type="optiongroup" appearance="combo" gui-text="Sub split line style">
<option value="default">Use default sub split style</option>
<option value="apply_from_highlightings">Apply highlighting styles</option>
<option value="apply_from_original">Apply original path styles</option>
</param>
<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>
</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_relative" type="bool" gui-text="relative cmd">false</param>
<param name="remove_absolute" type="bool" gui-text="absolute 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_mixed" type="bool" gui-text="mixed cmd" gui-description="combined relative and absolute">false</param>
@ -27,22 +38,35 @@
<param name="remove_opened" type="bool" gui-text="opened">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_closed" type="bool" gui-text="closed">false</param>
<param name="remove_self_intersecting" type="bool" gui-text="self-intersecting">false</param> <param name="remove_self_intersecting" type="bool" gui-text="self-intersecting">false</param>
<separator/> <label appearance="header">Applying to sub split lines only</label>
<label appearance="header">Highlighting</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="highlight_relative" type="bool" gui-text="relative cmd paths">false</param> <param name="filter_subsplit_collinear_action" type="optiongroup" appearance="combo" gui-text="What to do with collinear overlapping lines?">
<param name="highlight_absolute" type="bool" gui-text="absolute cmd paths">false</param> <option value="remove">remove</option>
<param name="highlight_mixed" type="bool" gui-text="mixed cmd paths" gui-description="combined relative and absolute">false</param> <option value="separate_group">put to separate group</option>
<param name="highlight_polylines" type="bool" gui-text="polyline paths">false</param> </param>
<param name="highlight_beziers" type="bool" gui-text="bezier paths">false</param> <label appearance="header">Applying to original paths only</label>
<param name="highlight_opened" type="bool" gui-text="opened paths">false</param> <param name="keep_original_after_split_trim" type="bool" gui-text="Keep original paths after sub splitting / trimming">false</param>
<param name="highlight_closed" type="bool" gui-text="closed paths">false</param> </page>
<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> <page name="tab_highlighting" gui-text="Highlighting">
<param name="visualize_self_intersections" type="bool" gui-text="self-intersecting path points">false</param> <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> <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> </page>
<separator/> <page name="tab_trimming" gui-text="Trimming">
<vbox> <label appearance="header">General trimming settings</label>
<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!"> <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="both">all:all paths</option>
<option value="open_paths">open:open paths</option> <option value="open_paths">open:open paths</option>
@ -50,11 +74,11 @@
</param> </param>
<param name="draw_trimmed" type="bool" gui-text="Draw trimmed lines">false</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="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="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_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="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="remove_subsplit_after_trimming" type="bool" gui-text="Remove sub split lines after trimming" gui-description="Recommended if option 'Filter collinear overlapping lines' is enabled">true</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> <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>
<param name="keep_original_after_trim" type="bool" gui-text="Keep original paths after trimming">false</param> <label appearance="header">Bentley-Ottmann sweep line settings</label>
<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_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_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_verbose" type="bool" gui-text="Verbose">false</param>
@ -64,48 +88,44 @@
<option value="native">native (default)</option> <option value="native">native (default)</option>
<option value="numpy">numpy</option> <option value="numpy">numpy</option>
</param> </param>
</vbox> </page>
</hbox> <page name="tab_colors" gui-text="Colors">
</page> <hbox>
<page name="tab_style" gui-text="Style"> <vbox>
<hbox> <label appearance="header">Sub split lines</label>
<vbox> <param name="color_subsplit" type="color" appearance="colorbutton" gui-text="sub split lines">1630897151</param>
<label appearance="header">Scanning Colors</label> <label appearance="header">Path structure</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_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_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_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_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_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_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_closed" type="color" appearance="colorbutton" gui-text="closed paths">2330080511</param> </vbox>
<param name="color_self_intersecting_paths" type="color" appearance="colorbutton" gui-text="self-intersecting paths">2593756927</param> <separator/>
<param name="color_self_intersections" type="color" appearance="colorbutton" gui-text="self-intersecting paths points">6320383</param> <vbox>
<param name="color_global_intersections" type="color" appearance="colorbutton" gui-text="global intersection points">4239343359</param> <label appearance="header">Duplicates and merges</label>
</vbox> <param name="color_duplicates" type="color" appearance="colorbutton" gui-text="duplicates" gui-description="Color for overlapping line segments / duplicated lines)">897901823</param>
<separator/> <param name="color_merges" type="color" appearance="colorbutton" gui-text="merges" gui-description="Color for replaced merges">869366527</param>
<vbox> <label appearance="header">Intersections</label>
<label appearance="header">Trimming Colors</label> <param name="color_self_intersecting_paths" type="color" appearance="colorbutton" gui-text="self-intersecting paths">2593756927</param>
<param name="color_trimmed" type="color" appearance="colorbutton" gui-text="trimmed lines">3227634687</param> <param name="color_self_intersections" type="color" appearance="colorbutton" gui-text="self-intersecting paths points">6320383</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_global_intersections" type="color" appearance="colorbutton" gui-text="global intersection points">4239343359</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">Trimming</label>
<label appearance="header">General Style</label> <param name="color_trimmed" type="color" appearance="colorbutton" gui-text="trimmed lines">3227634687</param>
<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="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="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="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>
<param name="removefillsetstroke" type="bool" gui-text="Remove fill and define stroke" gui-description="Modifies original path style">false</param> </vbox>
<param name="apply_style_to_subsplits" type="bool" gui-text="Highlighting styles for sub split lines" gui-description="Apply highlighting styles to sub split lines.">true</param> </hbox>
<param name="apply_style_to_trimmed" type="bool" gui-text="Original style for trimmed lines" gui-description="Apply original path style to trimmed lines.">true</param> </page>
</param>
</vbox>
</hbox>
</page> </page>
<page name="tab_tips" gui-text="Tips"> <page name="tab_tips" gui-text="Tips">
<label xml:space="preserve"> - Helps to find duplicate lines and to visualize intersections <label xml:space="preserve"> - Allows to separate different contour types by colors
- Works for self-intersecting paths too - Finds overlapping / collinear / (self-)intersecting
- Uses Bentley-Ottmann algorithm to detect intersections (using Bentley-Ottmann algorithm) lines
- Allows to separate different contour types by colors
- Works with paths which have Live Path Effects (LPE) - Works with paths which have Live Path Effects (LPE)
- Does not find overlapping colinear lines (sweep line algorithm does not intersect them)
Tips: 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. - 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.

View File

@ -3,16 +3,22 @@
''' '''
Extension for InkScape 1.0+ Extension for InkScape 1.0+
- WARNING: HORRIBLY SLOW CODE. PLEASE HELP TO MAKE IT USEFUL FOR LARGE AMOUNT OF PATHS - WARNING: HORRIBLY SLOW CODE. PLEASE HELP TO MAKE IT USEFUL FOR LARGE AMOUNT OF PATHS
- add options: - ToDo:
- replace trimmed paths by bezier paths (calculating lengths and required t parameter) - add more comments
- filter/remove overlapping/duplicates in - add more debug output
- in original selection (not working bezier but for straight line segments!) We can use another extension for it - add documentation at online page
- split bezier - add statistics about type counts and path lengths (before/after sub splitting/trimming)
- ... - add options:
- maybe option: convert abs path to rel path - replace trimmed paths by bezier paths (calculating lengths and required t parameter)
- maybe option: convert rel path to abs path - filter/remove overlapping/duplicates in
replacedelement.path = replacedelement.path.to_absolute().to_superpath().to_path() - in original selection (not working bezier but for straight line segments!) We can use another extension for it
- maybe option: break apart while keeping relative/absolute commands (more complex and not sure if we have a great advantage having this) - 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)
- note: running this extension might leave some empty parent groups in some circumstances. run the clean groups extension separately to fix that
- important to notice - important to notice
- this algorithm might be really slow. Reduce flattening quality to speed up - this algorithm might be really slow. Reduce flattening quality to speed up
@ -47,7 +53,7 @@ Extension for InkScape 1.0+
Author: Mario Voigt / FabLab Chemnitz Author: Mario Voigt / FabLab Chemnitz
Mail: mario.voigt@stadtfabrikanten.org Mail: mario.voigt@stadtfabrikanten.org
Date: 09.08.2020 (extension originally called "Contour Scanner") Date: 09.08.2020 (extension originally called "Contour Scanner")
Last patch: 22.06.2021 Last patch: 24.06.2021
License: GNU GPL v3 License: GNU GPL v3
''' '''
@ -68,10 +74,11 @@ from shapely import speedups
if speedups.available: if speedups.available:
speedups.enable() speedups.enable()
idPrefixSubSplit = "subsplit" idPrefixSubSplit = "subsplit"
idPrefixTrimming = "shapely" idPrefixTrimming = "trimmed"
intersectedVerb = "intersected" intersectedVerb = "intersected"
collinearVerb = "collinear"
EPS_M = 0.01 EPS_M = 0.01
class ContourScannerAndTrimmer(inkex.EffectExtension): class ContourScannerAndTrimmer(inkex.EffectExtension):
@ -216,6 +223,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
selfIntersectionPointCircle.set('id', self.svg.get_unique_id('selfIntersectionPoint-')) selfIntersectionPointCircle.set('id', self.svg.get_unique_id('selfIntersectionPoint-'))
selfIntersectionPointCircle.style = selfIntersectionPointStyle selfIntersectionPointCircle.style = selfIntersectionPointStyle
selfIntersectionGroup.add(selfIntersectionPointCircle) selfIntersectionGroup.add(selfIntersectionPointCircle)
return selfIntersectionGroup
def visualize_global_intersections(self, globalIntersectionPoints): def visualize_global_intersections(self, globalIntersectionPoints):
@ -296,9 +304,9 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
#if trimGroupParentTransform is not None: #if trimGroupParentTransform is not None:
# trimLine.path = trimLine.path.transform(-trimGroupParentTransform) # trimLine.path = trimLine.path.transform(-trimGroupParentTransform)
if self.options.apply_style_to_trimmed is False: if self.options.trimmed_style == "apply_from_trimmed":
trimLine.style = trimLineStyle trimLine.style = trimLineStyle
else: elif self.options.trimmed_style == "apply_from_original":
trimLine.style = subSplitLineArray[subSplitIndex].attrib['originalPathStyle'] trimLine.style = subSplitLineArray[subSplitIndex].attrib['originalPathStyle']
trimGroup.add(trimLine) trimGroup.add(trimLine)
return trimGroup return trimGroup
@ -368,7 +376,10 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
def filter_collinear(self, lineArray): def filter_collinear(self, lineArray):
''' '''
Loop through a set of lines and find + fiter all overlapping segments / duplicate segments 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_set = []
input_ids = [] input_ids = []
@ -376,7 +387,11 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
# collect segments, calculate their slopes, order their points left-to-right # collect segments, calculate their slopes, order their points left-to-right
for line in lineArray: for line in lineArray:
#csp = line.path.to_arrays() #csp = line.path.to_arrays()
csp = Path(line.path.transform(line.getparent().composed_transform())).to_arrays() parent = line.getparent()
if parent is not None:
csp = Path(line.path.transform(parent.composed_transform())).to_arrays()
else:
csp = line.path.to_arrays()
#self.msg("csp = {}".format(csp)) #self.msg("csp = {}".format(csp))
x1, y1, x2, y2 = csp[0][1][0], csp[0][1][1], csp[1][1][0], csp[1][1][1] x1, y1, x2, y2 = csp[0][1][0], csp[0][1][1], csp[1][1][0], csp[1][1][1]
# ensure p0 is left of p1 # ensure p0 is left of p1
@ -431,7 +446,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
#we finally build a list which contains all overlapping elements we want to drop #we finally build a list which contains all overlapping elements we want to drop
dropped_ids = [] dropped_ids = []
for input_id in input_ids: #if the working id is not in the output id we are going to drop it for input_id in input_ids: #if the input_id id is not in the output ids we are going to drop it
if input_id not in output_ids: if input_id not in output_ids:
dropped_ids.append(input_id) dropped_ids.append(input_id)
@ -459,10 +474,14 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
return output_set, dropped_ids return output_set, dropped_ids
def remove_duplicates(self, allTrimGroups): def remove_trim_duplicates(self, allTrimGroups):
''' find duplicate lines in a given array [] of groups ''' '''
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 = [] totalTrimPaths = []
if self.options.reverse_removal_order is True: if self.options.reverse_trim_removal_order is True:
allTrimGroups = allTrimGroups[::-1] allTrimGroups = allTrimGroups[::-1]
for trimGroup in allTrimGroups: for trimGroup in allTrimGroups:
for element in trimGroup: for element in trimGroup:
@ -522,7 +541,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
self.msg("trim group {} has {} combinable segments:".format(trimGroup.get('id'), len(newPathData))) self.msg("trim group {} has {} combinable segments:".format(trimGroup.get('id'), len(newPathData)))
self.msg("{}".format(newPathData)) self.msg("{}".format(newPathData))
combinedPath.path = Path(newPathData) combinedPath.path = Path(newPathData)
if self.options.apply_style_to_trimmed is False: if self.options.trimmed_style == "apply_from_trimmed":
combinedPath.style = trimNonIntersectedStyle combinedPath.style = trimNonIntersectedStyle
if totalIntersectionsAtPath == 0: if totalIntersectionsAtPath == 0:
combinedPath.style = nonTrimLineStyle combinedPath.style = nonTrimLineStyle
@ -574,9 +593,10 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
def add_arguments(self, pars): 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("--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("--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") pars.add_argument("--handle_groups", type=inkex.Boolean, default=False, help="Also looks for paths in groups which are in the current selection")
@ -585,10 +605,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("--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("--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("--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)") #Settings - General Style
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("--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 #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_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_absolute", type=inkex.Boolean, default=False, help="absolute cmd")
pars.add_argument("--remove_mixed", type=inkex.Boolean, default=False, help="mixed cmd (relative + absolute)") pars.add_argument("--remove_mixed", type=inkex.Boolean, default=False, help="mixed cmd (relative + absolute)")
@ -597,8 +622,13 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
pars.add_argument("--remove_opened", type=inkex.Boolean, default=False, help="opened") 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_closed", type=inkex.Boolean, default=False, help="closed")
pars.add_argument("--remove_self_intersecting", type=inkex.Boolean, default=False, help="self-intersecting") 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 #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_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_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") pars.add_argument("--highlight_mixed", type=inkex.Boolean, default=False, help="mixed cmd (relative + absolute) paths")
@ -606,17 +636,22 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
pars.add_argument("--highlight_beziers", type=inkex.Boolean, default=False, help="bezier paths") 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_opened", type=inkex.Boolean, default=False, help="opened paths")
pars.add_argument("--highlight_closed", type=inkex.Boolean, default=False, help="closed 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("--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_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") pars.add_argument("--visualize_global_intersections", type=inkex.Boolean, default=False, help="global intersection points")
#Settings - Trimming #Trimming - General trimming settings
pars.add_argument("--draw_trimmed", type=inkex.Boolean, default=False, help="Draw trimmed lines") 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("--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("--remove_trim_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("--reverse_trim_removal_order", type=inkex.Boolean, default=False, help="Reverses the order of removal. Relevant for keeping certain styles of elements")
pars.add_argument("--keep_original_after_trim", type=inkex.Boolean, default=False, help="Keep original paths after trimming") pars.add_argument("--remove_subsplit_after_trimming", type=inkex.Boolean, default=True, help="Remove sub split lines after trimming")
#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_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_debug", type=inkex.Boolean, default=False)
pars.add_argument("--bent_ott_use_verbose", type=inkex.Boolean, default=False) pars.add_argument("--bent_ott_use_verbose", type=inkex.Boolean, default=False)
@ -624,28 +659,24 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
pars.add_argument("--bent_ott_use_vertical", type=inkex.Boolean, default=True) pars.add_argument("--bent_ott_use_vertical", type=inkex.Boolean, default=True)
pars.add_argument("--bent_ott_number_type", default="native") pars.add_argument("--bent_ott_number_type", default="native")
#Style - General Style #Colors
pars.add_argument("--strokewidth", type=float, default=1.0, help="Stroke width (px)") pars.add_argument("--color_subsplit", type=Color, default='1630897151', help="sub split lines")
pars.add_argument("--dotsize_intersections", type=int, default=30, help="Dot size (px) for self-intersecting and global intersection points") #Colors - path structure
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("--apply_style_to_subsplits", type=inkex.Boolean, default=True, help="Apply highlighting styles to sub split lines.")
pars.add_argument("--apply_style_to_trimmed", type=inkex.Boolean, default=True, help="Apply original path style to trimmed lines")
#Style - Scanning Colors
pars.add_argument("--color_subsplit", type=Color, default='1630897151', help="sub split lines")
pars.add_argument("--color_relative", type=Color, default='3419879935', help="relative cmd paths") 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_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_polyline", type=Color, default='4289703935', help="polyline paths")
pars.add_argument("--color_bezier", type=Color, default='258744063', help="bezier 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_opened", type=Color, default='4012452351', help="opened paths")
pars.add_argument("--color_closed", type=Color, default='2330080511', help="closed 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_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_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") pars.add_argument("--color_global_intersections", type=Color, default='4239343359', help="global intersection points")
#Colors - trimming
#Style - Trimming Color
pars.add_argument("--color_trimmed", type=Color, default='1923076095', help="trimmed lines") 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_combined", type=Color, default='3227634687', help="non-intersected lines")
pars.add_argument("--color_nonintersected", type=Color, default='3045284607', help="non-intersected paths") pars.add_argument("--color_nonintersected", type=Color, default='3045284607', help="non-intersected paths")
@ -658,6 +689,20 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
if so.break_apart is True and so.show_debug is True: 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)!") 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_duplicates is True or \
so.highlight_merges is True:
so.filter_subsplit_collinear = True
if so.filter_subsplit_collinear is True: #this is a must.
#if so.draw_subsplit is disabled bu we filter sub split lines and follow with trim operation we lose a lot of elements which may not be deleted!
so.draw_subsplit = True
#some constant stuff / styles #some constant stuff / styles
relativePathStyle = {'stroke': str(so.color_relative), 'fill': 'none', 'stroke-width': so.strokewidth} relativePathStyle = {'stroke': str(so.color_relative), 'fill': 'none', 'stroke-width': so.strokewidth}
absolutePathStyle = {'stroke': str(so.color_absolute), 'fill': 'none', 'stroke-width': so.strokewidth} absolutePathStyle = {'stroke': str(so.color_absolute), 'fill': 'none', 'stroke-width': so.strokewidth}
@ -666,6 +711,8 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
bezierPathStyle = {'stroke': str(so.color_bezier), 'fill': 'none', 'stroke-width': so.strokewidth} bezierPathStyle = {'stroke': str(so.color_bezier), 'fill': 'none', 'stroke-width': so.strokewidth}
openPathStyle = {'stroke': str(so.color_opened), '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} 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} 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} basicSubSplitLineStyle = {'stroke': str(so.color_subsplit), 'fill': 'none', 'stroke-width': so.strokewidth}
@ -778,7 +825,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
subSplitId = "{}-{}-{}".format(idPrefixSubSplit, originalPathId, i) subSplitId = "{}-{}-{}".format(idPrefixSubSplit, originalPathId, i)
line = inkex.PathElement(id=subSplitId) line = inkex.PathElement(id=subSplitId)
#apply line path with composed negative transform from parent element #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]]] #line.path = [['M', [x1, y1]], ['L', [x2, y2]]]
if pathElement.getparent() != self.svg.root and pathElement.getparent() != None: if pathElement.getparent() != self.svg.root and pathElement.getparent() != None:
line.path = line.path.transform(-pathElement.getparent().composed_transform()) line.path = line.path.transform(-pathElement.getparent().composed_transform())
@ -792,7 +839,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
line.attrib['originalPathStyle'] = str(pathElement.style) line.attrib['originalPathStyle'] = str(pathElement.style)
subSplitLineArray.append(line) subSplitLineArray.append(line)
if so.apply_style_to_subsplits is True: if so.subsplit_style == "apply_from_highlightings":
if line.attrib['originalPathIsRelative'] == 'True': if line.attrib['originalPathIsRelative'] == 'True':
if so.highlight_relative is True: if so.highlight_relative is True:
line.style = relativePathStyle line.style = relativePathStyle
@ -818,6 +865,8 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
else: else:
if so.highlight_opened is True: if so.highlight_opened is True:
line.style = openPathStyle line.style = openPathStyle
elif so.subsplit_style == "apply_from_original":
line.style = line.attrib['originalPathStyle']
if so.draw_subsplit is True: if so.draw_subsplit is True:
subSplitLineGroup.add(line) subSplitLineGroup.add(line)
@ -830,15 +879,14 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
isSelfIntersecting = True isSelfIntersecting = True
if so.show_debug is True: if so.show_debug is True:
self.msg("{} in {} intersects itself with {} intersections!".format(subSplitId, originalPathId, len(selfIntersectionPoints))) 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:
if so.highlight_self_intersecting is True: for subSplitLine in subSplitLineGroup:
for subSplitLine in subSplitLineGroup: subSplitLine.style = selfIntersectingPathStyle #adjusts line color
subSplitLine.style = selfIntersectingPathStyle #adjusts line color
#delete cosmetic sub split lines if desired #delete cosmetic sub split lines if desired
if so.remove_self_intersecting: if so.remove_self_intersecting:
subSplitLineGroup.delete() subSplitLineGroup.delete()
if so.visualize_self_intersections is True: #draw points (circles) 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 #delete self-intersecting sub split lines and orginal paths
if so.remove_self_intersecting: if so.remove_self_intersecting:
@ -888,31 +936,81 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
if so.show_debug is True: if so.show_debug is True:
self.msg("sub split line count: {}".format(len(subSplitLineArray))) 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 so.show_debug is True: self.msg("filtering collinear overlapping lines / duplicate lines")
if len(subSplitLineArray) > 0: if len(subSplitLineArray) > 0:
output_set, dropped_ids = self.filter_collinear(subSplitLineArray) output_set, dropped_ids = self.filter_collinear(subSplitLineArray)
deleteIndices = []
deleteIndice = 0
for subSplitLine in subSplitLineArray: for subSplitLine in subSplitLineArray:
ssl_id = subSplitLine.get('id') '''
if ssl_id in dropped_ids: Replace the overlapping items with the new merged output
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
for output in output_set: for output in output_set:
if output['id'] == subSplitLine.attrib['id']: if output['id'] == subSplitLine.attrib['id']:
#self.msg(output['p0']) originalSplitLinePath = subSplitLine.path
subSplitLine.attrib['d'] = 'M {},{} L {},{}'.format( output_line = '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 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']]] #subSplitLine.path = [['M', output['p0']], ['L', output['p1']]]
#self.msg("composed_transform = {}".format(output['composed_transform'])) #self.msg("composed_transform = {}".format(output['composed_transform']))
#subSplitLine.transform = Transform(-output['composed_transform']) * subSplitLine.transform #subSplitLine.transform = Transform(-output['composed_transform']) * subSplitLine.transform
subSplitLine.path = subSplitLine.path.transform(-output['composed_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!) now we intersect the sub split lines to find the global intersection points using Bentley-Ottmann algorithm (contains self-intersections too!)
@ -950,7 +1048,7 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
for subSplitLine in subSplitLineArray: for subSplitLine in subSplitLineArray:
csp = subSplitLine.path.to_arrays() csp = subSplitLine.path.to_arrays()
lineString = [(csp[0][1][0], csp[0][1][1]), (csp[1][1][0], csp[1][1][1])] 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: if lineString not in allSubSplitLineStrings:
allSubSplitLineStrings.append(lineString) allSubSplitLineStrings.append(lineString)
else: else:
@ -990,27 +1088,37 @@ class ContourScannerAndTrimmer(inkex.EffectExtension):
if so.show_debug is True: self.msg("trimming beziers - not working yet") if so.show_debug is True: self.msg("trimming beziers - not working yet")
self.trim_bezier(allTrimGroups) 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") 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.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)") if so.show_debug is True: self.msg("glueing together all non-intersected sub split lines to larger path structures again (cleaning up)")
self. combine_nonintersects(allTrimGroups) self.combine_nonintersects(allTrimGroups)
#clean original paths if selected. This option is explicitely independent from remove_open, remove_closed
if so.keep_original_after_trim is False:
if so.show_debug is True: self.msg("cleaning original paths")
for pathElement in pathElements:
pathElement.delete()
if so.remove_subsplit_after_trimming is True:
if so.show_debug is True: self.msg("removing unwanted subsplit lines after trimming")
for subSplitLine in subSplitLineArray:
ssl_parent = subSplitLine.getparent()
subSplitLine.delete()
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()
except AssertionError as e: except AssertionError as e:
self.msg("Error calculating global intersections.\n\ self.msg("Error calculating global intersections.\n\
See https://github.com/ideasman42/isect_segments-bentley_ottmann.\n\n\ See https://github.com/ideasman42/isect_segments-bentley_ottmann.\n\n\
You can try to fix this by:\n\ You can try to fix this by:\n\
- reduce or raise the 'decimals' setting (default is 3 but try to set to 6 for example)\n\ - reduce or raise the 'decimals' setting (default is 3 but try to set to 6 for example)\n\
- reduce or raise the 'flatness' setting (if quantization option is used at all; default is 0.100).") - reduce or raise the 'flatness' setting (if quantization option is used at all; default is 0.100).")
return return
#clean original paths if selected.
if so.keep_original_after_split_trim is False:
if so.show_debug is True: self.msg("cleaning original paths after sub splitting / trimming")
for pathElement in pathElements:
pathElement.delete()
if __name__ == '__main__': if __name__ == '__main__':
ContourScannerAndTrimmer().run() ContourScannerAndTrimmer().run()