/*===========================================================================*\ * * * OpenFlipper * * Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen * * www.openflipper.org * * * *--------------------------------------------------------------------------- * * This file is part of OpenFlipper. * * * * OpenFlipper is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenFlipper is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU LesserGeneral Public * * License along with OpenFlipper. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $LastChangedBy$ * * $Date$ * * * \*===========================================================================*/ #include #include "PrimitivesGenerator.hh" #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT #include "TetrahedralCuboidGenerator.hh" #endif #include #include #ifdef ENABLE_BSPLINECURVE_SUPPORT #include #endif #ifdef ENABLE_BSPLINESURFACE_SUPPORT #include #endif PrimitivesGeneratorPlugin::PrimitivesGeneratorPlugin() : triMesh_(0), polyMesh_(0), slices_(50), stacks_(50), primitivesMenu_(0) { } PrimitivesGeneratorPlugin::~PrimitivesGeneratorPlugin() { if ( OpenFlipper::Options::gui()) { delete primitivesMenu_; } } void PrimitivesGeneratorPlugin::initializePlugin() { emit setSlotDescription("addTetrahedron(Vector,double)", tr("Generates a tetrahedron (ObjectId is returned)"), QString("Position,Length").split(","), QString("Center position,Length of each edge").split(",")); emit setSlotDescription("addIcosahedron(Vector,double)", tr("Generates an icosahedron (ObjectId is returned)"), QString("Position,Length").split(","), QString("Center position,Length of each edge").split(",")); emit setSlotDescription("addPyramid(Vector,double)", tr("Generates a pyramid (ObjectId is returned)"), QString("Position,Length").split(","), QString("Center position,Length of each edge").split(",")); emit setSlotDescription("addOctahedron(Vector,double)", tr("Generates an octahedron (ObjectId is returned)"), QString("Position,Length").split(","), QString("Center position,Length of each edge").split(",")); emit setSlotDescription("addDodecahedron(Vector,double)", tr("Generates a dodecahedron (ObjectId is returned)"), QString("Position,Length").split(","), QString("Center position,Length of each edge").split(",")); emit setSlotDescription("addSphere(Vector,double)", tr("Generates a triangulated sphere with all vertical lines connected to the poles (ObjectId is returned)"), QString("Position, Radius").split(","), QString("Center position,Radius").split(",")); emit setSlotDescription("addSubdivisionSphere(Vector,double)", tr("Generates a triangulated sphere by subdivision without poles. (ObjectId is returned)"), QString("Position, Radius").split(","), QString("Center position,Radius").split(",")); emit setSlotDescription("addTriangulatedCube(Vector,double)", tr("Generates a triangular mesh of cube (ObjectId is returned)"), QString("Position,Length").split(","), QString("Center position,Length of each edge").split(",")); emit setSlotDescription("addTriangulatedCylinder(Vector,Vector,double,double)", tr("Generates a triangulated cylinder (ObjectId is returned)") , QString("Position,Axis,Radius,Height,Top,Bottom").split(","), QString("Bottom center vertex position,Center axis,radius,height,add top vertex,add bottom vertex").split(",")); #ifdef ENABLE_BSPLINECURVE_SUPPORT emit setSlotDescription("addRandomBSplineCurve(Vector,int)", tr("Generates a random B-spline curve (ObjectId is returned)"), QString("Position,Count").split(","), QString("Center position,Number of control points").split(",")); #endif #ifdef ENABLE_BSPLINESURFACE_SUPPORT emit setSlotDescription("addRandomBSplineSurface(Vector,int)", tr("Generates a random B-spline surface (ObjectId is returned)"), QString("Position,Count").split(","), QString("Center position,Number of control points").split(",")); #endif #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT emit setSlotDescription("addTetrahedralCube(Vector,double)", tr("Generates a tetrahedral mesh of a cube (ObjectId is returned)"), QString("Position,Length").split(","), QString("Center position,Length of each edge").split(",")); emit setSlotDescription("addTetrahedralCuboid(Vector,Vector,uint,uint,uint)", tr("Generates a tetrahedral mesh of a cuboid (ObjectId is returned)"), QString("Position,Lengths,Count,Count,Count").split(","), 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(",")); #endif } void PrimitivesGeneratorPlugin::pluginsInitialized() { if ( OpenFlipper::Options::gui()) { emit getMenubarMenu(tr("&Primitives"), primitivesMenu_, true ); QAction* action; action = primitivesMenu_->addAction("Cube (Triangle Mesh)" ,this,SLOT(addTriangulatedCube())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cube.png")); WhatsThisGenerator whatsThisGen("PrimitivesGenerator"); whatsThisGen.setWhatsThis(action,tr("Create a Cube."),"Cube"); action = primitivesMenu_->addAction("Dodecahedron" ,this,SLOT(addDodecahedron())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_dodecahedron.png")); whatsThisGen.setWhatsThis(action,tr("Create a Dodecahedron."), "Dodecahedron"); action = primitivesMenu_->addAction("Icosahedron" ,this,SLOT(addIcosahedron())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_icosahedron.png")); whatsThisGen.setWhatsThis(action,tr("Create a Icosahedron.","Icosahedron")); action = primitivesMenu_->addAction("Octahedron" ,this,SLOT(addOctahedron())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_octahedron.png")); whatsThisGen.setWhatsThis(action,tr("Create an Octahedron."),"Octahedron"); action = primitivesMenu_->addAction("Pyramid" ,this,SLOT(addPyramid())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_pyramid.png")); whatsThisGen.setWhatsThis(action,tr("Create a Pyramid."),"Pyramid"); action = primitivesMenu_->addAction("Cylinder (Triangle Mesh)" ,this,SLOT(addTriangulatedCylinder())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cylinder.png")); action = primitivesMenu_->addAction("Sphere (Poles,Triangle Mesh)",this,SLOT(addSphere())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_sphere.png")); whatsThisGen.setWhatsThis(action,tr("Create a Sphere. All vertical lines connect to poles) "),"Sphere"); action = primitivesMenu_->addAction("Sphere (Subdivision,Triangle Mesh)",this,SLOT(addSubdivisionSphere())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_sphere.png")); whatsThisGen.setWhatsThis(action,tr("Create a Sphere. No poles due to Subdivision) "),"Sphere"); action = primitivesMenu_->addAction("Tetrahedron",this,SLOT(addTetrahedron())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_tetrahedron.png")); whatsThisGen.setWhatsThis(action,tr("Create a Tetrahedron."),"Tetrahedron"); #ifdef ENABLE_BSPLINECURVE_SUPPORT action = primitivesMenu_->addAction("Random B-spline curve",this,SLOT(addRandomBSplineCurve())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator() + "bspline_curve.png")); whatsThisGen.setWhatsThis(action, tr("Create a random B-spline curve."), "B-spline curve"); #endif #ifdef ENABLE_BSPLINESURFACE_SUPPORT action = primitivesMenu_->addAction("Random B-spline surface",this,SLOT(addRandomBSplineSurface())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"bspline_surface.png")); whatsThisGen.setWhatsThis(action,tr("Create a random B-spline surface."),"B-spline surface"); #endif #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT action = primitivesMenu_->addAction("Cube (Tetrahedral Mesh)" ,this,SLOT(addTetrahedralCube())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cube.png")); whatsThisGen.setWhatsThis(action,tr("Create a Tetrahedral Cube."), "Cube"); action = primitivesMenu_->addAction("Cuboid (Tetrahedral Mesh)" ,this,SLOT(addTetrahedralCuboid())); action->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"primitive_cube.png")); whatsThisGen.setWhatsThis(action,tr("Create a Tetrahedral Cuboid."), "Cuboid"); #endif } } int PrimitivesGeneratorPlugin::addTriMesh() { int objectId = -1; emit addEmptyObject( DATA_TRIANGLE_MESH, objectId ); TriMeshObject* object; if ( !PluginFunctions::getObject(objectId,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } return objectId; } int PrimitivesGeneratorPlugin::addPolyMesh() { int objectId = -1; emit addEmptyObject( DATA_POLY_MESH, objectId ); PolyMeshObject* object; if ( !PluginFunctions::getObject(objectId,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } return objectId; } #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT int PrimitivesGeneratorPlugin::addPolyhedralMesh() { int objectId = -1; emit addEmptyObject( DATA_POLYHEDRAL_MESH, objectId ); PolyhedralMeshObject* object; if (!PluginFunctions::getObject(objectId, object) ) { emit log(LOGERR, "Unable to create new PolyhedralMesh object"); return -1; } return objectId; } #endif int PrimitivesGeneratorPlugin::addTetrahedron(const Vector& _position, const double _length) { int newObject = addTriMesh(); TriMeshObject* object; if ( !PluginFunctions::getObject(newObject,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } else { object->setName( "Tetrahedron " + QString::number(newObject) ); triMesh_ = object->mesh(); triMesh_->clear(); // Add 4 vertices vhandles_.resize(4); const double halfSize = 0.5*_length; vhandles_[0] = triMesh_->add_vertex(TriMesh::Point(-halfSize, -halfSize, halfSize)+_position); vhandles_[1] = triMesh_->add_vertex(TriMesh::Point( halfSize, halfSize, halfSize)+_position); vhandles_[2] = triMesh_->add_vertex(TriMesh::Point(-halfSize, halfSize, -halfSize)+_position); vhandles_[3] = triMesh_->add_vertex(TriMesh::Point( halfSize, -halfSize, -halfSize)+_position); // Add 4 faces add_face(0,1,2); add_face(0,2,3); add_face(2,1,3); add_face(3,1,0); triMesh_->update_normals(); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return newObject; } return -1; } int PrimitivesGeneratorPlugin::addTriangulatedCube(const Vector& _position,const double _length) { int newObject = addTriMesh(); TriMeshObject* object; if ( !PluginFunctions::getObject(newObject,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } else { object->setName( "Cube " + QString::number(newObject) ); triMesh_ = object->mesh(); triMesh_->clear(); // Add 8 vertices vhandles_.resize(8); const double halfSize = 0.5*_length; vhandles_[0] = triMesh_->add_vertex(TriMesh::Point( halfSize, -halfSize, halfSize)+_position); vhandles_[1] = triMesh_->add_vertex(TriMesh::Point( halfSize, halfSize, halfSize)+_position); vhandles_[2] = triMesh_->add_vertex(TriMesh::Point(-halfSize, halfSize, halfSize)+_position); vhandles_[3] = triMesh_->add_vertex(TriMesh::Point(-halfSize, -halfSize, halfSize)+_position); vhandles_[4] = triMesh_->add_vertex(TriMesh::Point( halfSize, -halfSize,-halfSize)+_position); vhandles_[5] = triMesh_->add_vertex(TriMesh::Point( halfSize, halfSize,-halfSize)+_position); vhandles_[6] = triMesh_->add_vertex(TriMesh::Point(-halfSize, halfSize,-halfSize)+_position); vhandles_[7] = triMesh_->add_vertex(TriMesh::Point(-halfSize, -halfSize,-halfSize)+_position); // Add 12 faces add_face(0,1,2); add_face(0,2,3); add_face(0,5,1); add_face(5,0,4); add_face(4,0,7); add_face(7,0,3); add_face(7,3,6); add_face(6,3,2); add_face(6,2,5); add_face(5,2,1); add_face(6,5,4); add_face(6,4,7); triMesh_->update_normals(); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return newObject; } return -1; } //======================================================================== // Tetrahedral cube //======================================================================== #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT int PrimitivesGeneratorPlugin::addTetrahedralCube(const Vector& _position, const double _length) { return addTetrahedralCuboid(_position, Vector(_length, _length, _length), 1, 1, 1); } #endif //======================================================================== // Tetrahedral Cuboid //======================================================================== #ifdef ENABLE_OPENVOLUMEMESH_POLYHEDRAL_SUPPORT int PrimitivesGeneratorPlugin::addTetrahedralCuboid(const Vector& _position, const Vector& _length, const unsigned int n_x, const unsigned int n_y, const unsigned int n_z) { int object_id = addPolyhedralMesh(); PolyhedralMeshObject* object; if (!PluginFunctions::getObject(object_id, object)) { return -1; } object->setName("Cuboid " + QString::number(object_id)); TetrahedralCuboidGenerator gen(*(object->mesh()), _position, _length, n_x, n_y, n_z); emit updatedObject(object_id, UPDATE_ALL); emit createBackup(object_id, "Original Object"); object->setObjectDrawMode(ACG::SceneGraph::DrawModes::getDrawMode("Cells (flat shaded)")); PluginFunctions::viewAll(); return object_id; } #endif //======================================================================== // Cylinder //======================================================================== ACG::Vec3d PrimitivesGeneratorPlugin::positionOnCylinder(const int _sliceNumber, const int _stackNumber, const Vector _position, const Vector _axis, const double _radius, const double _height) { ACG::Vec3d position; const ACG::Vec3d right = (ACG::Geometry::perpendicular(_axis)).normalized(); const ACG::Vec3d left = (cross( _axis, right)).normalized(); double beta = ((2.0 * M_PI) / double(slices_)) * double(_sliceNumber); if ( _sliceNumber == 0 && _stackNumber == 0) { position[0] = 0.0; position[1] = 0.0; position[2] = _height; } else if ( _sliceNumber == slices_ && _stackNumber == stacks_ ) { position[0] = 0.0; position[1] = 0.0; position[2] = 0.0; } else { position[0] = sin(beta) * _radius; position[1] = cos(beta) * _radius; position[2] = _height * double(stacks_ - _stackNumber -1 ) / double(stacks_-2); } position = _position + position[0] * right + position[1] * left + position[2] * _axis ; return position; } int PrimitivesGeneratorPlugin::addTriangulatedCylinder(const Vector& _position,const Vector& _axis,const double _radius,const double _height,const bool _top,const bool _bottom ) { // TODO: Generate texture coordinates for cylinder (Glu compatible) int newObject = addTriMesh(); TriMeshObject* object; if (!PluginFunctions::getObject(newObject, object)) { emit log(LOGERR, "Unable to create new Object"); return -1; } else { object->setName( "Cylinder " + QString::number(newObject) ); triMesh_ = object->mesh(); triMesh_->clear(); //triMesh_->request_vertex_texcoords2D(); TriMesh::VertexHandle vh; TriMesh::VertexHandle top = triMesh_->add_vertex(positionOnCylinder(0, 0,_position,_axis,_radius,_height)); //triMesh_->set_texcoord2D(vh, texCoordOnSphere(0, 0)); for (int st = 1; st < stacks_; ++st) { for (int sl = 0; sl < slices_; ++sl) { vh = triMesh_->add_vertex(positionOnCylinder(sl, st,_position,_axis,_radius,_height)); //triMesh_->set_texcoord2D(vh, texCoordOnSphere(sl, st)); } } TriMesh::VertexHandle bottom = triMesh_->add_vertex(positionOnCylinder(slices_, stacks_,_position,_axis,_radius,_height)); //triMesh_->set_texcoord2D(vh, texCoordOnSphere(slices_, stacks_)); std::vector vhandles; // Add top triangle fan ( Vertex index is shifted by one for the first slice ) if ( _top ) { for (int sl = 1; sl < slices_ + 1; ++sl) { vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(sl)); vhandles.push_back(triMesh_->vertex_handle(0)); vhandles.push_back(triMesh_->vertex_handle(1 * 1 + (sl % slices_))); triMesh_->add_face(vhandles); } } else { triMesh_->delete_vertex(top); } for (int st = 0; st < stacks_ - 2; ++st) { // Move around one slice for (int sl = 0; sl < slices_; ++sl) { // Offset 1 because of singular vertex unsigned int startTop = 1 + slices_ * st; unsigned int startBottom = 1 + slices_ * (st + 1); vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(startTop + sl)); vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_))); vhandles.push_back(triMesh_->vertex_handle(startBottom + sl)); triMesh_->add_face(vhandles); vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(startBottom + sl)); vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_))); vhandles.push_back(triMesh_->vertex_handle(startBottom + ((sl + 1) % slices_))); triMesh_->add_face(vhandles); } } const int startTop = 1 + (stacks_ - 2) * slices_; const int bottomVertex = 1 + (stacks_ - 1) * slices_; // Add bottom triangle fan if ( _bottom) { for (int sl = 0; sl < slices_; ++sl) { vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(bottomVertex)); vhandles.push_back(triMesh_->vertex_handle(startTop + sl)); vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_))); triMesh_->add_face(vhandles); } } else { triMesh_->delete_vertex(bottom); } // Cleanup if bottom or top vertex is missing triMesh_->garbage_collection(); triMesh_->update_normals(); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return object->id(); } } //======================================================================== // Sphere //======================================================================== ACG::Vec3d PrimitivesGeneratorPlugin::positionOnSphere(int _sliceNumber, int _stackNumber, double _radius, const Vector& _position) { ACG::Vec3d position; double alpha = (M_PI / double(stacks_)) * double(_stackNumber); double beta = ((2.0 * M_PI) / double(slices_)) * double(_sliceNumber); double ringRadius = sin(alpha); position[0] = sin(beta) * ringRadius * _radius; position[1] = cos(beta) * ringRadius * _radius; position[2] = cos(alpha)* _radius; return _position+position; } //------------------------------------------------------------------------ ACG::Vec2f PrimitivesGeneratorPlugin::texCoordOnSphere(int _sliceNumber, int _stackNumber) { ACG::Vec2f texCoord; double alpha = (M_PI / double(stacks_)) * double(_stackNumber); texCoord[0] = double(_sliceNumber) / double(slices_); texCoord[1] = 0.5 * (cos(alpha) + 1.0); return texCoord; } //------------------------------------------------------------------------ int PrimitivesGeneratorPlugin::addSphere(const Vector& _position, const double _radius) { int newObject = addTriMesh(); TriMeshObject* object; if (!PluginFunctions::getObject(newObject, object)) { emit log(LOGERR, "Unable to create new Object"); return -1; } else { object->setName( "Sphere " + QString::number(newObject) ); triMesh_ = object->mesh(); triMesh_->clear(); triMesh_->request_vertex_texcoords2D(); TriMesh::VertexHandle vh; vh = triMesh_->add_vertex(positionOnSphere(0, 0, _radius,_position)); triMesh_->set_texcoord2D(vh, texCoordOnSphere(0, 0)); for (int st = 1; st < stacks_; ++st) { for (int sl = 0; sl < slices_; ++sl) { vh = triMesh_->add_vertex(positionOnSphere(sl, st, _radius,_position)); triMesh_->set_texcoord2D(vh, texCoordOnSphere(sl, st)); } } vh = triMesh_->add_vertex(positionOnSphere(slices_, stacks_, _radius,_position)); triMesh_->set_texcoord2D(vh, texCoordOnSphere(slices_, stacks_)); std::vector vhandles; // Add top triangle fan ( Vertex index is shifted by one for the first slice ) for (int sl = 1; sl < slices_ + 1; ++sl) { vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(sl)); vhandles.push_back(triMesh_->vertex_handle(0)); vhandles.push_back(triMesh_->vertex_handle(1 * 1 + (sl % slices_))); triMesh_->add_face(vhandles); } for (int st = 0; st < stacks_ - 2; ++st) { // Move around one slice for (int sl = 0; sl < slices_; ++sl) { // Offset 1 because of singular vertex unsigned int startTop = 1 + slices_ * st; unsigned int startBottom = 1 + slices_ * (st + 1); vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(startTop + sl)); vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_))); vhandles.push_back(triMesh_->vertex_handle(startBottom + sl)); triMesh_->add_face(vhandles); vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(startBottom + sl)); vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_))); vhandles.push_back(triMesh_->vertex_handle(startBottom + ((sl + 1) % slices_))); triMesh_->add_face(vhandles); } } const int startTop = 1 + (stacks_ - 2) * slices_; const int bottomVertex = 1 + (stacks_ - 1) * slices_; // Add bottom triangle fan for (int sl = 0; sl < slices_; ++sl) { vhandles.clear(); vhandles.push_back(triMesh_->vertex_handle(bottomVertex)); vhandles.push_back(triMesh_->vertex_handle(startTop + sl)); vhandles.push_back(triMesh_->vertex_handle(startTop + ((sl + 1) % slices_))); triMesh_->add_face(vhandles); } triMesh_->update_normals(); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return object->id(); } } //------------------------------------------------------------------------ int PrimitivesGeneratorPlugin::addSubdivisionSphere(const Vector& _position, const double _radius) { // Create the underlying octahedron int newObject = addTriMesh(); TriMeshObject* object; if (!PluginFunctions::getObject(newObject, object)) { emit log(LOGERR, "Unable to create new Object"); return -1; } else { object->setName( "Sphere " + QString::number(newObject) ); triMesh_ = object->mesh(); constructOctahedron(_position, _radius); // Number of subdivision iterations for the sphere const size_t subdivisionSteps = 4; for (size_t i = 0 ; i < subdivisionSteps; ++i) { // Call the subdivision algorithm RPC::callFunction("subdivider", "subdivide", newObject, QString("loop"), 1, false); // Reposition vertices onto sphere for (TriMesh::VertexIter v_it = triMesh_->vertices_begin(); v_it != triMesh_->vertices_end(); ++v_it) { TriMesh::Point p = triMesh_->point(*v_it); p -= _position; p = _radius * p.normalize() + _position; triMesh_->set_point(*v_it, p); } } // Make sure that the normals are fine triMesh_->update_normals(); emit updatedObject(newObject, UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return newObject; } } //======================================================================== // Pyramid //======================================================================== int PrimitivesGeneratorPlugin::addPyramid(const Vector& _position,const double _length) { int newObject = addTriMesh(); TriMeshObject* object; if ( !PluginFunctions::getObject(newObject,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } else { object->setName( "Pyramid " + QString::number(newObject) ); triMesh_ = object->mesh(); triMesh_->clear(); // Add 5 vertices vhandles_.resize(5); const double halfLength = 0.5*_length; vhandles_[0] = triMesh_->add_vertex(TriMesh::Point( halfLength, -halfLength, 0.0)+_position); vhandles_[1] = triMesh_->add_vertex(TriMesh::Point( halfLength, halfLength, 0.0)+_position); vhandles_[2] = triMesh_->add_vertex(TriMesh::Point(-halfLength, halfLength, 0.0)+_position); vhandles_[3] = triMesh_->add_vertex(TriMesh::Point(-halfLength, -halfLength, 0.0)+_position); vhandles_[4] = triMesh_->add_vertex(TriMesh::Point(0.0, 0.0, sqrt(2.0)*halfLength)); // Add 6 faces add_face(2,1,0); add_face(3,2,0); add_face(4,0,1); add_face(3,0,4); add_face(4,2,3); add_face(1,2,4); triMesh_->update_normals(); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return newObject; } return -1; } void PrimitivesGeneratorPlugin::add_face( int _vh1 , int _vh2, int _vh3 ) { std::vector vhandles; vhandles.push_back(vhandles_[_vh1]); vhandles.push_back(vhandles_[_vh2]); vhandles.push_back(vhandles_[_vh3]); triMesh_->add_face(vhandles); } void PrimitivesGeneratorPlugin::add_face( int _vh1 , int _vh2, int _vh3, int _vh4 , int _vh5 ) { std::vector vhandles; vhandles.push_back(vphandles_[_vh1]); vhandles.push_back(vphandles_[_vh2]); vhandles.push_back(vphandles_[_vh3]); vhandles.push_back(vphandles_[_vh4]); vhandles.push_back(vphandles_[_vh5]); polyMesh_->add_face(vhandles); } int PrimitivesGeneratorPlugin::addIcosahedron(const Vector& _position,const double _length) { int newObject = addTriMesh(); TriMeshObject* object; if ( !PluginFunctions::getObject(newObject,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } else { object->setName( "Icosahedron " + QString::number(newObject) ); triMesh_ = object->mesh(); triMesh_->clear(); // Add 12 vertices vhandles_.resize(12); const double phi = 0.5 * (1.0 + sqrt(5.0)); //double norm = 1.0 / sqrt(1.0 + phi*phi); const double norm = 1.0; const double halfLength = 0.5*_length; vhandles_[0 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , -halfLength , -phi )+_position); vhandles_[1 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , halfLength , -phi )+_position); vhandles_[2 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , halfLength , phi )+_position); vhandles_[3 ] = triMesh_->add_vertex(norm * TriMesh::Point( 0.0 , -halfLength , phi )+_position); vhandles_[4 ] = triMesh_->add_vertex(norm * TriMesh::Point( -halfLength , -phi , 0.0 )+_position); vhandles_[5 ] = triMesh_->add_vertex(norm * TriMesh::Point( halfLength , -phi , 0.0 )+_position); vhandles_[6 ] = triMesh_->add_vertex(norm * TriMesh::Point( halfLength , phi , 0.0 )+_position); vhandles_[7 ] = triMesh_->add_vertex(norm * TriMesh::Point( -halfLength , phi , 0.0 )+_position); vhandles_[8 ] = triMesh_->add_vertex(norm * TriMesh::Point( -phi , 0.0 , -halfLength )+_position); vhandles_[9 ] = triMesh_->add_vertex(norm * TriMesh::Point( -phi , 0.0 , halfLength )+_position); vhandles_[10] = triMesh_->add_vertex(norm * TriMesh::Point( phi , 0.0 , halfLength )+_position); vhandles_[11] = triMesh_->add_vertex(norm * TriMesh::Point( phi , 0.0 , -halfLength )+_position); // Add 20 faces add_face(2,6,7); add_face(7,6,1); add_face(11,0,1); add_face(0, 8,1); add_face(4,9,8); add_face(8,9,7); add_face(9,3,2); add_face(10,2,3); add_face(5,11,10); add_face(11,6,10); add_face(0,5,4); add_face(5,3,4); // Upper block add_face(6,2,10); add_face(6,11,1); add_face(1,8,7); add_face(9,2,7); // Lower block add_face(3,5,10); add_face(0,11,5); add_face(3,9,4); add_face(0,4,8); triMesh_->update_normals(); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return newObject; } return -1; } void PrimitivesGeneratorPlugin::constructOctahedron(const Vector& _position, const double _length) { triMesh_->clear(); // Add 6 vertices vhandles_.resize(6); const double sqrtLength = sqrt(_length); vhandles_[0 ] = triMesh_->add_vertex(TriMesh::Point(-sqrtLength, 0.0, 0.0)+_position); vhandles_[1 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, -sqrtLength, 0.0)+_position); vhandles_[2 ] = triMesh_->add_vertex(TriMesh::Point( sqrtLength, 0.0, 0.0)+_position); vhandles_[3 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, sqrtLength, 0.0)+_position); vhandles_[4 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, 0.0, sqrtLength)+_position); vhandles_[5 ] = triMesh_->add_vertex(TriMesh::Point( 0.0, 0.0, -sqrtLength)+_position); // Add 8 faces add_face(0,1,4); add_face(1,2,4); add_face(2,3,4); add_face(0,4,3); add_face(5,1,0); add_face(5,2,1); add_face(5,3,2); add_face(5,0,3); triMesh_->update_normals(); } int PrimitivesGeneratorPlugin::addOctahedron(const Vector& _position,const double _length) { int newObject = addTriMesh(); TriMeshObject* object; if ( !PluginFunctions::getObject(newObject,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } else { object->setName( "Octahedron " + QString::number(newObject) ); triMesh_ = object->mesh(); constructOctahedron(_position, _length); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return newObject; } return -1; } int PrimitivesGeneratorPlugin::addDodecahedron(const Vector& _position,const double _length) { int newObject = addPolyMesh(); PolyMeshObject* object; if ( !PluginFunctions::getObject(newObject,object) ) { emit log(LOGERR,"Unable to create new Object"); return -1; } else { object->setName( "Dodecahedron " + QString::number(newObject) ); polyMesh_ = object->mesh(); polyMesh_->clear(); // Add 20 vertices vphandles_.resize(20); const double phi = (1.0 + sqrt(5.0)) / 2.0; const double halfLength = 0.5*_length; vphandles_[0 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , halfLength , halfLength )+_position); vphandles_[1 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , halfLength ,-halfLength )+_position); vphandles_[2 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , -halfLength , halfLength )+_position); vphandles_[3 ] = polyMesh_->add_vertex(TriMesh::Point( halfLength , -halfLength ,-halfLength )+_position); vphandles_[4 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , halfLength , halfLength )+_position); vphandles_[5 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , halfLength ,-halfLength )+_position); vphandles_[6 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , -halfLength , halfLength )+_position); vphandles_[7 ] = polyMesh_->add_vertex(TriMesh::Point( -halfLength , -halfLength ,-halfLength )+_position); vphandles_[8 ] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , halfLength / phi , phi )+_position); vphandles_[9 ] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , halfLength / phi , -phi )+_position); vphandles_[10] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , -halfLength / phi , phi )+_position); vphandles_[11] = polyMesh_->add_vertex(TriMesh::Point( 0.0 , -halfLength / phi , -phi )+_position); vphandles_[12] = polyMesh_->add_vertex(TriMesh::Point( halfLength / phi , phi, 0.0)+_position); vphandles_[13] = polyMesh_->add_vertex(TriMesh::Point( halfLength / phi , -phi, 0.0)+_position); vphandles_[14] = polyMesh_->add_vertex(TriMesh::Point( -halfLength / phi , phi, 0.0)+_position); vphandles_[15] = polyMesh_->add_vertex(TriMesh::Point( -halfLength / phi , -phi, 0.0)+_position); vphandles_[16] = polyMesh_->add_vertex(TriMesh::Point( phi , 0.0 , halfLength / phi)+_position); vphandles_[17] = polyMesh_->add_vertex(TriMesh::Point( phi , 0.0 ,-halfLength / phi)+_position); vphandles_[18] = polyMesh_->add_vertex(TriMesh::Point( -phi , 0.0 , halfLength / phi)+_position); vphandles_[19] = polyMesh_->add_vertex(TriMesh::Point( -phi , 0.0 ,-halfLength / phi)+_position); // Add 12 faces add_face(14, 5,19,18, 4); add_face( 5, 9,11, 7,19); add_face( 6,15,13, 2,10); add_face(12, 0,16,17, 1); add_face( 0, 8,10, 2,16); add_face(16, 2,13, 3,17); add_face( 3,13,15, 7,11); add_face( 7,15, 6,18,19); add_face( 4,18, 6,10, 8); add_face( 4, 8, 0,12,14); add_face(14,12, 1, 9, 5); add_face( 9, 1,17, 3,11); polyMesh_->update_normals(); emit updatedObject(newObject,UPDATE_ALL); emit createBackup(newObject, "Original Object"); PluginFunctions::viewAll(); return newObject; } return -1; } #ifdef ENABLE_BSPLINECURVE_SUPPORT int PrimitivesGeneratorPlugin::addRandomBSplineCurve(const Vector& _position, int nDiv) { int id = -1; emit addEmptyObject(DATA_BSPLINE_CURVE, id); if (id == -1) { return -1; } BSplineCurveObject *object = NULL; if (!PluginFunctions::getObject(id, object)) { return -1; } BSplineCurve *curve = object->splineCurve(); curve->autocompute_knotvector(true); for (int i = 0; i < nDiv; ++i) { double x = _position[0] + i - nDiv / 2.0; double r = (2.0 * std::rand()) / RAND_MAX - 1.0; BSplineCurve::Point cp(x, _position[1] + r, _position[2]); curve->add_control_point(cp); } emit updatedObject(id, UPDATE_ALL); emit createBackup(id, "Original Object"); PluginFunctions::viewAll(); return id; } #endif #ifdef ENABLE_BSPLINESURFACE_SUPPORT int PrimitivesGeneratorPlugin::addRandomBSplineSurface(const Vector& _position, int nDiv) { int id = -1; emit addEmptyObject(DATA_BSPLINE_SURFACE, id); if (id == -1) { return -1; } BSplineSurfaceObject *object = NULL; if (!PluginFunctions::getObject(id, object)) { return -1; } BSplineSurface *surf = object->splineSurface(); typedef BSplineSurface::Point Point; std::vector cp(nDiv); for (int i = 0; i < nDiv; ++i) { double x = _position[0] + i - nDiv / 2.0; for (int j = 0; j < nDiv; ++j) { double y = _position[1] + j - nDiv / 2.0; cp[j] = Point(x, y, _position[2] + (2.0 * std::rand()) / RAND_MAX - 1); } surf->add_vector_m(cp); } surf->createKnots(); emit updatedObject(id, UPDATE_ALL); emit createBackup(id, "Original Object"); PluginFunctions::viewAll(); return id; } #endif #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2( primitivesgeneratorplugin , PrimitivesGeneratorPlugin ); #endif