fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / NodeCores / Drawables / Nurbs / Internal / OSGBSplineCurve2D.cpp
blobdd0cc722a03e2bf753035ba4d334441f30de8b97
1 /*---------------------------------------------------------------------------*\
2 * OpenSG NURBS Library *
3 * *
4 * *
5 * Copyright (C) 2001-2006 by the University of Bonn, Computer Graphics Group*
6 * *
7 * http://cg.cs.uni-bonn.de/ *
8 * *
9 * contact: edhellon@cs.uni-bonn.de, guthe@cs.uni-bonn.de, rk@cs.uni-bonn.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
38 #ifdef WIN32
39 # pragma warning (disable : 985)
40 #endif
41 #include "OSGBSplineCurve2D.h"
43 OSG_USING_NAMESPACE
45 #ifdef _DEBUG
46 #ifdef WIN32
47 #undef THIS_FILE
48 static char THIS_FILE[] = __FILE__;
49 #endif
50 #endif
52 const char BSplineCurve2D::ff_const_1[] = "BEGINBSPLINECURVE2D";
53 const char BSplineCurve2D::ff_const_2[] = "DIMENSION";
54 const char BSplineCurve2D::ff_const_3[] = "NUMBEROFCONTROLPOINTS";
55 const char BSplineCurve2D::ff_const_4[] = "BEGINRATIONALBSPLINECURVE2D";
57 int BSplineCurve2D::CheckKnotPoints(const DCTPdvector& knots, int dim)
59 //now check knotvector whether it has
60 //(a,a,....a, ......., b,b,....b)
61 // |-dim+1-| |-dim+1-|
62 //structure
64 DCTPdvector::size_type max_index = knots.size() - 1;
65 double test_begin = knots[0], test_end = knots[max_index];
67 for(DCTPdvector::size_type i = 1; i < static_cast<unsigned int>(dim) + 1; ++i)
68 if(knots[i] != test_begin || knots[max_index - i] != test_end)
69 return -1; //FIXME: double comparison ?!
71 return 0;
74 int BSplineCurve2D::deleteBezierKnot(double k)
76 DCTPdvector knots = basis_function.getKnotVector();
78 if(k >= knots[knots.size() - 1])
79 return -1; // knot is too high
80 if(k <= knots[0])
81 return -2; // knot is too low
83 DCTPdvector::size_type i = 0;
84 int mult = 0;
85 while(knots[i] <= k)
87 if(knots[i] == k)
88 mult++;
89 i++;
91 if(mult < dimension + 1)
92 return -2; // knot doesn't have enough multiplicity
93 i--;
95 // delete from knotvector
96 knots.erase(knots.begin() + i);
97 // set new knot vector
98 basis_function.setKnotVector(knots);
99 // delete control point corresponding to just deleted knot
100 control_points.erase(control_points.begin() + i - dimension);
101 return 0;
105 //setup functions
106 int BSplineCurve2D::setKnotsAndDimension(const DCTPdvector& knots, int dim)
108 if(dim < 1)
109 return -1; //invalid dimension
111 DCTPdvector::size_type max_index = knots.size() - 1;
112 if(max_index < 3)
113 return -2; //here's an implicit check fer structure, see below
115 if(CheckKnotPoints(knots, dim) )
116 return -3;
118 dimension = dim;
119 if(basis_function.setKnotVector(knots) )
120 return -4; //error in BSplineBasisFunction.setKno...
122 return 0;
125 void BSplineCurve2D::setControlPointVector(const DCTPVec3dvector &cps)
127 control_points = cps;
130 //query functions
131 void BSplineCurve2D::getParameterInterval(double &minpar, double &maxpar)
133 basis_function.getParameterInterval(minpar, maxpar);
136 //I/O facilities - FIXME: read( char *fname ), etc. missing
137 int BSplineCurve2D::read(std::istream &infile)
139 //FIXME: maybe we need more checks!!!
140 char txtbuffer[256];
141 bool israt = false;
142 bool isemptyknot = false;
145 infile.getline(txtbuffer, 255); //read line
146 if(strcmp(txtbuffer, ff_const_1) &&
147 strcmp(txtbuffer, ff_const_4))
149 return -1; //bad file format
151 if(!strcmp(txtbuffer, ff_const_4))
153 israt = true;
155 infile >> txtbuffer; //FIXME: error prone: too long string causes problem!!!
156 if(strcmp(txtbuffer, ff_const_2) )
157 return -1; //yeah, bad file format again
159 infile >> dimension >> std::ws;
160 if(dimension < 1)
161 return -2; //ah, bad dimension
163 int knoterr = basis_function.read(infile);
164 if(knoterr == -3) // FIXME: hardwired val...
166 isemptyknot = true;
168 else if(knoterr)
170 return -3; //error reading basis function
172 if(CheckKnotPoints(basis_function.getKnotVector(), dimension) )
173 return -4;
175 infile >> txtbuffer; //FIXME: error prone: too long string causes problem!!!
176 if(strcmp(txtbuffer, ff_const_3) )
177 return -1; //bad file format once again
179 DCTPVec3dvector::size_type num_of_cps;
180 infile >> num_of_cps >> std::ws;
181 if(num_of_cps < 1)
182 return -5; //too few control points
183 control_points.resize(num_of_cps); //FIXME: whatif not enoght memory?
185 for(DCTPdvector::size_type i = 0; i < num_of_cps; ++i)
187 Vec3d cp;
188 if(israt)
190 infile >> cp[0] >> cp[1] >> cp[2] >> std::ws;
192 else
194 infile >> cp[0] >> cp[1] >> std::ws;
195 cp[2] = 1.0;
197 control_points[i] = cp; //FIXME: ya see, we need ERROR CHECKS!!!
200 if(isemptyknot)
202 return -10;
205 return 0;
208 int BSplineCurve2D::write(std::ostream &outfile)
210 bool israt = false;
211 DCTPdvector::size_type i = 0;
213 for(i = 0; i < control_points.size(); ++i)
215 if(osgAbs(control_points[i][2] - 1.0) > DCTP_EPS)
217 israt = true;
218 break;
222 //FIXME: maybe we need more checks!!!
223 outfile.precision(DCTP_PRECISION);
224 if(!israt)
226 outfile << ff_const_1 << std::endl;
228 else
230 outfile << ff_const_4 << std::endl;
232 outfile << ff_const_2 << " " << dimension << std::endl;
233 basis_function.write(outfile);
234 DCTPdvector::size_type num_of_cps = control_points.size();
235 outfile << ff_const_3 << " " << num_of_cps << std::endl;
237 for(i = 0; i < num_of_cps; ++i)
239 Vec3d cp = control_points[i];
240 if(!israt)
242 outfile << cp[0] << " " << cp[1] << std::endl;
244 else
246 outfile << cp[0] << " " << cp[1] << " " << cp[2] << std::endl;
251 return 0;
255 //some REAL functionality
256 Vec2d BSplineCurve2D::compute(double t, int &error)
258 //FIXME: verification before goin' into computation!!
259 double *pd_n;
260 int span = basis_function.computeAllNonzero(t, dimension, pd_n);
261 Vec2d result(0.0, 0.0);
262 Vec3d rat_res(0.0, 0.0, 0.0);
263 if(span < 0)
265 error = span;
266 return result; //error occured in BSplineBasisFunction.computeAll...
269 for(int i = 0; i <= dimension; ++i)
271 rat_res = rat_res + control_points[span - dimension + i] * pd_n[i];
274 delete[] pd_n;
275 result[0] = rat_res[0] / rat_res[2];
276 result[1] = rat_res[1] / rat_res[2];
277 return result;
280 //insert knot. Returns < 0 on error, otherwise 0.
281 int BSplineCurve2D::insertKnot(double k)
283 DCTPdvector knots = basis_function.getKnotVector();
284 int span = basis_function.insertKnot(k);
285 if(span < 0)
286 return span; // some error happened
288 DCTPVec3dvector newcps;
289 newcps.resize(control_points.size() + 1);
290 DCTPVec3dvector::size_type i;
292 for(i = 0; i <= static_cast<unsigned int>(span) - dimension; i++)
294 newcps[i] = control_points[i];
297 for(i = span - dimension + 1; i <= static_cast<unsigned int>(span); i++)
299 double alpha;
300 if(knots[i + dimension] != knots[i])
302 alpha = (k - knots[i]) / (knots[i + dimension] - knots[i]);
304 else
306 alpha = 0;
308 newcps[i] = control_points[i] * alpha + control_points[i - 1] * (1 - alpha);
311 for(i = span + 1; i < newcps.size(); i++)
314 newcps[i] = control_points[i - 1];
317 control_points = newcps;
318 return 0;
321 int BSplineCurve2D::makeBezier(bezier2dvector &beziers, DCTPdvector &pars)
323 double firstknot, lastknot;
324 basis_function.getParameterInterval(firstknot, lastknot);
325 DCTPdvector knots = basis_function.getKnotVector();
326 DCTPdvector origknots = knots; // backup original curve characteristics
327 DCTPVec3dvector origcps = control_points; // same here
328 double prevknot = firstknot;
329 int mult = 0;
330 int err;
331 unsigned int i;
333 for(i = 1; i < knots.size(); i++)
335 double actk = knots[i];
336 if(actk == prevknot)
337 mult++;
338 else
340 for(int j = mult + 1; j < dimension; j++) //each interior knot must have the multiplicity of dimension-1
341 { //each interior knot must have the multiplicity of dimension -1
342 err = insertKnot(prevknot);
343 if(err)
344 return err; // some error happened during insertKnot
347 if(prevknot != firstknot && prevknot != lastknot)
349 for(int j = mult; j > dimension - 1; j--)
351 err = deleteBezierKnot(prevknot);
352 if(err)
353 return err; // some error happened during deleteBezierKnot
356 mult = 0;
358 prevknot = actk;
361 // now do the actual conversation into n. bezier segments
362 knots = basis_function.getKnotVector(); // FIXME: it could be more efficient.
363 unsigned int num_of_beziers = (UInt32(knots.size()) - 2) / dimension - 1;
364 if( (num_of_beziers * dimension + 2) != knots.size() - dimension)
366 basis_function.setKnotVector(origknots);
367 control_points = origcps;
368 return -5;
371 beziers.resize(num_of_beziers);
372 pars.resize(num_of_beziers + 1);
374 for(i = 0; i < num_of_beziers + 1; i++)
375 pars[i] = knots[1 + dimension * i];
377 DCTPVec3dvector beziercps(dimension + 1);
378 Vec3d firstcp;
379 bool degenerate;
380 bezier2dvector::size_type bezind = 0;
381 bezier2dvector::size_type orig_num_of_beziers = num_of_beziers;
383 for(i = 0; i < orig_num_of_beziers; i++)
385 firstcp = control_points[i * dimension + 0];
386 degenerate = true;
388 for(DCTPVec3dvector::size_type j = 0;
389 j < static_cast<unsigned int>(dimension) + 1; j++)
391 beziercps[j] = control_points[i * dimension + j];
392 if(degenerate)
393 if(DCTPVecIsNotEqual(firstcp, beziercps[j]) )
395 degenerate = false;
397 } // j
399 if(degenerate)
401 num_of_beziers--;
402 bezier2dvector::iterator bi = beziers.begin() + bezind; // + i ???
403 DCTPdvector::iterator pi = pars.begin() + bezind;
404 beziers.erase(bi); beziers.resize(num_of_beziers);
405 pars.erase(pi); pars.resize(num_of_beziers + 1);
406 // std::cerr << "Ignoring degenerate curve... " << std::endl;
408 else
410 beziers[bezind++].setControlPointVector(beziercps);
412 } // i
414 // restore original curve
415 basis_function.setKnotVector(origknots);
416 control_points = origcps;
417 return 0;