def display_mesh_face_normals(mesh, display=True, layer=None, scale=1.0, color=(0, 0, 255)): guids = compas_rhino.get_objects( name='{0}.face.normal.*'.format(mesh.attributes['name'])) compas_rhino.delete_objects(guids) if not display: return lines = [] for fkey in mesh.faces(): normal = mesh.face_normal(fkey) start = mesh.face_center(fkey) end = [start[axis] + normal[axis] for axis in range(3)] name = '{0}.face.normal.{1}'.format(mesh.attributes['name'], fkey) lines.append({ 'start': start, 'end': end, 'name': name, 'color': color, 'arrow': 'end', }) compas_rhino.xdraw_lines(lines, layer=layer, clear=False, redraw=True)
def draw_selfweight(self, scale=None, eps=None): """Draw vectors indicating the magnitude of the selfweight of the blocks. Parameters ---------- scale : float, optional The scale at which the selfweight vectors should be drawn. Default is `0.1`. eps : float, optional A tolerance for drawing small vectors. Selfweight vectors with a scaled length smaller than this tolerance are not drawn. Default is `1e-3`. Notes ----- * Selfweight vectors are drawn as Rhino lines with arrow heads. * The default color is *green*: `'#00ff00'` or `(0, 255, 0)`. * Selfweight vectors are drawn in a sub-layer *Selfweight* of the base layer, if a base layer was specified. * Selfweight vectors are named according to the following pattern: `"{assembly name}.selfweight.{block id}"`. """ layer = "{}::Selfweight".format(self.layer) if self.layer else None scale = scale or self.defaults['scale.selfweight'] eps = eps or self.defaults['eps.selfweight'] color = self.defaults['color.selfweight'] lines = [] for key, attr in self.assembly.vertices(True): block = self.assembly.blocks[key] volume = block.volume() if volume * scale < eps: continue vector = [0.0, 0.0, -1.0 * volume * scale] sp = block.centroid() ep = sp[:] ep[2] += vector[2] lines.append({ 'start': sp, 'end': ep, 'name': "{}.selfweight.{}".format(self.assembly.name, key), 'color': color, 'arrow': 'end' }) compas_rhino.xdraw_lines(lines, layer=layer, clear=False, redraw=False)
def draw_lines(self, lines, layer=None, clear_layer=False, redraw=False): """Draw a collection of lines. Parameters ---------- lines : list of dict The lines to draw. layer : str, optional The layer to draw the points in. Default is ``None``. clear_layer : bool, optional Clear the specified layer. Default is ``False``. redraw : bool, optional Redraw the Rhino view. Default is ``False``. Returns ------- list of guid The GUIDs of the points. """ layer = layer or self.layer return compas_rhino.xdraw_lines(lines, layer=layer, clear=clear_layer, redraw=redraw)
def network_draw_loads(network, scale=1.0, layer=None, clear_layer=False): lines = [] for key, attr in network.vertices(True): if not attr['is_fixed']: force = attr['px'], attr['py'], attr['pz'] start = network.vertex_coordinates(key) end = [start[axis] + scale * force[axis] for axis in (0, 1, 2)] lines.append({ 'start': start, 'end' : end, 'name' : '{}.load.{}'.format(network.name, key), 'color': (0, 255, 255), 'arrow': 'end', }) guids = compas_rhino.get_objects(name='{}.load.*'.format(network.name)) compas_rhino.delete_objects(guids) compas_rhino.xdraw_lines(lines, layer=layer, clear=clear_layer)
def display_network_residual_forces(network, display=True, layer=None, clear_layer=False, scale=1.0, color=(0, 255, 255), attr_name='is_anchor'): tol = compas_rhino.get_tolerance() guids = compas_rhino.get_objects(name='{0}.force:residual.*'.format(network.attributes['name'])) compas_rhino.delete_objects(guids) if not display: return lines = [] for key, attr in network.vertices(True): if attr[attr_name]: continue force = attr['rx'], attr['ry'], attr['rz'] start = network.vertex_coordinates(key) end = [start[i] + scale * force[i] for i in range(3)] length = distance_point_point(start, end) arrow = 'end' name = '{0}.force:residual.{1}'.format(network.attributes['name'], key) if length < tol: continue lines.append({ 'start' : start, 'end' : end, 'name' : name, 'color' : color, 'arrow' : arrow, }) compas_rhino.xdraw_lines(lines, layer=layer, clear=clear_layer)
def draw_edges(self, keys=None, color=None): """Draw a selection of edges of the network. Parameters ---------- keys : 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 : str, tuple, dict The color specififcation for the edges. Colors should be specified in the form of a string (hex colors) or as a tuple of RGB components. To apply the same color to all faces, provide a single color specification. Individual colors can be assigned using a dictionary of key-color pairs. Missing keys will be assigned the default face color (``self.defaults['face.color']``). The default is ``None``, in which case all faces are assigned the default edge color. Notes ----- All edges are named using the following template: ``"{}.edge.{}-{}".fromat(self.datastructure.name, u, v)``. This name is used afterwards to identify edges of the network in the Rhino model. Examples -------- >>> artist.draw_edges() >>> artist.draw_edges(color='#ff0000') >>> artist.draw_edges(color=(255, 0, 0)) >>> artist.draw_edges(keys=self.datastructure.edges_xxx()) >>> artist.draw_edges(color={(u, v): '#00ff00' for u, v in self.datastructure.edges_xxx()}) """ keys = keys or list(self.datastructure.edges()) colordict = color_to_colordict(color, keys, default=self.defaults['color.edge'], colorformat='rgb', normalize=False) lines = [] for u, v in keys: lines.append({ 'start': self.datastructure.vertex_coordinates(u), 'end': self.datastructure.vertex_coordinates(v), 'color': colordict[(u, v)], 'name': self.datastructure.edge_name(u, v) }) return compas_rhino.xdraw_lines(lines, layer=self.layer, clear=False, redraw=False)
def draw_selfweight(self, scale=None, color=None): self.clear_selfweight() lines = [] color = color or self.form.attributes['color.selfweight'] scale = scale or self.form.attributes['scale.selfweight'] tol = self.form.attributes['tol.selfweight'] tol2 = tol**2 for key, attr in self.form.vertices_where( { 'is_anchor': False, 'is_external': False }, True): t = attr['t'] a = self.form.vertex_area(key) sp = self.form.vertex_coordinates(key) dz = scale * t * a if dz**2 < tol2: continue ep = sp[0], sp[1], sp[2] - dz lines.append({ 'start': sp, 'end': ep, 'color': color, 'arrow': 'end', 'name': "{}.selfweight.{}".format(self.form.name, key) }) compas_rhino.xdraw_lines(lines, layer=self.layer, clear=False, redraw=False)
def draw_reactions(self, scale=1.0, color=None): compas_rhino.delete_objects( compas_rhino.get_objects( name="{}.reaction.*".format(self.mesh.name))) color = color or (0, 255, 0) lines = [] for key, attr in self.mesh.vertices(True): if not attr['is_anchor']: continue r = [attr['rx'], attr['ry'], attr['rz']] sp = [attr['x'], attr['y'], attr['z']] ep = add_vectors(sp, scale_vector(r, -scale)) lines.append({ 'start': sp, 'end': ep, 'color': color, 'name': "{}.reaction.{}".format(self.mesh.name, key), 'arrow': 'end' }) compas_rhino.xdraw_lines(lines, layer=self.layer, redraw=True)
def draw_loads(self, scale=None, color=None): self.clear_loads() lines = [] color = color or self.form.attributes['color.load'] scale = scale or self.form.attributes['scale.load'] tol = self.form.attributes['tol.load'] tol2 = tol**2 for key, attr in self.form.vertices_where( { 'is_anchor': False, 'is_external': False }, True): px = scale * attr['px'] py = scale * attr['py'] pz = scale * attr['pz'] if px**2 + py**2 + pz**2 < tol2: continue sp = self.form.vertex_coordinates(key) ep = sp[0] + px, sp[1] + py, sp[2] + pz lines.append({ 'start': sp, 'end': ep, 'color': color, 'arrow': 'end', 'name': "{}.load.{}".format(self.form.name, key) }) compas_rhino.xdraw_lines(lines, layer=self.layer, clear=False, redraw=False)
def draw_residuals(self, scale=None, color=None): self.clear_residuals() lines = [] color = color or self.form.attributes['color.residual'] scale = scale or self.form.attributes['scale.residual'] tol = self.form.attributes['tol.residual'] tol2 = tol**2 for key, attr in self.form.vertices_where( { 'is_anchor': False, 'is_external': False }, True): rx = scale * attr['rx'] ry = scale * attr['ry'] rz = scale * attr['rz'] if rx**2 + ry**2 + rz**2 < tol2: continue sp = self.form.vertex_coordinates(key) ep = sp[0] + rx, sp[1] + ry, sp[2] + rz lines.append({ 'start': sp, 'end': ep, 'color': color, 'arrow': 'start', 'name': "{}.residual.{}".format(self.form.name, key) }) compas_rhino.xdraw_lines(lines, layer=self.layer, clear=False, redraw=False)
def display_network_applied_loads(network, display=True, layer=None, clear_layer=False, scale=1.0, color=(0, 0, 255)): tol = compas_rhino.get_tolerance() guids = compas_rhino.get_objects(name='{0}.force:load.*'.format(network.attributes['name'])) compas_rhino.delete_objects(guids) if not display: return lines = [] for key, attr in network.vertices(True): load = attr['px'], attr['py'], attr['pz'] end = network.vertex_coordinates(key) start = [end[i] - scale * load[i] for i in range(3)] length = distance_point_point(start, end) arrow = 'end' name = '{0}.force:load.{1}'.format(network.attributes['name'], key) if length < tol: continue lines.append({ 'start': start, 'end' : end, 'name' : name, 'color': color, 'arrow': arrow, }) compas_rhino.xdraw_lines(lines, layer=layer, clear=clear_layer)
def draw_facenormals(self, color=None): """Draw the normals of the faces. Parameters ---------- color : str (HEX) or tuple (RGB), optional The color specification of the normal vectors. String values are interpreted as hex colors (e.g. ``'#ff0000'`` for red). Tuples are interpreted as RGB component specifications (e.g. ``(255, 0, 0) for red``. The default value is ``None``, in which case the labels are assigned the default normal vector color (``self.defaults['color.normal']``). Notes ----- The face normals are named using the following template: ``"{}.face.normal.{}".format(self.datastructure.name, key)``. This name is used afterwards to identify the normals in the Rhino model. """ color = color or self.defaults.get('color.normal') lines = [] for fkey, attr in self.datastructure.faces(True): n = self.datastructure.face_normal(fkey) sp = self.datastructure.face_centroid(fkey) ep = add_vectors(sp, n) lines.append({ 'start': sp, 'end': ep, 'name': "{}.face.normal.{}".format(self.datastructure.name, fkey), 'color': color, 'arrow': 'end' }) return compas_rhino.xdraw_lines(lines, layer=self.layer, clear=False, redraw=False)
def _draw_lines(self, lines): compas_rhino.xdraw_lines(lines, layer=self.cablenet.layer, clear=False, redraw=True)
def draw_reactions(self, scale=None, color=None): self.clear_reactions() lines = [] color = color or self.form.attributes['color.reaction'] scale = scale or self.form.attributes['scale.reaction'] tol = self.form.attributes['tol.reaction'] tol2 = tol**2 for key, attr in self.form.vertices_where({'is_anchor': True}, True): rx = attr['rx'] ry = attr['ry'] rz = attr['rz'] for nbr in self.form.vertex_neighbors(key): is_external = self.form.get_edge_attribute( (key, nbr), 'is_external', False) if is_external: f = self.form.get_edge_attribute((key, nbr), 'f', 0.0) u = self.form.edge_direction(key, nbr) u[2] = 0 v = scale_vector(u, f) rx += v[0] ry += v[1] rx = scale * rx ry = scale * ry rz = scale * rz sp = self.form.vertex_coordinates(key) if rx**2 + ry**2 > tol2: e1 = sp[0] + rx, sp[1] + ry, sp[2] lines.append({ 'start': sp, 'end': e1, 'color': color, 'arrow': 'start', 'name': "{}.reaction.{}".format(self.form.name, key) }) if rz**2 > tol2: e2 = sp[0], sp[1], sp[2] + rz lines.append({ 'start': sp, 'end': e2, 'color': color, 'arrow': 'start', 'name': "{}.reaction.{}".format(self.form.name, key) }) compas_rhino.xdraw_lines(lines, layer=self.layer, clear=False, redraw=False)
def draw_forces(self, scale=None, eps=None, mode=0): """Draw the contact forces at the interfaces. Parameters ---------- scale : float, optional The scale at which the forces should be drawn. Default is `0.1`. eps : float, optional A tolerance for drawing small force vectors. Force vectors with a scaled length smaller than this tolerance are not drawn. Default is `1e-3`. mode : int, optional Display mode: 0 normal, 1 resultant forces Default is 0 Notes ----- * Forces are drawn as lines with arrow heads. * Forces are drawn on a sub-layer *Forces* of the base layer, if a base layer was specified. * At every interface point there can be a *compression* force (blue) and a *tension* force (red). * Forces are named according to the following pattern: ``"{assembly_name}.force.{from block}-{to block}.{interface point}"`` """ layer = "{}::Forces".format(self.layer) if self.layer else None scale = scale or self.defaults['scale.force'] eps = eps or self.defaults['eps.force'] color_compression = self.defaults['color.force:compression'] color_tension = self.defaults['color.force:tension'] lines = [] # resultant_lines = [] for a, b, attr in self.assembly.edges(True): if attr['interface_forces'] is None: continue w = attr['interface_uvw'][2] # forces = [] for i in range(len(attr['interface_points'])): sp = attr['interface_points'][i] c = attr['interface_forces'][i]['c_np'] t = attr['interface_forces'][i]['c_nn'] f = c - t if f > 0.0: if scale * f < eps: continue color = color_compression elif f < 0.0: if -scale * f < eps: continue color = color_tension else: continue lines.append({ 'start': sp, 'end': [sp[axis] + scale * f * w[axis] for axis in range(3)], 'color': color, 'name': "{0}.force.{1}-{2}.{3}".format(self.assembly.name, a, b, i), 'arrow': 'end' }) # if mode == 1: # forces.append([scale * f * w[axis] for axis in range(3)]) # if mode == 0: # continue # resultant_force = sum_vectors(forces) # if len(forces) == 0: # continue # resultant_pt = sum_vectors([ # scale_vector(attr['interface_points'][i], (length_vector(forces[i]) / length_vector(resultant_force))) # for i in range(len(attr['interface_points'])) # ]) # resultant_lines.append({ # 'start' : resultant_pt, # 'end' : [resultant_pt[axis] + resultant_force[axis] for axis in range(3)], # 'color' : color, # 'name' : "{0}.resultant-friction.{1}-{2}.{3}".format(self.assembly.name, a, b, i), # 'arrow' : 'end' # }) # if mode == 0: compas_rhino.xdraw_lines(lines, layer=layer, clear=False, redraw=False)
def draw_frictions(self, scale=None, eps=None, mode=0): """Draw the contact frictions at the interfaces. Parameters ---------- scale : float, optional The scale at which the forces should be drawn. Default is `0.1`. eps : float, optional A tolerance for drawing small force vectors. Force vectors with a scaled length smaller than this tolerance are not drawn. Default is `1e-3`. mode : int, optional Display mode: 0 normal, 1 resultant forces Default is 0 Notes ----- * Forces are drawn as lines with arrow heads. * Forces are drawn on a sub-layer *Frictions* of the base layer, if a base layer was specified. * Forces are named according to the following pattern: ``"{assembly_name}.friction.{from block}-{to block}.{interface point}"`` """ layer = "{}::Frictions".format(self.layer) if self.layer else None scale = scale or self.defaults['scale.friction'] eps = eps or self.defaults['eps.friction'] color_friction = self.defaults['color.force:friction'] lines = [] resultant_lines = [] for a, b, attr in self.assembly.edges(True): if attr['interface_forces'] is None: continue u, v = attr['interface_uvw'][0], attr['interface_uvw'][1] forces = [] for i in range(len(attr['interface_points'])): sp = attr['interface_points'][i] fr_u_unit = attr['interface_forces'][i]['c_u'] fr_v_unit = attr['interface_forces'][i]['c_v'] fr_u = scale_vector(u, fr_u_unit) fr_v = scale_vector(v, fr_v_unit) f = add_vectors(fr_u, fr_v) f_l = length_vector(f) if f_l > 0.0: if scale * f_l < eps: continue color = color_friction else: continue f = scale_vector(f, scale) lines.append({ 'start': sp, 'end': [sp[axis] + f[axis] for axis in range(3)], 'color': color, 'name': "{0}.friction.{1}-{2}.{3}".format(self.assembly.name, a, b, i), 'arrow': 'end' }) if mode == 1: forces.append(f) if mode == 0: continue resultant_force = sum_vectors(forces) if len(forces) == 0: continue resultant_pt = sum_vectors([ scale_vector(attr['interface_points'][i], (length_vector(forces[i]) / length_vector(resultant_force))) for i in range(len(attr['interface_points'])) ]) resultant_lines.append({ 'start': resultant_pt, 'end': [ resultant_pt[axis] + resultant_force[axis] for axis in range(3) ], 'color': color, 'name': "{0}.resultant-friction.{1}-{2}.{3}".format( self.assembly.name, a, b, i), 'arrow': 'end' }) if mode == 0: compas_rhino.xdraw_lines(lines, layer=layer, clear=False, redraw=False) else: compas_rhino.xdraw_lines(resultant_lines, layer=layer, clear=False, redraw=False)
def draw_network(network, layer=None, clear_layer=False, vertexcolor=None, edgecolor=None, edgelabel=None): """Draw a network data structure in Rhino. Parameters: network (compas.datastructures.network.Network): The network object. layer (str): Optional. The layer to draw in. Default is ``None``. If ``None``, the currenlt layer is used. clear_layer (bool): Optional. Clear the layer if ``True``. Default is ``False``. vertexcolor (list, tuple, str, dict): Optional. The color specification for the vertices. Default is ``None``. * list, tuple: rgb color, with color specs between 0 and 255 (e.g. ``(255, 0, 0)``). * str: hex color (e.g. ``'#ff0000'``). * dict: dictionary of hex or rgb colors. edgecolor (list, tuple, str, dict): Optional. The color specification for the edges. Default is ``None``. * list, tuple: rgb color, with color specs between 0 and 255 (e.g. ``(255, 0, 0)``). * str: hex color (e.g. ``'#ff0000'``). * dict: dictionary of hex or rgb color. Note: * Any network objects with the same name that are already present in the model will be deleted by this function. * To also clear the entire layer the network will be drawn on, for example, if you have a dedicated network layer, use the ``clear_layer`` flag as well. See Also: * :class:`compas.datastructures.network.Network` * :func:`compas_compas_rhino.utilities.drawing.xdraw_lines` * :func:`compas_compas_rhino.utilities.drawing.xdraw_points` Example: .. code-block:: python :emphasize-lines: 7 import compas from compas.datastructures.network import Network import compas_rhino as compas_rhino network = Network.from_obj(compas.get_data('lines.obj')) compas_compas_rhino.draw_network(network) """ vertexcolor = color_to_colordict(vertexcolor, network.vertices(), default=network.attributes['color.vertex'], colorformat='rgb', normalize=False) edgecolor = color_to_colordict(edgecolor, network.edges(), default=network.attributes['color.edge'], colorformat='rgb', normalize=False) edgelabel = edgelabel or {} points = [] for key, attr in network.vertices(True): points.append({ 'pos' : network.vertex_coordinates(key), 'name' : '{0}.vertex.{1}'.format(network.attributes['name'], repr(key)), 'color': vertexcolor[key] }) lines = [] for u, v, attr in network.edges(True): lines.append({ 'start': network.vertex_coordinates(u), 'end' : network.vertex_coordinates(v), 'name' : '{0}.edge.{1}-{2}'.format(network.attributes['name'], repr(u), repr(v)), 'color': edgecolor[(u, v)] }) labels = [] for (u, v), text in edgelabel.items(): labels.append({ 'pos' : network.edge_midpoint(u, v), 'text' : str(text), 'name' : '{0}.edge.label.{1}-{2}'.format(network.attributes['name'], repr(u), repr(v)), 'color': edgecolor[(u, v)], }) guids = compas_rhino.get_objects(name='{0}.*'.format(network.attributes['name'])) compas_rhino.delete_objects(guids) compas_rhino.xdraw_points( points, layer=layer, clear=clear_layer, redraw=False ) compas_rhino.xdraw_lines( lines, layer=layer, clear=False, redraw=False ) compas_rhino.xdraw_labels( labels, layer=layer, clear=False, redraw=True )
def draw_volmesh(volmesh, name=None, layer=None, clear=True, redraw=True, show_faces=True, show_vertices=True, show_edges=True, vertex_color=None, edge_color=None, face_color=None): """""" # set default options if not isinstance(vertex_color, dict): vertex_color = {} if not isinstance(edge_color, dict): edge_color = {} if not isinstance(face_color, dict): face_color = {} if name: volmesh.attributes['name'] = name name = volmesh.setdefault('name', name) if layer: volmesh.attributes['layer'] = layer layer = volmesh.setdefault('layer', layer) # delete all relevant objects by name objects = compas_rhino.get_objects(name='{0}.mesh'.format(name)) objects += compas_rhino.get_objects(name='{0}.vertex.*'.format(name)) objects += compas_rhino.get_objects(name='{0}.edge.*'.format(name)) compas_rhino.delete_objects(objects) # clear the layer if requested if clear: compas_rhino.clear_layers([layer]) # draw the requested components if show_faces: faces = [] color = volmesh.attributes['color.face'] for vertices in volmesh.faces(): points = [ volmesh.vertex_coordinates(vkey) for vkey in vertices + [vertices[0]] ] faces.append({ 'points': points, 'name': '', 'color': color, }) compas_rhino.xdraw_faces(faces, layer=layer, clear=False, redraw=False) if show_edges: lines = [] color = volmesh.attributes['color.edge'] for u, v in volmesh.edges_iter(): lines.append({ 'start': volmesh.vertex_coordinates(u), 'end': volmesh.vertex_coordinates(v), 'name': '{0}.edge.{1}-{2}'.format(name, u, v), 'color': edge_color.get((u, v), color), }) compas_rhino.xdraw_lines(lines, layer=layer, clear=False, redraw=False) if show_vertices: points = [] color = volmesh.attributes['color.vertex'] for key in volmesh.vertices_iter(): points.append({ 'pos': volmesh.vertex_coordinates(key), 'name': '{0}.vertex.{1}'.format(name, key), 'color': vertex_color.get(key, color), }) compas_rhino.xdraw_points(points, layer=layer, clear=False, redraw=False) # redraw if requested if redraw: rs.Redraw()
def draw_mesh( mesh, layer=None, clear_layer=False, show_faces=True, show_vertices=False, show_edges=False, show_wireframe=False, vertexcolor=None, edgecolor=None, wireframecolor=None, facecolor=None, ): """ Draw a mesh object in Rhino. Parameters: mesh (compas.datastructures.mesh.Mesh): The mesh object. layer (str): Optional. The layer to draw in. Default is ``None``. clear_layer (bool): Optional. Clear the drawing layer. Default is ``True``. show_faces (bool): Optional. Show the faces. Default is ``True``. show_vertices (bool): Optional. Show the vertices. Default is ``True``. show_edges (bool): Optional. Show the edges. Default is ``True``. vertexcolor (str, tuple, list, dict): Optional. The vertex color specification. Default is ``None``. edgecolor (str, tuple, list, dict): Optional. The edge color specification. Default is ``None``. facecolor (str, tuple, list, dict): Optional. The face color specification. Default is ``None``. redraw (bool): Optional. Redraw instructions. Default is ``True``. Note: Colors can be specifiedin different ways: * str: A hexadecimal color that will be applied to all elements subject to the specification. * tuple, list: RGB color that will be applied to all elements subject to the specification. * dict: RGB or hex color dict with a specification for some or all of the related elements. Important: RGB colors should specify color values between 0 and 255. """ vertexcolor = color_to_colordict(vertexcolor, mesh.vertices(), default=mesh.attributes['color.vertex'], colorformat='rgb', normalize=False) edgecolor = color_to_colordict(edgecolor, mesh.edges(), default=mesh.attributes['color.edge'], colorformat='rgb', normalize=False) # facecolor = color_to_colordict(facecolor, # mesh.faces(), # default=mesh.attributes['color.face'], # colorformat='rgb', # normalize=False) guids = compas_rhino.get_objects( name='{0}.*'.format(mesh.attributes['name'])) compas_rhino.delete_objects(guids) if clear_layer: if not layer: compas_rhino.clear_current_layer() else: compas_rhino.clear_layer(layer) if show_faces: key_index = {key: index for index, key in enumerate(mesh.vertices())} xyz = [mesh.vertex_coordinates(key) for key in mesh.vertices()] faces = [] color = mesh.attributes['color.face'] for fkey in mesh.face: face = mesh.face_vertices(fkey, ordered=True) v = len(face) if v < 3: print('Degenerate face: {0} => {1}'.format(fkey, face)) elif v == 3: faces.append([key_index[k] for k in face + [face[-1]]]) elif v == 4: faces.append([key_index[k] for k in face]) else: c = len(xyz) xyz.append(mesh.face_center(fkey)) for i in range(-1, len(face) - 1): key = face[i] nbr = face[i + 1] vertices = [ c, key_index[key], key_index[nbr], key_index[nbr] ] faces.append(vertices) compas_rhino.xdraw_mesh(xyz, faces, color, '{0}.mesh'.format(mesh.attributes['name']), layer=layer, clear=False, redraw=False) if show_edges: lines = [] color = mesh.attributes['color.edge'] for u, v in mesh.edges(): lines.append({ 'start': mesh.vertex_coordinates(u), 'end': mesh.vertex_coordinates(v), 'name': '{0}.edge.{1}-{2}'.format(mesh.attributes['name'], repr(u), repr(v)), 'color': edgecolor.get((u, v), color), }) compas_rhino.xdraw_lines(lines, layer=layer, clear=False, redraw=False) if show_wireframe: lines = [] color = mesh.attributes['color.edge'] for u, v in mesh.wireframe(): lines.append({ 'start': mesh.vertex_coordinates(u), 'end': mesh.vertex_coordinates(v), 'name': '{0}.edge.{1}-{2}'.format(mesh.attributes['name'], repr(u), repr(v)), 'color': edgecolor.get((u, v), color), }) compas_rhino.xdraw_lines(lines, layer=layer, clear=False, redraw=False) if show_vertices: points = [] color = mesh.attributes['color.vertex'] for key in mesh.vertices(): points.append({ 'pos': mesh.vertex_coordinates(key), 'name': '{0}.vertex.{1}'.format(mesh.attributes['name'], repr(key)), 'color': vertexcolor.get(key, color), }) compas_rhino.xdraw_points(points, layer=layer, clear=False, redraw=False) rs.EnableRedraw() rs.Redraw()