Skip to content

Spline

Spline(a=None, mode='COPY', selector=None, attr_from=None, **attrs)

Curve spline domain.

Groups control points into splines and stores per-spline parameters (type, resolution, cyclic flags, and NURBS settings). Provides accessors to parametric functions and common evaluations.

Attributes:

Name Type Description
loop_start (S,) int

Starting control-point index of each spline.

loop_total (S,) int

Control-point count per spline.

material_index (S,) int, optional

Material index per spline.

curve_type (S,) int

One of constants BEZIER, POLY, NURBS.

resolution (S,) int, optional

Evaluation resolution (samples per segment).

cyclic (S,) bool, optional

Whether each spline is closed.

order (S,) int, optional

NURBS order.

bezierpoint, endpoint (S,) bool, optional

NURBS flags.

Properties

has_bezier : bool True if any spline is Bezier. functions : list List-like container of parametric spline functions (Bezier/Poly/NURBS). length : list of float Length of each spline (delegates to functions).

Methods:

Name Description
delete_splines

Delete splines and their control points.

add_splines

Append new splines given control-point counts.

tangent

Evaluate tangents at parameter t in [0, 1].

compute_attribute_on_points

Broadcast per-spline attributes to control points.

Examples:

Build functions and sample tangents:

funcs = splines.functions
tan = splines.tangent(0.25)

Append three splines with different sizes:

splines.add_splines([4, 6, 8], material_index=[0, 1, 1])

Note: functions relies on project spline implementations. Ensure control-point attributes (e.g., handles for Bezier, weights/order for NURBS) are present when required.

Caution: resolution semantics differ for cyclic vs. non-cyclic splines (endpoints handling).

Initialize a domain array and its attribute schema.

Initializes the storage from an existing array/domain or creates an empty structure. Optionally merges attribute definitions/values from another domain and keyword-provided attributes.

Domains are never instancied directly but by owning geometries.

Actual Domains are Vertex, [Faces][npblender.Faces], Corner, Edge, ControlPoint, Spline and Point.

Domains are initialized with their defaults attributes, for instance position for point domaines.

Use attributes can be freely added.

Note: user attributes are saved in Blender Mesh objects only, Blender Curve objects don't store user attributes.

Parameters:

Name Type Description Default
a array - like or FieldArray or None

Source data used to initialize the domain. If None, an empty domain is created and _declare_attributes() is called to register defaults.

None
mode (COPY, CAPTURE, EMPTY)

Initialization mode. 'COPY' duplicates the input data, 'CAPTURE' references the input buffer when supported, 'EMPTY' creates the structure without copying values.

'COPY'
selector Any

Optional row/element selector applied to a prior to initialization.

None
attr_from Domain or Mapping or None

Attribute schema (and possibly values) to merge into this domain.

None
**attrs

Additional attribute name/value pairs to inject or override.

{}
Notes

The effective attribute list results from _declare_attributes(), then attr_from, then **attrs (later entries take precedence).

Examples:

cube = Mesh.cube() # points, corners, faces and edges domains are created
# Adding named attribute to point domain
cube.points.new_float('age')
# Setting the age
cube.points.age = np.random.uniforme(10, 10, len(cube.points))

actual_names property

actual_names

Column names.

Returns the actual field names, excluding optional fields.

all_names property

all_names

Column names.

Returns all the field names, including optional ones.

dtype property

dtype

Array structured dtype

Returns the dtype property of the structured array.

has_bezier property

has_bezier

Check if the domain contains any Bézier splines.

Evaluates the curve_type attribute and returns True if at least one spline in the domain is of type BEZIER.

Returns:

Type Description
bool

True if the domain has at least one Bézier spline, False otherwise.

Notes
  • Useful for quickly testing whether Bézier-specific logic (e.g., handle attributes) must be considered.
  • For mixed domains, the result is True as soon as one Bézier is present.

Examples:

if splines.has_bezier:
    print("Domain contains Bézier curves.")

next_loop_start property

next_loop_start

Offset to use for the next appended item.

Returns:

Type Description
int

loop_start[-1] + loop_total[-1] if the domain is non-empty, otherwise 0.

See Also

[compute_loop_start][npblender.FaceSplineDomain.compute_loop_start]

reversed_indices property

reversed_indices

Map each corner/control-point index back to its owning item.

Returns:

Type Description
ndarray of shape ``(sum(loop_total),)``

For index k in the flattened corner/control-point array, the value is the face/spline index that owns k.

transdom_names property

transdom_names

List the names of trans-domain attributes.

Returns:

Type Description
list of str

Names of attributes flagged with transdom=True.

Examples:

names = D.transdom_names()

__array__

__array__(dtype=None)

Allow implicit conversion to np.ndarray

add

add(count, **fields)

Add count records

New records are set with default values or values provided by the user in fields dict.

Parameters:

Name Type Description Default
count int

Number of records to add.

required
fields dict

Keyword arguments mapping field names to values.

{}

append

append(**fields)

Append values to the structured array.

The number of records to append is determined by the number of fields provided in the fields dictionary. The values of the fields are copied to the new records.

Parameters:

Name Type Description Default
fields dict

Keyword arguments mapping field names to values.

{}

append_sizes

append_sizes(sizes, **fields)

Append new items given their sizes.

If loop_start is not provided in fields, computes it from sizes using [compute_loop_start][npblender.FaceSplineDomain.compute_loop_start].

Parameters:

Name Type Description Default
sizes array-like of int or None

Number of corners/control-points for each new item.

required
**fields

Additional per-item attributes to append (e.g., material_index).

{}

Returns:

Type Description
Any

The value returned by append(...) (implementation-defined, often the indices/slice of appended items).

Notes

Passing sizes=None is a no-op and returns an empty list.

as_kwargs

as_kwargs(selector=None, include=None, exclude=None)

Return a dictionary of field values formatted as kwargs.

Parameters:

Name Type Description Default
selector slice, int, list, or mask

Optional selection of elements to extract.

None
include list[str]

List of field names (original or python names) to include.

None
exclude list[str]

List of field names (original or python names) to exclude.

None

Returns:

Type Description
dict

Mapping from python-safe field names to array values.

check

check(count, halt=True)

Validate loop counters against a reference element count.

Verifies that the sum of loop_total equals count (i.e., the total number of referenced elements such as corners or control points).

Parameters:

Name Type Description Default
count int

Expected total number of elements referenced by all items.

required
halt bool

If True, raise on failure; otherwise print a message and return False.

True

Returns:

Type Description
bool

True if the check passes or the domain is empty; False only when invalid and halt is False.

Raises:

Type Description
RuntimeError

If sum(loop_total) != count and halt is True.

Examples:

ok = fs.check(count=len(corners), halt=False)
if not ok:
    # fix topology or sizes, then recompute
    fs.update_loop_start()

compute_attribute_on_points

compute_attribute_on_points(attr, points)

Expand spline attributes to control points.

Broadcasts attributes defined per-spline into per-point arrays by repeating each spline’s value over all its control points. This ensures compatibility when working in the control-point domain.

Parameters:

Name Type Description Default
attr str or ndarray

Attribute to expand. If a string, it is looked up in this domain. If an array, it must have length equal to the number of splines.

required
points ControlPoint

Control-point domain that receives the expanded attributes. The result has length equal to len(points).

required

Returns:

Type Description
ndarray

Array of shape (len(points), *attr_shape) containing the broadcasted attribute values.

Raises:

Type Description
AttributeError

If the attribute is not found in this domain.

ValueError

If the provided attribute array shape does not match the number of splines.

Notes
  • Expansion uses the loop_start and loop_total arrays to map splines to their corresponding ranges of control points.
  • This is the inverse of aggregating per-point attributes back to splines.

Examples:

# Broadcast per-spline weights to all control points
w_points = splines.compute_attribute_on_points("weight", cpoints)

compute_loop_start

compute_loop_start(loop_total=None)

Compute offsets for one or many new items to append.

Parameters:

Name Type Description Default
loop_total int or array-like of int or None

Sizes of the items to add. If None, returns None. If a scalar, returns the single offset. If 1D array-like, returns one offset per size.

None

Returns:

Type Description
int or ndarray or None

Offsets starting from [next_loop_start][npblender.FaceSplineDomain.next_loop_start], shaped like loop_total.

Examples:

# Prepare offsets for three faces of sizes 4, 5, 4
starts = fs.compute_loop_start([4, 5, 4])
fs.append(loop_start=starts, loop_total=[4, 5, 4])

copy_field

copy_field(field_name, new_name, **infos)

Duplicate an existing field under a new name, with optional metadata overrides.

Parameters:

Name Type Description Default
field_name str

The name of the existing field to copy.

required
new_name str

The name of the new field to create.

required
infos keyword arguments

Optional metadata (e.g. default, unit, description...) to override or supplement the original field's metadata.

{}

Raises:

Type Description
KeyError

If the source field does not exist.

ValueError

If the target name already exists or is reserved.

delete

delete(selection)

Delete selected items and maintain consistent offsets.

After deleting items via super().delete(selection), recomputes loop_start with [update_loop_start][npblender.FaceSplineDomain.update_loop_start].

Parameters:

Name Type Description Default
selection Any

Boolean mask, integer index, slice, or array of indices.

required

Returns:

Type Description
None
See Also

[update_loop_start][npblender.FaceSplineDomain.update_loop_start]

delete_splines

delete_splines(selection, cpoints)

Delete splines and their associated control points.

Removes the splines selected in this domain, and deletes the corresponding control points from the given control-point domain. Corner indices are retrieved first to ensure consistent cleanup.

Parameters:

Name Type Description Default
selection array-like of bool or int

Indices or boolean mask selecting which splines to delete.

required
cpoints ControlPoint

Control-point domain from which the corresponding points are removed.

required

Returns:

Type Description
None

Raises:

Type Description
IndexError

If any index in selection is out of bounds for this domain.

ValueError

If selection has an incompatible shape or type.

Notes
  • This operation modifies both the spline domain and the control-point domain in place.
  • Deletion preserves consistency between splines and their control points.

Examples:

# Delete the first spline and its control points
splines.delete_splines([0], cpoints)

dump

dump(title='Dump', attributes=None, target='SCREEN')

Pretty-print or export domain content.

Formats attribute values and prints to screen or builds a tabular dump suitable for spreadsheets.

Parameters:

Name Type Description Default
title str

Title displayed in the report.

'Dump'
attributes Sequence[str] or None

Subset of attribute names to include. If None, all attributes are shown.

None
target (SCREEN, ...)

Output target. 'SCREEN' prints to stdout; other targets may trigger file creation depending on the implementation.

'SCREEN'

Returns:

Type Description
None

Examples:

Domain(points).dump(title="Vertices")

Note: Formatting adapts to the chosen target.

extend

extend(other, join_fields=True)

Append multiple records from another array or FieldArray.

Parameters:

Name Type Description Default
other FieldArray or structured np.ndarray

The array of records to append. Must have named fields matching a subset of the current array's fields.

required

filtered

filtered(selector, *, copy=False)

Return a FieldArray containing only the selected records.

Parameters:

Name Type Description Default
selector array‑like, slice or int

Any valid NumPy 1‑D index: boolean mask, integer index/array, or slice. It is applied to the current valid part of the buffer (self._data[:self._length]).

required
copy bool
  • False (default) => the new array shares the same memory (changes propagate both ways).
  • True => the data are physically copied.
False

Returns:

Type Description
FieldArray

A new instance holding exactly len(selector) records and inheriting the current field‑infos.

from_bl_attributes

from_bl_attributes(bl_attributes)

Import attributes from a Blender attribute collection.

Reads geometry attributes from a Blender data-block and creates/updates the corresponding domain attributes, resizing the domain if needed.

Parameters:

Name Type Description Default
bl_attributes Mapping[str, Any]

Blender attributes collection (name → attribute descriptor) providing at least .domain, .is_internal, .data_type, and .data.

required

Returns:

Type Description
None
> ***Note:*** Only external (non-internal) Blender attributes matching this
domain are imported. Missing attributes are created with `transfer=True`.

from_dict classmethod

from_dict(data)

Build a FieldArray from a dictionary with field data and optional metadata.

Parameters:

Name Type Description Default
data dict[str, array - like or (array, dict)]

Mapping field names to arrays or (array, infos). Infos must include NAME.

required
copy bool

Whether to copy the data. Default: True.

required

Returns:

Type Description
FieldArray

get

get(name, default=None, broadcast_shape=None)

Get attribute by name.

If name is not an actual field, return default value. Name can be an array.

pos = field_array.get("position", (0, 0, 1))
pos = field_array.get([[0, 0, 1], [0, 0, 0]])

get_corner_indices

get_corner_indices()

Return the contiguous range of corner/control-point indices.

For each item, expands its [loop_start, loop_start + loop_total) range and concatenates the result for all items.

Returns:

Type Description
ndarray of shape ``(sum(loop_total),)``

Absolute indices into the corner/control-point array.

Notes

A fast Numba kernel is used for vectorized cases; the scalar case is handled directly.

join_attributes

join_attributes(other)

Merge trans-domain attributes from another domain.

Copies or aligns attributes from other into the current domain, excluding any attributes not flagged as trans-domain in other.

Parameters:

Name Type Description Default
other Domain or None

Source domain. If None, the call is a no-op.

required

Returns:

Type Description
Domain

The domain itself (for chaining).

join_fields

join_fields(other, exclude=[])

Add all missing fields from another FieldArray.

For every field in other that is not present in self, a new field is created with the same dtype and shape, and initialized with its default value across all existing records.

Parameters:

Name Type Description Default
other FieldArray

Another FieldArray instance whose fields will be checked for missing fields.

required

Returns:

Type Description
self

load_bl_attributes

load_bl_attributes(data)

Load spline attributes from a Blender object.

Reads attributes stored in a Blender data block and transfers those that belong to the spline domain into this domain. New attributes are created if they do not already exist.

Parameters:

Name Type Description Default
data ID or similar

Blender object or data block exposing an attributes mapping.

required

Returns:

Type Description
None

Raises:

Type Description
Exception

If reading or assignment of an attribute fails.

AssertionError

If Blender provides inconsistent attribute sizes.

Notes
  • Only attributes with a matching domain and not marked as internal are imported.
  • If an attribute does not exist yet, it is created with the appropriate data type and marked as transferable.
  • The domain is resized once to match the size of Blender attributes.

Examples:

import bpy
from npblender import Spline

curve = bpy.data.curves["MyCurve"]
splines = Spline()
splines.load_bl_attributes(curve)

make_buckets

make_buckets(attr)

Group items into buckets by attribute value.

When a domain is to be considered as a collection of packets of various sizes, buckets mechanism groups pakets by size, allowing further operation with numpy vectorization.

Parameters:

Name Type Description Default
attr array - like or str

Either an integer of shape (N,) or the name of an existing integer attribute in the domain.

required

Returns:

Type Description
list[ndarray(count, n)]

A list of int arrays (count, n): count is the number of buckets of length n.

Examples:

buckets = mesh.make_buckets('material')
for bucket in buckets:
    print(bucket.shape)

Note: The bucket attribute can be read with attr[bucket[:, 0]].

multiply

multiply(count)

Duplicate the current records count times.

Parameters:

Name Type Description Default
count int

Number of times to repeat the current records.

required
Notes

This duplicates the current valid records (up to self._length). If the array is empty or count <= 1, nothing happens.

Example:

If the array has 3 records and count == 4, the result will be:

[rec0, rec1, rec2, rec0, rec1, rec2, rec0, rec1, rec2, rec0, rec1, rec2]

new_attribute

new_attribute(name, data_type, default, optional=False, transfer=True, transdom=True)

Register a new attribute in the domain schema.

Creates (or ensures) an attribute with a given name, logical data type, default value, and flags controlling Blender transfer and cross-domain propagation.

Note: data_type argument is a Blender data type not a python data type. The data type name is compatible with Blender internal storage. FLOATdata type is implemented as np.float32 and 'INT' as np.int32.

Parameters:

Name Type Description Default
name str

Attribute name (Python identifier recommended).

required
data_type (FLOAT, INT, BOOL, VECTOR, VECTOR2, COLOR, QUATERNION, MATRIX, STRING, ...)

Logical data type used by the domain.

'FLOAT'
default Any

Default value for newly allocated elements.

required
optional bool

If True, the attribute may be absent on some elements.

False
transfer bool

If True, eligible to be transferred to Blender as a geometry attribute.

True
transdom bool

If True, considered a trans-domain attribute that can be copied across compatible domains.

True
See Also

new_float, new_vector, new_int, new_bool, new_color, new_vector2, new_quaternion, new_matrix

new_bool

new_bool(name, default=False, optional=False, transfer=True, transdom=True)

Create or ensure a boolean attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default bool

Default value.

False
optional bool
False
transfer bool
True
transdom bool
True

new_color

new_color(name, default=(0.5, 0.5, 0.5, 1.0), optional=False, transfer=True, transdom=True)

Create or ensure a color attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default array-like of shape (3,) or (4,)

Default color as RGB or RGBA.

(0.5, 0.5, 0.5, 1.0)
optional bool
False
transfer bool
True
transdom bool
True

new_field

new_field(name, dtype, shape=None, default=0, optional=False, **infos)

Add a field to the structured array.

Arguments
- name (str) : field name
- dtype (type) : a valid numpy dtype
- shape (tuple = None) : the shape of the field
- default (any = 0) : default value
- optional (bool = False) : the field is created only when accessed
- infos (dict) : field infos

new_float

new_float(name, default=0.0, optional=False, transfer=True, transdom=True)

Create or ensure a scalar float attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default float

Default value.

0.0
optional bool
False
transfer bool
True
transdom bool
True

new_int

new_int(name, default=0, optional=False, transfer=True, transdom=True)

Create or ensure an integer attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default int

Default value.

0
optional bool
False
transfer bool
True
transdom bool
True

new_matrix

new_matrix(name, default=np.eye(4), optional=False, transfer=True, transdom=True)

Create or ensure a matrix attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default array - like

Default matrix. By convention this is a square matrix per element (e.g., (3, 3) rotation or (4, 4) transform).

np.eye(4)
optional bool
False
transfer bool
True
transdom bool
True
order
required

new_quaternion

new_quaternion(name, default=(0.0, 0.0, 0.0, 1.0), optional=False, transfer=True, transdom=True)

Create or ensure a quaternion attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default array-like of shape (4,)

Default quaternion in (x, y, z, w) convention.

(0.0, 0.0, 0.0, 1.0)
optional bool
False
transfer bool
True
transdom bool
True

new_vector

new_vector(name, default=(0.0, 0.0, 0.0), optional=False, transfer=True, transdom=True)

Create or ensure a 3D vector attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default array-like of shape (3,)

Default XYZ vector.

(0.0, 0.0, 0.0)
optional bool
False
transfer bool
True
transdom bool
True

new_vector2

new_vector2(name, default=(0.0, 0.0), optional=False, transfer=True, transdom=True)

Create or ensure a 2D vector attribute.

Parameters:

Name Type Description Default
name str

Attribute name.

required
default array-like of shape (2,)

Default XY vector.

(0.0, 0.0)
optional bool
False
transfer bool
True
transdom bool
True

per_size

per_size()

Group items by their loop_total (polygon/control-point count).

Returns a dictionary keyed by size (3, 4, …) where each entry contains: - 'start' : array of loop_start values for items of that size. - 'indices' : array mapping entry order back to item indices.

Returns:

Type Description
dict[int, dict[str, ndarray]]

Grouped start offsets and reverse indices for each size present.

Notes

Uses a Numba kernel to bucketize items efficiently.

to_bl_attributes

to_bl_attributes(attributes, update=False)

Export attributes to a Blender attribute collection.

Writes eligible domain attributes to a Blender data-block, creating missing attributes and adjusting sizes as needed.

Parameters:

Name Type Description Default
attributes Any

Blender attributes collection receiving the values.

required
update bool

If True, update existing attributes in-place; otherwise create them when missing.

False

Returns:

Type Description
None
> ***Caution:*** Only attributes with `transfer=True` are exported. Optional
attributes are skipped.
> ***Caution:*** Curve domains user attributes are not saved.

to_dict

to_dict(*, copy=True, with_infos=True)

Convert the array to a dictionary of fields or (field, infos) pairs.

Parameters:

Name Type Description Default
copy bool

Whether to copy the arrays.

True
with_infos bool

If True, return (array, infos) for each field.

True

Returns:

Type Description
dict[str, array or (array, dict)]

to_object

to_object(data, update=False)

Transfer spline attributes to a Blender object.

Writes this domain’s Blender attributes into the target Blender object or data block.

Parameters:

Name Type Description Default
data ID or similar

Blender object or data block exposing an attributes mapping.

required
update bool

If True, update existing attributes only. If False, create new attributes when they do not exist.

False

Returns:

Type Description
None

Raises:

Type Description
Exception

If attribute creation or assignment fails.

Notes
  • Only attributes flagged with transfer=True are exported.
  • String attributes are currently skipped.

Examples:

import bpy
from npblender import Spline

curve = bpy.data.curves["MyCurve"]
splines = Spline()
splines.to_object(curve, update=False)

Caution: Blender does not save user-defined attributes inside curve objects. Attributes written here may be lost when saving and reopening the file.

transfer_attributes

transfer_attributes(other, shape=None, other_shape=None)

Transfer values of trans-domain attributes from another domain.

Copies values for each trans-domain attribute present in other into the corresponding attributes of self, with optional reshaping for batched assignments.

Parameters:

Name Type Description Default
other Domain

Source domain providing attribute values.

required
shape tuple of int or None

Target reshape for self before assignment. If None, uses (self._length,).

None
other_shape tuple of int or None

Source reshape for other before assignment. If None, uses (other._length,).

None

Returns:

Type Description
Domain

The domain itself (for chaining).

> ***Note:*** Each attribute is reshaped as `shape + item_shape` on `self`
and `other_shape + item_shape` on `other` prior to assignment.

update_loop_start

update_loop_start()

Recompute loop_start from loop_total (cumulative layout).

Sets loop_start to a left-rolled cumulative sum of loop_total, so item i starts right after the end of item i-1.

Returns:

Type Description
FaceSplineDomain

Self (for chaining).

Notes

Call this after deletions / resizes to keep indices consistent.

See Also

[compute_loop_start][npblender.FaceSplineDomain.compute_loop_start] : Compute offsets for new items to be appended.