meerk40t 0.9.7020__py2.py3-none-any.whl → 0.9.7040__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meerk40t/balormk/clone_loader.py +3 -2
- meerk40t/balormk/controller.py +28 -11
- meerk40t/balormk/cylindermod.py +1 -0
- meerk40t/balormk/device.py +13 -9
- meerk40t/balormk/driver.py +9 -2
- meerk40t/balormk/galvo_commands.py +3 -1
- meerk40t/balormk/gui/gui.py +6 -0
- meerk40t/balormk/livelightjob.py +338 -321
- meerk40t/balormk/mock_connection.py +4 -3
- meerk40t/balormk/usb_connection.py +11 -2
- meerk40t/camera/camera.py +19 -14
- meerk40t/camera/gui/camerapanel.py +6 -0
- meerk40t/core/cutcode/cutcode.py +1 -1
- meerk40t/core/cutplan.py +169 -43
- meerk40t/core/elements/element_treeops.py +444 -147
- meerk40t/core/elements/elements.py +100 -9
- meerk40t/core/elements/grid.py +8 -1
- meerk40t/core/elements/offset_mk.py +2 -1
- meerk40t/core/elements/shapes.py +618 -279
- meerk40t/core/elements/tree_commands.py +10 -5
- meerk40t/core/node/elem_ellipse.py +18 -8
- meerk40t/core/node/elem_image.py +51 -19
- meerk40t/core/node/elem_line.py +18 -8
- meerk40t/core/node/elem_path.py +18 -8
- meerk40t/core/node/elem_point.py +10 -4
- meerk40t/core/node/elem_polyline.py +19 -11
- meerk40t/core/node/elem_rect.py +18 -8
- meerk40t/core/node/elem_text.py +11 -5
- meerk40t/core/node/filenode.py +2 -8
- meerk40t/core/node/groupnode.py +11 -11
- meerk40t/core/node/image_processed.py +11 -5
- meerk40t/core/node/image_raster.py +11 -5
- meerk40t/core/node/node.py +70 -19
- meerk40t/core/node/refnode.py +2 -1
- meerk40t/core/planner.py +23 -0
- meerk40t/core/svg_io.py +91 -34
- meerk40t/core/undos.py +1 -1
- meerk40t/core/wordlist.py +1 -0
- meerk40t/device/dummydevice.py +7 -1
- meerk40t/dxf/dxf_io.py +6 -0
- meerk40t/extra/mk_potrace.py +1959 -0
- meerk40t/extra/param_functions.py +1 -1
- meerk40t/extra/potrace.py +14 -10
- meerk40t/extra/vtracer.py +222 -0
- meerk40t/grbl/device.py +81 -8
- meerk40t/grbl/interpreter.py +1 -1
- meerk40t/gui/about.py +21 -3
- meerk40t/gui/basicops.py +3 -3
- meerk40t/gui/choicepropertypanel.py +1 -4
- meerk40t/gui/devicepanel.py +20 -16
- meerk40t/gui/gui_mixins.py +8 -1
- meerk40t/gui/icons.py +330 -253
- meerk40t/gui/laserpanel.py +8 -3
- meerk40t/gui/laserrender.py +41 -21
- meerk40t/gui/magnetoptions.py +158 -65
- meerk40t/gui/materialtest.py +229 -39
- meerk40t/gui/navigationpanels.py +229 -24
- meerk40t/gui/propertypanels/hatchproperty.py +2 -0
- meerk40t/gui/propertypanels/imageproperty.py +160 -106
- meerk40t/gui/ribbon.py +6 -1
- meerk40t/gui/scenewidgets/gridwidget.py +29 -32
- meerk40t/gui/scenewidgets/rectselectwidget.py +190 -192
- meerk40t/gui/simulation.py +75 -77
- meerk40t/gui/spoolerpanel.py +6 -9
- meerk40t/gui/statusbarwidgets/defaultoperations.py +84 -48
- meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
- meerk40t/gui/themes.py +7 -1
- meerk40t/gui/tips.py +15 -1
- meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
- meerk40t/gui/wxmeerk40t.py +26 -0
- meerk40t/gui/wxmmain.py +242 -114
- meerk40t/gui/wxmscene.py +180 -4
- meerk40t/gui/wxmtree.py +4 -2
- meerk40t/gui/wxutils.py +60 -15
- meerk40t/image/imagetools.py +130 -66
- meerk40t/internal_plugins.py +4 -0
- meerk40t/kernel/kernel.py +49 -22
- meerk40t/kernel/settings.py +29 -8
- meerk40t/lihuiyu/device.py +30 -12
- meerk40t/main.py +22 -5
- meerk40t/moshi/device.py +20 -6
- meerk40t/network/console_server.py +22 -6
- meerk40t/newly/device.py +10 -3
- meerk40t/newly/gui/gui.py +10 -0
- meerk40t/ruida/device.py +22 -2
- meerk40t/ruida/gui/gui.py +6 -6
- meerk40t/ruida/gui/ruidaoperationproperties.py +1 -10
- meerk40t/ruida/loader.py +6 -3
- meerk40t/ruida/rdjob.py +3 -3
- meerk40t/tools/geomstr.py +195 -39
- meerk40t/tools/rasterplotter.py +179 -93
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/RECORD +98 -96
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/WHEEL +1 -1
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7020.dist-info → meerk40t-0.9.7040.dist-info}/zip-safe +0 -0
meerk40t/tools/geomstr.py
CHANGED
@@ -107,7 +107,15 @@ TYPE_CALL = 0xB0 | 0b1111 # The two higher level bytes are call label index.
|
|
107
107
|
|
108
108
|
# A summary of all points that have a special meaning, ie intended for other uses than pure geometry
|
109
109
|
META_TYPES = (TYPE_NOP, TYPE_FUNCTION, TYPE_VERTEX, TYPE_UNTIL, TYPE_CALL)
|
110
|
-
NON_GEOMETRY_TYPES = (
|
110
|
+
NON_GEOMETRY_TYPES = (
|
111
|
+
TYPE_NOP,
|
112
|
+
TYPE_FUNCTION,
|
113
|
+
TYPE_VERTEX,
|
114
|
+
TYPE_UNTIL,
|
115
|
+
TYPE_CALL,
|
116
|
+
TYPE_END,
|
117
|
+
)
|
118
|
+
|
111
119
|
|
112
120
|
class Polygon:
|
113
121
|
def __init__(self, *args):
|
@@ -118,7 +126,6 @@ class Polygon:
|
|
118
126
|
return self.geomstr.bbox(mx)
|
119
127
|
|
120
128
|
|
121
|
-
|
122
129
|
def triangle_area(p1, p2, p3):
|
123
130
|
"""
|
124
131
|
calculates the area of a triangle given its vertices
|
@@ -180,6 +187,78 @@ def remove(s, i):
|
|
180
187
|
s[i:-1] = s[i + 1 :]
|
181
188
|
|
182
189
|
|
190
|
+
def stitch_geometries(geometry_list: list, tolerance: float = 0.0) -> list:
|
191
|
+
"""
|
192
|
+
Stitches geometries within the given tolerance.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
geometry_list: List of Geomstr objects to stitch.
|
196
|
+
tolerance: Maximum distance between endpoints to consider a stitch.
|
197
|
+
|
198
|
+
Returns:
|
199
|
+
List of stitched Geomstr objects, or None if no stitches were made.
|
200
|
+
"""
|
201
|
+
|
202
|
+
geometries = [g for g in geometry_list if g is not None]
|
203
|
+
if not geometries:
|
204
|
+
return None
|
205
|
+
if tolerance == 0:
|
206
|
+
tolerance = 1e-6
|
207
|
+
|
208
|
+
stitched_geometries = []
|
209
|
+
while geometries:
|
210
|
+
g1 = geometries.pop(0)
|
211
|
+
stitched = False
|
212
|
+
for i, g2 in enumerate(stitched_geometries):
|
213
|
+
for reverse1 in (False, True):
|
214
|
+
for reverse2 in (False, True):
|
215
|
+
g1_start = g1.last_point if reverse1 else g1.first_point
|
216
|
+
g1_end = g1.first_point if reverse1 else g1.last_point
|
217
|
+
g2_start = g2.last_point if reverse2 else g2.first_point
|
218
|
+
g2_end = g2.first_point if reverse2 else g2.last_point
|
219
|
+
|
220
|
+
if (
|
221
|
+
g1_start is None
|
222
|
+
or g1_end is None
|
223
|
+
or g2_start is None
|
224
|
+
or g2_end is None
|
225
|
+
):
|
226
|
+
continue
|
227
|
+
if abs(g2_end - g1_start) <= tolerance:
|
228
|
+
if abs(g2_end - g1_start) > 0:
|
229
|
+
g2.line(g2_end, g1_start)
|
230
|
+
if reverse1:
|
231
|
+
g1.reverse()
|
232
|
+
g2.append(g1, end=False)
|
233
|
+
stitched_geometries[i] = g2
|
234
|
+
stitched = True
|
235
|
+
break
|
236
|
+
elif abs(g2_start - g1_end) <= tolerance:
|
237
|
+
if abs(g2_start - g1_end) > 0:
|
238
|
+
g1.line(g1_end, g2_start)
|
239
|
+
if reverse1:
|
240
|
+
g1.reverse()
|
241
|
+
g2.insert(0, g1.segments[: g1.index])
|
242
|
+
stitched_geometries[i] = g2
|
243
|
+
stitched = True
|
244
|
+
break
|
245
|
+
if stitched:
|
246
|
+
break
|
247
|
+
if stitched:
|
248
|
+
break
|
249
|
+
|
250
|
+
if not stitched:
|
251
|
+
stitched_geometries.append(g1)
|
252
|
+
|
253
|
+
# Close any remaining small gaps between start and end points.
|
254
|
+
for g in stitched_geometries:
|
255
|
+
if 0 < abs(g.last_point - g.first_point) <= tolerance:
|
256
|
+
g.line(g.last_point, g.first_point)
|
257
|
+
|
258
|
+
return stitched_geometries
|
259
|
+
|
260
|
+
|
261
|
+
|
183
262
|
class Simplifier:
|
184
263
|
# Copyright (c) 2014 Elliot Hallmark
|
185
264
|
# The MIT License (MIT)
|
@@ -305,7 +384,7 @@ class Simplifier:
|
|
305
384
|
areas[min_vert] = right_area
|
306
385
|
|
307
386
|
if min_vert > 1:
|
308
|
-
#
|
387
|
+
# can't try/except because 0-1=-1 is a valid index
|
309
388
|
left_area = triangle_area(
|
310
389
|
self.pts[i[min_vert - 2]],
|
311
390
|
self.pts[i[min_vert - 1]],
|
@@ -354,13 +433,15 @@ class Simplifier:
|
|
354
433
|
# for some points
|
355
434
|
# sort point indices by threshold
|
356
435
|
idx = list(range(len(self.pts)))
|
357
|
-
sorted_indices = sorted(
|
436
|
+
sorted_indices = sorted(
|
437
|
+
zip(idx, self.thresholds), reverse=True, key=lambda x: x[1]
|
438
|
+
)
|
358
439
|
|
359
440
|
# grab first n indices
|
360
441
|
sorted_indices = sorted_indices[:n]
|
361
442
|
|
362
443
|
# re-sort by index
|
363
|
-
final_indices = sorted(
|
444
|
+
final_indices = sorted([x[0] for x in sorted_indices])
|
364
445
|
|
365
446
|
return self.pts[final_indices]
|
366
447
|
|
@@ -1191,6 +1272,8 @@ class Scanbeam:
|
|
1191
1272
|
@param tolerance: wiggle room, in favor of inside
|
1192
1273
|
@return:
|
1193
1274
|
"""
|
1275
|
+
if tolerance == 0:
|
1276
|
+
tolerance == 1e-6
|
1194
1277
|
self.scanline_to(y)
|
1195
1278
|
for i in range(1, len(self._active_edge_list), 2):
|
1196
1279
|
prior = self._active_edge_list[i - 1]
|
@@ -1624,11 +1707,26 @@ class Geomstr:
|
|
1624
1707
|
):
|
1625
1708
|
# This is a deliberate subpath break
|
1626
1709
|
obj.end()
|
1627
|
-
elif
|
1710
|
+
elif (
|
1711
|
+
isinstance(seg, (Line, Close))
|
1712
|
+
and seg.start is not None
|
1713
|
+
and seg.end is not None
|
1714
|
+
):
|
1628
1715
|
obj.line(complex(seg.start), complex(seg.end))
|
1629
|
-
elif
|
1716
|
+
elif (
|
1717
|
+
isinstance(seg, QuadraticBezier)
|
1718
|
+
and seg.start is not None
|
1719
|
+
and seg.end is not None
|
1720
|
+
and seg.control is not None
|
1721
|
+
):
|
1630
1722
|
obj.quad(complex(seg.start), complex(seg.control), complex(seg.end))
|
1631
|
-
elif
|
1723
|
+
elif (
|
1724
|
+
isinstance(seg, CubicBezier)
|
1725
|
+
and seg.start is not None
|
1726
|
+
and seg.end is not None
|
1727
|
+
and seg.control1 is not None
|
1728
|
+
and seg.control2 is not None
|
1729
|
+
):
|
1632
1730
|
obj.cubic(
|
1633
1731
|
complex(seg.start),
|
1634
1732
|
complex(seg.control1),
|
@@ -1779,16 +1877,22 @@ class Geomstr:
|
|
1779
1877
|
rx = abs(rx)
|
1780
1878
|
ry = abs(ry)
|
1781
1879
|
if rx == ry == 0:
|
1782
|
-
path.line(complex(x, y), complex(x + width, y), settings=settings),
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1880
|
+
(path.line(complex(x, y), complex(x + width, y), settings=settings),)
|
1881
|
+
(
|
1882
|
+
path.line(
|
1883
|
+
complex(x + width, y),
|
1884
|
+
complex(x + width, y + height),
|
1885
|
+
settings=settings,
|
1886
|
+
),
|
1887
|
+
)
|
1888
|
+
(
|
1889
|
+
path.line(
|
1890
|
+
complex(x + width, y + height),
|
1891
|
+
complex(x, y + height),
|
1892
|
+
settings=settings,
|
1893
|
+
),
|
1894
|
+
)
|
1895
|
+
(path.line(complex(x, y + height), complex(x, y), settings=settings),)
|
1792
1896
|
else:
|
1793
1897
|
offset = 1 - (1.0 / math.sqrt(2))
|
1794
1898
|
path.line(complex(x + rx, y), complex(x + width - rx, y), settings=settings)
|
@@ -1940,7 +2044,7 @@ class Geomstr:
|
|
1940
2044
|
return geometry
|
1941
2045
|
|
1942
2046
|
@classmethod
|
1943
|
-
def wobble(cls, algorithm, outer, radius, interval, speed, unit_factor
|
2047
|
+
def wobble(cls, algorithm, outer, radius, interval, speed, unit_factor=1):
|
1944
2048
|
from meerk40t.fill.fills import Wobble
|
1945
2049
|
|
1946
2050
|
w = Wobble(algorithm, radius=radius, speed=speed, interval=interval)
|
@@ -2042,12 +2146,28 @@ class Geomstr:
|
|
2042
2146
|
@classmethod
|
2043
2147
|
def wobble_dash(cls, outer, dashlength, interval, irrelevant, unit_factor=1):
|
2044
2148
|
from meerk40t.fill.fills import dashed_line as algorithm
|
2045
|
-
|
2149
|
+
|
2150
|
+
return cls.wobble(
|
2151
|
+
algorithm,
|
2152
|
+
outer,
|
2153
|
+
dashlength,
|
2154
|
+
interval * unit_factor,
|
2155
|
+
irrelevant,
|
2156
|
+
unit_factor=unit_factor,
|
2157
|
+
)
|
2046
2158
|
|
2047
2159
|
@classmethod
|
2048
2160
|
def wobble_tab(cls, outer, tablength, interval, tabpositions, unit_factor=1):
|
2049
2161
|
from meerk40t.fill.fills import tabbed_path as algorithm
|
2050
|
-
|
2162
|
+
|
2163
|
+
return cls.wobble(
|
2164
|
+
algorithm,
|
2165
|
+
outer,
|
2166
|
+
tablength,
|
2167
|
+
interval * unit_factor,
|
2168
|
+
tabpositions,
|
2169
|
+
unit_factor=unit_factor,
|
2170
|
+
)
|
2051
2171
|
|
2052
2172
|
@classmethod
|
2053
2173
|
def from_float_segments(cls, float_segments):
|
@@ -2173,7 +2293,7 @@ class Geomstr:
|
|
2173
2293
|
if segments:
|
2174
2294
|
yield segments
|
2175
2295
|
|
2176
|
-
def as_equal_interpolated_points(self, distance=100):
|
2296
|
+
def as_equal_interpolated_points(self, distance=100, expand_lines=False):
|
2177
2297
|
"""
|
2178
2298
|
Regardless of specified distance this will always give the start and end points of each node within the
|
2179
2299
|
geometry. It will not duplicate the nodes if the start of one is the end of another. If the start and end
|
@@ -2206,7 +2326,21 @@ class Geomstr:
|
|
2206
2326
|
at_start = True
|
2207
2327
|
continue
|
2208
2328
|
elif seg_type == TYPE_LINE:
|
2209
|
-
|
2329
|
+
if expand_lines:
|
2330
|
+
ts = np.linspace(0, 1, 1000)
|
2331
|
+
pts = self._line_position(e, ts)
|
2332
|
+
distances = np.abs(pts[:-1] - pts[1:])
|
2333
|
+
distances = np.cumsum(distances)
|
2334
|
+
max_distance = distances[-1]
|
2335
|
+
dist_values = np.linspace(
|
2336
|
+
0,
|
2337
|
+
max_distance,
|
2338
|
+
int(np.ceil(max_distance / distance)),
|
2339
|
+
endpoint=False,
|
2340
|
+
)[1:]
|
2341
|
+
near_t = np.searchsorted(distances, dist_values, side="right")
|
2342
|
+
pts = pts[near_t]
|
2343
|
+
yield from pts
|
2210
2344
|
elif seg_type == TYPE_QUAD:
|
2211
2345
|
ts = np.linspace(0, 1, 1000)
|
2212
2346
|
pts = self._quad_position(e, ts)
|
@@ -2723,7 +2857,7 @@ class Geomstr:
|
|
2723
2857
|
|
2724
2858
|
@return:
|
2725
2859
|
"""
|
2726
|
-
sweep = end_t - start_t
|
2860
|
+
sweep = end_t - start_t
|
2727
2861
|
if slices is None:
|
2728
2862
|
# A full ellipse can be properly represented with 12 slices - we err on the side of caution here...
|
2729
2863
|
slices = int(1.5 * 12 * sweep / math.tau)
|
@@ -2879,7 +3013,10 @@ class Geomstr:
|
|
2879
3013
|
current = self.segments[i]
|
2880
3014
|
start0, control0, info0, control20, end0 = previous
|
2881
3015
|
start1, control1, info1, control21, end1 = current
|
2882
|
-
if
|
3016
|
+
if (
|
3017
|
+
self._segtype(previous) != TYPE_LINE
|
3018
|
+
or self._segtype(current) != TYPE_LINE
|
3019
|
+
):
|
2883
3020
|
continue
|
2884
3021
|
towards0 = Geomstr.towards(None, start0, end0, 1 - amount)
|
2885
3022
|
towards1 = Geomstr.towards(None, start1, end1, amount)
|
@@ -2898,7 +3035,10 @@ class Geomstr:
|
|
2898
3035
|
current = self.segments[i]
|
2899
3036
|
start0, control0, info0, control20, end0 = previous
|
2900
3037
|
start1, control1, info1, control21, end1 = current
|
2901
|
-
if
|
3038
|
+
if (
|
3039
|
+
self._segtype(previous) != TYPE_LINE
|
3040
|
+
or self._segtype(current) != TYPE_LINE
|
3041
|
+
):
|
2902
3042
|
continue
|
2903
3043
|
towards0 = Geomstr.towards(None, start0, end0, 1 - amount)
|
2904
3044
|
towards1 = Geomstr.towards(None, start1, end1, amount)
|
@@ -3439,7 +3579,7 @@ class Geomstr:
|
|
3439
3579
|
|
3440
3580
|
def _cubic_length_via_quad(self, line):
|
3441
3581
|
"""
|
3442
|
-
If we have scipy.integrate
|
3582
|
+
If we have scipy.integrate available, use quad from that to solve this.
|
3443
3583
|
|
3444
3584
|
@param line:
|
3445
3585
|
@return:
|
@@ -3492,9 +3632,13 @@ class Geomstr:
|
|
3492
3632
|
yield start, control, info, control2, mid[0]
|
3493
3633
|
for i in range(1, len(mid)):
|
3494
3634
|
if breaks:
|
3495
|
-
yield
|
3496
|
-
i - 1
|
3497
|
-
|
3635
|
+
yield (
|
3636
|
+
mid[i - 1],
|
3637
|
+
mid[i - 1],
|
3638
|
+
complex(TYPE_END, info.imag),
|
3639
|
+
mid[i - 1],
|
3640
|
+
mid[i - 1],
|
3641
|
+
)
|
3498
3642
|
yield mid[i - 1], control, info, control2, mid[i]
|
3499
3643
|
if breaks:
|
3500
3644
|
yield mid[-1], 0, complex(TYPE_END, info.imag), 0, mid[-1]
|
@@ -4278,7 +4422,7 @@ class Geomstr:
|
|
4278
4422
|
return wh, x_vals + y_vals * 1j, ta_hit, tb_hit
|
4279
4423
|
|
4280
4424
|
#######################
|
4281
|
-
# Geom
|
4425
|
+
# Geom Transformations
|
4282
4426
|
#######################
|
4283
4427
|
|
4284
4428
|
def transform(self, mx, e=None):
|
@@ -4568,10 +4712,13 @@ class Geomstr:
|
|
4568
4712
|
return process(S, K, a, c)[:-1] + process(S, K, c, b)
|
4569
4713
|
|
4570
4714
|
def quickhull_2d(S: np.ndarray) -> np.ndarray:
|
4571
|
-
a, b = np.argmin(S[:,0]), np.argmax(S[:,0])
|
4572
|
-
max_index = np.argmax(S[:,0])
|
4715
|
+
a, b = np.argmin(S[:, 0]), np.argmax(S[:, 0])
|
4716
|
+
max_index = np.argmax(S[:, 0])
|
4573
4717
|
# max_element = S[max_index]
|
4574
|
-
return
|
4718
|
+
return (
|
4719
|
+
process(S, np.arange(S.shape[0]), a, max_index)[:-1]
|
4720
|
+
+ process(S, np.arange(S.shape[0]), max_index, a)[:-1]
|
4721
|
+
)
|
4575
4722
|
|
4576
4723
|
if len(pts) == 0:
|
4577
4724
|
return
|
@@ -4597,7 +4744,6 @@ class Geomstr:
|
|
4597
4744
|
for p in res_pts:
|
4598
4745
|
yield complex(p[0], p[1])
|
4599
4746
|
|
4600
|
-
|
4601
4747
|
def _convex_hull_original(self, pts):
|
4602
4748
|
"""
|
4603
4749
|
Generate points of the convex hull around the given points.
|
@@ -4668,7 +4814,9 @@ class Geomstr:
|
|
4668
4814
|
# but that will let multiple unit tests fail
|
4669
4815
|
# val = (q.real - p.real) * (r.imag - p.imag) - (q.imag - p.imag) * (r.real - p.real)
|
4670
4816
|
|
4671
|
-
val = (q.imag - p.imag) * (r.real - q.real) - (q.real - p.real) * (
|
4817
|
+
val = (q.imag - p.imag) * (r.real - q.real) - (q.real - p.real) * (
|
4818
|
+
r.imag - q.imag
|
4819
|
+
)
|
4672
4820
|
if val == 0:
|
4673
4821
|
return "linear"
|
4674
4822
|
elif val > 0:
|
@@ -5326,7 +5474,9 @@ class Geomstr:
|
|
5326
5474
|
self.segments[p1] = c
|
5327
5475
|
pt = c[-1]
|
5328
5476
|
|
5329
|
-
def two_opt_distance(
|
5477
|
+
def two_opt_distance(
|
5478
|
+
self, max_passes=None, chunk=0, auto_stop_threshold=None, feedback=None
|
5479
|
+
):
|
5330
5480
|
"""
|
5331
5481
|
Perform two-opt optimization to minimize travel distances.
|
5332
5482
|
@param max_passes: Max number of passes to attempt
|
@@ -5347,7 +5497,11 @@ class Geomstr:
|
|
5347
5497
|
improved = True
|
5348
5498
|
first_travel = self.travel_distance()
|
5349
5499
|
last_travel = first_travel
|
5350
|
-
threshold_value =
|
5500
|
+
threshold_value = (
|
5501
|
+
None
|
5502
|
+
if auto_stop_threshold is None
|
5503
|
+
else auto_stop_threshold / 100.0 * last_travel
|
5504
|
+
)
|
5351
5505
|
while improved:
|
5352
5506
|
improved = False
|
5353
5507
|
|
@@ -5556,7 +5710,9 @@ class Geomstr:
|
|
5556
5710
|
elif threshold is not None:
|
5557
5711
|
newpoints = simplifier.simplify(threshold=threshold)
|
5558
5712
|
else:
|
5559
|
-
raise ValueError(
|
5713
|
+
raise ValueError(
|
5714
|
+
"You need to provide at least one parameter for simplify_geomstr"
|
5715
|
+
)
|
5560
5716
|
newgeom.append(Geomstr.lines(newpoints))
|
5561
5717
|
points.clear()
|
5562
5718
|
|