Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / pacs / local_retriever.cpp
blob9a73e8b2832b8f7ef5c4988bb5a78cff3a893618
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2015-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdpacs.h"
22 #include <sstream>
24 #include "nel/misc/plane.h"
26 #include "nel/pacs/local_retriever.h"
27 #include "nel/pacs/collision_desc.h"
28 #include "nel/pacs/retriever_instance.h"
30 #include "nel/misc/hierarchical_timer.h"
33 using namespace std;
34 using namespace NLMISC;
36 /// The max distance allowed to merge tips.
37 const float NLPACS::CLocalRetriever::_TipThreshold = 0.1f;
38 const float NLPACS::CLocalRetriever::_EdgeTipThreshold = 0.1f;
40 /// The threshold distance to insure a position belongs to a surface
41 const float InsurePositionThreshold = 2.0e-2f;
43 //static float hybrid2dNorm(const CVector &v)
44 //{
45 // return (float)(sqrt(sqr(v.x)+sqr(v.y))+fabs(v.z)*0.1);
46 //}
52 NLPACS::CLocalRetriever::CLocalRetriever()
54 _Type = Landscape;
55 _Loaded = false;
56 LoadCheckFlag = false;
60 void NLPACS::CLocalRetriever::clear()
62 contReset(_OrderedChains);
63 contReset(_FullOrderedChains);
64 contReset(_Chains);
65 contReset(_Surfaces);
66 contReset(__Tips);
67 contReset(_BorderChains);
68 uint i;
69 for (i=0; i<NumMaxCreatureModels; ++i)
70 contReset(_Topologies[i]);
71 _ChainQuad.clear();
72 _ExteriorMesh.clear();
73 contReset(_InteriorVertices);
74 contReset(_InteriorFaces);
75 _FaceGrid.clear();
76 _Id.resize(0);
77 _Loaded = false;
78 LoadCheckFlag = false;
82 const CVector &NLPACS::CLocalRetriever::getStartVector(uint32 chain) const
84 const COrderedChain3f &ochain = _FullOrderedChains[_Chains[chain].getSubChains().front()];
85 return (ochain.isForward()) ? ochain.getVertices().front() : ochain.getVertices().back();
88 const CVector &NLPACS::CLocalRetriever::getStopVector(uint32 chain) const
90 const COrderedChain3f &ochain = _FullOrderedChains[_Chains[chain].getSubChains().back()];
91 return (ochain.isForward()) ? ochain.getVertices().back() : ochain.getVertices().front();
97 const CVector &NLPACS::CLocalRetriever::getStartVector(uint32 chain, sint32 surface) const
99 bool onLeft = _Chains[chain].getLeft() == surface;
100 const COrderedChain3f &ochain = onLeft ? _FullOrderedChains[_Chains[chain].getSubChains().front()] :
101 _FullOrderedChains[_Chains[chain].getSubChains().back()];
103 if (ochain.isForward() == onLeft)
104 return ochain.getVertices().front();
105 else
106 return ochain.getVertices().back();
109 const CVector &NLPACS::CLocalRetriever::getStopVector(uint32 chain, sint32 surface) const
111 bool onLeft = _Chains[chain].getLeft() == surface;
112 const COrderedChain3f &ochain = onLeft ? _FullOrderedChains[_Chains[chain].getSubChains().back()] :
113 _FullOrderedChains[_Chains[chain].getSubChains().front()];
115 if (ochain.isForward() == onLeft)
116 return ochain.getVertices().back();
117 else
118 return ochain.getVertices().front();
124 uint16 NLPACS::CLocalRetriever::getStartTip(uint32 chain, sint32 surface) const
126 return (_Chains[chain].getLeft() == surface) ? _Chains[chain].getStartTip() : _Chains[chain].getStopTip();
129 uint16 NLPACS::CLocalRetriever::getStopTip(uint32 chain, sint32 surface) const
131 return (_Chains[chain].getLeft() == surface) ? _Chains[chain].getStopTip() : _Chains[chain].getStartTip();
138 void NLPACS::CLocalRetriever::setStartTip(uint32 chain, sint32 surface, uint16 startTip)
140 if (_Chains[chain].getLeft() == surface)
141 _Chains[chain]._StartTip = startTip;
142 else
143 _Chains[chain]._StopTip = startTip;
146 void NLPACS::CLocalRetriever::setStopTip(uint32 chain, sint32 surface, uint16 stopTip)
148 if (_Chains[chain].getLeft() == surface)
149 _Chains[chain]._StopTip = stopTip;
150 else
151 _Chains[chain]._StartTip = stopTip;
157 uint32 NLPACS::CLocalRetriever::getPreviousChain(uint32 chain, sint32 surface) const
159 uint loop;
160 uint loopIndex;
162 if (_Chains[chain].getLeft() == surface)
164 loop = _Chains[chain]._LeftLoop;
165 loopIndex = _Chains[chain]._LeftLoopIndex;
167 else
169 loop = _Chains[chain]._RightLoop;
170 loopIndex = _Chains[chain]._RightLoopIndex;
173 const CRetrievableSurface &surf = _Surfaces[surface];
174 const CRetrievableSurface::TLoop &sLoop = surf._Loops[loop];
175 return surf._Chains[sLoop[(loopIndex+sLoop.size()-1)%sLoop.size()]].Chain;
178 uint32 NLPACS::CLocalRetriever::getNextChain(uint32 chain, sint32 surface) const
180 uint loop;
181 uint loopIndex;
183 if (_Chains[chain].getLeft() == surface)
185 loop = _Chains[chain]._LeftLoop;
186 loopIndex = _Chains[chain]._LeftLoopIndex;
188 else
190 loop = _Chains[chain]._RightLoop;
191 loopIndex = _Chains[chain]._RightLoopIndex;
194 const CRetrievableSurface &surf = _Surfaces[surface];
195 const CRetrievableSurface::TLoop &sLoop = surf._Loops[loop];
196 return surf._Chains[sLoop[(loopIndex+1)%sLoop.size()]].Chain;
202 void NLPACS::CLocalRetriever::unify()
205 uint i, j;
207 for (i=0; i<_Chains.size(); ++i)
208 _Chains[i].unify(_OrderedChains);
210 for (i=0; i<_Tips.size(); ++i)
212 NLPACS::CLocalRetriever::CTip &tip = _Tips[i];
213 CVector2s ptip = tip.Point;
215 for (j=0; j<tip.Chains.size(); ++j)
217 if (tip.Chains[j].Start)
219 if (_Chains[tip.Chains[j].Chain].getStartVector(_OrderedChains) != ptip)
220 nlwarning("chain %d is not stuck to tip %d", tip.Chains[j].Chain, i);
221 _Chains[tip.Chains[j].Chain].setStartVector(ptip, _OrderedChains);
223 else
225 if (_Chains[tip.Chains[j].Chain].getStopVector(_OrderedChains) != ptip)
226 nlwarning("chain %d is not stuck to tip %d", tip.Chains[j].Chain, i);
227 _Chains[tip.Chains[j].Chain].setStopVector(ptip, _OrderedChains);
232 _FullOrderedChains.resize(_OrderedChains.size());
233 for (i=0; i<_OrderedChains.size(); ++i)
234 _FullOrderedChains[i].unpack(_OrderedChains[i]);
244 void NLPACS::CLocalRetriever::dumpSurface(uint surf, const CVector &vect) const
246 const CRetrievableSurface &surface = _Surfaces[surf];
248 nlinfo("dump surf %d", surf);
249 nlinfo("%d chains, %d loops", surface._Chains.size(), surface._Loops.size());
251 uint i, j, k;
253 for (i=0; i<surface._Chains.size(); ++i)
255 uint chainId = surface._Chains[i].Chain;
256 const CChain &chain = _Chains[chainId];
257 nlinfo("-- chain %d[%d]: %d sub left=%d right=%d start=%d stop=%d", i, chainId, chain.getSubChains().size(), chain.getLeft(), chain.getRight(), chain.getStartTip(), chain.getStopTip());
259 for (j=0; j<chain.getSubChains().size(); ++j)
261 const COrderedChain3f &ochain = _FullOrderedChains[chain.getSubChain(j)];
262 const COrderedChain &ochains = _OrderedChains[chain.getSubChain(j)];
263 nlinfo(" subchain %d[%d]: fwd=%d parent=%d idx=%d", j, chain.getSubChain(j), ochain.isForward(), ochain.getParentId(), ochain.getIndexInParent());
264 for (k=0; k<ochain.getVertices().size(); ++k)
265 nlinfo(" v[%d]=(%.3f,%.3f,%.3f) (%d,%d)", k, ochain.getVertices()[k].x+vect.x, ochain.getVertices()[k].y+vect.y, ochain.getVertices()[k].z+vect.z, ochains.getVertices()[k].x, ochains.getVertices()[k].y);
270 for (i=0; i<surface._Loops.size(); ++i)
272 const CRetrievableSurface::TLoop &loop = surface._Loops[i];
273 nlinfo("-- loop %d: %d chains length=%.2f", i, loop.size(), loop.Length);
274 char wbuffer[256];
275 stringstream ss;
276 sprintf(wbuffer, " chains:");
277 ss << wbuffer;
278 for (j=0; j<loop.size(); ++j)
280 sprintf(wbuffer, " %d[%d]", loop[j], surface._Chains[loop[j]].Chain);
281 ss << wbuffer;
283 nlinfo("%s", ss.str().c_str());
288 float NLPACS::CLocalRetriever::distanceToBorder(const ULocalPosition &pos) const
290 if (!isLoaded())
291 return 0.0f;
293 const CRetrievableSurface &surf = _Surfaces[pos.Surface];
294 uint i, j;
295 float minDist = 1.0e10f, dist;
297 for (i=0; i<surf._Chains.size(); ++i)
299 const CChain &chain = _Chains[surf._Chains[i].Chain];
300 for (j=0; j<chain.getSubChains().size(); ++j)
302 dist = _OrderedChains[chain.getSubChain(j)].distance(pos.Estimation);
303 if (dist < minDist)
305 minDist = dist;
310 return minDist;
317 sint32 NLPACS::CLocalRetriever::addSurface(uint8 normalq, uint8 orientationq,
318 uint8 mat, uint8 charact, uint8 level,
319 bool isUnderWater, float waterHeight,
320 bool clusterHint,
321 const CVector &center,
322 const NLPACS::CSurfaceQuadTree &quad,
323 sint8 quantHeight)
325 // creates a new surface...
326 sint32 newId = (sint32)_Surfaces.size();
327 _Surfaces.resize(newId+1);
328 CRetrievableSurface &surf = _Surfaces.back();
330 // ... and fills it
331 surf._NormalQuanta = normalq;
332 surf._OrientationQuanta = orientationq;
333 surf._Material = mat;
334 surf._Character = charact;
335 surf._Level = level;
336 surf._Quad = quad;
337 surf._Center = center;
338 surf._QuantHeight = quantHeight;
340 // WARNING!! MODIFY THESE IF QUANTAS VALUES CHANGE !!
341 surf._IsFloor = (surf._NormalQuanta <= 1);
342 surf._IsCeiling = (surf._NormalQuanta >= 3);
344 surf._Flags = 0;
345 surf._Flags |= (surf._IsFloor) ? (1<<CRetrievableSurface::IsFloorBit) : 0;
346 surf._Flags |= (surf._IsCeiling) ? (1<<CRetrievableSurface::IsCeilingBit) : 0;
347 surf._Flags |= (!surf._IsFloor && !surf._IsCeiling) ? (1<<CRetrievableSurface::IsSlantBit) : 0;
348 surf._Flags |= clusterHint ? (1<<CRetrievableSurface::ClusterHintBit) : 0;
350 surf._Flags |= (isUnderWater) ? (1<<CRetrievableSurface::IsUnderWaterBit) : 0;
351 surf._WaterHeight = waterHeight;
353 surf._Flags |= ((0xffffffff<<(CRetrievableSurface::NormalQuantasStartBit)) & CRetrievableSurface::NormalQuantasBitMask);
355 return newId;
358 sint32 NLPACS::CLocalRetriever::addChain(const vector<CVector> &verts,
359 sint32 left, sint32 right)
361 vector<CVector> vertices = verts;
362 uint i;
364 if (vertices.size() < 2)
366 nlwarning("in NLPACS::CLocalRetriever::addChain()");
367 nlwarning("The chain has less than 2 vertices");
368 return -1;
371 // Remove doubled vertices due to CVector2s snapping
372 vector<CVector2s> converts;
374 for (i=0; i<vertices.size(); ++i)
375 converts.push_back(CVector2s(vertices[i]));
377 vector<CVector2s>::iterator next2s = converts.begin(), it2s, prev2s;
378 prev2s = next2s; ++next2s;
379 it2s = next2s; ++next2s;
381 vector<CVector>::iterator it3f = vertices.begin();
382 CVector prev3f = *it3f;
383 ++it3f;
386 for (; it2s != converts.end() && next2s != converts.end(); )
388 // if the next point is equal to the previous
389 if (*it2s == *prev2s || *it2s == *next2s)
391 // then remove the next point
392 it2s = converts.erase(it2s);
393 it3f = vertices.erase(it3f);
395 prev2s = it2s;
396 --prev2s;
397 next2s = it2s;
398 ++next2s;
400 else
402 // else remember the next point, and step to the next...
403 ++prev2s;
404 ++it2s;
405 ++next2s;
406 ++it3f;
407 prev3f = *it3f;
411 if (vertices.size() < 2)
413 nlwarning("in NLPACS::CLocalRetriever::addChain()");
414 nlwarning("The chain was snapped to a single point");
415 return -1;
418 sint32 newId = (sint32)_Chains.size();
419 _Chains.resize(newId+1);
420 CChain &chain = _Chains.back();
422 if (left>(sint)_Surfaces.size())
423 nlerror ("left surface id MUST be id<%d (id=%d)", _Surfaces.size(), left);
424 if (right>(sint)_Surfaces.size())
425 nlerror ("right surface id MUST be id<%d (id=%d)", _Surfaces.size(), right);
427 // checks if we can build the chain.
428 if (newId > 65535)
429 nlerror("in NLPACS::CLocalRetriever::addChain(): reached the maximum number of chains");
431 CRetrievableSurface *leftSurface = (left>=0) ? &(_Surfaces[left]) : NULL;
432 CRetrievableSurface *rightSurface = (right>=0) ? &(_Surfaces[right]) : NULL;
434 // adds the chain and the link to the surface links vector.
435 if (leftSurface != NULL)
436 leftSurface->_Chains.push_back(CRetrievableSurface::CSurfaceLink(newId, right));
437 if (rightSurface != NULL)
438 rightSurface->_Chains.push_back(CRetrievableSurface::CSurfaceLink(newId, left));
440 chain._StartTip = 0xffff;
441 chain._StopTip = 0xffff;
443 // make the chain and its subchains.
444 vector<uint> empty;
445 chain.make(vertices, left, right, _OrderedChains, (uint16)newId, _FullOrderedChains, empty);
447 return newId;
453 void NLPACS::CLocalRetriever::computeLoopsAndTips()
455 // for each surface,
456 // examine each chain tip to match another tip inside the surface tips
457 // if there is no matching tip, then creates a new one
459 uint i, j;
461 for (i=0; i<_Surfaces.size(); ++i)
463 CRetrievableSurface &surface = _Surfaces[i];
465 vector<bool> chainFlags;
466 chainFlags.resize(surface._Chains.size());
467 for (j=0; j<chainFlags.size(); ++j)
468 chainFlags[j] = false;
470 uint totalAdded = 0;
472 for(;;)
474 for (j=0; j<chainFlags.size() && chainFlags[j]; ++j)
477 if (j == chainFlags.size())
478 break;
480 uint32 loopId = (uint32)surface._Loops.size();
481 surface._Loops.push_back(CRetrievableSurface::TLoop());
482 CRetrievableSurface::TLoop &loop = surface._Loops.back();
484 CVector loopStart = getStartVector(surface._Chains[j].Chain, i);
485 CVector currentEnd = getStopVector(surface._Chains[j].Chain, i);
486 _Chains[surface._Chains[j].Chain].setLoopIndexes(i, loopId, (uint)loop.size());
487 loop.push_back(uint16(j));
488 chainFlags[j] = true;
490 float loopCloseDistance;
492 for(;;)
494 // loopCloseDistance = hybrid2dNorm(loopStart-currentEnd);
495 loopCloseDistance = (loopStart-currentEnd).norm();
497 // choose the best matching start vector
498 sint bestChain = -1;
499 float best = 1.0e10f;
500 CVector thisStart;
501 for (j=0; j<chainFlags.size(); ++j)
503 if (chainFlags[j])
504 continue;
505 thisStart = getStartVector(surface._Chains[j].Chain, i);
506 // float d = hybrid2dNorm(thisStart-currentEnd);
507 float d = (thisStart-currentEnd).norm();
508 if (d < best)
510 best = d;
511 bestChain = j;
515 if ((bestChain == -1 || best > 4.0e-2f)&& loopCloseDistance > 4.0e-2f)
517 nlwarning("in NLPACS::CLocalRetriever::computeTips()");
519 dumpSurface(i);
521 for (j=0; j<surface._Chains.size(); ++j)
523 CVector start = getStartVector(surface._Chains[j].Chain, i);
524 CVector end = getStopVector(surface._Chains[j].Chain, i);
525 nlinfo("surf=%d chain=%d", i, surface._Chains[j].Chain);
526 nlinfo("start=(%f,%f,%f)", start.x, start.y, start.z);
527 nlinfo("end=(%f,%f,%f)", end.x, end.y, end.z);
530 nlwarning("bestChain=%d best=%f", bestChain, best);
531 nlwarning("loopCloseDistance=%f", loopCloseDistance);
532 nlerror("Couldn't close loop on surface=%d", i);
534 else if ((best > 1.0e0f && loopCloseDistance < 3.0e-2f) ||
535 loopCloseDistance < 1.0e-3f)
537 break;
540 currentEnd = getStopVector(surface._Chains[bestChain].Chain, i);
541 _Chains[surface._Chains[bestChain].Chain].setLoopIndexes(i, loopId, (uint)loop.size());
542 loop.push_back(uint16(bestChain));
543 chainFlags[bestChain] = true;
544 ++totalAdded;
549 dumpSurface(9);
550 dumpSurface(10);
552 for (i=0; i<_Chains.size(); ++i)
554 if (i == 127)
555 nlinfo("");
557 uint whichTip;
558 // for both tips (start and stop)
559 for (whichTip=0; whichTip<=1; ++whichTip)
561 // get the tip id
562 uint thisTip = (whichTip) ? _Chains[i].getStopTip() : _Chains[i].getStartTip();
564 if (thisTip != 0xffff && thisTip >= _Tips.size())
566 nlwarning("in NLPACS::CLocalRetriever::computeLoopsAndTips()");
567 nlerror("checked a tip that doesn't exist on chain %d (tipId=%d)", i, thisTip);
570 // if it is unaffected yet creates an new tip and affect it to the common chains
571 if (thisTip == 0xffff)
573 uint turn;
574 uint tipId = _Tips.size();
576 if (tipId == 62)
577 nlinfo("");
579 _Tips.resize(tipId+1);
580 CTip &tip = _Tips[tipId];
581 tip.Point = (whichTip) ? getStopVector(i) : getStartVector(i);
583 for (turn=0; turn<=1; ++turn)
585 uint chain = i;
588 if (whichTip)
589 _Chains[chain]._StopTip = tipId;
590 else
591 _Chains[chain]._StartTip = tipId;
593 sint32 surf = (!turn && !whichTip || turn && whichTip) ? _Chains[chain].getLeft() : _Chains[chain].getRight();
595 while (surf >= 0)
598 CChain &nextChain = (turn) ? _Chains[chain = getNextChain(chain, surf)] : _Chains[chain = getPreviousChain(chain, surf)];
599 bool isForward = (nextChain.getLeft() == surf); // tells if the left surf is the current surf
600 bool selectTip = isForward && !turn || !isForward && turn;
601 uint16 &tipRef = selectTip ? nextChain._StopTip : nextChain._StartTip;
602 surf = (isForward) ? nextChain.getRight() : nextChain.getLeft();
604 if (tipRef != 0xffff && tipRef != tipId)
606 nlwarning("in NLPACS::CLocalRetriever::computeLoopsAndTips()");
607 nlerror("Trying to setup a already created tip (tipId=%d, previous=%d)", tipId, tipRef);
609 else if (tipRef != 0xffff)
611 break;
614 tipRef = tipId;
621 for (i=0; i<_Chains.size(); ++i)
623 uint startTip = _Chains[i].getStartTip(),
624 stopTip = _Chains[i].getStopTip();
627 // if (_Chains[i].getEdge() >= 0 && startTip == stopTip)
628 // {
629 // nlwarning("NLPACS::CLocalRetriever::computeLoopsAndTips(): chain %d on edge %d has same StartTip and StopTip", i, _Chains[i].getEdge(), startTip, stopTip);
630 // }
633 _Tips[startTip].Chains.push_back(CTip::CChainTip(i, true));
634 _Tips[stopTip].Chains.push_back(CTip::CChainTip(i, false));
637 for (i=0; i<_Surfaces.size(); ++i)
639 for (j=0; j<_Surfaces[i]._Loops.size(); ++j)
641 _Surfaces[i]._Loops[j].Length = 0.0f;
642 uint k;
644 for (k=0; k<_Surfaces[i]._Loops[j].size(); ++k)
645 _Surfaces[i]._Loops[j].Length += _Chains[_Surfaces[i]._Chains[_Surfaces[i]._Loops[j][k]].Chain].getLength();
652 void NLPACS::CLocalRetriever::buildSurfacePolygons(uint32 surface, list<CPolygon> &polygons) const
654 const CRetrievableSurface &surf = _Surfaces[surface];
656 uint i, j, k, l;
658 for (i=0; i<surf._Loops.size(); ++i)
660 polygons.push_back(CPolygon());
661 CPolygon &poly = polygons.back();
663 for (j=0; j<surf._Loops[i].size(); ++j)
665 const CChain &chain = _Chains[surf._Loops[i][j]];
666 bool chainforward = ((uint32)chain._Left == surface);
668 if (chainforward)
670 for (k=0; k<chain._SubChains.size(); ++k)
672 const COrderedChain &ochain = _OrderedChains[chain._SubChains[k]];
673 bool ochainforward = ochain.isForward();
675 if (ochainforward)
677 for (l=0; l<ochain.getVertices().size()-1; ++l)
678 poly.Vertices.push_back(ochain[l].unpack3f());
680 else
682 for (l=(uint)ochain.getVertices().size()-1; l>0; --l)
683 poly.Vertices.push_back(ochain[l].unpack3f());
687 else
689 for (k=(uint)chain._SubChains.size(); (sint)k>0; --k)
691 const COrderedChain &ochain = _OrderedChains[chain._SubChains[k]];
692 bool ochainforward = ochain.isForward();
694 if (ochainforward)
696 for (l=(uint)ochain.getVertices().size()-1; (sint)l>0; --l)
697 poly.Vertices.push_back(ochain[l].unpack3f());
699 else
701 for (l=0; l<ochain.getVertices().size()-1; ++l)
702 poly.Vertices.push_back(ochain[l].unpack3f());
711 void NLPACS::CLocalRetriever::build3dSurfacePolygons(uint32 surface, list<CPolygon> &polygons) const
713 const CRetrievableSurface &surf = _Surfaces[surface];
715 uint i, j, k, l;
717 for (i=0; i<surf._Loops.size(); ++i)
719 polygons.push_back(CPolygon());
720 CPolygon &poly = polygons.back();
722 for (j=0; j<surf._Loops[i].size(); ++j)
724 const CRetrievableSurface::TLoop &loop = surf._Loops[i];
725 const CChain &chain = _Chains[surf._Chains[loop[j]].Chain];
726 bool chainforward = ((uint32)chain._Left == surface);
728 if (chainforward)
730 for (k=0; k<chain._SubChains.size(); ++k)
732 const COrderedChain3f &ochain = _FullOrderedChains[chain._SubChains[k]];
733 bool ochainforward = ochain.isForward();
735 if (ochainforward)
737 for (l=0; l<ochain.getVertices().size()-1; ++l)
738 poly.Vertices.push_back(ochain[l]);
740 else
742 for (l=(uint)ochain.getVertices().size()-1; l>0; --l)
743 poly.Vertices.push_back(ochain[l]);
747 else
749 for (k=(uint)chain._SubChains.size()-1; (sint)k>=0; --k)
751 const COrderedChain3f &ochain = _FullOrderedChains[chain._SubChains[k]];
752 bool ochainforward = ochain.isForward();
754 if (ochainforward)
756 for (l=(uint)ochain.getVertices().size()-1; (sint)l>0; --l)
757 poly.Vertices.push_back(ochain[l]);
759 else
761 for (l=0; l<ochain.getVertices().size()-1; ++l)
762 poly.Vertices.push_back(ochain[l]);
771 // not implemented...
772 void NLPACS::CLocalRetriever::sortTips()
779 void NLPACS::CLocalRetriever::findBorderChains()
781 uint chain;
783 // for each chain, if it belongs to an edge of the
784 // local retriever, then adds it to the _BorderChains.
785 for (chain=0; chain<_Chains.size(); ++chain)
786 if (_Chains[chain].isBorderChain())
788 sint32 index = (sint32)_BorderChains.size();
789 _BorderChains.push_back(uint16(chain));
790 _Chains[chain].setBorderChainIndex(index);
794 void NLPACS::CLocalRetriever::updateChainIds()
796 uint surf, link;
798 for (surf=0; surf<_Surfaces.size(); ++surf)
800 CRetrievableSurface &surface = _Surfaces[surf];
802 for (link=0; link<surface._Chains.size(); ++link)
804 sint32 chain = surface._Chains[link].Chain;
806 if (_Chains[chain]._Left == (sint32)surf)
807 surface._Chains[link].Surface = _Chains[chain]._Right;
808 else if (_Chains[chain]._Right == (sint32)surf)
809 surface._Chains[link].Surface = _Chains[chain]._Left;
810 else
812 nlwarning("in NLPACS::CLocalRetriever::updateEdgesOnSurfaces()");
813 nlerror("Can't find back point to surface %d on chain %d", surf, chain);
819 void NLPACS::CLocalRetriever::computeTopologies()
821 //nlinfo("compute topologies");
823 // Find topologies out...
824 uint character;
825 for (character=0; character<NumCreatureModels; ++character)
827 // for each type of creature, flood fill surfaces...
828 sint32 surface;
829 uint topology = 0;
831 for (surface=0; surface<(sint)_Surfaces.size(); ++surface)
833 if (_Surfaces[surface]._Topologies[character] == -1 &&
834 _Surfaces[surface]._Character == character)
836 vector<sint32> surfacesStack;
837 surfacesStack.push_back(surface);
839 while (!surfacesStack.empty())
841 CRetrievableSurface &current = _Surfaces[surfacesStack.back()];
842 surfacesStack.pop_back();
843 current._Topologies[character] = topology;
845 uint i;
846 for (i=0; i<current._Chains.size(); ++i)
848 CChain &chain = _Chains[current._Chains[i].Chain];
849 sint32 link = (chain.getLeft() == surface) ? chain.getRight() : chain.getLeft();
850 if (link>=0 && link<(sint)_Surfaces.size() &&
851 _Surfaces[link]._Topologies[character] == -1 &&
852 _Surfaces[link]._Character >= character)
854 surfacesStack.push_back(link);
855 _Surfaces[link]._Topologies[character] = topology;
860 ++topology;
864 _Topologies[character].resize(topology);
865 //nlinfo("generated %d topologies for character %d", topology, character);
868 uint surface;
869 for (surface=0; surface<_Surfaces.size(); ++surface)
871 CRetrievableSurface &current = _Surfaces[surface];
873 for (character=0; character<NumCreatureModels; ++character)
874 if (current._Topologies[character] >= 0)
875 _Topologies[character][current._Topologies[character]].push_back(surface);
879 void NLPACS::CLocalRetriever::translate(const NLMISC::CVector &translation)
881 uint i;
882 for (i=0; i<_OrderedChains.size(); ++i)
883 _OrderedChains[i].translate(translation);
884 for (i=0; i<_Surfaces.size(); ++i)
885 _Surfaces[i].translate(translation);
887 for (i=0; i<_Tips.size(); ++i)
888 _Tips[i].translate(translation);
892 void NLPACS::CLocalRetriever::serial(NLMISC::IStream &f)
895 Version 0:
896 - base version (with collision info).
897 Version 1:
898 - interior vertices and faces, for interior ground snapping
899 Version 2:
900 - face grid added.
901 Version 3:
902 - identifier added.
903 Version 4:
904 - topologies no more in stream (obsolete)
906 sint ver= f.serialVersion(4);
908 if (ver < 4)
909 throw EOlderStream();
911 uint i;
912 f.serialCont(_Chains);
913 f.serialCont(_OrderedChains);
914 f.serialCont(_FullOrderedChains);
915 f.serialCont(_Surfaces);
916 f.serialCont(__Tips);
917 f.serialCont(_BorderChains);
918 if (ver < 4)
920 for (i=0; i<NumMaxCreatureModels; ++i)
921 f.serialCont(_Topologies[i]);
923 f.serial(_ChainQuad);
924 f.serial(_BBox);
925 f.serialEnum(_Type);
926 f.serial(_ExteriorMesh);
928 // a fix for old versions (with wrong _Type value)
929 if (_Type != CLocalRetriever::Interior) _Type = CLocalRetriever::Landscape;
931 if (ver >= 1)
933 f.serialCont(_InteriorVertices);
934 f.serialCont(_InteriorFaces);
937 if (ver >= 2)
939 f.serial(_FaceGrid);
941 if (ver >= 3)
943 f.serial(_Id);
946 _Loaded = true;
947 LoadCheckFlag = false;
957 bool NLPACS::CLocalRetriever::insurePosition(NLPACS::ULocalPosition &local) const
959 if (!_Loaded)
960 return false;
962 if (local.Surface < 0 || local.Surface >= (sint)_Surfaces.size())
964 nlwarning("PACS: can't insure position to inexistant surface %d", local.Surface);
965 return false;
968 // the surface
969 const NLPACS::CRetrievableSurface &surface = _Surfaces[local.Surface];
971 uint i, j, k;
972 CVector2f M = CVector2f(local.Estimation);
973 bool moved = false;
975 // for each chain and each subchain of the surface,
976 // check if point is located on the good side of the border (and far enough to avoid accuracy issues)
977 for (i=0; i<surface.getChains().size(); ++i)
979 uint ichain = surface.getChain(i).Chain;
980 const NLPACS::CChain &chain = _Chains[ichain];
982 for (j=0; j<chain.getSubChains().size(); ++j)
984 uint iochain = chain.getSubChain(j);
985 const NLPACS::COrderedChain &ochain = _OrderedChains[iochain];
987 uint isAtLeft = ((chain.getLeft() == local.Surface) ? 1 : 0);
988 uint isForward = (ochain.isForward() ? 1 : 0);
989 bool shouldBeUpper = !((isAtLeft ^ isForward) != 0); // shouldBeAtLeft for vertical segment
991 for (k=0; (sint)k<(sint)(ochain.getVertices().size()-1); ++k)
993 CVector2f A = ochain[k].unpack();
994 CVector2f B = ochain[k+1].unpack();
995 CVector2f AB = B-A;
997 float lambda = ((M-A)*AB)/AB.sqrnorm();
999 if (lambda<0.0f || lambda>1.0f)
1000 continue;
1002 CVector2f n = (shouldBeUpper ? CVector2f(-AB.y, AB.x) : CVector2f(AB.y, -AB.x)).normed();
1003 float d = (M-A)*n;
1005 // if point is too close of the border or on the wrong side
1006 // move it far enough
1007 if (d < InsurePositionThreshold && d > -InsurePositionThreshold)
1009 M += (InsurePositionThreshold*1.1f-d)*n;
1010 moved = true;
1016 NLPACS::CRetrieverInstance::snapVector(M);
1018 local.Estimation.x = M.x;
1019 local.Estimation.y = M.y;
1022 float fx1024 = local.Estimation.x * 1024.0f;
1023 float fy1024 = local.Estimation.x * 1024.0f;
1024 sint32 ix1024 = (sint32)floor(fx1024);
1025 sint32 iy1024 = (sint32)floor(fy1024);
1027 nlassert ((float)ix1024 == fx1024);
1028 nlassert ((float)iy1024 == fy1024);
1031 return moved;
1035 bool NLPACS::CLocalRetriever::testPosition(NLPACS::ULocalPosition &local, CCollisionSurfaceTemp &cst) const
1037 if (!_Loaded)
1038 return false;
1040 if (local.Surface < 0 || local.Surface >= (sint)_Surfaces.size())
1042 nlwarning("PACS: can't test inexistant surface %d", local.Surface);
1043 return false;
1046 if (fabs(local.Estimation.x) >= 256.0 || fabs(local.Estimation.y) >= 256.0)
1047 return false;
1049 retrievePosition(local.Estimation, cst);
1051 bool result = (cst.SurfaceLUT[local.Surface].Counter == 2 || cst.SurfaceLUT[local.Surface].OnVerticalEdge);
1053 uint i;
1054 for (i=0; i<cst.PossibleSurfaces.size(); ++i)
1055 cst.SurfaceLUT[cst.PossibleSurfaces[i]].reset();
1057 return result;
1061 void NLPACS::CLocalRetriever::retrievePosition(CVector estimated, CCollisionSurfaceTemp &cst) const
1063 if (!_Loaded)
1064 return;
1066 CAABBox box;
1067 const double BorderThreshold = 2.0e-2f;
1068 box.setMinMax(CVector(estimated.x-(float)BorderThreshold, _BBox.getMin().y, 0.0f), CVector(estimated.x+(float)BorderThreshold, _BBox.getMax().y, 0.0f));
1069 uint numEdges = _ChainQuad.selectEdges(box, cst);
1071 uint ochain, i;
1072 CVector2s estim = CVector2s(estimated);
1074 cst.PossibleSurfaces.clear();
1076 // WARNING!!
1077 // cst.SurfaceLUT is assumed to be 0 filled !!
1079 //nldebug("estim=(%d,%d)", estim.x, estim.y);
1081 // for each ordered chain, checks if the estimated position is between the min and max.
1082 for (i=0; i<numEdges; ++i)
1084 ochain = cst.EdgeChainEntries[i].OChainId;
1086 const COrderedChain &sub = _OrderedChains[ochain];
1087 const CVector2s &min = sub.getMin(),
1088 &max = sub.getMax();
1090 // checks the position against the min and max of the chain
1091 if (estim.x < min.x || estim.x > max.x)
1092 continue;
1094 bool isUpper;
1095 bool isOnBorder = false;
1097 sint32 left = _Chains[sub.getParentId()].getLeft(),
1098 right = _Chains[sub.getParentId()].getRight();
1100 if (estim.y < min.y)
1102 if (estim.x == max.x)
1103 continue;
1104 isUpper = false;
1105 // nlinfo("Box: min(%d,%d) max(%d,%d) forward=%d left=%d right=%d upper=false", min.x, min.y, max.x, max.y, sub.isForward(), left, right);
1107 else if (estim.y > max.y)
1109 if (estim.x == max.x)
1110 continue;
1111 isUpper = true;
1112 // nlinfo("Box: min(%d,%d) max(%d,%d) forward=%d left=%d right=%d upper=true", min.x, min.y, max.x, max.y, sub.isForward(), left, right);
1114 else
1116 const vector<CVector2s> &vertices = sub.getVertices();
1117 uint start = 0, stop = (uint)vertices.size()-1;
1119 // then finds the smallest segment of the chain that includes the estimated position.
1120 while (stop-start > 1)
1122 uint mid = (start+stop)/2;
1124 if (vertices[mid].x > estim.x)
1125 stop = mid;
1126 else
1127 start = mid;
1130 // if a vertical edge
1131 if (vertices[start].x == vertices[stop].x)
1133 // look for maximal bounds
1134 while (start > 0 && vertices[start].x == vertices[start-1].x)
1135 --start;
1137 while (stop < vertices.size()-1 && vertices[stop].x == vertices[stop+1].x)
1138 ++stop;
1140 // if upper or lower the bounds, do nothing
1141 if ((estim.y > vertices[start].y && estim.y > vertices[stop].y) ||
1142 (estim.y < vertices[start].y && estim.y < vertices[stop].y))
1143 continue;
1145 isOnBorder = true;
1146 if (left >= 0)
1148 cst.SurfaceLUT[left].FoundCloseEdge = true;
1149 cst.SurfaceLUT[left].OnVerticalEdge = true;
1151 if (right >= 0)
1153 cst.SurfaceLUT[right].FoundCloseEdge = true;
1154 cst.SurfaceLUT[right].OnVerticalEdge = true;
1156 // nlinfo("Edge: start(%d,%d) stop(%d,%d) forward=%d left=%d right=%d border=true", vertices[start].x, vertices[start].y, vertices[stop].x, vertices[stop].y, sub.isForward(), left, right);
1157 continue;
1159 else if (vertices[stop].x == estim.x)
1161 // if (yes)
1162 continue;
1165 // and then checks if the estimated position is up or down the chain.
1167 // first trivial case (up both tips)
1168 if (estim.y > vertices[start].y && estim.y > vertices[stop].y)
1170 isUpper = true;
1171 // nlinfo("Edge: start(%d,%d) stop(%d,%d) forward=%d left=%d right=%d upper=true", vertices[start].x, vertices[start].y, vertices[stop].x, vertices[stop].y, sub.isForward(), left, right);
1173 // second trivial case (down both tips)
1174 else if (estim.y < vertices[start].y && estim.y < vertices[stop].y)
1176 isUpper = false;
1177 // nlinfo("Edge: start(%d,%d) stop(%d,%d) forward=%d left=%d right=%d upper=false", vertices[start].x, vertices[start].y, vertices[stop].x, vertices[stop].y, sub.isForward(), left, right);
1179 // full test...
1180 else
1182 const CVector2s &vstart = vertices[start],
1183 &vstop = vertices[stop];
1185 sint16 intersect = vstart.y + (vstop.y-vstart.y)*(estim.x-vstart.x)/(vstop.x-vstart.x);
1187 isUpper = estim.y > intersect;
1188 //isOnBorder = (fabs(estim.y - intersect)<BorderThreshold*Vector2sAccuracy);
1189 isOnBorder = (fabs((double)(estim.y - intersect))<(double)(BorderThreshold*Vector2sAccuracy));
1190 // nlinfo("Edge: start(%d,%d) stop(%d,%d) forward=%d left=%d right=%d upper=%s border=%s", vertices[start].x, vertices[start].y, vertices[stop].x, vertices[stop].y, sub.isForward(), left, right, isUpper ? "true":"false", isOnBorder ? "true":"false");
1194 if (isOnBorder)
1196 cst.incSurface(left);
1197 cst.incSurface(right);
1198 if (left >= 0) cst.SurfaceLUT[left].FoundCloseEdge = true;
1199 if (right >= 0) cst.SurfaceLUT[right].FoundCloseEdge = true;
1200 continue;
1203 // Depending on the chain is forward, up the position, increase/decrease the surface table...
1204 if (sub.isForward())
1206 if (isUpper)
1208 cst.incSurface(left);
1209 cst.decSurface(right);
1211 else
1213 cst.decSurface(left);
1214 cst.incSurface(right);
1217 else
1219 if (isUpper)
1221 cst.decSurface(left);
1222 cst.incSurface(right);
1224 else
1226 cst.incSurface(left);
1227 cst.decSurface(right);
1234 void NLPACS::CLocalRetriever::retrieveAccuratePosition(CVector2s estim, CCollisionSurfaceTemp &cst, bool &onBorder) const
1236 if (!_Loaded)
1237 return;
1239 CAABBox box;
1240 CVector estimated = estim.unpack3f();
1241 const double BorderThreshold = 2.0e-2f;
1242 box.setMinMax(CVector(estimated.x-(float)BorderThreshold, _BBox.getMin().y, 0.0f),
1243 CVector(estimated.x+(float)BorderThreshold, _BBox.getMax().y, 0.0f));
1244 uint numEdges = _ChainQuad.selectEdges(box, cst);
1246 uint ochain, i;
1248 onBorder = false;
1250 cst.PossibleSurfaces.clear();
1252 // WARNING!!
1253 // cst.SurfaceLUT is assumed to be 0 filled !!
1255 //nldebug("estim=(%d,%d)", estim.x, estim.y);
1257 // for each ordered chain, checks if the estimated position is between the min and max.
1258 for (i=0; i<numEdges; ++i)
1260 ochain = cst.EdgeChainEntries[i].OChainId;
1262 const COrderedChain &sub = _OrderedChains[ochain];
1263 const CVector2s &min = sub.getMin(),
1264 &max = sub.getMax();
1266 // checks the position against the min and max of the chain
1267 if (estim.x < min.x || estim.x > max.x)
1268 continue;
1270 bool isUpper;
1271 //bool isOnBorder = false;
1273 sint32 left = _Chains[sub.getParentId()].getLeft(),
1274 right = _Chains[sub.getParentId()].getRight();
1276 if (estim.y < min.y)
1278 if (estim.x == max.x)
1279 continue;
1280 isUpper = false;
1282 else if (estim.y > max.y)
1284 if (estim.x == max.x)
1285 continue;
1286 isUpper = true;
1288 else
1290 const vector<CVector2s> &vertices = sub.getVertices();
1291 uint start = 0, stop = (uint)vertices.size()-1;
1293 // then finds the smallest segment of the chain that includes the estimated position.
1294 while (stop-start > 1)
1296 uint mid = (start+stop)/2;
1298 if (vertices[mid].x > estim.x)
1299 stop = mid;
1300 else
1301 start = mid;
1304 // if a vertical edge
1305 if (vertices[start].x == vertices[stop].x)
1307 // look for maximal bounds
1308 while (start > 0 && vertices[start].x == vertices[start-1].x)
1309 --start;
1311 while (stop < vertices.size()-1 && vertices[stop].x == vertices[stop+1].x)
1312 ++stop;
1314 // if upper or lower the bounds, do nothing
1315 if ((estim.y > vertices[start].y && estim.y > vertices[stop].y) ||
1316 (estim.y < vertices[start].y && estim.y < vertices[stop].y))
1317 continue;
1319 onBorder = true;
1320 continue;
1322 else if (vertices[stop].x == estim.x)
1324 // if (yes)
1325 continue;
1328 // and then checks if the estimated position is up or down the chain.
1330 // first trivial case (up both tips)
1331 if (estim.y > vertices[start].y && estim.y > vertices[stop].y)
1333 isUpper = true;
1335 // second trivial case (down both tips)
1336 else if (estim.y < vertices[start].y && estim.y < vertices[stop].y)
1338 isUpper = false;
1340 // full test...
1341 else
1343 const CVector2s &vstart = vertices[start],
1344 &vstop = vertices[stop];
1346 // this test is somewhat more accurate
1347 // no division performed
1348 sint32 det = (estim.y-vstart.y)*(vstop.x-vstart.x) - (estim.x-vstart.x)*(vstop.y-vstart.y);
1350 isUpper = (det > 0);
1352 if (det == 0)
1353 onBorder = true;
1357 // Depending on the chain is forward, up the position, increase/decrease the surface table...
1358 if (sub.isForward())
1360 if (isUpper)
1362 cst.incSurface(left);
1363 cst.decSurface(right);
1365 else
1367 cst.decSurface(left);
1368 cst.incSurface(right);
1371 else
1373 if (isUpper)
1375 cst.decSurface(left);
1376 cst.incSurface(right);
1378 else
1380 cst.incSurface(left);
1381 cst.decSurface(right);
1389 void NLPACS::CLocalRetriever::initFaceGrid()
1391 CFaceGrid::CFaceGridBuild fgb;
1392 fgb.init(64, 4.0f);
1394 uint i;
1395 for (i=0; i<_InteriorFaces.size(); ++i)
1397 CAABBox box;
1398 CInteriorFace &f = _InteriorFaces[i];
1399 box.setCenter(_InteriorVertices[f.Verts[0]]);
1400 box.extend(_InteriorVertices[f.Verts[1]]);
1401 box.extend(_InteriorVertices[f.Verts[2]]);
1403 fgb.insert(box.getMin(), box.getMax(), i);
1406 _FaceGrid.create(fgb);
1409 void NLPACS::CLocalRetriever::snapToInteriorGround(NLPACS::ULocalPosition &position, bool &snapped) const
1411 if (!_Loaded)
1412 return;
1414 // first preselect faces around the (x, y) position (CQuadGrid ?)
1415 vector<uint32> selection;
1416 _FaceGrid.select(position.Estimation, selection);
1418 // from the preselect faces, look for the only face that belongs to the surface
1419 // and that contains the position
1420 CVector pos = position.Estimation;
1421 CVector posh = pos+CVector(0.0f, 0.0f, 1.0f);
1422 CVector2f pos2d = position.Estimation;
1423 float bestDist = 1.0e10f;
1424 CVector best(0.0f, 0.0f, 0.0f);
1425 vector<uint32>::iterator it;
1426 snapped = false;
1427 for (it=selection.begin(); it!=selection.end(); ++it)
1429 const CInteriorFace &f = _InteriorFaces[*it];
1430 if (f.Surface == (uint32)position.Surface)
1432 CVector v[3];
1433 v[0] = _InteriorVertices[f.Verts[0]];
1434 v[1] = _InteriorVertices[f.Verts[1]];
1435 v[2] = _InteriorVertices[f.Verts[2]];
1437 CVector2f n;
1438 float c; // 2D cartesian coefficients of line in plane X/Y.
1439 // Line p0-p1.
1440 n = CVector2f(-(v[1].y-v[0].y), (v[1].x-v[0].x)).normed();
1441 c = -(v[0].x*n.x + v[0].y*n.y);
1442 if (n*pos2d + c < -1.0f/Vector2sAccuracy) continue;
1443 // Line p1-p2.
1444 n = CVector2f(-(v[2].y-v[1].y), (v[2].x-v[1].x)).normed();
1445 c = -(v[1].x*n.x + v[1].y*n.y);
1446 if (n*pos2d + c < -1.0f/Vector2sAccuracy) continue;
1447 // Line p2-p0.
1448 n = CVector2f(-(v[0].y-v[2].y), (v[0].x-v[2].x)).normed();
1449 c = -(v[2].x*n.x + v[2].y*n.y);
1450 if (n*pos2d + c < -1.0f/Vector2sAccuracy) continue;
1452 CPlane p;
1453 p.make(v[0], v[1], v[2]);
1455 CVector i = p.intersect(pos, posh);
1457 float d = (float)fabs(pos.z-i.z);
1459 if (d < bestDist)
1461 bestDist = d;
1462 best = i;
1467 // and computes the real position on this face
1468 if (bestDist < 400.0f)
1470 snapped = true;
1471 position.Estimation = best;
1475 // ***************************************************************************
1476 float NLPACS::CLocalRetriever::getHeight(const NLPACS::ULocalPosition &position) const
1478 if (!_Loaded)
1479 return 0.0f;
1481 if (_Type == Interior)
1483 // first preselect faces around the (x, y) position (CQuadGrid ?)
1484 vector<uint32> selection;
1485 _FaceGrid.select(position.Estimation, selection);
1487 // from the preselect faces, look for the only face that belongs to the surface
1488 // and that contains the position
1489 CVector pos = position.Estimation;
1490 CVector posh = pos+CVector(0.0f, 0.0f, 1.0f);
1491 float bestDist = 1.0e10f;
1492 CVector best(0.0f, 0.0f, 0.0f);
1493 vector<uint32>::iterator it;
1494 for (it=selection.begin(); it!=selection.end(); ++it)
1496 const CInteriorFace &f = _InteriorFaces[*it];
1497 if (f.Surface == (uint32)position.Surface)
1499 CVector v[3];
1500 v[0] = _InteriorVertices[f.Verts[0]];
1501 v[1] = _InteriorVertices[f.Verts[1]];
1502 v[2] = _InteriorVertices[f.Verts[2]];
1504 float a,b,c; // 2D cartesian coefficients of line in plane X/Y.
1505 // Line p0-p1.
1506 a = -(v[1].y-v[0].y);
1507 b = (v[1].x-v[0].x);
1508 c = -(v[0].x*a + v[0].y*b);
1509 if (a*pos.x + b*pos.y + c < 0) continue;
1510 // Line p1-p2.
1511 a = -(v[2].y-v[1].y);
1512 b = (v[2].x-v[1].x);
1513 c = -(v[1].x*a + v[1].y*b);
1514 if (a*pos.x + b*pos.y + c < 0) continue;
1515 // Line p2-p0.
1516 a = -(v[0].y-v[2].y);
1517 b = (v[0].x-v[2].x);
1518 c = -(v[2].x*a + v[2].y*b);
1519 if (a*pos.x + b*pos.y + c < 0) continue;
1521 CPlane p;
1522 p.make(v[0], v[1], v[2]);
1524 CVector i = p.intersect(pos, posh);
1526 float d = (float)fabs(pos.z-i.z);
1528 if (d < bestDist)
1530 bestDist = d;
1531 best = i;
1536 // and computes the real position on this face
1537 return (bestDist < 200.0f) ? best.z : position.Estimation.z;
1539 else
1541 if (_Surfaces[position.Surface].getQuadTree().getRoot() != NULL)
1543 // find quad leaf.
1544 const CQuadLeaf *leaf = _Surfaces[position.Surface].getQuadTree().getLeaf(position.Estimation);
1546 // if there is no acceptable leaf, just give up
1547 if (leaf == NULL)
1549 //nlinfo("COL: quadtree: don't find the quadLeaf!");
1550 return position.Estimation.z;
1552 else
1554 // else return mean height.
1555 float meanHeight = (leaf->getMinHeight()+leaf->getMaxHeight())*0.5f;
1556 return meanHeight;
1559 else if (_Surfaces[position.Surface].isUnderWater())
1561 return _Surfaces[position.Surface].getWaterHeight();
1563 else
1565 sint8 qh = _Surfaces[position.Surface].getQuantHeight();
1566 return qh*2.0f + 1.0f;
1572 // ***************************************************************************
1573 float NLPACS::CLocalRetriever::getInteriorHeightAround(const ULocalPosition &position, float outsideTolerance) const
1575 if (!_Loaded)
1576 return 0.0f;
1578 if (_Type == Interior)
1580 // first preselect faces around the (x, y) position (CQuadGrid ?)
1581 vector<uint32> selection;
1582 _FaceGrid.select(position.Estimation, selection);
1584 // from the preselect faces, look for the only face that belongs to the surface
1585 // and that contains the position
1586 CVector pos = position.Estimation;
1587 CVector posh = pos+CVector(0.0f, 0.0f, 1.0f);
1588 float bestDist = 1.0e10f;
1589 CVector best(0.0f, 0.0f, 0.0f);
1590 vector<uint32>::iterator it;
1591 for (it=selection.begin(); it!=selection.end(); ++it)
1593 const CInteriorFace &f = _InteriorFaces[*it];
1594 if (f.Surface == (uint32)position.Surface)
1596 CVector v[3];
1597 v[0] = _InteriorVertices[f.Verts[0]];
1598 v[1] = _InteriorVertices[f.Verts[1]];
1599 v[2] = _InteriorVertices[f.Verts[2]];
1601 // Test if out of this triangle (+ tolerance)
1602 float a,b; // 2D cartesian coefficients of line in plane X/Y.
1603 float len;
1604 // Line p0-p1.
1605 a = -(v[1].y-v[0].y);
1606 b = (v[1].x-v[0].x);
1607 len= sqrtf(a*a+b*b); // norm of the normal vector
1608 if (a*(pos.x-v[0].x) + b*(pos.y-v[0].y) < -len*outsideTolerance) continue;
1609 // Line p1-p2.
1610 a = -(v[2].y-v[1].y);
1611 b = (v[2].x-v[1].x);
1612 len= sqrtf(a*a+b*b); // norm of the normal vector
1613 if (a*(pos.x-v[1].x) + b*(pos.y-v[1].y) < -len*outsideTolerance) continue;
1614 // Line p2-p0.
1615 a = -(v[0].y-v[2].y);
1616 b = (v[0].x-v[2].x);
1617 len= sqrtf(a*a+b*b); // norm of the normal vector
1618 if (a*(pos.x-v[2].x) + b*(pos.y-v[2].y) < -len*outsideTolerance) continue;
1621 // Ok IN => compute z and keep nearest to wanted one
1622 CPlane p;
1623 p.make(v[0], v[1], v[2]);
1625 CVector i = p.intersect(pos, posh);
1627 float d = (float)fabs(pos.z-i.z);
1629 if (d < bestDist)
1631 bestDist = d;
1632 best = i;
1637 // and computes the real position on this face
1638 return (bestDist < 200.0f) ? best.z : position.Estimation.z;
1641 return 0.f;
1645 // ***************************************************************************
1646 #ifdef NL_OS_WINDOWS
1647 //#pragma optimize( "", off )
1648 #endif // NL_OS_WINDOWS
1650 void NLPACS::CLocalRetriever::findPath(const NLPACS::CLocalRetriever::CLocalPosition &A,
1651 const NLPACS::CLocalRetriever::CLocalPosition &B,
1652 std::vector<NLPACS::CVector2s> &path,
1653 NLPACS::CCollisionSurfaceTemp &cst) const
1655 if (A.Surface != B.Surface)
1657 nlwarning("in NLPACS::CLocalRetriever::findPath()");
1658 nlerror("Try to find a path between 2 points that are not in the same surface (A=%d, B=%d)", A.Surface, B.Surface);
1661 CVector a = A.Estimation,
1662 b = B.Estimation,
1663 n = CVector(a.y-b.y, b.x-a.x, 0.0f);
1665 _ChainQuad.selectEdges(a, b, cst);
1667 vector<CIntersectionMarker> intersections;
1669 uint i, j;
1670 sint32 surfaceId = A.Surface;
1671 const CRetrievableSurface &surface = _Surfaces[surfaceId];
1673 for (i=0; i<cst.EdgeChainEntries.size(); ++i)
1675 CEdgeChainEntry &entry = cst.EdgeChainEntries[i];
1676 const COrderedChain &chain = _OrderedChains[entry.OChainId];
1678 if (_Chains[chain.getParentId()].getLeft() != surfaceId &&
1679 _Chains[chain.getParentId()].getRight() != surfaceId)
1680 continue;
1682 for (j=entry.EdgeStart; j<entry.EdgeEnd; ++j)
1684 // here the edge collision test
1686 CVector p0 = chain[j].unpack3f(),
1687 p1 = chain[j+1].unpack3f();
1689 float vp0 = (p0-a)*n,
1690 vp1 = (p1-a)*n;
1692 if (vp0*vp1 <= 0.0f)
1694 CVector np = CVector(p0.y-p1.y, p1.x-p0.x, 0.0f);
1696 float va = (a-p0)*np,
1697 vb = (b-p0)*np;
1699 // here we have an intersection
1700 if (va*vb <= 0.0f)
1702 const CChain &parent = _Chains[chain.getParentId()];
1703 bool isIn = (va-vb < 0.0f) ^ (parent.getLeft() == surfaceId) ^ chain.isForward();
1705 intersections.push_back(CIntersectionMarker(va/(va-vb), entry.OChainId, uint16(j), isIn));
1711 sort(intersections.begin(), intersections.end());
1713 uint intersStart = 0;
1714 uint intersEnd = (uint)intersections.size();
1716 if (intersEnd > 0)
1718 while (intersStart < intersections.size() &&
1719 intersections[intersStart].In && intersections[intersStart].Position < 1.0e-4f)
1720 ++intersStart;
1722 while (intersStart < intersEnd &&
1723 !intersections[intersEnd-1].In && intersections[intersEnd-1].Position > 1.0f-1.0e-4f)
1724 --intersEnd;
1726 // Check intersections have a valid order
1727 if ((intersEnd-intersStart) & 1)
1729 nlwarning("in NLPACS::CLocalRetriever::findPath()");
1730 nlerror("Found an odd (%d) number of intersections", intersections.size());
1733 for (i=intersStart; i<intersEnd; )
1735 uint exitLoop, enterLoop;
1737 const CChain &exitChain = _Chains[_OrderedChains[intersections[i].OChain].getParentId()];
1738 exitLoop = (exitChain.getLeft() == surfaceId) ? exitChain.getLeftLoop() : exitChain.getRightLoop();
1740 if (intersections[i++].In)
1742 nlwarning("in NLPACS::CLocalRetriever::findPath()");
1743 nlerror("Entered the surface before exited", intersections.size());
1746 const CChain &enterChain = _Chains[_OrderedChains[intersections[i].OChain].getParentId()];
1747 enterLoop = (enterChain.getLeft() == surfaceId) ? enterChain.getLeftLoop() : enterChain.getRightLoop();
1749 if (!intersections[i++].In)
1751 nlwarning("in NLPACS::CLocalRetriever::findPath()");
1752 nlerror("Exited twice the surface", intersections.size());
1755 if (exitLoop != enterLoop)
1757 nlwarning("in NLPACS::CLocalRetriever::findPath()");
1758 nlerror("Exited and rentered by a different loop");
1763 // dumpSurface(surfaceId);
1765 path.push_back(CVector2s(A.Estimation));
1767 for (i=intersStart; i<intersEnd; )
1769 uint exitChainId = _OrderedChains[intersections[i].OChain].getParentId(),
1770 enterChainId = _OrderedChains[intersections[i+1].OChain].getParentId();
1771 const CChain &exitChain = _Chains[exitChainId],
1772 &enterChain = _Chains[enterChainId];
1773 uint loopId, exitLoopIndex, enterLoopIndex;
1775 if (exitChain.getLeft() == surfaceId)
1777 loopId = exitChain.getLeftLoop();
1778 exitLoopIndex = exitChain.getLeftLoopIndex();
1780 else
1782 loopId = exitChain.getRightLoop();
1783 exitLoopIndex = exitChain.getRightLoopIndex();
1786 const CRetrievableSurface::TLoop &loop = surface._Loops[loopId];
1788 if (enterChain.getLeft() == surfaceId)
1789 enterLoopIndex = enterChain.getLeftLoopIndex();
1790 else
1791 enterLoopIndex = enterChain.getRightLoopIndex();
1793 float forwardLength = (exitChain.getLength()+enterChain.getLength())*0.5f;
1795 sint loopIndex = exitLoopIndex;
1796 uint thisChainId = exitChainId;
1797 bool thisChainForward = (enterChain.getLeft() == surfaceId);
1798 uint thisOChainId = intersections[i].OChain;
1799 sint thisOChainIndex = _OrderedChains[thisOChainId].getIndexInParent();
1800 bool forward;
1802 if (exitChainId != enterChainId)
1804 for (j=(exitLoopIndex+1)%loop.size(); j!=enterLoopIndex; j=(j+1)%loop.size())
1805 forwardLength += _Chains[surface._Chains[loop[j]].Chain].getLength();
1806 forward = (forwardLength <= loop.Length-forwardLength);
1808 else
1810 forward = !thisChainForward ^ (_OrderedChains[intersections[i].OChain].getIndexInParent() < _OrderedChains[intersections[i+1].OChain].getIndexInParent());
1813 path.push_back(CVector2s(A.Estimation+intersections[i].Position*(B.Estimation-A.Estimation)));
1815 for(;;)
1817 sint from = (thisOChainId == intersections[i].OChain) ? intersections[i].Edge : -1,
1818 to = (thisOChainId == intersections[i+1].OChain) ? intersections[i+1].Edge : -1;
1819 bool oforward = thisChainForward ^ forward ^ _OrderedChains[thisOChainId].isForward();
1821 if (from != -1 && to != -1)
1822 oforward = (intersections[i].Edge < intersections[i+1].Edge);
1824 _OrderedChains[thisOChainId].traverse(from, to, oforward, path);
1826 if (thisOChainId == intersections[i+1].OChain)
1827 break;
1829 thisOChainIndex = (thisChainForward ^ forward) ? thisOChainIndex-1 : thisOChainIndex+1;
1831 if (thisOChainIndex < 0 || thisOChainIndex >= (sint)_Chains[thisChainId]._SubChains.size())
1833 if (forward)
1835 loopIndex++;
1836 if (loopIndex == (sint)loop.size())
1837 loopIndex = 0;
1839 else
1841 loopIndex--;
1842 if (loopIndex < 0)
1843 loopIndex = (sint)loop.size()-1;
1846 thisChainId = surface._Chains[loop[loopIndex]].Chain;
1847 thisChainForward = (_Chains[thisChainId].getLeft() == surfaceId);
1848 thisOChainIndex = (thisChainForward == forward) ?
1849 0 : (sint)_Chains[thisChainId]._SubChains.size()-1;
1852 thisOChainId = _Chains[thisChainId]._SubChains[thisOChainIndex];
1855 path.push_back(CVector2s(A.Estimation+intersections[i+1].Position*(B.Estimation-A.Estimation)));
1856 i += 2;
1859 path.push_back(CVector2s(B.Estimation));
1861 #ifdef NL_OS_WINDOWS
1862 //#pragma optimize( "", on )
1863 #endif // NL_OS_WINDOWS
1865 // ***************************************************************************
1866 // ***************************************************************************
1867 // Collisions part.
1868 // ***************************************************************************
1869 // ***************************************************************************
1872 // ***************************************************************************
1873 void NLPACS::CLocalRetriever::computeCollisionChainQuad()
1875 _ChainQuad.build(_OrderedChains);
1879 // ***************************************************************************
1880 void NLPACS::CLocalRetriever::testCollision(CCollisionSurfaceTemp &cst, const CAABBox &bboxMove, const CVector2f &transBase) const
1882 if (!_Loaded)
1883 return;
1885 // H_AUTO(PACS_LR_testCollision);
1887 sint i;
1889 // 0. select ordered chains in the chainquad.
1890 //=====================================
1891 // H_BEFORE(PACS_LR_testCol_selEdges);
1892 sint nEce= _ChainQuad.selectEdges(bboxMove, cst);
1893 // H_AFTER(PACS_LR_testCol_selEdges);
1894 // NB: cst.OChainLUT is assured to be full of 0xFFFF after this call (if was right before).
1897 // 1. regroup them in chains. build cst.CollisionChains
1898 //=====================================
1899 // NB: use cst.OChainLUT to look if a Chain has been inserted before.
1900 uint16 *chainLUT= cst.OChainLUT;
1902 // bkup where we begin to add chains.
1903 uint firstChainAdded= (uint)cst.CollisionChains.size();
1905 // For all edgechain entry.
1906 for(i=0;i<nEce;i++)
1908 CEdgeChainEntry &ece= cst.EdgeChainEntries[i];
1909 // this is the ordered chain in the retriever.
1910 const COrderedChain &oChain= this->getOrderedChains()[ece.OChainId];
1911 // this is the id of the chain is the local retriever.
1912 uint16 chainId= oChain.getParentId();
1914 // test if edge is interior and points to another instance
1915 if (_Type == Interior && CChain::isBorderChainId(this->getChains()[chainId].getRight()))
1917 // then look for a door that match this edge
1918 uint l;
1919 for (l=0; l<_ExteriorMesh.getLinks().size() && _ExteriorMesh.getLink(l).ChainId != chainId; ++l)
1922 // if found a door, then leave the edge as is
1923 if (l < _ExteriorMesh.getLinks().size())
1924 continue;
1928 // add/retrieve the id in cst.CollisionChains.
1929 //=================================
1930 uint ccId;
1931 // if never added.
1932 if(chainLUT[chainId]==0xFFFF)
1934 // H_AUTO(PACS_LR_testCol_addToLUT);
1935 // add a new CCollisionChain.
1936 ccId= (uint)cst.CollisionChains.size();
1937 cst.CollisionChains.push_back(CCollisionChain());
1938 // Fill it with default.
1939 cst.CollisionChains[ccId].Tested= false;
1940 cst.CollisionChains[ccId].ExteriorEdge = false;
1941 cst.CollisionChains[ccId].FirstEdgeCollide= 0xFFFFFFFF;
1942 cst.CollisionChains[ccId].ChainId= chainId;
1943 // Fill Left right info.
1944 cst.CollisionChains[ccId].LeftSurface.SurfaceId= this->getChains()[chainId].getLeft();
1945 cst.CollisionChains[ccId].RightSurface.SurfaceId= this->getChains()[chainId].getRight();
1946 // NB: cst.CollisionChains[ccId].*Surface.RetrieverInstanceId is not filled here because we don't have
1947 // this info at this level.
1949 // store this Id in the LUT of chains.
1950 chainLUT[chainId]= uint16(ccId);
1952 else
1954 // get the id of this collision chain.
1955 ccId= chainLUT[chainId];
1958 // add edge collide to the list.
1959 //=================================
1960 // H_BEFORE(PACS_LR_testCol_addToList);
1961 CCollisionChain &colChain= cst.CollisionChains[ccId];
1962 const std::vector<CVector2s> &oChainVertices= oChain.getVertices();
1963 for(sint edge=ece.EdgeStart; edge<ece.EdgeEnd; edge++)
1965 CVector2f p0= oChainVertices[edge].unpack();
1966 CVector2f p1= oChainVertices[edge+1].unpack();
1968 // alloc a new edgeCollide.
1969 uint32 ecnId= cst.allocEdgeCollideNode();
1970 CEdgeCollideNode &ecn= cst.getEdgeCollideNode(ecnId);
1972 // append to the front of the list.
1973 ecn.Next= colChain.FirstEdgeCollide;
1974 colChain.FirstEdgeCollide= ecnId;
1976 // build this edge.
1977 p0+= transBase;
1978 p1+= transBase;
1979 ecn.make(p0, p1);
1981 // H_AFTER(PACS_LR_testCol_addToList);
1986 // 2. Reset LUT to 0xFFFF.
1987 //=====================================
1989 // H_BEFORE(PACS_LR_testCol_resetLUT);
1990 // for all collisions chains inserted (starting from firstChainAdded), reset LUT.
1991 for(i=firstChainAdded; i<(sint)cst.CollisionChains.size(); i++)
1993 uint ccId= cst.CollisionChains[i].ChainId;
1994 chainLUT[ccId]= 0xFFFF;
1996 // H_AFTER(PACS_LR_testCol_resetLUT);
2000 // ***************************************************************************
2001 // ***************************************************************************
2002 // ***************************************************************************
2003 // ***************************************************************************
2006 // ***************************************************************************
2007 void NLPACS::CLocalRetriever::buildInteriorSurfaceBBoxes(std::vector<NLMISC::CAABBox> &surfaceBBoxes) const
2009 // resize dest, and init.
2010 vector<bool> firstTriangle;
2011 surfaceBBoxes.clear();
2012 surfaceBBoxes.resize(_Surfaces.size());
2013 firstTriangle.resize(_Surfaces.size(), true);
2015 // For all _InteriorFaces.
2016 for(uint iIntFace=0; iIntFace<_InteriorFaces.size(); iIntFace++)
2018 const CInteriorFace &intFace= _InteriorFaces[iIntFace];
2020 // Extend the surface of this face with her 3 points.
2022 // check good id.
2023 if(intFace.Surface==(uint)-1)
2024 continue;
2025 nlassert(intFace.Surface<_Surfaces.size());
2027 // If first time we extend the bbox of this surface
2028 if(firstTriangle[intFace.Surface])
2030 surfaceBBoxes[intFace.Surface].setCenter(_InteriorVertices[intFace.Verts[0]] );
2031 firstTriangle[intFace.Surface]= false;
2033 else
2034 surfaceBBoxes[intFace.Surface].extend(_InteriorVertices[intFace.Verts[0]] );
2036 // extend with other 2 points
2037 surfaceBBoxes[intFace.Surface].extend(_InteriorVertices[intFace.Verts[1]] );
2038 surfaceBBoxes[intFace.Surface].extend(_InteriorVertices[intFace.Verts[2]] );
2044 // ***************************************************************************
2045 void NLPACS::CLocalRetriever::replaceChain(uint32 chainId, const std::vector<NLPACS::CLocalRetriever::CChainReplacement> &replacement)
2047 // free subchains
2048 uint i, j;
2049 for (i=0; i<_Chains[chainId]._SubChains.size(); ++i)
2051 FreeOChains.push_back(_Chains[chainId]._SubChains[i]);
2052 _OrderedChains[_Chains[chainId]._SubChains[i]] = COrderedChain();
2053 _FullOrderedChains[_Chains[chainId]._SubChains[i]] = COrderedChain3f();
2056 // create new chains in replacement of this chain
2058 for (i=0; i<replacement.size(); ++i)
2060 vector<CVector> vertices = replacement[i].Vertices;
2061 sint left = replacement[i].Left;
2062 sint right = replacement[i].Right;
2064 if (CChain::isBorderChainId(right))
2066 // check border already exists for this particular chain
2067 sint32 border = CChain::convertBorderChainId(right);
2069 if (border < (sint)_BorderChains.size() && (chainId != _BorderChains[border] || chainId != replacement[i].Chain))
2071 nlwarning("replaceChain(): replacement of a border is forced whereas this border is already used and not replaced!");
2074 if (border >= (sint)_BorderChains.size())
2076 if (border > (sint)_BorderChains.size())
2078 nlwarning("replaceChain(): _BorderChains size increased of more than 1 step, holes may result!");
2081 _BorderChains.resize(border+1, 0xffff);
2084 _BorderChains[border] = uint16(replacement[i].Chain);
2087 nlassert(vertices.size() >= 2);
2089 // Remove doubled vertices due to CVector2s snapping
2090 vector<CVector2s> converts;
2092 for (j=0; j<vertices.size(); ++j)
2093 converts.push_back(CVector2s(vertices[j]));
2095 vector<CVector2s>::iterator next2s = converts.begin(), it2s, prev2s;
2096 prev2s = next2s; ++next2s;
2097 it2s = next2s; ++next2s;
2099 vector<CVector>::iterator it3f = vertices.begin();
2100 CVector prev3f = *it3f;
2101 ++it3f;
2104 for (; it2s != converts.end() && next2s != converts.end(); )
2106 // if the next point is equal to the previous
2107 if (*it2s == *prev2s || *it2s == *next2s)
2109 // then remove the next point
2110 it2s = converts.erase(it2s);
2111 it3f = vertices.erase(it3f);
2113 prev2s = it2s;
2114 --prev2s;
2115 next2s = it2s;
2116 ++next2s;
2118 else
2120 // else remember the next point, and step to the next...
2121 ++prev2s;
2122 ++it2s;
2123 ++next2s;
2124 ++it3f;
2125 prev3f = *it3f;
2129 nlassert(vertices.size() >= 2);
2131 sint32 newId = replacement[i].Chain;
2132 if (newId >= (sint)_Chains.size())
2133 _Chains.resize(newId+1);
2135 //CChain &nchain = _Chains[newId];
2137 if (left>(sint)_Surfaces.size())
2138 nlerror ("left surface id MUST be id<%d (id=%d)", _Surfaces.size(), left);
2139 if (right>(sint)_Surfaces.size())
2140 nlerror ("right surface id MUST be id<%d (id=%d)", _Surfaces.size(), right);
2142 // checks if we can build the chain.
2143 if (newId > 65535)
2144 nlerror("in NLPACS::CLocalRetriever::addChain(): reached the maximum number of chains");
2146 //CRetrievableSurface *leftSurface = (left>=0) ? &(_Surfaces[left]) : NULL;
2147 //CRetrievableSurface *rightSurface = (right>=0) ? &(_Surfaces[right]) : NULL;
2149 CChain &chain = _Chains[newId];
2151 chain._StartTip = 0xffff;
2152 chain._StopTip = 0xffff;
2154 // make the chain and its subchains.
2155 chain.make(vertices, left, right, _OrderedChains, (uint16)newId, _FullOrderedChains, FreeOChains);
2158 for (i=0; i<_Surfaces.size(); ++i)
2160 // remove old chain and replace by new chains in surface links
2161 for (j=0; j<_Surfaces[i]._Chains.size(); ++j)
2163 if (_Surfaces[i]._Chains[j].Chain == (sint)chainId)
2165 _Surfaces[i]._Chains.erase(_Surfaces[i]._Chains.begin()+j);
2167 uint k;
2168 for (k=0; k<replacement.size(); ++k)
2170 CRetrievableSurface::CSurfaceLink link;
2172 link.Chain = replacement[k].Chain;
2173 link.Surface = (replacement[k].Left == (sint)i ? replacement[k].Right : replacement[k].Left);
2174 _Surfaces[i]._Chains.push_back(link);
2177 break;
2181 // remove old chain and replace by new chains in surface loops
2182 for (j=0; j<_Surfaces[i]._Loops.size(); ++j)
2184 uint k;
2186 for (k=0; k<_Surfaces[i]._Loops[j].size(); ++k)
2188 if (_Surfaces[i]._Loops[j][k] == chainId)
2190 _Surfaces[i]._Loops[j].erase(_Surfaces[i]._Loops[j].begin()+k);
2191 uint m;
2193 for (m=0; m<replacement.size(); ++m)
2194 _Surfaces[i]._Loops[j].insert(_Surfaces[i]._Loops[j].begin()+k+m, uint16(replacement[m].Chain));
2196 break;
2207 * Check surface integrity
2209 bool NLPACS::CLocalRetriever::checkSurfacesIntegrity(NLMISC::CVector translation, bool verbose) const
2211 bool success = true;
2212 uint surf;
2214 for (surf=0; surf<_Surfaces.size(); ++surf)
2216 if (!checkSurfaceIntegrity(surf, translation, verbose))
2218 success = false;
2219 if (verbose)
2221 dumpSurface(surf, translation);
2227 return success;
2232 * Check surface integrity
2234 bool NLPACS::CLocalRetriever::checkSurfaceIntegrity(uint surf, NLMISC::CVector translation, bool verbose) const
2236 if (surf >= _Surfaces.size())
2237 return false;
2239 const CRetrievableSurface& surface = _Surfaces[surf];
2241 uint nloops = (uint)surface.getLoops().size();
2243 std::vector<std::pair<CVector2s, CVector2s> > edges;
2245 uint iloop;
2246 uint i, j, k;
2247 for (iloop=0; iloop<nloops; ++iloop)
2249 const CRetrievableSurface::TLoop& loop = surface.getLoop(iloop);
2251 for (i=0; i<loop.size(); ++i)
2253 // loop[i] is the index in the surface list of chains
2254 // so surface._Chains[loop[i]].Chain is really the chain id !!!
2255 const CChain& chain = _Chains[ surface._Chains[loop[i]].Chain ];
2256 for (j=0; j<chain.getSubChains().size(); ++j)
2258 const COrderedChain& ochain = _OrderedChains[chain.getSubChain(j)];
2260 for (k=0; k+1<ochain.getVertices().size(); ++k)
2262 edges.push_back(std::pair<CVector2s, CVector2s>(ochain[k], ochain[k+1]));
2268 bool success = true;
2270 for (i=0; i+1<edges.size(); ++i)
2272 for (j=i+1; j<edges.size(); ++j)
2274 CVector2s a0 = edges[i].first,
2275 a1 = edges[i].second;
2276 CVector2s b0 = edges[j].first,
2277 b1 = edges[j].second;
2279 double a, b;
2280 bool inters = CVector2s::intersect(a0, a1, b0, b1, &a, &b);
2282 if (!inters)
2283 continue;
2285 double da = (a1-a0).norm();
2286 double db = (b1-b0).norm();
2288 bool tipa = (fabs(a)*da < 4.0e-2 || fabs(1.0-a)*da < 4.0e-2);
2289 bool tipb = (fabs(b)*db < 4.0e-2 || fabs(1.0-b)*db < 4.0e-2);
2291 if (tipa && tipb)
2292 continue;
2294 CVector2s ip = a0 + (a1-a0)*(float)a;
2295 CVector p = ip.unpack3f() - translation;
2296 nlwarning("Surface %d has issue at position (%f,%f)", surf, p.x, p.y);
2297 if (verbose)
2299 NLMISC::CVector v;
2300 v = a0.unpack3f() - translation;
2301 nlwarning(" -- a0: (%f,%f)", v.x, v.y);
2302 v = a1.unpack3f() - translation;
2303 nlwarning(" -- a1: (%f,%f)", v.x, v.y);
2304 v = b0.unpack3f() - translation;
2305 nlwarning(" -- b0: (%f,%f)", v.x, v.y);
2306 v = b1.unpack3f() - translation;
2307 nlwarning(" -- b1: (%f,%f)", v.x, v.y);
2310 success = false;
2314 return success;