Mondschein Engine  0.3.0
nurbscurve.cpp
1 /* Mondschein Engine is a fast, powerful, and easy-to-use 3D realtime rendering engine.
2  *
3  * Copyright (C) 2009-2013 by Andreas Amereller
4  * E-Mail: andreas.amereller.dev@googlemail.com
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include "core/nurbscurve.h"
22 //#include <algorithm>
23 
24 using namespace mondschein;
25 using namespace math;
26 
27 void NURBScurve::uniform_knots()
28 {
29  try
30  {
31  knots.clear();
32  if (points.size()<=degree) return;
33  knots.assign(points.size()+degree+1,0.0);
34  float64 k=knots.size()-degree-1;
35 
36  // Set the knot values in uniform length
37  for (uint32 i=degree; i<k; ++i)
38  {
39  knots.at(i)=(i-degree)/(k-degree);
40  }
41  for (uint32 i=k; i<knots.size(); ++i)
42  {
43  knots.at(i)=1.0;
44  }
45  return;
46  }
47  catch (std::exception &e)
48  {
49  std::string err("Mondschein Engine ERROR: ");
50  err+=e.what();
51  err+=", exception raised in function\n\t";
52  err+="void mondschein::math::NURBScurve::uniform_knots()";
53  throw boost::enable_current_exception(exception()) << exception_error(err);
54  }
55 }
56 
57 void NURBScurve::chord_knots()
58 {
59  try
60  {
61  knots.clear();
62  if (points.size()<=degree) return;
63  knots.assign(points.size()+degree+1,0.0);
64  float64 k=knots.size()-degree-1;
65 
66  // Calculate the control point distances
67  std::vector<float64> distances(1,0.0);
68  for (uint32 i=1; i<points.size(); ++i)
69  {
70  distances.push_back(distances.at(i-1)+(points.at(i)-points.at(i-1)).norm());
71  }
72 
73  // Create knot values in chord length
74  for (uint32 i=degree; i<k; ++i)
75  {
76  knots.at(i)=distances.at(i-degree)/distances.back();
77  }
78  for (uint32 i=k; i<knots.size(); ++i)
79  {
80  knots.at(i)=1.0;
81  }
82  return;
83  }
84  catch (std::exception &e)
85  {
86  std::string err("Mondschein Engine ERROR: ");
87  err+=e.what();
88  err+=", exception raised in function\n\t";
89  err+="void mondschein::math::NURBScurve::chord_knots()";
90  throw boost::enable_current_exception(exception()) << exception_error(err);
91  }
92 }
93 
94 NURBScurve::NURBScurve() : degree(1), points(), knots()
95 {
96  return;
97 }
98 
99 NURBScurve::NURBScurve(uint32 _d,const std::vector<Eigen::Vector4d> &_p) : degree(_d), points(_p), knots()
100 {
101  return;
102 }
103 
104 NURBScurve::NURBScurve(NURBScurve_c _c) : degree(_c->degree), points(_c->points), knots(_c->knots)
105 {
106  return;
107 }
108 
109 NURBScurve::~NURBScurve()
110 {
111  return;
112 }
113 
114 NURBScurve &NURBScurve::operator=(NURBScurve_c _c)
115 {
116  degree=_c->degree;
117  points=_c->points;
118  knots=_c->knots;
119  return *this;
120 }
121 
122 Eigen::Vector3d NURBScurve::operator()(float64 _t) const
123 {
124  try
125  {
126  return get_point(_t);
127  }
128  catch (exception &e)
129  {
130  std::string err(*boost::get_error_info<exception_error>(e));
131  err+=", called in function\n\t";
132  err+="Eigen::Vector4d mondschein::math::NURBScurve::operator()(float64 _t) const";
133  throw boost::enable_current_exception(e) << exception_error(err);
134  }
135 }
136 
138 {
139  if (_d==0) _d=1;
140  degree=_d;
141  return;
142 }
143 
145 {
146  return degree;
147 }
148 
149 void NURBScurve::set_points(const std::vector<Eigen::Vector4d> &_p)
150 {
151  points=_p;
152  return;
153 }
154 
155 std::vector<Eigen::Vector4d> NURBScurve::get_points() const
156 {
157  return points;
158 }
159 
161 {
162  try
163  {
164  if (_cl) chord_knots();
165  else uniform_knots();
166  return;
167  }
168  catch (exception &e)
169  {
170  std::string err(*boost::get_error_info<exception_error>(e));
171  err+=", called in function\n\t";
172  err+="void mondschein::math::NURBScurve::calc_knots(bool _cl) const";
173  throw boost::enable_current_exception(e) << exception_error(err);
174  }
175 }
176 
177 Eigen::Vector3d NURBScurve::get_point(float64 _t) const
178 {
179  if (knots.empty())
180  {
181  std::string err("Mondschein Engine ERROR: Knot vector must not be empty. ");
182  err+="Exception raised in function\n\t";
183  err+="Eigen::Vector3d mondschein::math::NURBScurve::get_point(mondschein::float64 _t) const";
184  throw boost::enable_current_exception(exception()) << exception_error(err);
185  }
186  try
187  {
188  // Clamp _t
189  if (_t<=0) return Eigen::Vector3d(points.front()(0),points.front()(1),points.front()(2));
190  else if (_t>=1.0) return Eigen::Vector3d(points.back()(0),points.back()(1),points.back()(2));
191 
192  // Find the interval
193  uint32 i = distance(knots.begin(),upper_bound(knots.begin(),knots.end(),_t))-1;
194 
195  // Create the deBoor vector of the needed control points
196  std::vector<Eigen::Vector3d> v(degree+1,Eigen::Vector3d(0,0,0));
197  Eigen::Vector4d tmp;
198  for (uint32 j=i-degree; j<=i; ++j)
199  {
200  tmp=points.at(j);
201  v.at(j-(i-degree)) << tmp(0),tmp(1),tmp(2);
202  v.at(j-(i-degree))*=tmp(3);
203  }
204 
205  // Calculate the curve point by performing the deBoor iterations
206  for (uint32 r=1; r<=degree; ++r)
207  {
208  for (uint32 j=i; j>=i-(degree-r); --j)
209  {
210  uint32 m=j-i+degree;
211  float64 c=(_t-knots.at(j)/(knots.at(j+degree-r+1) - knots.at(j)));
212  v.at(m)=(1-c)*v.at(m-1)+c*v.at(m);
213  }
214  }
215  return v.back();
216  }
217  catch (std::exception &e)
218  {
219  std::string err("Mondschein Engine ERROR: ");
220  err+=e.what();
221  err+=", exception raised in function\n\t";
222  err+="void mondschein::math::NURBScurve::get_curve_point(float64 _t)";
223  throw boost::enable_current_exception(exception()) << exception_error(err);
224  }
225 }