Voreen - Volume Rendering Engine Voreen - Volume Rendering Engine
Voreen - Volume Rendering Engine Westfälische Wilhelms-Universität Münster
  • About
  • Gallery
  • Download
  • Documentation
  • Publications
  • Community

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List

src/modules/base/processors/image/labelingmath.cpp

00001 /**********************************************************************
00002  *                                                                    *
00003  * Voreen - The Volume Rendering Engine                               *
00004  *                                                                    *
00005  * Copyright (C) 2005-2010 The Voreen Team. <http://www.voreen.org>   *
00006  *                                                                    *
00007  * This file is part of the Voreen software package. Voreen is free   *
00008  * software: you can redistribute it and/or modify it under the terms *
00009  * of the GNU General Public License version 2 as published by the    *
00010  * Free Software Foundation.                                          *
00011  *                                                                    *
00012  * Voreen is distributed in the hope that it will be useful,          *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the       *
00015  * GNU General Public License for more details.                       *
00016  *                                                                    *
00017  * You should have received a copy of the GNU General Public License  *
00018  * in the file "LICENSE.txt" along with this program.                 *
00019  * If not, see <http://www.gnu.org/licenses/>.                        *
00020  *                                                                    *
00021  * The authors reserve all rights not expressly granted herein. For   *
00022  * non-commercial academic use see the license exception specified in *
00023  * the file "LICENSE-academic.txt". To get information about          *
00024  * commercial licensing please contact the authors.                   *
00025  *                                                                    *
00026  **********************************************************************/
00027 
00028 #include "voreen/modules/base/processors/image/labelingmath.h"
00029 
00030 // for least-squares-fitting
00031 #include "jama/include/jama_qr.h"
00032 
00033 using namespace labeling;
00034 using namespace tgt;
00035 using namespace std;
00036 
00037 inline float faculty(int a) {
00038     if (a > 1)
00039         return a*faculty(a-1);
00040     else
00041         return 1.f;
00042 }
00043 
00044 // functions for evaluating bernstein polynomials
00045 // formula taken from: Angel, Edward. Interactive Computer Graphics, 2006
00046 
00047 // evaluates a bernstein polynomial
00048 // @param u parameter in range [0;1]
00049 // @param comp component of vector (starting with 0)
00050 // @param deg degree of polynomial
00051 float bernstein(float u, int comp, int deg) {
00052     float factor = faculty(deg) / ( faculty(comp)*faculty(deg - comp) );
00053     return factor*pow(u, static_cast<float>(comp))*pow(1-u, static_cast<float>(deg-comp));
00054 }
00055 
00056 // evaluates a bernstein polynomial's first derivative
00057 // @param u parameter in range [0;1]
00058 // @param comp component of vector (starting with 0)
00059 // @param deg degree of polynomial
00060 float bernsteinDerivative(float u, int comp, int deg) {
00061     float factor = faculty(deg) / ( faculty(comp)*faculty(deg - comp) );
00062     if (comp == 0)
00063         return -factor*deg*pow(1-u, static_cast<float>(deg-1));
00064     else if (deg == comp)
00065         return factor*comp*pow(u,static_cast<float>(comp-1));
00066     else
00067         return     factor*( comp*pow(u,static_cast<float>(comp-1))*pow(1-u, static_cast<float>(deg-comp))
00068         - pow(u, static_cast<float>(comp))*(deg-comp)*pow(1-u, static_cast<float>(deg-comp-1)) );
00069 }
00070 
00071 //----------------------------------------------------------------------------
00072 
00073 // several functions for evaluating polynomials
00074 
00075 float evalPolynomial(float t, void* params) {
00076     int degree = (static_cast<Polynomial*>(params))->degree;
00077     float* coeff = (static_cast<Polynomial*>(params))->coeff;
00078     float result = 0;
00079     for (int i=0; i<=degree; i++)
00080         result += coeff[i]*pow(t,i);
00081     return result;
00082 }
00083 
00084 float evalPolynomialDerivative(float t, void* params) {
00085     int degree = (static_cast<Polynomial*>(params))->degree;
00086     float* coeff = (static_cast<Polynomial*>(params))->coeff;
00087     float result = 0;
00088     for (int i=0; i<degree; i++)
00089         result += coeff[i+1]*(i+1)*pow(t,i);
00090     return result;
00091 }
00092 
00093 float evalPolynomialCurve2DTangentMagnitude(float t, void* params) {
00094     Polynomial xpoly = (static_cast<Polynomial*>(params))[0];
00095     Polynomial ypoly = (static_cast<Polynomial*>(params))[1];
00096     return sqrt( pow(evalPolynomialDerivative(t, &xpoly), 2) +
00097         pow(evalPolynomialDerivative(t, &ypoly), 2) );
00098 }
00099 
00100 float evalPolynomialCurve3DTangentMagnitude(float t, void* params) {
00101     Polynomial xpoly = (static_cast<Polynomial*>(params))[0];
00102     Polynomial ypoly = (static_cast<Polynomial*>(params))[1];
00103     Polynomial zpoly = (static_cast<Polynomial*>(params))[2];
00104     return sqrt( pow(evalPolynomialDerivative(t, &xpoly), 2) +
00105         pow(evalPolynomialDerivative(t, &ypoly), 2) +
00106         pow(evalPolynomialDerivative(t, &zpoly), 2) );
00107 }
00108 
00109 //----------------------------------------------------------------------------
00110 
00111 Curve3D::Curve3D() {
00112 }
00113 
00114 bool Curve3D::setCtrlPoints(vector<tgt::vec3> &ctrlPoints, float curveLength) {
00115     ctrlPoints_ = ctrlPoints;
00116     return calcFunction(curveLength);
00117 }
00118 
00119 //----------------------------------------------------------------------------
00120 
00121 Curve2D::Curve2D() {
00122 }
00123 
00124 bool Curve2D::setCtrlPoints(vector<tgt::vec2> &ctrlPoints, float curveLength) {
00125     ctrlPoints_ = ctrlPoints;
00126     return calcFunction(curveLength);
00127 }
00128 
00129 //----------------------------------------------------------------------------
00130 
00131 Curve3DPolynomial::Curve3DPolynomial(int degree) {
00132     degree_ = degree;
00133     numCoeff_ = degree+1;
00134     xfunc_.degree = degree;
00135     xfunc_.coeff = 0;
00136     yfunc_.degree = degree;
00137     yfunc_.coeff = 0;
00138     zfunc_.degree = degree;
00139     zfunc_.coeff = 0;
00140 }
00141 
00142 
00143 bool Curve3DPolynomial::calcFunction(float curveLength) {
00144     if (ctrlPoints_.size() < (size_t)numCoeff_)
00145         return false;
00146 
00147     if (!xfunc_.coeff) {
00148         xfunc_.coeff = new float[numCoeff_];
00149         yfunc_.coeff = new float[numCoeff_];
00150         zfunc_.coeff = new float[numCoeff_];
00151     }
00152 
00153     /*
00154     Calculate a least-squares-fit of the polynomial function to the control points.
00155     For each coordinate (x,y,z) there is one polynomial function. The least-squares-fit
00156     is performed by solving the linear equation system X*c=y,
00157     where X(i,j)=i^j and y holds the control points coordinates.
00158     */
00159 
00160     TNT::Array1D<float> y(ctrlPoints_.size());
00161     TNT::Array2D<float> X(ctrlPoints_.size(), numCoeff_);
00162     TNT::Array1D<float> c(numCoeff_);
00163 
00164     // Create matrix X and the corresponding QR-matrix
00165     for (int i=0; i<static_cast<int>(ctrlPoints_.size()); ++i) {
00166         for (int j=0; j<numCoeff_; ++j) {
00167             X[i][j] = pow(static_cast<float>(i), static_cast<float>(j));
00168         }
00169     }
00170     JAMA::QR<float> QR_Matrix(X);
00171 
00172     // x(t)
00173     for (int i=0; i<static_cast<int>(ctrlPoints_.size()); ++i)
00174         y[i] = ctrlPoints_[i].x;
00175 
00176     c = QR_Matrix.solve(y);
00177     for (int i=0; i<numCoeff_; ++i)
00178         xfunc_.coeff[i] = c[i];
00179 
00180     // y(t)
00181     for (int i=0; i<static_cast<int>(ctrlPoints_.size()); ++i)
00182         y[i] = ctrlPoints_[i].y;
00183 
00184     c = QR_Matrix.solve(y);
00185     for (int i=0; i<numCoeff_; ++i)
00186         yfunc_.coeff[i] = c[i];
00187 
00188     // z(t)
00189     for (int i=0; i<static_cast<int>(ctrlPoints_.size()); ++i)
00190         y[i] = ctrlPoints_[i].z;
00191     c = QR_Matrix.solve(y);
00192     for (int i=0; i<numCoeff_; ++i)
00193         zfunc_.coeff[i] = c[i];
00194 
00195     // map the curve segment's parameter range to [0;1]
00196     paramScale_ = static_cast<float>(ctrlPoints_.size()-1);
00197     paramShift_ = 0.f;
00198     if (curveLength > 0.f) {
00199         float length = getSegmentLength(0.f, 1.f);
00200         paramScale_ = (curveLength / length) * (ctrlPoints_.size()-1);
00201         paramShift_ = -(paramScale_-(ctrlPoints_.size()-1)) / 2.f;
00202     }
00203 
00204     return true;
00205 }
00206 
00207 tgt::vec3 Curve3DPolynomial::getCurvePoint(float t) {
00208     float p = t*paramScale_+paramShift_;
00209     tgt::vec3 result;
00210     result.x = evalPolynomial(p, &xfunc_);
00211     result.y = evalPolynomial(p, &yfunc_);
00212     result.z = evalPolynomial(p, &zfunc_);
00213     return result;
00214 }
00215 
00216 tgt::vec3 Curve3DPolynomial::getTangent(float t) {
00217     float p = t*paramScale_+paramShift_;
00218     tgt::vec3 result = vec3(0.f);
00219     result.x = evalPolynomialDerivative(p, &xfunc_);
00220     result.y = evalPolynomialDerivative(p, &yfunc_);
00221     result.z = evalPolynomialDerivative(p, &zfunc_);
00222     return result*paramScale_;
00223 }
00224 
00225 float Curve3DPolynomial::getTangentMagnitude(float t) {
00226     return length(getTangent(t));
00227 }
00228 
00229 
00230 float Curve3DPolynomial::getSegmentLength(float t1, float t2) {
00231     float avgTangentMagnitude = ( getTangentMagnitude(t1) +
00232         getTangentMagnitude((t1+t2)/2.f) +
00233         getTangentMagnitude(t2) ) / 3.f;
00234     return fabs(t2-t1)*avgTangentMagnitude;
00235 }
00236 
00237 tgt::vec3 Curve3DPolynomial::getNextPoint(float &curParam, float offset) {
00238     float pixelsPerParam = getTangentMagnitude(curParam);
00239     curParam += offset / pixelsPerParam;
00240     return getCurvePoint(curParam);
00241 }
00242 
00243 void Curve3DPolynomial::shift(vec3 shiftVector) {
00244     xfunc_.coeff[0] += shiftVector.x;
00245     yfunc_.coeff[0] += shiftVector.y;
00246     zfunc_.coeff[0] += shiftVector.z;
00247 
00248     for (size_t i=0; i<ctrlPoints_.size(); ++i)
00249         ctrlPoints_[i] = ctrlPoints_[i] + shiftVector;
00250 }
00251 
00252 
00253 //----------------------------------------------------------------------------
00254 
00255 Curve2DPolynomial::Curve2DPolynomial(int degree) {
00256     degree_ = degree;
00257     numCoeff_ = degree+1;
00258     xfunc_.degree = degree;
00259     xfunc_.coeff = 0;
00260     yfunc_.degree = degree;
00261     yfunc_.coeff = 0;
00262 }
00263 
00264 bool Curve2DPolynomial::calcFunction(float curveLength) {
00265     if (ctrlPoints_.size() < (size_t)numCoeff_)
00266         return false;
00267 
00268     if (!xfunc_.coeff){
00269         xfunc_.coeff = new float[numCoeff_];
00270         yfunc_.coeff = new float[numCoeff_];
00271     }
00272 
00273     /*
00274     Calculate a least-squares-fit of the polynomial function to the control points.
00275     For each coordinate (x,y,z) there is one polynomial function. The least-squares-fit
00276     is performed by solving the linear equation system X*c=y,
00277     where X(i,j)=i^j and y holds the control points coordinates.
00278     */
00279 
00280     TNT::Array1D<float> y(ctrlPoints_.size());
00281     TNT::Array2D<float> X(ctrlPoints_.size(), numCoeff_);
00282     TNT::Array1D<float> c(numCoeff_);
00283 
00284     // Create matrix X and the corresponding QR-matrix
00285     for (int i=0; i<static_cast<int>(ctrlPoints_.size()); i++)
00286         for (int j=0; j<numCoeff_; j++)
00287             X[i][j] = pow((float)i, (float)j);
00288 
00289     JAMA::QR<float> QR_Matrix(X);
00290 
00291     // x(t)
00292     for (int i=0; i<static_cast<int>(ctrlPoints_.size()); ++i)
00293         y[i] = ctrlPoints_[i].x;
00294     c = QR_Matrix.solve(y);
00295     for (int i=0; i<numCoeff_; ++i)
00296         xfunc_.coeff[i] = c[i];
00297 
00298     // y(t)
00299     for (int i=0; i<static_cast<int>(ctrlPoints_.size()); ++i)
00300         y[i] = ctrlPoints_[i].y;
00301     c = QR_Matrix.solve(y);
00302     for (int i=0; i<numCoeff_; ++i)
00303         yfunc_.coeff[i] = c[i];
00304 
00305     // map the curve segment's parameter range to [0;1]
00306     paramScale_ = static_cast<float>(ctrlPoints_.size()-1);
00307     paramShift_ = 0.f;
00308     if (curveLength > 0.f) {
00309         float length = getSegmentLength(0.f, 1.f);
00310         paramScale_ = (curveLength / length) * (ctrlPoints_.size()-1);
00311         paramShift_ = -(paramScale_-(ctrlPoints_.size()-1)) / 2.f;
00312     }
00313     return true;
00314 }
00315 
00316 tgt::vec2 Curve2DPolynomial::getCurvePoint(float t) {
00317     float p = t*paramScale_+paramShift_;
00318     tgt::vec2 result;
00319     result.x = evalPolynomial(p, &xfunc_);
00320     result.y = evalPolynomial(p, &yfunc_);
00321     return result;
00322 }
00323 
00324 tgt::vec2 Curve2DPolynomial::getTangent(float t) {
00325     float p = t*paramScale_+paramShift_;
00326     tgt::vec2 result = vec2(0.f);
00327     result.x = evalPolynomialDerivative(p, &xfunc_);
00328     result.y = evalPolynomialDerivative(p, &yfunc_);
00329     return result*paramScale_;
00330 }
00331 
00332 float Curve2DPolynomial::getTangentMagnitude(float t) {
00333     return length(getTangent(t));
00334 }
00335 
00336 
00337 float Curve2DPolynomial::getSegmentLength(float t1, float t2) {
00338     float avgTangentMagnitude = ( getTangentMagnitude(t1) +
00339         getTangentMagnitude((t1+t2)/2.f) +
00340         getTangentMagnitude(t2) ) / 3.f;
00341     return fabs(t2-t1)*avgTangentMagnitude;
00342 }
00343 
00344 tgt::vec2 Curve2DPolynomial::getNextPoint(float &curParam, float offset) {
00345     float pixelsPerParam = getTangentMagnitude(curParam);
00346     curParam += offset / pixelsPerParam;
00347     return getCurvePoint(curParam);
00348 }
00349 
00350 void Curve2DPolynomial::shift(vec2 shiftVector) {
00351     xfunc_.coeff[0] += shiftVector.x;
00352     yfunc_.coeff[0] += shiftVector.y;
00353 
00354     for (size_t i=0; i<ctrlPoints_.size(); i++)
00355         ctrlPoints_[i] = ctrlPoints_[i] + shiftVector;
00356 }
00357 
00358 //----------------------------------------------------------------------------
00359 
00360 BezierPatch::BezierPatch(bool useDisplayList) {
00361     degreeS_ = -1;
00362     degreeT_ = -1;
00363     ctrlPoints_ = NULL;
00364     displayList_ = 0;
00365     useDisplayList_ = useDisplayList;
00366 }
00367 
00368 BezierPatch::~BezierPatch() {
00369     if (displayList_ > 0) {
00370         glDeleteLists(displayList_, 1);
00371         displayList_ = 0;
00372     }
00373 }
00374 
00375 int BezierPatch::getDegreeS(){
00376     return degreeS_;
00377 }
00378 
00379 int BezierPatch::getDegreeT(){
00380     return degreeT_;
00381 }
00382 
00383 void BezierPatch::setCtrlPoints(vec3* ctrlPoints, int degreeS, int degreeT) {
00384     delete ctrlPoints_;
00385 
00386     ctrlPoints_ = ctrlPoints;
00387     degreeS_ = degreeS;
00388     degreeT_ = degreeT;
00389     if (displayList_ > 0) {
00390         glDeleteLists(displayList_, 1);
00391         displayList_ = 0;
00392     }
00393 }
00394 
00395 vec3* BezierPatch::getCtrlPoints(int &degreeS, int &degreeT) {
00396     degreeS = degreeS_;
00397     degreeT = degreeT_;
00398     return ctrlPoints_;
00399 }
00400 
00401 vec3 BezierPatch::getPoint(float s, float t) {
00402     vec3 result = vec3(0.f);
00403     for (int i=0; i<=degreeS_; ++i) {
00404         for (int j=0; j<=degreeT_; ++j) {
00405             result += bernstein(s,i,degreeS_)*bernstein(t,j,degreeT_)*
00406                 ctrlPoints_[j*(degreeS_+1)+i];
00407         }
00408     }
00409     return result;
00410 }
00411 
00412 vec3 BezierPatch::getTangentS(float s, float t) {
00413     vec3 result = vec3(0.f);
00414     for (int i=0; i<=degreeS_; ++i){
00415         for (int j=0; j<=degreeT_; ++j) {
00416             result += bernsteinDerivative(s,i,degreeS_)*bernstein(t,j,degreeT_)*
00417                 ctrlPoints_[j*(degreeS_+1)+i];
00418         }
00419     }
00420     return result;
00421 }
00422 
00423 vec3 BezierPatch::getTangentT(float s, float t) {
00424     vec3 result = vec3(0.f);
00425     for (int i=0; i<=degreeS_; ++i) {
00426         for (int j=0; j<=degreeT_; ++j) {
00427             result += bernstein(s,i,degreeS_)*bernsteinDerivative(t,j,degreeT_)*
00428                 ctrlPoints_[j*(degreeS_+1)+i];
00429         }
00430     }
00431     return result;
00432 }
00433 
00434 vec3 BezierPatch::getNormal(float s, float t){
00435     vec3 tangentS = getTangentS(s,t);
00436     vec3 tangentT = getTangentT(s,t);
00437     vec3 result = normalize(cross(tangentS,tangentT));
00438 
00439     return result;
00440 }
00441 
00442 void BezierPatch::render(int s_steps, int t_steps, bool genTexCoords, GLuint texUnit) {
00443     bool creatingDisplayList = false;
00444     if (displayList_ == 0 && useDisplayList_) {
00445         displayList_ = glGenLists(1);
00446         glNewList(displayList_, GL_COMPILE);
00447         creatingDisplayList = true;
00448     }
00449 
00450     if (displayList_ == 0 || creatingDisplayList) {
00451         float s_offset = 1/(s_steps+1.f);
00452         float t_offset = 1/(t_steps+1.f);
00453         for (float s=0.f; s<0.99; s += s_offset ) {
00454             vec3 last0 = getPoint(s,0.f);
00455             vec3 last1 = getPoint(s+s_offset,0.f);
00456             glBegin(GL_QUAD_STRIP);
00457             if (genTexCoords)
00458                 glMultiTexCoord2f( texUnit, s, 0.f );
00459             glVertex3fv(last0.elem);
00460             if (genTexCoords)
00461                 glMultiTexCoord2f( texUnit, s+s_offset, 0.f );
00462             glVertex3fv(last1.elem);
00463             for (float t=t_offset; t<1.01f; t += t_offset) {
00464                 vec3 cur0 = getPoint(s, t);
00465                 vec3 cur1 = getPoint(s+s_offset, t);
00466                 if (genTexCoords)
00467                     glMultiTexCoord2f(texUnit, s,t);
00468                 glVertex3fv(cur0.elem);
00469                 if (genTexCoords)
00470                     glMultiTexCoord2f(texUnit, s+s_offset,t);
00471                 glVertex3fv(cur1.elem);
00472 
00473                 last0 = cur0;
00474                 last1 = cur1;
00475             }
00476             glEnd();
00477         }
00478     }
00479 
00480     if (creatingDisplayList)
00481         glEndList();
00482 
00483     if (displayList_ != 0)
00484         glCallList(displayList_);
00485 
00486     // tried to use opengl evaluators for rendering the patch. problem is
00487     // that I did not manage to generate texture coords for a texture unit
00488     // different from the first.
00489 
00490     /*
00491     GLfloat* ctrlPoints = new GLfloat[(degreeS_+1)*(degreeT_+1)*3];
00492     for (int i=0; i<(degreeS_+1)*(degreeT_+1); i++){
00493     vec3 point = ctrlPoints_[i];
00494     ctrlPoints[3*i] = point.x;
00495     ctrlPoints[3*i+1] = point.y;
00496     ctrlPoints[3*i+2] = point.z;
00497     }
00498     glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, degreeS_+1, 0, 1,
00499         (degreeS_+1)*3, degreeT_+1, ctrlPoints);
00500 
00501     GLfloat texpts[2][2][2] = {{{0.0, 0.0}, {0.0, 1.0}},
00502     {{1.0, 0.0}, {1.0, 1.0}}};
00503     glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2,
00504     0, 1, 4, 2, &texpts[0][0][0]);
00505 
00506     glEnable(GL_MAP2_VERTEX_3);
00507     glEnable(GL_MAP2_TEXTURE_COORD_2);
00508 
00509     glMapGrid2f(10, 0, 1, 10, 0, 1);
00510     glEvalMesh2(GL_FILL, 0, 10, 0, 10);
00511     glDisable(GL_MAP2_VERTEX_3);
00512     glDisable(GL_MAP2_TEXTURE_COORD_2);
00513 
00514     delete ctrlPoints; */
00515 }
00516 
00517 //----------------------------------------------------------------------------
  • Getting Started
  • Video Tutorials
  • Build Instructions
  • Adding a Module
  • Programming Tutorials
  • API Documentation
  • FAQ
edit