494 lines
12 KiB
C++
494 lines
12 KiB
C++
|
/*
|
||
|
* The MIT License (MIT)
|
||
|
*
|
||
|
* Copyright (c) 2016 Marcel Steinbeck
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
* of this software and associated documentation files (the "Software"), to deal
|
||
|
* in the Software without restriction, including without limitation the rights
|
||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
* copies of the Software, and to permit persons to whom the Software is
|
||
|
* furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in all
|
||
|
* copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
|
* SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#include "tinysplinecpp.h"
|
||
|
#include <stdexcept>
|
||
|
|
||
|
/********************************************************
|
||
|
* *
|
||
|
* DeBoorNet *
|
||
|
* *
|
||
|
********************************************************/
|
||
|
tinyspline::DeBoorNet::DeBoorNet()
|
||
|
{
|
||
|
ts_deboornet_default( &deBoorNet );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::DeBoorNet::DeBoorNet( const tinyspline::DeBoorNet& other )
|
||
|
{
|
||
|
const tsError err = ts_deboornet_copy( &other.deBoorNet, &deBoorNet );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::DeBoorNet::~DeBoorNet()
|
||
|
{
|
||
|
ts_deboornet_free( &deBoorNet );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::DeBoorNet& tinyspline::DeBoorNet::operator=( const tinyspline::DeBoorNet& other )
|
||
|
{
|
||
|
if( &other != this )
|
||
|
{
|
||
|
const tsError err = ts_deboornet_copy(
|
||
|
&other.deBoorNet, &deBoorNet );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::real tinyspline::DeBoorNet::u() const
|
||
|
{
|
||
|
return deBoorNet.u;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::DeBoorNet::k() const
|
||
|
{
|
||
|
return deBoorNet.k;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::DeBoorNet::s() const
|
||
|
{
|
||
|
return deBoorNet.s;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::DeBoorNet::h() const
|
||
|
{
|
||
|
return deBoorNet.h;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::DeBoorNet::dim() const
|
||
|
{
|
||
|
return deBoorNet.dim;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::DeBoorNet::nPoints() const
|
||
|
{
|
||
|
return deBoorNet.n_points;
|
||
|
}
|
||
|
|
||
|
|
||
|
std::vector<tinyspline::real> tinyspline::DeBoorNet::points() const
|
||
|
{
|
||
|
const tinyspline::real* begin = deBoorNet.points;
|
||
|
const tinyspline::real* end = begin + deBoorNet.n_points * deBoorNet.dim;
|
||
|
|
||
|
return std::vector<tinyspline::real>( begin, end );
|
||
|
}
|
||
|
|
||
|
|
||
|
std::vector<tinyspline::real> tinyspline::DeBoorNet::result() const
|
||
|
{
|
||
|
const tinyspline::real* begin = deBoorNet.result;
|
||
|
const tinyspline::real* end = begin + deBoorNet.dim;
|
||
|
|
||
|
return std::vector<tinyspline::real>( begin, end );
|
||
|
}
|
||
|
|
||
|
|
||
|
tsDeBoorNet* tinyspline::DeBoorNet::data()
|
||
|
{
|
||
|
return &deBoorNet;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef TINYSPLINE_DISABLE_CXX11_FEATURES
|
||
|
tinyspline::DeBoorNet::DeBoorNet( tinyspline::DeBoorNet&& other ) noexcept
|
||
|
{
|
||
|
ts_deboornet_default( &deBoorNet );
|
||
|
swap( other );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::DeBoorNet& tinyspline::DeBoorNet::operator=( tinyspline::DeBoorNet&& other ) noexcept
|
||
|
{
|
||
|
if( &other != this )
|
||
|
{
|
||
|
ts_deboornet_free( &deBoorNet );
|
||
|
swap( other );
|
||
|
}
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
void tinyspline::DeBoorNet::swap( tinyspline::DeBoorNet& other )
|
||
|
{
|
||
|
if( &other != this )
|
||
|
{
|
||
|
std::swap( deBoorNet.u, other.deBoorNet.u );
|
||
|
std::swap( deBoorNet.k, other.deBoorNet.k );
|
||
|
std::swap( deBoorNet.s, other.deBoorNet.s );
|
||
|
std::swap( deBoorNet.h, other.deBoorNet.h );
|
||
|
std::swap( deBoorNet.dim, other.deBoorNet.dim );
|
||
|
std::swap( deBoorNet.n_points, other.deBoorNet.n_points );
|
||
|
std::swap( deBoorNet.points, other.deBoorNet.points );
|
||
|
std::swap( deBoorNet.result, other.deBoorNet.result );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/********************************************************
|
||
|
* *
|
||
|
* BSpline *
|
||
|
* *
|
||
|
********************************************************/
|
||
|
tinyspline::BSpline::BSpline()
|
||
|
{
|
||
|
ts_bspline_default( &bspline );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline::BSpline( const tinyspline::BSpline& other )
|
||
|
{
|
||
|
const tsError err = ts_bspline_copy( &other.bspline, &bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline::BSpline( const size_t nCtrlp, const size_t dim,
|
||
|
const size_t deg, const tinyspline::BSpline::type type )
|
||
|
{
|
||
|
const tsError err = ts_bspline_new( nCtrlp, dim, deg, type, &bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline::~BSpline()
|
||
|
{
|
||
|
ts_bspline_free( &bspline );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline& tinyspline::BSpline::operator=( const tinyspline::BSpline& other )
|
||
|
{
|
||
|
if( &other != this )
|
||
|
{
|
||
|
const tsError err = ts_bspline_copy( &other.bspline, &bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::DeBoorNet tinyspline::BSpline::operator()( const tinyspline::real u ) const
|
||
|
{
|
||
|
return evaluate( u );
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::BSpline::deg() const
|
||
|
{
|
||
|
return bspline.deg;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::BSpline::order() const
|
||
|
{
|
||
|
return bspline.order;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::BSpline::dim() const
|
||
|
{
|
||
|
return bspline.dim;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::BSpline::nCtrlp() const
|
||
|
{
|
||
|
return bspline.n_ctrlp;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t tinyspline::BSpline::nKnots() const
|
||
|
{
|
||
|
return bspline.n_knots;
|
||
|
}
|
||
|
|
||
|
|
||
|
std::vector<tinyspline::real> tinyspline::BSpline::ctrlp() const
|
||
|
{
|
||
|
const tinyspline::real* begin = bspline.ctrlp;
|
||
|
const tinyspline::real* end = begin + bspline.n_ctrlp * bspline.dim;
|
||
|
|
||
|
return std::vector<tinyspline::real>( begin, end );
|
||
|
}
|
||
|
|
||
|
|
||
|
std::vector<tinyspline::real> tinyspline::BSpline::knots() const
|
||
|
{
|
||
|
const tinyspline::real* begin = bspline.knots;
|
||
|
const tinyspline::real* end = begin + bspline.n_knots;
|
||
|
|
||
|
return std::vector<tinyspline::real>( begin, end );
|
||
|
}
|
||
|
|
||
|
|
||
|
tsBSpline* tinyspline::BSpline::data()
|
||
|
{
|
||
|
return &bspline;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::DeBoorNet tinyspline::BSpline::evaluate( const tinyspline::real u ) const
|
||
|
{
|
||
|
tinyspline::DeBoorNet deBoorNet;
|
||
|
const tsError err = ts_bspline_evaluate( &bspline, u, deBoorNet.data() );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return deBoorNet;
|
||
|
}
|
||
|
|
||
|
|
||
|
void tinyspline::BSpline::setCtrlp( const std::vector<tinyspline::real>& ctrlp )
|
||
|
{
|
||
|
if( ctrlp.size() != nCtrlp() * dim() )
|
||
|
{
|
||
|
throw std::runtime_error( "The number of values must be equals"
|
||
|
"to the spline's number of control points multiplied"
|
||
|
"by the dimension of each control point." );
|
||
|
}
|
||
|
|
||
|
const tsError err = ts_bspline_set_ctrlp(
|
||
|
&bspline, ctrlp.data(), &bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
void tinyspline::BSpline::setKnots( const std::vector<tinyspline::real>& knots )
|
||
|
{
|
||
|
if( knots.size() != nKnots() )
|
||
|
{
|
||
|
throw std::runtime_error( "The number of values must be equals"
|
||
|
"to the spline's number of knots." );
|
||
|
}
|
||
|
|
||
|
const tsError err = ts_bspline_set_knots(
|
||
|
&bspline, knots.data(), &bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline tinyspline::BSpline::fillKnots( const tsBSplineType type,
|
||
|
const tinyspline::real min,
|
||
|
const tinyspline::real max ) const
|
||
|
{
|
||
|
tinyspline::BSpline bs;
|
||
|
const tsError err = ts_bspline_fill_knots(
|
||
|
&bspline, type, min, max, &bs.bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bs;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline tinyspline::BSpline::insertKnot( const tinyspline::real u,
|
||
|
const size_t n ) const
|
||
|
{
|
||
|
tinyspline::BSpline bs;
|
||
|
size_t k;
|
||
|
const tsError err = ts_bspline_insert_knot(
|
||
|
&bspline, u, n, &bs.bspline, &k );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bs;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline tinyspline::BSpline::resize( const int n, const int back ) const
|
||
|
{
|
||
|
tinyspline::BSpline bs;
|
||
|
const tsError err = ts_bspline_resize( &bspline, n, back, &bs.bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bs;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline tinyspline::BSpline::split( const tinyspline::real u ) const
|
||
|
{
|
||
|
tinyspline::BSpline bs;
|
||
|
size_t k;
|
||
|
const tsError err = ts_bspline_split( &bspline, u, &bs.bspline, &k );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bs;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline tinyspline::BSpline::buckle( const tinyspline::real b ) const
|
||
|
{
|
||
|
tinyspline::BSpline bs;
|
||
|
const tsError err = ts_bspline_buckle( &bspline, b, &bs.bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bs;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline tinyspline::BSpline::toBeziers() const
|
||
|
{
|
||
|
tinyspline::BSpline bs;
|
||
|
const tsError err = ts_bspline_to_beziers( &bspline, &bs.bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bs;
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline tinyspline::BSpline::derive() const
|
||
|
{
|
||
|
tinyspline::BSpline bs;
|
||
|
const tsError err = ts_bspline_derive( &bspline, &bs.bspline );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bs;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef TINYSPLINE_DISABLE_CXX11_FEATURES
|
||
|
tinyspline::BSpline::BSpline( tinyspline::BSpline&& other ) noexcept
|
||
|
{
|
||
|
ts_bspline_default( &bspline );
|
||
|
swap( other );
|
||
|
}
|
||
|
|
||
|
|
||
|
tinyspline::BSpline& tinyspline::BSpline::operator=( tinyspline::BSpline&& other ) noexcept
|
||
|
{
|
||
|
if( &other != this )
|
||
|
{
|
||
|
ts_bspline_free( &bspline );
|
||
|
swap( other );
|
||
|
}
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
void tinyspline::BSpline::swap( tinyspline::BSpline& other )
|
||
|
{
|
||
|
if( &other != this )
|
||
|
{
|
||
|
std::swap( bspline.deg, other.bspline.deg );
|
||
|
std::swap( bspline.order, other.bspline.order );
|
||
|
std::swap( bspline.dim, other.bspline.dim );
|
||
|
std::swap( bspline.n_ctrlp, other.bspline.n_ctrlp );
|
||
|
std::swap( bspline.n_knots, other.bspline.n_knots );
|
||
|
std::swap( bspline.ctrlp, other.bspline.ctrlp );
|
||
|
std::swap( bspline.knots, other.bspline.knots );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/********************************************************
|
||
|
* *
|
||
|
* Utils *
|
||
|
* *
|
||
|
********************************************************/
|
||
|
tinyspline::BSpline tinyspline::Utils::interpolateCubic(
|
||
|
const std::vector<tinyspline::real>* points,
|
||
|
const size_t dim )
|
||
|
{
|
||
|
if( dim == 0 )
|
||
|
throw std::runtime_error( ts_enum_str( TS_DIM_ZERO ) );
|
||
|
|
||
|
if( points->size() % dim != 0 )
|
||
|
throw std::runtime_error( "#points % dim == 0 failed" );
|
||
|
|
||
|
tinyspline::BSpline bspline;
|
||
|
const tsError err = ts_bspline_interpolate_cubic(
|
||
|
points->data(), points->size() / dim, dim, bspline.data() );
|
||
|
|
||
|
if( err < 0 )
|
||
|
throw std::runtime_error( ts_enum_str( err ) );
|
||
|
|
||
|
return bspline;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool tinyspline::Utils::fequals( const tinyspline::real x, const tinyspline::real y )
|
||
|
{
|
||
|
return ts_fequals( x, y ) == 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
std::string tinyspline::Utils::enum_str( const tsError err )
|
||
|
{
|
||
|
return std::string( ts_enum_str( err ) );
|
||
|
}
|
||
|
|
||
|
|
||
|
tsError tinyspline::Utils::str_enum( const std::string str )
|
||
|
{
|
||
|
return ts_str_enum( str.c_str() );
|
||
|
}
|