surface_quad.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "stdpacs.h"
00025 
00026 #include "nel/misc/file.h"
00027 
00028 #include "surface_quad.h"
00029 
00030 #include <vector>
00031 
00032 using namespace NLMISC;
00033 using namespace std;
00034 
00035 NLPACS::CSurfaceQuadTree::CSurfaceQuadTree()
00036 {
00037     _Root = NULL;
00038     _MaxThickness = FLT_MAX;
00039     _MaxLevel = 1;
00040     _BBox.setCenter(CVector::Null);
00041     _BBox.setSize(CVector::Null);
00042 }
00043 
00044 NLPACS::CSurfaceQuadTree::CSurfaceQuadTree(const NLPACS::CSurfaceQuadTree &quad)
00045 {
00046     *this = quad;
00047 }
00048 
00049 NLPACS::CSurfaceQuadTree    &NLPACS::CSurfaceQuadTree::operator = (const NLPACS::CSurfaceQuadTree &quad)
00050 {
00051     if (&quad == this)
00052         return *this;
00053 
00054     _MaxThickness = quad._MaxThickness;
00055     _MaxLevel = quad._MaxLevel;
00056     _BBox = quad._BBox;
00057 
00058     _Root = NULL;
00059     if (quad._Root != NULL)
00060     {
00061         if (quad._Root->isLeaf())
00062         {
00063             CQuadLeaf   *newLeaf = new CQuadLeaf();
00064             *newLeaf = *((CQuadLeaf *)(quad._Root));
00065             _Root = newLeaf;
00066         }
00067         else
00068         {
00069             CQuadBranch *newBranch = new CQuadBranch();
00070             *newBranch = *((CQuadBranch *)(quad._Root));
00071             _Root = newBranch;
00072         }
00073     }
00074 
00075     return *this;
00076 }
00077 
00078 void    NLPACS::CSurfaceQuadTree::clear()
00079 {
00080     delete _Root;
00081     _Root = NULL;
00082 }
00083 
00084 void    NLPACS::CSurfaceQuadTree::init(float maxThickness, uint maxLevel, const CVector &center, float halfSize)
00085 {
00086     nlassert(maxLevel > 0);
00087     clear();
00088     _MaxThickness = maxThickness;
00089     _MaxLevel = uint8(maxLevel);
00090     _BBox.setCenter(center);
00091     _BBox.setHalfSize(CVector(halfSize, halfSize, 10000.0f));
00092 }
00093 
00094 void    NLPACS::CSurfaceQuadTree::addVertex(const CVector &v)
00095 {
00096     if (!_BBox.include(v))
00097         return;
00098 
00099     if (_Root == NULL)
00100     {
00101         if (_MaxLevel == 1)
00102         {
00103             _Root = new CQuadLeaf(_MaxLevel);
00104         }
00105         else
00106         {
00107             _Root = new CQuadBranch(_MaxLevel);
00108         }
00109 
00110         _Root->_MaxThickness = _MaxThickness;
00111         _Root->_HalfSize = _BBox.getHalfSize().x;
00112         _Root->_MinHeight = FLT_MAX;
00113         _Root->_MaxHeight = -FLT_MAX;
00114         _Root->_XCenter = _BBox.getCenter().x;
00115         _Root->_YCenter = _BBox.getCenter().y;
00116     }
00117 
00118     _Root->addVertex(v);
00119 }
00120 
00121 void    NLPACS::CSurfaceQuadTree::compile()
00122 {
00123     if (_Root != NULL &&
00124         !_Root->isLeaf() &&
00125         _Root->getMaxHeight()-_Root->getMinHeight() <= _MaxThickness)
00126     {
00127         CQuadLeaf   *leaf = new CQuadLeaf();
00128         *((IQuadNode *)leaf) = *_Root;
00129         delete _Root;
00130         _Root = leaf;
00131     }
00132     else if (_Root != NULL &&
00133              !_Root->isLeaf())
00134     {
00135         ((CQuadBranch *)_Root)->reduceChildren();
00136     }
00137 }
00138 
00139 
00140 NLPACS::CQuadBranch::CQuadBranch(const NLPACS::CQuadBranch &branch) : NLPACS::IQuadNode(branch)
00141 {
00142     *this = branch;
00143 }
00144 
00145 NLPACS::CQuadBranch &NLPACS::CQuadBranch::operator = (const NLPACS::CQuadBranch &branch)
00146 {
00147     IQuadNode::operator=(branch);
00148 
00149     uint    child;
00150     for (child=0; child<4; ++child)
00151     {
00152         _Children[child] = NULL;
00153         if (branch._Children[child] != NULL)
00154         {
00155             if (branch._Children[child]->isLeaf())
00156             {
00157                 CQuadLeaf   *newLeaf = new CQuadLeaf();
00158                 *newLeaf = *((CQuadLeaf *)(branch._Children[child]));
00159                 _Children[child] = newLeaf;
00160             }
00161             else
00162             {
00163                 CQuadBranch *newBranch = new CQuadBranch();
00164                 *newBranch = *((CQuadBranch *)(branch._Children[child]));
00165                 _Children[child] = newBranch;
00166             }
00167         }
00168     }
00169     return *this;
00170 }
00171 
00172 void    NLPACS::CQuadBranch::reduceChildren()
00173 {
00174     uint    i;
00175 
00176     for (i=0; i<4; ++i)
00177     {
00178         if (_Children[i] != NULL &&
00179             !_Children[i]->isLeaf() &&
00180             _Children[i]->getMaxHeight()-_Children[i]->getMinHeight() <= _MaxThickness)
00181         {
00182             CQuadLeaf   *leaf = new CQuadLeaf();
00183             *((IQuadNode *)leaf) = *_Children[i];
00184             delete _Children[i];
00185             _Children[i] = leaf;
00186         }
00187         else if (_Children[i] != NULL &&
00188                  !_Children[i]->isLeaf())
00189         {
00190             ((CQuadBranch *)_Children[i])->reduceChildren();
00191         }
00192     }
00193 }
00194 
00195 void    NLPACS::CQuadBranch::addVertex(const CVector &v)
00196 {
00197     IQuadNode::addVertex(v);
00198     uint    child;
00199     if (v.x > _XCenter)
00200         child = (v.y > _YCenter) ? 2 : 1;
00201     else
00202         child = (v.y > _YCenter) ? 3 : 0;
00203 
00204     if (_Children[child] == NULL)
00205     {
00206         if (_Level == 2)
00207         {
00208             _Children[child] = new CQuadLeaf(_Level-1);
00209         }
00210         else
00211         {
00212             _Children[child] = new CQuadBranch(_Level-1);
00213         }
00214 
00215         _Children[child]->_MaxThickness = _MaxThickness;
00216         _Children[child]->_HalfSize = _HalfSize/2.0f;
00217         _Children[child]->_MinHeight = FLT_MAX;
00218         _Children[child]->_MaxHeight = -FLT_MAX;
00219         _Children[child]->_XCenter = _XCenter+_Children[child]->_HalfSize*((child == 1 || child == 2) ? 1.0f : -1.0f);
00220         _Children[child]->_YCenter = _YCenter+_Children[child]->_HalfSize*((child == 2 || child == 3) ? 1.0f : -1.0f);
00221     }
00222 
00223     _Children[child]->addVertex(v);
00224 }
00225 
00226 bool    NLPACS::CQuadBranch::check() const
00227 {
00228     if (!IQuadNode::check())
00229         return false;
00230 
00231     uint    child;
00232     for (child=0; child<4; ++child)
00233         if (_Children[child] != NULL && !_Children[child]->check())
00234             return false;
00235     return true;
00236 }
00237 
00238 
00239 /*
00240  * Serialization methods...
00241  */
00242 
00243 
00244 void    NLPACS::CQuadBranch::serial(NLMISC::IStream &f)
00245 {
00246     IQuadNode::serial(f);
00247 
00248     uint    child;
00249     for (child=0; child<4; ++child)
00250     {
00251         uint8   childType = 0;
00252 
00253         if (f.isReading())
00254         {
00255             CQuadLeaf   *leaf;
00256             CQuadBranch *branch;
00257             f.serial(childType);
00258             switch (childType)
00259             {
00260             case NoChild:
00261                 _Children[child] = NULL;
00262                 break;
00263             case LeafChild:
00264                 leaf = new CQuadLeaf();
00265                 _Children[child] = leaf;
00266                 leaf->serial(f);
00267                 break;
00268             case BranchChild:
00269                 branch = new CQuadBranch();;
00270                 _Children[child] = branch;
00271                 branch->serial(f);
00272                 break;
00273             default:
00274                 nlerror("While serializing (read) CQuadBranch: unknown child type");
00275                 break;
00276             }
00277         }
00278         else
00279         {
00280             if (_Children[child] == NULL)
00281             {
00282                 childType = NoChild;
00283                 f.serial(childType);
00284             }
00285             else
00286             {
00287                 childType = uint8(_Children[child]->isLeaf() ? LeafChild : BranchChild);
00288                 f.serial(childType);
00289                 _Children[child]->serial(f);
00290             }
00291         }
00292     }
00293 }
00294 
00295 bool    NLPACS::CSurfaceQuadTree::check() const
00296 {
00297     if (_Root != NULL)
00298         return _Root->check();
00299     return true;
00300 }
00301 
00302 const NLPACS::CQuadLeaf *NLPACS::CSurfaceQuadTree::getLeaf(const CVector &v) const
00303 {
00304     CVector pos = CVector(v.x, v.y, 0.0f);
00305     if (_Root == NULL || !_BBox.include(pos))
00306         return NULL;
00307 
00308     const IQuadNode *node = _Root;
00309 
00310     while (node != NULL && !node->isLeaf())
00311     {
00312         nlassert(node->getBBox().include(pos));
00313         uint    child;
00314 
00315         if (pos.x > node->_XCenter)
00316             child = ((pos.y > node->_YCenter) ? 2 : 1);
00317         else
00318             child = ((pos.y > node->_YCenter) ? 3 : 0);
00319 
00320         node = node->getChild(child);
00321     }
00322 
00323     return (const CQuadLeaf *)node;
00324 }
00325 
00326 
00327 void    NLPACS::CSurfaceQuadTree::serial(NLMISC::IStream &f)
00328 {
00329     /*
00330     Version 0:
00331         - base version.
00332     */
00333     (void)f.serialVersion(0);
00334 
00335     uint8   childType = 0;
00336     f.serial(_MaxThickness);
00337     f.serial(_MaxLevel);
00338     f.serial(_BBox);
00339     if (f.isReading())
00340     {
00341         CQuadLeaf   *leaf;
00342         CQuadBranch *branch;
00343 
00344         f.serial(childType);
00345         switch (childType)
00346         {
00347         case CQuadBranch::NoChild:
00348             _Root = NULL;
00349             break;
00350         case CQuadBranch::LeafChild:
00351             leaf = new CQuadLeaf();
00352             _Root = leaf;
00353             leaf->serial(f);
00354             break;
00355         case CQuadBranch::BranchChild:
00356             branch = new CQuadBranch();
00357             _Root = branch;
00358             branch->serial(f);
00359             break;
00360         default:
00361             nlerror("While serializing (read) CQuadBranch: unknown child type");
00362             break;
00363         }
00364     }
00365     else
00366     {
00367         if (_Root == NULL)
00368         {
00369             childType = CQuadBranch::NoChild;
00370             f.serial(childType);
00371         }
00372         else
00373         {
00374             childType = uint8(_Root->isLeaf() ? CQuadBranch::LeafChild : CQuadBranch::BranchChild);
00375             f.serial(childType);
00376             _Root->serial(f);
00377         }
00378     }
00379 }
00380 
00381 //
00382 float   NLPACS::CSurfaceQuadTree::getInterpZ(const CVector &v) const
00383 {
00384     // first get final leaf for position
00385     CVector pos = CVector(v.x, v.y, 0.0f);
00386     if (_Root == NULL || !_BBox.include(pos))
00387         return v.z; // return unmodified z
00388 
00389     const IQuadNode             *node = _Root;
00390     vector<uint>                children;
00391     vector<const IQuadNode*>    nodes;
00392 
00393     while (node != NULL && !node->isLeaf())
00394     {
00395         nodes.push_back(node);
00396 
00397         nlassert(node->getBBox().include(pos));
00398         uint    child;
00399 
00400         if (pos.x > node->_XCenter)
00401             child = ((pos.y > node->_YCenter) ? 2 : 1);
00402         else
00403             child = ((pos.y > node->_YCenter) ? 3 : 0);
00404 
00405         children.push_back(child);
00406 
00407         node = node->getChild(child);
00408     }
00409 
00410     if (node == NULL)
00411         return v.z; // return unmodified z
00412 
00413     nodes.push_back(node);
00414 
00415     vector<const CQuadLeaf*>    leaves;
00416     vector<const IQuadNode*>    explore;
00417 
00418     leaves.push_back((const CQuadLeaf*)node);
00419 
00420     // for each side of the leaf, find neighbor leaves
00421     uint    side;
00422     for (side=0; side<4; ++side)
00423     {
00424         static const sint   ct[4][4] = { {-1, 1, 3,-1}, {-1,-1, 2, 0}, { 1,-1,-1, 3}, { 0, 2,-1,-1} };  // child table
00425         static const sint   nt[4][4] = { { 3, 1, 3, 1}, { 2, 0, 2, 0}, { 1, 3, 1, 3}, { 0, 2, 0, 2} };  // neighbor table
00426 
00427         sint    nlev = nodes.size()-1;
00428         sint    child = -1;
00429 
00430         while (nlev > 0)
00431         {
00432             child = ct[children[nlev-1]][side];
00433 
00434             if (child >= 0)
00435                 break;
00436 
00437             --nlev;
00438         }
00439 
00440         // neighbor not found in root, leave
00441         if (nlev == 0)
00442             continue;
00443 
00444         // get father
00445         node = nodes[nlev-1];
00446 
00447         while (nlev < (sint)nodes.size() && node!=NULL && !node->isLeaf())
00448         {
00449             child = nt[children[nlev-1]][side];
00450             node = node->getChild(child);
00451 
00452             ++nlev;
00453         }
00454 
00455         if (node == NULL)
00456             continue;
00457 
00458         if (node->isLeaf())
00459         {
00460             leaves.push_back((const CQuadLeaf*)node);
00461         }
00462         else
00463         {
00464             explore.push_back(node);
00465 
00466             while (!explore.empty())
00467             {
00468                 node = explore.back();
00469                 explore.pop_back();
00470 
00471                 if (node == NULL)
00472                     continue;
00473 
00474                 if (node->isLeaf())
00475                     leaves.push_back((const CQuadLeaf*)node);
00476                 else
00477                 {
00478                     explore.push_back(node->getChild((side+2)&3));
00479                     explore.push_back(node->getChild((side+3)&3));
00480                 }
00481             }
00482         }
00483     }
00484 
00485     uint            i;
00486     float           di, wi;
00487     float           sum = 0.0;
00488     float           interpZ = 0.0;
00489 
00490     for (i=0; i<leaves.size(); ++i)
00491     {
00492         di = (float)sqrt(sqr(v.x-leaves[i]->_XCenter)+sqr(v.y-leaves[i]->_YCenter))*(float)pow(1.5, leaves[i]->_Level);
00493         wi = 1.0f/di;
00494         sum += wi;
00495         interpZ += (leaves[i]->getMinHeight()+leaves[i]->getMaxHeight())*0.5f*wi;
00496     }
00497 
00498     return interpZ / sum;
00499 }

Generated on Thu Jan 7 08:26:36 2010 for NeL by  doxygen 1.6.1