Skip to content

compas_timber.panel_features ¤

Classes¤

InterfaceRole ¤

Enumeration of the possible interface roles.

Attributes:

  • MAIN (literal(MAIN)) –

    The interface is the main interface.

  • CROSS (literal(CROSS)) –

    The interface is the cross interface.

  • NONE (literal(NONE)) –

    The interface has no specific role. E.g. when a miter joint is used.

Opening ¤

Opening(frame, outline_a, outline_b, opening_type=None, name='Opening', **kwargs)
Source code in src/compas_timber/panel_features/opening.py
def __init__(self, frame, outline_a, outline_b, opening_type=None, name="Opening", **kwargs):
    super(Opening, self).__init__(frame=frame, name=name, **kwargs)
    self._outline_a = outline_a
    self._outline_b = outline_b
    self.opening_type = opening_type or OpeningType.WINDOW
    self._shape = None

Methods:¤

apply ¤
apply(panel_geometry, panel)

Applies the opening to the given panel geometry.

Parameters:

  • panel_geometry (:class:`compas.geometry.Brep`) –

    The geometry of the panel to which the opening will be applied.

  • panel (:class:`compas_timber.elements.Panel`) –

    The panel element.

Returns:

  • class:`compas.geometry.Brep` –

    The modified panel geometry with the opening applied.

Raises:

  • :class:`compas_timber.errors.FeatureApplicationError` –

    If the opening cannot be applied to the panel geometry.

Source code in src/compas_timber/panel_features/opening.py
def apply(self, panel_geometry, panel):
    """Applies the opening to the given panel geometry.

    Parameters
    ----------
    panel_geometry : :class:`compas.geometry.Brep`
        The geometry of the panel to which the opening will be applied.
    panel : :class:`compas_timber.elements.Panel`
        The panel element.

    Returns
    -------
    :class:`compas.geometry.Brep`
        The modified panel geometry with the opening applied.

    Raises
    ------
    :class:`compas_timber.errors.FeatureApplicationError`
        If the opening cannot be applied to the panel geometry.

    """
    try:
        return brep_difference_first(panel_geometry, self.shape.transformed(self.transformation))
    except Exception as e:
        raise FeatureApplicationError(panel_geometry, self.shape, f"Failed to apply opening to panel geometry: {e}")
from_outline_panel classmethod ¤
from_outline_panel(
    outline, panel, opening_type=None, project_horizontal=False, name=None
)

Creates an opening from a single outline and a panel.

The outline defined locally relative to the panel frame. The outline is projected onto the outline_a side of the panel.

Parameters:

  • outline (:class:`compas.geometry.Polyline`) –

    The outline of the opening.

  • panel (:class:`compas_timber.elements.Panel`) –

    The panel in which the opening is located.

  • name (str, default: None ) –

    The name of the opening.

Returns:

  • class:`Opening` –

    The created opening.

Source code in src/compas_timber/panel_features/opening.py
@classmethod
def from_outline_panel(cls, outline, panel, opening_type=None, project_horizontal=False, name=None):
    """Creates an opening from a single outline and a panel.

    The outline defined locally relative to the panel frame. The outline is projected
    onto the outline_a side of the panel.

    Parameters
    ----------
    outline : :class:`compas.geometry.Polyline`
        The outline of the opening.
    panel : :class:`compas_timber.elements.Panel`
        The panel in which the opening is located.
    name : str, optional
        The name of the opening.

    Returns
    -------
    :class:`Opening`
        The created opening.
    """
    # project outline onto top and bottom faces of panel
    outline.transform(panel.modeltransformation.inverse())
    box = Box.from_points(outline.points)
    frame = Frame(box.points[0], Vector(1, 0, 0), Vector(0, 1, 0))
    pts_a = []
    pts_b = []
    if project_horizontal:
        vector = Vector(panel.frame.normal[0], panel.frame.normal[1], 0).transformed(panel.modeltransformation.inverse())
        for pt in outline.points:
            line = Line.from_point_and_vector(pt, vector)
            intersection_a = intersection_line_plane(line, Plane.worldXY())
            if intersection_a:
                pts_a.append(intersection_a)
            else:
                raise ValueError("Could not project opening outline point onto panel inner plane.")
            intersection_b = intersection_line_plane(line, Plane(Point(0, 0, panel.thickness), Vector(0, 0, 1)))
            if intersection_b:
                pts_b.append(intersection_b)
            else:
                raise ValueError("Could not project opening outline point onto panel outer plane.")
    else:
        for pt in outline.points:
            pts_a.append(Point(pt[0], pt[1], 0))  # project to panel.planes[0]/panel.outline_a
            pts_b.append(Point(pt[0], pt[1], panel.thickness))
    pl_a = Polyline(pts_a).transformed(Transformation.from_frame(frame).inverse())
    pl_b = Polyline(pts_b).transformed(Transformation.from_frame(frame).inverse())
    return cls(frame, pl_a, pl_b, opening_type=opening_type, name=name)

OpeningType ¤

Constants for different types of openings in panels.

Attributes:

  • DOOR (str) –

    Constant for door openings.

  • WINDOW (str) –

    Constant for window openings.

PanelConnectionInterface ¤

PanelConnectionInterface(
    polyline: Polyline,
    frame: Frame,
    edge_index: int | None,
    interface_role: InterfaceRole = NONE,
    name="PanelConnectionInterface",
    **kwargs,
)
Source code in src/compas_timber/panel_features/panel_connection_interface.py
def __init__(
    self,
    polyline: Polyline,
    frame: Frame,
    edge_index: Optional[int],
    interface_role: InterfaceRole = InterfaceRole.NONE,
    name="PanelConnectionInterface",
    **kwargs,
):
    super(PanelConnectionInterface, self).__init__(frame=frame, panel_feature_type=PanelFeatureType.CONNECTION_INTERFACE, name=name, **kwargs)
    self._polyline = polyline
    self.edge_index = edge_index  # index of the edge in the plate outline where the interface is located
    self.interface_role = interface_role if interface_role else InterfaceRole.NONE

Attributes¤

polyline property ¤
polyline: Polyline

Returns the interface polyline in the coordinates of the containing Panel.

width property ¤
width: float

Returns the width of the interface polyline.

Methods:¤

as_plane ¤
as_plane() -> Plane

Returns the interface as a plane.

Source code in src/compas_timber/panel_features/panel_connection_interface.py
def as_plane(self) -> Plane:
    """Returns the interface as a plane."""
    return Plane.from_frame(self.frame)

PanelFeature ¤

PanelFeature(frame: Frame, panel_feature_type: PanelFeatureType | str = NONE, **kwargs)
Source code in src/compas_timber/panel_features/panel_features.py
def __init__(self, frame: Frame, panel_feature_type: Union[PanelFeatureType, str] = PanelFeatureType.NONE, **kwargs) -> None:
    super(PanelFeature, self).__init__(transformation=Transformation.from_frame(frame), **kwargs)
    self.panel_feature_type = panel_feature_type

Attributes¤

geometry property ¤
geometry: Geometry

The geometry of the element in the model's global coordinates.

Methods:¤

apply ¤
apply(geometry: Brep, panel: Panel) -> Brep

Apply the panel feature to the panel geometry.

Source code in src/compas_timber/panel_features/panel_features.py
def apply(self, geometry: Brep, panel: Panel) -> Brep:
    """Apply the panel feature to the panel geometry."""
    return geometry
compute_modelgeometry ¤
compute_modelgeometry() -> Geometry

Same as parent but handles standalone elements.

Source code in src/compas_timber/panel_features/panel_features.py
def compute_modelgeometry(self) -> Geometry:
    """Same as parent but handles standalone elements."""
    if not self.model:
        return self.elementgeometry.transformed(self.transformation)  # type: ignore
    return super().compute_modelgeometry()  # type: ignore
compute_modeltransformation ¤
compute_modeltransformation() -> Transformation

Same as parent but handles standalone elements.

Source code in src/compas_timber/panel_features/panel_features.py
def compute_modeltransformation(self) -> Transformation:
    """Same as parent but handles standalone elements."""
    if not self.model:
        assert self.transformation is not None
        return self.transformation
    return super().compute_modeltransformation()  # type: ignore