meerk40t 0.9.7030__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/cutplan.py +109 -51
- meerk40t/core/elements/element_treeops.py +435 -140
- meerk40t/core/elements/elements.py +100 -9
- meerk40t/core/elements/shapes.py +259 -39
- 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 +64 -16
- meerk40t/core/node/refnode.py +2 -1
- meerk40t/core/svg_io.py +91 -34
- meerk40t/device/dummydevice.py +7 -1
- meerk40t/extra/vtracer.py +222 -0
- meerk40t/grbl/device.py +81 -8
- meerk40t/gui/about.py +20 -0
- meerk40t/gui/devicepanel.py +20 -16
- meerk40t/gui/gui_mixins.py +4 -0
- 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/statusbarwidgets/defaultoperations.py +84 -48
- meerk40t/gui/statusbarwidgets/infowidget.py +2 -2
- meerk40t/gui/tips.py +15 -1
- meerk40t/gui/toolwidgets/toolpointmove.py +3 -1
- meerk40t/gui/wxmmain.py +242 -114
- meerk40t/gui/wxmscene.py +107 -24
- meerk40t/gui/wxmtree.py +4 -2
- meerk40t/gui/wxutils.py +60 -15
- meerk40t/image/imagetools.py +129 -65
- meerk40t/internal_plugins.py +4 -0
- meerk40t/kernel/kernel.py +39 -18
- meerk40t/kernel/settings.py +28 -9
- meerk40t/lihuiyu/device.py +24 -12
- meerk40t/main.py +1 -1
- 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/loader.py +6 -3
- meerk40t/tools/geomstr.py +193 -125
- meerk40t/tools/rasterplotter.py +179 -93
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/METADATA +1 -1
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/RECORD +79 -78
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/LICENSE +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/WHEEL +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/entry_points.txt +0 -0
- {meerk40t-0.9.7030.dist-info → meerk40t-0.9.7040.dist-info}/top_level.txt +0 -0
- {meerk40t-0.9.7030.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
|
@@ -179,94 +186,78 @@ def remove(s, i):
|
|
179
186
|
"""
|
180
187
|
s[i:-1] = s[i + 1 :]
|
181
188
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
g2.
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
g2.insert(0, g1.segments[:g1.index])
|
240
|
-
was_stitched = True
|
241
|
-
if was_stitched:
|
242
|
-
# print ("stitched")
|
243
|
-
# g2.debug_me()
|
244
|
-
anychanges = True
|
245
|
-
start_points[idx] = g2.first_point
|
246
|
-
end_points[idx] = g2.last_point
|
247
|
-
result_list[idx] = g2
|
248
|
-
were_stitches = True
|
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:
|
249
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
|
+
|
250
260
|
|
251
|
-
if not was_stitched:
|
252
|
-
# print ("Unchanged")
|
253
|
-
result_list.append(g1)
|
254
|
-
start_points.append(fp1)
|
255
|
-
end_points.append(lp1)
|
256
|
-
if anychanges:
|
257
|
-
action_list = list(result_list)
|
258
|
-
result_list.clear()
|
259
|
-
start_points.clear()
|
260
|
-
end_points.clear()
|
261
|
-
if were_stitches:
|
262
|
-
for g1 in result_list:
|
263
|
-
fp1 = g1.first_point
|
264
|
-
lp1 = g1.last_point
|
265
|
-
dist_e_s = abs(lp1 - fp1)
|
266
|
-
if 0 < dist_e_s <= tolerance:
|
267
|
-
g1.line(lp1, fp1)
|
268
|
-
return result_list
|
269
|
-
return None
|
270
261
|
|
271
262
|
class Simplifier:
|
272
263
|
# Copyright (c) 2014 Elliot Hallmark
|
@@ -393,7 +384,7 @@ class Simplifier:
|
|
393
384
|
areas[min_vert] = right_area
|
394
385
|
|
395
386
|
if min_vert > 1:
|
396
|
-
#
|
387
|
+
# can't try/except because 0-1=-1 is a valid index
|
397
388
|
left_area = triangle_area(
|
398
389
|
self.pts[i[min_vert - 2]],
|
399
390
|
self.pts[i[min_vert - 1]],
|
@@ -442,13 +433,15 @@ class Simplifier:
|
|
442
433
|
# for some points
|
443
434
|
# sort point indices by threshold
|
444
435
|
idx = list(range(len(self.pts)))
|
445
|
-
sorted_indices = sorted(
|
436
|
+
sorted_indices = sorted(
|
437
|
+
zip(idx, self.thresholds), reverse=True, key=lambda x: x[1]
|
438
|
+
)
|
446
439
|
|
447
440
|
# grab first n indices
|
448
441
|
sorted_indices = sorted_indices[:n]
|
449
442
|
|
450
443
|
# re-sort by index
|
451
|
-
final_indices = sorted(
|
444
|
+
final_indices = sorted([x[0] for x in sorted_indices])
|
452
445
|
|
453
446
|
return self.pts[final_indices]
|
454
447
|
|
@@ -1279,6 +1272,8 @@ class Scanbeam:
|
|
1279
1272
|
@param tolerance: wiggle room, in favor of inside
|
1280
1273
|
@return:
|
1281
1274
|
"""
|
1275
|
+
if tolerance == 0:
|
1276
|
+
tolerance == 1e-6
|
1282
1277
|
self.scanline_to(y)
|
1283
1278
|
for i in range(1, len(self._active_edge_list), 2):
|
1284
1279
|
prior = self._active_edge_list[i - 1]
|
@@ -1712,11 +1707,26 @@ class Geomstr:
|
|
1712
1707
|
):
|
1713
1708
|
# This is a deliberate subpath break
|
1714
1709
|
obj.end()
|
1715
|
-
elif
|
1710
|
+
elif (
|
1711
|
+
isinstance(seg, (Line, Close))
|
1712
|
+
and seg.start is not None
|
1713
|
+
and seg.end is not None
|
1714
|
+
):
|
1716
1715
|
obj.line(complex(seg.start), complex(seg.end))
|
1717
|
-
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
|
+
):
|
1718
1722
|
obj.quad(complex(seg.start), complex(seg.control), complex(seg.end))
|
1719
|
-
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
|
+
):
|
1720
1730
|
obj.cubic(
|
1721
1731
|
complex(seg.start),
|
1722
1732
|
complex(seg.control1),
|
@@ -1867,16 +1877,22 @@ class Geomstr:
|
|
1867
1877
|
rx = abs(rx)
|
1868
1878
|
ry = abs(ry)
|
1869
1879
|
if rx == ry == 0:
|
1870
|
-
path.line(complex(x, y), complex(x + width, y), settings=settings),
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
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),)
|
1880
1896
|
else:
|
1881
1897
|
offset = 1 - (1.0 / math.sqrt(2))
|
1882
1898
|
path.line(complex(x + rx, y), complex(x + width - rx, y), settings=settings)
|
@@ -2028,7 +2044,7 @@ class Geomstr:
|
|
2028
2044
|
return geometry
|
2029
2045
|
|
2030
2046
|
@classmethod
|
2031
|
-
def wobble(cls, algorithm, outer, radius, interval, speed, unit_factor
|
2047
|
+
def wobble(cls, algorithm, outer, radius, interval, speed, unit_factor=1):
|
2032
2048
|
from meerk40t.fill.fills import Wobble
|
2033
2049
|
|
2034
2050
|
w = Wobble(algorithm, radius=radius, speed=speed, interval=interval)
|
@@ -2130,12 +2146,28 @@ class Geomstr:
|
|
2130
2146
|
@classmethod
|
2131
2147
|
def wobble_dash(cls, outer, dashlength, interval, irrelevant, unit_factor=1):
|
2132
2148
|
from meerk40t.fill.fills import dashed_line as algorithm
|
2133
|
-
|
2149
|
+
|
2150
|
+
return cls.wobble(
|
2151
|
+
algorithm,
|
2152
|
+
outer,
|
2153
|
+
dashlength,
|
2154
|
+
interval * unit_factor,
|
2155
|
+
irrelevant,
|
2156
|
+
unit_factor=unit_factor,
|
2157
|
+
)
|
2134
2158
|
|
2135
2159
|
@classmethod
|
2136
2160
|
def wobble_tab(cls, outer, tablength, interval, tabpositions, unit_factor=1):
|
2137
2161
|
from meerk40t.fill.fills import tabbed_path as algorithm
|
2138
|
-
|
2162
|
+
|
2163
|
+
return cls.wobble(
|
2164
|
+
algorithm,
|
2165
|
+
outer,
|
2166
|
+
tablength,
|
2167
|
+
interval * unit_factor,
|
2168
|
+
tabpositions,
|
2169
|
+
unit_factor=unit_factor,
|
2170
|
+
)
|
2139
2171
|
|
2140
2172
|
@classmethod
|
2141
2173
|
def from_float_segments(cls, float_segments):
|
@@ -2261,7 +2293,7 @@ class Geomstr:
|
|
2261
2293
|
if segments:
|
2262
2294
|
yield segments
|
2263
2295
|
|
2264
|
-
def as_equal_interpolated_points(self, distance=100):
|
2296
|
+
def as_equal_interpolated_points(self, distance=100, expand_lines=False):
|
2265
2297
|
"""
|
2266
2298
|
Regardless of specified distance this will always give the start and end points of each node within the
|
2267
2299
|
geometry. It will not duplicate the nodes if the start of one is the end of another. If the start and end
|
@@ -2294,7 +2326,21 @@ class Geomstr:
|
|
2294
2326
|
at_start = True
|
2295
2327
|
continue
|
2296
2328
|
elif seg_type == TYPE_LINE:
|
2297
|
-
|
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
|
2298
2344
|
elif seg_type == TYPE_QUAD:
|
2299
2345
|
ts = np.linspace(0, 1, 1000)
|
2300
2346
|
pts = self._quad_position(e, ts)
|
@@ -2811,7 +2857,7 @@ class Geomstr:
|
|
2811
2857
|
|
2812
2858
|
@return:
|
2813
2859
|
"""
|
2814
|
-
sweep = end_t - start_t
|
2860
|
+
sweep = end_t - start_t
|
2815
2861
|
if slices is None:
|
2816
2862
|
# A full ellipse can be properly represented with 12 slices - we err on the side of caution here...
|
2817
2863
|
slices = int(1.5 * 12 * sweep / math.tau)
|
@@ -2967,7 +3013,10 @@ class Geomstr:
|
|
2967
3013
|
current = self.segments[i]
|
2968
3014
|
start0, control0, info0, control20, end0 = previous
|
2969
3015
|
start1, control1, info1, control21, end1 = current
|
2970
|
-
if
|
3016
|
+
if (
|
3017
|
+
self._segtype(previous) != TYPE_LINE
|
3018
|
+
or self._segtype(current) != TYPE_LINE
|
3019
|
+
):
|
2971
3020
|
continue
|
2972
3021
|
towards0 = Geomstr.towards(None, start0, end0, 1 - amount)
|
2973
3022
|
towards1 = Geomstr.towards(None, start1, end1, amount)
|
@@ -2986,7 +3035,10 @@ class Geomstr:
|
|
2986
3035
|
current = self.segments[i]
|
2987
3036
|
start0, control0, info0, control20, end0 = previous
|
2988
3037
|
start1, control1, info1, control21, end1 = current
|
2989
|
-
if
|
3038
|
+
if (
|
3039
|
+
self._segtype(previous) != TYPE_LINE
|
3040
|
+
or self._segtype(current) != TYPE_LINE
|
3041
|
+
):
|
2990
3042
|
continue
|
2991
3043
|
towards0 = Geomstr.towards(None, start0, end0, 1 - amount)
|
2992
3044
|
towards1 = Geomstr.towards(None, start1, end1, amount)
|
@@ -3527,7 +3579,7 @@ class Geomstr:
|
|
3527
3579
|
|
3528
3580
|
def _cubic_length_via_quad(self, line):
|
3529
3581
|
"""
|
3530
|
-
If we have scipy.integrate
|
3582
|
+
If we have scipy.integrate available, use quad from that to solve this.
|
3531
3583
|
|
3532
3584
|
@param line:
|
3533
3585
|
@return:
|
@@ -3580,9 +3632,13 @@ class Geomstr:
|
|
3580
3632
|
yield start, control, info, control2, mid[0]
|
3581
3633
|
for i in range(1, len(mid)):
|
3582
3634
|
if breaks:
|
3583
|
-
yield
|
3584
|
-
i - 1
|
3585
|
-
|
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
|
+
)
|
3586
3642
|
yield mid[i - 1], control, info, control2, mid[i]
|
3587
3643
|
if breaks:
|
3588
3644
|
yield mid[-1], 0, complex(TYPE_END, info.imag), 0, mid[-1]
|
@@ -4366,7 +4422,7 @@ class Geomstr:
|
|
4366
4422
|
return wh, x_vals + y_vals * 1j, ta_hit, tb_hit
|
4367
4423
|
|
4368
4424
|
#######################
|
4369
|
-
# Geom
|
4425
|
+
# Geom Transformations
|
4370
4426
|
#######################
|
4371
4427
|
|
4372
4428
|
def transform(self, mx, e=None):
|
@@ -4656,10 +4712,13 @@ class Geomstr:
|
|
4656
4712
|
return process(S, K, a, c)[:-1] + process(S, K, c, b)
|
4657
4713
|
|
4658
4714
|
def quickhull_2d(S: np.ndarray) -> np.ndarray:
|
4659
|
-
a, b = np.argmin(S[:,0]), np.argmax(S[:,0])
|
4660
|
-
max_index = np.argmax(S[:,0])
|
4715
|
+
a, b = np.argmin(S[:, 0]), np.argmax(S[:, 0])
|
4716
|
+
max_index = np.argmax(S[:, 0])
|
4661
4717
|
# max_element = S[max_index]
|
4662
|
-
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
|
+
)
|
4663
4722
|
|
4664
4723
|
if len(pts) == 0:
|
4665
4724
|
return
|
@@ -4685,7 +4744,6 @@ class Geomstr:
|
|
4685
4744
|
for p in res_pts:
|
4686
4745
|
yield complex(p[0], p[1])
|
4687
4746
|
|
4688
|
-
|
4689
4747
|
def _convex_hull_original(self, pts):
|
4690
4748
|
"""
|
4691
4749
|
Generate points of the convex hull around the given points.
|
@@ -4756,7 +4814,9 @@ class Geomstr:
|
|
4756
4814
|
# but that will let multiple unit tests fail
|
4757
4815
|
# val = (q.real - p.real) * (r.imag - p.imag) - (q.imag - p.imag) * (r.real - p.real)
|
4758
4816
|
|
4759
|
-
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
|
+
)
|
4760
4820
|
if val == 0:
|
4761
4821
|
return "linear"
|
4762
4822
|
elif val > 0:
|
@@ -5414,7 +5474,9 @@ class Geomstr:
|
|
5414
5474
|
self.segments[p1] = c
|
5415
5475
|
pt = c[-1]
|
5416
5476
|
|
5417
|
-
def two_opt_distance(
|
5477
|
+
def two_opt_distance(
|
5478
|
+
self, max_passes=None, chunk=0, auto_stop_threshold=None, feedback=None
|
5479
|
+
):
|
5418
5480
|
"""
|
5419
5481
|
Perform two-opt optimization to minimize travel distances.
|
5420
5482
|
@param max_passes: Max number of passes to attempt
|
@@ -5435,7 +5497,11 @@ class Geomstr:
|
|
5435
5497
|
improved = True
|
5436
5498
|
first_travel = self.travel_distance()
|
5437
5499
|
last_travel = first_travel
|
5438
|
-
threshold_value =
|
5500
|
+
threshold_value = (
|
5501
|
+
None
|
5502
|
+
if auto_stop_threshold is None
|
5503
|
+
else auto_stop_threshold / 100.0 * last_travel
|
5504
|
+
)
|
5439
5505
|
while improved:
|
5440
5506
|
improved = False
|
5441
5507
|
|
@@ -5644,7 +5710,9 @@ class Geomstr:
|
|
5644
5710
|
elif threshold is not None:
|
5645
5711
|
newpoints = simplifier.simplify(threshold=threshold)
|
5646
5712
|
else:
|
5647
|
-
raise ValueError(
|
5713
|
+
raise ValueError(
|
5714
|
+
"You need to provide at least one parameter for simplify_geomstr"
|
5715
|
+
)
|
5648
5716
|
newgeom.append(Geomstr.lines(newpoints))
|
5649
5717
|
points.clear()
|
5650
5718
|
|