// ============================================================================ // // Copyright (c) 1997-2002 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------------- // // file : So_node_terrain.h // package : OpenInventor // author(s) : Radu Ursu // release : // release_date : // // coordinator : Andreas Fabri // // ============================================================================ #ifndef CGAL_SO_NODE_TERRAIN_H #define CGAL_SO_NODE_TERRAIN_H #include #include #if HAVE_CONFIG_H #include #endif // HAVE_CONFIG_H #if HAVE_WINDOWS_H #include // gl.h needs types from this file on MSWindows. #endif // HAVE_WINDOWS_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include template class Node_terrain_constrained : public SoNonIndexedShape{ //SO_NODE_HEADER(Node_terrain); //defined in Inventor/nodes/SoSubNode.h //it's not working with this node because this node //it's a template class public: typedef typename Triangulation_2::Geom_traits Traits; typedef typename Triangulation_2::Vertex_handle Vertex_handle; typedef typename Triangulation_2::Face_handle Face_handle; typedef typename Triangulation_2::Finite_vertices_iterator Finite_vertices_iterator; typedef typename Triangulation_2::Finite_faces_iterator Finite_faces_iterator; typedef typename Triangulation_2::Face_circulator Face_circulator; typedef typename Triangulation_2::Finite_edges_iterator Finite_edges_iterator; typedef CGAL::Simple_cartesian FT; typedef FT::Point_3 CPoint3; //typedef CGAL::Point_3 CPoint3; typedef CGAL::Vector_3 CVector3; typedef std::pair FACENORMALPAIR; typedef std::pair VERTEXNORMALPAIR; static void initClass(){ do { const char * classname = SO__QUOTE(Node_terrain); //PRIVATE_COMMON_INIT_CODE(_class_, classname, // &_class_::createInstance, _parentclass_); do { // Make sure we only initialize once. assert(Node_terrain::classTypeId == SoType::badType() && "don't init() twice!"); // Make sure superclass gets initialized before subclass. assert(SoShape::getClassTypeId() != SoType::badType() && "you forgot init() on parentclass!"); // Set up entry in the type system. Node_terrain_constrained::classTypeId = SoType::createType(SoShape::getClassTypeId(), classname, &Node_terrain_constrained::createInstance, SoNode::getNextActionMethodIndex()); SoNode::incNextActionMethodIndex(); // Store parent's fielddata pointer for later use in the constructor. Node_terrain_constrained::parentFieldData = SoShape::getFieldDataPtr(); } while (0); } while (0); }// Initializes this class Node_terrain_constrained() : LOCK(0), max_height(0) { do { Node_terrain_constrained::classinstances++; // Catch attempts to use a node class which has not been initialized. assert(Node_terrain_constrained::classTypeId != SoType::badType() && "you forgot init()!"); // Initialize a fielddata container for the class only once. if (!Node_terrain_constrained::fieldData) { Node_terrain_constrained::fieldData = new SoFieldData(Node_terrain_constrained::parentFieldData ? \ *Node_terrain_constrained::parentFieldData : NULL); } // Extension classes from the application programmers should not be // considered native. This is important to get the export code to do // the Right Thing. this->isBuiltIn = FALSE; } while (0); }// The constructor Node_terrain_constrained(Triangulation_2 *T) : t(T), LOCK(0), max_height(0) { do { compute_normals_for_faces(); compute_normals_for_vertices(); Node_terrain_constrained::classinstances++; // Catch attempts to use a node class which has not been initialized. assert(Node_terrain_constrained::classTypeId != SoType::badType() && "you forgot init()!"); // Initialize a fielddata container for the class only once. if (!Node_terrain_constrained::fieldData) { Node_terrain_constrained::fieldData = new SoFieldData(Node_terrain_constrained::parentFieldData ? \ *Node_terrain_constrained::parentFieldData : NULL); } // Extension classes from the application programmers should not be // considered native. This is important to get the export code to do // the Right Thing. this->isBuiltIn = FALSE; } while (0); }// The constructor void compute_normals_for_faces(){ lock(); faces_normals.erase(faces_normals.begin(), faces_normals.end()); QProgressBar * progress = new QProgressBar(NULL, "My Progress"); progress->setCaption("Normals for faces"); progress->setTotalSteps(t->number_of_faces()); progress->show(); int faces_count = 0; Finite_faces_iterator fit; for (fit = t->finite_faces_begin(); fit != t->finite_faces_end(); fit++){ progress->setProgress( faces_count ); CPoint3 p1(CGAL::to_double((*(*fit).vertex(0)).point().x()), CGAL::to_double((*(*fit).vertex(0)).point().y()), CGAL::to_double((*(*fit).vertex(0)).point().z())); CPoint3 p2(CGAL::to_double((*(*fit).vertex(1)).point().x()), CGAL::to_double((*(*fit).vertex(1)).point().y()), CGAL::to_double((*(*fit).vertex(1)).point().z())); CPoint3 p3(CGAL::to_double((*(*fit).vertex(2)).point().x()), CGAL::to_double((*(*fit).vertex(2)).point().y()), CGAL::to_double((*(*fit).vertex(2)).point().z())); CVector3 normal = CGAL::cross_product(p2 - p1, p3 - p1); double sqnorm = normal * normal; if(sqnorm != 0){ CVector3 v_n = normal / std::sqrt(sqnorm); faces_normals.insert(FACENORMALPAIR(&(*fit), v_n)); } faces_count++; } progress->setProgress( faces_count ); progress->hide(); //delete progress; unlock(); } void compute_normals_for_vertices(){ lock(); vertices_normals.erase(vertices_normals.begin(), vertices_normals.end()); QProgressBar * progress = new QProgressBar(NULL, "My Progress"); progress->setCaption("Normals for vertices"); progress->setTotalSteps(t->number_of_vertices()); progress->show(); int vertices_count = 0; Finite_vertices_iterator vit; for ( vit = t->finite_vertices_begin(); vit != t->finite_vertices_end(); vit++){ progress->setProgress(vertices_count); Face_circulator cit = (&(*vit))->incident_faces(); unsigned int normals_count = 0; CVector3 normals_sum(0, 0, 0); do{ normals_sum = normals_sum + faces_normals[&(*cit)]; normals_count++; }while(++cit!=(&(*vit))->incident_faces()); normals_sum = normals_sum/normals_count; double sqnorm = normals_sum * normals_sum; if(sqnorm != 0){ CVector3 v_n = normals_sum / std::sqrt(sqnorm); vertices_normals.insert(VERTEXNORMALPAIR(&(*vit), v_n)); } vertices_count++; } progress->setProgress(vertices_count); progress->hide(); //delete progress; unlock(); } void lock(){LOCK++;} void unlock(){ if(LOCK>0) LOCK--; else assert( LOCK != 0 && "lock is already 0. Be sure you have the same \ number of locks as the number of unlocks"); } SoMFInt32 numVertices; public: void set_max_height(double h){max_height = h;} static SoType getClassTypeId(void){ return Node_terrain_constrained::classTypeId; } virtual SoType getTypeId(void) const{ return Node_terrain_constrained::classTypeId; } private: static SoType classTypeId; static void * createInstance(void){ return new Node_terrain_constrained; } protected: static const SoFieldData ** getFieldDataPtr(void){ return (const SoFieldData **)(&Node_terrain_constrained::fieldData); } virtual const SoFieldData * getFieldData(void) const{ return Node_terrain_constrained::fieldData; } private: static const SoFieldData ** parentFieldData; static const SoFieldData * fieldData; static unsigned int classinstances; protected: virtual ~Node_terrain_constrained(){} //The destructor virtual void getPrimitiveCount(SoGetPrimitiveCountAction * action){ if (!this->shouldPrimitiveCount(action)) return; int32_t dummyarray[1]; const int32_t *ptr = this->numVertices.getValues(0); const int32_t *end = ptr + this->numVertices.getNum(); this->fixNumVerticesPointers(action->getState(), ptr, end, dummyarray); if (action->canApproximateCount()) { action->addNumLines(end-ptr); } else { int cnt = 0; while (ptr < end) { cnt += *ptr++ - 1; } action->addNumLines(cnt); } } void set_face_color(Finite_faces_iterator *fit){ double a = CGAL::to_double((*(*(*fit)).vertex(0)).point().z()); double b = CGAL::to_double((*(*(*fit)).vertex(1)).point().z()); double c = CGAL::to_double((*(*(*fit)).vertex(2)).point().z()); if(a > max_height/3 || b > max_height/3 || c > max_height/3){ glColor3f(1.0f, 1.0f, 1.0f); } else if(a > max_height/6 || b > max_height/6 || c > max_height/6){ glColor3f(0.8f, 0.4f, 0.1f); } else if(a > max_height/10 || b > max_height/10 || c > max_height/10){ glColor3f(0.0f, 1.0f, 0.0f); } else glColor3f(0.0f, 0.0f, 1.0f); } virtual void GLRender(SoGLRenderAction *action){ if (LOCK) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); return; } else lock(); SoState * state = action->getState(); // First see if the object is visible and should be rendered // now. This is a method on SoShape that checks for INVISIBLE // draw style, BOUNDING_BOX complexity, and delayed // transparency. if (!this->shouldGLRender(action)) { return; } // Determine if we need to send normals. Normals are // necessary if we are not doing BASE_COLOR lighting. // we use the Lazy element to get the light model. SbBool sendNormals = (SoLazyElement::getLightModel(state) != SoLazyElement::BASE_COLOR); // Determine if there's a material bound per part SoMaterialBindingElement::Binding material_binding = SoMaterialBindingElement::get(state); SbBool materialPerPart = (material_binding == SoMaterialBindingElement::PER_PART || material_binding == SoMaterialBindingElement::PER_PART_INDEXED); // issue a lazy element send. // This send will ensure that all material state in GL is current. SoGLLazyElement::sendAllMaterial(state); float complexity = SbClamp(this->getComplexityValue(action), 0.0f, 1.0f); //Complexity value, valid settings range //from 0.0 (worst appearance, best perfomance) //to 1.0 (optimal appearance, lowest rendering speed) glPushMatrix(); if(complexity == 0){//render the bounding box SbVec3f min = polyhedron_bounding_box.getMin(); SbVec3f max = polyhedron_bounding_box.getMax(); glBegin(GL_QUADS); { CVector3 normal = CGAL::cross_product( CPoint3(min[0], min[1], max[2]) - CPoint3(min[0], min[1], min[2]), CPoint3(min[0], max[1], max[2]) - CPoint3(min[0], min[1], max[2])); double sqnorm = normal * normal; if(sqnorm != 0){ CVector3 v_n = normal / std::sqrt(sqnorm); CPoint3 pn = CPoint3(0, 0, 0) + v_n; glNormal3f(pn.x(), pn.y(), pn.z()); } } glVertex3f(min[0], min[1], min[2]); glVertex3f(min[0], min[1], max[2]); glVertex3f(min[0], max[1], max[2]); glVertex3f(min[0], max[1], min[2]); { CVector3 normal = CGAL::cross_product( CPoint3(max[0], max[1], min[2]) - CPoint3(max[0], min[1], min[2]), CPoint3(max[0], min[1], min[2]) - CPoint3(min[0], min[1], min[2])); double sqnorm = normal * normal; if(sqnorm != 0){ CVector3 v_n = normal / std::sqrt(sqnorm); CPoint3 pn = CPoint3(0, 0, 0) + v_n; glNormal3f(pn.x(), pn.y(), pn.z()); } } glVertex3f(min[0], min[1], min[2]); glVertex3f(max[0], min[1], min[2]); glVertex3f(max[0], max[1], min[2]); glVertex3f(min[0], max[1], min[2]); { CVector3 normal = CGAL::cross_product( CPoint3(max[0], min[1], max[2]) - CPoint3(min[0], min[1], max[2]), CPoint3(max[0], max[1], max[2]) - CPoint3(max[0], min[1], max[2])); double sqnorm = normal * normal; if(sqnorm != 0){ CVector3 v_n = normal / std::sqrt(sqnorm); CPoint3 pn = CPoint3(0, 0, 0) + v_n; glNormal3f(pn.x(), pn.y(), pn.z()); } } glVertex3f(min[0], min[1], max[2]); glVertex3f(max[0], min[1], max[2]); glVertex3f(max[0], max[1], max[2]); glVertex3f(min[0], max[1], max[2]); { CVector3 normal = CGAL::cross_product( CPoint3(max[0], min[1], max[0]) - CPoint3(min[0], min[1], max[0]), CPoint3(min[0], min[1], max[0]) - CPoint3(min[0], min[1], min[2])); double sqnorm = normal * normal; if(sqnorm != 0){ CVector3 v_n = normal / std::sqrt(sqnorm); CPoint3 pn = CPoint3(0, 0, 0) + v_n; glNormal3f(pn.x(), pn.y(), pn.z()); } } glVertex3f(min[0], min[1], min[2]); glVertex3f(min[0], min[1], max[2]); glVertex3f(max[0], min[1], max[2]); glVertex3f(max[0], min[1], min[2]); { CVector3 normal = CGAL::cross_product( CPoint3(max[0], max[1], max[2]) - CPoint3(max[0], min[1], max[2]), CPoint3(max[0], min[1], max[2]) - CPoint3(max[0], min[1], min[2])); double sqnorm = normal * normal; if(sqnorm != 0){ CVector3 v_n = normal / std::sqrt(sqnorm); CPoint3 pn = CPoint3(0, 0, 0) + v_n; glNormal3f(pn.x(), pn.y(), pn.z()); } } glVertex3f(max[0], min[1], min[2]); glVertex3f(max[0], min[1], max[2]); glVertex3f(max[0], max[1], max[2]); glVertex3f(max[0], max[1], min[2]); { CVector3 normal = CGAL::cross_product( CPoint3(min[0], max[1], min[2]) - CPoint3(min[0], max[1], max[2]), CPoint3(min[0], max[1], max[2]) - CPoint3(max[0], max[1], max[2])); double sqnorm = normal * normal; if(sqnorm != 0){ CVector3 v_n = normal / std::sqrt(sqnorm); CPoint3 pn = CPoint3(0, 0, 0) + v_n; glNormal3f(pn.x(), pn.y(), pn.z()); } } glVertex3f(max[0], max[1], max[2]); glVertex3f(min[0], max[1], max[2]); glVertex3f(min[0], max[1], min[2]); glVertex3f(max[0], max[1], min[2]); glEnd(); } else if(complexity==1){ //render smooth Finite_faces_iterator fit; glBegin(GL_TRIANGLES); for (fit = t->finite_faces_begin(); fit != t->finite_faces_end(); fit++){ CPoint3 pn = CPoint3(0, 0, 0) + vertices_normals[(*fit).vertex(0)]; set_face_color(&fit); glNormal3f(pn.x(), pn.y(), pn.z()); glVertex3f(CGAL::to_double((*(*fit).vertex(0)).point().x()), CGAL::to_double((*(*fit).vertex(0)).point().y()), CGAL::to_double((*(*fit).vertex(0)).point().z())); pn = CPoint3(0, 0, 0) + vertices_normals[(*fit).vertex(1)]; glNormal3f(pn.x(), pn.y(), pn.z()); glVertex3f(CGAL::to_double((*(*fit).vertex(1)).point().x()), CGAL::to_double((*(*fit).vertex(1)).point().y()), CGAL::to_double((*(*fit).vertex(1)).point().z())); pn = CPoint3(0, 0, 0) + vertices_normals[(*fit).vertex(2)]; glNormal3f(pn.x(), pn.y(), pn.z()); glVertex3f(CGAL::to_double((*(*fit).vertex(2)).point().x()), CGAL::to_double((*(*fit).vertex(2)).point().y()), CGAL::to_double((*(*fit).vertex(2)).point().z())); } glEnd(); Finite_edges_iterator eit = t->finite_edges_begin(); while(eit!=t->finite_edges_end()){ if(t->is_constrained((*eit))){ glColor3f(1.0f, 0.0f, 0.0f); glLineWidth(2); glBegin(GL_LINES); CPoint3 p1 = (*(*((*eit).first)).vertex(((*eit).second + 1)%3)).point(); CPoint3 p2 = (*(*((*eit).first)).vertex(((*eit).second + 2)%3)).point(); glVertex3f(p1.x(), p1.y(), p1.z()); glVertex3f(p2.x(), p2.y(), p2.z()); glEnd(); } else { glBegin(GL_LINES); glEnd(); } eit++; } } else { Finite_faces_iterator fit; glColor3f(0.5f, 0.6f, 0.0f); glBegin(GL_TRIANGLES); for (fit = t->finite_faces_begin(); fit != t->finite_faces_end(); fit++){ CPoint3 pn = CPoint3(0, 0, 0) + faces_normals[&(*fit)]; glNormal3f(pn.x(), pn.y(), pn.z()); set_face_color(&fit); glVertex3f(CGAL::to_double((*(*fit).vertex(0)).point().x()), CGAL::to_double((*(*fit).vertex(0)).point().y()), CGAL::to_double((*(*fit).vertex(0)).point().z())); glVertex3f(CGAL::to_double((*(*fit).vertex(1)).point().x()), CGAL::to_double((*(*fit).vertex(1)).point().y()), CGAL::to_double((*(*fit).vertex(1)).point().z())); glVertex3f(CGAL::to_double((*(*fit).vertex(2)).point().x()), CGAL::to_double((*(*fit).vertex(2)).point().y()), CGAL::to_double((*(*fit).vertex(2)).point().z())); } glEnd(); Finite_edges_iterator eit = t->finite_edges_begin(); while(eit!=t->finite_edges_end()){ if(t->is_constrained((*eit))){ glColor3f(1.0f, 0.0f, 0.0f); glLineWidth(2); glBegin(GL_LINES); CPoint3 p1 = (*(*((*eit).first)).vertex(((*eit).second + 1)%3)).point(); CPoint3 p2 = (*(*((*eit).first)).vertex(((*eit).second + 2)%3)).point(); glVertex3f(p1.x(), p1.y(), p1.z()); glVertex3f(p2.x(), p2.y(), p2.z()); glEnd(); } else { glBegin(GL_LINES); glEnd(); } eit++; } } glPopMatrix(); unlock(); } virtual void computeBBox(SoAction *, SbBox3f &box, SbVec3f ¢er){ Finite_vertices_iterator vit; double xmin = 0, ymin = 0, zmin = 0, xmax = 0, ymax = 0, zmax = 0; for ( vit = t->finite_vertices_begin(); vit != t->finite_vertices_end(); vit++) { if(CGAL::to_double((*vit).point().x()) < xmin) xmin = CGAL::to_double((*vit).point().x()); if(CGAL::to_double((*vit).point().y()) < ymin) ymin = CGAL::to_double((*vit).point().y()); if(CGAL::to_double((*vit).point().z()) < zmin) zmin = CGAL::to_double((*vit).point().z()); if(CGAL::to_double((*vit).point().x()) > xmax) xmax = CGAL::to_double((*vit).point().x()); if(CGAL::to_double((*vit).point().y()) > ymax) ymax = CGAL::to_double((*vit).point().y()); if(CGAL::to_double((*vit).point().z()) > zmax) zmax = CGAL::to_double((*vit).point().z()); } SbVec3f min, max; // Set the box to bound the two extreme points min.setValue(xmin, ymin, zmin); max.setValue(xmax, ymax, zmax); box.setBounds(min, max); polyhedron_bounding_box.setBounds(min, max); } // Generates triangles representing the triangulation virtual void generatePrimitives(SoAction *action){} private: virtual SbBool generateDefaultNormals(SoState *, SoNormalCache * nc){ // not possible to generate normals for LineSet nc->set(0, NULL); return TRUE; } virtual SbBool generateDefaultNormals(SoState * state, SoNormalBundle * bundle){return FALSE;} std::map vertices_normals; std::map faces_normals; Triangulation_2 *t; int LOCK; SbBox3f polyhedron_bounding_box; double max_height; }; template const SoFieldData ** Node_terrain_constrained::parentFieldData = NULL; template unsigned int Node_terrain_constrained::classinstances = 0; template const SoFieldData * Node_terrain_constrained::fieldData = NULL; template SoType Node_terrain_constrained::classTypeId = SoType::badType(); #endif