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 move_network(network): """Move the entire network. Parameters: network (compas.datastructures.network.Network): A network object. """ color = Rhino.ApplicationSettings.AppearanceSettings.FeedbackColor origin = {key: network.vertex_coordinates(key) for key in network.vertices()} vertex = {key: network.vertex_coordinates(key) for key in network.vertices()} edges = network.edges() start = rhino.pick_point('Point to move from?') if not start: return def OnDynamicDraw(sender, e): current = list(e.CurrentPoint) vec = [current[i] - start[i] for i in range(3)] for key in vertex: vertex[key] = [origin[key][i] + vec[i] for i in range(3)] for u, v in iter(edges): sp = vertex[u] ep = vertex[v] sp = Point3d(*sp) ep = Point3d(*ep) e.Display.DrawDottedLine(sp, ep, color) guids = rhino.get_objects(name='{0}.*'.format(network.attributes['name'])) rhino.delete_objects(guids, False) gp = Rhino.Input.Custom.GetPoint() gp.SetCommandPrompt('Point to move to?') gp.DynamicDraw += OnDynamicDraw gp.Get() if gp.CommandResult() == Rhino.Commands.Result.Success: end = list(gp.Point()) vec = [end[i] - start[i] for i in range(3)] for key, attr in network.vertices(True): attr['x'] += vec[0] attr['y'] += vec[1] attr['z'] += vec[2] try: network.draw() except AttributeError: # this may result in the network being drawn in a different layer then before draw_network(network)
def draw_mesh_as_faces(mesh, layer=None, clear_layer=False, facecolor=None, redraw=True): 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) facecolor = facecolor or {} meshes = [] for fkey in mesh.faces(): vertices = mesh.face_coordinates(fkey) faces = [range(len(vertices))] color = facecolor.get(fkey, (255, 255, 255)) guid = compas_rhino.xdraw_mesh(vertices, faces, None, '{0}.face.{1}'.format( mesh.attributes['name'], fkey), layer=layer, clear=False, redraw=False) compas_rhino.set_mesh_vertex_colors( guid, [color for i in range(len(vertices))]) meshes.append(guid) if layer: previous = rs.CurrentLayer(layer) guid = rs.JoinMeshes(meshes, delete_input=True) if layer: rs.CurrentLayer(previous) rs.ObjectName(guid, '{0}'.format(mesh.attributes['name'])) rs.EnableRedraw() rs.Redraw()
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 = rhino.get_tolerance() guids = rhino.get_objects(name='{0}.force:residual.*'.format(network.attributes['name'])) 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, }) rhino.xdraw_lines(lines, layer=layer, clear=clear_layer)
def display_network_applied_loads(network, display=True, layer=None, clear_layer=False, scale=1.0, color=(0, 0, 255)): tol = rhino.get_tolerance() guids = rhino.get_objects(name='{0}.force:load.*'.format(network.attributes['name'])) 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, }) rhino.xdraw_lines(lines, layer=layer, clear=clear_layer)
def display_network_face_labels(network, attr_name=None, layer=None, color=None, formatter=None): """Display labels for the faces of a network. Parameters: network (compas.datastructures.network.Network): The network object. attr_name (str): Optional. The name of the attribute value to display in the label. Default is ``None``. If ``None``, the key of the face is displayed. layer (str): Optional. The layer to draw in. Default is ``None``. color (str, tuple, list, dict): Optional. The color specification. Default is ``None``. The following values are supported: * str: A HEX color. For example, ``'#ff0000'``. * tuple, list: RGB color. For example, ``(255, 0, 0)``. * dict: A dictionary of RGB and/or HEX colors. If ``None``, the default face color of the network will be used. formatter (callable): Optional. A formatting function. Default is ``None``. Example: .. code-block:: python import compas from compas.cad import rhino as compas_rhino from compas.datastructures.network import Network network = Network.from_obj(compas.get_data('lines.obj')) compas_rhino.display_network_face_labels(network) See Also: * :func:`display_network_vertex_labels` * :func:`display_network_edge_labels` """ rhino.delete_objects(rhino.get_objects(name="{0}.face.label.*".format(network.attributes['name']))) if not attr_name: attr_name = 'key' colordict = color_to_colordict(color, network.faces(), default=network.attributes['color.face'], colorformat='rgb', normalize=False) if formatter: if not callable(formatter): raise Exception('The provided formatter is not callable.') else: formatter = str labels = [] for index, fkey in enumerate(network.faces()): if attr_name == 'key': value = fkey elif attr_name == 'index': value = index else: value = network.facedata[fkey][attr_name] labels.append({ 'pos' : network.face_centroid(fkey), 'text' : formatter(value), 'name' : '{0}.face.label.{1}'.format(network.attributes['name'], fkey), 'color': colordict[fkey] }) rhino.xdraw_labels( labels, layer=layer, clear=False, redraw=True )
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_rhino.utilities.drawing.xdraw_lines` * :func:`compas_rhino.utilities.drawing.xdraw_points` Example: .. code-block:: python :emphasize-lines: 7 import compas from compas.datastructures.network import Network from compas.cad import rhino as compas_rhino network = Network.from_obj(compas.get_data('lines.obj')) 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 = rhino.get_objects(name='{0}.*'.format(network.attributes['name'])) rhino.delete_objects(guids) rhino.xdraw_points( points, layer=layer, clear=clear_layer, redraw=False ) rhino.xdraw_lines( lines, layer=layer, clear=False, redraw=False ) rhino.xdraw_labels( labels, layer=layer, clear=False, redraw=True )
def display_network_axial_forces(network, display=True, layer=None, clear_layer=False, scale=1.0, attr_name='f', color_tension=(255, 0, 0), color_compression=(0, 0, 255)): """Display the axial forces in the edges of a network. Parameters: network (compas.datastructures.network.Network): The network object. display (bool): Optional. If ``True``, display the axial forces. If ``False``, don't display the axial forces. Default is ``True``. layer (str): Optional. The layer to draw in. Default is ``None``. clear_layer (bool): Optional. Flag for clearing the layer. Default is ``False``. scale (float): Optional. The scale of the forces. Default is ``1.0``. attr_name (str): Optional. The name of the edge attribute storing the force value. Default is ``'f'``. color_tension (tuple): Optional. The color to use for tension forces. Default is ``(255, 0, 0)``. color_compression (tuple): Optional. The color to use for compression forces. Default is ``(0, 0, 255)``. Example: .. code-block:: python import random import compas from compas.cad import rhino as compas_rhino from compas.datastructures.network import Network network = Network.from_obj(compas.get_data('lines.obj')) for u, v, attr in network.edges(True): attr['f'] = random.choice([-1.0, 1.0]) * random.randint(1, 10) compas_rhino.display_network_axial_forces(network) See Also: * :func:`display_network_reaction_forces` * :func:`display_network_residual_forces` * :func:`display_network_selfweight` """ tol = rhino.get_tolerance() objects = rhino.get_objects(name='{0}.force:axial.*'.format(network.attributes['name'])) rhino.delete_objects(objects) if not display: return lines = [] for u, v, attr in network.edges(True): start = network.vertex_coordinates(u) end = network.vertex_coordinates(v) force = attr['f'] color = color_tension if force > 0.0 else color_compression radius = scale * ((force ** 2) ** 0.5 / 3.14159) ** 0.5 name = '{0}.force:axial.{1}-{2}'.format(network.attributes['name'], u, v) if radius < tol: continue lines.append({ 'start' : start, 'end' : end, 'name' : name, 'color' : color, 'radius': radius, }) rhino.xdraw_cylinders(lines, layer=layer, clear=clear_layer)
def display_mesh_edge_labels(mesh, attr_name=None, layer=None, color=None, formatter=None): """Display labels for the edges of a mesh. Parameters: mesh (compas.datastructures.mesh.Mesh): The mesh object. attr_name (str): Optional. The name of the attribute value to display in the label. Default is ``None``. If ``None``, the key of the edge is displayed. layer (str): Optional. The layer to draw in. Default is ``None``. color (str, tuple, list, dict): Optional. The color specification. Default is ``None``. The following values are supported: * str: A HEX color. For example, ``'#ff0000'``. * tuple, list: RGB color. For example, ``(255, 0, 0)``. * dict: A dictionary of RGB and/or HEX colors. If ``None``, the default edge color of the mesh will be used. formatter (callable): Optional. A formatting function. Default is ``None``. Example: .. code-block:: python import compas from compas.cad import rhino as compas_rhino from compas.datastructures.mesh import Mesh mesh = Mesh.from_obj(compas.get_data('faces.obj')) compas_rhino.display_mesh_edge_labels(mesh) See Also: * :func:`display_mesh_vertex_labels` * :func:`display_mesh_face_labels` """ compas_rhino.delete_objects( compas_rhino.get_objects( name="{0}.edge.label.*".format(mesh.attributes['name']))) if not attr_name: attr_name = 'key' colordict = color_to_colordict(color, mesh.edges(), default=mesh.attributes['color.edge'], colorformat='rgb', normalize=False) if formatter: if not callable(formatter): raise Exception('The provided formatter is not callable.') else: formatter = str labels = [] for index, (u, v, attr) in enumerate(mesh.edges(True)): if attr_name == 'key': value = '{0}-{1}'.format(u, v) elif attr_name == 'index': value = index else: value = attr[attr_name] labels.append({ 'pos': mesh.edge_midpoint(u, v), 'text': formatter(value), 'name': '{0}.edge.label.{1}-{2}'.format(mesh.attributes['name'], u, v), 'color': colordict[(u, v)], }) compas_rhino.xdraw_labels(labels, layer=layer, clear=False, redraw=True)
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()
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 = rhino.get_objects(name='{0}.mesh'.format(name)) objects += rhino.get_objects(name='{0}.vertex.*'.format(name)) objects += rhino.get_objects(name='{0}.edge.*'.format(name)) rhino.delete_objects(objects) # clear the layer if requested if clear: 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, }) 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), }) 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), }) rhino.xdraw_points(points, layer=layer, clear=False, redraw=False) # redraw if requested if redraw: rs.Redraw()