aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-28 10:43:51 +0100
committerDanilo M. <danix@danix.xyz>2026-10-28 10:43:51 +0100
commitd368de4b30d8a1dc9bb72ba45c55b07d3f034c82 (patch)
tree66c586ec73f84f4c30b9d2da4bfa332cc93c7ec0
parent91c87e7dbcb3029d23ce0baa9b2bcab1394381c3 (diff)
downloadgenerat3D-d368de4b30d8a1dc9bb72ba45c55b07d3f034c82.tar.gz
generat3D-d368de4b30d8a1dc9bb72ba45c55b07d3f034c82.zip
Register figure node formulas after the figure exists
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
-rw-r--r--generat3d/scene.py5
-rw-r--r--tests/test_scene.py23
2 files changed, 27 insertions, 1 deletions
diff --git a/generat3d/scene.py b/generat3d/scene.py
index 03b92f7..25e4b61 100644
--- a/generat3d/scene.py
+++ b/generat3d/scene.py
@@ -115,8 +115,11 @@ class _Loader:
if len(figs) > 1:
raise Error(f"{self.path}: v1 handles one figure per scene, found {len(figs)}")
self.inst = {figs[0][0]["id"], figs[0][0].get("name")} - {None}
+ self.pending = []
self.figure = self._figure(*figs[0])
self.ids = {n.id for n in self.figure.nodes} | {n.name for n in self.figure.nodes}
+ for f, source in self.pending:
+ self._formula(f, source)
self._morphs(figs[0][1])
posed = self._dials() or posed
if posed:
@@ -143,7 +146,7 @@ class _Loader:
for a, v in zip(AXES, _channel(n, ch)):
self.graph.add_prop(key(n["id"], n["id"], f"{ch}/{a}"), v)
for f in n.get("formulas", []):
- self._formula(f, fpath)
+ self.pending.append((f, fpath))
return Figure(asset["id"], inst.get("name", asset.get("name", asset["id"])),
inst.get("label", asset.get("label", asset["id"])),
np.array(geom["vertices"]["values"], dtype=float),
diff --git a/tests/test_scene.py b/tests/test_scene.py
index 6ea7fa3..76a28b6 100644
--- a/tests/test_scene.py
+++ b/tests/test_scene.py
@@ -210,3 +210,26 @@ class SceneTest(unittest.TestCase):
def test_follower_modifier_not_reported_missing(self):
load_quiet(self.duf({"nodes": self.base_nodes(), "modifiers": [
self.tall("#Shirt", 1, "/data/Test/Shirt/Shirt.dsf#Loose")]}))
+
+ def fig_doc(self, hip_extra=None, verts=None):
+ """A figure file with root Fig2 and a bone hip (id), optionally tweaked."""
+ xyz = lambda *v: [{"id": a, "value": x} for a, x in zip("xyz", v)]
+ hip = {"id": "hip", "name": "hip", "type": "bone", "center_point": xyz(0, 5, 0),
+ "end_point": xyz(0, 8, 0), "orientation": xyz(0, 0, 0)}
+ hip.update(hip_extra or {})
+ root = {"id": "Fig2", "name": "Fig2", "type": "figure", "center_point": xyz(0, 0, 0),
+ "end_point": xyz(0, 10, 0), "orientation": xyz(0, 0, 0)}
+ return {"node_library": [root, hip], "geometry_library": [
+ {"id": "g", "vertices": {"values": verts or [[0, 0, 0], [1, 0, 0], [0, 1, 0]]}}]}
+
+ def fig2(self, **kw):
+ """Load a scene of the temp figure; returns (scene, stderr)."""
+ root = self.root("data/Test/Fig2/Fig2.dsf", self.fig_doc(**kw))
+ nodes = [{"id": "Fig2", "url": "/data/Test/Fig2/Fig2.dsf#Fig2", "name": "Fig2"}]
+ return load_quiet(self.duf({"nodes": nodes}), [root])
+
+ def test_figure_node_formulas_registered(self):
+ scene, _ = self.fig2(hip_extra={"formulas": [{
+ "output": "hip:/data/Test/Fig2/Fig2.dsf#hip?center_point/y",
+ "operations": [{"op": "push", "val": 1}]}]})
+ self.assertEqual(len(scene.graph.formulas["hip:hip?center_point/y"]), 1)