This page contains all the documentation of the classes and methods.

class nurbs.GeneratorKnotVector[source]

Set of static functions to help creating KnotVector of given degree and npts

static bezier(degree: int, cls: type | None = <class 'int'>) KnotVector[source]

Creates the KnotVector of a bezier curve.

Parameters:
  • degree (int) – The degree of the bezier curve, non-negative

  • cls (int(, optional)) – The class to convert the number, defaults to int

Raises:

AssertionError – If degree is not a non-negative integer

Returns:

The bezier knot vector

Return type:

KnotVector

Example use

>>> from compmec.nurbs import GeneratorKnotVector
>>> GeneratorKnotVector.bezier(1)
(0, 0, 1, 1)
>>> GeneratorKnotVector.bezier(2)
(0, 0, 0, 1, 1, 1)
>>> GeneratorKnotVector.bezier(3)
(0, 0, 0, 0, 1, 1, 1, 1)
>>> GeneratorKnotVector.bezier(3, float)
(0., 0., 0., 0., 1., 1., 1., 1.)
static integer(degree: int, npts: int, cls: type | None = <class 'int'>) KnotVector[source]

Creates a KnotVector of equally integer spaced.

Parameters:
  • degree (int) – The degree of the curve, non-negative

  • npts (int) – The number of control points of the curve

  • cls (int(, optional)) – The class to convert the number, defaults to int

Raises:
  • AssertionError – If degree or npts is not a non-negative integer

  • AssertionError – If npts is not greater than degree

Returns:

The bezier knot vector

Return type:

KnotVector

Example use

>>> from compmec.nurbs import GeneratorKnotVector
>>> GeneratorKnotVector.integer(1, 2)
(0, 0, 1, 1)
>>> GeneratorKnotVector.integer(1, 3)
(0, 0, 1, 2, 2)
>>> GeneratorKnotVector.integer(2, 5)
(0, 0, 0, 1, 2, 3, 3, 3)
>>> GeneratorKnotVector.integer(2, 5, float)
(0., 0., 0., 1., 2., 3., 3., 3.)
static uniform(degree: int, npts: int, cls: type | None = <class 'int'>) KnotVector[source]

Creates a equally distributed knotvector between [0, 1]

Parameters:
  • degree (int) – The degree of the curve, non-negative

  • npts (int) – The number of control points of the curve

  • cls (int(, optional)) – The class to convert the number, defaults to int

Raises:
  • AssertionError – If degree or npts is not a non-negative integer

  • AssertionError – If npts is not greater than degree

Returns:

The uniform knotvector of given degree and number of control points

Return type:

KnotVector

Example use

>>> from fractions import Fraction
>>> from compmec.nurbs import GeneratorKnotVector
>>> GeneratorKnotVector.uniform(1, 2)
(0, 0, 1, 1)
>>> GeneratorKnotVector.uniform(1, 3)
(0, 0, 0.5, 1, 1)
>>> GeneratorKnotVector.uniform(2, 6)
(0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1)
>>> GeneratorKnotVector.uniform(1, 3, Fraction)
(Fraction(0, 1), Fraction(0, 1), Fraction(1, 2), Fraction(1, 1), Fraction(1, 1))
static random(degree: int, npts: int, cls: type | None = <class 'float'>) KnotVector[source]

Creates a random distributed knotvector between [0, 1]

Parameters:
  • degree (int) – The degree of the curve, non-negative

  • npts (int) – The number of control points of the curve

  • cls (float(, optional)) – The class to convert the number, defaults to float

Raises:
  • AssertionError – If degree or npts is not a non-negative integer

  • AssertionError – If npts is not greater than degree

Returns:

The random knotvector of given degree and number of control points

Return type:

KnotVector

Example use

>>> from compmec.nurbs import GeneratorKnotVector
>>> GeneratorKnotVector.random(1, 2)
(0, 0, 1, 1)
>>> GeneratorKnotVector.random(1, 3)
(0, 0, 0.4, 1, 1)
>>> GeneratorKnotVector.random(2, 6)
[0, 0, 0, 0.21, 0.57, 0.61, 1, 1, 1]
static weight(degree: int, weights: Tuple[float]) KnotVector[source]

Creates a knotvector of degree degree based on given weights vector.

Parameters:
  • degree (int) – The degree of the curve, non-negative

  • weights (tuple[float]) – The vector of weights

Raises:
  • AssertionError – If degree is not a non-negative integer

  • AssertionError – If the weights is not an array of positive numbers

Returns:

A knotvector of degree degree

Return type:

KnotVector

Example use

>>> from compmec.nurbs import GeneratorKnotVector
>>> GeneratorKnotVector.weights(1, [1])
(0, 0, 1, 1)
>>> GeneratorKnotVector.weights(2, [1])
(0, 0, 0, 1, 1, 1)
>>> GeneratorKnotVector.weights(2, [2])
(0, 0, 0, 2, 2, 2)
>>> GeneratorKnotVector.weights(1, [2, 2])
(0, 0, 2, 4, 4)
>>> GeneratorKnotVector.weights(1, [1, 2])
(0, 0, 1, 3, 3)
>>> GeneratorKnotVector.weights(1, [1., 2.])
(0., 0., 1., 3., 3.)
class nurbs.KnotVector(vector: Tuple[float], degree: int | None = None)[source]

Creates a KnotVector instance

Examples

>>> KnotVector([0, 1])
(0, 1)
>>> KnotVector([0, 0, 1, 1])
(0, 0, 1, 1)
>>> KnotVector([0, 0, 0.5, 1, 1])
(0, 0, 0.5, 1, 1)
property npts: int

Number of control points

Getter:

Returns the number of control points

Type:

int

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0., 1.])
>>> knotvector.npts
1
>>> knotvector = KnotVector([1, 1, 2, 3, 3])
>>> knotvector.npts
3
property knots: Tuple[float]

Non-repeted knots

Getter:

Non-repeted knots

Type:

tuple[float]

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0., 1.])
>>> knotvector.knots
(0., 1.)
>>> knotvector = KnotVector([1, 1, 2, 3, 3])
>>> knotvector.knots
(1, 2, 3)
>>> knotvector = KnotVector([0, 0, 0, 1, 2, 2, 3, 3, 3])
>>> knotvector.knots
(0, 1, 2, 3)
property limits: Tuple[float]

The knotvector limits

Getter:

Returns the tuple [Umin, Umax]

Type:

tuple[float]

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0., 1.])
>>> knotvector.limits
(0., 1.)
>>> knotvector = KnotVector([1, 1, 2, 3, 3])
>>> knotvector.degree
(1, 3)
property degree: int

Polynomial degree

Getter:

Returns the degree of the curve

Setter:

Increases or decreases curve’s degree

Type:

int

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0., 1.])
>>> knotvector.degree
0
>>> knotvector.degree = 1
>>> print(knotvector)
(0., 0., 1., 1.)
>>> knotvector = KnotVector([1, 1, 2, 3, 3])
>>> knotvector.degree
1
>>> knotvector.degree = 3
>>> print(knotvector)
(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3)
property internal: ImmutableKnotVector

Internal immutable knotvector

Getter:

Returns the immutable knot vector instance

Setter:

Sets as new knot vector instance

Type:

ImmutableKnotVector

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0., 1.])
>>> knotvector.internal
(0., 1.)
shift(value: float) KnotVector[source]

Add value to each knot

Parameters:

value (float) – The amount to shift every knot

Raises:

TypeError – If value is not a number

Returns:

The same instance

Return type:

KnotVector

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0, 0, 1, 1])
>>> knotvector.shift(1)
(1, 1, 2, 2)
>>> knotvector.shift(-1)
(0, 0, 1, 1)
>>> knotvector.shift(1.0)
(1., 1., 2., 2.)
>>> knotvector += 1  # same as shift(1)
(2., 2., 3., 3.)
>>> knotvector -= 1  # same as shift(-1)
(1., 1., 2., 2.)
scale(value: float) KnotVector[source]

Multiplies every knot by amount value

Parameters:

value (float) – The amount to scale every knot

Raises:
  • TypeError – If value is not a number

  • AssertionError – If value is not positive

Returns:

The same instance

Return type:

KnotVector

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([1, 1, 2, 2])
>>> knotvector.scale(2)
(2, 2, 4, 4)
>>> knotvector *= 2  # same as scale(2)
(4, 4, 8, 8)
>>> knotvector.scale(1/2)
(2., 2., 4., 4.)
>>> knotvector /= 2  # same as scale(1/2)
(1., 1., 2., 2.)
convert(cls: type, tolerance: float | None = 1e-09) KnotVector[source]

Convert the knots from current type to given type.

If tolerance is too small, it raises a ValueError cause cannot convert.

Parameters:
  • cls (type) – The class to convert the knots

  • tolerance (float) – The tolerance to check if each node is very far from other

Raises:

ValueError – If cannot convert all knots to given type for given tolerance

Returns:

The same instance

Return type:

KnotVector

Example use

>>> from fractions import Fraction
>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([1., 1., 2., 3., 3.])
>>> knotvector.convert(int)
(1, 1, 2, 3, 3)
>>> knotvector.convert(float)
(1., 1., 2., 3., 3.)
>>> knotvector.convert(Fraction)
(Fraction(1, 1), Fraction(1, 1), Fraction(2, 1), Fraction(3, 1), Fraction(3, 1))
>>> knotvector = KnotVector([0., 0., 0.5, 1., 1.])
>>> knotvector.convert(int)
ValueError: Cannot convert knot 0.5 from type <class 'float'> to type <class 'int'>
normalize() KnotVector[source]

Shift and scale the vector to match the interval [0, 1]

Returns:

The same instance

Return type:

KnotVector

Example use

>>> from fractions import Fraction
>>> from compmec.nurbs import KnotVector
>>> vector = [1, 1, 2, 3, 3]
>>> knotvector = KnotVector(vector)
>>> knotvector.normalize()
(0., 0., 0.5, 1., 1.)
>>> vector = [2, 2, 3, 4, 4]
>>> knotvector = KnotVector(vector)
>>> knotvector.convert(Fraction)
>>> knotvector.normalize(Fraction)
(Fraction(0, 1), Fraction(0, 1), Fraction(1, 2), Fraction(1, 1), Fraction(1, 1))
insert(nodes: Tuple[float]) KnotVector[source]

Insert given nodes inside knotvector

Parameters:

nodes (tuple[float]) – The nodes to be inserted

Raises:

ValueError – If cannot insert knots

Returns:

The same instance

Return type:

KnotVector

Example use

>>> from fractions import Fraction
>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0, 0, 2, 3, 3])
>>> knotvector.insert([2])
(0, 0, 2, 2, 3, 3)
>>> knotvector.insert([2])
ValueError: Cannot insert nodes [2] in knotvector (0, 0, 2, 2, 3, 3)"
>>> knotvector += [1]  # Same as insert([1])
(0, 0, 1, 2, 2, 3, 3)
remove(nodes: Tuple[float]) KnotVector[source]

Remove given nodes inside knotvector

Parameters:

nodes (tuple[float]) – The nodes to be remove

Raises:

ValueError – If cannot remove knots

Returns:

The same instance

Return type:

KnotVector

Example use

>>> from fractions import Fraction
>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0, 0, 1, 2, 3, 3])
>>> knotvector.remove([2])
(0, 0, 1, 3, 3)
>>> knotvector.remove([2])
ValueError: Cannot remove nodes [2] in knotvector (0, 0, 1, 3, 3)"
>>> knotvector -= [1]  # Same as remove([1])
(0, 0, 3, 3)
span(nodes: float | Tuple[float]) int | Tuple[int][source]

Finds the index position of a node such knotvector[span] <= node < knotvector[span+1]

If nodes is a vector of numbers, it returns a vector of indexs

Parameters:

nodes (float | tuple[float]) – A node to compute the span, or a list of nodes

Raises:
  • TypeError – If nodes is not a list of numbers

  • ValueError – If at least one node is outside [umin, umax]

Returns:

The index of the node

Return type:

int | tuple[int]

Example use

>>> from compmec.nurbs import KnotVector
>>> vector = [0, 0, 1, 2, 2]
>>> knotvector = KnotVector(vector)
>>> knotvector.span(0)
1
>>> knotvector.span(0.5)
1
>>> knotvector.span(1)
2
>>> knotvector.span([0, 0.5, 1, 1.5, 2])
(1, 1, 2, 2, 2)
mult(nodes: float | Tuple[float]) int | Tuple[int][source]

Counts how many times a node is inside the knotvector

If nodes is a vector of numbers, it returns a list of mult

Parameters:

nodes (float | tuple[float]) – The node to count, or a list of nodes

Raises:
  • TypeError – If nodes is not a number or a list of numbers

  • ValueError – If the node is outside [umin, umax]

Returns:

The index of the node

Return type:

int | tuple[int]

Example use

>>> from compmec.nurbs import KnotVector
>>> vector = [0, 0, 1, 2, 2]
>>> knotvector = KnotVector(vector)
>>> knotvector.mult(0)
2
>>> knotvector.mult(1)
1
>>> knotvector.mult(0.5)
0
>>> knotvector.mult([0, 0.5, 1, 1.2, 1.8, 2])
(2, 0, 1, 0, 0, 2)
valid(nodes: Tuple[float]) bool[source]

Tells if all given nodes are valid

Parameters:

nodes (tuple[float]) – The list of nodes

Raises:

TypeError – If nodes is not a list of numbers

Returns:

If all the nodes are in the interval [umin, umax]

Return type:

bool

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0, 0, 1, 1])
>>> knotvector.valid([0, 0.5, 1])
True
>>> knotvector.valid([-1, 0.5, 1])
False
split(nodes: Tuple[float]) Tuple[KnotVector][source]

Split the knot vector at given nodes

Parameters:

nodes (tuple[float]) – The list of nodes

Raises:

TypeError – If nodes is not a list of numbers

Returns:

The list of splited knot vectors

Return type:

tuple[KnotVector]

Example use

>>> from compmec.nurbs import KnotVector
>>> knotvector = KnotVector([0, 0, 1, 1])
>>> knotvector.split([0.5])
((0, 0, 0.5, 0.5), (0.5, 0.5, 1, 1))
class nurbs.Function(knotvector: KnotVector)[source]

Basis Function class, to evaluate functions

Example use

>>> import numpy as np
>>> from compmec.nurbs import Function
>>> knotvector = [0, 0, 1, 1]
>>> basis = Function(knotvector)
>>> basis.degree
1
>>> basis.npts
2
>>> basis(0.5)  # same as basis[:, degree](0.5)
(0.5, 0.5)
>>> basis([0, 0.5, 1])
((0, 0.5, 1), (1, 0.5, 0))
class nurbs.Curve(knotvector: KnotVector, ctrlpoints: ndarray | None = None, weights: ndarray | None = None)[source]
eval(nodes: float | Tuple[float]) Any | Tuple[Any][source]

Point evaluation function

Parameters:

nodes (float | tuple[float]) – The nodes to evaluates

Raises:
  • TypeError – If nodes is not a number or a list of numbers

  • ValueError – If at least node is outside [umin, umax]

Returns:

The point computed by using control points

Return type:

Any | tuple[Any]

Example use

>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0.5, 1, 1])
>>> curve.ctrlpoints = (1, 2, -3)
>>> curve(0)
1.0
>>> curve(0.2)
1.4
>>> curve(0.5)]
2.0
>>> curve([0, 0.5, 1])
(1.0, 2.0, -3.0)
knot_insert(nodes: Tuple[float]) None[source]

Insert given nodes inside knotvector

Parameters:

nodes (tuple[float]) – The nodes to be inserted

Raises:
  • TypeError – If nodes is not a number or a list of numbers

  • ValueError – If it’s not possible to insert the knots

Example use

>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0.5, 1, 1])
>>> curve.ctrlpoints = (1, 2, -3)
>>> curve.knot_insert([0.2, 0.7])
>>> curve.knotvector
(0, 0, 0.2, 0.5, 0.7, 1, 1)
knot_remove(nodes: Tuple[float], tolerance: float = 1e-09) None[source]

Remove given nodes from knotvector

Parameters:
  • nodes (tuple[float](, optional)) – The nodes to be removed

  • tolerance (float(, optional)) – Tolerance to remove knots, defaults to 1

  • nodes – Nodes to be assure to, defaults to None

Raises:
  • TypeError – If nodes is not a number or a list of numbers

  • ValueError – If it’s not possible to remove the knot

Example use

>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0, 0.5, 1, 1, 1])
>>> curve.ctrlpoints = [1, 1.5, -0.5, -3]
>>> print(curve)
Spline curve of degree 2 and 4 control points
KnotVector = (0, 0, 0, 0.5, 1, 1, 1)
ControlPoints = [1, 1.5, -0.5, -3]
>>> curve.knot_remove([0.5])
>>> print(curve)
Bezier curve of degree 2 and 3 control points
KnotVector = (0, 0, 0, 1, 1, 1)
ControlPoints = [1.0, 2.0, -3.0]
knot_clean(nodes: Tuple[float] | None = None, tolerance: float | None = 1e-09) None[source]

Remove all unnecessary knots.

If no nodes are given, it tries to remove all internal knots

Nothing happens if the curve is irreductible

Nodes equals to extremities are ignored

Nodes which are not in knotvectors are ignored

Parameters:
  • nodes (tuple[float](, optional)) – The nodes to be removed, defaults to None, all internal knots

  • tolerance (float(, optional)) – The tolerance to remove knots, defaults to 1e-9

Raises:
  • TypeError – If nodes is not a number or a list of numbers

  • TypeError – If tolerance is not a number

  • ValueError – If tolerance is negative

Example use

>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0, 0.5, 1, 1, 1])
>>> curve.ctrlpoints = [1, 1.5, -0.5, -3]
>>> print(curve)
Spline curve of degree 2 and 4 control points
KnotVector = (0, 0, 0, 0.5, 1, 1, 1)
ControlPoints = [1, 1.5, -0.5, -3]
>>> curve.knot_clean()
>>> print(curve)
Bezier curve of degree 2 and 3 control points
KnotVector = (0, 0, 0, 1, 1, 1)
ControlPoints = [1.0, 2.0, -3.0]
degree_increase(times: int | None = 1)[source]

Increase the degree of the curve by an amount times

Parameters:

times (int(, optional)) – The number of times to increase, defaults to 1

Raises:

AssertionError – If times is not a integer >= 0

Example use

>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0, 0.5, 1, 1, 1])
>>> curve.ctrlpoints = [1, 1.5, -0.5, -3]
>>> print(curve)
Spline curve of degree 2 and 4 control points
KnotVector = (0, 0, 0, 0.5, 1, 1, 1)
ControlPoints = [1, 1.5, -0.5, -3]
>>> curve.degree_increase(1)
>>> print(curve)
Spline curve of degree 3 and 6 control points
KnotVector = (0, 0, 0, 0, 0.5, 0.5, 1, 1, 1, 1)
ControlPoints = [1.0, 1.33, 1.17, -0.17, -1.33, -3.0]
degree_decrease(times: int | None = 1, tolerance: float | None = 1e-09)[source]

Decrease the degree of the curve by an amount times

Parameters:
  • times (int(, optional)) – The number of times to reduce degree, defaults to 1

  • tolerance (float(, optional)) – Tolerance to remove knots, defaults to 1

Raises:

AssertionError – If times is not a integer >= 0

Example use

>>> from compmec.nurbs import Curve
>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0, 0, 0.5, 0.5, 1, 1, 1, 1])
>>> curve.ctrlpoints = [1, 4/3, 7/6, -1/6, -4/3, -3]
>>> print(curve)
Spline curve of degree 3 and 6 control points
KnotVector = (0, 0, 0, 0, 0.5, 0.5, 1, 1, 1, 1)
ControlPoints = [1.0, 1.33, 1.17, -0.17, -1.33, -3.0]
>>> curve.degree_decrease(1)
>>> print(curve)
Spline curve of degree 2 and 4 control points
KnotVector = (0, 0, 0, 0.5, 1, 1, 1)
ControlPoints = [1, 1.5, -0.5, -3]
degree_clean(tolerance: float = 1e-09)[source]

Reduces au maximum the degree of the curve for given tolerance.

Does nothing if cannot reduce the degree

Parameters:

tolerance (float(, optional)) – The tolerance to reduce degree, defaults to 1e-9

Raises:

AssertionError – If tolerance is not a number >= 0

Example use

>>> from compmec.nurbs import Curve
>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0, 0, 0.5, 0.5, 1, 1, 1, 1])
>>> curve.ctrlpoints = [1, 4/3, 7/6, -1/6, -4/3, -3]
>>> print(curve)
Spline curve of degree 3 and 6 control points
KnotVector = (0, 0, 0, 0, 0.5, 0.5, 1, 1, 1, 1)
ControlPoints = [1.0, 1.33, 1.17, -0.17, -1.33, -3.0]
>>> curve.degree_clean()
>>> print(curve)
Spline curve of degree 2 and 4 control points
KnotVector = (0, 0, 0, 0.5, 1, 1, 1)
ControlPoints = [1, 1.5, -0.5, -3]
clean(tolerance: float = 1e-09)[source]

Calls degree_clean and knot_clean

If the curve is rational, it tries to simplify,

Parameters:

tolerance (float(, optional)) – The tolerance to reduce degree, defaults to 1e-9

Raises:

AssertionError – If tolerance is not a number >= 0

Example use

>>> from compmec.nurbs import Curve
>>> from compmec.nurbs import Curve
>>> curve = Curve([0, 0, 0, 0, 0.5, 0.5, 1, 1, 1, 1])
>>> curve.ctrlpoints = [1, 4/3, 7/6, -1/6, -4/3, -3]
>>> print(curve)
Spline curve of degree 3 and 6 control points
KnotVector = (0, 0, 0, 0, 0.5, 0.5, 1, 1, 1, 1)
ControlPoints = [1.0, 1.33, 1.17, -0.17, -1.33, -3.0]
>>> curve.degree_clean()
>>> print(curve)
Spline curve of degree 2 and 4 control points
KnotVector = (0, 0, 0, 0.5, 1, 1, 1)
ControlPoints = [1, 1.5, -0.5, -3]
split(nodes: Tuple[float] | None = None) Tuple[Curve][source]

Separate the current curve at specified nodes

If no arguments are given, it splits at every knot, returning a list of bezier curves

Parameters:

nodes – The positions to split, defaults to None, all internal nodes

Example use

>>> from compmec.nurbs import Curve
>>> knotvector = (0, 0, 0, 0.5, 1, 1, 1)
>>> ctrlpoints = [2, 1, 3, 0]
>>> curve = Curve(knotvector, ctrlpoints)
>>> subcurves = curve.split([0.2, 0.8])
>>> len(subcurves)
3
>>> subcurves[0].knotvector
(0.0, 0.0, 0.0, 0.2, 0.2, 0.2)
>>> subcurves[1].knotvector
(0.2, 0.2, 0.2, 0.5, 0.8, 0.8, 0.8)
>>> subcurves[2].knotvector
(0.8, 0.8, 0.8, 1.0, 1.0, 1.0)
fit_curve(other: Curve, nodes: Tuple[float] | None = None) float[source]

Finds the control points such this curve keeps as near as possible to other

If nodes are given

  • if len(nodes) < npts

    interpolates all nodes, uses least square in the other degrees of freedom

  • if len(nodes) == npts

    interpolate at all points

  • if len(nodes) > npts:

    same as fit_points(other(nodes), nodes)

Parameters:
  • other (Curve) – The objective curve

  • nodes (None | tuple[float](, optional)) – The positions to fit, defaults to None

Example use

>>> from compmec.nurbs import Curve
>>> knotvector = (0, 0, 0, 0.5, 1, 1, 1)
>>> ctrlpoints = [2, 1, 3, 0]
>>> curvea = Curve(knotvector, ctrlpoints)
>>> curveb = Curve([0, 0, 0.5, 1, 1])
>>> curveb.fit_curve(curvea)
>>> print(curveb)
Spline curve of degree 1 and 3 control points
KnotVector = (0, 0, 0.5, 1, 1)
ControlPoints = [1.417, 2.167, 0.917]
fit_function(function: Callable, nodes: Tuple[float] | None = None) None[source]

Finds the control points such this curve keeps as near as possible to function

If nodes are not given, it uses least square in many intervals

for subinterval [uk, u_{k+1}] evaluates on max(degree+1, 5*npts/len(subintervals)) using chebyshev nodes

  • if len(nodes) < npts

    interpolates all nodes, uses least square in the other degrees of freedom

  • if len(nodes) == npts

    interpolate at all points

  • if len(nodes) > npts:

    same as fit_points(other(nodes), nodes)

Parameters:
  • other (Curve) – The objective curve

  • nodes (None | tuple[float](, optional)) – The positions to fit, defaults to None

Example use

>>> from compmec.nurbs import Curve
>>> knotvector = (0, 0, 0.5, 1, 1)
>>> curve = Curve(knotvector)
>>> function = lambda x: 1 + x**2
>>> curve.fit_function(function)
>>> print(curve)
Spline curve of degree 1 and 3 control points
KnotVector = (0, 0, 0.5, 1, 1)
ControlPoints = [0.969, 1.219, 1.969]
fit_points(points: Tuple[Any], nodes: Tuple[float] | None = None) None[source]

Finds the control points such this curve keeps as near as possible to points

If nodes are not given, it supposes equally distributed nodes

  • if len(points) < npts

    ValueError

  • if len(nodes) == npts

    interpolate at all points

  • if len(nodes) > npts:

    Uses discrete least squares

Parameters:
  • points (tuple[any]) – The objective points

  • nodes (None | tuple[float](, optional)) – The positions to fit, defaults to None, equally distributed points

Example use

>>> import numpy as np
>>> from compmec.nurbs import Curve
>>> knotvector = (0, 0, 0.5, 1, 1)
>>> curve = Curve(knotvector)
>>> function = lambda x: 1 + x**2
>>> usample = np.linspace(0, 1, 129)
>>> points = function(usample)
>>> curve.fit_points(points)
>>> print(curve)
Spline curve of degree 1 and 3 control points
KnotVector = (0, 0, 0.5, 1, 1)
ControlPoints = [0.96, 1.21, 1.96]
fit(param: Curve | Callable[[float], float] | Tuple[Any], nodes: Tuple[float] | None = None) None[source]

Calls fit_curve, fit_function or fit_points depending on param

class nurbs.calculus.Derivate(curve: Curve)[source]
class nurbs.calculus.Integrate[source]
static scalar(curve: Curve, function: Callable[[float], Any] | None = None, method: str | None = None, nnodes: int | None = None) float[source]

Computes the integral I

If no function is given, it supposes that \(g(u)=1\)

If no method = (algo, npts) is given

  • If knotvector number type is int or Fraction
    • npts = 1 + curve.degree

    • algo = "closed-newton-cotes"

  • Else
    • npts = 1 + curve.degree

    • algo = "chebyshev"

Valid algorithms algo are closed-newton-cotes, open-newton-cotes, chebyshev or gauss-legendre

Parameters:
  • curve (Curve) – The curve \(\mathbf{C}(u)\) to integrate

  • function (None | callable[[float], Any](, optional)) – The weight function \(g(u)\), defaults to None

  • method (None | tuple[str, int](, optional)) – The integration method, defaults to None

static lenght(curve: Curve, function: Callable[[float], Any] | None = None, method: str | None = None, nnodes: int | None = None) float[source]

Computes the integral I

The operation @ is needed cause norm(curve(u)) = numpy.sqrt(curve(u) @ curve(u))

If no function is given, it supposes that \(g(u)=1\)

If method == None:
  • If knotvector number type is int or Fraction
    • method = "closed-newton-cotes"

  • Else
    • npts = 1 + curve.degree

    • method = "chebyshev"

Valid algorithms algo are closed-newton-cotes, open-newton-cotes, chebyshev or gauss-legendre

Parameters:
  • curve (Curve) – The curve \(\mathbf{C}(u)\) to integrate

  • function (None | callable[[float], Any](, optional)) – The weight function \(g(u)\), defaults to None

  • method (None | tuple[str, int](, optional)) – The integration method, defaults to None

static density(curve: Curve, function: Callable[[float], Any] | None = None, method: str | None = None, nnodes: int | None = None) float[source]

Computes the integral I

The operation @ is needed cause norm(curve(u)) = numpy.sqrt(curve(u) @ curve(u))

If no function is given, it supposes that \(g(u)=1\)

If no method = (algo, npts) is given

  • If knotvector number type is int or Fraction
    • npts = 1 + curve.degree

    • algo = "closed-newton-cotes"

  • Else
    • npts = 1 + curve.degree

    • algo = "chebyshev"

Valid algorithms algo are closed-newton-cotes, open-newton-cotes, chebyshev or gauss-legendre

Parameters:
  • curve (Curve) – The curve \(\mathbf{C}(u)\) to integrate

  • function (None | callable[[float], Any](, optional)) – The weight function \(g(u)\), defaults to None

  • method (None | tuple[str, int](, optional)) – The integration method, defaults to None

static function(knotvector: KnotVector, function: Callable[[float], Any] | None, method: str | None = None, nnodes: int | None = None) float[source]

Computes the integral I

\[I = \int_{a}^{b} g ( u ) \ du\]

The operation @ is needed cause norm(curve(u)) = numpy.sqrt(curve(u) @ curve(u))

If no function is given, it supposes that \(g(u)=1\)

If no method = (algo, npts) is given

  • If knotvector number type is int or Fraction
    • npts = 1 + curve.degree

    • algo = "closed-newton-cotes"

  • Else
    • npts = 1 + curve.degree

    • algo = "chebyshev"

Valid algorithms algo are closed-newton-cotes, open-newton-cotes, chebyshev or gauss-legendre

Parameters:
  • curve (Curve) – The curve \(\mathbf{C}(u)\) to integrate

  • function (None | callable[[float], Any](, optional)) – The weight function \(g(u)\), defaults to None

  • method (None | tuple[str, int](, optional)) – The integration method, defaults to None

class nurbs.advanced.Projection[source]

Projection class to evaluate the nearest point/curve with respect to another point/curve

static point_on_bezier(point: Tuple[float], bezier: Curve) Tuple[float][source]

Finds the parameters t* such bezier(t*) is the near point

static point_on_curve(point: Tuple[float], curve: Curve) Tuple[float][source]

Finds the parameters t* such curve(t*) is near point

This function finds the parameter tstar in [tmin, tmax] such minimizes the distance abs(curve(tstar) - point).

Trully, it minimizes the distance square, related to the inner product < C(u) - P, C(u) - P > = abs(C(u)-P)^2 This function finds the solution of f(u) = < C’(u), C(u) - P > = 0

Since it’s possible to have more than one solution: for example, the center of a circle is at equal distance always then we return a list of parameters

First, we decompose the curve in beziers, and try to find the minimum distance of each bezier curve. We use Newton’s method

class nurbs.advanced.Intersection[source]

Intersection static class, responsible to compute the intersection between two objects, like curve and curve, surface and curve, and so on

static filter_pairs(pairs: Tuple[Tuple[float]], tolerance: float = 1e-09)[source]

Filter the repeted knots within a given tolerance

static pairs_min_distance(pairs: Tuple[float], curvea: Curve, curveb: Curve, tolerance: float = 1e-09)[source]

Filter the pairs (t*, u*) such abs(curvea(t*) - curveb(u*)) > tolerance

static bcurve_and_bcurve(beziera: Curve, bezierb: Curve) Tuple[float, float][source]

Return the parameters t*, u* such beziera(t*) = bezierb(u*)

Given two bezier curves, A(t) and B(u), this function returns the intersections between A and B. It can be:

  • If A(t) don’t touch B(u), returns empty tuple

  • If A(t) touches B(u) in a finite number of points, it returns

    the pairs [(ta, ua), (tb, ub), …, (tk, uk)]

  • If A(t) overlaps B(u) in some interval, it returns

    The interval [(ta, tb), (ua, ub)] Still needs implementation

static curve_and_curve(curvea: Curve, curveb: Curve) Tuple[Curve][source]

Return the parameters t*, u* such curvea(t*) = curveb(u*)

Given two curves, A(t) and B(u), this function returns the intersections between A and B. It can be:

  • If A(t) don’t touch B(u), returns empty tuple

  • If A(t) touches B(u) in a finite number of points, it returns

    the pairs [(ta, ua), (tb, ub), …, (tk, uk)]

  • If A(t) overlaps B(u) in some interval, it returns

    The interval [(ta, tb), (ua, ub)]