diff --git a/CHANGELOG.md b/CHANGELOG.md index fa1c484e..cfd03d6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `use_tab` option to `compas_ui.rhino.forms.SettingsForm`. * Added `export` and `remove` buttons to `compas_ui.rhino.forms.SceneForm`. * Added `compas_ui.rhino.forms.ToolbarForm`. +* Added `frame` to `compas_ui.objects.Object`. ### Changed diff --git a/scripts/test_artists.py b/scripts/test_artists.py new file mode 100644 index 00000000..6134a58a --- /dev/null +++ b/scripts/test_artists.py @@ -0,0 +1,25 @@ +from compas_ui.ui import UI +from compas.geometry import Frame +from compas.geometry import Line +from compas_rhino.geometry import RhinoCurve +import compas_rhino + + +ui = UI({"plugin": {"title": ["Frame"]}, "settings": {}}) +ui.scene.clear() + +line = Line([0, 0, 0], [10, 0, 0]) +lineObj = ui.scene.add(line, name='line', frame=Frame([20, 0, 0], [1, 0, 0], [0, 1, 0])) + +guid = compas_rhino.select_curve('Select a curve') +rhinoCurve = RhinoCurve.from_guid(guid) +curve = rhinoCurve.to_compas() +curveObj = ui.scene.add(curve, name='curve', frame=Frame([0, 20, 0], [1, 0, 0], [0, 1, 0])) + +ui.scene.update() + +lineObj.move_start() +ui.scene.update() + +# curveObj.move_start() +# ui.scene.update() \ No newline at end of file diff --git a/scripts/test_frame.py b/scripts/test_frame.py new file mode 100644 index 00000000..f7c74495 --- /dev/null +++ b/scripts/test_frame.py @@ -0,0 +1,20 @@ +from compas_ui.ui import UI +from compas.datastructures import Mesh +from compas.geometry import Frame +from compas_ui.objects import Group +import compas + + +ui = UI({"plugin": {"title": ["Frame"]}, "settings": {}}) +ui.scene.clear() + +mesh1 = Mesh.from_obj(compas.get('faces.obj')) +mesh2 = mesh1.copy() +mesh3 = mesh1.copy() + +mesh1Obj = ui.scene.add(mesh1, name='mesh1') +mesh2Obj = mesh1Obj.add(mesh2, name='mesh2', frame=Frame([20, 0, 0], [1, 0, 0], [0, 1, 0])) +mesh2Obj.add(mesh3, name='mesh3', frame=Frame([0, 20, 0], [0, 0, 1], [0, 1, 0])) + +ui.scene.update() +ui.scene_objects() diff --git a/src/compas_ui/objects/curveobject.py b/src/compas_ui/objects/curveobject.py index ab702fef..5b0daff1 100644 --- a/src/compas_ui/objects/curveobject.py +++ b/src/compas_ui/objects/curveobject.py @@ -41,6 +41,10 @@ def curve(self): def curve(self, curve): self.item = curve + @property + def view_curve(self): + return self.view_item + def move(self): raise NotImplementedError diff --git a/src/compas_ui/objects/lineobject.py b/src/compas_ui/objects/lineobject.py index d51e627c..d31f44de 100644 --- a/src/compas_ui/objects/lineobject.py +++ b/src/compas_ui/objects/lineobject.py @@ -41,6 +41,10 @@ def line(self): def line(self, line): self.item = line + @property + def view_line(self): + return self.view_item + def move(self): raise NotImplementedError diff --git a/src/compas_ui/objects/meshobject.py b/src/compas_ui/objects/meshobject.py index 0d830054..661af12c 100644 --- a/src/compas_ui/objects/meshobject.py +++ b/src/compas_ui/objects/meshobject.py @@ -102,6 +102,10 @@ def mesh(self): def mesh(self, mesh): self.item = mesh + @property + def view_mesh(self): + return self.view_item + @property def anchor(self): return self._anchor @@ -144,8 +148,9 @@ def rotation(self, rotation): @property def vertex_xyz(self): origin = Point(0, 0, 0) - vertices = list(self.mesh.vertices()) - xyz = self.mesh.vertices_attributes(["x", "y", "z"], keys=vertices) + view_mesh = self.view_mesh + vertices = list(view_mesh.vertices()) + xyz = view_mesh.vertices_attributes(["x", "y", "z"], keys=vertices) stack = [] if self.scale != 1: @@ -156,7 +161,7 @@ def vertex_xyz(self): stack.append(R) if self.location != origin: if self.anchor is not None: - xyz = self.mesh.vertex_attributes(self.anchor, "xyz") + xyz = view_mesh.vertex_attributes(self.anchor, "xyz") point = Point(*xyz) T1 = Translation.from_vector(origin - point) stack.insert(0, T1) diff --git a/src/compas_ui/objects/networkobject.py b/src/compas_ui/objects/networkobject.py index 76341c21..00fb3970 100644 --- a/src/compas_ui/objects/networkobject.py +++ b/src/compas_ui/objects/networkobject.py @@ -59,6 +59,10 @@ def network(self): def network(self, network): self.item = network + @property + def view_network(self): + return self.view_item + @property def anchor(self): return self._anchor @@ -101,8 +105,9 @@ def rotation(self, rotation): @property def node_xyz(self): origin = Point(0, 0, 0) - nodes = list(self.network.nodes()) - xyz = self.network.nodes_attributes(['x', 'y', 'z'], keys=nodes) + view_network = self.view_network + nodes = list(view_network.nodes()) + xyz = view_network.nodes_attributes(['x', 'y', 'z'], keys=nodes) stack = [] if self.scale != 1.0: @@ -113,7 +118,7 @@ def node_xyz(self): stack.append(R) if self.location != origin: if self.anchor is not None: - xyz = self.network.node_attributes(self.anchor, 'xyz') + xyz = view_network.node_attributes(self.anchor, 'xyz') point = Point(* xyz) T1 = Translation.from_vector(origin - point) stack.insert(0, T1) diff --git a/src/compas_ui/objects/object.py b/src/compas_ui/objects/object.py index 9ce7ffa0..a776d515 100644 --- a/src/compas_ui/objects/object.py +++ b/src/compas_ui/objects/object.py @@ -9,6 +9,8 @@ from collections import defaultdict import compas +from compas.geometry import Frame +from compas.geometry import Transformation from compas.artists import Artist from compas.plugins import pluggable from compas.plugins import PluginValidator @@ -111,7 +113,7 @@ def __new__(cls, *args, **kwargs): PluginValidator.ensure_implementations(cls) return super(Object, cls).__new__(cls) - def __init__(self, item, scene=None, name=None, visible=True, settings=None): + def __init__(self, item, scene=None, name=None, visible=True, settings=None, frame=None): super(Object, self).__init__() self._guid = None self._item = None @@ -123,6 +125,7 @@ def __init__(self, item, scene=None, name=None, visible=True, settings=None): self.settings = self.SETTINGS.copy() self.settings.update(settings or {}) self.parent = None + self.frame = frame or Frame.worldXY() def __getstate__(self): return self.state @@ -140,6 +143,7 @@ def state(self): "settings": self.settings, "artist": self.artist.state, "visible": self.visible, + "frame": self.frame, } @state.setter @@ -149,9 +153,21 @@ def state(self, state): self.settings.update(state["settings"]) self.artist.state = state["artists"] self.visible = state["visible"] + self.frame = state["frame"] # parent? # item? + @property + def local_frame_transormation(self): + return Transformation.from_frame(self.frame) + + @property + def world_frame_transormation(self): + if self.parent: + return self.parent.world_frame_transormation * self.local_frame_transormation + else: + return self.local_frame_transormation + @property def children(self): return list(filter(lambda x: x.parent == self, self._scene.objects)) @@ -184,6 +200,10 @@ def guid(self): def item(self): return self._item + @property + def view_item(self): + return self.item.transformed(self.world_frame_transormation) + @item.setter def item(self, item): self._item = item diff --git a/src/compas_ui/objects/volmeshobject.py b/src/compas_ui/objects/volmeshobject.py index 74d58120..39a36d44 100644 --- a/src/compas_ui/objects/volmeshobject.py +++ b/src/compas_ui/objects/volmeshobject.py @@ -65,6 +65,10 @@ def volmesh(self): def volmesh(self, volmesh): self.item = volmesh + @property + def view_volmesh(self): + return self.view_item + @property def anchor(self): return self._anchor @@ -107,8 +111,10 @@ def rotation(self, rotation): @property def vertex_xyz(self): origin = Point(0, 0, 0) - vertices = list(self.volmesh.vertices()) - xyz = self.volmesh.vertices_attributes(["x", "y", "z"], keys=vertices) + view_volmesh = self.view_volmesh + vertices = list(view_volmesh.vertices()) + xyz = view_volmesh.vertices_attributes(["x", "y", "z"], keys=vertices) + xyz = transform_points(xyz, self.world_frame_transormation) stack = [] if self.scale != 1: @@ -119,7 +125,7 @@ def vertex_xyz(self): stack.append(R) if self.location != origin: if self.anchor is not None: - xyz = self.volmesh.vertex_attributes(self.anchor, "xyz") + xyz = view_volmesh.vertex_attributes(self.anchor, "xyz") point = Point(*xyz) T1 = Translation.from_vector(origin - point) stack.insert(0, T1) diff --git a/src/compas_ui/rhino/artists/curveartist.py b/src/compas_ui/rhino/artists/curveartist.py index e0ce6af8..b856286e 100644 --- a/src/compas_ui/rhino/artists/curveartist.py +++ b/src/compas_ui/rhino/artists/curveartist.py @@ -2,9 +2,14 @@ from __future__ import absolute_import from __future__ import division +import compas_rhino from compas_ui.artists import CurveArtist from compas_rhino.artists import CurveArtist as RhinoCurveArtist +from compas.colors import Color class CurveArtist(RhinoCurveArtist, CurveArtist): - pass + def draw(self, color=None): + color = Color.coerce(color) or self.color + curves = [{'curve': self.curve, 'color': color.rgb255, 'name': self.curve.name}] + return compas_rhino.draw_curves(curves, layer=self.layer, clear=False, redraw=False) diff --git a/src/compas_ui/rhino/artists/lineartist.py b/src/compas_ui/rhino/artists/lineartist.py index 330c5d6b..fb82dd99 100644 --- a/src/compas_ui/rhino/artists/lineartist.py +++ b/src/compas_ui/rhino/artists/lineartist.py @@ -2,9 +2,25 @@ from __future__ import absolute_import from __future__ import division +import compas_rhino +from compas.colors import Color from compas_ui.artists import PrimitiveArtist from compas_rhino.artists import LineArtist class LineArtist(LineArtist, PrimitiveArtist): - pass + def draw(self, color=None, show_points=False): + start = list(self.line.start) + end = list(self.line.end) + color = Color.coerce(color) or self.color + color = color.rgb255 + guids = [] + if show_points: + points = [ + {'pos': start, 'color': color, 'name': self.primitive.name}, + {'pos': end, 'color': color, 'name': self.primitive.name} + ] + guids += compas_rhino.draw_points(points, layer=self.layer, clear=False, redraw=False) + lines = [{'start': start, 'end': end, 'color': color, 'name': self.primitive.name}] + guids += compas_rhino.draw_lines(lines, layer=self.layer, clear=False, redraw=False) + return guids diff --git a/src/compas_ui/rhino/objects/curveobject.py b/src/compas_ui/rhino/objects/curveobject.py index 0dee18c6..dc83c301 100644 --- a/src/compas_ui/rhino/objects/curveobject.py +++ b/src/compas_ui/rhino/objects/curveobject.py @@ -25,6 +25,7 @@ def clear(self): def draw(self): self.clear() + self.artist.curve = self.view_curve if not self.visible: return self._guids = self.artist.draw() @@ -59,8 +60,9 @@ def move_start(self): curveobj.draw() """ - start = point_to_rhino(self.curve.start) - end = point_to_rhino(self.curve.end) + view_curve = self.view_curve + start = point_to_rhino(view_curve.start) + end = point_to_rhino(view_curve.end) color = Rhino.ApplicationSettings.AppearanceSettings.FeedbackColor gp = Rhino.Input.Custom.GetPoint() @@ -76,7 +78,7 @@ def OnDynamicDraw(sender, e): return False start = point_to_compas(gp.Point()) - self.curve.start = start + self.curve.start = start.transformed(self.world_frame_transormation.inverted()) return True def move_end(self): @@ -109,8 +111,9 @@ def move_end(self): curveobj.draw() """ - start = point_to_rhino(self.curve.start) - end = point_to_rhino(self.curve.end) + view_curve = self.view_curve + start = point_to_rhino(view_curve.start) + end = point_to_rhino(view_curve.end) color = Rhino.ApplicationSettings.AppearanceSettings.FeedbackColor gp = Rhino.Input.Custom.GetPoint() @@ -126,5 +129,5 @@ def OnDynamicDraw(sender, e): return False end = point_to_compas(gp.Point()) - self.curve.end = end + self.curve.end = end.transformed(self.world_frame_transormation.inverted()) return True diff --git a/src/compas_ui/rhino/objects/lineobject.py b/src/compas_ui/rhino/objects/lineobject.py index 3b55371a..b9582673 100644 --- a/src/compas_ui/rhino/objects/lineobject.py +++ b/src/compas_ui/rhino/objects/lineobject.py @@ -24,6 +24,7 @@ def clear(self): self._guids = [] def draw(self): + self.artist.line = self.view_line self.clear() if not self.visible: return @@ -59,8 +60,9 @@ def move_start(self): lineobj.draw() """ - start = point_to_rhino(self.line.start) - end = point_to_rhino(self.line.end) + view_line = self.view_line + start = point_to_rhino(view_line.start) + end = point_to_rhino(view_line.end) color = Rhino.ApplicationSettings.AppearanceSettings.FeedbackColor gp = Rhino.Input.Custom.GetPoint() @@ -76,7 +78,7 @@ def OnDynamicDraw(sender, e): return False start = point_to_compas(gp.Point()) - self.line.start = start + self.line.start = start.transformed(self.world_frame_transormation.inverted()) return True def move_end(self): @@ -109,8 +111,9 @@ def move_end(self): lineobj.draw() """ - start = point_to_rhino(self.line.start) - end = point_to_rhino(self.line.end) + view_line = self.view_line + start = point_to_rhino(view_line.start) + end = point_to_rhino(view_line.end) color = Rhino.ApplicationSettings.AppearanceSettings.FeedbackColor gp = Rhino.Input.Custom.GetPoint() @@ -126,5 +129,5 @@ def OnDynamicDraw(sender, e): return False end = point_to_compas(gp.Point()) - self.line.end = end + self.line.end = end.transformed(self.world_frame_transormation.inverted()) return True