TinySpline

repository·master·Indexed 23 days ago

https://github.com/msteinbeck/tinyspline

A lightweight library for interpolating, transforming, and querying NURBS, B-Splines, and Bézier curves. Written in ANSI C with a C++ wrapper, it provides bindings for Python, Go, Java, C#, Lua, Ruby, and others. Key features include natural cubic and Catmull-Rom interpolation, rotation minimizing frames (RMF), arc-length reparametrization via ChordLengths, and spline morphing.

Tokens
3K
Snippets
6
Records
17
Agent score
79%

What's inside TinySpline

  1. Understand the B-Spline hierarchy and relationship

    master

    TinySpline works with a hierarchy of spline types where each type is a specialized version of the one above it. The relationship is defined as follows:

    NURBS > BSPLINES > BEZIERS > LINES > POINTS

    This means every point can be treated as a line, every line as a Bézier curve, every Bézier curve as a B-Spline, and every B-Spline as a NURBS curve.

  2. Understand B-Spline attributes and domain

    master

    A B-Spline is defined by four primary attributes:

    1. Degree (p): Describes the general smoothness of the spline.
    2. Control Points (m): Points used to shape the spline.
    3. Knot Vector (knots): A monotonically increasing sequence of values used to define continuity at specific points (not the control points).
    4. Dimension: The number of components per control point (e.g., 2D uses (x, y)).

    Mathematical Constraints

    • Knot Count: For a B-Spline of degree p with m control points, the number of knots n is calculated as n = m + p + 1.
    • Domain: The valid range for evaluating the spline is between the p-th knot and the (n-p)-th knot. You can only retrieve points by evaluating the spline at a value u where u_p <= u <= u_{n-p}.
    • Knot Multiplicity and Continuity: The multiplicity s(u) (how many times a knot value repeats) must not exceed the order of the spline (p + 1). The continuity at a knot u is C^{p-s(u)}. Increasing the multiplicity of a knot decreases the spline's continuity at that point.
  3. Install C and C++ interfaces

    master

    You can install the C and C++ interfaces to your system using the CMake install target. This also installs CMake config scripts and pkg-config files.

    Using in CMake projects

    Use find_package(tinyspline) for the C interface or find_package(tinysplinecxx) for the C++ interface.

    Exported Variables

    C Interface:

    • TINYSPLINE_INCLUDE_DIRS: Header file locations.
    • TINYSPLINE_LIBRARY_DIRS: Library locations.
    • TINYSPLINE_LIBRARIES: Shared libraries to link.
    • TINYSPLINE_DEFINITIONS: Definitions for add_definitions.
    • TINYSPLINE_VERSION: Version string.

    C++ Interface: Uses the same variable names but with the TINYSPLINECXX_ prefix (e.g., TINYSPLINECXX_INCLUDE_DIRS).

    cmake --build . --target install
  4. Enable specific language interfaces during build

    master

    By default, the C interface is always enabled and the C++ interface is enabled unless explicitly disabled. To build specific language bindings, use the -DTINYSPLINE_ENABLE_<LANGUAGE> flag during the CMake configuration step.

    To enable all interfaces at once, use -DTINYSPLINE_ENABLE_ALL_INTERFACES=True.

    # Build only the Python interface
    cmake -DTINYSPLINE_ENABLE_PYTHON=True ..
    cmake --build . tinysplinepython
    
    # Build all interfaces
    cmake -DTINYSPLINE_ENABLE_ALL_INTERFACES=True ..
    cmake --build .
  5. Build TinySpline from source

    master

    TinySpline uses CMake to compile its interfaces. The build requires a compiler suite like GCC, Clang, or MSVC. To create language bindings, Swig (4.1.0 or later) must be installed.

    Follow these steps to perform a standard build:

    1. Clone the repository and enter the directory.
    2. Create and enter a build directory.
    3. Run CMake and build the project.

    Compiled libraries and packages are located in tinyspline/build/lib after a successful build.

    git clone https://github.com/msteinbeck/tinyspline.git tinyspline
    cd tinyspline
    
    mkdir build
    cd build
    
    cmake ..
    cmake --build .
  6. Install TinySpline via package managers

    master

    TinySpline is available through several package managers depending on your target language:

    • C# (NuGet): Use <PackageReference Include="tinyspline" Version="0.6.0.1" />.
    • Go: Use go get github.com/tinyspline/go@v0.6.0.
    • Lua (Luarocks): Use luarocks install --server=https://tinyspline.github.io/lua tinyspline.
    • Java (Maven): Add the org.tinyspline:tinyspline:0.6.0-1 dependency.
    • Python (PyPI): Use python -m pip install tinyspline.
    • Ruby (RubyGems): Use gem install tinyspline.
    • C/C++ (Conan): Available on Conan Center.

    Pre-built binaries can also be downloaded from the official releases page.

    <PackageReference Include="tinyspline" Version="0.6.0.1" />
    go get github.com/tinyspline/go@v0.6.0
    luarocks install --server=https://tinyspline.github.io/lua tinyspline
    <dependency>
       <groupId>org.tinyspline</groupId>
       <artifactId>tinyspline</artifactId>
       <version>0.6.0-1</version>
    </dependency>
    python -m pip install tinyspline
    gem install tinyspline
  7. Configure Python version for bindings

    master
    Swig distinguishes between Python 2 and Python 3 using -py and -py3 flags. CMake automatically selects the most recent version of Python found on your system. If you need to force a specific version, use the TINYSPLINE_PYTHON_VERSION CMake option.
  8. Compute rotation minimizing frames (RMF)

    master

    To compute rotation minimizing frames (RMF) along a spline, first generate an equidistant sequence of knots using equidistant_knot_seq(n), then pass those knots to compute_rmf(knots). The resulting frames allow you to access the position, normal, tangent, and binormal at each knot.

    knots = spline.equidistant_knot_seq(15)
    frames = spline.compute_rmf(knots)
    for i in range(frames.size()):
        pos = frames.at(i).position
        nor = pos + frames.at(i).normal * 20
        # You can also fetch the tangent and binormal:
        #     frames.at(i).tangent
        #     frames.at(i).binormal
        plt.plot([pos.x, nor.x], [pos.y, nor.y], 'g')
  9. Interpolate and evaluate a B-Spline in Python

    master

    You can create a B-Spline using cubic natural interpolation by providing a flat list of coordinates and the dimensionality of the points. Once created, you can sample points along the spline, evaluate the position at a specific knot, or compute derivatives (tangents).

    from tinyspline import *
    import matplotlib.pyplot as plt
    
    spline = BSpline.interpolate_cubic_natural(
      [
         100, -100, # P1
        -100,  200, # P2
         100,  400, # P3
         400,  300, # P4
         700,  500  # P5
      ], 2) # <- dimensionality of the points
    
    # Draw spline as polyline.
    spline.sample(100)
    
    # Draw point at knot 0.3.
    vec2 = spline.eval(0.3).result_vec2()
    
    # Draw tangent at knot 0.7.
    pos = spline(0.7).result_vec2() # operator () -> eval
    der = spline.derive()(0.7).result_vec2().normalize() * 200
  10. Language dependencies and output directories

    master

    When building bindings, certain languages require specific headers or tools.

    LanguageDependencies to Generate Source(Relative) Output Directory
    C#-csharp
    D-dlang
    Golang-go
    JavaJava Development Kitjava/org/tinyspline
    LuaLua headerslua
    OctaveOctave headersoctave
    PHPPHP (Zend) headers *php
    PythonPython headerspython
    RR headers and RCPPr
    RubyRuby headersruby
    • Note: On macOS, use a package manager like Homebrew to get PHP Zend headers.

    Required tools for creating binary packages:

    • C#: csc, mcs, dmcs, or gmcs (outputs TinySpline.dll)
    • Java: javac and jar from JDK (outputs tinyspline.jar)
  11. Evaluate spline points using DeBoorNet

    master

    The DeBoorNet class provides a way to evaluate the spline at a specific knot using the De Boor algorithm. It is returned by calling BSpline::eval(real knot) or using the operator()(real knot).

    Capabilities:

    • Access the knot value, index, and multiplicity.
    • Retrieve the result at a specific index as a Vec2, Vec3, or Vec4 using resultVec2(idx), resultVec3(idx), or resultVec4(idx). These methods are safe to call even if the spline dimension is lower than the requested vector dimension (missing components are set to 0).
  12. Use VecMath for static vector operations

    master

    When using the Emscripten build, the VecMath class provides static methods to perform vector operations without needing to manage object instances manually. This is useful for functional-style programming.

    Available Methods:

    • add2, add3, add4
    • subtract2, subtract3, subtract4
    • multiply2, multiply3, multiply4
    • cross3 (3D only)
    • normalize2, normalize3, normalize4
    • magnitude2, magnitude3, magnitude4
    • dot2, dot3, dot4
    • angle2, angle3, angle4
    • distance2, distance3, distance4