Skip to content

Commit 9a28b2c

Browse files
authored
Merge pull request #2 from arpastrana/fresh-view-coordinates
Return fresh view coordinates from GraphObject.node_xyz and MeshObject.vertex_xyz
2 parents f990a1c + 78a1b82 commit 9a28b2c

4 files changed

Lines changed: 64 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727

2828
### Changed
2929

30+
* `GraphObject.node_xyz` and `MeshObject.vertex_xyz` return fresh view
31+
coordinates on every access instead of a mapping cached at first access, so
32+
a redraw in a `Plotter.on` animation loop picks up
33+
changes to the coordinates of the underlying datastructure.
34+
3035
### Removed

src/compas_plotters/scene/graphobject.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
from compas.colors import Color
4+
from compas.geometry import transform_points
45
from compas.scene import GraphObject as BaseGraphObject
56
from matplotlib.collections import LineCollection
67
from matplotlib.collections import PatchCollection
@@ -61,6 +62,20 @@ def __init__(
6162
self.nodetext = nodetext or {}
6263
self.edgetext = edgetext or {}
6364

65+
@property
66+
def node_xyz(self) -> dict:
67+
"""Mapping of nodes to their view coordinates."""
68+
if self._node_xyz is not None:
69+
return self._node_xyz
70+
nodes = list(self.graph.nodes())
71+
points = self.graph.nodes_attributes("xyz", keys=nodes)
72+
points = transform_points(points, self.worldtransformation)
73+
return dict(zip(nodes, points))
74+
75+
@node_xyz.setter
76+
def node_xyz(self, node_xyz: dict | None) -> None:
77+
self._node_xyz = node_xyz
78+
6479
def _node_radius(self) -> float:
6580
factor = self.plotter.dpi if self.sizepolicy == "absolute" else max(self.graph.number_of_nodes(), 1)
6681
return self.nodesize / factor

src/compas_plotters/scene/meshobject.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,25 @@ def __init__(
6161
vertexcolor=vertexcolor,
6262
**kwargs,
6363
)
64+
self._vertex_xyz = None
6465
self.vertextext = vertextext or {}
6566
self.edgetext = edgetext or {}
6667
self.facetext = facetext or {}
6768

6869
@property
6970
def vertex_xyz(self) -> dict:
70-
"""Mapping of vertices to their world coordinates."""
71+
"""Mapping of vertices to their view coordinates."""
72+
if self._vertex_xyz is not None:
73+
return self._vertex_xyz
7174
vertices = list(self.mesh.vertices())
7275
points = [self.mesh.vertex_coordinates(vertex) for vertex in vertices]
7376
points = transform_points(points, self.worldtransformation)
7477
return dict(zip(vertices, points))
7578

79+
@vertex_xyz.setter
80+
def vertex_xyz(self, vertex_xyz: dict | None) -> None:
81+
self._vertex_xyz = vertex_xyz
82+
7683
def viewdata(self) -> list[list[float]]:
7784
return [xyz[:2] for xyz in self.vertex_xyz.values()]
7885

tests/test_plotter.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,39 @@ def frame(f):
181181
point.x = f
182182

183183
assert seen == [0, 1, 2]
184+
185+
186+
def test_dynamic_on_updates_graph_node_xyz():
187+
plotter = Plotter()
188+
graph = Graph()
189+
a = graph.add_node(x=0, y=0, z=0)
190+
b = graph.add_node(x=1, y=0, z=0)
191+
graph.add_edge(a, b)
192+
obj = plotter.add(graph)
193+
194+
@plotter.on(interval=0, frames=3)
195+
def frame(f):
196+
x = graph.node_attribute(b, "x")
197+
graph.node_attribute(b, "x", x + f)
198+
199+
assert obj.node_xyz[b][0] == 4.0
200+
201+
202+
def test_mesh_vertex_xyz_is_fresh_and_assignable():
203+
plotter = Plotter()
204+
mesh = Mesh.from_vertices_and_faces(
205+
{0: [0.0, 0.0, 0.0], 1: [1.0, 0.0, 0.0], 2: [1.0, 1.0, 0.0], 3: [0.0, 1.0, 0.0]},
206+
[[0, 1, 2, 3]],
207+
)
208+
obj = plotter.add(mesh)
209+
210+
@plotter.on(interval=0, frames=3)
211+
def frame(f):
212+
y = mesh.vertex_attribute(1, "y")
213+
mesh.vertex_attribute(1, "y", y + f)
214+
215+
z = mesh.vertex_attribute(3, "z")
216+
mesh.vertex_attribute(3, "z", z + f)
217+
218+
assert obj.vertex_xyz[1][1] == 3.0
219+
assert obj.vertex_xyz[3][2] == 3.0

0 commit comments

Comments
 (0)