stentfit.core.splines
Functions
|
Split the skeleton graph into curves: chains between junctions/endpoints, |
|
Drop curves that end in a free (unshared) endpoint, iteratively. |
|
Fit one B-spline to a single curve's skeleton points. |
|
Convert one |
|
Group the skeleton graph into curves and fit a B-spline to each. |
|
Read one stent feature, whichever of its two saved shapes it's stored in. |
|
Rebuild a |
|
Build a BeamMe 1D beam mesh from a stent's saved splines. |
Module Contents
- stentfit.core.splines.group_skeleton_curves(skeleton_points_df: pandas.DataFrame) list[list[int]]
Split the skeleton graph into curves: chains between junctions/endpoints, plus closed loops.
A “special” node is anything with degree != 2 (an endpoint, junction, or isolated point). From every special node, each unvisited edge is walked until it reaches another special node, tracing out one curve. Any edges left unvisited afterward belong to a closed loop with no special node at all (every node on it has degree 2), so those are walked separately, starting anywhere on the loop and ending back where they started.
- Parameters:
skeleton_points_df – 3D skeleton graph with
skeleton_point_idandneighbor_idscolumns.- Returns:
List of curves, each a list of point IDs in path order. A closed loop’s first and last ID are the same point.
- stentfit.core.splines.prune_spur_curves(curves: list[list[int]]) list[list[int]][source]
Drop curves that end in a free (unshared) endpoint, iteratively.
A closed loop (same start and end point) is always kept. Otherwise, a curve is dropped if either end is “free” — touched by only that one curve, meaning it’s a dead-end rather than a real junction shared with another curve. This repeats until a full pass drops nothing, since removing one spur can free up the endpoint of its neighbour, exposing a new spur to drop next round.
- Parameters:
curves – Curves from
group_skeleton_curves(), each a list of point IDs in path order.- Returns:
The curves that survived pruning.
- stentfit.core.splines.fit_curve_spline(point_ids: list[int], coords: pandas.DataFrame, every: int, k: int, s: float) dict | None[source]
Fit one B-spline to a single curve’s skeleton points.
Consecutive duplicate points are dropped first. Every
every-th point is kept as a spline control point (always including the last), witheveryreduced automatically if the curve is too short to leave enough control points for degreek. A closed loop is fit as a periodic spline, dropping its duplicated start/end control point first; if that leaves too few points to close the loop, it falls back to an open curve. Ifscipy.interpolate.splprepfails (or there aren’t enough control points for any spline), the control points themselves are returned as a polyline fallback instead.- Parameters:
point_ids – One curve’s point IDs in path order, from
group_skeleton_curves().coords – Skeleton points’
x,y,zcoordinates, indexed by point ID.every – Take every Nth point as a control point.
k – Target B-spline degree.
s – Smoothing factor passed to
splprep.0interpolates the control points exactly.
- Returns:
Noneif fewer than 2 distinct points remain. Otherwise a dict with the fittedtck/u(Noneif fitting failed or wasn’t attempted), thectrlpoints used,n_ctrl, the actual degreekused, whether it closed as a loop (is_loop), and the curve’s physicallength.
- stentfit.core.splines._spline_record(spl: dict | None) dict | None[source]
Convert one
fit_curve_spline()result into a JSON-serializable record.Unpacks scipy’s
tcktuple into plaindegree/knot_vector/control_pointsfields. WheretckisNone(the polyline fallback), recordsdegree=1andknot_vector=Nonewith the raw control points instead.- Parameters:
spl – One curve’s fit result from
fit_curve_spline(), orNone.- Returns:
NoneifsplisNone. Otherwise a dict withdegree,knot_vector(Nonefor the polyline fallback),control_points(as a plain nested list),is_loop, andlength.
- stentfit.core.splines.fit_skeleton_splines(skeleton_df: pandas.DataFrame, output_dir: str, spline_every: int = 10, spline_degree: int = 3, smooth: float = 0.0, prune_spurs: bool = True) dict[source]
Group the skeleton graph into curves and fit a B-spline to each.
Groups the 3D skeleton into curves with
group_skeleton_curves()(degree-2 chains between junctions/endpoints, plus closed loops), drops any spur curve with a free end ifprune_spurs(viaprune_spur_curves()), then fits each remaining curve withfit_curve_spline(). Savessplines.htmlandskeleton_splines.json(per-curve degree, knot vector, control points — with a plain polyline as the fallback where a curve is too short to fit a spline to).- Parameters:
skeleton_df – 3D skeleton graph with
skeleton_point_id,x,y,z, andneighbor_idscolumns, fromwrap_skeleton_to_3d().output_dir – Folder the HTML view and JSON export are written into.
spline_every – Take every Nth skeleton point as a spline control point, to keep the control polygon from being one point per sample.
spline_degree – Target B-spline degree, reduced automatically for short curves.
smooth – Smoothing factor passed to
scipy.interpolate.splprep.0interpolates the control points exactly.prune_spurs – Drop curves with a free (non-junction, non-loop) end, instead of fitting a spline to them.
- Returns:
Dict with the grouped point-id curves (
curves) and their fitted splines (splines, one entry per curve,Nonewhere fitting failed).
- stentfit.core.splines._feat(stent_features: dict, key: str)[source]
Read one stent feature, whichever of its two saved shapes it’s stored in.
A feature is either a plain scalar or a
{'value': ..., 'unit': ...}dict (the shape used for material parameters elsewhere in the pipeline); this reads either the same way.- Parameters:
stent_features – Stent features dict (from
stent_features.jsonor in-memory).key – Feature name to read.
- Returns:
The feature’s plain value.
- stentfit.core.splines._bspline_from_record(rec: dict) splinepy.BSpline[source]
Rebuild a
splinepy.BSplinefrom one_spline_record()entry.Where
knot_vectorisNone(the polyline fallback), builds a degree-1 B-spline with a uniform clamped knot vector instead, so the polyline can still be meshed the same way as a real spline.- Parameters:
rec – One curve’s record, from
skeleton_splines.json(or_spline_record()directly) — withdegree,knot_vector, andcontrol_points.- Returns:
The reconstructed B-spline.
- stentfit.core.splines.mesh_skeleton_beams(input_dir: str, l_el: float = 0.1, youngs_modulus: float = 200000.0, poisson_ratio: float = 0.3, density: float = 0.0, beam_class_label: str = 'Beam3rHerm2Line3') beamme.core.mesh.Mesh[source]
Build a BeamMe 1D beam mesh from a stent’s saved splines.
Reads back
stent_features.json(for the strut thickness, used as the circular cross-section radius) andskeleton_splines.json(for the per-curve splines) frominput_dir, then meshes each curve with BeamMe’screate_beam_mesh_from_splinepy, using_bspline_from_record()to rebuild each spline. A curve is skipped if it has fewer than 2 control points or meshing raises. Each curve’s new elements are tagged with acurve_colorVTK cell scalar (folded into 16 bins) for ParaView inspection — this is visualisation-only and has no effect on the 4C simulation input.- Parameters:
input_dir – Stent output folder to read
stent_features.jsonandskeleton_splines.jsonfrom — normally the same folderskeletonize()wrote them to.l_el – Target element length, in mm.
youngs_modulus – Beam material Young’s modulus, in MPa.
poisson_ratio – Beam material Poisson’s ratio.
density – Beam material density.
beam_class_label – BeamMe beam element type, either
'Beam3rHerm2Line3'or'Beam3rLine2Line2'.
- Returns:
The assembled BeamMe
Mesh.