toolwake 0.2.1__tar.gz → 0.2.2__tar.gz
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.
- {toolwake-0.2.1 → toolwake-0.2.2}/CHANGELOG.md +16 -0
- {toolwake-0.2.1/src/toolwake.egg-info → toolwake-0.2.2}/PKG-INFO +1 -1
- {toolwake-0.2.1 → toolwake-0.2.2}/pyproject.toml +1 -1
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/__init__.py +1 -1
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/viewer.py +21 -3
- {toolwake-0.2.1 → toolwake-0.2.2/src/toolwake.egg-info}/PKG-INFO +1 -1
- {toolwake-0.2.1 → toolwake-0.2.2}/tests/test_toolwake.py +35 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/LICENSE +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/MANIFEST.in +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/README.md +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/examples/demo.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/setup.cfg +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/cli.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/deposit.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/geometry.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/profile.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/render.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/serve.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/simulate.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/tool.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake/toolpath.py +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake.egg-info/SOURCES.txt +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake.egg-info/dependency_links.txt +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake.egg-info/entry_points.txt +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake.egg-info/requires.txt +0 -0
- {toolwake-0.2.1 → toolwake-0.2.2}/src/toolwake.egg-info/top_level.txt +0 -0
|
@@ -4,6 +4,22 @@ All notable changes to this project are documented here. Format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
|
|
5
5
|
[Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.2.2] — 2026-09-18
|
|
8
|
+
|
|
9
|
+
Bounds the size of the viewer page. No reported number changes.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **The viewer inlined every deposited bead, so the page grew without limit.**
|
|
13
|
+
Frames were capped at 400; beads were not capped at all. A 2 674-row path
|
|
14
|
+
already produces a 1.2 MB page, and a 100 000-row one would produce tens of
|
|
15
|
+
megabytes — which is a problem the moment anyone raises their row budget and
|
|
16
|
+
tries to embed the result in an iframe.
|
|
17
|
+
|
|
18
|
+
`to_html_str` now takes `max_beads` (default 20 000) and decimates the drawn
|
|
19
|
+
wake on the same rule as frames: sample evenly, and never drop a bead
|
|
20
|
+
something collided with. Purely cosmetic — the report is computed from the
|
|
21
|
+
full deposit, and nothing on the page claims a bead count.
|
|
22
|
+
|
|
7
23
|
## [0.2.1] — 2026-09-18
|
|
8
24
|
|
|
9
25
|
Finishes 0.2.0. That release fixed the tool's geometry; this one fixes the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: toolwake
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Simulate a depositing tool travelling a toolpath, accumulate the material it leaves in its wake, and check the tool against it.
|
|
5
5
|
Author-email: Zane Bates <zanetbates1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "toolwake"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Simulate a depositing tool travelling a toolpath, accumulate the material it leaves in its wake, and check the tool against it."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -19,7 +19,7 @@ from .profile import Section, ToolProfile, blunt_cannula, luer_taper_tip
|
|
|
19
19
|
from .tool import Needle, ToolPose
|
|
20
20
|
from .toolpath import PRINT, TRAVEL, Toolpath
|
|
21
21
|
|
|
22
|
-
__version__ = "0.2.
|
|
22
|
+
__version__ = "0.2.2"
|
|
23
23
|
|
|
24
24
|
__all__ = [
|
|
25
25
|
"Toolpath", "PRINT", "TRAVEL",
|
|
@@ -310,7 +310,7 @@ def to_html(result, out="wake.html", **kw):
|
|
|
310
310
|
return out
|
|
311
311
|
|
|
312
312
|
|
|
313
|
-
def to_html_str(result, *, max_frames=400, fps=20, title=None,
|
|
313
|
+
def to_html_str(result, *, max_frames=400, max_beads=20000, fps=20, title=None,
|
|
314
314
|
show_housing=True, live_poll=None):
|
|
315
315
|
"""Write a standalone interactive viewer for `result`.
|
|
316
316
|
|
|
@@ -318,6 +318,10 @@ def to_html_str(result, *, max_frames=400, fps=20, title=None,
|
|
|
318
318
|
"jump to worst" goes straight to the deepest penetration — which is usually
|
|
319
319
|
the only frame anyone actually wants to see.
|
|
320
320
|
|
|
321
|
+
`max_frames` and `max_beads` bound the size of the page. Both sample evenly
|
|
322
|
+
and both keep every collision regardless: the page exists to show what went
|
|
323
|
+
wrong, so that is the one thing decimation must never discard.
|
|
324
|
+
|
|
321
325
|
The current frame is mirrored into the URL hash, so `file.html#f=506` or
|
|
322
326
|
`file.html#worst` opens directly on a given row. That turns "look at the
|
|
323
327
|
collision around row 506" into something sendable.
|
|
@@ -353,8 +357,22 @@ def to_html_str(result, *, max_frames=400, fps=20, title=None,
|
|
|
353
357
|
if c >= 0 and d < result.threshold}
|
|
354
358
|
segs = dep.segments()
|
|
355
359
|
t_of = np.asarray(dep._t) if len(dep) else np.zeros(0, dtype=int)
|
|
356
|
-
|
|
357
|
-
|
|
360
|
+
|
|
361
|
+
# Decimate the drawn wake, on the same rule as frames: sample evenly, and
|
|
362
|
+
# never drop a bead something collided with. Every segment is inlined into
|
|
363
|
+
# the page, so an unbounded wake is an unbounded page — a 2 674-row path
|
|
364
|
+
# gives 1.2 MB, and a 100 000-row one would give tens of megabytes that no
|
|
365
|
+
# iframe is going to enjoy. Purely cosmetic: the report is computed from
|
|
366
|
+
# the full deposit, and nothing on the page claims a bead count.
|
|
367
|
+
n_segs = len(segs)
|
|
368
|
+
if max_beads and n_segs > max_beads:
|
|
369
|
+
stride = int(np.ceil(n_segs / max_beads))
|
|
370
|
+
shown = sorted(set(range(0, n_segs, stride)) | hot)
|
|
371
|
+
else:
|
|
372
|
+
shown = range(n_segs)
|
|
373
|
+
beads = [[*map(float, segs[j][0]), *map(float, segs[j][1]),
|
|
374
|
+
int(t_of[j]), 1 if j in hot else 0]
|
|
375
|
+
for j in shown]
|
|
358
376
|
|
|
359
377
|
frames = []
|
|
360
378
|
for r in rows:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: toolwake
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Simulate a depositing tool travelling a toolpath, accumulate the material it leaves in its wake, and check the tool against it.
|
|
5
5
|
Author-email: Zane Bates <zanetbates1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -885,3 +885,38 @@ def test_bead_sits_below_the_nozzle_face_not_on_the_path():
|
|
|
885
885
|
assert dropped.n_hits == 0, (
|
|
886
886
|
f"bead dropped to its layer still collides: {dropped.n_hits} rows, "
|
|
887
887
|
f"worst {dropped.worst * 1e3:.4f} mm")
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
def test_viewer_bounds_the_wake_but_keeps_every_collision():
|
|
891
|
+
"""The page inlines every bead, so an unbounded wake is an unbounded page.
|
|
892
|
+
|
|
893
|
+
A 2 674-row path already produces 1.2 MB; at the 100 000-row budget the
|
|
894
|
+
backend now allows, an uncapped wake would be tens of megabytes and no
|
|
895
|
+
iframe would enjoy it. Decimation samples evenly and keeps every bead
|
|
896
|
+
something collided with — the page exists to show what went wrong, so that
|
|
897
|
+
is the one thing it must never drop.
|
|
898
|
+
"""
|
|
899
|
+
import json
|
|
900
|
+
import re
|
|
901
|
+
|
|
902
|
+
from toolwake.viewer import to_html_str
|
|
903
|
+
|
|
904
|
+
# A tight spiral so plenty of beads land near the tool and some collide.
|
|
905
|
+
path = Toolpath.helix(radius=0.004, pitch=2e-4, turns=12.0, per_turn=120)
|
|
906
|
+
res = simulate(path, Needle(inner_d=90e-6), lag=4, threshold=0.0)
|
|
907
|
+
|
|
908
|
+
def beads_of(html):
|
|
909
|
+
m = re.search(r'"beads":\s*(\[.*?\])\s*,\s*"', html, re.S)
|
|
910
|
+
assert m, "bead array not found in the page"
|
|
911
|
+
return json.loads(m.group(1))
|
|
912
|
+
|
|
913
|
+
full = beads_of(to_html_str(res, max_beads=0))
|
|
914
|
+
small = beads_of(to_html_str(res, max_beads=60))
|
|
915
|
+
assert len(full) > 200, "fixture is too small to exercise decimation"
|
|
916
|
+
|
|
917
|
+
n_hot = sum(1 for b in full if b[7])
|
|
918
|
+
assert len(small) <= 60 + n_hot, (
|
|
919
|
+
f"{len(small)} beads kept against a cap of 60 (+{n_hot} collisions)")
|
|
920
|
+
assert len(small) < len(full)
|
|
921
|
+
assert sum(1 for b in small if b[7]) == n_hot, (
|
|
922
|
+
"decimation dropped a bead that something collided with")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|