# from __future__ import annotations
from functools import partial
import compas_blender
from compas_blender.artists._artist import BaseArtist
from compas.utilities import color_to_colordict
colordict = partial(color_to_colordict, colorformat='rgb', normalize=True)
__all__ = ['MeshArtist']
[docs]class MeshArtist(BaseArtist):
"""A mesh artist defines functionality for visualising COMPAS meshes in Blender.
Parameters
----------
mesh : :class:`compas.datastructures.Mesh`
A COMPAS mesh.
settings : dict, optional
A dict with custom visualisation settings.
Attributes
----------
mesh : :class:`compas.datastructures.Mesh`
The COMPAS mesh associated with the artist.
settings : dict
Default settings for color, scale, tolerance, ...
Examples
--------
.. code-block:: python
import compas
from compas.datastructures import Mesh
from compas_blender.artists import MeshArtist
mesh = Mesh.from_obj(compas.get('faces.obj'))
MeshArtist(mesh).draw()
"""
[docs] def __init__(self, mesh):
super().__init__()
self._collection = None
self._vertexcollection = None
self._edgecollection = None
self._facecollection = None
self._object_vertex = {}
self._object_edge = {}
self._object_face = {}
self.color_vertices = (1.0, 1.0, 1.0)
self.color_edges = (0.0, 0.0, 0.0)
self.color_faces = (0.7, 0.7, 0.7)
self.show_vertices = True
self.show_edges = True
self.show_faces = True
self.mesh = mesh
@property
def collection(self):
if not self._collection:
self._collection = compas_blender.create_collection(self.mesh.name)
return self._collection
@property
def vertexcollection(self):
path = f"{self.mesh.name}::Vertices"
if not self._vertexcollection:
self._vertexcollection = compas_blender.create_collections_from_path(path)[1]
return self._vertexcollection
@property
def edgecollection(self):
path = f"{self.mesh.name}::Edges"
if not self._edgecollection:
self._edgecollection = compas_blender.create_collections_from_path(path)[1]
return self._edgecollection
@property
def facecollection(self):
path = f"{self.mesh.name}::Faces"
if not self._facecollection:
self._facecollection = compas_blender.create_collections_from_path(path)[1]
return self._facecollection
@property
def object_vertex(self):
"""Map between Blender object objects and mesh vertex identifiers."""
return self._object_vertex
@object_vertex.setter
def object_vertex(self, values):
self._object_vertex = dict(values)
@property
def object_edge(self):
"""Map between Blender object objects and mesh edge identifiers."""
return self._object_edge
@object_edge.setter
def object_edge(self, values):
self._object_edge = dict(values)
@property
def object_face(self):
"""Map between Blender object objects and mesh face identifiers."""
return self._object_face
@object_face.setter
def object_face(self, values):
self._object_face = dict(values)
# ==========================================================================
# clear
# ==========================================================================
[docs] def clear(self):
"""Clear all objects previously drawn by this artist.
"""
objects = []
objects += list(self.object_vertex)
objects += list(self.object_edge)
objects += list(self.object_face)
compas_blender.delete_objects(objects, purge_data=True)
self._object_vertex = {}
self._object_edge = {}
self._object_face = {}
# ==========================================================================
# components
# ==========================================================================
[docs] def draw(self):
"""Draw the mesh using the chosen visualisation settings.
Parameters
----------
settings : dict, optional
Dictionary of visualisation settings that will be merged with the settings of the artist.
"""
self.clear()
if self.show_vertices:
self.draw_vertices()
if self.show_faces:
self.draw_faces()
if self.show_edges:
self.draw_edges()
[docs] def draw_mesh(self):
"""Draw the mesh."""
vertices, faces = self.mesh.to_vertices_and_faces()
obj = compas_blender.draw_mesh(vertices, faces, name=self.mesh.name, collection=self.collection)
return [obj]
[docs] def draw_vertices(self, vertices=None, color=None):
"""Draw a selection of vertices.
Parameters
----------
vertices : list
A list of vertex keys identifying which vertices to draw.
Default is ``None``, in which case all vertices are drawn.
color : rgb-tuple or dict of rgb-tuple
The color specififcation for the vertices.
Returns
-------
list of :class:`bpy.types.Object`
"""
vertices = vertices or list(self.mesh.vertices())
vertex_color = colordict(color, vertices, default=self.color_vertices)
points = []
for vertex in vertices:
points.append({
'pos': self.mesh.vertex_coordinates(vertex),
'name': f"{self.mesh.name}.vertex.{vertex}",
'color': vertex_color[vertex],
'radius': 0.01
})
objects = compas_blender.draw_points(points, self.vertexcollection)
self.object_vertex = zip(objects, vertices)
return objects
[docs] def draw_faces(self, faces=None, color=None):
"""Draw a selection of faces.
Parameters
----------
faces : list
A list of face keys identifying which faces to draw.
The default is ``None``, in which case all faces are drawn.
color : rgb-tuple or dict of rgb-tuple
The color specififcation for the faces.
Returns
-------
list of :class:`bpy.types.Object`
"""
faces = faces or list(self.mesh.faces())
face_color = colordict(color, faces, default=self.color_faces)
facets = []
for face in faces:
facets.append({
'points': self.mesh.face_coordinates(face),
'name': f"{self.mesh.name}.face.{face}",
'color': face_color[face]
})
objects = compas_blender.draw_faces(facets, self.facecollection)
self.object_face = zip(objects, faces)
return objects
[docs] def draw_edges(self, edges=None, color=None):
"""Draw a selection of edges.
Parameters
----------
edges : list
A list of edge keys (as uv pairs) identifying which edges to draw.
The default is ``None``, in which case all edges are drawn.
color : rgb-tuple or dict of rgb-tuple
The color specififcation for the edges.
Returns
-------
list of :class:`bpy.types.Object`
"""
edges = edges or list(self.mesh.edges())
edge_color = colordict(color, edges, default=self.color_edges)
lines = []
for edge in edges:
lines.append({
'start': self.mesh.vertex_coordinates(edge[0]),
'end': self.mesh.vertex_coordinates(edge[1]),
'color': edge_color[edge],
'name': f"{self.mesh.name}.edge.{edge[0]}-{edge[1]}"
})
objects = compas_blender.draw_lines(lines, self.edgecollection)
self.object_edge = zip(objects, edges)
return objects
# ==============================================================================
# Main
# ==============================================================================
if __name__ == "__main__":
pass