cgal/Coin/include/CGAL/IO/So_node_terrain.h

535 lines
19 KiB
C++

// ============================================================================
//
// 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<rursu@sophia.inria.fr>
// release :
// release_date :
//
// coordinator : Andreas Fabri<afabri@sophia.inria.fr>
//
// ============================================================================
#ifndef CGAL_SO_NODE_TERRAIN_H
#define CGAL_SO_NODE_TERRAIN_H
#include <CGAL/Cartesian.h>
#include <CGAL/Triangulation_2.h>
#if HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
#if HAVE_WINDOWS_H
#include <windows.h> // gl.h needs types from this file on MSWindows.
#endif // HAVE_WINDOWS_H
#include <qgl.h>
#include <map>
#include <qprogressbar.h>
#include <Inventor/SbBox.h>
#include <Inventor/caches/SoNormalCache.h>
#include <Inventor/caches/SoBoundingBoxCache.h>
#include <Inventor/SoPrimitiveVertex.h>
#include <Inventor/elements/SoGLCoordinateElement.h>
#include <Inventor/elements/SoNormalBindingElement.h>
#include <Inventor/elements/SoGLLazyElement.h>
#include <Inventor/elements/SoGLTextureCoordinateElement.h>
#include <Inventor/elements/SoGLTextureEnabledElement.h>
#include <Inventor/elements/SoMaterialBindingElement.h>
#include <Inventor/elements/SoModelMatrixElement.h>
#include <Inventor/elements/SoDrawStyleElement.h>
#include <Inventor/elements/SoGLLightModelElement.h>
#include <Inventor/misc/SoState.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/actions/SoGetPrimitiveCountAction.h>
#include <Inventor/bundles/SoMaterialBundle.h>
#include <Inventor/bundles/SoTextureCoordinateBundle.h>
#include <Inventor/details/SoLineDetail.h>
#include <Inventor/nodes/SoNonIndexedShape.h>
#include <Inventor/fields/SoMFInt32.h>
template <class Triangulation_2>
class Node_terrain : public SoNonIndexedShape{
//SO_NODE_HEADER(Node_terrain<Triangulation_2>);
//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 CGAL::Cartesian<double> FT;
typedef CGAL::Point_3<FT> CPoint3;
typedef CGAL::Vector_3<FT> CVector3;
typedef std::pair<Face_handle, CVector3> FACENORMALPAIR;
typedef std::pair<Vertex_handle, CVector3> 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::classTypeId =
SoType::createType(SoShape::getClassTypeId(),
classname,
&Node_terrain::createInstance,
SoNode::getNextActionMethodIndex());
SoNode::incNextActionMethodIndex();
// Store parent's fielddata pointer for later use in the constructor.
Node_terrain::parentFieldData = SoShape::getFieldDataPtr();
} while (0);
} while (0);
}// Initializes this class
Node_terrain() : LOCK(0) {
do {
Node_terrain::classinstances++;
// Catch attempts to use a node class which has not been initialized.
assert(Node_terrain::classTypeId != SoType::badType()
&& "you forgot init()!");
// Initialize a fielddata container for the class only once.
if (!Node_terrain::fieldData) {
Node_terrain::fieldData =
new SoFieldData(Node_terrain::parentFieldData ? \
*Node_terrain::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(Triangulation_2 *T) : t(T), LOCK(0) {
do {
compute_normals_for_faces();
compute_normals_for_vertices();
Node_terrain::classinstances++;
// Catch attempts to use a node class which has not been initialized.
assert(Node_terrain::classTypeId != SoType::badType()
&& "you forgot init()!");
// Initialize a fielddata container for the class only once.
if (!Node_terrain::fieldData) {
Node_terrain::fieldData =
new SoFieldData(Node_terrain::parentFieldData ? \
*Node_terrain::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:
static SoType getClassTypeId(void){
return Node_terrain::classTypeId;
}
virtual SoType getTypeId(void) const{
return Node_terrain::classTypeId;
}
private:
static SoType classTypeId;
static void * createInstance(void){
return new Node_terrain;
}
protected:
static const SoFieldData ** getFieldDataPtr(void){
return (const SoFieldData **)(&Node_terrain::fieldData);
}
virtual const SoFieldData * getFieldData(void) const{
return Node_terrain::fieldData;
}
private:
static const SoFieldData ** parentFieldData;
static const SoFieldData * fieldData;
static unsigned int classinstances;
protected:
virtual ~Node_terrain(){} //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);
}
}
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)];
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();
} else {
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) + faces_normals[&(*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()));
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();
}
glPopMatrix();
unlock();
}
virtual void computeBBox(SoAction *,
SbBox3f &box, SbVec3f &center){
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<Vertex_handle, CVector3> vertices_normals;
std::map<Face_handle, CVector3> faces_normals;
Triangulation_2 *t;
int LOCK;
SbBox3f polyhedron_bounding_box;
};
template<class Triangulation_2>
const SoFieldData ** Node_terrain<Triangulation_2>::parentFieldData = NULL;
template<class Triangulation_2>
unsigned int Node_terrain<Triangulation_2>::classinstances = 0;
template<class Triangulation_2>
const SoFieldData * Node_terrain<Triangulation_2>::fieldData = NULL;
template <class Triangulation_2>
SoType Node_terrain<Triangulation_2>::classTypeId = SoType::badType();
#endif