Developer Documentation
PrimitivesGenerator.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 #include <cstdlib>
51 
52 #include "PrimitivesGenerator.hh"
53 
54 #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT
55 #include "TetrahedralCuboidGenerator.hh"
56 #endif
57 
58 #ifdef ENABLE_BSPLINECURVE_SUPPORT
60 #endif
61 
62 #ifdef ENABLE_BSPLINESURFACE_SUPPORT
64 #endif
65 
66 PrimitivesGeneratorPlugin::PrimitivesGeneratorPlugin() :
67  triMesh_(0),
68  polyMesh_(0),
69  slices_(50),
70  stacks_(50),
71  primitivesMenu_(0)
72 {
73 
74 }
75 
76 PrimitivesGeneratorPlugin::~PrimitivesGeneratorPlugin()
77 {
78 
79  if ( OpenFlipper::Options::gui()) {
80  delete primitivesMenu_;
81  }
82 
83 }
84 
86 {
87  emit setSlotDescription("addTetrahedron(Vector,double)",
88  tr("Generates a tetrahedron (ObjectId is returned)"),
89  QString("Position,Length").split(","),
90  QString("Center position,Length of each edge").split(","));
91 
92  emit setSlotDescription("addIcosahedron(Vector,double)",
93  tr("Generates an icosahedron (ObjectId is returned)"),
94  QString("Position,Length").split(","),
95  QString("Center position,Length of each edge").split(","));
96 
97  emit setSlotDescription("addPyramid(Vector,double)",
98  tr("Generates a pyramid (ObjectId is returned)"),
99  QString("Position,Length").split(","),
100  QString("Center position,Length of each edge").split(","));
101 
102  emit setSlotDescription("addOctahedron(Vector,double)",
103  tr("Generates an octahedron (ObjectId is returned)"),
104  QString("Position,Length").split(","),
105  QString("Center position,Length of each edge").split(","));
106 
107  emit setSlotDescription("addDodecahedron(Vector,double)",
108  tr("Generates a dodecahedron (ObjectId is returned)"),
109  QString("Position,Length").split(","),
110  QString("Center position,Length of each edge").split(","));
111 
112  emit setSlotDescription("addSphere(Vector,double)",
113  tr("Generates a triangulated sphere with all vertical lines connected to the poles (ObjectId is returned)"),
114  QString("Position, Radius").split(","),
115  QString("Center position,Radius").split(","));
116 
117  emit setSlotDescription("addSubdivisionSphere(Vector,double)",
118  tr("Generates a triangulated sphere by subdivision without poles. (ObjectId is returned)"),
119  QString("Position, Radius").split(","),
120  QString("Center position,Radius").split(","));
121 
122  emit setSlotDescription("addTriangulatedCube(Vector,double)",
123  tr("Generates a triangular mesh of cube (ObjectId is returned)"),
124  QString("Position,Length").split(","),
125  QString("Center position,Length of each edge").split(","));
126 
127  emit setSlotDescription("addTriangulatedCylinder(Vector,Vector,double,double)",
128  tr("Generates a triangulated cylinder (ObjectId is returned)") ,
129  QString("Position,Axis,Radius,Height,Top,Bottom").split(","),
130  QString("Bottom center vertex position,Center axis,radius,height,add top vertex,add bottom vertex").split(","));
131 
132 #ifdef ENABLE_BSPLINECURVE_SUPPORT
133  emit setSlotDescription("addRandomBSplineCurve(Vector,int)",
134  tr("Generates a random B-spline curve (ObjectId is returned)"),
135  QString("Position,Count").split(","),
136  QString("Center position,Number of control points").split(","));
137 #endif
138 
139 #ifdef ENABLE_BSPLINESURFACE_SUPPORT
140  emit setSlotDescription("addRandomBSplineSurface(Vector,int)",
141  tr("Generates a random B-spline surface (ObjectId is returned)"),
142  QString("Position,Count").split(","),
143  QString("Center position,Number of control points").split(","));
144 #endif
145 
146 #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT
147  emit setSlotDescription("addTetrahedralCube(Vector,double)",
148  tr("Generates a tetrahedral mesh of a cube (ObjectId is returned)"),
149  QString("Position,Length").split(","),
150  QString("Center position,Length of each edge").split(","));
151 
152  emit setSlotDescription("addTetrahedralCuboid(Vector,Vector,uint,uint,uint)",
153  tr("Generates a tetrahedral mesh of a cuboid (ObjectId is returned)"),
154  QString("Position,Lengths,Count,Count,Count").split(","),
155  QString("Center position,Length of each side,Number of units in x-axis,Number of units in y-axis,Number of units in z-axis").split(","));
156 #endif
157 
158 }
159 
160 void PrimitivesGeneratorPlugin::pluginsInitialized() {
161 
162  if ( OpenFlipper::Options::gui()) {
163 
164  emit getMenubarMenu(tr("&Primitives"), primitivesMenu_, true );
165 
166  QAction* action;
167 
168  action = primitivesMenu_->addAction("Cube (Triangle Mesh)" ,this,SLOT(addTriangulatedCube()));
169  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cube.png"));
170 
171  WhatsThisGenerator whatsThisGen("PrimitivesGenerator");
172  whatsThisGen.setWhatsThis(action,tr("Create a Cube."),"Cube");
173 
174  action = primitivesMenu_->addAction("Dodecahedron" ,this,SLOT(addDodecahedron()));
175  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_dodecahedron.png"));
176  whatsThisGen.setWhatsThis(action,tr("Create a Dodecahedron."), "Dodecahedron");
177 
178  action = primitivesMenu_->addAction("Icosahedron" ,this,SLOT(addIcosahedron()));
179  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_icosahedron.png"));
180  whatsThisGen.setWhatsThis(action,tr("Create a Icosahedron.","Icosahedron"));
181 
182  action = primitivesMenu_->addAction("Octahedron" ,this,SLOT(addOctahedron()));
183  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_octahedron.png"));
184  whatsThisGen.setWhatsThis(action,tr("Create an Octahedron."),"Octahedron");
185 
186  action = primitivesMenu_->addAction("Pyramid" ,this,SLOT(addPyramid()));
187  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_pyramid.png"));
188  whatsThisGen.setWhatsThis(action,tr("Create a Pyramid."),"Pyramid");
189 
190  action = primitivesMenu_->addAction("Cylinder (Triangle Mesh)" ,this,SLOT(addTriangulatedCylinder()));
191  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cylinder.png"));
192 
193  action = primitivesMenu_->addAction("Sphere (Poles,Triangle Mesh)",this,SLOT(addSphere()));
194  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_sphere.png"));
195  whatsThisGen.setWhatsThis(action,tr("Create a Sphere. All vertical lines connect to poles) "),"Sphere");
196 
197  action = primitivesMenu_->addAction("Sphere (Subdivision,Triangle Mesh)",this,SLOT(addSubdivisionSphere()));
198  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_sphere.png"));
199  whatsThisGen.setWhatsThis(action,tr("Create a Sphere. No poles due to Subdivision) "),"Sphere");
200 
201  action = primitivesMenu_->addAction("Tetrahedron",this,SLOT(addTetrahedron()));
202  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_tetrahedron.png"));
203  whatsThisGen.setWhatsThis(action,tr("Create a Tetrahedron."),"Tetrahedron");
204 
205 #ifdef ENABLE_BSPLINECURVE_SUPPORT
206  action = primitivesMenu_->addAction("Random B-spline curve",this,SLOT(addRandomBSplineCurve()));
207  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "bspline_curve.png"));
208  whatsThisGen.setWhatsThis(action, tr("Create a random B-spline curve."), "B-spline curve");
209 #endif
210 
211 #ifdef ENABLE_BSPLINESURFACE_SUPPORT
212  action = primitivesMenu_->addAction("Random B-spline surface",this,SLOT(addRandomBSplineSurface()));
213  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"bspline_surface.png"));
214  whatsThisGen.setWhatsThis(action,tr("Create a random B-spline surface."),"B-spline surface");
215 #endif
216 
217 #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT
218  action = primitivesMenu_->addAction("Cube (Tetrahedral Mesh)" ,this,SLOT(addTetrahedralCube()));
219  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cube.png"));
220  whatsThisGen.setWhatsThis(action,tr("Create a Tetrahedral Cube."), "Cube");
221 
222  action = primitivesMenu_->addAction("Cuboid (Tetrahedral Mesh)" ,this,SLOT(addTetrahedralCuboid()));
223  action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cube.png"));
224  whatsThisGen.setWhatsThis(action,tr("Create a Tetrahedral Cuboid."), "Cuboid");
225 #endif
226  }
227 }
228 
229 
230 int PrimitivesGeneratorPlugin::addTriMesh() {
231  int objectId = -1;
232 
233  emit addEmptyObject( DATA_TRIANGLE_MESH, objectId );
234 
235  TriMeshObject* object;
236  if ( !PluginFunctions::getObject(objectId,object) ) {
237  emit log(LOGERR,"Unable to create new Object");
238  return -1;
239  }
240 
241  return objectId;
242 }
243 
244 int PrimitivesGeneratorPlugin::addPolyMesh() {
245  int objectId = -1;
246 
247  emit addEmptyObject( DATA_POLY_MESH, objectId );
248 
249  PolyMeshObject* object;
250  if ( !PluginFunctions::getObject(objectId,object) ) {
251  emit log(LOGERR,"Unable to create new Object");
252  return -1;
253  }
254 
255  return objectId;
256 }
257 
258 
259 #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT
260 int PrimitivesGeneratorPlugin::addPolyhedralMesh() {
261  int objectId = -1;
262 
263  emit addEmptyObject( DATA_POLYHEDRAL_MESH, objectId );
264 
265  PolyhedralMeshObject* object;
266  if (!PluginFunctions::getObject(objectId, object) ) {
267  emit log(LOGERR, "Unable to create new PolyhedralMesh object");
268  return -1;
269  }
270 
271 
272  return objectId;
273 }
274 #endif
275 
276 int PrimitivesGeneratorPlugin::addTetrahedron(const Vector& _position, const double _length) {
277 
278  int newObject = addTriMesh();
279 
280  TriMeshObject* object;
281  if ( !PluginFunctions::getObject(newObject,object) ) {
282  emit log(LOGERR,"Unable to create new Object");
283  return -1;
284  } else {
285 
286  object->setName( "Tetrahedron " + QString::number(newObject) );
287 
288  triMesh_ = object->mesh();
289 
290  triMesh_->clear();
291 
292  // Add 4 vertices
293  vhandles_.resize(4);
294 
295  const double halfSize = 0.5*_length;
296 
297  vhandles_[0] = triMesh_->add_vertex(TriMesh::Point(-halfSize, -halfSize, halfSize)+_position);
298  vhandles_[1] = triMesh_->add_vertex(TriMesh::Point( halfSize, halfSize, halfSize)+_position);
299  vhandles_[2] = triMesh_->add_vertex(TriMesh::Point(-halfSize, halfSize, -halfSize)+_position);
300  vhandles_[3] = triMesh_->add_vertex(TriMesh::Point( halfSize, -halfSize, -halfSize)+_position);
301 
302  // Add 4 faces
303  add_face(0,1,2);
304  add_face(0,2,3);
305  add_face(2,1,3);
306  add_face(3,1,0);
307 
308  triMesh_->update_normals();
309 
310  emit updatedObject(newObject,UPDATE_ALL);
311  emit createBackup(newObject, "Original Object");
312 
314 
315  return newObject;
316  }
317 
318  return -1;
319 }
320 
321 int PrimitivesGeneratorPlugin::addTriangulatedCube(const Vector& _position,const double _length) {
322 
323 
324  int newObject = addTriMesh();
325 
326  TriMeshObject* object;
327  if ( !PluginFunctions::getObject(newObject,object) ) {
328  emit log(LOGERR,"Unable to create new Object");
329  return -1;
330  } else {
331 
332  object->setName( "Cube " + QString::number(newObject) );
333 
334  triMesh_ = object->mesh();
335 
336  triMesh_->clear();
337 
338  // Add 8 vertices
339  vhandles_.resize(8);
340 
341  const double halfSize = 0.5*_length;
342 
343  vhandles_[0] = triMesh_->add_vertex(TriMesh::Point( halfSize, -halfSize, halfSize)+_position);
344  vhandles_[1] = triMesh_->add_vertex(TriMesh::Point( halfSize, halfSize, halfSize)+_position);
345  vhandles_[2] = triMesh_->add_vertex(TriMesh::Point(-halfSize, halfSize, halfSize)+_position);
346  vhandles_[3] = triMesh_->add_vertex(TriMesh::Point(-halfSize, -halfSize, halfSize)+_position);
347  vhandles_[4] = triMesh_->add_vertex(TriMesh::Point( halfSize, -halfSize,-halfSize)+_position);
348  vhandles_[5] = triMesh_->add_vertex(TriMesh::Point( halfSize, halfSize,-halfSize)+_position);
349  vhandles_[6] = triMesh_->add_vertex(TriMesh::Point(-halfSize, halfSize,-halfSize)+_position);
350  vhandles_[7] = triMesh_->add_vertex(TriMesh::Point(-halfSize, -halfSize,-halfSize)+_position);
351 
352 
353  // Add 12 faces
354  add_face(0,1,2);
355  add_face(0,2,3);
356  add_face(0,5,1);
357  add_face(5,0,4);
358  add_face(4,0,7);
359  add_face(7,0,3);
360 
361  add_face(7,3,6);
362  add_face(6,3,2);
363  add_face(6,2,5);
364  add_face(5,2,1);
365  add_face(6,5,4);
366  add_face(6,4,7);
367 
368  triMesh_->update_normals();
369 
370  emit updatedObject(newObject,UPDATE_ALL);
371  emit createBackup(newObject, "Original Object");
372 
374 
375  return newObject;
376  }
377 
378  return -1;
379 }
380 
381 //========================================================================
382 // Tetrahedral cube
383 //========================================================================
384 
385 #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT
386 
387 int PrimitivesGeneratorPlugin::addTetrahedralCube(const Vector& _position, const double _length)
388 {
389  return addTetrahedralCuboid(_position, Vector(_length, _length, _length), 1, 1, 1);
390 }
391 
392 #endif
393 
394 //========================================================================
395 // Tetrahedral Cuboid
396 //========================================================================
397 
398 #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT
399 
400 int PrimitivesGeneratorPlugin::addTetrahedralCuboid(const Vector& _position,
401  const Vector& _length, const unsigned int n_x, const unsigned int n_y, const unsigned int n_z)
402 {
403 
404  int object_id = addPolyhedralMesh();
405  PolyhedralMeshObject* object;
406 
407  if (!PluginFunctions::getObject(object_id, object)) {
408  return -1;
409  }
410 
411  object->setName("Cuboid " + QString::number(object_id));
412 
413  TetrahedralCuboidGenerator gen(*(object->mesh()), _position, _length, n_x, n_y, n_z);
414 
415  emit updatedObject(object_id, UPDATE_ALL);
416  emit createBackup(object_id, "Original Object");
417 
418  object->setObjectDrawMode(ACG::SceneGraph::DrawModes::getDrawMode("Cells (flat shaded)"));
420 
421  return object_id;
422 }
423 
424 #endif
425 
426 //========================================================================
427 // Cylinder
428 //========================================================================
429 
430 
431 ACG::Vec3d PrimitivesGeneratorPlugin::positionOnCylinder(const int _sliceNumber,
432  const int _stackNumber,
433  const Vector _position,
434  const Vector _axis,
435  const double _radius,
436  const double _height)
437 {
438  ACG::Vec3d position;
439 
440  const ACG::Vec3d right = (ACG::Geometry::perpendicular(_axis)).normalized();
441  const ACG::Vec3d left = (cross( _axis, right)).normalized();
442 
443  double beta = ((2.0 * M_PI) / double(slices_)) * double(_sliceNumber);
444 
445  if ( _sliceNumber == 0 && _stackNumber == 0) {
446  position[0] = 0.0;
447  position[1] = 0.0;
448  position[2] = _height;
449  } else if ( _sliceNumber == slices_ && _stackNumber == stacks_ ) {
450  position[0] = 0.0;
451  position[1] = 0.0;
452  position[2] = 0.0;
453  } else {
454  position[0] = sin(beta) * _radius;
455  position[1] = cos(beta) * _radius;
456  position[2] = _height * double(stacks_ - _stackNumber -1 ) / double(stacks_-2);
457  }
458 
459  position = _position + position[0] * right + position[1] * left + position[2] * _axis ;
460 
461  return position;
462 }
463 
464 int PrimitivesGeneratorPlugin::addTriangulatedCylinder(const Vector& _position,const Vector& _axis,const double _radius,const double _height,const bool _top,const bool _bottom ) {
465 
466  // TODO: Generate texture coordinates for cylinder (Glu compatible)
467  int newObject = addTriMesh();
468 
469  TriMeshObject* object;
470  if (!PluginFunctions::getObject(newObject, object)) {
471  emit log(LOGERR, "Unable to create new Object");
472  return -1;
473  } else {
474 
475  object->setName( "Cylinder " + QString::number(newObject) );
476 
477  triMesh_ = object->mesh();
478 
479  triMesh_->clear();
480 
481  //triMesh_->request_vertex_texcoords2D();
482 
483  TriMesh::VertexHandle vh;
484  TriMesh::VertexHandle top = triMesh_->add_vertex(positionOnCylinder(0, 0,_position,_axis,_radius,_height));
485  //triMesh_->set_texcoord2D(vh, texCoordOnSphere(0, 0));
486 
487  for (int st = 1; st < stacks_; ++st) {
488  for (int sl = 0; sl < slices_; ++sl) {
489  vh = triMesh_->add_vertex(positionOnCylinder(sl, st,_position,_axis,_radius,_height));
490  //triMesh_->set_texcoord2D(vh, texCoordOnSphere(sl, st));
491  }
492  }
493 
494  TriMesh::VertexHandle bottom = triMesh_->add_vertex(positionOnCylinder(slices_, stacks_,_position,_axis,_radius,_height));
495  //triMesh_->set_texcoord2D(vh, texCoordOnSphere(slices_, stacks_));
496 
497  std::vector<TriMesh::VertexHandle> vhandles;
498 
499  // Add top triangle fan ( Vertex index is shifted by one for the first slice )
500  if ( _top ) {
501  for (int sl = 1; sl < slices_ + 1; ++sl) {
502 
503  vhandles.clear();
504 
505  vhandles.push_back(triMesh_->vertex_handle(sl));
506  vhandles.push_back(triMesh_->vertex_handle(0));
507  vhandles.push_back(triMesh_->vertex_handle(1 * 1 + (sl % slices_)));
508 
509  triMesh_->add_face(vhandles);
510  }
511  } else {
512  triMesh_->delete_vertex(top);
513  }
514 
515  for (int st = 0; st < stacks_ - 2; ++st) {
516 
517  // Move around one slice
518  for (int sl = 0; sl < slices_; ++sl) {
519 
520  // Offset 1 because of singular vertex
521  unsigned int startTop = 1 + slices_ * st;
522  unsigned int startBottom = 1 + slices_ * (st + 1);
523 
524  vhandles.clear();
525 
526  vhandles.push_back(triMesh_->vertex_handle(startTop + sl));
527  vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_)));
528  vhandles.push_back(triMesh_->vertex_handle(startBottom + sl));
529 
530  triMesh_->add_face(vhandles);
531 
532  vhandles.clear();
533 
534  vhandles.push_back(triMesh_->vertex_handle(startBottom + sl));
535  vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_)));
536  vhandles.push_back(triMesh_->vertex_handle(startBottom + ((sl + 1) % slices_)));
537 
538  triMesh_->add_face(vhandles);
539  }
540 
541  }
542 
543  const int startTop = 1 + (stacks_ - 2) * slices_;
544  const int bottomVertex = 1 + (stacks_ - 1) * slices_;
545 
546  // Add bottom triangle fan
547  if ( _bottom) {
548  for (int sl = 0; sl < slices_; ++sl) {
549 
550  vhandles.clear();
551 
552  vhandles.push_back(triMesh_->vertex_handle(bottomVertex));
553  vhandles.push_back(triMesh_->vertex_handle(startTop + sl));
554  vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_)));
555 
556  triMesh_->add_face(vhandles);
557  }
558  } else {
559  triMesh_->delete_vertex(bottom);
560  }
561 
562  // Cleanup if bottom or top vertex is missing
563  triMesh_->garbage_collection();
564 
565  triMesh_->update_normals();
566 
567  emit updatedObject(newObject,UPDATE_ALL);
568  emit createBackup(newObject, "Original Object");
569 
571 
572  return object->id();
573  }
574 
575 }
576 
577 
578 //========================================================================
579 // Sphere
580 //========================================================================
581 
582 
583 ACG::Vec3d PrimitivesGeneratorPlugin::positionOnSphere(int _sliceNumber, int _stackNumber, double _radius, const Vector& _position)
584 {
585  ACG::Vec3d position;
586 
587  double alpha = (M_PI / double(stacks_)) * double(_stackNumber);
588  double beta = ((2.0 * M_PI) / double(slices_)) * double(_sliceNumber);
589 
590  double ringRadius = sin(alpha);
591  position[0] = sin(beta) * ringRadius * _radius;
592  position[1] = cos(beta) * ringRadius * _radius;
593  position[2] = cos(alpha)* _radius;
594 
595  return _position+position;
596 }
597 
598 //------------------------------------------------------------------------
599 
600 ACG::Vec2f PrimitivesGeneratorPlugin::texCoordOnSphere(int _sliceNumber, int _stackNumber)
601 {
602  ACG::Vec2f texCoord;
603 
604  double alpha = (M_PI / double(stacks_)) * double(_stackNumber);
605  texCoord[0] = double(_sliceNumber) / double(slices_);
606  texCoord[1] = 0.5 * (cos(alpha) + 1.0);
607 
608  return texCoord;
609 }
610 
611 
612 //------------------------------------------------------------------------
613 
614 int PrimitivesGeneratorPlugin::addSphere(const Vector& _position, const double _radius)
615 {
616  int newObject = addTriMesh();
617 
618  TriMeshObject* object;
619  if (!PluginFunctions::getObject(newObject, object)) {
620  emit log(LOGERR, "Unable to create new Object");
621  return -1;
622  } else {
623 
624  object->setName( "Sphere " + QString::number(newObject) );
625 
626  triMesh_ = object->mesh();
627 
628  triMesh_->clear();
629 
630  triMesh_->request_vertex_texcoords2D();
631 
632  TriMesh::VertexHandle vh;
633 
634  vh = triMesh_->add_vertex(positionOnSphere(0, 0, _radius,_position));
635  triMesh_->set_texcoord2D(vh, texCoordOnSphere(0, 0));
636 
637  for (int st = 1; st < stacks_; ++st) {
638  for (int sl = 0; sl < slices_; ++sl) {
639  vh = triMesh_->add_vertex(positionOnSphere(sl, st, _radius,_position));
640  triMesh_->set_texcoord2D(vh, texCoordOnSphere(sl, st));
641  }
642  }
643 
644  vh = triMesh_->add_vertex(positionOnSphere(slices_, stacks_, _radius,_position));
645  triMesh_->set_texcoord2D(vh, texCoordOnSphere(slices_, stacks_));
646 
647  std::vector<TriMesh::VertexHandle> vhandles;
648 
649  // Add top triangle fan ( Vertex index is shifted by one for the first slice )
650  for (int sl = 1; sl < slices_ + 1; ++sl) {
651 
652  vhandles.clear();
653 
654  vhandles.push_back(triMesh_->vertex_handle(sl));
655  vhandles.push_back(triMesh_->vertex_handle(0));
656  vhandles.push_back(triMesh_->vertex_handle(1 * 1 + (sl % slices_)));
657 
658  triMesh_->add_face(vhandles);
659  }
660 
661  for (int st = 0; st < stacks_ - 2; ++st) {
662 
663  // Move around one slice
664  for (int sl = 0; sl < slices_; ++sl) {
665 
666  // Offset 1 because of singular vertex
667  unsigned int startTop = 1 + slices_ * st;
668  unsigned int startBottom = 1 + slices_ * (st + 1);
669 
670  vhandles.clear();
671 
672  vhandles.push_back(triMesh_->vertex_handle(startTop + sl));
673  vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_)));
674  vhandles.push_back(triMesh_->vertex_handle(startBottom + sl));
675 
676  triMesh_->add_face(vhandles);
677 
678  vhandles.clear();
679 
680  vhandles.push_back(triMesh_->vertex_handle(startBottom + sl));
681  vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_)));
682  vhandles.push_back(triMesh_->vertex_handle(startBottom + ((sl + 1) % slices_)));
683 
684  triMesh_->add_face(vhandles);
685  }
686 
687  }
688 
689  const int startTop = 1 + (stacks_ - 2) * slices_;
690  const int bottomVertex = 1 + (stacks_ - 1) * slices_;
691 
692  // Add bottom triangle fan
693  for (int sl = 0; sl < slices_; ++sl) {
694 
695  vhandles.clear();
696 
697  vhandles.push_back(triMesh_->vertex_handle(bottomVertex));
698  vhandles.push_back(triMesh_->vertex_handle(startTop + sl));
699  vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_)));
700 
701  triMesh_->add_face(vhandles);
702  }
703 
704  triMesh_->update_normals();
705 
706  emit updatedObject(newObject,UPDATE_ALL);
707  emit createBackup(newObject, "Original Object");
708 
710 
711  return object->id();
712  }
713 
714 
715 }
716 
717 //------------------------------------------------------------------------
718 
719 int PrimitivesGeneratorPlugin::addSubdivisionSphere(const Vector& _position, const double _radius)
720 {
721 
722  // Create the underlying octahedron
723  int newObject = addTriMesh();
724 
725  TriMeshObject* object;
726  if (!PluginFunctions::getObject(newObject, object)) {
727  emit log(LOGERR, "Unable to create new Object");
728  return -1;
729  } else {
730  object->setName( "Sphere " + QString::number(newObject) );
731 
732  triMesh_ = object->mesh();
733  constructOctahedron(_position, _radius);
734 
735  // Number of subdivision iterations for the sphere
736  const size_t subdivisionSteps = 4;
737 
738  for (size_t i = 0 ; i < subdivisionSteps; ++i) {
739 
740  // Call the subdivision algorithm
741  RPC::callFunction("subdivider", "subdivide", newObject, QString("loop"), 1, false);
742 
743  // Reposition vertices onto sphere
744  for (TriMesh::VertexIter v_it = triMesh_->vertices_begin(); v_it != triMesh_->vertices_end(); ++v_it) {
745  TriMesh::Point p = triMesh_->point(*v_it);
746  p -= _position;
747  p = _radius * p.normalize() + _position;
748  triMesh_->set_point(*v_it, p);
749  }
750  }
751 
752  // Make sure that the normals are fine
753  triMesh_->update_normals();
754 
755  emit updatedObject(newObject, UPDATE_ALL);
756  emit createBackup(newObject, "Original Object");
757 
759 
760  return newObject;
761 
762  }
763 
764 
765 }
766 
767 
768 //========================================================================
769 // Pyramid
770 //========================================================================
771 
772 int PrimitivesGeneratorPlugin::addPyramid(const Vector& _position,const double _length) {
773  int newObject = addTriMesh();
774 
775  TriMeshObject* object;
776  if ( !PluginFunctions::getObject(newObject,object) ) {
777  emit log(LOGERR,"Unable to create new Object");
778  return -1;
779  } else {
780 
781  object->setName( "Pyramid " + QString::number(newObject) );
782 
783  triMesh_ = object->mesh();
784 
785  triMesh_->clear();
786 
787  // Add 5 vertices
788  vhandles_.resize(5);
789 
790  const double halfLength = 0.5*_length;
791 
792  vhandles_[0] = triMesh_->add_vertex(TriMesh::Point( halfLength, -halfLength, 0.0)+_position);
793  vhandles_[1] = triMesh_->add_vertex(TriMesh::Point( halfLength, halfLength, 0.0)+_position);
794  vhandles_[2] = triMesh_->add_vertex(TriMesh::Point(-halfLength, halfLength, 0.0)+_position);
795  vhandles_[3] = triMesh_->add_vertex(TriMesh::Point(-halfLength, -halfLength, 0.0)+_position);
796 
797  vhandles_[4] = triMesh_->add_vertex(TriMesh::Point(0.0, 0.0, sqrt(2.0)*halfLength));
798 
799  // Add 6 faces
800  add_face(2,1,0);
801  add_face(3,2,0);
802  add_face(4,0,1);
803 
804  add_face(3,0,4);
805  add_face(4,2,3);
806  add_face(1,2,4);
807 
808  triMesh_->update_normals();
809 
810  emit updatedObject(newObject,UPDATE_ALL);
811  emit createBackup(newObject, "Original Object");
812 
814 
815  return newObject;
816  }
817 
818  return -1;
819 }
820 
821 void PrimitivesGeneratorPlugin::add_face( int _vh1 , int _vh2, int _vh3 ) {
822  std::vector<TriMesh::VertexHandle> vhandles;
823 
824  vhandles.push_back(vhandles_[_vh1]);
825  vhandles.push_back(vhandles_[_vh2]);
826  vhandles.push_back(vhandles_[_vh3]);
827 
828  triMesh_->add_face(vhandles);
829 
830 }
831 
832 void PrimitivesGeneratorPlugin::add_face( int _vh1 , int _vh2, int _vh3, int _vh4 , int _vh5 ) {
833  std::vector<PolyMesh::VertexHandle> vhandles;
834 
835  vhandles.push_back(vphandles_[_vh1]);
836  vhandles.push_back(vphandles_[_vh2]);
837  vhandles.push_back(vphandles_[_vh3]);
838  vhandles.push_back(vphandles_[_vh4]);
839  vhandles.push_back(vphandles_[_vh5]);
840 
841  polyMesh_->add_face(vhandles);
842 }
843 
844 int PrimitivesGeneratorPlugin::addIcosahedron(const Vector& _position,const double _length) {
845  int newObject = addTriMesh();
846 
847  TriMeshObject* object;
848  if ( !PluginFunctions::getObject(newObject,object) ) {
849  emit log(LOGERR,"Unable to create new Object");
850  return -1;
851  } else {
852 
853  object->setName( "Icosahedron " + QString::number(newObject) );
854 
855  triMesh_ = object->mesh();
856 
857  triMesh_->clear();
858 
859  // Add 12 vertices
860  vhandles_.resize(12);
861 
862  const double phi = 0.5 * (1.0 + sqrt(5.0));
863  //double norm = 1.0 / sqrt(1.0 + phi*phi);
864  const double norm = 1.0;
865  const double halfLength = 0.5*_length;
866 
867  vhandles_[0 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , -halfLength , -phi )+_position);
868  vhandles_[1 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , halfLength , -phi )+_position);
869  vhandles_[2 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , halfLength , phi )+_position);
870  vhandles_[3 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , -halfLength , phi )+_position);
871 
872  vhandles_[4 ] = triMesh_->add_vertex(norm * TriMesh::Point( -halfLength , -phi , 0.0 )+_position);
873  vhandles_[5 ] = triMesh_->add_vertex(norm * TriMesh::Point( halfLength , -phi , 0.0 )+_position);
874  vhandles_[6 ] = triMesh_->add_vertex(norm * TriMesh::Point( halfLength , phi , 0.0 )+_position);
875  vhandles_[7 ] = triMesh_->add_vertex(norm * TriMesh::Point( -halfLength , phi , 0.0 )+_position);
876 
877  vhandles_[8 ] = triMesh_->add_vertex(norm * TriMesh::Point( -phi , 0.0 , -halfLength )+_position);
878  vhandles_[9 ] = triMesh_->add_vertex(norm * TriMesh::Point( -phi , 0.0 , halfLength )+_position);
879  vhandles_[10] = triMesh_->add_vertex(norm * TriMesh::Point( phi , 0.0 , halfLength )+_position);
880  vhandles_[11] = triMesh_->add_vertex(norm * TriMesh::Point( phi , 0.0 , -halfLength )+_position);
881 
882 
883  // Add 20 faces
884  add_face(2,6,7);
885  add_face(7,6,1);
886 
887  add_face(11,0,1);
888  add_face(0, 8,1);
889 
890  add_face(4,9,8);
891  add_face(8,9,7);
892 
893  add_face(9,3,2);
894  add_face(10,2,3);
895 
896  add_face(5,11,10);
897  add_face(11,6,10);
898 
899  add_face(0,5,4);
900  add_face(5,3,4);
901 
902  // Upper block
903  add_face(6,2,10);
904  add_face(6,11,1);
905  add_face(1,8,7);
906  add_face(9,2,7);
907 
908  // Lower block
909  add_face(3,5,10);
910  add_face(0,11,5);
911  add_face(3,9,4);
912  add_face(0,4,8);
913 
914  triMesh_->update_normals();
915 
916  emit updatedObject(newObject,UPDATE_ALL);
917  emit createBackup(newObject, "Original Object");
918 
920 
921  return newObject;
922  }
923 
924  return -1;
925 }
926 
927 void PrimitivesGeneratorPlugin::constructOctahedron(const Vector& _position, const double _length)
928 {
929  triMesh_->clear();
930 
931  // Add 6 vertices
932  vhandles_.resize(6);
933 
934  const double sqrtLength = sqrt(_length);
935 
936  vhandles_[0 ] = triMesh_->add_vertex(TriMesh::Point(-sqrtLength, 0.0, 0.0)+_position);
937  vhandles_[1 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, -sqrtLength, 0.0)+_position);
938  vhandles_[2 ] = triMesh_->add_vertex(TriMesh::Point( sqrtLength, 0.0, 0.0)+_position);
939  vhandles_[3 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, sqrtLength, 0.0)+_position);
940 
941  vhandles_[4 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, 0.0, sqrtLength)+_position);
942  vhandles_[5 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, 0.0, -sqrtLength)+_position);
943 
944 
945  // Add 8 faces
946  add_face(0,1,4);
947  add_face(1,2,4);
948 
949  add_face(2,3,4);
950  add_face(0,4,3);
951 
952  add_face(5,1,0);
953  add_face(5,2,1);
954 
955  add_face(5,3,2);
956  add_face(5,0,3);
957 
958  triMesh_->update_normals();
959 }
960 
961 int PrimitivesGeneratorPlugin::addOctahedron(const Vector& _position,const double _length) {
962  int newObject = addTriMesh();
963 
964  TriMeshObject* object;
965  if ( !PluginFunctions::getObject(newObject,object) ) {
966  emit log(LOGERR,"Unable to create new Object");
967  return -1;
968  } else {
969 
970  object->setName( "Octahedron " + QString::number(newObject) );
971 
972  triMesh_ = object->mesh();
973 
974  constructOctahedron(_position, _length);
975 
976  emit updatedObject(newObject,UPDATE_ALL);
977  emit createBackup(newObject, "Original Object");
978 
980 
981  return newObject;
982  }
983 
984  return -1;
985 }
986 
987 int PrimitivesGeneratorPlugin::addDodecahedron(const Vector& _position,const double _length) {
988  int newObject = addPolyMesh();
989 
990  PolyMeshObject* object;
991  if ( !PluginFunctions::getObject(newObject,object) ) {
992  emit log(LOGERR,"Unable to create new Object");
993  return -1;
994  } else {
995 
996  object->setName( "Dodecahedron " + QString::number(newObject) );
997 
998  polyMesh_ = object->mesh();
999 
1000  polyMesh_->clear();
1001 
1002  // Add 20 vertices
1003  vphandles_.resize(20);
1004 
1005  const double phi = (1.0 + sqrt(5.0)) / 2.0;
1006  const double halfLength = 0.5*_length;
1007 
1008 
1009  vphandles_[0 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , halfLength , halfLength )+_position);
1010  vphandles_[1 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , halfLength ,-halfLength )+_position);
1011  vphandles_[2 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , -halfLength , halfLength )+_position);
1012  vphandles_[3 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , -halfLength ,-halfLength )+_position);
1013  vphandles_[4 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , halfLength , halfLength )+_position);
1014  vphandles_[5 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , halfLength ,-halfLength )+_position);
1015  vphandles_[6 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , -halfLength , halfLength )+_position);
1016  vphandles_[7 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , -halfLength ,-halfLength )+_position);
1017 
1018  vphandles_[8 ] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , halfLength / phi , phi )+_position);
1019  vphandles_[9 ] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , halfLength / phi , -phi )+_position);
1020  vphandles_[10] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , -halfLength / phi , phi )+_position);
1021  vphandles_[11] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , -halfLength / phi , -phi )+_position);
1022 
1023  vphandles_[12] = polyMesh_->add_vertex(TriMesh::Point( halfLength / phi , phi, 0.0)+_position);
1024  vphandles_[13] = polyMesh_->add_vertex(TriMesh::Point( halfLength / phi , -phi, 0.0)+_position);
1025  vphandles_[14] = polyMesh_->add_vertex(TriMesh::Point( -halfLength / phi , phi, 0.0)+_position);
1026  vphandles_[15] = polyMesh_->add_vertex(TriMesh::Point( -halfLength / phi , -phi, 0.0)+_position);
1027 
1028  vphandles_[16] = polyMesh_->add_vertex(TriMesh::Point( phi , 0.0 , halfLength / phi)+_position);
1029  vphandles_[17] = polyMesh_->add_vertex(TriMesh::Point( phi , 0.0 ,-halfLength / phi)+_position);
1030  vphandles_[18] = polyMesh_->add_vertex(TriMesh::Point( -phi , 0.0 , halfLength / phi)+_position);
1031  vphandles_[19] = polyMesh_->add_vertex(TriMesh::Point( -phi , 0.0 ,-halfLength / phi)+_position);
1032 
1033  // Add 12 faces
1034  add_face(14, 5,19,18, 4);
1035  add_face( 5, 9,11, 7,19);
1036  add_face( 6,15,13, 2,10);
1037  add_face(12, 0,16,17, 1);
1038 
1039  add_face( 0, 8,10, 2,16);
1040  add_face(16, 2,13, 3,17);
1041  add_face( 3,13,15, 7,11);
1042  add_face( 7,15, 6,18,19);
1043 
1044  add_face( 4,18, 6,10, 8);
1045  add_face( 4, 8, 0,12,14);
1046  add_face(14,12, 1, 9, 5);
1047  add_face( 9, 1,17, 3,11);
1048 
1049  polyMesh_->update_normals();
1050 
1051  emit updatedObject(newObject,UPDATE_ALL);
1052  emit createBackup(newObject, "Original Object");
1053 
1055 
1056  return newObject;
1057  }
1058 
1059  return -1;
1060 }
1061 
1062 #ifdef ENABLE_BSPLINECURVE_SUPPORT
1063 int PrimitivesGeneratorPlugin::addRandomBSplineCurve(const Vector& _position, int nDiv)
1064 {
1065  int id = -1;
1066  emit addEmptyObject(DATA_BSPLINE_CURVE, id);
1067  if (id == -1) {
1068  return -1;
1069  }
1070 
1071  BSplineCurveObject *object = NULL;
1072  if (!PluginFunctions::getObject(id, object)) {
1073  return -1;
1074  }
1075 
1076  BSplineCurve *curve = object->splineCurve();
1077 
1078  curve->autocompute_knotvector(true);
1079  for (int i = 0; i < nDiv; ++i) {
1080  double x = _position[0] + i - nDiv / 2.0;
1081 
1082  double r = (2.0 * std::rand()) / RAND_MAX - 1.0;
1083  BSplineCurve::Point cp(x, _position[1] + r, _position[2]);
1084  curve->add_control_point(cp);
1085  }
1086 
1087  emit updatedObject(id, UPDATE_ALL);
1088  emit createBackup(id, "Original Object");
1089 
1091 
1092  return id;
1093 }
1094 #endif
1095 
1096 #ifdef ENABLE_BSPLINESURFACE_SUPPORT
1097 int PrimitivesGeneratorPlugin::addRandomBSplineSurface(const Vector& _position, int nDiv)
1098 {
1099  int id = -1;
1100  emit addEmptyObject(DATA_BSPLINE_SURFACE, id);
1101  if (id == -1) {
1102  return -1;
1103  }
1104 
1105  BSplineSurfaceObject *object = NULL;
1106  if (!PluginFunctions::getObject(id, object)) {
1107  return -1;
1108  }
1109 
1110  BSplineSurface *surf = object->splineSurface();
1111  typedef BSplineSurface::Point Point;
1112  std::vector<Point> cp(nDiv);
1113 
1114  for (int i = 0; i < nDiv; ++i) {
1115  double x = _position[0] + i - nDiv / 2.0;
1116  for (int j = 0; j < nDiv; ++j) {
1117  double y = _position[1] + j - nDiv / 2.0;
1118  cp[j] = Point(x, y, _position[2] + (2.0 * std::rand()) / RAND_MAX - 1);
1119  }
1120  surf->add_vector_m(cp);
1121  }
1122  surf->createKnots();
1123 
1124  emit updatedObject(id, UPDATE_ALL);
1125  emit createBackup(id, "Original Object");
1126 
1128 
1129  return id;
1130 }
1131 #endif
1132 
1133 #if QT_VERSION < 0x050000
1134  Q_EXPORT_PLUGIN2( primitivesgeneratorplugin , PrimitivesGeneratorPlugin );
1135 #endif
void createKnots()
Creates interpolating knotvectors 0...0, 1, 2, ..., n...n.
const DrawMode & getDrawMode(const std::string &_name)
Get a custom DrawMode.
Definition: DrawModes.cc:813
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:73
bool getObject(int _identifier, BSplineCurveObject *&_object)
#define DATA_POLYHEDRAL_MESH
MeshT * mesh()
return a pointer to the mesh
void add_vector_m(const std::vector< Point > &_control_polygon)
Adds a control point n-vector.
void viewAll(int _viewer)
View the whole scene.
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
void add_control_point(const Point &_cp)
add a control point
ACG::Vec3d Vector
Standard Type for 3d Vector used for scripting.
Definition: DataTypes.hh:187
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:428
#define DATA_BSPLINE_CURVE
Definition: BSplineCurve.hh:73
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:70
void setWhatsThis(QAction *_action, const QString &_msg, const QString &_ref="", const QString &_site="index.html") const
sets a whatsThis Message plus link to the doc for the given QAction
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:115
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
#define DATA_POLY_MESH
Definition: PolyMesh.hh:65
#define DATA_BSPLINE_SURFACE
QScriptValue callFunction(QString _plugin, QString _functionName, std::vector< QScriptValue > _parameters)
Call a function provided by a plugin getting multiple parameters.
Definition: RPCWrappers.cc:63
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:66
VectorT< Scalar, 3 > perpendicular(const VectorT< Scalar, 3 > &v)
find a vector that&#39;s perpendicular to _v
Definition: Algorithms.cc:1162
void initializePlugin()
BaseInterface.
void setName(QString _name)
Set the name of the Object.