{"id":21169573,"url":"https://github.com/pellaeon/tinyspline-example","last_synced_at":"2025-07-09T19:31:51.225Z","repository":{"id":146908331,"uuid":"45166667","full_name":"pellaeon/tinyspline-example","owner":"pellaeon","description":null,"archived":false,"fork":false,"pushed_at":"2015-10-29T09:19:06.000Z","size":1648,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-03-24T11:29:45.539Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pellaeon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-29T07:15:09.000Z","updated_at":"2023-04-11T10:39:57.806Z","dependencies_parsed_at":"2023-04-11T10:47:37.391Z","dependency_job_id":null,"html_url":"https://github.com/pellaeon/tinyspline-example","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellaeon%2Ftinyspline-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellaeon%2Ftinyspline-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellaeon%2Ftinyspline-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pellaeon%2Ftinyspline-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pellaeon","download_url":"https://codeload.github.com/pellaeon/tinyspline-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225587811,"owners_count":17492632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-20T15:52:31.843Z","updated_at":"2024-11-20T15:52:32.611Z","avatar_url":"https://github.com/pellaeon.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"TinySpline\n========\n\nTinySpline is a C library for \n[NURBS](https://de.wikipedia.org/wiki/Non-Uniform_Rational_B-Spline),\n[B-Splines](https://en.wikipedia.org/wiki/B-spline) and\n[Bézier curves](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)\n(even lines and points) with a modern C++11 wrapper and bindings for C#,\nJava and Python (via Swig). The goal of this project is to provide a small\nlibrary with a minimum set of dependencies which is easy and intuitively to\nuse. Moreover, the integration of TinySpline into OpenGL is straightforward.\n\nTinySpline is licensed under [the MIT License](http://opensource.org/licenses/MIT),\nhence feel free to use it anywhere.\n\n###Table of Contents\n- [Some Features of This Library](#features)\n- [Project Structure](#structure)\n- [Bindings](#bindings)\n- [API](#api)\n  - [Data Structures](#structs)\n  - [NURBS, B-Splines, Béziers, Lines and Points](#types)\n  - [Functions](#functions)\n  - [Memory Management](#memory)\n  - [Error Handling](#error)\n  - [OpenGL Integration](#opengl)\n  - [Spline Evaluation and Discontinuity](#evaldisc)\n- [Current Development](#development)\n- [Theoretical Backgrounds](#backgrounds)\n- [Installation](#installation)\n\n\u003ca name=\"features\" /\u003e\n###Some Features of This Library\n- TinySpline provides NURBS, B-Splines, Béziers, lines and points within a single struct.\n- Create splines of any degree with any dimensions.\n- Perform cubic spline interpolation using [Thomas' algorithm](https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm).\n- Evaluate splines using [De Boor's algorithm](https://en.wikipedia.org/wiki/De_Boor%27s_algorithm).\n- Insert knots and split splines while keeping the splines shape.\n- Subdivide B-Splines into Béziers.\n- A C++11 wrapper.\n- Bindings for C#, Java and Python.\n\n\u003ca name=\"structure\" /\u003e\n###Project Structure\nThe core of TinySpline is written in ANSI C and consists of the files\n[tinyspline.h](https://github.com/retuxx/tinyspline/blob/master/library/tinyspline.h) \nand [tinyspline.c](https://github.com/retuxx/tinyspline/blob/master/library/tinyspline.c).\nYou can either copy those files into your project or use CMake to create\na static or shared library.\n\nThe C++11 wrapper consists of the files [tinysplinecpp.h](https://github.com/retuxx/tinyspline/blob/master/library/tinysplinecpp.h)\nand [tinysplinecpp.cpp](https://github.com/retuxx/tinyspline/blob/master/library/tinysplinecpp.cpp).\nAs for the C library, you can copy those files (alongside tinyspline.h and\ntinyspline.c) into your project or use CMake to create a static or shared library.\n\nAll bindings of TinySpline work on top of the C++11 wrapper and will be \ngenerated with [Swig](http://www.swig.org/) (3.0.1 or above). While\n[tinyspline.i](https://github.com/retuxx/tinyspline/blob/master/library/tinyspline.i)\nconfigures all language independent settings, tinysplineXYZ.i adds\nlanguage related features. The file \n[swig_wrapper.h](https://github.com/retuxx/tinyspline/blob/master/library/swig_wrapper.h)\ncontains functions which are necessary to provide collections instead of plain C arrays.\nUsing CMake to create the bindings is recommended.\n\nAll these files can be found in the directory \n[library](https://github.com/retuxx/tinyspline/tree/master/library).\nThe directory \n[example](https://github.com/retuxx/tinyspline/tree/master/example) contains\nsome examples written in OpenGL.\n\n\u003ca name=\"bindings\" /\u003e\n###Bindings\nAlongside Swig, each binding may have additional dependencies to generate the \nsource code of the target language. The following table gives an overview:\n\nLanguage | Dependencies to Generate Source | (Relative) Output Directory\n-------- | ------------------------------- | ---------------------------\nC#       | -                               | csharp\nJava     | JNI headers                     | so/tinyspline\nPython   | Python headers                  | python\n\nBy design of Swig, each binding generates and compiles its own shared library\nwhich is necessary to use the binding. Depending on your operating system\nand the used compiler the actual names of the shared libraries may vary.\nThe following table shows the names of the shared libraries compiled with\nGCC on Linux:\n\nLanguage | Shared Library\n-------- | ----------------------\nC#       | libtinysplinecsharp.so\nJava     | libtinysplinejava.so\nPython   | _tinysplinepython.so\n\n**Note:** In order to use a binding make sure its shared library is available\nin the library path. Java does not load its shared libraries automatically.\nThus, you have to do it manually by placing the following code *before* the first\nuse of TinySpline:\n\n```java\n// loads the shared library\nSystem.loadLibrary(\"tinysplinejava\");\n```\n\nTo simplify the usage of the bindings, the generated source code will be compiled\nand/or packaged according to the target language idiom. The following table gives\nan overview of the neccessary tools and the resulting output files.\n\nLanguage | Necessary Tools                  | Output File\n-------- | -------------------------------- | ----------------\nC#       | Any of: csc, mcs, dmcs, gmcs     | tinysplinecs.dll\nJava     | javac and jar (available in JDK) | tinyspline.jar\nPython   | -                                | tinyspline.py*\n\n\\* The Python bindings are copied from the source code directory into\nthe build directory and may be renamed for convenience.\n\n\u003ca name=\"api\" /\u003e\n###API\n\n\u003ca name=\"structs\" /\u003e\n####Data Structures\nThe C library of TinySpline consists of two enums and two structs:\n\nName                   | Description\n---------------------- | -----------------------------------------------------\n`tsError` (enum)       | Defines some error codes\n`tsBSplineType` (enum) | Defines how to setup knots while creating splines\n`tsBSpline` (struct)   | The spline itself\n`tsDeBoorNet` (struct) | The result of spline evaluation (De Boor's algorithm)\n\nThe C++11 wrapper wraps `tsBSpline` and `tsDeBoorNet` into classes (namely \n`TsBSpline` and `TsDeBoorNet`) and maps functions into methods. Furthermore,\nconstructors and destructors are provided.\n\n\u003ca name=\"types\" /\u003e\n####NURBS, B-Splines, Béziers, Lines and Points\nLet `\u003e` be the [superset](https://en.wiktionary.org/wiki/superset) relation\nwith `A` is superset of `B` iff `A \u003e B`. Then the following equation applies:\n\n`NURBS \u003e B-Splines \u003e Béziers \u003e Lines \u003e Points`\n\nIt goes without saying that the struct `tsBSpline` can be used directly for\nB-Splines because it provides `control points` and `knots`. Now let's have\na look at Bézier curves. A Bézier curve `c` of degree `n` has `n + 1`\ncontrol points where `c` is tangent to control point `p_0` and tangent \nto control point `p_n`. The following code snippet shows how to create \na Bézier curve `c` of degree 3 in 2D:\n\n```c\ntsBSpline c;\nts_bspline_new(3, 2, 4, TS_CLAMPED, \u0026c);\n```\n\nThe first parameter is the degree (3) of `c` and the second one the\ndimension (2) of `c`. As already mentioned a Bézier curve has\n`n + 1` control points. Thus, the third parameter\n(number of control points) is 4. The enum `TS_CLAMPED` ensures that\n`c` is tangent to the first and last control point. That's it!\n\nBut wait... you may ask yourself what `tsBSpline.knots` looks like.\nDue to the fact that `c` is a Bézier curve and all Bézier curves are\nB-Splines, `c` actually **is** a B-Spline. Furthermore, a B-Spline of\ndegree `n` with `m` control points has `m + n + 1` knots. Thus, `c` has\n`3 + 4 + 1 = 8` knots. To ensure a B-Splines is tangent to the first and\nlast control point the first `n + 1` and the last `n + 1` knots need to\nbe equal. Since `c` has 8 knots the knot vector may look like:\n\n`[0, 0, 0, 0, 1, 1, 1, 1]`\n\n**Note:** Keep in mind that `u_i \u003c= u_i + 1` must apply for all knot\nvalues `u` and `i = 0...m + n - 1`. \n\nIn conclusion all knot values of `c` are either `0` or `1`.\nWithout getting too much into details, that's the reason why you\ndon't need to take care about the knot vector of `c` and \nBézier curves in general.\n\nAfter looking closely to Bézier curves it should be obvious how to\ncreate lines and points. Lines are Bézier curves of degree 1 with\n2 control points:\n\n```c\ntsBSpline line;\nts_bspline_new(1, dim, 2, TS_CLAMPED, \u0026line);\n```\n\nand points are just a very short lines (generally spoken). Actually\na point is of degree 0 with 1 control point:\n\n```c\ntsBSpline point;\nts_bspline_new(0, dim, 1, TS_CLAMPED, \u0026point);\n```\n\n**Note:** If you want to create a sequence of connected lines, you\njust have to increase the number of control points. A sequence of\n8 connected lines, for example, is of degree 1 with 9 control \npoints.\n\nFinally, we should have a look at NURBS. NURBS are generalizations\nof B-Splines and can be expressed by\n[homogeneous coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates).\nIf you want to create a NURBS of degree `n` with `m` control points\nin 3D, then you have to create a B-Spline of degree `n` with `m`\ncontrol points in 4D:\n\n```c\ntsBSpline nurbs;\nts_bspline_new(n, 4, m, TS_CLAMPED, \u0026nurbs);\n// setup homogeneous coordinates\n```\n\nThe forth component of the dimension is used to weight the other\nthree components. You can find  an example of a NURBS in\n[nurbs.c](https://github.com/retuxx/tinyspline/blob/master/example/nurbs.c).\n\n**Note:** All functions of TinySpline (e.g. `ts_bspline_evaluate`)\nare capable of handling NURBS, B-Splines, Béziers, lines and points.\n\n\u003ca name=\"functions\" /\u003e\n####Functions \nWith a few exceptions, all functions of the C library provide input and output\nparameter, where all input parameter are const. Except of the copy functions\n(`ts_***_copy`), the pointer of the input may be equal to the pointer of the\noutput. To modify a spline use, it as input and output at once:\n\n```c\ntsBSpline spline;\nts_bspline_new(3, 3, 7, TS_CLAMPED, \u0026spline); // create spline\nts_bspline_buckle(\u0026spline, 0.6f, \u0026spline); // modify spline\n...\n```\n\n\u003ca name=\"memory\" /\u003e\n####Memory Management\nDue to the fact that TinySpline provides generic splines in size, degree and\ndimension, the structs `tsBSpline` and `tsDeBoorNet` contain pointers to \ndynamically allocated memory. That means you have to free the memory using one \nof the `ts_***_free` functions to prevent memory leaks:\n\n```c\ntsBSpline spline; // allocated on stack\nts_bspline_new(3, 3, 7, TS_CLAMPED, \u0026spline); // create spline\n// do some cool stuff here\ntsDeBoorNet net;\nts_bspline_evaluate(\u0026spline, 0.5f, \u0026net);\n// do more cool stuff\nts_deboornet_free(\u0026net); // free dynamically allocated memory\nts_bspline_free(\u0026spline); // free dynamically allocated memory\n```\n\nThe C++11 wrapper wraps the call of `ts_***_free` into the destrcutor of\nthe wrapper class. Thus, you don't need to take care of memory management\nin C++ and the bindings.\n\n\u003ca name=\"error\" /\u003e\n####Error Handling\nThe error handling of TinySpline has been implemented with error codes.\nThe enum `tsError` contains all available errors and should be used to reuse\nerror codes over several functions. Error checking is straightforward:\n\n```c\ntsBSpline spline;\nconst tsError err = ts_bspline_new(3, 3, 7, TS_CLAMPED, \u0026spline);\nif (err \u003c 0) // or use err != TS_SUCCESS\n  // error\nelse\n  // no error\n```\n\nThe C++11 wrapper uses std::runtime_error instead. All bindings map \nstd::runtime_error into their own exception types.\n\n\u003ca name=\"opengl\" /\u003e\n####OpenGL Integration\nUsing TinySpline within OpenGL is simple because the structs provide \nall necessary fields.\n\n```c\ntsBSpline spline;\nts_bspline_new(3, 3, 7, TS_CLAMPED, \u0026spline); // create spline\n// setup control points\n\nGLUnurbsObj *theNurb = gluNewNurbsRenderer(); // is part of GLU\n// setup theNurb, have a look at: gluNurbsProperty, gluNurbsCallback etc.\n\n// draw spline\ngluBeginCurve(theNurb);\n  gluNurbsCurve(\n    theNurb, \n    spline.n_knots, \n    spline.knots, \n    spline.dim, \n    spline.ctrlp, \n    spline.order, // no need to calc deg + 1\n    GL_MAP1_VERTEX_3 // MAP1 = spline, VERTEX_3 = 3 dimensions\n  );\ngluEndCurve(theNurb);\n\n// draw evaluation at u = 0.5\ntsDeBoorNet net;\nts_bspline_evaluate(\u0026spline, 0.5f, \u0026net);\nglBegin(GL_POINTS);\n  glVertex3fv(net.result);\nglEnd();\n...\n```\n\nIf your spline is a Bézier curve, you can use the following code instead:\n\n```c\ntsBSpline spline;\nts_bspline_new(3, 2, 4, TS_CLAMPED, \u0026spline); // create bezier curve\n// setup control points\n\n// setup evaluator\nglMap1f(\n  GL_MAP1_VERTEX_3, // MAP1 = curve, VERTEX_3 = 3 dimensions\n  0.0, // u_min, usually 0 \n  1.0, // u_max, usually 1\n  spline.dim,\n  spline.order, // no need to calc deg + 1\n  spline.ctrlp\n);\nglEnable(GL_MAP1_VERTEX_3);\n\n// draw bezier curve\nglBegin(GL_LINE_STRIP);\n  for (i = 0; i \u003c= 30; i++) \n    glEvalCoord1f((GLfloat) i/30.0);\nglEnd();\n```\n\n\u003ca name=\"evaldisc\" /\u003e\n####Spline Evaluation and Discontinuity\nAlthough evaluating a spline at a given knot value is straightforward,\nthere are some notes you should know about.\n\n1. TinySpline uses floats for control points and knots. Now if you want \n   to evaluate a spline `s` at knot value `u`, the function `ts_bspline_evaluate`\n   tries to find `u` within the knot vector of `s` and count its multiplicity\n   (as part of [De Boor's algorithm](https://en.wikipedia.org/wiki/De_Boor%27s_algorithm)).\n   Because of comparing floats with `==` isn't a smart idea in general, TinySpline provides\n   its own float comparing function (namely `ts_fequals`) which uses absolute and relative \n   errors. To keep things valid, the field `tsDeBoorNet.u` contains the actual used knot\n   value and may only differ from the given `u` if the multiplicity of `u` is \n   greater than or equals to 1 and `u` is not `==` to `tsDeBoorNet.u` but \n   `ts_fequals(u, tsDeBoorNet.u) == 1`. If further calculations depend on the \n   exact value of `u` use `tsDeBoorNet.u` instead.\n\n2. As you perhaps know increasing the multiplicity of a knot `u` by 1 within a spline \n   `s` decreases the continuity of `s` by 1. The upper bound of the multiplicity of `u`\n   is equals to the order (degree + 1) of `s` (in this case `s` is C^-1 continuous\n   aka. discontinuous). Usually you will find this in clamped splines to ensure a \n   spline 'hits' the first and last control point. TODO... FINISH THIS.\n\n**Note:** Keep in mind that these are rare cases. Usually you do not need to take care of this.\n\n\u003ca name=\"development\" /\u003e\n###Current Development\n- Deriving splines.\n- Knot removal.\n- Given a point P and a spline S, find the Point Q on S with the \nminimal distance ||P - Q||\u003csub\u003e2\u003c/sub\u003e.\n- Bindings for Rust and Julia.\n\n\u003ca name=\"backgrounds\" /\u003e\n###Theoretical Backgrounds\n[[1]](http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/B-spline/bspline-curve.html)\n\u0026nbsp;\u0026nbsp; is a very good entry point for B-Splines.  \n[[2]](http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/B-spline/de-Boor.html)\n\u0026nbsp;\u0026nbsp; explains the De Boor's Algorithm and gives some pseudo code.  \n[[3]](http://www.codeproject.com/Articles/996281/NURBS-curve-made-easy)\n\u0026nbsp;\u0026nbsp; provides a good overview of NURBS with some mathematical background.  \n[[4]](http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/NURBS/NURBS-def.html)\n\u0026nbsp;\u0026nbsp; is useful if you want to use NURBS in TinySpline.\n\n\u003ca name=\"installation\" /\u003e\n###Installation\n\n####Compiling From Source\nTinySpline uses the CMake build system. The C library is written in \nANSI C and should be compilable with nearly every compiler. All\nother features of TinySpline are optional and will be disabled\nif CMake does not find the required dependencies (such as \nSwig and OpenGL).\n\n- Checkout the repository\n```bash\ngit clone git@github.com:retuxx/tinyspline.git tinyspline\ncd tinyspline\n```\n- Create a build directory\n```bash\nmkdir build\ncd build\n```\n- Create the Makefiles and build the library\n```bash\ncmake ..\nmake\n```\n\nYou will find all static and shared libraries, jars etc. in\n`tinyspline/build/library`\n\n####Cross Compiling\nTinySpline provides toolchain files for mingw and arm. Use the following\ncommand within your build directory for cross compiling\n```bash\ncmake -DCMAKE_TOOLCHAIN_FILE=\u003cpath to root dir of tinypsline\u003e/Toolchain-*.cmake ..\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpellaeon%2Ftinyspline-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpellaeon%2Ftinyspline-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpellaeon%2Ftinyspline-example/lists"}