Skip to content

datastructures¤

Mesh data structures for quad meshes, coarse layouts and pseudo-quads, with the strip grammar, smoothing and colouring that act on them.

Classes¤

Mesh ¤

Mesh(*args: Any, **kwargs: Any)

Methods:¤

__from_data__ classmethod ¤
__from_data__(data: dict) -> Any

Decode a mesh, repairing digit-string strip and polyedge keys back into ints.

boundaries ¤
boundaries() -> list[list[int]]

Collect the mesh boundaries as lists of vertices.

Returns:

  • boundaries ( list ) –

    List of boundaries as lists of vertex keys.

boundary_kinks ¤
boundary_kinks(threshold_angle: float) -> list[int]

Return the boundary vertices with kinks.

Parameters:

  • threshold_angle (float) –

    Threshold angle in rad.

Returns:

  • list –

    The list of the boundary vertices at kink angles higher than the threshold value.

is_boundary_vertex_kink ¤
is_boundary_vertex_kink(vkey: int, threshold_angle: float) -> bool

Return whether there is a kink at a boundary vertex according to a threshold angle.

Parameters:

  • vkey (Key) –

    The boundary vertex key.

  • threshold_angle (float) –

    Threshold angle in rad.

Returns:

  • bool –

    True if vertex is on the boundary and has an angle larger than the threshold angle. False otherwise.

load_from_json classmethod ¤
load_from_json(filepath: str, default: Any = None) -> Any

Construct a mesh from what save_to_json wrote; the class comes from the file.

Digit-string strip keys are turned back into ints.

Parameters:

  • filepath (str) –
  • default (optional, default: None ) –

    Returned when the file does not exist, instead of raising. For a caller resuming from a cache that may not have been written yet.

Returns:

  • Mesh –

    Of whatever class the file names.

Raises:

  • TypeError –

    From Data.from_json, if the file holds a mesh that is not an instance of cls.

save_to_json ¤
save_to_json(filepath: str, pretty: bool = False) -> str

Write the mesh and its attributes to filepath, creating the folder. Returns filepath.

Parameters:

  • filepath (str) –
  • pretty (bool, default: False ) –

    Indent the output. Roughly doubles the size; useful while debugging.

Returns:

  • str –

    filepath.

vertex_centroid ¤
vertex_centroid() -> list[float]

Calculate the centroid of the mesh vertices.

Returns:

  • list –

    The coordinates of the centroid of the mesh vertices.

QuadMesh ¤

QuadMesh(*args: Any, **kwargs: Any)

Methods:¤

add_strip ¤
add_strip(
    polyedge: list[int],
    open_strip: bool = True,
    project: Callable[[list[float]], list[float]] | None = None,
) -> tuple[int, dict[int, tuple[int, int]]]

Add a strip along polyedge. (new strip key, {old vertex: pair}).

See compas_singular.datastructures.mesh_quad.grammar.add_strip.

add_strips ¤
add_strips(
    polyedges: list[list[int]],
    open_strip: bool = True,
    project: Callable[[list[float]], list[float]] | None = None,
) -> list[int]

Add a strip along each polyedge. The new strip keys.

open_strip and project as in add_strip.

collect_polyedge ¤
collect_polyedge(
    u0: int,
    v0: int,
    both_sides: bool = True,
    oriented: bool = False,
    strict: bool = False,
) -> list[int]

Collect all the edges in the polyedge of the input edge.

Parameters:

  • u0 (int) –

    The identifier of the edge start.

  • v0 (int) –

    The identifier of the edge end.

  • both_sides (bool, default: True ) –

    Whether to walk in both directions from the seed halfedge. Default is True. With False the walk stops at the first extremity, which is what a directional tracer wants.

  • oriented (bool, default: False ) –

    Whether to return the polyedge in the direction of the seed halfedge. Default is False, which returns the reversed polyedge whenever the walk reaches an extremity on the first side, i.e. the seed direction is lost.

  • strict (bool, default: False ) –

    Passed to vertex_opposite_vertex. Default is False.

Returns:

  • polyedge ( list ) –

    The list of the vertices in polyedge.

collect_polyedges ¤
collect_polyedges(strict: bool = False) -> Iterator[tuple[int, list[int]]]

Collect the polyedges accross four-valent vertices between boundaries and/or singularities and store it in the mesh data attributes.

Parameters:

  • strict (bool, default: False ) –

    Passed to vertex_opposite_vertex. Default is False.

Returns:

  • polyedges ( list ) –

    List of quad polyedges as list of vertices.

collect_strip ¤
collect_strip(u0: int, v0: int, both_sides: bool = True) -> list[tuple[int, int]]

Returns all the edges in the strip of the input edge; a non-quad face ends it like the boundary.

Parameters:

  • u0 (int) –

    The identifier of the edge start.

  • v0 (int) –

    The identifier of the edge end.

  • both_sides (bool, default: True ) –

    Whether to walk in both directions from the seed halfedge. Default is True. With False the walk stops at the first extremity.

Returns:

  • strip ( list ) –

    The list of the edges in strip.

collect_strips ¤
collect_strips() -> Iterator[tuple[int, list[tuple[int, int]]]]

Collect the strip data and store it in the mesh data attributes.

Returns:

  • strips ( dict ) –

    The strip data.

delete_face_in_strips ¤
delete_face_in_strips(fkey: int) -> None

Delete face in strips.

Parameters:

  • fkey (int) –

    The face to remove from every strip.

delete_strip ¤
delete_strip(skey: int) -> dict[int, int]

Delete the strip skey, welding its sides. {old vertex: the vertex it merged into}.

See compas_singular.datastructures.mesh_quad.grammar.delete_strip.

delete_strips ¤
delete_strips(skeys: list[int]) -> None

Delete several strips. See delete_strip.

edge_strip ¤
edge_strip(edge: tuple[int, int]) -> int | None

Return the strip of an edge.

Parameters:

  • edge (tuple) –

    An edge as two vertex keys.

Returns:

  • strip –

    The strip of the edge.

face_opposite_edge ¤
face_opposite_edge(u: int, v: int) -> tuple[int, int] | None

Returns the opposite edge in the quad face, or None on a boundary or a non-quad face.

Parameters:

  • u (int) –

    The identifier of the edge start.

  • v (int) –

    The identifier of the edge end.

Returns:

  • tuple or None –

    The opposite edge (w, x). None if (u, v) is a boundary halfedge, i.e. has no face, or if its face is not a quad.

face_strips ¤
face_strips(fkey: int) -> list[int | None]

Return the two strips of a face.

Parameters:

  • fkey (hashable) –

Returns:

  • list –

    The two strips of the face.

is_polyedge_closed ¤
is_polyedge_closed(pkey: int) -> bool

Output whether a polyedge is closed.

Parameters:

  • pkey (hashable) –

    A strip key.

Returns:

  • bool –

    True if the polyedge is closed. False otherwise.

is_strip_closed ¤
is_strip_closed(skey: int) -> bool

Output whether a strip is closed.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • bool –

    True if the strip is closed. False otherwise.

is_strip_face ¤
is_strip_face(fkey: int) -> bool

Whether a strip can cross this face: it has four sides.

is_vertex_singular ¤
is_vertex_singular(vkey: int) -> bool

Output whether a vertex is quad mesh singularity.

Parameters:

  • vkey (int) –

    The vertex key.

Returns:

  • bool –

    True if the vertex is a quad mesh singularity. False otherwise.

number_of_polyedges ¤
number_of_polyedges() -> int

Count the number of polyedges in the mesh.

number_of_strips ¤
number_of_strips() -> int

Count the number of strips in the mesh.

polyedge_edges ¤
polyedge_edges(pkey: int) -> list[tuple[int, int]]

Return the edges of a polyedge.

Parameters:

  • pkey (hashable) –

    A polyedge key.

Returns:

  • list –

    The edges of the polyedge, as pairs of vertex keys.

polyedge_graph ¤
polyedge_graph(
    legacy: bool = True,
) -> tuple[dict[int, list[float]], list[tuple[int, int]]]

Compute the vertices and edges of the graph representing the polyedge connectivity, where each graph vertex is a mesh polyedge and each graph edge a non-compas_singular mesh vertex representing the crossing of two polyedges. Polyedges connected by their extremities, which are singularities, do not count as overlapping.

Parameters:

  • legacy (bool, default: True ) –

    Use the historical implementation, about half of whose edges are self-loops. Default is True; False gives one edge per crossing.

Returns:

  • tuple –

    A tuple of two objects, the dictionary of mesh polyedge indices pointing to their centroid coordinates, and the list of edges between graph vertices.

polyedge_length ¤
polyedge_length(pkey: int) -> float

Return the length of a polyedge.

Parameters:

  • pkey (hashable) –

    A polyedge key.

Returns:

  • float –

    The sum of the lengths of the edges of the polyedge.

polyedge_midpoint ¤
polyedge_midpoint(pkey: int) -> Point

Return the point at mid-length of a polyedge.

Parameters:

  • pkey (hashable) –

    A polyedge key.

Returns:

  • Point –

    The midpoint.

polyedge_vertices ¤
polyedge_vertices(pkey: int) -> list[int]

Return the vertices of a polyedge.

Parameters:

  • pkey (hashable) –

    A polyedge key.

Returns:

  • list –

    The vertices of the polyedge.

polyline ¤
polyline(pkey: int) -> list[list[float]]

Return the coordinates of the vertices of a polyedge.

Parameters:

  • pkey (hashable) –

    A polyedge key.

Returns:

  • list –

    The polyline as a list of XYZ points.

polylines ¤
polylines() -> list[list[list[float]]]

Return the polylines of the quad mesh.

Returns:

  • list –

    The polylines.

singularities ¤
singularities() -> list[int]

Returns all the singularity indices in the quad mesh.

Returns:

  • list –

    The list of vertex indices that are quad mesh singularities.

singularity_polyedge_decomposition ¤
singularity_polyedge_decomposition(strict: bool = False) -> list[list[int]]

Returns a quad patch decomposition of the mesh based on the singularity polyedges, including boundaries and additionnal splits on the boundaries.

Parameters:

  • strict (bool, default: False ) –

    Passed to vertex_opposite_vertex. Default is False.

Returns:

  • list –

    The polyedges forming the decomposition.

singularity_polyedges ¤
singularity_polyedges() -> list[list[int]]

Collect the polyedges connected to singularities.

Returns:

  • list –

    The polyedges connected to singularities.

singularity_polyline_decomposition ¤
singularity_polyline_decomposition() -> list[list[list[float]]]

Return the polylines forming a quad patch decomposition of the mesh.

Returns:

  • list –

    The polylines connected to singularities.

singularity_polylines ¤
singularity_polylines() -> list[list[list[float]]]

Return the polylines connected to singularities.

Returns:

  • list –

    The polylines connected to singularities.

strip_edge_midpoint_polyline ¤
strip_edge_midpoint_polyline(skey: int) -> list[Point]

Return the strip polyline connecting edge midpoints.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • list –

    The edge midpoint polyline.

strip_edges ¤
strip_edges(skey: int) -> list[tuple[int, int]]

Return the edges of a strip.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • list –

    The edges of the strip.

strip_face_centroid_polyline ¤
strip_face_centroid_polyline(skey: int) -> list[Point]

Return the strip polyline connecting face centroids.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • list –

    The face centroid polyline.

strip_faces ¤
strip_faces(skey: int) -> list[int]

Return the faces of a strip.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • list –

    The faces of the strip.

strip_graph ¤
strip_graph() -> tuple[dict[int, list[float]], list[tuple[int | None, int | None]]]

Compute the vertices and edges of the graph representing the strip connectivity, where each graph vertex is a mesh strip and each graph edge a mesh face representing the crossing of two strips. Potentially includes loop edges (u, u) or multiple arallel edges (u, v) and/or (v, u).

Returns:

  • tuple –

    A tuple of two objects, the dictionary of mesh strip keys pointing to graph vertex coordinates, and the list of edges between graph vertices.

strip_side_polyedges ¤
strip_side_polyedges(skey: int) -> tuple[list[int], list[int]]

Return the two side polyedges of a strip.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • tuple –

    The pair of polyedges on the side of the strip.

strip_side_polylines ¤
strip_side_polylines(skey: int) -> tuple[list[list[float]], list[list[float]]]

Return the two side polylines of a strip.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • tuple –

    The pair of polylines on the side of the strip.

substitute_vertex_in_strips ¤
substitute_vertex_in_strips(
    old_vkey: int, new_vkey: int, strips: list[int] | None = None
) -> None

Substitute a vertex by another one.

Parameters:

  • old_vkey (hashable) –

    The old vertex key.

  • new_vkey (hashable) –

    The new vertex key.

  • strips (list, default: None ) –

    List of specific strip keys. Per default None, i.e. all.

vertex_opposite_vertex ¤
vertex_opposite_vertex(u: int, v: int, strict: bool = False) -> int | None

Returns the opposite vertex to u accross vertex v.

Parameters:

  • u (hashable) –

    A vertex key.

  • v (hashable) –

    A vertex key.

  • strict (bool, default: False ) –

    Decide the crossing on edges rather than vertices. Default is False, the historical behaviour; switching it changes decompositions.

Returns:

  • (hashable, None) –

    The opposite vertex. None if v is a singularity or if (u, v) leads outwards.

vertex_topo_index ¤
vertex_topo_index(vkey: int) -> float

Compute vertex index.

Parameters:

  • vkey (int) –

    The vertex key.

Returns:

  • int –

    Vertex index.

CoarseQuadMesh ¤

CoarseQuadMesh(*args: Any, **kwargs: Any)

Attributes¤

__data__ property ¤
__data__: dict[str, Any]

Everything but the derived dense meshes this layout last produced.

Methods:¤

coarse_edge_dense_edges ¤
coarse_edge_dense_edges(u: int, v: int) -> list[int]

Return the child edges, or polyedge, in the dense quad mesh from a parent edge in the coarse quad mesh.

densification ¤
densification(
    boundary_curvature: bool = True,
    skeleton_curvature: bool = True,
    overwrite_edges_to_curves: dict[tuple[int, int], list[list[float]]] | None = None,
    field: Any = None,
) -> QuadMesh

Generate a denser quad mesh from the coarse quad mesh and its strip densities.

Parameters:

  • boundary_curvature (bool, default: True ) –

    Use the shape edges_to_curves has stored for edges on the layout's own boundary, instead of chording them. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given.

  • skeleton_curvature (bool, default: True ) –

    Same, for the edges that are NOT on the boundary -- the interior edges a skeleton or field decomposition traced as separatrices. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given.

  • overwrite_edges_to_curves (dict, default: None ) –

    A dictionary with edges (u, v) pointing to a curve for densification, overriding whatever edges_to_curves has stored -- for every edge, regardless of boundary_curvature / skeleton_curvature. The curves are lists of XYZ points.

  • field (optional, default: None ) –

    A CrossField to steer patch interiors; boundaries stay fixed. Any layout on the same walls works, including a skeleton one.

Returns:

  • QuadMesh –

    The dense mesh, also stored on this one -- get_quad_mesh().

edges_to_curves ¤
edges_to_curves() -> dict[tuple[int, int], list[list[float]]]

{(u, v): polyline}: the stored shape of every coarse edge that has one, one direction per edge.

Returns:

  • dict[tuple[int, int], list[[x, y, z]]] –

    Keyed one way round per edge. densification looks up (v, u) and reverses when (u, v) is absent, so both directions are covered.

from_quad_mesh classmethod ¤
from_quad_mesh(
    quad_mesh: QuadMesh,
    collect_strips: bool = True,
    collect_polyedges: bool = True,
    attribute_density: bool = True,
    strict: bool = False,
) -> "CoarseQuadMesh"

Build coarse quad mesh from quad mesh with density and child-parent element data.

Parameters:

  • quad_mesh (QuadMesh) –

    A quad mesh.

  • attribute_density (bool, default: True ) –

    Keep density data of dense quad mesh and inherit it as aatribute.

  • strict (bool, default: False ) –

    Passed to QuadMesh.singularity_polyedge_decomposition. Default is False. Setting it to True changes the resulting coarse layout.

Returns:

  • coarse_quad_mesh ( CoarseQuadMesh ) –

    A coarse quad mesh with density data.

get_strip_densities ¤
get_strip_densities() -> dict[int, int]

Get the density of a strip.

Returns:

  • dict –

    The dictionary of the strip densities.

get_strip_density ¤
get_strip_density(skey: int) -> int

Get the density of a strip.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • int –

    The strip density.

has_densities ¤
has_densities() -> bool

Whether every strip already carries a density; a partial table counts as none.

Returns:

set_edges_to_curves ¤
set_edges_to_curves(
    edges_to_curves: dict[tuple[int, int], list[list[float]]] | None,
) -> None

Remember the shape of each coarse edge, stored JSON-safe as [u, v, points]. None or {} clears it.

Parameters:

set_mesh_density_face_target ¤
set_mesh_density_face_target(nb_faces: int) -> None

Set equal strip densities based on a target number of faces.

Parameters:

  • nb_faces (int) –

    The target number of faces.

set_shape_polylines ¤
set_shape_polylines(polylines: list[list[list[float]]] | None) -> None

Remember the polylines the edges take their shape from. None clears them.

set_strip_density ¤
set_strip_density(skey: int, d: int) -> None

Set the densty of one strip.

Parameters:

  • skey (hashable) –

    A strip key.

  • d (int) –

    A density parameter.

set_strip_density_func ¤
set_strip_density_func(skey: int, func: Callable, func_args: Any) -> None

Set the strip densities based on a function.

Parameters:

  • skey (hashable) –

    A strip key.

set_strip_density_target ¤
set_strip_density_target(skey: int, t: float) -> None

Set the strip densities based on a target length and the average length of the strip edges.

Parameters:

  • skey (hashable) –

    A strip key.

  • t (float) –

    A target length.

set_strips_density ¤
set_strips_density(d: int, skeys: list[int] | None = None) -> None

Set the same density to all strips.

Parameters:

  • d (int) –

    A density parameter.

  • skeys ((list, None), default: None ) –

    The keys of strips to set density. If is None, all strips are considered.

set_strips_density_func ¤
set_strips_density_func(
    func: Callable, func_args: Any, skeys: list[int] | None = None
) -> None

Set the strip densities based on a function.

Parameters:

  • skeys ((list, None), default: None ) –

    The keys of strips to set density. If is None, all strips are considered.

set_strips_density_target ¤
set_strips_density_target(t: float, skeys: list[int] | None = None) -> None

Set the strip densities based on a target length and the average length of the strip edges.

Parameters:

  • t (float) –

    A target length.

  • skeys ((list, None), default: None ) –

    The keys of strips to set density. If is None, all strips are considered.

shape_polylines ¤
shape_polylines() -> list[list[list[float]]]

The polylines the coarse edges take their shape from (separatrices, branches, drawn curves). [] if none.

PseudoQuadMesh ¤

PseudoQuadMesh(*args: Any, **kwargs: Any)

Methods:¤

collect_strip ¤
collect_strip(u0: int, v0: int) -> list[tuple[int, int]]

Returns all the edges in the strip of the input edge.

Parameters:

  • u0 (int) –

    The identifier of the edge start.

  • v0 (int) –

    The identifier of the edge end.

Returns:

  • strip ( list ) –

    The list of the edges in strip.

collect_strips ¤
collect_strips() -> Iterator[tuple[int, list[tuple[int, int]]]]

Collect the strip data.

Returns:

  • strip ( int ) –

    The number of strips.

delete_face_in_strips ¤
delete_face_in_strips(fkey: int) -> None

Delete face in strips.

Parameters:

  • fkey (int) –

    The face to remove from every strip.

face_opposite_edge ¤
face_opposite_edge(u: int, v: int) -> tuple[int, int] | None

Returns the opposite edge in the quad face.

Parameters:

  • u (int) –

    The identifier of the edge start.

  • v (int) –

    The identifier of the edge end.

Returns:

  • (w, x) : tuple –

    The opposite edge. None on the boundary, and for a face a strip cannot cross -- see is_strip_face.

face_strips ¤
face_strips(fkey: int) -> list[int]

Return the two strips of a face.

Parameters:

  • fkey (hashable) –

Returns:

  • list –

    The two strips of the face.

is_strip_closed ¤
is_strip_closed(skey: int) -> bool

Output whether a strip is closed.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • bool –

    True if the strip is closed. False otherwise.

is_strip_face ¤
is_strip_face(fkey: int) -> bool

A quad, or a triangle registered as a pseudo-quad in face_pole.

is_vertex_singular ¤
is_vertex_singular(vkey: int) -> bool

Output whether a vertex is quad mesh singularity.

Parameters:

  • vkey (int) –

    The vertex key.

Returns:

  • bool –

    True if the vertex is a quad mesh singularity. False otherwise.

singularity_polyedges ¤
singularity_polyedges() -> list[list[int]]

Collect the polyedges connected to singularities.

Returns:

  • list –

    The polyedges connected to singularities.

strip_faces ¤
strip_faces(skey: int) -> list[int]

Return the faces of a strip.

Parameters:

  • skey (hashable) –

    A strip key.

Returns:

  • list –

    The faces of the strip.

vertex_topo_index ¤
vertex_topo_index(vkey: int) -> float

Compute vertex index.

Parameters:

  • vkey (int) –

    The vertex key.

Returns:

  • int –

    Vertex index.

CoarsePseudoQuadMesh ¤

CoarsePseudoQuadMesh(*args: Any, **kwargs: Any)

Methods:¤

densification ¤
densification(
    boundary_curvature: bool = True,
    skeleton_curvature: bool = True,
    overwrite_edges_to_curves: dict[tuple[int, int], list[list[float]]] | None = None,
    field: Any = None,
) -> "QuadMesh"

Generate a denser quad mesh from the coarse quad mesh and its strip densities.

Parameters:

  • boundary_curvature (bool, default: True ) –

    Use the stored edges_to_curves shape for edges on the layout's own boundary. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given.

  • skeleton_curvature (bool, default: True ) –

    Same, for the interior edges. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given.

  • overwrite_edges_to_curves (dict, default: None ) –

    A dictionary with edges (u, v) pointing to a curve for densification, overriding whatever edges_to_curves has stored -- for every edge. The curves are lists of XYZ points.

  • field (optional, default: None ) –

    A CrossField (from FieldDecomposition.get_field() or CrossField.from_boundary(...)). With it, each patch INTERIOR is integrated from the field instead of blended from its own four sides -- which is the only way a guide curve reaches a patch it forced no topology in. The layout does not have to have come from that field: a skeleton layout and a field solved on the same walls work together. Boundaries stay fixed either way, so the result still welds into a mesh whose strips can be collected and edited.

Returns:

  • QuadMesh –

    The dense mesh, also stored on this one -- get_quad_mesh().

densify ¤
densify(
    pattern_overwrite: "str | dict[int, str] | None" = None,
    boundary_curvature: bool = True,
    skeleton_curvature: bool = True,
    overwrite_edges_to_curves: dict[tuple[int, int], list[list[float]]] | None = None,
    field: Any = None,
) -> "QuadMesh"

Build one dense patch per coarse face from the pattern's template and weld them together.

Parameters:

  • pattern_overwrite (str or dict, default: None ) –

    A key of PATTERNS for every face, or a dict of face to key.

  • boundary_curvature (bool, default: True ) –

    Use the stored edges_to_curves shape for edges on the layout's own boundary. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given.

  • skeleton_curvature (bool, default: True ) –

    Same, for the interior edges. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given.

  • overwrite_edges_to_curves (dict, default: None ) –

    Overrides whatever edges_to_curves has stored, for every edge.

  • field (optional, default: None ) –

Returns:

  • QuadMesh –
from_coarse_polylines classmethod ¤
from_coarse_polylines(
    polylines: list[list[list[float]]],
    poles: list[list[float]] | None = None,
    holes: list[list[float]] | None = None,
    precision: int | None = None,
    tol: float | None = None,
    collect_strips: bool = True,
) -> "CoarsePseudoQuadMesh"

A coarse quad layout from a drawn network with one polyline per coarse edge.

Validates rather than repairs; triangular patches become pseudo-quads.

Parameters:

  • polylines (list[list[[x, y, z]]]) –

    One polyline per coarse edge. A straight edge is two points.

  • poles (list[[x, y, z]], default: None ) –

    Preferred pole positions. A triangular patch is a pseudo-quad with or without one; a position given here decides which corner collapses.

  • holes (list[[x, y, z]], default: None ) –

    One point inside each hole of the domain. A hole is a bounded cycle of the network and is otherwise indistinguishable from a patch, so without this it is filled.

  • precision (int, default: None ) –

    Decimals the endpoints are welded at. Default is COMPAS's own, 3.

  • tol (float, default: None ) –

    Distance below which a point is ON a curve, for the validity checks. Defaults to the weld resolution.

  • collect_strips (bool, default: True ) –

    Collect strip data before returning, as CoarseQuadMesh.from_quad_mesh does.

Returns:

  • CoarsePseudoQuadMesh –

    Carrying the drawn shape of every edge -- see CoarseQuadMesh.edges_to_curves.

Raises:

  • ValueError –

    On a network that is not a clean planar arrangement of triangular and quadrilateral patches.

quad_mesh ¤
quad_mesh(
    boundary_curvature: bool = True,
    skeleton_curvature: bool = True,
    overwrite_edges_to_curves: dict[tuple[int, int], list[list[float]]] | None = None,
    field: Any = None,
    pattern_overwrite: "str | dict[int, str] | None" = None,
) -> "QuadMesh"

Generate a dense quad mesh from this layout in a chosen pattern.

'diagonal' and 'fan' first raise densities to equal and even values per patch.

Parameters:

  • boundary_curvature (bool, default: True ) –

    Use the shape edges_to_curves has stored for edges on the layout's own boundary, instead of chording them. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given. See densify.

  • skeleton_curvature (bool, default: True ) –

    Same, for the edges that are NOT on the boundary -- the interior edges a skeleton or field decomposition traced as separatrices. Defaults to True. Ignored -- treated as True -- when overwrite_edges_to_curves is given.

  • overwrite_edges_to_curves (dict, default: None ) –

    Coarse edges (u, v) pointing to a curve to densify them along, each curve a list of XYZ points, overriding whatever edges_to_curves has stored -- for every edge, regardless of boundary_curvature / skeleton_curvature.

  • field (optional, default: None ) –

    A CrossField. Only valid with the ortho pattern -- see densification.

  • pattern_overwrite (str or dict, default: None ) –

    One of compas_singular...patterns.PATTERNS: 'ortho' (the plain grid), 'diagonal' (the grid with both patch diagonals cut through it) or 'fan' (four polar fans meeting at the centre).

Returns:

  • QuadMesh –

    The dense mesh, also stored on this one -- get_quad_mesh().

Skeleton ¤

Skeleton(*args: Any, **kwargs: Any)

Skeleton class for the generation of the topological skeleton or medial axis from a Delaunay mesh.

References
  1. Harry Blum. 1967. A transformation for extracting new descriptors of shape. Models for Perception of Speech and Visual Forms, pages 362--380. Available at http://pageperso.lif.univ-mrs.fr/~edouard.thiel/rech/1967-blum.pdf.
  2. Punam K. Saha, Gunilla Borgefors, and Gabriella Sanniti di Baja. 2016. A survey on skeletonization algorithms and their applications. Pattern Recognition Letters, volume 76, pages 3--12. Available at https://www.sciencedirect.com/science/article/abs/pii/S0167865515001233.

Methods:¤

branches ¤
branches() -> list[list[list[float]]]

Get the branch polylines of the topological skeleton as polylines connecting singular points.

Returns:

  • list –

    List of polylines as tuples of XYZ-coordinates.

from_mesh classmethod ¤
from_mesh(mesh: Mesh) -> 'Skeleton'

Construct a Skeleton object from a Mesh.

Returns:

lines ¤
lines() -> list[tuple[list[float], list[float]]]

Get the lines forming the topological skeleton, i.e. the lines connecting the circumcentres of adjacent faces.

Returns:

  • list –

    List of lines as tuples of pairs XYZ-coordinates.

real_neighbors ¤
real_neighbors(fkey: int) -> list[int]

The adjacent faces of fkey, excluding any across a curve feature.

A safeguard: with a complete topological cut it equals face_neighbors.

Returns:

singular_faces ¤
singular_faces() -> list[int]

Get the indices of the singular faces in the Delaunay mesh, i.e. the ones with three neighbours.

Returns:

  • list –

    List of face keys.

singular_points ¤
singular_points() -> list[list[float]]

Get the XYZ-coordinates of the singular points of the topological skeleton, i.e. the face circumcentre of the singular faces.

Returns:

  • list –

    List of point XYZ-coordinates.

BoundaryLoop ¤

BoundaryLoop(points: list[list[float]])

A closed domain wall, arc-length parametrised, stored doubled so an arc across the seam is a slice.

Parameters:

  • points (list[[x, y, z]]) –

    The loop, closed. A repeated closing point is dropped: the loop is stored open and closed by the doubling, so keeping it would put a zero-length segment in the middle of every arc that crosses the seam.

Methods:¤

arc ¤
arc(pa: list[float], pb: list[float]) -> list[list[float]] | None

The shorter way round the loop from pa to pb, or None.

arcs ¤
arcs(pa: list[float], pb: list[float]) -> list[list[list[float]]]

Both ways round the loop from pa to pb, shorter first.

On a hole the edge can be the longer way, so both are offered.

project ¤
project(point: list[float]) -> tuple[float, float, list[float] | None]

(distance, arclength, closest point) for a point near the loop.

Searched over ONE turn -- the second turn is the same loop and would only ever tie.

Strip grammar¤

add_strip ¤

add_strip(
    mesh: QuadMesh,
    polyedge: list[int],
    open_strip: bool = True,
    project: Callable[[list[float]], list[float]] | None = None,
) -> tuple[int, dict[int, tuple[int, int]]]

Add a strip along polyedge, opened by open_added_strip by default.

The polyedge is consumed. It may run along a wall, and pass a vertex twice (a self-crossing strip).

Parameters:

  • mesh (QuadMesh) –

    A quad mesh. attributes['strips'] must be non-empty -- update_strip_data does max(...) + 1 and raises on an empty dict.

  • polyedge (list[int]) –

    Vertex keys in order, each joined to the next by an edge. Either closed, or with both ends on the boundary or at a pole (see pole_ends).

  • open_strip (bool, default: True ) –

    Give the new strip its width with open_added_strip. Default True. False is topology only: both copies of each vertex stay on top of the vertex they replace.

  • project (callable, default: None ) –

    project(xyz) -> xyz for the new pair at a BOUNDARY vertex, e.g. back onto a curved wall. Without it they stay on the chord across the vertex. Ignored when open_strip is False.

Returns:

  • tuple[int, dict] –

    The new strip key, and {old vertex: (left copy, right copy)}. The left and right polyedges are the values of that map read in polyedge order; the pairs in it are exactly the vertices an opener has to separate. A pole end maps to (pole, pole). A vertex passed twice is split twice: the second pass splits the first pass's copies, which then key its pairs although they are no longer in the mesh.

Raises:

  • ValueError –

    With open_strip, when a face next to the strip is left folded or without area. The mesh is left edited: work on a copy.

Notes

An end at an existing pole is not copied: the strip ends there in a new pseudo-quad, as in thesis Fig. 5.15. See pole_ends.

add_strips ¤

add_strips(
    mesh: QuadMesh,
    polyedges: list[list[int]],
    open_strip: bool = True,
    project: Callable[[list[float]], list[float]] | None = None,
) -> list[int]

Add a strip along each polyedge in order, re-deriving the remaining polyedges after each insertion.

Parameters:

  • mesh (QuadMesh) –

    A quad mesh, with attributes['strips'] already collected.

  • polyedges (list[list[int]]) –

    Polyedges, each a list of vertex keys.

  • open_strip (bool, default: True ) –

    Open each new strip by open_added_strip. Default True.

  • project (callable, default: None ) –

    Passed on to open_added_strip.

Returns:

  • list –

    The new strip keys, in the order the strips were added.

split_strip ¤

split_strip(
    mesh: QuadMesh,
    skey: int,
    n: int = 2,
    open_strip: bool = True,
    project: Callable[[list[float]], list[float]] | None = None,
) -> list[int]

Refine a strip into n strips. open_strip/project as in add_strip.

Returns:

  • list –

    The existing strip key, followed by the n - 1 new ones.

split_strips ¤

split_strips(
    mesh: QuadMesh,
    skey_to_n: dict[int, int],
    open_strip: bool = True,
    project: Callable[[list[float]], list[float]] | None = None,
) -> dict[int, list[int]]

Refine several strips. open_strip/project as in add_strip.

Parameters:

  • mesh (QuadMesh) –

    A quad mesh.

  • skey_to_n (dict) –

    Strip keys pointing to the number of strips to refine each one into.

Returns:

  • dict –

    Each split strip key, pointing to the keys of the strips refining it.

open_added_strip ¤

open_added_strip(
    mesh: QuadMesh,
    old_to_new: dict[int, tuple[int, int]],
    sides: dict[int, tuple[list[int], list[int]] | None],
    on_boundary: Iterable[int] = (),
    project: Callable[[list[float]], list[float]] | None = None,
) -> int

Give a new strip its width: place each new pair at thirds of the span across the old vertex.

Only the new pairs move; boundary pairs go through project. Returns the number repositioned.

Parameters:

  • mesh (QuadMesh) –

    The mesh after a topology-only add_strip.

  • old_to_new (dict) –

    {old vertex: (copy, copy)}, the second return value of add_strip.

  • sides (dict) –

    polyedge_sides of the polyedge, measured BEFORE add_strip.

  • on_boundary (iterable, default: () ) –

    Old vertices that were on the boundary.

  • project (callable, default: None ) –

    project(xyz) -> xyz applied to the new pair at a boundary vertex.

Returns:

  • int –

    The number of pairs actually repositioned. Planar (xy): z is set to 0.

strip_polyedge_update ¤

strip_polyedge_update(
    mesh: QuadMesh,
    polyedge: list[int],
    vertex_modifications: dict[int, tuple[int, int]],
) -> list[int]

Rewrite polyedge in terms of the vertices an insertion left behind.

Parameters:

  • mesh (QuadMesh) –

    A quad mesh.

  • polyedge (list[int]) –

    A polyedge, as a list of the OLD vertex keys.

  • vertex_modifications (dict) –

    Old vertex keys pointing to the new ones that replaced them -- the second return value of add_strip.

Returns:

  • list –

    The shortest path that visits the replacements in the original order.

is_polyedge_valid_for_strip_addition ¤

is_polyedge_valid_for_strip_addition(mesh: QuadMesh, polyedge: list[int]) -> bool

polyedge_sides ¤

polyedge_sides(
    mesh: QuadMesh, polyedge: list[int]
) -> dict[int, tuple[list[int], list[int]] | None]

{vertex: (left neighbours, right neighbours)} across the polyedge, in XY.

delete_strip ¤

delete_strip(mesh: QuadMesh, skey: int) -> dict[int, int]

Delete the strip skey, welding the faces either side together.

Consumed strips go with it and face_pole is repointed; vertices move.

Parameters:

  • mesh (QuadMesh) –

    A quad mesh.

  • skey (hashable) –

    A strip key.

Returns:

  • dict –

    {old vertex: the vertex it was merged into}. Empty if there was no such strip.

delete_strips ¤

delete_strips(mesh: QuadMesh, skeys: list[int]) -> None

Delete several strips.

Strip keys are re-checked as the deletions go, because deleting one strip can delete others with it -- see collateral_strip_deletions.

collateral_strip_deletions ¤

collateral_strip_deletions(mesh: QuadMesh, skeys: list[int]) -> list[int]

The strips that deleting skeys would delete as well. Mutates nothing.

total_boundary_deletions ¤

total_boundary_deletions(mesh: QuadMesh, skeys: list[int]) -> list[list[int]]

The boundaries that deleting skeys would collapse. Mutates nothing.

strips_to_split_to_prevent_boundary_collapse ¤

strips_to_split_to_prevent_boundary_collapse(
    mesh: QuadMesh, skeys: list[int]
) -> dict[int, int] | None

What to split before deleting skeys so every boundary keeps three edges (thesis 5.3.2). Mutates nothing.

Returns:

  • dict or None –

    None if the collapse cannot be prevented, {} if nothing is at risk, else {skey: n} to refine first. Do not conflate None and {}.

Pole grammar¤

split_quad_in_pseudo_quads ¤

split_quad_in_pseudo_quads(
    mesh: "PseudoQuadMesh", fkey: int, vkey: int
) -> dict[int, int] | None

merge_pseudo_quads_in_quad ¤

merge_pseudo_quads_in_quad(
    mesh: "PseudoQuadMesh", fkey_1: int, fkey_2: int
) -> int | None

Shape grammar¤

add_opening ¤

add_opening(mesh: Mesh, fkey: int) -> list[int]

Add an opening to a mesh face.

Parameters:

  • mesh (Mesh) –

    A mesh.

  • fkey (hashable) –

    A face key.

Returns:

  • list –

    List of new vertex keys around the opening oriented towards the outside.

add_handle ¤

add_handle(mesh: QuadMesh, fkey_1: int, fkey_2: int) -> list[int]

Add a handle between two quad mesh faces.

Parameters:

  • mesh (QuadMesh) –

    A quad mesh.

  • fkey_1 (hashable) –

    A face key.

  • fkey_2 (hashable) –

    A face key.

Returns:

  • list –

    List of new face keys around the opening

Smoothing¤

constrained_smoothing ¤

constrained_smoothing(
    mesh: Mesh,
    kmax: int = 100,
    damping: float = 0.5,
    constraints: dict[int, Constraint] | None = None,
    algorithm: str | Sequence[str] = "centroid",
    fixed: Sequence[int] | None = None,
    symmetric: bool | None = None,
) -> None

Smooth a mesh in place, moving each constrained vertex back onto its constraint after every iteration.

Parameters:

  • mesh (Mesh) –

    A mesh to smooth, modified in place.

  • kmax (int, default: 100 ) –

    Number of iterations for smoothing, per algorithm. Default is 100.

  • damping (float, default: 0.5 ) –

    Damping value for smoothing between 0 and 1. Default is 0.5.

  • constraints (dict[int, Constraint], default: None ) –

    Dictionary of constraints as vertex keys pointing to COMPAS geometry (points, polylines, curves or surfaces). Empty by default. See closest_point_on_constraint for the accepted geometry.

  • algorithm (('centroid', 'area', 'centerofmass'), default: 'centroid' ) –

    Smoothing algorithm to apply. Classic centroid by default. A sequence of algorithms, such as ['area', 'centroid'], runs each in turn for kmax iterations, in the order given.

  • fixed (sequence[int], default: None ) –

    Vertices that the smoothing algorithm must not move at all. Default is None.

  • symmetric (bool, default: None ) –

    Keep a mesh made by expand_symmetrically exactly symmetric by averaging each vertex over its attributes['orbits'] every iteration. None (default) means: when the mesh has orbits.

Returns:

  • None –

    The mesh is modified in place.

Raises:

  • ValueError –

    If an algorithm is not recognised.

boundary_constrained_smoothing ¤

boundary_constrained_smoothing(
    mesh: Mesh,
    curves: Sequence[Constraint] | None = None,
    kmax: int = 100,
    damping: float = 0.5,
    algorithm: str | Sequence[str] = "centroid",
    corner_angle: float = pi / 6,
    fix_corners: bool = True,
    constraints: dict[int, Constraint] | None = None,
) -> dict[int, Constraint]

Smooth a mesh with its boundary vertices sliding along the boundary and corners fixed.

Parameters:

  • mesh (Mesh) –

    A mesh to smooth, modified in place.

  • curves (sequence, default: None ) –

    The boundary geometry to snap the boundary vertices to, as COMPAS polylines or curves. Default is None, in which case the mesh boundary polylines are used.

  • kmax (int, default: 100 ) –

    Number of iterations for smoothing, per algorithm. Default is 100.

  • damping (float, default: 0.5 ) –

    Damping value for smoothing between 0 and 1. Default is 0.5.

  • algorithm (('centroid', 'area', 'centerofmass'), default: 'centroid' ) –

    Smoothing algorithm to apply, or several to run in turn. Classic centroid by default. See constrained_smoothing.

  • corner_angle (float, default: pi / 6 ) –

    Threshold deviation angle for a boundary kink, in radians. Default is pi / 6 (30 degrees).

  • fix_corners (bool, default: True ) –

    If True, pin the boundary vertices at a kink to their current position. Default is True.

  • constraints (dict[int, Constraint], default: None ) –

    Additional constraints, as vertex keys pointing to COMPAS geometry, applied on top of the automated ones. Default is None.

Returns:

  • dict[int, Constraint] –

    The constraints that were applied, as vertex keys pointing to point, polyline or curve objects. The mesh itself is modified in place.

boundary_smoothing ¤

boundary_smoothing(
    mesh: Mesh,
    curves: Sequence[Constraint] | None = None,
    kmax: int = 100,
    damping: float = 0.5,
    algorithm: str | Sequence[str] = "area",
    corner_angle: float = pi / 6,
    fix_corners: bool = True,
) -> dict[int, Constraint]

Smooth only the boundary of a mesh, sliding its vertices along the boundary.

Unlike boundary_constrained_smoothing, every interior vertex is fixed: the boundary vertices are redistributed along the boundary and nothing else moves.

Parameters:

  • mesh (Mesh) –

    A mesh to smooth, modified in place.

  • curves (sequence, default: None ) –

    The boundary geometry to slide the boundary vertices along, as COMPAS polylines or curves. Default is None, in which case the mesh boundary polylines are used.

  • kmax (int, default: 100 ) –

    Number of iterations for smoothing, per algorithm. Default is 100.

  • damping (float, default: 0.5 ) –

    Damping value for smoothing between 0 and 1. Default is 0.5.

  • algorithm (('area', 'centroid', 'centerofmass'), default: 'area' ) –

    Smoothing algorithm to apply, or several to run in turn. Area by default. See constrained_smoothing.

  • corner_angle (float, default: pi / 6 ) –

    Threshold deviation angle for a boundary kink, in radians. Default is pi / 6 (30 degrees).

  • fix_corners (bool, default: True ) –

    If True, pin the boundary vertices at a kink to their current position. Default is True.

Returns:

  • dict[int, Constraint] –

    The constraints that were applied to the boundary vertices. The mesh itself is modified in place.

region_smoothing ¤

region_smoothing(
    mesh: Mesh,
    vertices: Sequence[int] | dict[int, float],
    kmax: int = 50,
    damping: float = 0.5,
    blend: int = 3,
    constraints: dict[int, Constraint] | None = None,
) -> dict[int, float]

Area-weighted smoothing of one region, with damping tapered to zero over blend rings.

Everything outside the region is fixed; the taper avoids a crease at its edge.

Parameters:

  • mesh (Mesh) –

    A mesh to smooth, modified in place.

  • vertices (sequence[int] | dict[int, float]) –

    The region to smooth, either as the vertex keys of its core -- which are then tapered over blend rings -- or as a ready-made dictionary of vertex keys pointing to damping weights between 0 and 1, in which case blend is ignored. A vertex that is absent, or whose weight is not positive, is fixed.

  • kmax (int, default: 50 ) –

    Number of iterations for smoothing. Default is 50, fewer than the whole-mesh functions, since a region is small and needs fewer to settle.

  • damping (float, default: 0.5 ) –

    Damping value for smoothing between 0 and 1, scaled per vertex by its weight. Default is 0.5.

  • blend (int, default: 3 ) –

    Rings of vertices outside the core over which the damping falls to zero. Default is 3. Ignored if vertices is a dictionary of weights.

  • constraints (dict[int, Constraint], default: None ) –

    Dictionary of constraints as vertex keys pointing to COMPAS geometry, applied to the vertices of the region after every iteration. Constraints on vertices outside the region are ignored, since those vertices do not move. Default is None, in which case automated_boundary_constraints is used: a region touching the boundary then slides along it instead of being dragged inward. See closest_point_on_constraint for the accepted geometry.

Returns:

  • dict[int, float] –

    The damping weights that were applied, as vertex keys pointing to a weight between 0 and 1. The mesh itself is modified in place.

relaxation ¤

relaxation(
    mesh: Mesh,
    fixed: str | Sequence[int] = "corners",
    constraints: dict[int, Constraint] | None = None,
    q_factor: float = 100.0,
) -> None

Force-density relaxation of a mesh with compas_fd, boundary edges q_factor times stiffer.

Parameters:

  • mesh (Mesh) –

    A mesh to relax, modified in place.

  • fixed (('corners', 'boundary'), default: 'corners' ) –

    The vertices that do not move: 'corners' (default) for the boundary vertices at a kink, 'boundary' for every boundary vertex, or the vertex keys themselves.

  • constraints (dict[int, Constraint], default: None ) –

    Dictionary of constraints as vertex keys pointing to geometry the vertex must stay on. A point pins the vertex there, like a fixed vertex. A polyline or a sequence of points, a compas Vector, Frame, Line, Plane, Circle, NurbsCurve or NurbsSurface, or a compas_fd Constraint lets it slide along. Constraints on fixed vertices are ignored. Default is None.

  • q_factor (float, default: 100.0 ) –

    How much larger the force density of a boundary edge is than that of an interior edge. Default is 100.

Returns:

  • None –

    The mesh is modified in place.

Raises:

  • ValueError –

    If fixed is an unrecognised string.

  • TypeError –

    If a constraint cannot be turned into a compas_fd constraint.

  • ImportError –

    If compas_fd is not installed.

automated_boundary_constraints ¤

automated_boundary_constraints(
    mesh: Mesh,
    curves: Sequence[Constraint] | None = None,
    corner_angle: float = pi / 6,
    fix_corners: bool = True,
) -> dict[int, Constraint]

Constrain every boundary vertex to the boundary curve it belongs to, pinning kinks.

Parameters:

  • mesh (Mesh) –

    The mesh to constrain.

  • curves (sequence, default: None ) –

    The boundary geometry to snap the boundary vertices to, as COMPAS polylines or curves. Each run of boundary vertices between two corners is matched to the curve it is closest to. Default is None, in which case the mesh boundary polylines are used.

  • corner_angle (float, default: pi / 6 ) –

    Threshold deviation angle for a boundary kink, in radians. Default is pi / 6 (30 degrees).

  • fix_corners (bool, default: True ) –

    If True, pin the boundary vertices at a kink to their current position. Default is True.

Returns:

  • dict[int, Constraint] –

    A dictionary of mesh constraints for smoothing, as vertex keys pointing to point, polyline or curve objects.

closest_point_on_constraint ¤

closest_point_on_constraint(
    constraint: Constraint, xyz: list[float], discretisation: int = 128
) -> list[float] | None

Project a point onto a constraint object, using COMPAS geometry only.

Parameters:

  • constraint (None | Point | [float, float, float] | Polyline | sequence[point] | Curve | Any) –

    The geometry to project onto:

    • None -- no constraint, None is returned;
    • a compas.geometry.Point or a bare [x, y, z] -- the point itself, i.e. a pin;
    • a compas.geometry.Polyline or any sequence of points -- the closest point on that polyline, via compas.geometry.closest_point_on_polyline;
    • any other compas.geometry.Curve -- a compas.geometry.Line, a compas.geometry.Circle, a curve from compas_rhino's curve_to_compas or from compas_occ -- the closest point on the curve, from its own closest_point. See _closest_point_on_curve for the curves that have none and fall back on their to_polyline discretisation;
    • any other object with a working closest_point method (a compas_singular.editing.GuideCurve, a Rhino or OCC surface, ...) -- the result of that method;
    • anything else with a to_polyline -- the closest point on that discretisation.
  • xyz ([float, float, float]) –

    The coordinates of the point to project.

  • discretisation (int, default: 128 ) –

    Number of segments used to discretise a curve that has no analytical closest point. Default is 128.

Returns:

  • list[float] | None –

    The XYZ coordinates of the closest point on the constraint, or None if the constraint is None.

Raises:

  • TypeError –

    If the closest point on the constraint cannot be computed.

mesh_boundary_loops ¤

mesh_boundary_loops(mesh: Mesh) -> list[list[int]]

Collect the boundaries of a mesh as ordered, non-repeating loops of vertices.

Parameters:

  • mesh (Mesh) –

    A mesh.

Returns:

  • list[list[int]] –

    A list of boundaries as ordered lists of vertex keys. The first vertex is not repeated at the end, the loops are implicitly closed.

mesh_boundary_polylines ¤

mesh_boundary_polylines(mesh: Mesh) -> list[Polyline]

Collect the boundaries of a mesh as closed polylines.

Parameters:

  • mesh (Mesh) –

    A mesh.

Returns:

mesh_boundary_corners ¤

mesh_boundary_corners(mesh: Mesh, corner_angle: float = pi / 6) -> list[int]

Collect the boundary vertices of a mesh that sit on a kink.

The kink is measured as the deviation from straight between the two boundary edges at the vertex: zero along a straight boundary, pi / 2 at a square corner.

Parameters:

  • mesh (Mesh) –

    A mesh.

  • corner_angle (float, default: pi / 6 ) –

    Threshold deviation angle, in radians. Default is pi / 6 (30 degrees).

Returns:

  • list[int] –

    The keys of the boundary vertices at a kink.

automated_smoothing_surface_constraints ¤

automated_smoothing_surface_constraints(
    mesh: Mesh,
    surface: Any,
    borders: Sequence[Any],
    kinks: Sequence[list[float]] | None = None,
) -> dict[int, Any]

Constrain every vertex to a surface, each boundary vertex to its nearest border, and kinks to points.

Parameters:

  • mesh (Mesh) –

    The mesh to constrain.

  • surface (Any) –

    The surface, as anything with a closest_point method.

  • borders (sequence) –

    The border curves of the surface, as polylines or curves.

  • kinks (sequence[[float, float, float]], default: None ) –

    The points along the borders where the tangent jumps.

Returns:

  • dict –

    Vertex keys pointing to the surface, a border curve or a compas.geometry.Point.

automated_smoothing_constraints ¤

automated_smoothing_constraints(
    mesh: Mesh,
    points: Sequence[list[float]] | None = None,
    curves: Sequence[Any] | None = None,
    surface: Any | None = None,
) -> dict[int, Any]

Constrain the vertices of a mesh to pins, boundary curves and a surface; pins win.

Parameters:

  • mesh (Mesh) –

    The mesh to constrain.

  • points (sequence[[float, float, float]], default: None ) –

    Each pins the mesh vertex nearest to it, anywhere in the mesh.

  • curves (sequence, default: None ) –

    Curves for the boundary vertices, as polylines or curves.

  • surface (Any, default: None ) –

    A surface -- or a mesh -- for every vertex, as anything with a closest_point method.

Returns:

  • dict –

    Vertex keys pointing to a point, curve or surface.

surface_constrained_smoothing ¤

surface_constrained_smoothing(
    mesh: Mesh,
    surface: Any,
    borders: Sequence[Any],
    kmax: int = 100,
    damping: float = 0.5,
    algorithm: str = "centroid",
) -> dict[int, Any]

Smooth a mesh on a surface, re-projecting boundary vertices onto the nearest border every iteration.

Parameters:

  • mesh (Mesh) –

    A mesh to smooth, modified in place.

  • surface (Any) –

    The surface, as anything with a closest_point method.

  • borders (sequence) –

    The border curves of the surface, as polylines or curves.

  • kmax (int, default: 100 ) –

    Number of iterations for smoothing. Default is 100.

  • damping (float, default: 0.5 ) –

    Damping value for smoothing between 0 and 1. Default is 0.5.

  • algorithm (('centroid', 'area', 'centerofmass'), default: 'centroid' ) –

    Type of smoothing algorithm to apply. Classic centroid by default.

Returns:

  • dict –

    The constraints that were applied. The mesh itself is modified in place.

Coarse edge curves¤

coarse_edges_to_curves ¤

coarse_edges_to_curves(
    coarse: "CoarseQuadMesh | CoarsePseudoQuadMesh",
    loops: "list[list[list[float]]] | tuple[list[list[float]], ...]" = (),
    polylines: "list[list[list[float]]] | tuple[list[list[float]], ...]" = (),
    wall_tol: float | None = None,
    precision: int | None = None,
) -> tuple[dict[tuple[int, int], list[list[float]]], dict[str, int]]

({(u, v): polyline}, tally): the shape of every coarse edge, for densification(edges_to_curves=...).

The mapping is complete for every edge, as densification requires.

Parameters:

  • coarse (CoarseQuadMesh or CoarsePseudoQuadMesh) –

    The layout to densify. Read only.

  • loops (list[list[[x, y, z]]], default: () ) –

    The domain walls, outer first, each closed. Sample them from the Rhino curves at whatever resolution the final mesh should follow -- these points ARE the boundary from here on, so an arc handed over as two points is a chord.

  • polylines (list[list[[x, y, z]]], default: () ) –

    The decomposition's branches, as baked on Skeleton::Polylines. Matched by the geometric key of their two ends.

  • wall_tol (float, default: None ) –

    How far from a wall a boundary corner may sit and still be taken as on it. Defaults to a quarter of the mean coarse edge length, which is generous on purpose: a corner placed by the background triangulation lies on a CHORD of the wall, so on a tightly curved boundary it is a sagitta off it -- 0.03 for a 0.5 background on a 1-unit radius -- and the branch is already gated on the edge being topologically on the layout boundary and on _arc_is_one_edge.

  • precision (int, default: None ) –

    Decimals for the geometric key of the traced branch. The default is COMPAS's own (3), which is far coarser than the single-precision error a Rhino mesh round trip introduces and so is safe.

Returns:

  • tuple[dict, dict] –

    The mapping, complete for every edge of coarse, and {'boundary': n, 'traced': n, 'chord': n, 'wall_missed': n}.

    wall_missed (a subset of the others) counts boundary edges that did not get their wall arc; expect 0 on a generated layout.

snap_corners_to_walls ¤

snap_corners_to_walls(
    coarse: "CoarseQuadMesh | CoarsePseudoQuadMesh",
    loops: "list[list[list[float]]] | tuple[list[list[float]], ...]" = (),
    wall_tol: float | None = None,
) -> tuple[int, float]

Move the layout's boundary corners onto the nearest wall, within wall_tol. (moved, worst).

Mutates coarse; call it before coarse_edges_to_curves.

Parameters:

  • coarse (CoarseQuadMesh or CoarsePseudoQuadMesh) –

    The layout. Modified in place.

  • loops (list[list[[x, y, z]]], default: () ) –

    The domain walls, outer first, each closed -- the same ones handed to coarse_edges_to_curves.

  • wall_tol (float, default: None ) –

    Largest move allowed. Defaults to a quarter of the mean coarse edge length, matching coarse_edges_to_curves.

Returns:

  • tuple[int, float] –

    How many corners moved, and the largest distance any of them moved.

mean_edge_length ¤

mean_edge_length(coarse: 'CoarseQuadMesh | CoarsePseudoQuadMesh') -> float

Average coarse edge length, the scale every tolerance here is relative to.

Coarse mesh from polylines¤

split_at_corners ¤

split_at_corners(
    points: list[list[float]], angle: float = CORNER_ANGLE
) -> list[list[list[float]]]

Cut a clicked polyline into one piece per straight run, at every vertex turning more than angle.

Never hand it a sampled curve; not called by weld_network.

Parameters:

  • points (list[[x, y, z]]) –
  • angle (float, default: CORNER_ANGLE ) –

    Radians. Defaults to CORNER_ANGLE, one degree.

Returns:

  • list[list[[x, y, z]]] –

    One point list per straight run. A polyline with no corner comes back whole.

split_at_junctions ¤

split_at_junctions(
    polylines: list[list[list[float]]],
    tol: float | None = None,
    precision: int | None = None,
    points: "list[list[float]] | tuple[list[float], ...]" = (),
) -> tuple[list[list[list[float]]], list[int]]

Split every polyline wherever another ends on it or crosses it. (pieces, origin).

Turns a drawing into a network weld_network accepts; dangling ends are left for it to refuse.

Parameters:

  • polylines (list[list[[x, y, z]]]) –
  • tol (float, default: None ) –

    How close an end must be to another curve to be ON it. Defaults to the weld resolution, the same distance check_network refuses a T-junction at -- so what this splits is exactly what that would refuse.

  • precision (int, default: None ) –

    Decimals of the weld, used only to derive the default tol.

  • points (list[[x, y, z]], default: () ) –

    Extra points to cut at. Any polyline passing within tol of one is split there, exactly as if a curve had ended on it. For a caller that knows where a corner is without having a curve that ends there -- a corner on a wall, marked by a piece of wall that is not itself an edge.

Returns:

  • tuple[list[list[[x, y, z]]], list[int]] –

    The pieces, and for each the index of the input polyline it came from -- so a caller can map a later refusal back to what the user drew.

weld_network ¤

weld_network(
    polylines: list[list[list[float]]], precision: int | None = None
) -> tuple[list[list[float]], list[tuple[int, int, list[list[float]]]]]

(vertices, edges) from a drawn network. One polyline is one coarse edge.

Parameters:

  • polylines (list[list[[x, y, z]]]) –

    One polyline per coarse edge. A straight edge is two points; a curved one is however many the CAD session sampled it at.

  • precision (int, default: None ) –

    Decimals the endpoints are welded at. The default is COMPAS's own, 3, which is the resolution Mesh.from_polylines matches endpoints at and the one a Rhino mesh round trip already rounds to.

Returns:

  • tuple[list[[x, y, z]], list[int, int, list[[x, y, z]]]] –

    The corners, and one (start, end, points) per edge with points running start -> end. Corner indices are positional, so handing vertices straight to from_vertices_and_faces gives mesh keys that are these same indices.

Raises:

  • ValueError –

    On a polyline that is not an edge, or a second polyline between two corners that already have one.

check_network ¤

check_network(
    vertices: list[list[float]],
    edges: list[tuple[int, int, list[list[float]]]],
    tol: float,
) -> None

Raise unless the drawn network is a clean planar arrangement.

Checks T-junctions, crossings, dangling curves and loose pieces, most specific first.

Parameters:

  • vertices (list) –

    As returned by weld_network.

  • edges (list) –

    As returned by weld_network.

  • tol (float) –

    Distance below which a point is ON a curve. The weld resolution is the right scale -- two points nearer than that are already one corner.

Raises:

faces_from_network ¤

faces_from_network(
    vertices: list[list[float]],
    edges: list[tuple[int, int, list[list[float]]]],
    holes: list[list[float]] | None = None,
) -> list[list[int]]

The domain's patches as counter-clockwise rings of corner indices, by planar face walk.

The unbounded face (by the full point ring's signed area) and holes are dropped.

Parameters:

  • vertices (list) –

    As returned by weld_network.

  • edges (list) –

    As returned by weld_network.

  • holes (list[[x, y, z]], default: None ) –

    One point inside each hole of the domain.

Returns:

  • list[list[int]] –

    One ring of corner indices per patch, counter-clockwise.

check_faces ¤

check_faces(
    faces: list[list[int]], vertices: list[list[float]], sides: tuple[int, ...] = (3, 4)
) -> None

Raise unless every recovered patch has an allowed number of sides (triangles become poles).

Colouring¤

mesh_vertex_2_coloring ¤

mesh_vertex_2_coloring(mesh: Mesh) -> dict[int, int] | None

Try to color the vertices of a mesh with two colors only without adjacent vertices with the same color.

Parameters:

  • mesh (Mesh) –

    A mesh.

Returns:

  • (dict, None) –

    A dictionary with vertex keys pointing to colors, if two-colorable. None if not two-colorable.

mesh_vertex_n_coloring ¤

mesh_vertex_n_coloring(mesh: Mesh) -> dict[int, int]

Color the vertices of a mesh with a minimum number of colors without adjacent vertices with the same color.

Parameters:

  • mesh (Mesh) –

    A mesh.

Returns:

  • dict –

    A dictionary with vertex keys pointing to colors.

mesh_face_2_coloring ¤

mesh_face_2_coloring(mesh: Mesh) -> dict[int, int] | None

Try to color the faces of a mesh with two colors only without adjacent faces with the same color.

Parameters:

  • mesh (Mesh) –

    A mesh.

Returns:

  • (dict, None) –

    A dictionary with face keys pointing to colors, if two-colorable. None if not two-colorable.

mesh_face_n_coloring ¤

mesh_face_n_coloring(mesh: Mesh) -> dict[int, int]

Color the faces of a mesh with a minimum number of colors without adjacent faces with the same color.

Parameters:

  • mesh (Mesh) –

    A mesh.

Returns:

  • dict –

    A dictionary with face keys pointing to colors.

quad_mesh_strip_2_coloring ¤

quad_mesh_strip_2_coloring(quad_mesh: QuadMesh) -> dict[int, int] | None

Try to color the strips of a quad mesh with two colors only without overlapping strips with the same color.

Parameters:

  • quad_mesh (QuadMesh) –

    A quad mesh.

Returns:

  • (dict, None) –

    A dictionary with strip keys pointing to colors, if two-colorable. None if not two-colorable.

quad_mesh_strip_n_coloring ¤

quad_mesh_strip_n_coloring(quad_mesh: QuadMesh) -> dict[int, int]

Color the strips of a quad mesh with a minimum number of colors without overlapping strips with the same color.

Parameters:

  • quad_mesh (QuadMesh) –

    A quad mesh.

Returns:

  • dict –

    A dictionary with strip keys pointing to colors.

quad_mesh_polyedge_2_coloring ¤

quad_mesh_polyedge_2_coloring(
    quad_mesh: QuadMesh, edge_output: bool = False
) -> dict[Any, int] | None

Try to color the polyedges of a quad mesh with two colors only without overlapping polyedges with the same color. Polyedges connected by their extremities, which are singularities, do not count as overlapping.

Parameters:

  • quad_mesh (QuadMesh) –

    A quad mesh.

  • edge_output (bool, default: False ) –

    Optional to output coloring per edge keys instead of polyedge key.

Returns:

  • (dict, None) –

    A dictionary with polyedge keys pointing to colors, if two-colorable. If edge_output, edge keys pointing to colors. None if not two-colorable.

quad_mesh_polyedge_n_coloring ¤

quad_mesh_polyedge_n_coloring(
    quad_mesh: QuadMesh, edge_output: bool = False
) -> dict[Any, int]

Color the polyedges of a quad mesh with a minimum number of colors without overlapping polyedges with the same color. Polyedges connected by their extremities, which are singularities, do not count as overlapping.

Parameters:

  • quad_mesh (QuadMesh) –

    A quad mesh.

  • edge_output (bool, default: False ) –

    Optional to output coloring per edge keys instead of polyedge key.

Returns:

  • dict –

    A dictionary with polyedge keys pointing to colors. If edge_output, edge keys pointing to colors.

dense_quad_mesh_polyedge_2_coloring ¤

dense_quad_mesh_polyedge_2_coloring(quad_mesh: 'QuadMesh') -> dict[int, int | None]

Morphing¤

fold ¤

fold(
    quad_mesh: QuadMesh,
    vkey_to_group: dict[int, int],
    func0: Callable[[QuadMesh, int], list[float]],
    func1: Callable[[QuadMesh, int], list[float]],
) -> dict[int, list[float]]

fold_vertex_group ¤

fold_vertex_group(quad_mesh: QuadMesh, polyedges: list[list[int]]) -> dict[int, int]

Operations¤

mesh_move_by ¤

mesh_move_by(mesh: Mesh, vector: list[float]) -> None

Move a mesh by a vector.

Parameters:

  • mesh (Mesh) –

    A mesh.

  • vector (list) –

    An XYZ vector.

mesh_move_vertices_by ¤

mesh_move_vertices_by(mesh: Mesh, key_to_vector: dict[int, list[float]]) -> None

Move mesh vertices by different vectors.

Parameters:

  • mesh (Mesh) –

    A mesh.

  • key_to_vector (dict) –

    A dictionary of vertex keys pointing to vectors.

mesh_move_vertex_to ¤

mesh_move_vertex_to(mesh: Mesh, point: list[float], vkey: int) -> None

Move a mesh vertex to a point.

Parameters:

  • mesh (Mesh) –

    A mesh.

  • point (list) –

    An XYZ point.

  • vkey (hashable) –

    A vertex key.

is_face_degenerate ¤

is_face_degenerate(
    a: list[float], b: list[float], c: list[float], tol: float = FLATNESS
) -> bool

Whether a triangle is flat (collinear or repeated corners), by a scale-relative height test.

Parameters:

  • a (list) –

    The three corners, as [x, y, z].

  • b (list) –

    The three corners, as [x, y, z].

  • c (list) –

    The three corners, as [x, y, z].

  • tol (float, default: FLATNESS ) –

    Relative height below which the triangle counts as flat.

Returns:

trimesh_face_circle ¤

trimesh_face_circle(
    mesh: Mesh, fkey: int
) -> tuple[list[float], float, list[float]] | None

Circumcircle of a triangular face, in closed form so the centre is bit-reproducible.

Parameters:

  • mesh (Mesh) –

    A mesh.

  • fkey (hashable) –

    A face key.

Returns:

  • tuple or None –

    (center, radius, normal) -- centre first, which is the ordering compas_singular relies on -- or None if the face is not a triangle.

Raises:

  • ValueError –

    If the triangle is flat. A flat triangle has no circumcircle, and the closed form below divides by its doubled squared area. boundary_triangulation deletes flat faces before any caller here gets to walk them, so reaching this means one was built some other way.

mesh_weld ¤

mesh_weld(mesh: Mesh, precision: int | None = None, cls: type | None = None) -> Any

Weld vertices within a precision into a new mesh, dropping faces that collapse below three vertices.

Parameters:

  • mesh (Mesh) –

    A mesh.

  • precision (int, default: None ) –

    Decimals of the geometric key used to match vertices. Defaults to the COMPAS tolerance precision.

  • cls (type, default: None ) –

    The class of the resulting mesh. Defaults to the class of mesh.

Returns:

  • Mesh –

    A new welded mesh.

meshes_join ¤

meshes_join(meshes: list[Mesh], cls: type | None = None) -> Any

Join meshes without welding, returning a new mesh.

Parameters:

  • meshes (list) –

    A list of meshes.

  • cls (type, default: None ) –

    The class of the resulting mesh. Defaults to the class of the first mesh.

Returns:

  • Mesh –

    A new joined mesh.

meshes_join_and_weld ¤

meshes_join_and_weld(
    meshes: list[Mesh], precision: int | None = None, cls: type | None = None
) -> Any

Join and weld meshes within a precision distance, returning a new mesh.

Parameters:

  • meshes (list) –

    A list of meshes.

  • precision (int, default: None ) –

    Decimals of the geometric key used to match vertices. Defaults to the COMPAS tolerance precision.

  • cls (type, default: None ) –

    The class of the resulting mesh. Defaults to the class of the first mesh.

Returns:

  • Mesh –

    A new joined and welded mesh.