summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/elements/__init__.py3
-rw-r--r--lib/elements/clone.py38
-rw-r--r--lib/elements/element.py12
-rw-r--r--lib/elements/fill_stitch.py (renamed from lib/elements/auto_fill.py)469
-rw-r--r--lib/elements/marker.py (renamed from lib/elements/pattern.py)13
-rw-r--r--lib/elements/utils.py13
-rw-r--r--lib/extensions/base.py6
-rw-r--r--lib/extensions/cleanup.py4
-rw-r--r--lib/extensions/params.py5
-rw-r--r--lib/marker.py13
-rw-r--r--symbols/marker.svg32
11 files changed, 343 insertions, 265 deletions
diff --git a/lib/elements/__init__.py b/lib/elements/__init__.py
index bb5c95ba..00933f36 100644
--- a/lib/elements/__init__.py
+++ b/lib/elements/__init__.py
@@ -3,11 +3,10 @@
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
-from .auto_fill import AutoFill
from .clone import Clone
from .element import EmbroideryElement
from .empty_d_object import EmptyDObject
-#from .fill import Fill
+from .fill_stitch import FillStitch
from .image import ImageObject
from .polyline import Polyline
from .satin_column import SatinColumn
diff --git a/lib/elements/clone.py b/lib/elements/clone.py
index 15e7591c..3f133471 100644
--- a/lib/elements/clone.py
+++ b/lib/elements/clone.py
@@ -5,18 +5,20 @@
from math import atan, degrees
+<<<<<<< HEAD
from ..commands import is_command, is_command_symbol
+=======
+import inkex
+
+from ..commands import is_command_symbol
+>>>>>>> c69b6f5a (* autofill to fillstitch)
from ..i18n import _
from ..svg.path import get_node_transform
from ..svg.svg import find_elements
-from ..svg.tags import (EMBROIDERABLE_TAGS, INKSTITCH_ATTRIBS,
- SVG_POLYLINE_TAG, SVG_USE_TAG, XLINK_HREF)
+from ..svg.tags import (EMBROIDERABLE_TAGS, INKSTITCH_ATTRIBS, SVG_USE_TAG,
+ XLINK_HREF)
from ..utils import cache
-from .auto_fill import AutoFill
from .element import EmbroideryElement, param
-from .polyline import Polyline
-from .satin_column import SatinColumn
-from .stroke import Stroke
from .validation import ObjectTypeWarning, ValidationWarning
@@ -67,28 +69,8 @@ class Clone(EmbroideryElement):
return self.get_float_param('angle', 0)
def clone_to_element(self, node):
- # we need to determine if the source element is polyline, stroke, fill or satin
- element = EmbroideryElement(node)
-
- if node.tag == SVG_POLYLINE_TAG:
- return [Polyline(node)]
-
- elif element.get_boolean_param("satin_column") and self.get_clone_style("stroke", self.node):
- return [SatinColumn(node)]
- else:
- elements = []
- if element.get_style("fill", "black") and not element.get_style("stroke", 1) == "0":
- # if element.get_boolean_param("auto_fill", True):
- elements.append(AutoFill(node))
- # else:
- # elements.append(Fill(node))
- if element.get_style("stroke", self.node) is not None:
- if not is_command(element.node):
- elements.append(Stroke(node))
- if element.get_boolean_param("stroke_first", False):
- elements.reverse()
-
- return elements
+ from .utils import node_to_elements
+ return node_to_elements(node)
def to_stitch_groups(self, last_patch=None):
patches = []
diff --git a/lib/elements/element.py b/lib/elements/element.py
index ef70510d..ee4eadbb 100644
--- a/lib/elements/element.py
+++ b/lib/elements/element.py
@@ -87,8 +87,11 @@ class EmbroideryElement(object):
return params
def replace_legacy_param(self, param):
- value = self.node.get(param, "").strip()
- self.set_param(param[10:], value)
+ # remove "embroider_" prefix
+ new_param = param[10:]
+ if new_param in INKSTITCH_ATTRIBS:
+ value = self.node.get(param, "").strip()
+ self.set_param(param[10:], value)
del self.node.attrib[param]
@cache
@@ -267,6 +270,11 @@ class EmbroideryElement(object):
return apply_transforms(self.path, self.node)
@property
+ @cache
+ def paths(self):
+ return self.flatten(self.parse_path())
+
+ @property
def shape(self):
raise NotImplementedError(
"INTERNAL ERROR: %s must implement shape()", self.__class__)
diff --git a/lib/elements/auto_fill.py b/lib/elements/fill_stitch.py
index 614e6887..ee56abfc 100644
--- a/lib/elements/auto_fill.py
+++ b/lib/elements/fill_stitch.py
@@ -9,20 +9,20 @@ import re
import sys
import traceback
-import inkex
from shapely import geometry as shgeo
from shapely.validation import explain_validity
from ..i18n import _
from ..marker import get_marker_elements
from ..stitch_plan import StitchGroup
-from ..stitches import StitchPattern, auto_fill, fill
+from ..stitches import StitchPattern, auto_fill, legacy_fill
from ..svg import PIXELS_PER_MM
from ..svg.tags import INKSCAPE_LABEL
from ..utils import Point as InkstitchPoint
from ..utils import cache, version
from .element import EmbroideryElement, param
-from .validation import ValidationWarning
+from .validation import ValidationError, ValidationWarning
+from shapely.ops import nearest_points
class SmallShapeWarning(ValidationWarning):
@@ -43,13 +43,53 @@ class UnderlayInsetWarning(ValidationWarning):
description = _("The underlay inset parameter for this fill object cannot be applied. "
"Ink/Stitch will ignore it and will use the original size instead.")
-
-class AutoFill(EmbroideryElement):
- element_name = _("AutoFill")
+class MissingGuideLineWarning(ValidationWarning):
+ name = _("Missing Guideline")
+ description = _('This object is set to "Guided AutoFill", but has no guide line.')
+ steps_to_solve = [
+ _('* Create a stroke object'),
+ _('* Select this object and run Extensions > Ink/Stitch > Edit > Selection to guide line')
+ ]
+
+class DisjointGuideLineWarning(ValidationWarning):
+ name = _("Disjointed Guide Line")
+ description = _("The guide line of this object isn't within the object borders. "
+ "The guide line works best, if it is within the target element.")
+ steps_to_solve = [
+ _('* Move the guide line into the element')
+ ]
+
+class MultipleGuideLineWarning(ValidationWarning):
+ name = _("Multiple Guide Lines")
+ description = _("This object has multiple guide lines, but only the first one will be used.")
+ steps_to_solve = [
+ _("* Remove all guide lines, except for one.")
+ ]
+
+class UnconnectedError(ValidationError):
+ name = _("Unconnected")
+ description = _("Fill: This object is made up of unconnected shapes. This is not allowed because "
+ "Ink/Stitch doesn't know what order to stitch them in. Please break this "
+ "object up into separate shapes.")
+ steps_to_solve = [
+ _('* Extensions > Ink/Stitch > Fill Tools > Break Apart Fill Objects'),
+ ]
+
+
+class InvalidShapeError(ValidationError):
+ name = _("Border crosses itself")
+ description = _("Fill: Shape is not valid. This can happen if the border crosses over itself.")
+ steps_to_solve = [
+ _('* Extensions > Ink/Stitch > Fill Tools > Break Apart Fill Objects')
+ ]
+
+
+class FillStitch(EmbroideryElement):
+ element_name = _("FillStitch")
@property
@param('auto_fill', _('Automatically routed fill stitching'), type='toggle', default=True, sort_index=1)
- def auto_fill2(self):
+ def auto_fill(self):
return self.get_boolean_param('auto_fill', True)
@property
@@ -168,12 +208,95 @@ class AutoFill(EmbroideryElement):
# ensure path length
for i, path in enumerate(paths):
if len(path) < 3:
- paths[i] = [(path[0][0], path[0][1]), (path[0][0] +
- 1.0, path[0][1]), (path[0][0], path[0][1]+1.0)]
+ paths[i] = [(path[0][0], path[0][1]), (path[0][0]+1.0, path[0][1]), (path[0][0], path[0][1]+1.0)]
return paths
@property
@cache
+ def shape(self):
+ # shapely's idea of "holes" are to subtract everything in the second set
+ # from the first. So let's at least make sure the "first" thing is the
+ # biggest path.
+ paths = self.paths
+ paths.sort(key=lambda point_list: shgeo.Polygon(point_list).area, reverse=True)
+ # Very small holes will cause a shape to be rendered as an outline only
+ # they are too small to be rendered and only confuse the auto_fill algorithm.
+ # So let's ignore them
+ if shgeo.Polygon(paths[0]).area > 5 and shgeo.Polygon(paths[-1]).area < 5:
+ paths = [path for path in paths if shgeo.Polygon(path).area > 3]
+
+ polygon = shgeo.MultiPolygon([(paths[0], paths[1:])])
+
+ # There is a great number of "crossing border" errors on fill shapes
+ # If the polygon fails, we can try to run buffer(0) on the polygon in the
+ # hope it will fix at least some of them
+ if not self.shape_is_valid(polygon):
+ why = explain_validity(polygon)
+ message = re.match(r".+?(?=\[)", why)
+ if message.group(0) == "Self-intersection":
+ buffered = polygon.buffer(0)
+ # if we receive a multipolygon, only use the first one of it
+ if type(buffered) == shgeo.MultiPolygon:
+ buffered = buffered[0]
+ # we do not want to break apart into multiple objects (possibly in the future?!)
+ # best way to distinguish the resulting polygon is to compare the area size of the two
+ # and make sure users will not experience significantly altered shapes without a warning
+ if type(buffered) == shgeo.Polygon and math.isclose(polygon.area, buffered.area, abs_tol=0.5):
+ polygon = shgeo.MultiPolygon([buffered])
+
+ return polygon
+
+ def shape_is_valid(self, shape):
+ # Shapely will log to stdout to complain about the shape unless we make
+ # it shut up.
+ logger = logging.getLogger('shapely.geos')
+ level = logger.level
+ logger.setLevel(logging.CRITICAL)
+
+ valid = shape.is_valid
+
+ logger.setLevel(level)
+
+ return valid
+
+ def validation_errors(self):
+ if not self.shape_is_valid(self.shape):
+ why = explain_validity(self.shape)
+ message, x, y = re.findall(r".+?(?=\[)|-?\d+(?:\.\d+)?", why)
+
+ # I Wish this weren't so brittle...
+ if "Hole lies outside shell" in message:
+ yield UnconnectedError((x, y))
+ else:
+ yield InvalidShapeError((x, y))
+
+ def validation_warnings(self):
+ if self.shape.area < 20:
+ label = self.node.get(INKSCAPE_LABEL) or self.node.get("id")
+ yield SmallShapeWarning(self.shape.centroid, label)
+
+ if self.shrink_or_grow_shape(self.expand, True).is_empty:
+ yield ExpandWarning(self.shape.centroid)
+
+ if self.shrink_or_grow_shape(-self.fill_underlay_inset, True).is_empty:
+ yield UnderlayInsetWarning(self.shape.centroid)
+
+ # guided fill warnings
+ if self.fill_method == 2:
+ guide_lines = self._get_guide_lines(True)
+ if not guide_lines or guide_lines[0].is_empty:
+ yield MissingGuideLineWarning(self.shape.centroid)
+ elif len(guide_lines) > 1:
+ yield MultipleGuideLineWarning(self.shape.centroid)
+ elif guide_lines[0].disjoint(self.shape):
+ yield DisjointGuideLineWarning(self.shape.centroid)
+ return None
+
+ for warning in super(FillStitch, self).validation_warnings():
+ yield warning
+
+ @property
+ @cache
def outline(self):
return self.shape.boundary[0]
@@ -308,52 +431,6 @@ class AutoFill(EmbroideryElement):
def underlay_underpath(self):
return self.get_boolean_param('underlay_underpath', True)
- @property
- @cache
- def shape(self):
- # shapely's idea of "holes" are to subtract everything in the second set
- # from the first. So let's at least make sure the "first" thing is the
- # biggest path.
- paths = self.paths
- paths.sort(key=lambda point_list: shgeo.Polygon(
- point_list).area, reverse=True)
- # Very small holes will cause a shape to be rendered as an outline only
- # they are too small to be rendered and only confuse the auto_fill algorithm.
- # So let's ignore them
- if shgeo.Polygon(paths[0]).area > 5 and shgeo.Polygon(paths[-1]).area < 5:
- paths = [path for path in paths if shgeo.Polygon(path).area > 3]
-
- polygon = shgeo.MultiPolygon([(paths[0], paths[1:])])
-
- # There is a great number of "crossing border" errors on fill shapes
- # If the polygon fails, we can try to run buffer(0) on the polygon in the
- # hope it will fix at least some of them
- if not self.shape_is_valid(polygon):
- why = explain_validity(polygon)
- message = re.match(r".+?(?=\[)", why)
- if message.group(0) == "Self-intersection":
- buffered = polygon.buffer(0)
- # we do not want to break apart into multiple objects (possibly in the future?!)
- # best way to distinguish the resulting polygon is to compare the area size of the two
- # and make sure users will not experience significantly altered shapes without a warning
- if math.isclose(polygon.area, buffered.area):
- polygon = shgeo.MultiPolygon([buffered])
-
- return polygon
-
- def shape_is_valid(self, shape):
- # Shapely will log to stdout to complain about the shape unless we make
- # it shut up.
- logger = logging.getLogger('shapely.geos')
- level = logger.level
- logger.setLevel(logging.CRITICAL)
-
- valid = shape.is_valid
-
- logger.setLevel(level)
-
- return valid
-
def shrink_or_grow_shape(self, amount, validate=False):
if amount:
shape = self.shape.buffer(amount)
@@ -392,142 +469,156 @@ class AutoFill(EmbroideryElement):
else:
return None
- def to_stitch_groups(self, last_patch): # noqa: C901
- # TODO: split this up do_legacy_fill() etc.
- stitch_groups = []
+ def to_stitch_groups(self, last_patch):
+ # backwards compatibility: legacy_fill used to be inkstitch:auto_fill == False
+ if not self.auto_fill or self.fill_method == 3:
+ return self.do_legacy_fill()
+ else:
+ stitch_groups = []
+ start = self.get_starting_point(last_patch)
+ end = self.get_ending_point()
- starting_point = self.get_starting_point(last_patch)
- ending_point = self.get_ending_point()
-
- try:
- if self.fill_underlay:
- for i in range(len(self.fill_underlay_angle)):
- underlay = StitchGroup(
- color=self.color,
- tags=("auto_fill", "auto_fill_underlay"),
- stitches=auto_fill(
- self.underlay_shape,
- None,
- self.fill_underlay_angle[i],
- self.fill_underlay_row_spacing,
- self.fill_underlay_row_spacing,
- self.fill_underlay_max_stitch_length,
- self.running_stitch_length,
- self.staggers,
- self.fill_underlay_skip_last,
- starting_point,
- underpath=self.underlay_underpath))
- stitch_groups.append(underlay)
- starting_point = underlay.stitches[-1]
-
- if self.fill_method == 0: # Auto Fill
- stitch_group = StitchGroup(
- color=self.color,
- tags=("auto_fill", "auto_fill_top"),
- stitches=auto_fill(
- self.fill_shape,
- None,
- self.angle,
- self.row_spacing,
- self.end_row_spacing,
- self.max_stitch_length,
- self.running_stitch_length,
- self.staggers,
- self.skip_last,
- starting_point,
- ending_point,
- self.underpath))
- stitch_groups.append(stitch_group)
- elif self.fill_method == 1: # Tangential Fill
- polygons = list(self.fill_shape)
- if not starting_point:
- starting_point = (0, 0)
- for poly in polygons:
- connectedLine, connectedLineOrigin = StitchPattern.offset_poly(
- poly,
- -self.row_spacing,
- self.join_style+1,
- self.max_stitch_length,
- self.interlaced,
- self.tangential_strategy,
- shgeo.Point(starting_point))
- path = [InkstitchPoint(*p) for p in connectedLine]
- stitch_group = StitchGroup(
- color=self.color,
- tags=("auto_fill", "auto_fill_top"),
- stitches=path)
- stitch_groups.append(stitch_group)
- elif self.fill_method == 2: # Guided Auto Fill
- lines = get_marker_elements(self.node, "guide-line", False, True)
- lines = lines['stroke']
- if not lines or lines[0].is_empty:
- inkex.errormsg(
- _("No line marked as guide line found within the same group as patch"))
- else:
- stitch_group = StitchGroup(
- color=self.color,
- tags=("auto_fill", "auto_fill_top"),
- stitches=auto_fill(
- self.fill_shape,
- lines[0].geoms[0],
- self.angle,
- self.row_spacing,
- self.end_row_spacing,
- self.max_stitch_length,
- self.running_stitch_length,
- 0,
- self.skip_last,
- starting_point,
- ending_point,
- self.underpath,
- self.interlaced))
- stitch_groups.append(stitch_group)
- elif self.fill_method == 3: # Legacy Fill
- stitch_lists = fill.legacy_fill(self.shape,
- self.angle,
- self.row_spacing,
- self.end_row_spacing,
- self.max_stitch_length,
- self.flip,
- self.staggers,
- self.skip_last)
- for stitch_list in stitch_lists:
- stitch_group = StitchGroup(
- color=self.color,
- tags=("auto_fill", "auto_fill_top"),
- stitches=stitch_list)
- stitch_groups.append(stitch_group)
-
- except Exception:
- if hasattr(sys, 'gettrace') and sys.gettrace():
- # if we're debugging, let the exception bubble up
- raise
-
- # for an uncaught exception, give a little more info so that they can create a bug report
- message = ""
- message += _("Error during autofill! This means that there is a problem with Ink/Stitch.")
- message += "\n\n"
- # L10N this message is followed by a URL: https://github.com/inkstitch/inkstitch/issues/new
- message += _("If you'd like to help us make Ink/Stitch better, please paste this whole message into a new issue at: ")
- message += "https://github.com/inkstitch/inkstitch/issues/new\n\n"
- message += version.get_inkstitch_version() + "\n\n"
- message += traceback.format_exc()
-
- self.fatal(message)
+ try:
+ if self.fill_underlay:
+ underlay_stitch_groups, start = self.do_underlay(start)
+ stitch_groups.extend(underlay_stitch_groups)
+ if self.fill_method == 0:
+ stitch_groups.extend(self.do_auto_fill(last_patch, start, end))
+ if self.fill_method == 1:
+ stitch_groups.extend(self.do_tangential_fill(last_patch, start))
+ elif self.fill_method == 2:
+ stitch_groups.extend(self.do_guided_fill(last_patch, start, end))
+ except Exception:
+ self.fatal_fill_error()
+
+ return stitch_groups
+
+ def do_legacy_fill(self):
+ stitch_lists = legacy_fill(self.shape,
+ self.angle,
+ self.row_spacing,
+ self.end_row_spacing,
+ self.max_stitch_length,
+ self.flip,
+ self.staggers,
+ self.skip_last)
+ return [StitchGroup(stitches=stitch_list, color=self.color) for stitch_list in stitch_lists]
+
+ def do_underlay(self, starting_point):
+ stitch_groups = []
+ for i in range(len(self.fill_underlay_angle)):
+ underlay = StitchGroup(
+ color=self.color,
+ tags=("auto_fill", "auto_fill_underlay"),
+ stitches=auto_fill(
+ self.underlay_shape,
+ None,
+ self.fill_underlay_angle[i],
+ self.fill_underlay_row_spacing,
+ self.fill_underlay_row_spacing,
+ self.fill_underlay_max_stitch_length,
+ self.running_stitch_length,
+ self.staggers,
+ self.fill_underlay_skip_last,
+ starting_point,
+ underpath=self.underlay_underpath))
+ stitch_groups.append(underlay)
+
+ starting_point = underlay.stitches[-1]
+ return [stitch_groups, starting_point]
+
+ def do_auto_fill(self, last_patch, starting_point, ending_point):
+ stitch_group = StitchGroup(
+ color=self.color,
+ tags=("auto_fill", "auto_fill_top"),
+ stitches=auto_fill(
+ self.fill_shape,
+ None,
+ self.angle,
+ self.row_spacing,
+ self.end_row_spacing,
+ self.max_stitch_length,
+ self.running_stitch_length,
+ self.staggers,
+ self.skip_last,
+ starting_point,
+ ending_point,
+ self.underpath))
+ return [stitch_group]
+
+ def do_tangential_fill(self, last_patch, starting_point):
+ stitch_groups = []
+ polygons = list(self.fill_shape)
+ if not starting_point:
+ starting_point = (0, 0)
+ for poly in polygons:
+ connectedLine, connectedLineOrigin = StitchPattern.offset_poly(
+ poly,
+ -self.row_spacing,
+ self.join_style+1,
+ self.max_stitch_length,
+ self.interlaced,
+ self.tangential_strategy,
+ shgeo.Point(starting_point))
+ path = [InkstitchPoint(*p) for p in connectedLine]
+ stitch_group = StitchGroup(
+ color=self.color,
+ tags=("auto_fill", "auto_fill_top"),
+ stitches=path)
+ stitch_groups.append(stitch_group)
return stitch_groups
+ def do_guided_fill(self, last_patch, starting_point, ending_point):
+ guide_line = self._get_guide_lines()
+
+ # No guide line: fallback to normal autofill
+ if not guide_line:
+ return self.do_auto_fill(last_patch, starting_point, ending_point)
+
+ stitch_group = StitchGroup(
+ color=self.color,
+ tags=("auto_fill", "auto_fill_top"),
+ stitches=auto_fill(
+ self.fill_shape,
+ guide_line.geoms[0],
+ self.angle,
+ self.row_spacing,
+ self.end_row_spacing,
+ self.max_stitch_length,
+ self.running_stitch_length,
+ 0,
+ self.skip_last,
+ starting_point,
+ ending_point,
+ self.underpath,
+ self.interlaced))
+ return [stitch_group]
-def validation_warnings(self):
- if self.shape.area < 20:
- label = self.node.get(INKSCAPE_LABEL) or self.node.get("id")
- yield SmallShapeWarning(self.shape.centroid, label)
-
- if self.shrink_or_grow_shape(self.expand, True).is_empty:
- yield ExpandWarning(self.shape.centroid)
-
- if self.shrink_or_grow_shape(-self.fill_underlay_inset, True).is_empty:
- yield UnderlayInsetWarning(self.shape.centroid)
-
- for warning in super(AutoFill, self).validation_warnings():
- yield warning
+ @cache
+ def _get_guide_lines(self, multiple=False):
+ guide_lines = get_marker_elements(self.node, "guide-line", False, True)
+ # No or empty guide line
+ if not guide_lines or guide_lines['stroke'][0].is_empty:
+ return None
+ if multiple:
+ return guide_lines['stroke']
+ else:
+ return guide_lines['stroke'][0]
+
+ def fatal_fill_error(self):
+ if hasattr(sys, 'gettrace') and sys.gettrace():
+ # if we're debugging, let the exception bubble up
+ raise
+
+ # for an uncaught exception, give a little more info so that they can create a bug report
+ message = ""
+ message += _("Error during autofill! This means that there is a problem with Ink/Stitch.")
+ message += "\n\n"
+ # L10N this message is followed by a URL: https://github.com/inkstitch/inkstitch/issues/new
+ message += _("If you'd like to help us make Ink/Stitch better, please paste this whole message into a new issue at: ")
+ message += "https://github.com/inkstitch/inkstitch/issues/new\n\n"
+ message += version.get_inkstitch_version() + "\n\n"
+ message += traceback.format_exc()
+
+ self.fatal(message)
diff --git a/lib/elements/pattern.py b/lib/elements/marker.py
index 4b92d366..574ce91e 100644
--- a/lib/elements/pattern.py
+++ b/lib/elements/marker.py
@@ -10,24 +10,23 @@ from .element import EmbroideryElement
from .validation import ObjectTypeWarning
-class PatternWarning(ObjectTypeWarning):
- name = _("Pattern Element")
+class MarkerWarning(ObjectTypeWarning):
+ name = _("Marker Element")
description = _("This element will not be embroidered. "
- "It will appear as a pattern applied to objects in the same group as it. "
- "Objects in sub-groups will be ignored.")
+ "It will be applied to objects in the same group. Objects in sub-groups will be ignored.")
steps_to_solve = [
- _("To disable pattern mode, remove the pattern marker:"),
+ _("Turn back to normal embroidery element mode, remove the marker:"),
_('* Open the Fill and Stroke panel (Objects > Fill and Stroke)'),
_('* Go to the Stroke style tab'),
_('* Under "Markers" choose the first (empty) option in the first dropdown list.')
]
-class PatternObject(EmbroideryElement):
+class MarkerObject(EmbroideryElement):
def validation_warnings(self):
repr_point = next(inkex.Path(self.parse_path()).end_points)
- yield PatternWarning(repr_point)
+ yield MarkerWarning(repr_point)
def to_stitch_groups(self, last_patch):
return []
diff --git a/lib/elements/utils.py b/lib/elements/utils.py
index 9b9b8f14..561188aa 100644
--- a/lib/elements/utils.py
+++ b/lib/elements/utils.py
@@ -7,12 +7,12 @@ from ..commands import is_command
from ..marker import has_marker
from ..svg.tags import (EMBROIDERABLE_TAGS, SVG_IMAGE_TAG, SVG_PATH_TAG,
SVG_POLYLINE_TAG, SVG_TEXT_TAG)
-from .auto_fill import AutoFill
+from .fill_stitch import FillStitch
from .clone import Clone, is_clone
from .element import EmbroideryElement
from .empty_d_object import EmptyDObject
from .image import ImageObject
-from .pattern import PatternObject
+from .marker import MarkerObject
from .polyline import Polyline
from .satin_column import SatinColumn
from .stroke import Stroke
@@ -29,8 +29,8 @@ def node_to_elements(node): # noqa: C901
elif node.tag == SVG_PATH_TAG and not node.get('d', ''):
return [EmptyDObject(node)]
- elif has_marker(node, 'pattern'):
- return [PatternObject(node)]
+ elif has_marker(node):
+ return [MarkerObject(node)]
elif node.tag in EMBROIDERABLE_TAGS:
element = EmbroideryElement(node)
@@ -40,10 +40,7 @@ def node_to_elements(node): # noqa: C901
else:
elements = []
if element.get_style("fill", "black") and not element.get_style('fill-opacity', 1) == "0":
- # if element.get_boolean_param("auto_fill", True):
- elements.append(AutoFill(node))
- # else:
- # elements.append(Fill(node))
+ elements.append(FillStitch(node))
if element.get_style("stroke"):
if not is_command(element.node):
elements.append(Stroke(node))
diff --git a/lib/extensions/base.py b/lib/extensions/base.py
index cf846324..949f947e 100644
--- a/lib/extensions/base.py
+++ b/lib/extensions/base.py
@@ -161,10 +161,10 @@ class InkstitchExtension(inkex.Effect):
if selected:
if node.tag == SVG_GROUP_TAG:
pass
- elif (node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not has_marker(node, 'pattern'):
+ elif (node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not has_marker(node):
nodes.append(node)
- # add images, text and patterns for the troubleshoot extension
- elif troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or has_marker(node, 'pattern')):
+ # add images, text and elements with a marker for the troubleshoot extension
+ elif troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or has_marker(node)):
nodes.append(node)
return nodes
diff --git a/lib/extensions/cleanup.py b/lib/extensions/cleanup.py
index ae95041b..4c350d62 100644
--- a/lib/extensions/cleanup.py
+++ b/lib/extensions/cleanup.py
@@ -5,7 +5,7 @@
from inkex import NSS, Boolean, errormsg
-from ..elements import AutoFill, Stroke
+from ..elements import FillStitch, Stroke
from ..i18n import _
from .base import InkstitchExtension
@@ -38,7 +38,7 @@ class Cleanup(InkstitchExtension):
return
for element in self.elements:
- if (isinstance(element, AutoFill) and self.rm_fill and element.shape.area < self.fill_threshold):
+ if (isinstance(element, FillStitch) and self.rm_fill and element.shape.area < self.fill_threshold):
element.node.getparent().remove(element.node)
count += 1
if (isinstance(element, Stroke) and self.rm_stroke and
diff --git a/lib/extensions/params.py b/lib/extensions/params.py
index 55963625..69a559ce 100644
--- a/lib/extensions/params.py
+++ b/lib/extensions/params.py
@@ -15,7 +15,7 @@ import wx
from wx.lib.scrolledpanel import ScrolledPanel
from ..commands import is_command, is_command_symbol
-from ..elements import (AutoFill, Clone, EmbroideryElement, Polyline,
+from ..elements import (FillStitch, Clone, EmbroideryElement, Polyline,
SatinColumn, Stroke)
from ..elements.clone import is_clone
from ..gui import PresetsPanel, SimulatorPreview, WarningPanel
@@ -606,8 +606,7 @@ class Params(InkstitchExtension):
classes.append(Clone)
else:
if element.get_style("fill", 'black') and not element.get_style("fill-opacity", 1) == "0":
- classes.append(AutoFill)
- # classes.append(Fill)
+ classes.append(FillStitch)
if element.get_style("stroke") is not None:
classes.append(Stroke)
if element.get_style("stroke-dasharray") is None:
diff --git a/lib/marker.py b/lib/marker.py
index 3c145145..56a43c3b 100644
--- a/lib/marker.py
+++ b/lib/marker.py
@@ -69,8 +69,11 @@ def get_marker_elements(node, marker, get_fills=True, get_strokes=True):
return {'fill': fills, 'stroke': strokes}
-def has_marker(node, marker):
- if node.tag not in EMBROIDERABLE_TAGS:
- return False
- style = node.get('style') or ''
- return "marker-start:url(#inkstitch-%s-marker)" % marker in style
+def has_marker(node, marker=list()):
+ if not marker:
+ marker = MARKER
+ for m in marker:
+ style = node.get('style') or ''
+ if "marker-start:url(#inkstitch-%s-marker)" % m in style:
+ return True
+ return False
diff --git a/symbols/marker.svg b/symbols/marker.svg
index 28f4f44d..45219073 100644
--- a/symbols/marker.svg
+++ b/symbols/marker.svg
@@ -34,21 +34,21 @@
</g>
</marker>
<marker
- refX="10"
- refY="5"
- orient="auto"
- id="inkstitch-guide-line-marker">
- <g
- id="inkstitch-guide-line-group">
- <path
- style="fill:#fafafa;stroke:#ff00ff;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;fill-opacity:0.8;"
- d="M 10.12911,5.2916678 A 4.8374424,4.8374426 0 0 1 5.2916656,10.12911 4.8374424,4.8374426 0 0 1 0.45422399,5.2916678 4.8374424,4.8374426 0 0 1 5.2916656,0.45422399 4.8374424,4.8374426 0 0 1 10.12911,5.2916678 Z"
- id="inkstitch-guide-line-marker-circle" />
- <path
- style="fill:none;stroke:#ff00ff;stroke-width:0.4;stroke-linecap:round;stroke-miterlimit:4;"
- id="inkstitch-guide-line-marker-spiral"
- d="M 4.9673651,5.7245662 C 4.7549848,5.7646159 4.6247356,5.522384 4.6430021,5.3419847 4.6765851,5.0103151 5.036231,4.835347 5.3381858,4.8987426 5.7863901,4.9928495 6.0126802,5.4853625 5.9002872,5.9065088 5.7495249,6.4714237 5.1195537,6.7504036 4.5799191,6.5874894 3.898118,6.3816539 3.5659013,5.6122905 3.7800789,4.9545192 4.0402258,4.1556558 4.9498996,3.7699484 5.7256318,4.035839 6.6416744,4.3498087 7.0810483,5.4003986 6.7631909,6.2939744 6.395633,7.3272552 5.2038143,7.8204128 4.1924535,7.4503931 3.0418762,7.0294421 2.4948761,5.6961604 2.9171752,4.567073 3.3914021,3.2991406 4.8663228,2.6982592 6.1130974,3.1729158 7.4983851,3.7003207 8.1531869,5.3169977 7.6260947,6.6814205 7.0456093,8.1841025 5.2870784,8.8928844 3.8050073,8.3132966 2.1849115,7.6797506 1.4221671,5.7793073 2.0542715,4.1796074 2.7408201,2.4420977 4.7832541,1.6253548 6.5005435,2.310012 8.3554869,3.0495434 9.2262638,5.2339874 8.4890181,7.0688861 8.4256397,7.2266036 8.3515789,7.379984 8.2675333,7.5277183" />
- </g>
- </marker>
+ refX="10"
+ refY="5"
+ orient="auto"
+ id="inkstitch-guide-line-marker">
+ <g
+ id="inkstitch-guide-line-group">
+ <path
+ style="fill:#fafafa;stroke:#ff5500;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;fill-opacity:0.8;"
+ d="M 10.12911,5.2916678 A 4.8374424,4.8374426 0 0 1 5.2916656,10.12911 4.8374424,4.8374426 0 0 1 0.45422399,5.2916678 4.8374424,4.8374426 0 0 1 5.2916656,0.45422399 4.8374424,4.8374426 0 0 1 10.12911,5.2916678 Z"
+ id="inkstitch-guide-line-marker-circle" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-miterlimit:4;"
+ id="inkstitch-guide-line-marker-spiral"
+ d="M 1.7506092,6.2728168 3.4558825,5.2833684 7.1038696,7.400035 8.8193256,6.4046783 M 1.7963222,4.129626 3.4558825,3.1667016 7.1038696,5.2833682 8.8475785,4.2716184 M 1.6318889,5.2833683 3.4558825,4.225035 7.1038696,6.3417016 8.9558408,5.2677331" />
+ </g>
+ </marker>
</defs>
</svg>