surface_quad.cpp
Go to the documentation of this file.00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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 ¢er, 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
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
00331
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
00385 CVector pos = CVector(v.x, v.y, 0.0f);
00386 if (_Root == NULL || !_BBox.include(pos))
00387 return v.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;
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
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} };
00425 static const sint nt[4][4] = { { 3, 1, 3, 1}, { 2, 0, 2, 0}, { 1, 3, 1, 3}, { 0, 2, 0, 2} };
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
00441 if (nlev == 0)
00442 continue;
00443
00444
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 }