/*===========================================================================*\ * * * OpenFlipper * * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * * www.openflipper.org * * * *--------------------------------------------------------------------------- * * This file is part of OpenFlipper. * * * * OpenFlipper is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenFlipper is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU LesserGeneral Public * * License along with OpenFlipper. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $LastChangedBy$ * * $Date$ * * * \*===========================================================================*/ //============================================================================= // // CLASS BSplineSurfaceT - IMPLEMENTATION // Author: Ellen Dekkers // //============================================================================= #define BSPLINESURFACE_BSPLINESURFACET_C //== INCLUDES ================================================================= #include #include #include #include "BSplineSurfaceT.hh" #include #include //== NAMESPACES =============================================================== namespace ACG { //== IMPLEMENTATION ========================================================== template BSplineSurfaceT:: BSplineSurfaceT( unsigned int _degm, unsigned int _degn ) : dimm_(0), dimn_(0), degree_m_(_degm), degree_n_(_degn), ref_count_cpselections_(0), ref_count_eselections_(0) { } //----------------------------------------------------------------------------- template BSplineSurfaceT:: BSplineSurfaceT( const BSplineSurfaceT& _surface ) { //copy control points control_net_ = _surface.control_net_; //copy knotvectors knotvector_m_ = _surface.knotvector_m_; knotvector_n_ = _surface.knotvector_n_; degree_m_ = _surface.degree_m_; degree_n_ = _surface.degree_n_; // copy properties cpselections_ = _surface.cpselections_; eselections_ = _surface.eselections_; // copy property reference counter ref_count_cpselections_ = _surface.ref_count_cpselections_; ref_count_eselections_ = _surface.ref_count_eselections_; } //----------------------------------------------------------------------------- template template void BSplineSurfaceT:: request_prop( unsigned int& _ref_count, PropT& _prop) { if(_ref_count == 0) { _ref_count = 1; // always use vertex size!!! _prop.resize(n_control_points_m()); for (unsigned int i = 0; i < _prop.size(); ++i) _prop[i].resize(n_control_points_n()); } else ++_ref_count; } //----------------------------------------------------------------------------- template template void BSplineSurfaceT:: release_prop( unsigned int& _ref_count, PropT& _prop) { if( _ref_count <= 1) { _ref_count = 0; _prop.clear(); } else --_ref_count; } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: resize(unsigned int _m, unsigned int _n) { control_net_.resize(_m); for (unsigned int i = 0; i < control_net_.size(); ++i) control_net_[i].resize(_n); dimm_ = _m; dimn_ = _n; // resize cpselections cpselections_.resize(_m); for (unsigned int i = 0; i < cpselections_.size(); ++i) cpselections_[i].resize(_n); // resize eselections eselections_.resize(_m); for (unsigned int i = 0; i < eselections_.size(); ++i) eselections_[i].resize(_n); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: reset_control_net() { control_net_.clear(); // reset properties cpselections_.clear(); eselections_.clear(); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: createKnots() { knotvector_m_.createKnots(degree_m_, dimm_); knotvector_n_.createKnots(degree_n_, dimn_); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: set_degree(unsigned int _degm, unsigned int _degn) { degree_m_ = _degm; degree_n_ = _degn; } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: add_vector_m(const std::vector< Point> & _control_polygon) { insert_vector_m(_control_polygon, dimm_); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: add_vector_n(const std::vector< Point> & _control_polygon) { insert_vector_n(_control_polygon, dimn_); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: insert_vector_m(const std::vector< Point> & _control_polygon, unsigned int _m) { std::cout << "insert_vector_m of size " << _control_polygon.size() << " at m = " << _m << std::endl; assert(_m <= dimm_); if (dimn_ == 0) dimn_ =_control_polygon.size(); assert(_control_polygon.size() == dimn_); resize(dimm_ + 1, dimn_); control_net_.insert(control_net_.begin() + _m, _control_polygon); control_net_.pop_back(); // TODO check std::cout << "control_net_: " << control_net_.size() << " x " << control_net_[control_net_.size()-1].size() << std::endl; // resize property net cpselection std::vector dummy(_control_polygon.size(), 0); cpselections_.insert(cpselections_.begin() + _m, dummy); cpselections_.pop_back(); std::cout << "cpselections_: " << cpselections_.size() << " x " << cpselections_[cpselections_.size()-1].size() << std::endl; // resize property net eselection eselections_.insert(eselections_.begin() + _m, dummy); eselections_.pop_back(); std::cout << "eselections_: " << eselections_.size() << " x " << eselections_[eselections_.size()-1].size() << std::endl; } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: insert_vector_n(const std::vector< Point> & _control_polygon, unsigned int _n) { assert(_n <= dimn_); if (dimm_ == 0) dimm_ = _control_polygon.size(); assert(_control_polygon.size() == dimm_); resize(dimm_, dimn_+1); for (unsigned int i = 0; i < dimm_; ++i) { control_net_[i].insert(control_net_[i].begin() + _n, _control_polygon[i]); control_net_[i].pop_back(); } // resize property net cpselection for (unsigned int i = 0; i < dimm_; ++i) { cpselections_[i].insert(cpselections_[i].begin() + _n, 0); cpselections_[i].pop_back(); } // resize property net eselection for (unsigned int i = 0; i < dimm_; ++i) { eselections_[i].insert(eselections_[i].begin() + _n, 0); eselections_[i].pop_back(); } } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: delete_vector_m(unsigned int _m) { assert(_m < dimm_); /// \todo Improve deletion routine for control points and knots! if(control_net_.begin() + _m < control_net_.end()) control_net_.erase(control_net_.begin() + _m); resize(dimm_-1, dimn_); // erase from properties if(cpselections_.begin() + _m < cpselections_.end()) cpselections_.erase(cpselections_.begin() + _m); if(eselections_.begin() + _m < eselections_.end()) eselections_.erase(eselections_.begin() + _m); // Now rebuild knot vectors createKnots(); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: delete_vector_n(unsigned int _n) { assert(_n < dimn_); /// \todo: Improve deletion routine for control points and knots! for (unsigned int i = 0; i < control_net_.size(); ++i) { if(control_net_[i].begin() + _n < control_net_[i].end()) control_net_[i].erase(control_net_[i].begin() + _n); } resize(dimm_, dimn_-1); // erase from properties for (unsigned int i = 0; i < cpselections_.size(); ++i) if(cpselections_[i].begin() + _n < cpselections_[i].end()) cpselections_[i].erase(cpselections_[i].begin() + _n); for (unsigned int i = 0; i < eselections_.size(); ++i) if(eselections_[i].begin() + _n < eselections_[i].end()) eselections_[i].erase(eselections_[i].begin() + _n); // Now rebuild knot vectors createKnots(); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: get_vector_m(std::vector< Point> & _control_polygon, unsigned int _m) { assert(_m < dimm_); _control_polygon = control_net_[_m]; } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: get_vector_n(std::vector< Point> & _control_polygon, unsigned int _n) { assert(_n < dimn_); _control_polygon.resize(dimm_); for (unsigned int i = 0; i < dimm_; ++i) _control_polygon[i] = control_net_[i][_n]; } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: set_knots_m(std::vector< Scalar > _knots) { // set the knotvector knotvector_m_.setKnotvector(_knots); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: set_knots_n(std::vector< Scalar > _knots) { // set the knotvector knotvector_n_.setKnotvector(_knots); } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: insert_knot_m(double _u) { // span and interval i,i+1 Vec2i span = spanm(_u); Vec2i interval = interval_m(_u); // create new knot vector Knotvector newknotvecu( get_knotvector_m() ); newknotvecu.insertKnot(interval[1], _u); // alphas std::vector alpha; for( int i = span[0]; i < span[1]; ++i) { double a(knotvector_m_.getKnot(i+1)); double b(knotvector_m_.getKnot(i+degree_m_+1)); alpha.push_back((_u-a)/(b-a)); } knotvector_m_ = newknotvecu; // new control net ControlNet oldcpts(control_net_); resize(n_control_points_m()+1, n_control_points_n()); for( int i = 0; i < n_control_points_m(); ++i) // for all v rows { if( i <= span[0]) control_net_[i] = oldcpts[i]; else if( i <= span[1]) for( unsigned int j = 0; j < n_control_points_n(); ++j) { control_net_[i][j] = oldcpts[i-1][j]*(1.0-alpha[i-span[0]-1])+oldcpts[i][j]*alpha[i-span[0]-1]; } else control_net_[i] = oldcpts[i-1]; } } //----------------------------------------------------------------------------- template void BSplineSurfaceT:: insert_knot_n(double _v) { // span and interval i,i+1 Vec2i span = spann(_v); Vec2i interval = interval_n(_v); // create new knot vector Knotvector newknotvecv( get_knotvector_n() ); newknotvecv.insertKnot(interval[1], _v); // alphas std::vector alpha; for( int i = span[0]; i < span[1]; ++i) { double a(knotvector_n_.getKnot(i+1)); double b(knotvector_n_.getKnot(i+degree_n_+1)); alpha.push_back((_v-a)/(b-a)); } knotvector_n_ = newknotvecv; // new control net ControlNet oldcpts(control_net_); resize(n_control_points_m(), n_control_points_n()+1); for( int i = 0; i < n_control_points_n(); ++i) // for all v rows { if( i <= span[0]) for( unsigned int j = 0; j < n_control_points_m(); ++j) control_net_[j][i] = oldcpts[j][i]; else if( i <= span[1]) for( unsigned int j = 0; j < n_control_points_m(); ++j) { control_net_[j][i] = oldcpts[j][i-1]*(1.0-alpha[i-span[0]-1])+oldcpts[j][i]*alpha[i-span[0]-1]; } else for( unsigned int j = 0; j < n_control_points_m(); ++j) control_net_[j][i] = oldcpts[j][i-1]; } } //----------------------------------------------------------------------------- template PointT BSplineSurfaceT:: surfacePoint(double _u, double _v) { double epsilon = 0.0000001; if (_u > upperu() && _u < upperu()+epsilon) _u = upperu(); if (_v > upperv() && _v < upperv()+epsilon) _v = upperv(); assert(_u >= loweru() && _u <= upperu()); assert(_v >= lowerv() && _v <= upperv()); int pm = degree_m(); int pn = degree_n(); Point point = Point(0.0, 0.0, 0.0); Vec2i span_m(spanm(_u)); Vec2i span_n(spann(_v)); for (int i = 0; i < (int)n_control_points_m(); ++i) for (int j = 0; j < (int)n_control_points_n(); ++j) point += control_net_[i][j] * basisFunction(knotvector_m_, i, pm, _u) * basisFunction(knotvector_n_, j, pn, _v); return point; } //----------------------------------------------------------------------------- template typename BSplineSurfaceT::Scalar BSplineSurfaceT:: basisFunction(Knotvector & _knotvector, int _i, int _n, double _t) { int m = _knotvector.size() - 1; // Mansfield Cox deBoor recursion if ((_i==0 && _t== _knotvector(0)) || (_i==m-_n-1 && _t==_knotvector(m))) return 1.0; if (_n == 0) { if (_t >= _knotvector(_i) && _t < _knotvector(_i+1)) return 1.0; else return 0.0; } double Nin1 = basisFunction(_knotvector, _i, _n-1, _t); double Nin2 = basisFunction(_knotvector, _i+1, _n-1, _t); double fac1 = 0; // if ((_knotvector(_i+_n) - _knotvector(_i)) > 0.000001 ) if ((_knotvector(_i+_n) - _knotvector(_i)) != 0) fac1 = (_t - _knotvector(_i)) / (_knotvector(_i+_n) - _knotvector(_i)) ; double fac2 = 0; // if ( (_knotvector(_i+1+_n) - _knotvector(_i+1)) > 0.000001 ) if ( (_knotvector(_i+1+_n) - _knotvector(_i+1)) != 0 ) fac2 = (_knotvector(_i+1+_n) - _t) / (_knotvector(_i+1+_n) - _knotvector(_i+1)); // std::cout << "Nin1 = " << Nin1 << ", Nin2 = " << Nin2 << ", fac1 = " << fac1 << ", fac2 = " << fac2 << std::endl; return (fac1*Nin1 + fac2*Nin2); } //----------------------------------------------------------------------------- template PointT BSplineSurfaceT:: derivativeSurfacePoint(double _u, double _v, int _derm, int _dern) { assert(_u >= loweru() && _u <= upperu()); assert(_v >= lowerv() && _v <= upperv()); int pn = degree_n(); int pm = degree_m(); Point point(0,0,0); Vec2i span_m(spanm(_u)); Vec2i span_n(spann(_v)); // for (int i = 0; i < n_control_points_m(); i++) // for (int j = 0; j < n_control_points_n(); j++) // point += control_net_[i][j] * derivativeBasisFunction(knotvector_m_, i, pm, _u, _derm) // * derivativeBasisFunction(knotvector_n_, j, pn, _v, _dern); for (int i = span_m[0]; i <= span_m[1]; i++) for (int j = span_n[0]; j <= span_n[1]; j++) point += control_net_[i][j] * derivativeBasisFunction(knotvector_m_, i, pm, _u, _derm) * derivativeBasisFunction(knotvector_n_, j, pn, _v, _dern); return point; } //----------------------------------------------------------------------------- template PointT BSplineSurfaceT:: normalSurfacePoint(double _u, double _v) { assert(_u >= loweru() && _u <= upperu()); assert(_v >= lowerv() && _v <= upperv()); int pn = degree_n(); int pm = degree_m(); Point derivu( derivativeSurfacePoint(_u,_v,1,0)); Point derivv( derivativeSurfacePoint(_u,_v,0,1)); Point normal( (derivu%derivv).normalize()); return normal; } //----------------------------------------------------------------------------- template typename BSplineSurfaceT::Scalar BSplineSurfaceT:: derivativeBasisFunction(Knotvector & _knotvector, int _i, int _n, double _t, int _der) { if (_der == 0) return basisFunction(_knotvector, _i, _n, _t); double Nin1 = derivativeBasisFunction(_knotvector, _i, _n-1, _t, _der-1); double Nin2 = derivativeBasisFunction(_knotvector, _i+1, _n-1, _t, _der-1); double fac1 = 0; if ( (_knotvector(_i+_n)-_knotvector(_i)) !=0 ) fac1 = double(_n) / (_knotvector(_i+_n)-_knotvector(_i)); double fac2 = 0; if ( (_knotvector(_i+_n+1)-_knotvector(_i+1)) !=0 ) fac2 = double(_n) / (_knotvector(_i+_n+1)-_knotvector(_i+1)); return (fac1*Nin1 - fac2*Nin2); } //----------------------------------------------------------------------------- template typename BSplineSurfaceT::Scalar BSplineSurfaceT:: loweru() { return knotvector_m_(degree_m()); } //----------------------------------------------------------------------------- template typename BSplineSurfaceT::Scalar BSplineSurfaceT:: upperu() { return knotvector_m_(knotvector_m_.size() - 1 - degree_m()); } //----------------------------------------------------------------------------- template typename BSplineSurfaceT::Scalar BSplineSurfaceT:: lowerv() { return knotvector_n_(degree_n()); } //----------------------------------------------------------------------------- template typename BSplineSurfaceT::Scalar BSplineSurfaceT:: upperv() { return knotvector_n_(knotvector_n_.size() - 1 - degree_n()); } //----------------------------------------------------------------------------- template ACG::Vec2i BSplineSurfaceT:: spanm(double _t) { unsigned int i(0); // if (i > knotvector_m_.size() - degree_m() - 1) // i = degree_m(); if (_t >= upperu()) i = dimm_ - 1; else { while (_t >= knotvector_m_(i)) i++; while (_t < knotvector_m_(i)) i--; } return ACG::Vec2i(i-degree_m(), i); } //----------------------------------------------------------------------------- template ACG::Vec2i BSplineSurfaceT:: spann(double _t) { unsigned int i(0); // if (i > knotvector_n_.size() - degree_n() - 1) // i = degree_n(); if (_t >= upperv()) i = dimn_-1; else { while (_t >= knotvector_n_(i)) i++; while (_t < knotvector_n_(i)) i--; } return Vec2i(i-degree_n(), i); } //----------------------------------------------------------------------------- template ACG::Vec2i BSplineSurfaceT:: interval_m(double _t) { Vec2i interval = Vec2i(-1, -1); unsigned int i(0); if (_t >= upperu()) i = dimm_-1; else { while (_t >= knotvector_m_(i)) i++; while (_t < knotvector_m_(i)) i--; } return Vec2i(i, i+1); } //----------------------------------------------------------------------------- template ACG::Vec2i BSplineSurfaceT:: interval_n(double _t) { Vec2i interval = Vec2i(-1, -1); unsigned int i(0); if (_t >= upperv()) i = dimn_-1; else { while (_t >= knotvector_n_(i)) i++; while (_t < knotvector_n_(i)) i--; } return Vec2i(i, i+1); } //----------------------------------------------------------------------------- //============================================================================= } // namespace ACG //=============================================================================