/*=====================================================================
File: nurbs.cpp
Purpose:
Revision: $Id: nurbs.cpp,v 1.3 2002/05/24 17:27:24 philosophil Exp $
Author: Philippe Lavoie (3 Oct, 1996)
Modified by:
Copyright notice:
Copyright (C) 1996-1997 Philippe Lavoie
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
=====================================================================*/
#ifndef nurbs_h__
#define nurbs_h__
#include <nurbs.h>
#include <fstream>
#include <string.h>
#include <nurbsS.h>
#include "integrate.h"
#include <malloc.h>
/*!
*/
namespace PLib {
/*!
\brief default constructor
\author Philippe Lavoie
\date 24 January 1997
*/
template <class T, int N>
NurbsCurve<T,N>::NurbsCurve(): P(1),U(1),deg_(0)
{
}
/*!
\brief A copy constructor.
\param nurb the NURBS curve to copy
\author Philippe Lavoie
\date 24 January 1997
*/
template <class T, int N>
NurbsCurve<T,N>::NurbsCurve(const NurbsCurve<T,N>& nurb):
ParaCurve<T,N>(), P(nurb.P),U(nurb.U),deg_(nurb.deg_)
{
}
/*!
\brief Resets a NURBS curve to new values
\param P1 the new values for the control points
\param U1 the new values for the knot vector
\param Degree the new degree of the curve
\warning The size of P1,U1 and Degree must agree: P.n()+degree+1=U.n()
\author Philippe Lavoie
\date 24 January 1997
*/
template <class T, int N>
void NurbsCurve<T,N>::reset(const Vector< HPoint_nD<T,N> >& P1, const Vector<T> &U1, int Degree) {
int nSize = P1.n() ;
int mSize = U1.n() ;
deg_ = Degree ;
if(nSize != mSize-deg_-1){
#ifdef USE_EXCEPTION
throw NurbsSizeError(P1.n(),U1.n(),Degree) ;
#else
Error err("reset");
err << "Invalid input size for the control points and the knot vector when reseting a Nurbs Curve.\n";
err << nSize << " control points and " << mSize << " knots\n" ;
err.fatal() ;
#endif
}
P.resize(P1.n()) ;
U.resize(U1.n()) ;
P = P1 ;
U = U1 ;
generatePolyCoefVectors();
}
/*!
\brief Constructor with control points in 4D
\param P1 the control points
\param U1 the knot vector
\param Degree the degree of the curve
\warning The size of P1,U1 and Degree must agree: P.n()+degree+1=U.n()
\author Philippe Lavoie
\date 24 January 1997
*/
template <class T, int N>
NurbsCurve<T,N>::NurbsCurve(const Vector< HPoint_nD<T,N> >& P1, const Vector<T> &U1, int Degree): P(P1), U(U1), deg_(Degree)
{
if(P.n() != U.n()-deg_-1){
#ifdef USE_EXCEPTION
throw NurbsSizeError(P.n(),U.n(),deg_) ;
#else
Error err("NurbsCurve(P1,U1,Degree)");
err << "Invalid input size for the control points and the knot vector.\n";
err << P.n() << " control points and " << U.n() << " knots\n" ;
err.fatal() ;
#endif
generatePolyCoefVectors();
}
}
/*!
\brief Constructor with control points in 3D
\param P1 --> the control point vector
\param W --> the weight for each control points
\param U1 --> the knot vector
\param Degree --> the degree of the curve
\warning The size of P1,U1 and Degree must agree: P.n()+degree+1=U.n()
\author Philippe Lavoie
\date 24 January 1997
*/
template <class T, int N>
NurbsCurve<T,N>::NurbsCurve(const Vector< Point_nD<T,N> >& P1, const Vector<T>& W, const Vector<T>& U1, int Degree): P(P1.n()), U(U1), deg_(Degree)
{
int nSize = P1.n() ;
int mSize = U1.n() ;
if(nSize != mSize-deg_-1){
#ifdef USE_EXCEPTION
throw NurbsSizeError(P.n(),U.n(),deg_) ;
#else
Error err("NurbsCurve(P1,W,U1,Degree)") ;
err << "Invalid input size for the control points and the knot vector.\n" ;
err << nSize << " control points and " << mSize << " knots\n" ;
err.fatal() ;
#endif
}
if(nSize != W.n()){
#ifdef USE_EXCEPTION
throw NurbsInputError(nSize,W.n()) ;
#else
Error err("NurbsCurve(P1,W,U1,Degree)") ;
err << "Size mismatched between the control points and the weights\n" ;
err << "ControlPoints size = " << nSize << ", Weight size = " << W.n() << endl ;
err.fatal() ;
#endif
}
for(int i = 0 ;i<nSize;i++){
const Point_nD<T,N>& pt = P1[i] ; // This makes the SGI compiler happy
for(int j=0;j<N;j++)
P[i].data[j] = pt.data[j] * W[i] ;
P[i].w() = W[i] ;
}
generatePolyCoefVectors();
}
/*!
\brief The assignment operator for a NURBS curve
\param curve the NURBS curve to copy
\return A reference to itself
\warning The curve being copied must be valid, otherwise strange
results might occur.
\author Philippe Lavoie
\date 24 January 1997
*/
template <class T, int N>
NurbsCurve<T,N>& NurbsCurve<T,N>::operator=(const NurbsCurve<T,N>& curve) {
if(curve.U.n() != curve.P.n()+curve.deg_+1){
#ifdef USE_EXCEPTION
throw NurbsSizeError(curve.P.n(),curve.U.n(),curve.deg_) ;
#else
Error err("operator=") ;
err << "Invalid assignment... the curve being assigned to isn't valid\n" ;
err.fatal() ;
#endif
}
deg_ = curve.deg_ ;
U = curve.U ;
P = curve.P ;
if(U.n()!=P.n()+deg_+1){
#ifdef USE_EXCEPTION
throw NurbsSizeError(P.n(),U.n(),deg_) ;
#else
Error err("operator=") ;
err << "Error in assignment... couldn't assign properly the vectors\n" ;
err.fatal() ;
#endif
}
return *this ;
}
/*!
\brief draws a NURBS curve on an image
This will draw very primitively the NURBS curve on an image.
The drawing assumes the line is only in the xy plane (the z
is not used for now).
The algorithm finds the points on the curve at a \a step
parametric intervall between them and join them by a line.
No fancy stuff.
\param Img <-- draws the nurbs curve to this Image
\param color --> the line is drawn in this color
\param step --> the parametric distance between two computed points.
\author Philippe Lavoie
\date 24 January 1997
*/
template <class T, int N>
void NurbsCurve<T,N>::drawImg(Image_UBYTE& Img,unsigned char color,T step){
Point_nD<T,N> a1,a2 ;
T u_max = U[U.n()-1-deg_] ;
if(step<=0)
step = 0.01 ;
a1 = this->pointAt(U[deg_]) ;
T u ;
int i1,j1,i2,j2 ;
getCoordinates(a1,i1,j1,Img.rows(),Img.cols()) ;
for(u=U[deg_]+step ; u < u_max+(step/2.0) ; u+=step){ // the <= u_max doesn't work
a2 = this->pointAt(u) ;
if(!getCoordinates(a2,i2,j2,Img.rows(),Img.cols()))
continue ;
Img.drawLine(i1,j1,i2,j2,color) ;
i1 = i2 ;
j1 = j2 ;
}
a2 = this->pointAt(U[P.n()]) ;
if(getCoordinates(a2,i2,j2,Img.rows(),Img.cols()))
Img.drawLine(i1,j1,i2,j2,color) ;
}
/*!
\brief Draws a NURBS curve on an image
This will draw very primitively the NURBS curve on an image.
The drawing assumes the line is only in the xy plane (the z
is not used for now).
The algorithm finds the points on the curve at a \a step
parametric intervall between them and join them by a line.
No fancy stuff.
\param Img draws the nurbs curve to this Image
\param color the line is drawn in this color
\param step the parametric distance between two computed points.