Skip to content

compas_cem.viewers ¤

Three-dimensional viewing of topology and form diagrams.

Classes¤

DiagramObject ¤

DiagramObject(
    nodetext=None,
    edgetext=None,
    loadscale=1.0,
    loadtol=0.001,
    residualscale=1.0,
    residualtol=0.001,
    show_loads=True,
    show_residuals=True,
    show_nodetext=False,
    show_edgetext=False,
    textsize=50,
    textcolor=None,
    **kwargs,
)

A scene object that draws a diagram in a viewer.

Parameters:

  • nodetext

    A tag naming what to label the nodes with, or a mapping of nodes to labels.

  • edgetext

    A tag naming what to label the edges with, or a mapping of edges to labels.

  • loadscale

    The factor to scale the load vectors by.

  • loadtol

    The smallest load magnitude worth drawing.

  • residualscale

    The factor to scale the residual force vectors by.

  • residualtol

    The smallest residual force magnitude worth drawing.

  • show_loads

    Whether to draw the loads.

  • show_residuals

    Whether to draw the residual forces.

  • show_nodetext

    Whether to draw the node labels.

  • show_edgetext

    Whether to draw the edge labels.

  • textsize

    The height of the labels.

  • textcolor

    The color of the labels.

Notes

The loads, the residual forces and the labels are added as children of this object, so they follow it when it is shown, hidden or removed.

Source code in src/compas_cem/viewers/scene_objects.py
def __init__(
    self,
    nodetext=None,
    edgetext=None,
    loadscale=1.0,
    loadtol=1e-3,
    residualscale=1.0,
    residualtol=1e-3,
    show_loads=True,
    show_residuals=True,
    show_nodetext=False,
    show_edgetext=False,
    textsize=50,
    textcolor=None,
    **kwargs,
):
    super(DiagramObject, self).__init__(**kwargs)

    self.load_scale = loadscale
    self.load_tol = loadtol
    self.residual_scale = residualscale
    self.residual_tol = residualtol

    self.show_loads = show_loads
    self.show_residuals = show_residuals
    self.show_nodetext = show_nodetext
    self.show_edgetext = show_edgetext

    self.textsize = textsize
    self.textcolor = textcolor or Color.black()

    self._nodetext_tag = nodetext
    self._edgetext_tag = edgetext

Attributes¤

diagram property ¤
diagram

The diagram this object draws.

Methods:¤

draw ¤
draw()

Draw the diagram, its forces and its labels.

Source code in src/compas_cem/viewers/scene_objects.py
def draw(self):
    """
    Draw the diagram, its forces and its labels.
    """
    super(DiagramObject, self).draw()

    if self.show_loads:
        self.draw_loads()
    if self.show_residuals:
        self.draw_residuals()
    if self.show_nodetext:
        self.draw_nodetext()
    if self.show_edgetext:
        self.draw_edgetext()
draw_edgetext ¤
draw_edgetext()

Draw the labels of the edges.

Source code in src/compas_cem/viewers/scene_objects.py
def draw_edgetext(self):
    """
    Draw the labels of the edges.
    """
    labels = self.edge_textlabels(self._edgetext_tag)
    if labels is None:
        labels = {edge: "{}-{}".format(*edge) for edge in self.diagram.edges()}

    for edge, label in labels.items():
        tag = Tag(
            str(label),
            self.diagram.edge_midpoint(edge),
            color=self.textcolor,
            height=self.textsize,
        )
        self.add(tag)
draw_loads ¤
draw_loads()

Draw the loads applied to the nodes as arrows.

Source code in src/compas_cem/viewers/scene_objects.py
def draw_loads(self):
    """
    Draw the loads applied to the nodes as arrows.
    """
    self._draw_force_vectors(
        attr_names=self.load_attrs,
        scale=self.load_scale,
        tol=self.load_tol,
        color=self.loadcolor,
        shift={node: False for node in self.diagram.nodes()},
    )
draw_nodetext ¤
draw_nodetext()

Draw the labels of the nodes.

Source code in src/compas_cem/viewers/scene_objects.py
def draw_nodetext(self):
    """
    Draw the labels of the nodes.
    """
    labels = self.node_textlabels(self._nodetext_tag)
    if labels is None:
        labels = {node: str(node) for node in self.diagram.nodes()}

    for node, label in labels.items():
        tag = Tag(
            str(label),
            self.diagram.node_coordinates(node),
            color=self.textcolor,
            height=self.textsize,
        )
        self.add(tag)
draw_residuals ¤
draw_residuals()

Draw the residual forces at the nodes as arrows.

Source code in src/compas_cem/viewers/scene_objects.py
def draw_residuals(self):
    """
    Draw the residual forces at the nodes as arrows.
    """
    self._draw_force_vectors(
        attr_names=self.residual_attrs,
        scale=self.residual_scale,
        tol=self.residual_tol,
        color=self.residualcolor,
        shift=self._residual_shifts(),
    )
edge_colors ¤
edge_colors()

The color of every edge.

Returns:

  • colors

    A mapping of edges to colors.

Source code in src/compas_cem/viewers/scene_objects.py
def edge_colors(self):
    """
    The color of every edge.

    Returns
    -------
    colors :
        A mapping of edges to colors.
    """
    raise NotImplementedError
edge_textlabel_formatters ¤
edge_textlabel_formatters()

The supported edge label tags and the formatter of each.

Source code in src/compas_cem/viewers/scene_objects.py
def edge_textlabel_formatters(self):
    """
    The supported edge label tags and the formatter of each.
    """
    precision = self.float_precision
    diagram = self.diagram

    def force_format(edge):
        return "{0:.{1}}".format(diagram.edge_force(edge), precision)

    def length_format(edge):
        return "{0:.{1}}".format(diagram.edge_length_2(edge), precision)

    def force_length_format(edge):
        return "f: {}\nl: {}".format(force_format(edge), length_format(edge))

    def state_format(edge):
        parameter = diagram.edge_force(edge)
        return "{0:.{1}}".format(copysign(1.00, parameter), precision)

    return {
        "force": force_format,
        "length": length_format,
        "state": state_format,
        "forcelength": force_length_format,
    }
edge_textlabels ¤
edge_textlabels(tag)

Build the labels to draw on the edges.

Parameters:

  • tag

    A tag naming what to label the edges with, or a mapping of edges to labels, which is returned unchanged.

Returns:

  • labels

    A mapping of edges to labels, or None if the tag is unsupported.

Source code in src/compas_cem/viewers/scene_objects.py
def edge_textlabels(self, tag):
    """
    Build the labels to draw on the edges.

    Parameters
    ----------
    tag :
        A tag naming what to label the edges with, or a mapping of edges to
        labels, which is returned unchanged.

    Returns
    -------
    labels :
        A mapping of edges to labels, or `None` if the tag is unsupported.
    """
    if tag is None or isinstance(tag, dict):
        return tag

    formatters = self.edge_textlabel_formatters()
    if tag not in formatters:
        return None

    formatter = formatters[tag]

    return {edge: formatter(edge) for edge in self.diagram.edges()}
node_colors ¤
node_colors()

The color of every node.

Returns:

  • colors

    A mapping of nodes to colors.

Source code in src/compas_cem/viewers/scene_objects.py
def node_colors(self):
    """
    The color of every node.

    Returns
    -------
    colors :
        A mapping of nodes to colors.
    """
    raise NotImplementedError
node_textlabel_formatters ¤
node_textlabel_formatters()

The supported node label tags and the formatter of each.

Source code in src/compas_cem/viewers/scene_objects.py
def node_textlabel_formatters(self):
    """
    The supported node label tags and the formatter of each.
    """
    precision = self.float_precision
    diagram = self.diagram

    def gkey_format(node):
        return TOL.geometric_key(diagram.node_coordinates(node), precision)

    def key_gkey_format(node):
        return "{}\n{}".format(node, gkey_format(node))

    def type_format(node):
        return "{}".format(diagram.node_attribute(node, "type"))

    return {
        "xyz": gkey_format,
        "keyxyz": key_gkey_format,
        "type": type_format,
    }
node_textlabels ¤
node_textlabels(tag)

Build the labels to draw on the nodes.

Parameters:

  • tag

    A tag naming what to label the nodes with, or a mapping of nodes to labels, which is returned unchanged.

Returns:

  • labels

    A mapping of nodes to labels, or None if the tag is unsupported.

Source code in src/compas_cem/viewers/scene_objects.py
def node_textlabels(self, tag):
    """
    Build the labels to draw on the nodes.

    Parameters
    ----------
    tag :
        A tag naming what to label the nodes with, or a mapping of nodes to
        labels, which is returned unchanged.

    Returns
    -------
    labels :
        A mapping of nodes to labels, or `None` if the tag is unsupported.
    """
    if tag is None or isinstance(tag, dict):
        return tag

    formatters = self.node_textlabel_formatters()
    if tag not in formatters:
        return None

    formatter = formatters[tag]

    return {node: formatter(node) for node in self.diagram.nodes()}

FormDiagramObject ¤

FormDiagramObject(
    nodetext=None,
    edgetext=None,
    loadscale=1.0,
    loadtol=0.001,
    residualscale=1.0,
    residualtol=0.001,
    show_loads=True,
    show_residuals=True,
    show_nodetext=False,
    show_edgetext=False,
    textsize=50,
    textcolor=None,
    **kwargs,
)

A scene object that draws a form diagram in a viewer.

Source code in src/compas_cem/viewers/scene_objects.py
def __init__(
    self,
    nodetext=None,
    edgetext=None,
    loadscale=1.0,
    loadtol=1e-3,
    residualscale=1.0,
    residualtol=1e-3,
    show_loads=True,
    show_residuals=True,
    show_nodetext=False,
    show_edgetext=False,
    textsize=50,
    textcolor=None,
    **kwargs,
):
    super(DiagramObject, self).__init__(**kwargs)

    self.load_scale = loadscale
    self.load_tol = loadtol
    self.residual_scale = residualscale
    self.residual_tol = residualtol

    self.show_loads = show_loads
    self.show_residuals = show_residuals
    self.show_nodetext = show_nodetext
    self.show_edgetext = show_edgetext

    self.textsize = textsize
    self.textcolor = textcolor or Color.black()

    self._nodetext_tag = nodetext
    self._edgetext_tag = edgetext

Attributes¤

form property ¤
form

The form diagram this object draws.

Methods:¤

edge_colors ¤
edge_colors()

Color the edges by whether they are in tension or in compression.

Source code in src/compas_cem/viewers/scene_objects.py
def edge_colors(self):
    """
    Color the edges by whether they are in tension or in compression.
    """
    form = self.form
    colors = {}

    for edge in form.edges():
        force = form.edge_force(edge)
        if force >= 0.0:
            colors[edge] = self.edgecolor_tension
        else:
            colors[edge] = self.edgecolor_compression

    return colors
node_colors ¤
node_colors()

Color the support nodes apart from the rest.

Source code in src/compas_cem/viewers/scene_objects.py
def node_colors(self):
    """
    Color the support nodes apart from the rest.
    """
    form = self.form

    return {
        node: (
            self.support_nodecolor
            if form.is_node_support(node)
            else self.default_nodecolor
        )
        for node in form.nodes()
    }

TopologyDiagramObject ¤

TopologyDiagramObject(
    nodetext=None,
    edgetext=None,
    loadscale=1.0,
    loadtol=0.001,
    residualscale=1.0,
    residualtol=0.001,
    show_loads=True,
    show_residuals=True,
    show_nodetext=False,
    show_edgetext=False,
    textsize=50,
    textcolor=None,
    **kwargs,
)

A scene object that draws a topology diagram in a viewer.

Source code in src/compas_cem/viewers/scene_objects.py
def __init__(
    self,
    nodetext=None,
    edgetext=None,
    loadscale=1.0,
    loadtol=1e-3,
    residualscale=1.0,
    residualtol=1e-3,
    show_loads=True,
    show_residuals=True,
    show_nodetext=False,
    show_edgetext=False,
    textsize=50,
    textcolor=None,
    **kwargs,
):
    super(DiagramObject, self).__init__(**kwargs)

    self.load_scale = loadscale
    self.load_tol = loadtol
    self.residual_scale = residualscale
    self.residual_tol = residualtol

    self.show_loads = show_loads
    self.show_residuals = show_residuals
    self.show_nodetext = show_nodetext
    self.show_edgetext = show_edgetext

    self.textsize = textsize
    self.textcolor = textcolor or Color.black()

    self._nodetext_tag = nodetext
    self._edgetext_tag = edgetext

Attributes¤

topology property ¤
topology

The topology diagram this object draws.

Methods:¤

edge_colors ¤
edge_colors()

Color the edges by their type.

Notes

Direct and indirect deviation edges are told apart only once the trails have been built, because the distinction is drawn from the sequence the two end nodes belong to.

Source code in src/compas_cem/viewers/scene_objects.py
def edge_colors(self):
    """
    Color the edges by their type.

    Notes
    -----
    Direct and indirect deviation edges are told apart only once the trails
    have been built, because the distinction is drawn from the sequence the
    two end nodes belong to.
    """
    topology = self.topology
    colors = {}

    for edge in topology.edges():
        if topology.is_auxiliary_trail_edge(edge):
            colors[edge] = self.edgecolor_auxiliary
        elif topology.is_trail_edge(edge):
            colors[edge] = self.edgecolor_trail
        elif topology.has_trails() and topology.is_indirect_deviation_edge(edge):
            colors[edge] = self.edgecolor_deviation_indirect
        else:
            colors[edge] = self.edgecolor_deviation

    return colors
edge_textlabel_formatters ¤
edge_textlabel_formatters()

The supported edge label tags and the formatter of each.

Source code in src/compas_cem/viewers/scene_objects.py
def edge_textlabel_formatters(self):
    """
    The supported edge label tags and the formatter of each.
    """
    formatters = super(TopologyDiagramObject, self).edge_textlabel_formatters()
    precision = self.float_precision
    topology = self.topology

    def state_format(edge):
        if topology.is_trail_edge(edge):
            parameter = topology.edge_length_2(edge)
        else:
            parameter = topology.edge_force(edge)
        return "{0:.{1}}".format(copysign(1.00, parameter), precision)

    def type_format(edge):
        return "{}".format(topology.edge_attribute(edge, "type"))

    formatters.update({"state": state_format, "type": type_format})

    return formatters
node_colors ¤
node_colors()

Color the support and the origin nodes apart from the rest.

Source code in src/compas_cem/viewers/scene_objects.py
def node_colors(self):
    """
    Color the support and the origin nodes apart from the rest.
    """
    topology = self.topology
    colors = {}

    for node in topology.nodes():
        if topology.is_node_support(node):
            colors[node] = self.support_nodecolor
        elif topology.is_node_origin(node):
            colors[node] = self.origin_nodecolor
        else:
            colors[node] = self.default_nodecolor

    return colors

Viewer ¤

Viewer(*args, **kwargs)

A thin wrapper on the compas_viewer.Viewer.

This object exists only for API consistency with compas_cem.plotters.Plotter.

Source code in src/compas_cem/viewers/viewer.py
def __init__(self, *args, **kwargs):
    super(Viewer, self).__init__(*args, **kwargs)