mascaf.skeleton

Graph-based skeleton handler.

Provides a SkeletonGraph class that inherits from networkx.Graph to: - Represent skeleton as a graph with xyz coordinates on each node - Load from polylines array or polylines text format: N x1 y1 z1 x2 y2 z2 … - Identify terminal nodes (degree 1) and branch nodes (degree 3+) - Every point from input polylines becomes a node in the SkeletonGraph

Note: This class represents skeleton topology as a graph where: - Nodes have ‘pos’ attribute with (x, y, z) coordinates - Edges connect consecutive nodes along polylines - Terminal nodes have degree 1 - Branch nodes have degree 3+ - Continuation nodes have degree 2

class mascaf.skeleton.SkeletonGraph(tolerance=1e-06, **attr)[source]

Bases: Graph3D

Graph-based skeleton representation with xyz coordinates on nodes.

Inherits from networkx.Graph. Each node has a ‘pos’ attribute storing (x, y, z) coordinates. Edges represent connections between consecutive points along polylines data.

Every point from input polylines file becomes a node. Endpoints within tolerance are merged into single nodes.

Terminal nodes (degree 1) are isolated endpoints. Branch nodes (degree 3+) are where multiple branches meet. Continuation nodes (degree 2) are intermediate points along branches.

Parameters:

tolerance (float)

__init__(tolerance=1e-06, **attr)[source]

Initialize a SkeletonGraph.

Parameters:
  • tolerance (float) – Distance threshold below which two endpoints are merged into a single node.

  • **attr – Additional keyword arguments forwarded to the networkx graph constructor as graph-level attributes.

position_attr = 'pos'
classmethod from_polylines(polylines, tolerance=1e-06)[source]

Create a SkeletonGraph from a sequence of polyline arrays.

Every point in every polyline becomes a node. Consecutive points within a polyline are connected by edges. Endpoints whose Euclidean distance is less than tolerance are merged into a single node.

Parameters:
  • polylines (Sequence[ndarray]) – Each element is an ordered array of 3D points representing one branch of the skeleton.

  • tolerance (float) – Maximum distance between two endpoint coordinates for them to be merged.

Returns:

Graph with node positions stored under the 'pos' attribute and edge 'length' attributes populated.

Return type:

SkeletonGraph

classmethod from_txt(path, tolerance=1e-06)[source]

Load a SkeletonGraph from a file.

Supports two formats: 1. GraphML format (.graphml or .xml extension) - native graph format 2. Legacy polylines format (.polylines.txt) - for backward compatibility

Return type:

SkeletonGraph

Parameters:
Args:

path: Path to the skeleton file tolerance: Distance threshold for merging nearby endpoints (polylines format only)

Returns:

SkeletonGraph instance

detect_branch_points(tolerance=1e-06)[source]

Detect branch points and endpoints in the skeleton.

Return type:

dict

Parameters:

tolerance (float)

Note:

SkeletonGraph already merges endpoints within tolerance on import. The tolerance argument is accepted for API compatibility.

Args:

tolerance: Unused; kept for compatibility.

Returns:
Dictionary containing:
  • ‘branch_points’: List of node IDs for branch nodes

  • ‘endpoints’: List of node IDs for terminal nodes

  • ‘branch_locations’: List of 3D coordinates of branch nodes

  • ‘endpoint_locations’: List of 3D coordinates of terminal nodes

get_branch_point_indices(tolerance=1e-06)[source]

Return the set of branch node IDs.

Return type:

Set[int]

Parameters:

tolerance (float)

Args:

tolerance: Unused; kept for compatibility.

Returns:

Set of node IDs.

get_true_endpoint_indices(tolerance=1e-06)[source]

Return the set of terminal node IDs.

Return type:

Set[int]

Parameters:

tolerance (float)

Args:

tolerance: Unused; kept for compatibility.

Returns:

Set of node IDs.

build_graph(tolerance=1e-06)[source]

Build a networkx graph representation with node type annotations.

This is primarily a compatibility helper for tests. The returned graph is a plain nx.Graph (not a SkeletonGraph).

Return type:

Graph

Parameters:

tolerance (float)

Args:

tolerance: Unused; kept for compatibility.

Returns:
A nx.Graph with nodes annotated with:
  • ‘pos’: (x, y, z)

  • ‘type’: ‘endpoint’ | ‘branch’ | ‘continuation’

prune_short_branches(min_length=None, min_length_fraction=None, tolerance=1e-06, iterative=True, verbose=False)[source]

Remove short terminal branches.

A terminal branch is a path from a terminal node (degree 1) to the next non-continuation node (degree != 2). If the path ends at a branch node (degree 3+) and its geometric length is below the threshold, it is removed. Isolated components that connect terminal-to-terminal with no branch nodes are removed regardless of length.

Length is computed from edge lengths (or node coordinates if missing), so “short” refers to geometric length, not node count.

Return type:

SkeletonGraph

Parameters:
prune_short_branches_inplace(min_length=None, min_length_fraction=None, tolerance=1e-06, iterative=True, verbose=False)[source]

In-place version of prune_short_branches.

Return type:

int

Parameters:
Returns:

Number of nodes removed.

to_point_set()[source]

Return all skeleton node locations as a PointSet.

Return type:

PointSet

to_polylines()[source]

Convert the graph back to a list of polyline arrays.

Reconstructs polylines by grouping edges with the same polyline_idx and ordering them by segment_idx, properly handling branch points.

Return type:

List[ndarray]

Returns:

List of (N_i, 3) arrays representing polylines

to_txt(path)[source]

Save the skeleton to a file.

Saves in GraphML format (.graphml) which preserves all graph structure, node positions, and edge metadata. This is the native format for SkeletonGraph.

For legacy polylines format, use to_polylines() and save manually.

Return type:

None

Parameters:

path (str)

Args:

path: Output file path (will use .graphml extension if not provided)

copy()[source]

Create a deep copy of the skeleton graph.

Return type:

SkeletonGraph

Returns:

New SkeletonGraph instance with copied data

get_statistics()[source]

Get statistics about the skeleton graph.

Return type:

dict

Returns:

Dictionary with various statistics

resample(spacing)[source]

Resample the skeleton to have approximately uniform spacing between nodes.

Works directly on graph edges, subdividing long edges and preserving topology.

Return type:

SkeletonGraph

Parameters:

spacing (float)

Args:

spacing: Target distance between consecutive nodes

Returns:

New SkeletonGraph with resampled nodes

snap_to_mesh_surface(mesh, project_outside_only=True, max_distance=None)[source]

Project node positions to the nearest surface point on mesh.

Return type:

tuple

Parameters:
  • project_outside_only (bool)

  • max_distance (float | None)

Args:

mesh: trimesh.Trimesh object project_outside_only: If True, only project points outside the mesh max_distance: If provided, only move points beyond this distance from surface

Returns:

(n_moved, mean_move_distance) tuple

compute_branch_lengths()[source]

Compute the length of each branch (path between terminal/branch nodes).

Return type:

dict

Returns:

Dictionary mapping (start_node, end_node) -> length

get_total_length()[source]

Get the total length of all edges in the skeleton.

Return type:

float

Returns:

Total length