summaryrefslogtreecommitdiff
path: root/lib/elements/fill.py
diff options
context:
space:
mode:
authorKaalleen <36401965+kaalleen@users.noreply.github.com>2019-08-06 04:42:48 +0200
committerLex Neva <lexelby@users.noreply.github.com>2019-08-05 22:42:48 -0400
commit077f7ea72ba38790bf030d3181c44787fef953b6 (patch)
tree1cd8bf2896d587735c98eee06589f4c88bee3aa9 /lib/elements/fill.py
parentcdb8d1d0d4a6dba9a1eb146167b1aef01de0e9d6 (diff)
add Troubleshoot extension (#465)
adds an extension to help you understand what's wrong with an object and how to fix it, e.g. "invalid" fill shapes
Diffstat (limited to 'lib/elements/fill.py')
-rw-r--r--lib/elements/fill.py54
1 files changed, 44 insertions, 10 deletions
diff --git a/lib/elements/fill.py b/lib/elements/fill.py
index 7ccf7b27..7157cc46 100644
--- a/lib/elements/fill.py
+++ b/lib/elements/fill.py
@@ -1,4 +1,6 @@
+import logging
import math
+import re
from shapely import geometry as shgeo
from shapely.validation import explain_validity
@@ -7,7 +9,29 @@ from ..i18n import _
from ..stitches import legacy_fill
from ..svg import PIXELS_PER_MM
from ..utils import cache
-from .element import param, EmbroideryElement, Patch
+from .element import EmbroideryElement, Patch, param
+from .validation import ValidationError
+
+
+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 = [
+ _('* Path > Break apart (Shift+Ctrl+K)'),
+ _('* (Optional) Recombine shapes with holes (Ctrl+K).')
+ ]
+
+
+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 = [
+ _('* Path > Union (Ctrl++)'),
+ _('* Path > Break apart (Shift+Ctrl+K)'),
+ _('* (Optional) Recombine shapes with holes (Ctrl+K).')
+ ]
class Fill(EmbroideryElement):
@@ -112,18 +136,28 @@ class Fill(EmbroideryElement):
paths.sort(key=lambda point_list: shgeo.Polygon(point_list).area, reverse=True)
polygon = shgeo.MultiPolygon([(paths[0], paths[1:])])
- if not polygon.is_valid:
- why = explain_validity(polygon)
+ return polygon
+
+ def validation_errors(self):
+ # 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 = self.shape.is_valid
+
+ logger.setLevel(level)
+
+ if not valid:
+ 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 why:
- self.fatal(_("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."))
+ if "Hole lies outside shell" in message:
+ yield UnconnectedError((x, y))
else:
- self.fatal(_("shape is not valid. This can happen if the border crosses over itself."))
-
- return polygon
+ yield InvalidShapeError((x, y))
def to_patches(self, last_patch):
stitch_lists = legacy_fill(self.shape,