Cutwork segmentation (#1582)

* add cutwork segmentation extension
* simulator: option to not render jump stitches
pull/1618/head
Kaalleen 2022-02-28 16:24:51 +01:00 zatwierdzone przez GitHub
rodzic 5f815a832b
commit bd43e00775
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
8 zmienionych plików z 269 dodań i 7 usunięć

Wyświetl plik

@ -49,6 +49,7 @@ export default {
showColorChanges: false,
showStops: false,
showNeedlePenetrationPoints: false,
renderJumps: true,
showRealisticPreview: false,
showCursor: true
}
@ -70,6 +71,10 @@ export default {
}
})
},
renderJumps() {
this.renderedStitch = 1
this.renderFrame()
},
showRealisticPreview() {
let animating = this.animating
this.stop()
@ -291,6 +296,14 @@ export default {
renderFrame() {
while (this.renderedStitch < this.currentStitch) {
this.renderedStitch += 1
if (!this.renderJumps && this.stitches[this.renderedStitch].jump){
if (this.showRealisticPreview) {
this.realisticPaths[this.renderedStitch].hide();
} else {
this.stitchPaths[this.renderedStitch].hide();
}
continue;
}
if (this.showRealisticPreview) {
this.realisticPaths[this.renderedStitch].show()
} else {

Wyświetl plik

@ -172,10 +172,6 @@ fieldset.show-commands span {
vertical-align: top;
}
fieldset.show-commands span.npp {
text-align: right;
}
fieldset.show-commands span:first-of-type {
padding: 0 5px;
}

Wyświetl plik

@ -215,7 +215,7 @@
<input id="stop-checkbox" type="checkbox" v-model="showStops"/>
<label for="stop-checkbox"><font-awesome-icon icon="pause"/> <translate>stops</translate></label>
</span>
<span class="npp">
<span>
<input id="npp-checkbox" type="checkbox" v-model="showNeedlePenetrationPoints"/>
<label for="npp-checkbox">
<font-awesome-layers>
@ -224,6 +224,9 @@
</font-awesome-layers>
<span v-translate>needle points</span>
</label>
<br />
<input id="render-jumps-checkbox" type="checkbox" v-model="renderJumps"/>
<label for="render-jumps-checkbox"><font-awesome-icon icon="link"/><span v-translate>render jumps</span></label>
</span>
<span>
<input id="realistic-checkbox" type="checkbox" v-model="showRealisticPreview"/>

Wyświetl plik

@ -24,6 +24,7 @@ import {
faExchangeAlt,
faEye,
faFrog,
faLink,
faHippo,
faHorse,
faInfo,
@ -60,6 +61,7 @@ library.add(
faExchangeAlt,
faEye,
faFrog,
faLink,
faHippo,
faHorse,
faInfo,

Wyświetl plik

@ -11,6 +11,7 @@ from .cleanup import Cleanup
from .convert_to_satin import ConvertToSatin
from .convert_to_stroke import ConvertToStroke
from .cut_satin import CutSatin
from .cutwork_segmentation import CutworkSegmentation
from .duplicate_params import DuplicateParams
from .embroider_settings import EmbroiderSettings
from .flip import Flip
@ -68,4 +69,5 @@ __all__ = extensions = [StitchPlanPreview,
Simulator,
Reorder,
DuplicateParams,
EmbroiderSettings]
EmbroiderSettings,
CutworkSegmentation]

Wyświetl plik

@ -0,0 +1,188 @@
# Authors: see git history
#
# Copyright (c) 2022 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from math import atan2, degrees
import inkex
from lxml import etree
from shapely.geometry import LineString, Point
from ..elements import Stroke
from ..i18n import _
from ..svg import get_correction_transform
from ..svg.tags import INKSCAPE_LABEL, SVG_PATH_TAG
from .base import InkstitchExtension
class CutworkSegmentation(InkstitchExtension):
'''
This will split up stroke elements according to their direction.
Overlapping angle definitions (user input) will result in overlapping paths.
This is wanted behaviour if the needles have a hard time to cut edges at the border of their specific angle capability.
'''
def __init__(self, *args, **kwargs):
InkstitchExtension.__init__(self, *args, **kwargs)
self.arg_parser.add_argument("-o", "--options", type=str, default=None, dest="page_1")
self.arg_parser.add_argument("-i", "--info", type=str, default=None, dest="page_2")
self.arg_parser.add_argument("-as", "--a_start", type=int, default=0, dest="a_start")
self.arg_parser.add_argument("-ae", "--a_end", type=int, default=0, dest="a_end")
self.arg_parser.add_argument("-ac", "--a_color", type=inkex.Color, default=inkex.Color(0x808080FF), dest="a_color")
self.arg_parser.add_argument("-bs", "--b_start", type=int, default=0, dest="b_start")
self.arg_parser.add_argument("-be", "--b_end", type=int, default=0, dest="b_end")
self.arg_parser.add_argument("-bc", "--b_color", type=inkex.Color, default=inkex.Color(0x808080FF), dest="b_color")
self.arg_parser.add_argument("-cs", "--c_start", type=int, default=0, dest="c_start")
self.arg_parser.add_argument("-ce", "--c_end", type=int, default=0, dest="c_end")
self.arg_parser.add_argument("-cc", "--c_color", type=inkex.Color, default=inkex.Color(0x808080FF), dest="c_color")
self.arg_parser.add_argument("-ds", "--d_start", type=int, default=0, dest="d_start")
self.arg_parser.add_argument("-de", "--d_end", type=int, default=0, dest="d_end")
self.arg_parser.add_argument("-dc", "--d_color", type=inkex.Color, default=inkex.Color(0x808080FF), dest="d_color")
self.arg_parser.add_argument("-s", "--sort_by_color", type=inkex.Boolean, default=True, dest="sort_by_color")
self.arg_parser.add_argument("-k", "--keep_original", type=inkex.Boolean, default=False, dest="keep_original")
def effect(self):
if not self.svg.selected:
inkex.errormsg(_("Please select one or more stroke elements."))
return
if not self.get_elements():
return
self.sectors = {
1: {'id': 1, 'start': self.options.a_start, 'end': self.options.a_end, 'color': self.options.a_color, 'point_list': []},
2: {'id': 2, 'start': self.options.b_start, 'end': self.options.b_end, 'color': self.options.b_color, 'point_list': []},
3: {'id': 3, 'start': self.options.c_start, 'end': self.options.c_end, 'color': self.options.c_color, 'point_list': []},
4: {'id': 4, 'start': self.options.d_start, 'end': self.options.d_end, 'color': self.options.d_color, 'point_list': []}
}
# remove sectors where the start angle equals the end angle (some setups only work with two needles instead of four)
self.sectors = {index: sector for index, sector in self.sectors.items() if sector['start'] != sector['end']}
self.new_elements = []
for element in self.elements:
if isinstance(element, Stroke):
# save parent and index to be able to position and insert new elements later on
parent = element.node.getparent()
index = parent.index(element.node)
for path in element.paths:
linestring = LineString(path)
# fill self.new_elements list with line segments
self._prepare_line_sections(element, linestring.coords)
self._insert_elements(parent, element, index)
self._remove_originals()
def _get_sectors(self, angle):
sectors = []
for sector in self.sectors.values():
if self._in_sector(angle, sector):
sectors.append(sector)
return sectors
def _in_sector(self, angle, sector):
stop = sector['end'] + 1
if sector['start'] > stop:
return angle in range(sector['start'], 181) or angle in range(0, stop)
else:
return angle in range(sector['start'], stop)
def _get_angle(self, p1, p2):
angle = round(degrees(atan2(p2.y - p1.y, p2.x - p1.x)) % 360)
if angle > 180:
angle -= 180
return angle
def _prepare_line_sections(self, element, coords):
prev_point = None
current_sectors = []
for index, point in enumerate(coords):
point = Point(*point)
if prev_point is None:
prev_point = point
continue
angle = self._get_angle(point, prev_point)
sectors = self._get_sectors(angle)
for sector in sectors:
self.sectors[sector['id']]['point_list'].append(prev_point)
# don't miss the last point
if index == len(coords) - 1:
self.sectors[sector['id']]['point_list'].append(point)
self._prepare_element(self.sectors[sector['id']], element)
# if a segment ends, prepare the element and clear point_lists
for current in current_sectors:
if current not in sectors:
# add last point
self.sectors[current['id']]['point_list'].append(prev_point)
self._prepare_element(self.sectors[current['id']], element)
prev_point = point
current_sectors = sectors
def _prepare_element(self, sector, element):
point_list = sector['point_list']
if len(point_list) < 2:
return
color = str(self.path_style(element, str(sector['color'])))
d = "M "
for point in point_list:
d += "%s,%s " % (point.x, point.y)
stroke_element = etree.Element(SVG_PATH_TAG,
{
"style": color,
"transform": get_correction_transform(element.node),
"d": d
})
self.new_elements.append([stroke_element, sector['id']])
# clear point_list in self.sectors
self.sectors[sector['id']].update({'point_list': []})
def _insert_elements(self, parent, element, index):
self.new_elements.reverse()
if self.options.sort_by_color is True:
self.new_elements = sorted(self.new_elements, key=lambda x: x[1], reverse=True)
group = self._insert_group(parent, _("Cutwork Group"), "__inkstitch_cutwork_group__", index)
section = 0
for element, section_id in self.new_elements:
# if sorted by color, add a subgroup for each knife
if self.options.sort_by_color:
if section_id != section:
section = section_id
section_group = self._insert_group(group, _("Needle #%s") % section, "__inkstitch_cutwork_needle_group__")
else:
section_group = group
section_group.insert(0, element)
def _insert_group(self, parent, label, group_id, index=0):
group = etree.Element("g", {
INKSCAPE_LABEL: "%s" % label,
"id": self.uniqueId("%s" % group_id)
})
parent.insert(index, group)
return group
def _remove_originals(self):
if self.options.keep_original:
return
for element in self.elements:
if isinstance(element, Stroke):
parent = element.node.getparent()
parent.remove(element.node)
def path_style(self, element, color):
# set stroke color and make it a running stitch - they don't want to cut zigzags
return inkex.Style(element.node.get('style', '')) + inkex.Style('stroke:%s;stroke-dasharray:6,1;' % color)

Wyświetl plik

@ -353,4 +353,6 @@ class Font(object):
"""
elements = nodes_to_elements(group.iterdescendants(SVG_PATH_TAG))
auto_satin(elements, preserve_order=True, trim=trim)
if elements:
auto_satin(elements, preserve_order=True, trim=trim)

Wyświetl plik

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Cutwork segmentation</name>
<id>org.inkstitch.cutwork_segmentation</id>
<param name="extension" type="string" gui-hidden="true">cutwork_segmentation</param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="Ink/Stitch" translatable="no" />
</effects-menu>
</effect>
<param name="options" type="notebook">
<page name="options" gui-text="Cutwork Options">
<hbox>
<label>#1</label><spacer />
<param name="a_start" type="int" appearance="full" gui-text="start" precision="1" min="0" max="180">112</param><spacer />
<param name="a_end" type="int" appearance="full" gui-text="end" precision="1" min="0" max="180">157</param><spacer />
<param name="a_color" type="color" gui-text="color" appearance="colorbutton">0x990000ff</param>
</hbox>
<hbox>
<label>#2 </label><spacer />
<param name="b_start" type="int" appearance="full" gui-text="start" precision="1" min="0" max="180">158</param><spacer />
<param name="b_end" type="int" appearance="full" gui-text="end" precision="1" min="0" max="180">23</param><spacer />
<param name="b_color" type="color" gui-text="color" appearance="colorbutton">0xe5a50aff</param>
</hbox>
<hbox>
<label>#3 </label><spacer />
<param name="c_start" type="int" appearance="full" gui-text="start" precision="1" min="0" max="180">22</param><spacer />
<param name="c_end" type="int" appearance="full" gui-text="end" precision="1" min="0" max="180">68</param><spacer />
<param name="c_color" type="color" gui-text="color" appearance="colorbutton">0x009900ff</param>
</hbox>
<hbox>
<label>#4 </label><spacer />
<param name="d_start" type="int" appearance="full" gui-text="start" precision="1" min="0" max="180">67</param><spacer />
<param name="d_end" type="int" appearance="full" gui-text="end" precision="1" min="0" max="180">113</param><spacer />
<param name="d_color" type="color" gui-text="color" appearance="colorbutton">0x000099ff</param>
</hbox>
<spacer />
<param name="sort_by_color" type="boolean" gui-text="Sort elements by color">true</param>
<param name="keep_original" type="boolean" gui-text="Keep original">false</param>
</page>
<page name="info" gui-text="Help">
<label appearance="header">This extension separates a path depending on the angle.</label>
<label>* If you don't want to use 4 needles, set both angle values to 0 for the rest of the rows.</label>
<label>* A horizontal line has an angle of 0 degrees.</label>
<label>* After the conversion through this extension, don't rotate your design again.</label>
<separator />
<label appearance="header">Please adjust angle and color options to your specific needle kit.</label>
<label>On our website we have collected some common setups.</label>
<label appearance="url">https://inkstitch.org/docs/cutwork/</label>
</page>
</param>
<script>
{{ command_tag | safe }}
</script>
</inkscape-extension>