kopia lustrzana https://github.com/inkstitch/inkstitch
improve params errors (#2437)
rodzic
3db335b0f4
commit
af96d720e9
electron/src/renderer
assets
style
components
lib
elements
extensions
gui
stitches
|
@ -54,7 +54,9 @@ export default {
|
|||
showNeedlePenetrationPoints: false,
|
||||
renderJumps: true,
|
||||
showRealisticPreview: false,
|
||||
showCursor: true
|
||||
showCursor: true,
|
||||
error: false,
|
||||
error_message: ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -543,6 +545,9 @@ export default {
|
|||
zoomPage () {
|
||||
this.svg.viewbox(this.page_specs.bbox.x, this.page_specs.bbox.y - 50, this.page_specs.bbox.width + 100, this.page_specs.bbox.height + 100)
|
||||
this.resizeCursor()
|
||||
},
|
||||
close () {
|
||||
window.close()
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
|
@ -642,6 +647,19 @@ export default {
|
|||
})
|
||||
|
||||
this.start()
|
||||
}).catch(error => {
|
||||
this.loading = false
|
||||
if (error.response) {
|
||||
// Stitch plan generation had an error. Show it to the user.
|
||||
this.error_message = error.response.data.error_message
|
||||
} else if (error.request) {
|
||||
// We sent the request and didn't get a response.
|
||||
this.error_message = "Stitch plan generation failed."
|
||||
} else {
|
||||
// Something weird happened in axios.
|
||||
this.error_message = error.message
|
||||
}
|
||||
this.error = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
padding: 1rem;
|
||||
}
|
||||
|
||||
button {
|
||||
.controls button {
|
||||
color: rgb(0, 51, 153);
|
||||
align-items: flex-start;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
background: linear-gradient(0deg, rgba(169,169,169,1) 0%, rgba(255,255,255,1) 68%, rgba(227,227,227,1) 100%);
|
||||
background: linear-gradient(0deg, rgba(169, 169, 169, 1) 0%, rgba(255, 255, 255, 1) 68%, rgba(227, 227, 227, 1) 100%);
|
||||
box-sizing: border-box;
|
||||
padding: 2px 6px 3px;
|
||||
border-width: 2px;
|
||||
|
|
|
@ -306,6 +306,19 @@
|
|||
</div>
|
||||
</div>
|
||||
</loading>
|
||||
<v-dialog v-model="error" width="auto">
|
||||
<v-card flat>
|
||||
<v-card-title class="pa-4">
|
||||
Error Generating Stitch Plan
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<p style="white-space: pre-wrap;">{{ error_message }}</p>
|
||||
</v-card-text>
|
||||
<v-card-actions class="justify-center">
|
||||
<v-btn color="primary" variant="text" class="dialog-button" @click="close">Close</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
24
inkstitch.py
24
inkstitch.py
|
@ -7,10 +7,11 @@ import pstats
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from argparse import ArgumentParser
|
||||
from io import StringIO
|
||||
|
||||
from lib.exceptions import InkstitchException, format_uncaught_exception
|
||||
|
||||
if getattr(sys, 'frozen', None) is None:
|
||||
# When running in development mode, we want to use the inkex installed by
|
||||
# pip install, not the one bundled with Inkscape which is not new enough.
|
||||
|
@ -28,7 +29,7 @@ from lxml.etree import XMLSyntaxError
|
|||
import lib.debug as debug
|
||||
from lib import extensions
|
||||
from lib.i18n import _
|
||||
from lib.utils import restore_stderr, save_stderr, version
|
||||
from lib.utils import restore_stderr, save_stderr
|
||||
|
||||
# ignore warnings in releases
|
||||
if getattr(sys, 'frozen', None):
|
||||
|
@ -90,24 +91,15 @@ else:
|
|||
msg += "\n\n"
|
||||
msg += _("Try to import the file into Inkscape through 'File > Import...' (Ctrl+I)")
|
||||
errormsg(msg)
|
||||
except InkstitchException as exc:
|
||||
errormsg(str(exc))
|
||||
except Exception:
|
||||
exception = traceback.format_exc()
|
||||
errormsg(format_uncaught_exception())
|
||||
sys.exit(1)
|
||||
finally:
|
||||
restore_stderr()
|
||||
|
||||
if shapely_errors.tell():
|
||||
errormsg(shapely_errors.getvalue())
|
||||
|
||||
if exception:
|
||||
errormsg(_("Ink/Stitch experienced an unexpected error. This means it is a bug in Ink/Stitch.") + "\n")
|
||||
errormsg(_("If you'd like to help please\n"
|
||||
"- copy the entire error message below\n"
|
||||
"- save your SVG file and\n"
|
||||
"- create a new issue at https://github.com/inkstitch/inkstitch/issues") + "\n")
|
||||
errormsg(_("Include the error description and also (if possible) "
|
||||
"the svg file.") + "\n")
|
||||
errormsg(version.get_inkstitch_version() + "\n")
|
||||
errormsg(exception)
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
sys.exit(0)
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
from flask import Blueprint, g, jsonify
|
||||
|
||||
from ..exceptions import InkstitchException, format_uncaught_exception
|
||||
from ..stitch_plan import stitch_groups_to_stitch_plan
|
||||
|
||||
|
||||
stitch_plan = Blueprint('stitch_plan', __name__)
|
||||
|
||||
|
||||
|
@ -16,10 +16,14 @@ def get_stitch_plan():
|
|||
if not g.extension.get_elements():
|
||||
return dict(colors=[], stitch_blocks=[], commands=[])
|
||||
|
||||
metadata = g.extension.get_inkstitch_metadata()
|
||||
collapse_len = metadata['collapse_len_mm']
|
||||
min_stitch_len = metadata['min_stitch_len_mm']
|
||||
patches = g.extension.elements_to_stitch_groups(g.extension.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
|
||||
return jsonify(stitch_plan)
|
||||
try:
|
||||
metadata = g.extension.get_inkstitch_metadata()
|
||||
collapse_len = metadata['collapse_len_mm']
|
||||
min_stitch_len = metadata['min_stitch_len_mm']
|
||||
patches = g.extension.elements_to_stitch_groups(g.extension.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
return jsonify(stitch_plan)
|
||||
except InkstitchException as exc:
|
||||
return jsonify({"error_message": str(exc)}), 500
|
||||
except Exception:
|
||||
return jsonify({"error_message": format_uncaught_exception()}), 500
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from copy import deepcopy
|
||||
|
||||
import inkex
|
||||
|
@ -11,6 +12,7 @@ from inkex import bezier
|
|||
|
||||
from ..commands import find_commands
|
||||
from ..debug import debug
|
||||
from ..exceptions import InkstitchException, format_uncaught_exception
|
||||
from ..i18n import _
|
||||
from ..marker import get_marker_elements_cache_key_data
|
||||
from ..patterns import apply_patterns, get_patterns_cache_key_data
|
||||
|
@ -546,23 +548,25 @@ class EmbroideryElement(object):
|
|||
|
||||
def embroider(self, last_stitch_group):
|
||||
debug.log(f"starting {self.node.get('id')} {self.node.get(INKSCAPE_LABEL)}")
|
||||
if last_stitch_group:
|
||||
previous_stitch = last_stitch_group.stitches[-1]
|
||||
else:
|
||||
previous_stitch = None
|
||||
stitch_groups = self._load_cached_stitch_groups(previous_stitch)
|
||||
|
||||
if not stitch_groups:
|
||||
self.validate()
|
||||
with self.handle_unexpected_exceptions():
|
||||
if last_stitch_group:
|
||||
previous_stitch = last_stitch_group.stitches[-1]
|
||||
else:
|
||||
previous_stitch = None
|
||||
stitch_groups = self._load_cached_stitch_groups(previous_stitch)
|
||||
|
||||
stitch_groups = self.to_stitch_groups(last_stitch_group)
|
||||
apply_patterns(stitch_groups, self.node)
|
||||
if not stitch_groups:
|
||||
self.validate()
|
||||
|
||||
if stitch_groups:
|
||||
stitch_groups[-1].trim_after = self.has_command("trim") or self.trim_after
|
||||
stitch_groups[-1].stop_after = self.has_command("stop") or self.stop_after
|
||||
stitch_groups = self.to_stitch_groups(last_stitch_group)
|
||||
apply_patterns(stitch_groups, self.node)
|
||||
|
||||
self._save_cached_stitch_groups(stitch_groups, previous_stitch)
|
||||
if stitch_groups:
|
||||
stitch_groups[-1].trim_after = self.has_command("trim") or self.trim_after
|
||||
stitch_groups[-1].stop_after = self.has_command("stop") or self.stop_after
|
||||
|
||||
self._save_cached_stitch_groups(stitch_groups, previous_stitch)
|
||||
|
||||
debug.log(f"ending {self.node.get('id')} {self.node.get(INKSCAPE_LABEL)}")
|
||||
return stitch_groups
|
||||
|
@ -575,14 +579,27 @@ class EmbroideryElement(object):
|
|||
else:
|
||||
name = id
|
||||
|
||||
# L10N used when showing an error message to the user such as
|
||||
# "Failed on PathLabel (path1234): Satin column: One or more of the rungs doesn't intersect both rails."
|
||||
error_msg = "%s %s: %s" % (_("Failed on "), name, message)
|
||||
error_msg = f"{name}: {message}"
|
||||
if point_to_troubleshoot:
|
||||
error_msg += "\n\n%s" % _("Please run Extensions > Ink/Stitch > Troubleshoot > Troubleshoot objects. "
|
||||
"This will indicate the errorneus position.")
|
||||
inkex.errormsg(error_msg)
|
||||
sys.exit(1)
|
||||
"This will show you the exact location of the problem.")
|
||||
|
||||
raise InkstitchException(error_msg)
|
||||
|
||||
@contextmanager
|
||||
def handle_unexpected_exceptions(self):
|
||||
try:
|
||||
# This runs the code in the `with` body so that we can catch
|
||||
# exceptions.
|
||||
yield
|
||||
except (InkstitchException, SystemExit, KeyboardInterrupt):
|
||||
raise
|
||||
except Exception:
|
||||
if hasattr(sys, 'gettrace') and sys.gettrace():
|
||||
# if we're debugging, let the exception bubble up
|
||||
raise
|
||||
|
||||
raise InkstitchException(format_uncaught_exception())
|
||||
|
||||
def validation_errors(self):
|
||||
"""Return a list of errors with this Element.
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
import logging
|
||||
import math
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import numpy as np
|
||||
from inkex import Transform
|
||||
|
@ -25,9 +23,8 @@ from ..stitches.meander_fill import meander_fill
|
|||
from ..svg import PIXELS_PER_MM, get_node_transform
|
||||
from ..svg.clip import get_clip_path
|
||||
from ..svg.tags import INKSCAPE_LABEL
|
||||
from ..utils import cache, version
|
||||
from ..utils import cache
|
||||
from ..utils.param import ParamOption
|
||||
from ..utils.threading import ExitThread
|
||||
from .element import EmbroideryElement, param
|
||||
from .validation import ValidationError, ValidationWarning
|
||||
|
||||
|
@ -706,30 +703,25 @@ class FillStitch(EmbroideryElement):
|
|||
|
||||
for shape in self.shape.geoms:
|
||||
start = self.get_starting_point(previous_stitch_group)
|
||||
try:
|
||||
if self.fill_underlay:
|
||||
underlay_shapes = self.underlay_shape(shape)
|
||||
for underlay_shape in underlay_shapes.geoms:
|
||||
underlay_stitch_groups, start = self.do_underlay(underlay_shape, start)
|
||||
stitch_groups.extend(underlay_stitch_groups)
|
||||
if self.fill_underlay:
|
||||
underlay_shapes = self.underlay_shape(shape)
|
||||
for underlay_shape in underlay_shapes.geoms:
|
||||
underlay_stitch_groups, start = self.do_underlay(underlay_shape, start)
|
||||
stitch_groups.extend(underlay_stitch_groups)
|
||||
|
||||
fill_shapes = self.fill_shape(shape)
|
||||
for i, fill_shape in enumerate(fill_shapes.geoms):
|
||||
if self.fill_method == 'contour_fill':
|
||||
stitch_groups.extend(self.do_contour_fill(fill_shape, previous_stitch_group, start))
|
||||
elif self.fill_method == 'guided_fill':
|
||||
stitch_groups.extend(self.do_guided_fill(fill_shape, previous_stitch_group, start, end))
|
||||
elif self.fill_method == 'meander_fill':
|
||||
stitch_groups.extend(self.do_meander_fill(fill_shape, shape, i, start, end))
|
||||
elif self.fill_method == 'circular_fill':
|
||||
stitch_groups.extend(self.do_circular_fill(fill_shape, previous_stitch_group, start, end))
|
||||
else:
|
||||
# auto_fill
|
||||
stitch_groups.extend(self.do_auto_fill(fill_shape, previous_stitch_group, start, end))
|
||||
except ExitThread:
|
||||
raise
|
||||
except Exception:
|
||||
self.fatal_fill_error()
|
||||
fill_shapes = self.fill_shape(shape)
|
||||
for i, fill_shape in enumerate(fill_shapes.geoms):
|
||||
if self.fill_method == 'contour_fill':
|
||||
stitch_groups.extend(self.do_contour_fill(fill_shape, previous_stitch_group, start))
|
||||
elif self.fill_method == 'guided_fill':
|
||||
stitch_groups.extend(self.do_guided_fill(fill_shape, previous_stitch_group, start, end))
|
||||
elif self.fill_method == 'meander_fill':
|
||||
stitch_groups.extend(self.do_meander_fill(fill_shape, shape, i, start, end))
|
||||
elif self.fill_method == 'circular_fill':
|
||||
stitch_groups.extend(self.do_circular_fill(fill_shape, previous_stitch_group, start, end))
|
||||
else:
|
||||
# auto_fill
|
||||
stitch_groups.extend(self.do_auto_fill(fill_shape, previous_stitch_group, start, end))
|
||||
previous_stitch_group = stitch_groups[-1]
|
||||
|
||||
return stitch_groups
|
||||
|
@ -885,28 +877,6 @@ class FillStitch(EmbroideryElement):
|
|||
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 it is a bug in 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 please\n"
|
||||
"- copy the entire error message below\n"
|
||||
"- save your SVG file and\n"
|
||||
"- create a new issue at")
|
||||
message += " https://github.com/inkstitch/inkstitch/issues/new\n\n"
|
||||
message += _("Include the error description and also (if possible) the svg file.")
|
||||
message += '\n\n\n'
|
||||
message += version.get_inkstitch_version() + '\n'
|
||||
message += traceback.format_exc()
|
||||
|
||||
self.fatal(message)
|
||||
|
||||
def do_circular_fill(self, shape, last_patch, starting_point, ending_point):
|
||||
# get target position
|
||||
command = self.get_command('ripple_target')
|
||||
|
|
|
@ -2,6 +2,36 @@
|
|||
#
|
||||
# Copyright (c) 2010 Authors
|
||||
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
|
||||
import traceback
|
||||
|
||||
|
||||
class InkstitchException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def format_uncaught_exception():
|
||||
"""Format the current exception as a request for a bug report.
|
||||
|
||||
Call this inside an except block so that there is an exception that we can
|
||||
call traceback.format_exc() on.
|
||||
"""
|
||||
|
||||
# importing locally to avoid any possibility of circular import
|
||||
from lib.utils import version
|
||||
from .i18n import _
|
||||
|
||||
message = ""
|
||||
message += _("Ink/Stitch experienced an unexpected error. This means it is a bug in 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 please\n"
|
||||
"- copy the entire error message below\n"
|
||||
"- save your SVG file and\n"
|
||||
"- create a new issue at")
|
||||
message += " https://github.com/inkstitch/inkstitch/issues/new\n\n"
|
||||
message += _("Include the error description and also (if possible) the svg file.")
|
||||
message += '\n\n\n'
|
||||
message += version.get_inkstitch_version() + '\n'
|
||||
message += traceback.format_exc()
|
||||
|
||||
return message
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from collections import defaultdict
|
||||
from copy import copy
|
||||
from itertools import groupby, zip_longest
|
||||
|
@ -20,6 +19,7 @@ from ..commands import is_command, is_command_symbol
|
|||
from ..elements import (Clone, EmbroideryElement, FillStitch, Polyline,
|
||||
SatinColumn, Stroke)
|
||||
from ..elements.clone import is_clone
|
||||
from ..exceptions import InkstitchException, format_uncaught_exception
|
||||
from ..gui import PresetsPanel, SimulatorPreview, WarningPanel
|
||||
from ..i18n import _
|
||||
from ..svg.tags import SVG_POLYLINE_TAG
|
||||
|
@ -544,24 +544,22 @@ class SettingsFrame(wx.Frame):
|
|||
patches.extend(copy(node).embroider(None))
|
||||
|
||||
check_stop_flag()
|
||||
except SystemExit:
|
||||
wx.CallAfter(self._show_warning)
|
||||
except (SystemExit, ExitThread):
|
||||
raise
|
||||
except ExitThread:
|
||||
raise
|
||||
except Exception as e:
|
||||
# Ignore errors. This can be things like incorrect paths for
|
||||
# satins or division by zero caused by incorrect param values.
|
||||
traceback.print_exception(e, file=sys.stderr)
|
||||
pass
|
||||
except InkstitchException as exc:
|
||||
wx.CallAfter(self._show_warning, str(exc))
|
||||
except Exception:
|
||||
wx.CallAfter(self._show_warning, format_uncaught_exception())
|
||||
|
||||
return patches
|
||||
|
||||
def _hide_warning(self):
|
||||
self.warning_panel.clear()
|
||||
self.warning_panel.Hide()
|
||||
self.Layout()
|
||||
|
||||
def _show_warning(self):
|
||||
def _show_warning(self, warning_text):
|
||||
self.warning_panel.set_warning_text(warning_text)
|
||||
self.warning_panel.Show()
|
||||
self.Layout()
|
||||
|
||||
|
|
|
@ -15,14 +15,25 @@ class WarningPanel(wx.Panel):
|
|||
def __init__(self, parent, *args, **kwargs):
|
||||
wx.Panel.__init__(self, parent, wx.ID_ANY, *args, **kwargs)
|
||||
|
||||
self.warning_box = wx.StaticBox(self, wx.ID_ANY)
|
||||
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.warning = wx.StaticText(self)
|
||||
self.warning.SetLabel(_("Cannot load simulator.\nClose Params to get full error message."))
|
||||
self.warning.SetLabel(_("An error occurred while rendering the stitch plan:"))
|
||||
self.warning.SetForegroundColour(wx.Colour(255, 25, 25))
|
||||
self.main_sizer.Add(self.warning, 1, wx.LEFT | wx.BOTTOM | wx.EXPAND, 10)
|
||||
|
||||
warning_sizer = wx.StaticBoxSizer(self.warning_box, wx.HORIZONTAL)
|
||||
warning_sizer.Add(self.warning, 1, wx.LEFT | wx.BOTTOM | wx.EXPAND, 10)
|
||||
tc_style = wx.TE_MULTILINE | wx.TE_READONLY | wx.VSCROLL | wx.TE_RICH2
|
||||
self.warning_text = wx.TextCtrl(self, size=(300, 100), style=tc_style)
|
||||
font = self.warning_text.GetFont()
|
||||
font.SetFamily(wx.FONTFAMILY_TELETYPE)
|
||||
self.warning_text.SetFont(font)
|
||||
self.main_sizer.Add(self.warning_text, 3, wx.LEFT | wx.BOTTOM | wx.EXPAND, 10)
|
||||
|
||||
self.SetSizerAndFit(warning_sizer)
|
||||
self.SetSizerAndFit(self.main_sizer)
|
||||
self.Layout()
|
||||
|
||||
def set_warning_text(self, text):
|
||||
self.warning_text.SetValue(text)
|
||||
|
||||
def clear(self):
|
||||
self.warning_text.SetValue("")
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from itertools import combinations
|
||||
|
||||
import networkx as nx
|
||||
from inkex import errormsg
|
||||
from shapely.geometry import LineString, MultiPoint, Point
|
||||
from shapely.ops import nearest_points
|
||||
|
||||
|
@ -30,10 +29,8 @@ def meander_fill(fill, shape, original_shape, shape_index, starting_point, endin
|
|||
graph = tile.to_graph(shape, fill.meander_scale, fill.meander_angle)
|
||||
|
||||
if not graph:
|
||||
label = fill.node.label or fill.node.get_id()
|
||||
errormsg(_('%s: Could not build graph for meander stitching. Try to enlarge your shape or '
|
||||
'scale your meander pattern down.') % label)
|
||||
return []
|
||||
fill.fatal(_('Could not build graph for meander stitching. Try to enlarge your shape or '
|
||||
'scale your meander pattern down.'))
|
||||
|
||||
debug.log_graph(graph, 'Meander graph')
|
||||
ensure_connected(graph)
|
||||
|
|
Ładowanie…
Reference in New Issue