PyCenterline

class multimodars.PyCenterline(points)

Bases: object

Python representation of a vessel centerline.

points

Ordered list of centerline points.

Type:

list of PyCenterlinePoint

branch_start_indices

Index into points where each branch begins. Entry 0 is always 0 (the main vessel); subsequent entries mark the start of side branches. Read-only — recomputed by calculate_branches.

Type:

list of int

Examples

>>> centerline = PyCenterline(points=[p1, p2, p3])
calculate_branches(spacing_tolerance=1.0)

Detect branches by spatial proximity and return a new centerline with branch_id assigned on every point.

Points whose mutual distance is ≤ spacing_tolerance × median_nn_spacing are considered spatially consecutive regardless of their original array order. The longest path through the resulting tree (by arc length, via a double-BFS diameter search) becomes branch 0 (main vessel); remaining connected components are numbered by descending point count.

Parameters:

spacing_tolerance (float) – Multiplier on the median nearest-neighbour spacing used as the adjacency threshold. 1.5 is a reasonable starting value; increase it if branches are incorrectly split, decrease it if distinct branches are incorrectly merged.

Returns:

New centerline with branch_id set on every point and branch_start_indices populated.

Return type:

PyCenterline

Examples

>>> cl = centerline.calculate_branches(1.5)
>>> main = [p for p in cl.points if p.branch_id == 0]
check_centerline()

Normalise branch ordering so that downstream processing is consistent.

  • Branch 0 – the point with the highest z-coordinate is moved to index 0 (the whole branch is reversed if necessary).

  • Side branches – the endpoint closest to branch 0 becomes index 0 (the branch is reversed if necessary).

Returns:

New centerline with all branches in canonical order.

Return type:

PyCenterline

cleanup_vtp_data(rm_start_mm=5.0, smooth=False, smooth_sigma=2.5)

Remove the run-alongside-main-branch prefix from every side branch, optionally strip the inlet region from branch 0, and optionally smooth.

VTP files export every branch starting from the vessel origin, so side branches share a common prefix with branch 0. This method trims that prefix from each side branch, keeping only the bifurcation junction and the diverged portion. Branches that overlap with branch 0 entirely are dropped. The trim threshold is one mean inter-point spacing of branch 0.

Parameters:
  • rm_start_mm (float, optional) – Arc-length in mm to remove from the start of branch 0 (the inlet region). Set to 0.0 to leave branch 0 untouched. Default 5.0.

  • smooth (bool, optional) – When True, apply a per-branch Gaussian smoothing pass after all trimming. Default False.

  • smooth_sigma (float, optional) – Half-width of the Gaussian kernel in number of centerline points. A value of 1.0 is a gentle neighbourhood average; 2–5 removes noise while preserving the overall vessel path. Ignored when smooth=False. Default 2.5.

Returns:

New centerline with overlapping prefixes removed from all side branches, the inlet trimmed from branch 0 if requested, and positions smoothed if requested.

Return type:

PyCenterline

find_sharp_angles(branch_id, cos_threshold)

Return local positions (0-indexed within the branch) of interior points where the opening angle is sharper than cos_threshold.

Parameters:
  • branch_id (int) – Branch to inspect (0 = main vessel).

  • cos_threshold (float) – Cosine of the opening angle above which a point is considered sharp. Use 0.0 for < 90°, 0.5 for < 60°, 0.866 for < 30°, etc.

Returns:

Local positions within the branch where sharp angles were found.

Return type:

list[int]

static from_contour_points(contour_points)

Build a centerline from a flat list of PyContourPoint objects.

Parameters:

contour_points (list of PyContourPoint) – Ordered sequence of contour points.

Returns:

Centerline constructed from the provided points.

Return type:

PyCenterline

Examples

>>> pts = [PyContourPoint(...), PyContourPoint(...), ...]
>>> cl = PyCenterline.from_contour_points(pts)
get_branch(branch_id)

Return a new centerline containing only the points of one branch.

All retained points are reassigned to branch_id = 0 and branch_start_indices is reset to [0].

Parameters:

branch_id (int) – Branch to extract.

Returns:

Single-branch centerline with the requested points.

Return type:

PyCenterline

Raises:

ValueError – If branch_id does not exist in this centerline.

merge_branches(branch_id_a, branch_id_b)

Merge two branches and return the updated centerline.

Segments are joined at the closest endpoint pair. If either branch is the main branch (id 0) the merged result becomes branch 0.

Parameters:
  • branch_id_a (int)

  • branch_id_b (int)

Returns:

New centerline with the two branches merged and all IDs reassigned.

Return type:

PyCenterline

points_as_tuples()
split_branch(branch_id, local_pos)

Split a branch at a local position and return the updated centerline.

Both resulting segments include the split point. When splitting the main branch (branch_id=0) the longer segment stays as branch 0; for side branches the first segment keeps its slot and the second is appended.

Parameters:
  • branch_id (int) – Branch to split.

  • local_pos (int) – 0-indexed position within the branch (as returned by find_sharp_angles).

Returns:

New centerline with the branch split and all IDs reassigned.

Return type:

PyCenterline