Mondschein Engine  0.3.0
nurbspatch.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/nurbspatch.h"
22 #include "core/nurbscurve.h"
23 #include "core/normgrid.h"
24 #include "core/mesh.h"
25 
26 using namespace mondschein;
27 using namespace math;
28 
29 void NURBSpatch::uniform_knots()
30 {
31  try
32  {
33  knots.clear();
34  if (curves.size()<=degree) return;
35  knots.assign(curves.size()+degree+1,0.0);
36  float64 k=knots.size()-degree-1;
37 
38  // Set the knot values in uniform length
39  for (uint32 i=degree; i<k; ++i)
40  {
41  knots.at(i)=(i-degree)/(k-degree);
42  }
43  for (uint32 i=k; i<knots.size(); ++i)
44  {
45  knots.at(i)=1.0;
46  }
47  return;
48  }
49  catch (std::exception &e)
50  {
51  std::string err("Mondschein Engine ERROR: ");
52  err+=e.what();
53  err+=", exception raised in function\n\t";
54  err+="void mondschein::math::NURBSpatch::uniform_knots()";
55  throw boost::enable_current_exception(exception()) << exception_error(err);
56  }
57 }
58 
59 void NURBSpatch::chord_knots()
60 {
61  try
62  {
63  knots.clear();
64  if (curves.size()<=degree) return;
65  knots.assign(curves.size()+degree+1,0.0);
66  float64 k=knots.size()-degree-1;
67 
68  // Calculate the curve meridians
69  std::vector<Eigen::Vector4d> p;
70  for (uint32 i=0; i<curves.size(); ++i)
71  {
72  p.push_back(Eigen::Vector4d(0,0,0,0));
73  uint32 size=curves.at(i)->get_points().size();
74  for (uint32 j=0; j<size; ++j)
75  {
76  p.back()+=curves.at(i)->get_points().at(j);
77  }
78  p.back()/=p.back().norm();
79  }
80 
81  // Calculate the meridian distances
82  std::vector<float64> distances(1,0.0);
83  for (uint32 i=1; i<p.size(); ++i)
84  {
85  distances.push_back(distances.at(i-1)+(p.at(i)-p.at(i-1)).norm());
86  }
87 
88  // Create knot values in chord length
89  for (uint32 i=degree; i<k; ++i)
90  {
91  knots.at(i)=distances.at(i-degree)/distances.back();
92  }
93  for (uint32 i=k; i<knots.size(); ++i)
94  {
95  knots.at(i)=1.0;
96  }
97  return;
98  }
99  catch (std::exception &e)
100  {
101  std::string err("Mondschein Engine ERROR: ");
102  err+=e.what();
103  err+=", exception raised in function\n\t";
104  err+="void mondschein::math::NURBSpatch::chord_knots()";
105  throw boost::enable_current_exception(exception()) << exception_error(err);
106  }
107 }
108 
109 NURBSpatch::NURBSpatch() : degree(1), curves(), knots()
110 {
111  return;
112 }
113 
114 NURBSpatch::NURBSpatch(uint32 _d,const std::vector<NURBScurve_p> &_c) : degree(_d), curves(_c), knots()
115 {
116  return;
117 }
118 
119 NURBSpatch::NURBSpatch(NURBSpatch_c _p) : degree(_p->degree), curves(_p->curves), knots(_p->knots)
120 {
121  return;
122 }
123 
124 NURBSpatch::~NURBSpatch()
125 {
126  return;
127 }
128 
129 NURBSpatch &NURBSpatch::operator=(NURBSpatch_c _p)
130 {
131  degree=_p->degree;
132  curves=_p->curves;
133  knots=_p->knots;
134  return *this;
135 }
136 
137 Eigen::Vector3d NURBSpatch::operator()(float64 _t,float64 _u) const
138 {
139  try
140  {
141  return get_point(_t,_u);
142  }
143  catch (exception &e)
144  {
145  std::string err(*boost::get_error_info<exception_error>(e));
146  err+=", called in function\n\t";
147  err+="Eigen::Vector4d mondschein::math::NURBSpatch::operator()(float64 _t,float64 _u) const";
148  throw boost::enable_current_exception(e) << exception_error(err);
149  }
150 }
151 
153 {
154  if (_d==0) _d=1;
155  degree=_d;
156  return;
157 }
158 
160 {
161  return degree;
162 }
163 
164 void NURBSpatch::set_curves(const std::vector<NURBScurve_p> &_c)
165 {
166  curves=_c;
167  return;
168 }
169 
170 std::vector<NURBScurve_p> NURBSpatch::get_curves() const
171 {
172  return curves;
173 }
174 
176 {
177  try
178  {
179  if (_cl) chord_knots();
180  else uniform_knots();
181  return;
182  }
183  catch (exception &e)
184  {
185  std::string err(*boost::get_error_info<exception_error>(e));
186  err+=", called in function\n\t";
187  err+="void mondschein::math::NURBSpatch::calc_knots(bool _cl) const";
188  throw boost::enable_current_exception(e) << exception_error(err);
189  }
190 }
191 
192 Eigen::Vector3d NURBSpatch::get_point(float64 _t,float64 _u) const
193 {
194  if (knots.empty())
195  {
196  std::string err("Mondschein Engine ERROR: Knot vector is empty, but must be initialized. ");
197  err+="Exception raised in function\n\t";
198  err+="Eigen::Vector3d mondschein::math::NURBSpatch::get_point(mondschein::float64 _t,mondschein::float64 _u) const";
199  throw boost::enable_current_exception(exception()) << exception_error(err);
200  }
201  try
202  {
203  // Clamp _u
204  if (_u<=0) return curves.front()->get_point(_t);
205  else if (_u>=1.0) return curves.back()->get_point(_t);
206 
207  // Find the interval
208  uint32 i = distance(knots.begin(),upper_bound(knots.begin(),knots.end(),_u))-1;
209 
210  // Create the deBoor vector of the needed control points
211  std::vector<Eigen::Vector3d> v(degree+1,Eigen::Vector3d(0,0,0));
212  for (uint32 j=i-degree; j<=i; ++j) v.at(j-(i-degree))=curves.at(j)->get_point(_t);
213 
214  // Calculate the curve point by performing the deBoor iterations
215  for (uint32 r=1; r<=degree; ++r)
216  {
217  for (uint32 j=i; j>=i-(degree-r); --j)
218  {
219  uint32 m=j-i+degree;
220  float64 c=(_u-knots.at(j)/(knots.at(j+degree-r+1) - knots.at(j)));
221  v.at(m)=(1-c)*v.at(m-1)+c*v.at(m);
222  }
223  }
224  return v.back();
225  }
226  catch (exception &e)
227  {
228  std::string err(*boost::get_error_info<exception_error>(e));
229  err+=", called in function\n\t";
230  err+="Eigen::Vector4d mondschein::math::NURBSpatch::operator()(float64 _t,float64 _u) const";
231  throw boost::enable_current_exception(e) << exception_error(err);
232  }
233  catch (std::exception &e)
234  {
235  std::string err("Mondschein Engine ERROR: ");
236  err+=e.what();
237  err+=", exception raised in function\n\t";
238  err+="void mondschein::math::NURBSpatch::chord_knots()";
239  throw boost::enable_current_exception(exception()) << exception_error(err);
240  }
241 }
242 
243 scene::Mesh_p NURBSpatch::generate_mesh(float64 _t,float64 _u,normal_calculation_e _normals) const
244 {
245  try
246  {
247  float64 n=1/_t;
248  float64 m=1/_u;
249  std::vector<std::vector<Eigen::Vector3d> > grid;
250  for (float64 t=0; t<=1; t+=n)
251  {
252  std::vector<Eigen::Vector3d> _grid;
253  for (float64 u=0; u<=1; u+=m)
254  {
255  _grid.push_back(get_point(t,u));
256  }
257  grid.push_back(_grid);
258  }
259  Normal_Grid_p ng(new Normal_Grid());
260  std::vector<Eigen::Vector3d> normals;
261  switch (_normals)
262  {
263  case FLAT:
264  normals=ng->flat(grid);
265  break;
266 
267  case FLAT_INV:
268  normals=ng->flat_inv(grid);
269  break;
270 
271  case INTERMEDIATE:
272  normals=ng->intermediate(grid);
273  break;
274 
275  case INTERMEDIATE_INV:
276  normals=ng->intermediate_inv(grid);
277  break;
278 
279  default:
280  std::string err("Mondschein Engine ERROR: Normal calculation type not supported. ");
281  err+="Exception raised in function\n\t";
282  err+="mondschein::scene::Mesh_p mondschein::math::Bezierpatch::generate_mesh(float64 _n,";
283  err+="float64 _m, mondschein::normal_calculation_e _normals) const";
284  throw boost::enable_current_exception(exception()) << exception_error(err);
285  break;
286  }
287  std::vector<Eigen::Vector4d> v;
288  std::vector<Eigen::Vector3d> vn;
289  std::vector<Eigen::Vector4d> vt;
290  std::vector<Eigen::Vector4d> vc;
291  Eigen::Vector4d tmp;
292  for (uint32 i=0; i<grid.size()-1; ++i)
293  {
294  for (uint32 j=0; j<grid.at(i).size()-1; ++j)
295  {
296  tmp << grid.at(i).at(j),1.0;
297  v.push_back(tmp);
298  tmp << grid.at(i+1).at(j),1.0;
299  v.push_back(tmp);
300  tmp << grid.at(i).at(j+1),1.0;
301  v.push_back(tmp);
302  if (_normals < INTERMEDIATE)
303  {
304  vn.push_back(normals.at(grid.at(i).size()*i+j*2));
305  vn.push_back(normals.at(grid.at(i).size()*i+j*2));
306  vn.push_back(normals.at(grid.at(i).size()*i+j*2));
307  }
308  else
309  {
310  vn.push_back(normals.at(grid.at(i).size()*(i)+j));
311  vn.push_back(normals.at(grid.at(i+1).size()*(i+1)+j));
312  vn.push_back(normals.at(grid.at(i).size()*(i)+j+1));
313  }
314  vt.push_back(Eigen::Vector4d(static_cast<float64>(i)/grid.size(),static_cast<float64>(j)/grid.at(i).size(),
315  0.0,1.0));
316  vt.push_back(Eigen::Vector4d(static_cast<float64>(i+1)/grid.size(),static_cast<float64>(j)/grid.at(i).size(),
317  0.0,1.0));
318  vt.push_back(Eigen::Vector4d(static_cast<float64>(i)/grid.size(),static_cast<float64>(j+1)/grid.at(i).size(),
319  0.0,1.0));
320  vc.push_back(Eigen::Vector4d(1.0,1.0,1.0,1.0));
321  vc.push_back(Eigen::Vector4d(1.0,1.0,1.0,1.0));
322  vc.push_back(Eigen::Vector4d(1.0,1.0,1.0,1.0));
323 
324  tmp << grid.at(i).at(j+1),1.0;
325  v.push_back(tmp);
326  tmp << grid.at(i+1).at(j),1.0;
327  v.push_back(tmp);
328  tmp << grid.at(i+1).at(j+1),1.0;
329  v.push_back(tmp);
330  if (_normals < INTERMEDIATE)
331  {
332  vn.push_back(normals.at(grid.at(i).size()*i+j*2+1));
333  vn.push_back(normals.at(grid.at(i).size()*i+j*2+1));
334  vn.push_back(normals.at(grid.at(i).size()*i+j*2+1));
335  }
336  else
337  {
338  vn.push_back(normals.at(grid.at(i).size()*(i)+j+1));
339  vn.push_back(normals.at(grid.at(i+1).size()*(i+1)+j));
340  vn.push_back(normals.at(grid.at(i+1).size()*(i+1)+j+1));
341  }
342  vt.push_back(Eigen::Vector4d(static_cast<float64>(i)/grid.size(),static_cast<float64>(j+1)/grid.at(i).size(),
343  0.0,1.0));
344  vt.push_back(Eigen::Vector4d(static_cast<float64>(i+1)/grid.size(),static_cast<float64>(j)/grid.at(i).size(),
345  0.0,1.0));
346  vt.push_back(Eigen::Vector4d(static_cast<float64>(i+1)/grid.size(),static_cast<float64>(j+1)/grid.at(i).size(),
347  0.0,1.0));
348  vc.push_back(Eigen::Vector4d(1.0,1.0,1.0,1.0));
349  vc.push_back(Eigen::Vector4d(1.0,1.0,1.0,1.0));
350  vc.push_back(Eigen::Vector4d(1.0,1.0,1.0,1.0));
351  }
352  }
353  return scene::Mesh_p(new scene::Mesh("NURBSPatch",scene::mesh_attribs_t(v,vn,vt,vc)));
354  }
355  catch (exception &e)
356  {
357  std::string err(*boost::get_error_info<exception_error>(e));
358  err+=", called in function\n\t";
359  err+="mondschein::scene::Mesh_p mondschein::math::NURBSpatch::generate_mesh(float64 _t,float64 _u,";
360  err+="normal_calculation_e _normals) const";
361  throw boost::enable_current_exception(e) << exception_error(err);
362  }
363 }