SoFCMeshObject.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2006 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #ifndef _PreComp_
00027 # include <algorithm>
00028 # ifdef FC_OS_WIN32
00029 # include <windows.h>
00030 # endif
00031 # ifdef FC_OS_MACOSX
00032 # include <OpenGL/gl.h>
00033 # include <OpenGL/glu.h>
00034 # else
00035 # include <GL/gl.h>
00036 # include <GL/glu.h>
00037 # endif
00038 # include <Inventor/actions/SoCallbackAction.h>
00039 # include <Inventor/actions/SoGetBoundingBoxAction.h>
00040 # include <Inventor/actions/SoGetPrimitiveCountAction.h>
00041 # include <Inventor/actions/SoGLRenderAction.h>
00042 # include <Inventor/actions/SoPickAction.h>
00043 # include <Inventor/actions/SoWriteAction.h>
00044 # include <Inventor/details/SoFaceDetail.h>
00045 # include <Inventor/errors/SoReadError.h>
00046 # include <Inventor/misc/SoState.h>
00047 #endif
00048 
00049 #include "SoFCMeshObject.h"
00050 #include <Base/Console.h>
00051 #include <Base/Exception.h>
00052 #include <Gui/SoFCInteractiveElement.h>
00053 #include <Gui/SoFCSelectionAction.h>
00054 #include <Mod/Mesh/App/Core/Algorithm.h>
00055 #include <Mod/Mesh/App/Core/MeshIO.h>
00056 #include <Mod/Mesh/App/Core/MeshKernel.h>
00057 #include <Mod/Mesh/App/Core/Elements.h>
00058 #include <Mod/Mesh/App/Core/Grid.h>
00059 
00060 using namespace MeshGui;
00061 
00062 
00063 class SoOutputStreambuf : public std::streambuf
00064 {
00065 public:
00066     SoOutputStreambuf(SoOutput* o) : out(o)
00067     {
00068     }
00069 protected:
00070     int overflow(int c = EOF)
00071     {
00072         if (c != EOF) {
00073             char z = static_cast<char>(c);
00074             out->write(z);
00075         }
00076         return c;
00077     }
00078     std::streamsize xsputn (const char* s, std::streamsize num)
00079     {
00080         out->write(s);
00081         return num;
00082     }
00083 
00084 private:
00085     SoOutput* out;
00086 };
00087 
00088 class SoOutputStream : public std::ostream
00089 {
00090 public:
00091     SoOutputStream(SoOutput* o) : std::ostream(0), buf(o)
00092     {
00093         this->rdbuf(&buf);
00094     }
00095 private:
00096     SoOutputStreambuf buf;
00097 };
00098 
00099 class SoInputStreambuf : public std::streambuf
00100 {
00101 public:
00102     SoInputStreambuf(SoInput* o) : inp(o)
00103     {
00104         setg (buffer+pbSize,
00105               buffer+pbSize,
00106               buffer+pbSize);
00107     }
00108 protected:
00109     int underflow()
00110     {
00111         if (gptr() < egptr()) {
00112             return *gptr();
00113         }
00114 
00115         int numPutback;
00116         numPutback = gptr() - eback();
00117         if (numPutback > pbSize) {
00118             numPutback = pbSize;
00119         }
00120 
00121         memcpy (buffer+(pbSize-numPutback), gptr()-numPutback, numPutback);
00122 
00123         int num=0;
00124         for (int i=0; i<bufSize; i++) {
00125             char c;
00126             SbBool ok = inp->get(c);
00127             if (ok) {
00128                 num++;
00129                 buffer[pbSize+i] = c;
00130                 if (c == '\n')
00131                     break;
00132             }
00133             else if (num==0) {
00134                 return EOF;
00135             }
00136         }
00137 
00138         setg (buffer+(pbSize-numPutback),
00139               buffer+pbSize,
00140               buffer+pbSize+num);
00141 
00142         return *gptr();
00143     }
00144 
00145 private:
00146     static const int pbSize = 4;
00147     static const int bufSize = 1024;
00148     char buffer[bufSize+pbSize];
00149     SoInput* inp;
00150 };
00151 
00152 class SoInputStream : public std::istream
00153 {
00154 public:
00155     SoInputStream(SoInput* o) : std::istream(0), buf(o)
00156     {
00157         this->rdbuf(&buf);
00158     }
00159     ~SoInputStream()
00160     {
00161     }
00162 
00163 private:
00164     SoInputStreambuf buf;
00165 };
00166 
00167 // Defines all required member variables and functions for a
00168 // single-value field
00169 SO_SFIELD_SOURCE(SoSFMeshObject, const Mesh::MeshObject*, const Mesh::MeshObject*);
00170 
00171 
00172 void SoSFMeshObject::initClass()
00173 {
00174     // This macro takes the name of the class and the name of the
00175     // parent class
00176     SO_SFIELD_INIT_CLASS(SoSFMeshObject, SoSField);
00177 }
00178 
00179 // This reads the value of a field from a file. It returns FALSE if the value could not be read
00180 // successfully.
00181 SbBool SoSFMeshObject::readValue(SoInput *in)
00182 {
00183     if (!in->isBinary()) {
00184         SoInputStream str(in);
00185         MeshCore::MeshKernel kernel;
00186         MeshCore::MeshInput(kernel).LoadMeshNode(str);
00187         value = new Mesh::MeshObject(kernel);
00188 
00189         // We need to trigger the notification chain here, as this function
00190         // can be used on a node in a scene graph in any state -- not only
00191         // during initial scene graph import.
00192         this->valueChanged();
00193 
00194         return TRUE;
00195     }
00196 
00197     int32_t countPt;
00198     in->read(countPt);
00199     std::vector<float> verts(countPt);
00200     in->readBinaryArray(&(verts[0]),countPt);
00201 
00202     MeshCore::MeshPointArray rPoints;
00203     rPoints.reserve(countPt/3);
00204     for (std::vector<float>::iterator it = verts.begin();
00205         it != verts.end();) {
00206             Base::Vector3f p;
00207             p.x = *it; it++;
00208             p.y = *it; it++;
00209             p.z = *it; it++;
00210             rPoints.push_back(p);
00211     }
00212 
00213     int32_t countFt;
00214     in->read(countFt);
00215     std::vector<int32_t> faces(countFt);
00216     in->readBinaryArray(&(faces[0]),countFt);
00217 
00218     MeshCore::MeshFacetArray rFacets;
00219     rFacets.reserve(countFt/3);
00220     for (std::vector<int32_t>::iterator it = faces.begin();
00221         it != faces.end();) {
00222             MeshCore::MeshFacet f;
00223             f._aulPoints[0] = *it; it++;
00224             f._aulPoints[1] = *it; it++;
00225             f._aulPoints[2] = *it; it++;
00226             rFacets.push_back(f);
00227     }
00228 
00229     MeshCore::MeshKernel kernel;
00230     kernel.Adopt(rPoints, rFacets, true);
00231     value = new Mesh::MeshObject(kernel);
00232 
00233     // We need to trigger the notification chain here, as this function
00234     // can be used on a node in a scene graph in any state -- not only
00235     // during initial scene graph import.
00236     this->valueChanged();
00237 
00238     return TRUE;
00239 }
00240 
00241 // This writes the value of a field to a file.
00242 void SoSFMeshObject::writeValue(SoOutput *out) const
00243 {
00244     if (!out->isBinary()) {
00245         SoOutputStream str(out);
00246         MeshCore::MeshOutput(value->getKernel()).SaveMeshNode(str);
00247         return;
00248     }
00249 
00250     if (!value) {
00251         int32_t count = 0;
00252         out->write(count);
00253         out->write(count);
00254         return;
00255     }
00256     const MeshCore::MeshPointArray& rPoints = value->getKernel().GetPoints();
00257     std::vector<float> verts;
00258     verts.reserve(3*rPoints.size());
00259     for (MeshCore::MeshPointArray::_TConstIterator it = rPoints.begin();
00260         it != rPoints.end(); ++it) {
00261         verts.push_back(it->x);
00262         verts.push_back(it->y);
00263         verts.push_back(it->z);
00264     }
00265 
00266     int32_t countPt = (int32_t)verts.size();
00267     out->write(countPt);
00268     out->writeBinaryArray(&(verts[0]),countPt);
00269 
00270     const MeshCore::MeshFacetArray& rFacets = value->getKernel().GetFacets();
00271     std::vector<uint32_t> faces;
00272     faces.reserve(3*rFacets.size());
00273     for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin();
00274         it != rFacets.end(); ++it) {
00275         faces.push_back((int32_t)it->_aulPoints[0]);
00276         faces.push_back((int32_t)it->_aulPoints[1]);
00277         faces.push_back((int32_t)it->_aulPoints[2]);
00278     }
00279 
00280     int32_t countFt = (int32_t)faces.size();
00281     out->write(countFt);
00282     out->writeBinaryArray((const int32_t*)&(faces[0]),countFt);
00283 }
00284 
00285 // -------------------------------------------------------
00286 
00287 SO_ELEMENT_SOURCE(SoFCMeshObjectElement);
00288 
00289 void SoFCMeshObjectElement::initClass()
00290 {
00291     SO_ELEMENT_INIT_CLASS(SoFCMeshObjectElement, inherited);
00292 }
00293 
00294 void SoFCMeshObjectElement::init(SoState * state)
00295 {
00296     inherited::init(state);
00297     this->mesh = 0;
00298 }
00299 
00300 SoFCMeshObjectElement::~SoFCMeshObjectElement()
00301 {
00302 }
00303 
00304 void SoFCMeshObjectElement::set(SoState * const state, SoNode * const node, const Mesh::MeshObject * const mesh)
00305 {
00306     SoFCMeshObjectElement * elem = (SoFCMeshObjectElement *)
00307         SoReplacedElement::getElement(state, classStackIndex, node);
00308     if (elem) {
00309         elem->mesh = mesh;
00310         elem->nodeId = node->getNodeId();
00311     }
00312 }
00313 
00314 const Mesh::MeshObject * SoFCMeshObjectElement::get(SoState * const state)
00315 {
00316     return SoFCMeshObjectElement::getInstance(state)->mesh;
00317 }
00318 
00319 const SoFCMeshObjectElement * SoFCMeshObjectElement::getInstance(SoState * state)
00320 {
00321     return (const SoFCMeshObjectElement *) SoElement::getConstElement(state, classStackIndex);
00322 }
00323 
00324 void SoFCMeshObjectElement::print(FILE * /* file */) const
00325 {
00326 }
00327 
00328 // -------------------------------------------------------
00329 
00330 SO_NODE_SOURCE(SoFCMeshPickNode);
00331 
00335 SoFCMeshPickNode::SoFCMeshPickNode(void) : meshGrid(0)
00336 {
00337     SO_NODE_CONSTRUCTOR(SoFCMeshPickNode);
00338 
00339     SO_NODE_ADD_FIELD(mesh, (0));
00340 }
00341 
00345 SoFCMeshPickNode::~SoFCMeshPickNode()
00346 {
00347     delete meshGrid;
00348 }
00349 
00350 // Doc from superclass.
00351 void SoFCMeshPickNode::initClass(void)
00352 {
00353     SO_NODE_INIT_CLASS(SoFCMeshPickNode, SoNode, "Node");
00354 }
00355 
00356 void SoFCMeshPickNode::notify(SoNotList *list)
00357 {
00358     SoField *f = list->getLastField();
00359     if (f == &mesh) {
00360         const Mesh::MeshObject* meshObject = mesh.getValue();
00361         if (meshObject) {
00362             MeshCore::MeshAlgorithm alg(meshObject->getKernel());
00363             float fAvgLen = alg.GetAverageEdgeLength();
00364             delete meshGrid;
00365             meshGrid = new MeshCore::MeshFacetGrid(meshObject->getKernel(), 5.0f * fAvgLen);
00366         }
00367     }
00368 }
00369 
00370 // Doc from superclass.
00371 void SoFCMeshPickNode::rayPick(SoRayPickAction * action)
00372 {
00373 }
00374 
00375 // Doc from superclass.
00376 void SoFCMeshPickNode::pick(SoPickAction * action)
00377 {
00378     SoRayPickAction* raypick = static_cast<SoRayPickAction*>(action);
00379     raypick->setObjectSpace();
00380 
00381     const Mesh::MeshObject* meshObject = mesh.getValue();
00382     MeshCore::MeshAlgorithm alg(meshObject->getKernel());
00383 
00384     const SbLine& line = raypick->getLine();
00385     const SbVec3f& pos = line.getPosition();
00386     const SbVec3f& dir = line.getDirection();
00387     Base::Vector3f pt(pos[0],pos[1],pos[2]);
00388     Base::Vector3f dr(dir[0],dir[1],dir[2]);
00389     unsigned long index;
00390     if (alg.NearestFacetOnRay(pt, dr, *meshGrid, pt, index)) {
00391         SoPickedPoint* pp = raypick->addIntersection(SbVec3f(pt.x,pt.y,pt.z));
00392         if (pp) {
00393             SoFaceDetail* det = new SoFaceDetail();
00394             det->setFaceIndex(index);
00395             pp->setDetail(det, this);
00396         }
00397     }
00398 }
00399 
00400 // -------------------------------------------------------
00401 
00402 SO_NODE_SOURCE(SoFCMeshGridNode);
00403 
00407 SoFCMeshGridNode::SoFCMeshGridNode(void)
00408 {
00409     SO_NODE_CONSTRUCTOR(SoFCMeshGridNode);
00410 
00411     SO_NODE_ADD_FIELD(minGrid, (SbVec3f(0,0,0)));
00412     SO_NODE_ADD_FIELD(maxGrid, (SbVec3f(0,0,0)));
00413     SO_NODE_ADD_FIELD(lenGrid, (SbVec3s(0,0,0)));
00414 }
00415 
00419 SoFCMeshGridNode::~SoFCMeshGridNode()
00420 {
00421 }
00422 
00423 // Doc from superclass.
00424 void SoFCMeshGridNode::initClass(void)
00425 {
00426     SO_NODE_INIT_CLASS(SoFCMeshGridNode, SoNode, "Node");
00427 }
00428 
00429 void SoFCMeshGridNode::GLRender(SoGLRenderAction * action)
00430 {
00431     const SbVec3f& min = minGrid.getValue();
00432     const SbVec3f& max = maxGrid.getValue();
00433     const SbVec3s& len = lenGrid.getValue();
00434     short u,v,w; len.getValue(u,v,w);
00435     float minX, minY, minZ; min.getValue(minX, minY, minZ);
00436     float maxX, maxY, maxZ; max.getValue(maxX, maxY, maxZ);
00437     float dx = (maxX-minX)/(float)u;
00438     float dy = (maxY-minY)/(float)v;
00439     float dz = (maxZ-minZ)/(float)w;
00440     glColor3f(0.0f,1.0f,0.0);
00441     glBegin(GL_LINES);
00442     for (short i=0; i<u+1; i++) {
00443         for (short j=0; j<v+1; j++) {
00444             float p[3];
00445             p[0] = i * dx + minX;
00446             p[1] = j * dy + minY;
00447             p[2] = minZ;
00448             glVertex3fv(p);
00449 
00450             p[0] = i * dx + minX;
00451             p[1] = j * dy + minY;
00452             p[2] = maxZ;
00453             glVertex3fv(p);
00454         }
00455     }
00456     for (short i=0; i<u+1; i++) {
00457         for (short j=0; j<w+1; j++) {
00458             float p[3];
00459             p[0] = i * dx + minX;
00460             p[1] = minY;
00461             p[2] = j * dz + minZ;
00462             glVertex3fv(p);
00463 
00464             p[0] = i * dx + minX;
00465             p[1] = maxY;
00466             p[2] = j * dz + minZ;
00467             glVertex3fv(p);
00468         }
00469     }
00470     for (short i=0; i<v+1; i++) {
00471         for (short j=0; j<w+1; j++) {
00472             float p[3];
00473             p[0] = minX;
00474             p[1] = i * dy + minY;
00475             p[2] = j * dz + minZ;
00476             glVertex3fv(p);
00477 
00478             p[0] = maxX;
00479             p[1] = i * dy + minY;
00480             p[2] = j * dz + minZ;
00481             glVertex3fv(p);
00482         }
00483     }
00484     glEnd();
00485 }
00486 
00487 // -------------------------------------------------------
00488 
00489 SO_NODE_SOURCE(SoFCMeshObjectNode);
00490 
00494 SoFCMeshObjectNode::SoFCMeshObjectNode(void)
00495 {
00496     SO_NODE_CONSTRUCTOR(SoFCMeshObjectNode);
00497 
00498     SO_NODE_ADD_FIELD(mesh, (0));
00499 }
00500 
00504 SoFCMeshObjectNode::~SoFCMeshObjectNode()
00505 {
00506 }
00507 
00508 // Doc from superclass.
00509 void SoFCMeshObjectNode::initClass(void)
00510 {
00511     SO_NODE_INIT_CLASS(SoFCMeshObjectNode, SoNode, "Node");
00512 
00513     SO_ENABLE(SoGetBoundingBoxAction, SoFCMeshObjectElement);
00514     SO_ENABLE(SoGLRenderAction, SoFCMeshObjectElement);
00515     SO_ENABLE(SoPickAction, SoFCMeshObjectElement);
00516     SO_ENABLE(SoCallbackAction, SoFCMeshObjectElement);
00517     SO_ENABLE(SoGetPrimitiveCountAction, SoFCMeshObjectElement);
00518 }
00519 
00520 // Doc from superclass.
00521 void SoFCMeshObjectNode::doAction(SoAction * action)
00522 {
00523     SoFCMeshObjectElement::set(action->getState(), this, mesh.getValue());
00524 }
00525 
00526 // Doc from superclass.
00527 void SoFCMeshObjectNode::GLRender(SoGLRenderAction * action)
00528 {
00529     SoFCMeshObjectNode::doAction(action);
00530 }
00531 
00532 // Doc from superclass.
00533 void SoFCMeshObjectNode::callback(SoCallbackAction * action)
00534 {
00535     SoFCMeshObjectNode::doAction(action);
00536 }
00537 
00538 // Doc from superclass.
00539 void SoFCMeshObjectNode::pick(SoPickAction * action)
00540 {
00541     SoFCMeshObjectNode::doAction(action);
00542 }
00543 
00544 // Doc from superclass.
00545 void SoFCMeshObjectNode::getBoundingBox(SoGetBoundingBoxAction * action)
00546 {
00547     SoFCMeshObjectNode::doAction(action);
00548 }
00549 
00550 // Doc from superclass.
00551 void SoFCMeshObjectNode::getPrimitiveCount(SoGetPrimitiveCountAction * action)
00552 {
00553     SoFCMeshObjectNode::doAction(action);
00554 }
00555 
00556 // Helper functions: draw vertices
00557 inline void glVertex(const MeshCore::MeshPoint& _v)  
00558 {
00559     float v[3];
00560     v[0]=_v.x; v[1]=_v.y;v[2]=_v.z;
00561     glVertex3fv(v); 
00562 }
00563 
00564 // Helper functions: draw normal
00565 inline void glNormal(const Base::Vector3f& _n)
00566 {
00567     float n[3];
00568     n[0]=_n.x; n[1]=_n.y;n[2]=_n.z;
00569     glNormal3fv(n); 
00570 }
00571 
00572 // Helper functions: draw normal
00573 inline void glNormal(float* n)
00574 {
00575     glNormal3fv(n); 
00576 }
00577 
00578 // Helper function: convert Vec to SbVec3f
00579 inline SbVec3f sbvec3f(const Base::Vector3f& _v)
00580 {
00581     return SbVec3f(_v.x, _v.y, _v.z); 
00582 }
00583 
00584 SO_NODE_SOURCE(SoFCMeshObjectShape);
00585 
00586 void SoFCMeshObjectShape::initClass()
00587 {
00588     SO_NODE_INIT_CLASS(SoFCMeshObjectShape, SoShape, "Shape");
00589 }
00590 
00591 SoFCMeshObjectShape::SoFCMeshObjectShape() : renderTriangleLimit(100000), meshChanged(true)
00592 {
00593     SO_NODE_CONSTRUCTOR(SoFCMeshObjectShape);
00594     setName(SoFCMeshObjectShape::getClassTypeId().getName());
00595 }
00596 
00597 void SoFCMeshObjectShape::notify(SoNotList * node)
00598 {
00599     inherited::notify(node);
00600     meshChanged = true;
00601 }
00602 
00606 void SoFCMeshObjectShape::GLRender(SoGLRenderAction *action)
00607 {
00608     if (shouldGLRender(action))
00609     {
00610         SoState*  state = action->getState();
00611 
00612         // Here we must save the model and projection matrices because
00613         // we need them later for picking
00614         glGetFloatv(GL_MODELVIEW_MATRIX, this->modelview);
00615         glGetFloatv(GL_PROJECTION_MATRIX, this->projection);
00616 
00617         SbBool mode = Gui::SoFCInteractiveElement::get(state);
00618         const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
00619         if (!mesh || mesh->countPoints() == 0) return;
00620 
00621         Binding mbind = this->findMaterialBinding(state);
00622 
00623         SoMaterialBundle mb(action);
00624         //SoTextureCoordinateBundle tb(action, true, false);
00625 
00626         SbBool needNormals = !mb.isColorOnly()/* || tb.isFunction()*/;
00627         mb.sendFirst();  // make sure we have the correct material
00628     
00629         SbBool ccw = TRUE;
00630         if (SoShapeHintsElement::getVertexOrdering(state) == SoShapeHintsElement::CLOCKWISE) 
00631             ccw = FALSE;
00632 
00633         if (mode == false || mesh->countFacets() <= this->renderTriangleLimit) {
00634             if (mbind != OVERALL)
00635                 drawFaces(mesh, &mb, mbind, needNormals, ccw);
00636             else
00637                 drawFaces(mesh, 0, mbind, needNormals, ccw);
00638         }
00639         else {
00640             drawPoints(mesh, needNormals, ccw);
00641         }
00642 
00643         // Disable caching for this node
00644         //SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
00645     }
00646 }
00647 
00651 SoFCMeshObjectShape::Binding SoFCMeshObjectShape::findMaterialBinding(SoState * const state) const
00652 {
00653     Binding binding = OVERALL;
00654     SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state);
00655 
00656     switch (matbind) {
00657     case SoMaterialBindingElement::OVERALL:
00658         binding = OVERALL;
00659         break;
00660     case SoMaterialBindingElement::PER_VERTEX:
00661         binding = PER_VERTEX_INDEXED;
00662         break;
00663     case SoMaterialBindingElement::PER_VERTEX_INDEXED:
00664         binding = PER_VERTEX_INDEXED;
00665         break;
00666     case SoMaterialBindingElement::PER_PART:
00667     case SoMaterialBindingElement::PER_FACE:
00668         binding = PER_FACE_INDEXED;
00669         break;
00670     case SoMaterialBindingElement::PER_PART_INDEXED:
00671     case SoMaterialBindingElement::PER_FACE_INDEXED:
00672         binding = PER_FACE_INDEXED;
00673         break;
00674     default:
00675         break;
00676     }
00677     return binding;
00678 }
00679 
00685 void SoFCMeshObjectShape::drawFaces(const Mesh::MeshObject * mesh, SoMaterialBundle* mb,
00686                                     Binding bind, SbBool needNormals, SbBool ccw) const
00687 {
00688     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
00689     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
00690     bool perVertex = (mb && bind == PER_VERTEX_INDEXED);
00691     bool perFace = (mb && bind == PER_FACE_INDEXED);
00692 
00693     if (needNormals)
00694     {
00695         glBegin(GL_TRIANGLES);
00696         if (ccw) {
00697             // counterclockwise ordering
00698             for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it)
00699             {
00700                 const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[0]];
00701                 const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[1]];
00702                 const MeshCore::MeshPoint& v2 = rPoints[it->_aulPoints[2]];
00703 
00704                 // Calculate the normal n = (v1-v0)x(v2-v0)
00705                 float n[3];
00706                 n[0] = (v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y);
00707                 n[1] = (v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z);
00708                 n[2] = (v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x);
00709     
00710                 if(perFace)
00711                 mb->send(it-rFacets.begin(), TRUE);
00712                 glNormal(n);
00713                 if(perVertex)
00714                 mb->send(it->_aulPoints[0], TRUE);
00715                 glVertex(v0);
00716                 if(perVertex)
00717                 mb->send(it->_aulPoints[1], TRUE);
00718                 glVertex(v1);
00719                 if(perVertex)
00720                 mb->send(it->_aulPoints[2], TRUE);
00721                 glVertex(v2);
00722             }
00723         }
00724         else {
00725             // clockwise ordering
00726             for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it)
00727             {
00728                 const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[0]];
00729                 const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[1]];
00730                 const MeshCore::MeshPoint& v2 = rPoints[it->_aulPoints[2]];
00731 
00732                 // Calculate the normal n = -(v1-v0)x(v2-v0)
00733                 float n[3];
00734                 n[0] = -((v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y));
00735                 n[1] = -((v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z));
00736                 n[2] = -((v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x));
00737 
00738                 glNormal(n);
00739                 glVertex(v0);
00740                 glVertex(v1);
00741                 glVertex(v2);
00742             }
00743         }
00744         glEnd();
00745     }
00746     else {
00747         glBegin(GL_TRIANGLES);
00748         for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it)
00749         {
00750             glVertex(rPoints[it->_aulPoints[0]]);
00751             glVertex(rPoints[it->_aulPoints[1]]);
00752             glVertex(rPoints[it->_aulPoints[2]]);
00753         }
00754         glEnd();
00755     }
00756 }
00757 
00761 void SoFCMeshObjectShape::drawPoints(const Mesh::MeshObject * mesh, SbBool needNormals, SbBool ccw) const
00762 {
00763     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
00764     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
00765     int mod = rFacets.size()/renderTriangleLimit+1;
00766 
00767     float size = std::min<float>((float)mod,3.0f);
00768     glPointSize(size);
00769 
00770     if (needNormals)
00771     {
00772         glBegin(GL_POINTS);
00773         int ct=0;
00774         if (ccw) {
00775             for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it, ct++)
00776             {
00777                 if (ct%mod==0) {
00778                     const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[0]];
00779                     const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[1]];
00780                     const MeshCore::MeshPoint& v2 = rPoints[it->_aulPoints[2]];
00781 
00782                     // Calculate the normal n = (v1-v0)x(v2-v0)
00783                     float n[3];
00784                     n[0] = (v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y);
00785                     n[1] = (v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z);
00786                     n[2] = (v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x);
00787 
00788                     // Calculate the center point p=(v0+v1+v2)/3
00789                     float p[3];
00790                     p[0] = (v0.x+v1.x+v2.x)/3.0f;
00791                     p[1] = (v0.y+v1.y+v2.y)/3.0f;
00792                     p[2] = (v0.z+v1.z+v2.z)/3.0f;
00793                     glNormal3fv(n);
00794                     glVertex3fv(p);
00795                 }
00796             }
00797         }
00798         else {
00799             for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it, ct++)
00800             {
00801                 if (ct%mod==0) {
00802                     const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[0]];
00803                     const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[1]];
00804                     const MeshCore::MeshPoint& v2 = rPoints[it->_aulPoints[2]];
00805 
00806                     // Calculate the normal n = -(v1-v0)x(v2-v0)
00807                     float n[3];
00808                     n[0] = -((v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y));
00809                     n[1] = -((v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z));
00810                     n[2] = -((v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x));
00811       
00812                     // Calculate the center point p=(v0+v1+v2)/3
00813                     float p[3];
00814                     p[0] = (v0.x+v1.x+v2.x)/3.0f;
00815                     p[1] = (v0.y+v1.y+v2.y)/3.0f;
00816                     p[2] = (v0.z+v1.z+v2.z)/3.0f;
00817                     glNormal3fv(n);
00818                     glVertex3fv(p);
00819                 }
00820             }
00821         }
00822         glEnd();
00823     }
00824     else {
00825         glBegin(GL_POINTS);
00826         int ct=0;
00827         for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it, ct++)
00828         {
00829             if (ct%mod==0) {
00830                 const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[0]];
00831                 const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[1]];
00832                 const MeshCore::MeshPoint& v2 = rPoints[it->_aulPoints[2]];
00833                 // Calculate the center point p=(v0+v1+v2)/3
00834                 float p[3];
00835                 p[0] = (v0.x+v1.x+v2.x)/3.0f;
00836                 p[1] = (v0.y+v1.y+v2.y)/3.0f;
00837                 p[2] = (v0.z+v1.z+v2.z)/3.0f;
00838                 glVertex3fv(p);
00839             }
00840         }
00841         glEnd();
00842     }
00843 }
00844 
00845 void SoFCMeshObjectShape::doAction(SoAction * action)
00846 {
00847     if (action->getTypeId() == Gui::SoGLSelectAction::getClassTypeId()) {
00848         SoNode* node = action->getNodeAppliedTo();
00849         if (!node) return; // on no node applied
00850 
00851         // The node we have is the parent of this node and the coordinate node
00852         // thus we search there for it.
00853         SoSearchAction sa;
00854         sa.setInterest(SoSearchAction::FIRST);
00855         sa.setSearchingAll(FALSE);
00856         sa.setType(SoFCMeshObjectNode::getClassTypeId(), 1);
00857         sa.apply(node);
00858         SoPath * path = sa.getPath();
00859         if (!path) return;
00860 
00861         // make sure we got the node we wanted
00862         SoNode* coords = path->getNodeFromTail(0);
00863         if (!(coords && coords->getTypeId().isDerivedFrom(SoFCMeshObjectNode::getClassTypeId())))
00864             return;
00865         const Mesh::MeshObject* mesh = static_cast<SoFCMeshObjectNode*>(coords)->mesh.getValue();
00866         startSelection(action, mesh);
00867         renderSelectionGeometry(mesh);
00868         stopSelection(action, mesh);
00869     }
00870 
00871     inherited::doAction(action);
00872 }
00873 
00874 void SoFCMeshObjectShape::startSelection(SoAction * action, const Mesh::MeshObject* mesh)
00875 {
00876     Gui::SoGLSelectAction *doaction = static_cast<Gui::SoGLSelectAction*>(action);
00877     const SbViewportRegion& vp = doaction->getViewportRegion();
00878     int x = vp.getViewportOriginPixels()[0];
00879     int y = vp.getViewportOriginPixels()[1];
00880     int w = vp.getViewportSizePixels()[0];
00881     int h = vp.getViewportSizePixels()[1];
00882 
00883     unsigned int bufSize = 5*mesh->countFacets(); // make the buffer big enough
00884     this->selectBuf = new GLuint[bufSize];
00885 
00886     glSelectBuffer(bufSize, selectBuf);
00887     glRenderMode(GL_SELECT);
00888 
00889     glInitNames();
00890     glPushName(-1);
00891 
00892     //double mp[16];
00893     GLint viewport[4];
00894     glGetIntegerv(GL_VIEWPORT,viewport);
00895     glMatrixMode(GL_PROJECTION);
00896     //glGetDoublev(GL_PROJECTION_MATRIX ,mp);
00897     glPushMatrix();
00898     glLoadIdentity();
00899     gluPickMatrix(x, y, w, h, viewport);
00900     glMultMatrixf(/*mp*/this->projection);
00901     glMatrixMode(GL_MODELVIEW);
00902     glPushMatrix();
00903     glLoadMatrixf(this->modelview);
00904 }
00905 
00906 void SoFCMeshObjectShape::stopSelection(SoAction * action, const Mesh::MeshObject* mesh)
00907 {
00908     // restoring the original projection matrix
00909     glPopMatrix();
00910     glMatrixMode(GL_PROJECTION);
00911     glPopMatrix();
00912     glMatrixMode(GL_MODELVIEW);
00913     glFlush();
00914 
00915     // returning to normal rendering mode
00916     GLint hits = glRenderMode(GL_RENDER);
00917 
00918     unsigned int bufSize = 5*mesh->countFacets();
00919     std::vector< std::pair<double,unsigned int> > hit;
00920     GLuint index=0;
00921     for (GLint ii=0;ii<hits && index<bufSize;ii++) {
00922         GLint ct = (GLint)selectBuf[index];
00923         hit.push_back(std::pair<double,unsigned int>
00924             (selectBuf[index+1]/4294967295.0,selectBuf[index+3]));
00925         index = index+ct+3;
00926     }
00927 
00928     delete [] selectBuf;
00929     selectBuf = 0;
00930     bool sorted = true;
00931     if(sorted) std::sort(hit.begin(),hit.end());
00932 
00933     Gui::SoGLSelectAction *doaction = static_cast<Gui::SoGLSelectAction*>(action);
00934     doaction->indices.reserve(hit.size());
00935     for (GLint ii=0;ii<hits;ii++) {
00936         doaction->indices.push_back(hit[ii].second);
00937     }
00938 }
00939 
00940 void SoFCMeshObjectShape::renderSelectionGeometry(const Mesh::MeshObject* mesh)
00941 {
00942     int fcnt=0;
00943     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
00944     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
00945     MeshCore::MeshFacetArray::_TConstIterator it_end = rFacets.end();
00946     for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != it_end; ++it) {
00947         const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[0]];
00948         const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[1]];
00949         const MeshCore::MeshPoint& v2 = rPoints[it->_aulPoints[2]];
00950         glLoadName(fcnt);
00951         glBegin(GL_TRIANGLES);
00952         glVertex(v0);
00953         glVertex(v1);
00954         glVertex(v2);
00955         glEnd();
00956         fcnt++;
00957     }
00958 }
00959 
00960 // test bbox intersection
00961 //static SbBool
00962 //SoFCMeshObjectShape_ray_intersect(SoRayPickAction * action, const SbBox3f & box)
00963 //{
00964 //    if (box.isEmpty()) return FALSE;
00965 //    return action->intersect(box, TRUE);
00966 //}
00967 
00971 void
00972 SoFCMeshObjectShape::rayPick(SoRayPickAction * action)
00973 {
00974     //if (this->shouldRayPick(action)) {
00975     //    this->computeObjectSpaceRay(action);
00976 
00977     //    const SoBoundingBoxCache* bboxcache = getBoundingBoxCache();
00978     //    if (!bboxcache || !bboxcache->isValid(action->getState()) ||
00979     //        SoFCMeshObjectShape_ray_intersect(action, bboxcache->getProjectedBox())) {
00980     //        this->generatePrimitives(action);
00981     //    }
00982     //}
00983     inherited::rayPick(action);
00984 }
00985 
00991 void SoFCMeshObjectShape::generatePrimitives(SoAction* action)
00992 {
00993     SoState*  state = action->getState();
00994     const Mesh::MeshObject* mesh = SoFCMeshObjectElement::get(state);
00995     if (!mesh)
00996         return;
00997     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
00998     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
00999     if (rPoints.size() < 3)
01000         return;
01001     if (rFacets.size() < 1)
01002         return;
01003 
01004     // get material binding
01005     Binding mbind = this->findMaterialBinding(state);
01006 
01007     // Create the information when moving over or picking into the scene
01008     SoPrimitiveVertex vertex;
01009     SoPointDetail pointDetail;
01010     SoFaceDetail faceDetail;
01011 
01012     vertex.setDetail(&pointDetail);
01013 
01014     beginShape(action, TRIANGLES, &faceDetail);
01015     try 
01016     {
01017         for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it)
01018         {
01019             const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[0]];
01020             const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[1]];
01021             const MeshCore::MeshPoint& v2 = rPoints[it->_aulPoints[2]];
01022 
01023             // Calculate the normal n = (v1-v0)x(v2-v0)
01024             SbVec3f n;
01025             n[0] = (v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y);
01026             n[1] = (v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z);
01027             n[2] = (v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x);
01028 
01029             // Set the normal
01030             vertex.setNormal(n);
01031 
01032             // Vertex 0
01033             if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
01034                 pointDetail.setMaterialIndex(it->_aulPoints[0]);
01035                 vertex.setMaterialIndex(it->_aulPoints[0]);
01036             }
01037             pointDetail.setCoordinateIndex(it->_aulPoints[0]);
01038             vertex.setPoint(sbvec3f(v0));
01039             shapeVertex(&vertex);
01040 
01041             // Vertex 1
01042             if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
01043                 pointDetail.setMaterialIndex(it->_aulPoints[1]);
01044                 vertex.setMaterialIndex(it->_aulPoints[1]);
01045             }
01046             pointDetail.setCoordinateIndex(it->_aulPoints[1]);
01047             vertex.setPoint(sbvec3f(v1));
01048             shapeVertex(&vertex);
01049 
01050             // Vertex 2
01051             if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
01052                 pointDetail.setMaterialIndex(it->_aulPoints[2]);
01053                 vertex.setMaterialIndex(it->_aulPoints[2]);
01054             }
01055             pointDetail.setCoordinateIndex(it->_aulPoints[2]);
01056             vertex.setPoint(sbvec3f(v2));
01057             shapeVertex(&vertex);
01058 
01059             // Increment for the next face
01060             faceDetail.incFaceIndex();
01061         }
01062     }
01063     catch (const Base::MemoryException&) {
01064         Base::Console().Log("Not enough memory to generate primitives\n");
01065     }
01066 
01067     endShape();
01068 }
01069 
01078 SoDetail * SoFCMeshObjectShape::createTriangleDetail(SoRayPickAction * action,
01079                                               const SoPrimitiveVertex * v1,
01080                                               const SoPrimitiveVertex * v2,
01081                                               const SoPrimitiveVertex * v3,
01082                                               SoPickedPoint * pp)
01083 {
01084     SoDetail* detail = inherited::createTriangleDetail(action, v1, v2, v3, pp);
01085     return detail;
01086 }
01087 
01091 void SoFCMeshObjectShape::computeBBox(SoAction *action, SbBox3f &box, SbVec3f &center)
01092 {
01093     SoState*  state = action->getState();
01094     const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01095     if (mesh && mesh->countPoints() > 0) {
01096         Base::BoundBox3f cBox = mesh->getKernel().GetBoundBox();
01097         box.setBounds(SbVec3f(cBox.MinX,cBox.MinY,cBox.MinZ),
01098                       SbVec3f(cBox.MaxX,cBox.MaxY,cBox.MaxZ));
01099         Base::Vector3f mid = cBox.CalcCenter();
01100         center.setValue(mid.x,mid.y,mid.z);
01101     }
01102     else {
01103         box.setBounds(SbVec3f(0,0,0), SbVec3f(0,0,0));
01104         center.setValue(0.0f,0.0f,0.0f);
01105     }
01106 }
01107 
01111 void SoFCMeshObjectShape::getPrimitiveCount(SoGetPrimitiveCountAction * action)
01112 {
01113     if (!this->shouldPrimitiveCount(action)) return;
01114     SoState*  state = action->getState();
01115     const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01116     action->addNumTriangles(mesh->countFacets());
01117     action->addNumPoints(mesh->countPoints());
01118 }
01119 
01123 unsigned int SoFCMeshObjectShape::countTriangles(SoAction * action) const
01124 {
01125     SoState*  state = action->getState();
01126     const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01127     return (unsigned int)mesh->countFacets();
01128 }
01129 
01130 // -------------------------------------------------------
01131 
01132 SO_NODE_SOURCE(SoFCMeshSegmentShape);
01133 
01134 void SoFCMeshSegmentShape::initClass()
01135 {
01136     SO_NODE_INIT_CLASS(SoFCMeshSegmentShape, SoShape, "Shape");
01137 }
01138 
01139 SoFCMeshSegmentShape::SoFCMeshSegmentShape() : renderTriangleLimit(100000)
01140 {
01141     SO_NODE_CONSTRUCTOR(SoFCMeshSegmentShape);
01142     SO_NODE_ADD_FIELD(index, (0));
01143 }
01144 
01148 void SoFCMeshSegmentShape::GLRender(SoGLRenderAction *action)
01149 {
01150     if (shouldGLRender(action))
01151     {
01152         SoState*  state = action->getState();
01153 
01154         SbBool mode = Gui::SoFCInteractiveElement::get(state);
01155         const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01156         if (!mesh) return;
01157 
01158         Binding mbind = this->findMaterialBinding(state);
01159 
01160         SoMaterialBundle mb(action);
01161         //SoTextureCoordinateBundle tb(action, true, false);
01162 
01163         SbBool needNormals = !mb.isColorOnly()/* || tb.isFunction()*/;
01164         mb.sendFirst();  // make sure we have the correct material
01165     
01166         SbBool ccw = TRUE;
01167         if (SoShapeHintsElement::getVertexOrdering(state) == SoShapeHintsElement::CLOCKWISE) 
01168             ccw = FALSE;
01169 
01170         if (mode == false || mesh->countFacets() <= this->renderTriangleLimit) {
01171             if (mbind != OVERALL)
01172                 drawFaces(mesh, &mb, mbind, needNormals, ccw);
01173             else
01174                 drawFaces(mesh, 0, mbind, needNormals, ccw);
01175         }
01176         else {
01177             drawPoints(mesh, needNormals, ccw);
01178         }
01179 
01180         // Disable caching for this node
01181         //SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
01182     }
01183 }
01184 
01188 SoFCMeshSegmentShape::Binding SoFCMeshSegmentShape::findMaterialBinding(SoState * const state) const
01189 {
01190     Binding binding = OVERALL;
01191     SoMaterialBindingElement::Binding matbind = SoMaterialBindingElement::get(state);
01192 
01193     switch (matbind) {
01194     case SoMaterialBindingElement::OVERALL:
01195         binding = OVERALL;
01196         break;
01197     case SoMaterialBindingElement::PER_VERTEX:
01198         binding = PER_VERTEX_INDEXED;
01199         break;
01200     case SoMaterialBindingElement::PER_VERTEX_INDEXED:
01201         binding = PER_VERTEX_INDEXED;
01202         break;
01203     case SoMaterialBindingElement::PER_PART:
01204     case SoMaterialBindingElement::PER_FACE:
01205         binding = PER_FACE_INDEXED;
01206         break;
01207     case SoMaterialBindingElement::PER_PART_INDEXED:
01208     case SoMaterialBindingElement::PER_FACE_INDEXED:
01209         binding = PER_FACE_INDEXED;
01210         break;
01211     default:
01212         break;
01213     }
01214     return binding;
01215 }
01216 
01222 void SoFCMeshSegmentShape::drawFaces(const Mesh::MeshObject * mesh, SoMaterialBundle* mb,
01223                                     Binding bind, SbBool needNormals, SbBool ccw) const
01224 {
01225     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
01226     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
01227     if (mesh->countSegments() <= this->index.getValue())
01228         return;
01229     const std::vector<unsigned long> rSegm = mesh->getSegment
01230         (this->index.getValue()).getIndices();
01231     bool perVertex = (mb && bind == PER_VERTEX_INDEXED);
01232     bool perFace = (mb && bind == PER_FACE_INDEXED);
01233 
01234     if (needNormals)
01235     {
01236         glBegin(GL_TRIANGLES);
01237         if (ccw) {
01238             // counterclockwise ordering
01239             for (std::vector<unsigned long>::const_iterator it = rSegm.begin(); it != rSegm.end(); ++it)
01240             {
01241                 const MeshCore::MeshFacet& f = rFacets[*it];
01242                 const MeshCore::MeshPoint& v0 = rPoints[f._aulPoints[0]];
01243                 const MeshCore::MeshPoint& v1 = rPoints[f._aulPoints[1]];
01244                 const MeshCore::MeshPoint& v2 = rPoints[f._aulPoints[2]];
01245 
01246                 // Calculate the normal n = (v1-v0)x(v2-v0)
01247                 float n[3];
01248                 n[0] = (v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y);
01249                 n[1] = (v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z);
01250                 n[2] = (v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x);
01251     
01252                 if(perFace)
01253                 mb->send(*it, TRUE);
01254                 glNormal(n);
01255                 if(perVertex)
01256                 mb->send(f._aulPoints[0], TRUE);
01257                 glVertex(v0);
01258                 if(perVertex)
01259                 mb->send(f._aulPoints[1], TRUE);
01260                 glVertex(v1);
01261                 if(perVertex)
01262                 mb->send(f._aulPoints[2], TRUE);
01263                 glVertex(v2);
01264             }
01265         }
01266         else {
01267             // clockwise ordering
01268             for (std::vector<unsigned long>::const_iterator it = rSegm.begin(); it != rSegm.end(); ++it)
01269             {
01270                 const MeshCore::MeshFacet& f = rFacets[*it];
01271                 const MeshCore::MeshPoint& v0 = rPoints[f._aulPoints[0]];
01272                 const MeshCore::MeshPoint& v1 = rPoints[f._aulPoints[1]];
01273                 const MeshCore::MeshPoint& v2 = rPoints[f._aulPoints[2]];
01274 
01275                 // Calculate the normal n = -(v1-v0)x(v2-v0)
01276                 float n[3];
01277                 n[0] = -((v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y));
01278                 n[1] = -((v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z));
01279                 n[2] = -((v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x));
01280 
01281                 glNormal(n);
01282                 glVertex(v0);
01283                 glVertex(v1);
01284                 glVertex(v2);
01285             }
01286         }
01287         glEnd();
01288     }
01289     else {
01290         glBegin(GL_TRIANGLES);
01291         for (std::vector<unsigned long>::const_iterator it = rSegm.begin(); it != rSegm.end(); ++it)
01292         {
01293             const MeshCore::MeshFacet& f = rFacets[*it];
01294             glVertex(rPoints[f._aulPoints[0]]);
01295             glVertex(rPoints[f._aulPoints[1]]);
01296             glVertex(rPoints[f._aulPoints[2]]);
01297         }
01298         glEnd();
01299     }
01300 }
01301 
01305 void SoFCMeshSegmentShape::drawPoints(const Mesh::MeshObject * mesh, SbBool needNormals, SbBool ccw) const
01306 {
01307     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
01308     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
01309     if (mesh->countSegments() <= this->index.getValue())
01310         return;
01311     const std::vector<unsigned long> rSegm = mesh->getSegment
01312         (this->index.getValue()).getIndices();
01313     int mod = rSegm.size()/renderTriangleLimit+1;
01314 
01315     float size = std::min<float>((float)mod,3.0f);
01316     glPointSize(size);
01317 
01318     if (needNormals)
01319     {
01320         glBegin(GL_POINTS);
01321         int ct=0;
01322         if (ccw) {
01323             for (std::vector<unsigned long>::const_iterator it = rSegm.begin(); it != rSegm.end(); ++it, ct++)
01324             {
01325                 if (ct%mod==0) {
01326                     const MeshCore::MeshFacet& f = rFacets[*it];
01327                     const MeshCore::MeshPoint& v0 = rPoints[f._aulPoints[0]];
01328                     const MeshCore::MeshPoint& v1 = rPoints[f._aulPoints[1]];
01329                     const MeshCore::MeshPoint& v2 = rPoints[f._aulPoints[2]];
01330 
01331                     // Calculate the normal n = (v1-v0)x(v2-v0)
01332                     float n[3];
01333                     n[0] = (v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y);
01334                     n[1] = (v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z);
01335                     n[2] = (v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x);
01336 
01337                     // Calculate the center point p=(v0+v1+v2)/3
01338                     float p[3];
01339                     p[0] = (v0.x+v1.x+v2.x)/3.0f;
01340                     p[1] = (v0.y+v1.y+v2.y)/3.0f;
01341                     p[2] = (v0.z+v1.z+v2.z)/3.0f;
01342                     glNormal3fv(n);
01343                     glVertex3fv(p);
01344                 }
01345             }
01346         }
01347         else {
01348             for (std::vector<unsigned long>::const_iterator it = rSegm.begin(); it != rSegm.end(); ++it, ct++)
01349             {
01350                 if (ct%mod==0) {
01351                     const MeshCore::MeshFacet& f = rFacets[*it];
01352                     const MeshCore::MeshPoint& v0 = rPoints[f._aulPoints[0]];
01353                     const MeshCore::MeshPoint& v1 = rPoints[f._aulPoints[1]];
01354                     const MeshCore::MeshPoint& v2 = rPoints[f._aulPoints[2]];
01355 
01356                     // Calculate the normal n = -(v1-v0)x(v2-v0)
01357                     float n[3];
01358                     n[0] = -((v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y));
01359                     n[1] = -((v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z));
01360                     n[2] = -((v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x));
01361       
01362                     // Calculate the center point p=(v0+v1+v2)/3
01363                     float p[3];
01364                     p[0] = (v0.x+v1.x+v2.x)/3.0f;
01365                     p[1] = (v0.y+v1.y+v2.y)/3.0f;
01366                     p[2] = (v0.z+v1.z+v2.z)/3.0f;
01367                     glNormal3fv(n);
01368                     glVertex3fv(p);
01369                 }
01370             }
01371         }
01372         glEnd();
01373     }
01374     else {
01375         glBegin(GL_POINTS);
01376         int ct=0;
01377         for (std::vector<unsigned long>::const_iterator it = rSegm.begin(); it != rSegm.end(); ++it, ct++)
01378         {
01379             if (ct%mod==0) {
01380                 const MeshCore::MeshFacet& f = rFacets[*it];
01381                 const MeshCore::MeshPoint& v0 = rPoints[f._aulPoints[0]];
01382                 const MeshCore::MeshPoint& v1 = rPoints[f._aulPoints[1]];
01383                 const MeshCore::MeshPoint& v2 = rPoints[f._aulPoints[2]];
01384                 // Calculate the center point p=(v0+v1+v2)/3
01385                 float p[3];
01386                 p[0] = (v0.x+v1.x+v2.x)/3.0f;
01387                 p[1] = (v0.y+v1.y+v2.y)/3.0f;
01388                 p[2] = (v0.z+v1.z+v2.z)/3.0f;
01389                 glVertex3fv(p);
01390             }
01391         }
01392         glEnd();
01393     }
01394 }
01395 
01401 void SoFCMeshSegmentShape::generatePrimitives(SoAction* action)
01402 {
01403     SoState*  state = action->getState();
01404     const Mesh::MeshObject* mesh = SoFCMeshObjectElement::get(state);
01405     if (!mesh)
01406         return;
01407     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
01408     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
01409     if (rPoints.size() < 3)
01410         return;
01411     if (rFacets.size() < 1)
01412         return;
01413     if (mesh->countSegments() <= this->index.getValue())
01414         return;
01415     const std::vector<unsigned long> rSegm = mesh->getSegment
01416         (this->index.getValue()).getIndices();
01417 
01418     // get material binding
01419     Binding mbind = this->findMaterialBinding(state);
01420 
01421     // Create the information when moving over or picking into the scene
01422     SoPrimitiveVertex vertex;
01423     SoPointDetail pointDetail;
01424     SoFaceDetail faceDetail;
01425 
01426     vertex.setDetail(&pointDetail);
01427 
01428     beginShape(action, TRIANGLES, &faceDetail);
01429     try 
01430     {
01431         for (std::vector<unsigned long>::const_iterator it = rSegm.begin(); it != rSegm.end(); ++it)
01432         {
01433             const MeshCore::MeshFacet& f = rFacets[*it];
01434             const MeshCore::MeshPoint& v0 = rPoints[f._aulPoints[0]];
01435             const MeshCore::MeshPoint& v1 = rPoints[f._aulPoints[1]];
01436             const MeshCore::MeshPoint& v2 = rPoints[f._aulPoints[2]];
01437 
01438             // Calculate the normal n = (v1-v0)x(v2-v0)
01439             SbVec3f n;
01440             n[0] = (v1.y-v0.y)*(v2.z-v0.z)-(v1.z-v0.z)*(v2.y-v0.y);
01441             n[1] = (v1.z-v0.z)*(v2.x-v0.x)-(v1.x-v0.x)*(v2.z-v0.z);
01442             n[2] = (v1.x-v0.x)*(v2.y-v0.y)-(v1.y-v0.y)*(v2.x-v0.x);
01443 
01444             // Set the normal
01445             vertex.setNormal(n);
01446 
01447             // Vertex 0
01448             if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
01449                 pointDetail.setMaterialIndex(f._aulPoints[0]);
01450                 vertex.setMaterialIndex(f._aulPoints[0]);
01451             }
01452             pointDetail.setCoordinateIndex(f._aulPoints[0]);
01453             vertex.setPoint(sbvec3f(v0));
01454             shapeVertex(&vertex);
01455 
01456             // Vertex 1
01457             if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
01458                 pointDetail.setMaterialIndex(f._aulPoints[1]);
01459                 vertex.setMaterialIndex(f._aulPoints[1]);
01460             }
01461             pointDetail.setCoordinateIndex(f._aulPoints[1]);
01462             vertex.setPoint(sbvec3f(v1));
01463             shapeVertex(&vertex);
01464 
01465             // Vertex 2
01466             if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
01467                 pointDetail.setMaterialIndex(f._aulPoints[2]);
01468                 vertex.setMaterialIndex(f._aulPoints[2]);
01469             }
01470             pointDetail.setCoordinateIndex(f._aulPoints[2]);
01471             vertex.setPoint(sbvec3f(v2));
01472             shapeVertex(&vertex);
01473 
01474             // Increment for the next face
01475             faceDetail.incFaceIndex();
01476         }
01477     }
01478     catch (const Base::MemoryException&) {
01479         Base::Console().Log("Not enough memory to generate primitives\n");
01480     }
01481 
01482     endShape();
01483 }
01484 
01488 void SoFCMeshSegmentShape::computeBBox(SoAction *action, SbBox3f &box, SbVec3f &center)
01489 {
01490     box.setBounds(SbVec3f(0,0,0), SbVec3f(0,0,0));
01491     center.setValue(0.0f,0.0f,0.0f);
01492 
01493     SoState*  state = action->getState();
01494     const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01495     if (mesh && mesh->countSegments() > this->index.getValue()) {
01496         const Mesh::Segment& segm = mesh->getSegment(this->index.getValue());
01497         const std::vector<unsigned long>& indices = segm.getIndices();
01498         Base::BoundBox3f cBox;
01499         if (!indices.empty()) {
01500             const MeshCore::MeshPointArray& rPoint = mesh->getKernel().GetPoints();
01501             const MeshCore::MeshFacetArray& rFaces = mesh->getKernel().GetFacets();
01502 
01503             for (std::vector<unsigned long>::const_iterator it = indices.begin();
01504                 it != indices.end(); ++it) {
01505                     const MeshCore::MeshFacet& face = rFaces[*it];
01506                     cBox &= rPoint[face._aulPoints[0]];
01507                     cBox &= rPoint[face._aulPoints[1]];
01508                     cBox &= rPoint[face._aulPoints[2]];
01509             }
01510             
01511             box.setBounds(SbVec3f(cBox.MinX,cBox.MinY,cBox.MinZ),
01512                           SbVec3f(cBox.MaxX,cBox.MaxY,cBox.MaxZ));
01513             Base::Vector3f mid = cBox.CalcCenter();
01514             center.setValue(mid.x,mid.y,mid.z);
01515         }
01516     }
01517 }
01518 
01522 void SoFCMeshSegmentShape::getPrimitiveCount(SoGetPrimitiveCountAction * action)
01523 {
01524     if (!this->shouldPrimitiveCount(action)) return;
01525     SoState*  state = action->getState();
01526     const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01527     if (mesh && mesh->countSegments() > this->index.getValue()) {
01528         const Mesh::Segment& segm = mesh->getSegment(this->index.getValue());
01529         action->addNumTriangles(segm.getIndices().size());
01530     }
01531 }
01532 
01533 // -------------------------------------------------------
01534 
01535 SO_NODE_SOURCE(SoFCMeshObjectBoundary);
01536 
01537 void SoFCMeshObjectBoundary::initClass()
01538 {
01539     SO_NODE_INIT_CLASS(SoFCMeshObjectBoundary, SoShape, "Shape");
01540 }
01541 
01542 SoFCMeshObjectBoundary::SoFCMeshObjectBoundary()
01543 {
01544     SO_NODE_CONSTRUCTOR(SoFCMeshObjectBoundary);
01545 }
01546 
01550 void SoFCMeshObjectBoundary::GLRender(SoGLRenderAction *action)
01551 {
01552     if (shouldGLRender(action))
01553     {
01554         SoState*  state = action->getState();
01555         const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01556         if (!mesh) return;
01557 
01558         SoMaterialBundle mb(action);
01559         SoTextureCoordinateBundle tb(action, TRUE, FALSE);
01560         SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
01561         mb.sendFirst();  // make sure we have the correct material
01562 
01563         drawLines(mesh);
01564 
01565         // Disable caching for this node
01566         //SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
01567     }
01568 }
01569 
01573 void SoFCMeshObjectBoundary::drawLines(const Mesh::MeshObject * mesh) const
01574 {
01575     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
01576     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
01577 
01578     // When rendering open edges use the given line width * 3 
01579     GLfloat lineWidth;
01580     glGetFloatv(GL_LINE_WIDTH, &lineWidth);
01581     glLineWidth(3.0f*lineWidth);
01582 
01583     // Use the data structure directly and not through MeshFacetIterator as this
01584     // class is quite slowly (at least for rendering)
01585     glBegin(GL_LINES);
01586     for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it) {
01587         for (int i=0; i<3; i++) {
01588             if (it->_aulNeighbours[i] == ULONG_MAX) {
01589                 glVertex(rPoints[it->_aulPoints[i]]);
01590                 glVertex(rPoints[it->_aulPoints[(i+1)%3]]);
01591             }
01592         }
01593     }
01594 
01595     glEnd();
01596 }
01597 
01598 void SoFCMeshObjectBoundary::generatePrimitives(SoAction* action)
01599 {
01600     // do not create primitive information as an SoFCMeshObjectShape
01601     // should already be used that delivers the information
01602     SoState*  state = action->getState();
01603     const Mesh::MeshObject* mesh = SoFCMeshObjectElement::get(state);
01604     if (!mesh)
01605         return;
01606     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
01607     const MeshCore::MeshFacetArray & rFacets = mesh->getKernel().GetFacets();
01608 
01609     // Create the information when moving over or picking into the scene
01610     SoPrimitiveVertex vertex;
01611     SoPointDetail pointDetail;
01612     SoLineDetail lineDetail;
01613 
01614     vertex.setDetail(&pointDetail);
01615 
01616     beginShape(action, LINES, &lineDetail);
01617     for (MeshCore::MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it)
01618     {
01619         for (int i=0; i<3; i++) {
01620             if (it->_aulNeighbours[i] == ULONG_MAX) {
01621                 const MeshCore::MeshPoint& v0 = rPoints[it->_aulPoints[i]];
01622                 const MeshCore::MeshPoint& v1 = rPoints[it->_aulPoints[(i+1)%3]];
01623 
01624                 // Vertex 0
01625                 pointDetail.setCoordinateIndex(it->_aulPoints[i]);
01626                 vertex.setPoint(sbvec3f(v0));
01627                 shapeVertex(&vertex);
01628 
01629                 // Vertex 1
01630                 pointDetail.setCoordinateIndex(it->_aulPoints[(i+1)%3]);
01631                 vertex.setPoint(sbvec3f(v1));
01632                 shapeVertex(&vertex);
01633 
01634                 // Increment for the next open edge
01635                 lineDetail.incLineIndex();
01636             }
01637         }
01638     }
01639 
01640     endShape();
01641 }
01642 
01646 void SoFCMeshObjectBoundary::computeBBox(SoAction *action, SbBox3f &box, SbVec3f &center)
01647 {
01648     SoState*  state = action->getState();
01649     const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01650     if (!mesh)
01651         return;
01652     const MeshCore::MeshPointArray & rPoints = mesh->getKernel().GetPoints();
01653     if (rPoints.size() > 0) {
01654         Base::BoundBox3f cBox;
01655         for (MeshCore::MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it)
01656             cBox &= (*it);
01657         box.setBounds(SbVec3f(cBox.MinX,cBox.MinY,cBox.MinZ),
01658                       SbVec3f(cBox.MaxX,cBox.MaxY,cBox.MaxZ));
01659         Base::Vector3f mid = cBox.CalcCenter();
01660         center.setValue(mid.x,mid.y,mid.z);
01661     }
01662     else {
01663         box.setBounds(SbVec3f(0,0,0), SbVec3f(0,0,0));
01664         center.setValue(0.0f,0.0f,0.0f);
01665     }
01666 }
01667 
01671 void SoFCMeshObjectBoundary::getPrimitiveCount(SoGetPrimitiveCountAction * action)
01672 {
01673     if (!this->shouldPrimitiveCount(action)) return;
01674     SoState*  state = action->getState();
01675     const Mesh::MeshObject * mesh = SoFCMeshObjectElement::get(state);
01676     if (!mesh)
01677         return;
01678     const MeshCore::MeshFacetArray & rFaces = mesh->getKernel().GetFacets();
01679 
01680     // Count number of open edges first
01681     int ctEdges=0;
01682     for (MeshCore::MeshFacetArray::_TConstIterator jt = rFaces.begin(); jt != rFaces.end(); ++jt) {
01683         for (int i=0; i<3; i++) {
01684             if (jt->_aulNeighbours[i] == ULONG_MAX) {
01685                 ctEdges++;
01686             }
01687         }
01688     }
01689 
01690     action->addNumLines(ctEdges);
01691 }

Generated on Wed Nov 23 19:00:39 2011 for FreeCAD by  doxygen 1.6.1