source: GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellBsp.cpp @ 1418

Revision 1418, 81.3 KB checked in by mattausch, 18 years ago (diff)
Line 
1#include "Plane3.h"
2#include "ViewCellBsp.h"
3#include "Mesh.h"
4#include "common.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "Polygon3.h"
8#include "Ray.h"
9#include "AxisAlignedBox3.h"
10#include "Triangle3.h"
11#include "Tetrahedron3.h"
12#include "ViewCellsManager.h"
13#include "Exporter.h"
14#include "Plane3.h"
15#include <stack>
16
17namespace GtpVisibilityPreprocessor {
18
19
20//-- static members
21
22int BspNode::sMailId = 1;
23
24/** Evaluates split plane classification with respect to the plane's
25        contribution for a minimum number splits in the tree.
26*/
27const float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0};
28/** Evaluates split plane classification with respect to the plane's
29        contribution for a balanced tree.
30*/
31const float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0};
32
33/** Evaluates split plane classification with respect to the plane's
34        contribution for a minimum number of ray splits.
35*/
36const float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};
37/** Evaluates split plane classification with respect to the plane's
38        contribution for balanced rays.
39*/
40const float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0};
41
42int BspTree::sFrontId = 0;
43int BspTree::sBackId = 0;
44int BspTree::sFrontAndBackId = 0;
45
46
47/******************************************************************/
48/*                  class BspNode implementation                  */
49/******************************************************************/
50
51
52BspNode::BspNode():
53mParent(NULL), mTreeValid(true), mTimeStamp(0)
54{}
55
56
57BspNode::BspNode(BspInterior *parent):
58mParent(parent), mTreeValid(true)
59{}
60
61
62bool BspNode::IsSibling(BspNode *n) const
63{
64        return  ((this != n) && mParent &&
65                         (mParent->GetFront() == n) || (mParent->GetBack() == n));
66}
67
68
69int BspNode::GetDepth() const
70{
71        int depth = 0;
72        BspNode *p = mParent;
73       
74        while (p)
75        {
76                p = p->mParent;
77                ++ depth;
78        }
79
80        return depth;
81}
82
83
84bool BspNode::TreeValid() const
85{
86        return mTreeValid;
87}
88
89
90void BspNode::SetTreeValid(const bool v)
91{
92        mTreeValid = v;
93}
94
95
96/****************************************************************/
97/*              class BspInterior implementation                */
98/****************************************************************/
99
100
101BspInterior::BspInterior(const Plane3 &plane):
102mPlane(plane), mFront(NULL), mBack(NULL)
103{}
104
105BspInterior::~BspInterior()
106{
107        DEL_PTR(mFront);
108        DEL_PTR(mBack);
109}
110
111
112void BspInterior::SetupChildLinks(BspNode *b, BspNode *f)
113{
114    mBack = b;
115    mFront = f;
116}
117
118
119/****************************************************************/
120/*                  class BspLeaf implementation                */
121/****************************************************************/
122
123
124BspLeaf::BspLeaf(): mViewCell(NULL), mPvs(NULL)
125{
126}
127
128
129BspLeaf::~BspLeaf()
130{
131        DEL_PTR(mPvs);
132
133        VssRayContainer::const_iterator vit, vit_end = mVssRays.end();
134        for (vit = mVssRays.begin(); vit != vit_end; ++ vit)
135        {
136                VssRay *ray = *vit;
137                ray->Unref();
138
139                if (!ray->IsActive())
140                        delete ray;
141        }
142}
143
144
145BspLeaf::BspLeaf(ViewCellLeaf *viewCell):
146mViewCell(viewCell)
147{
148}
149
150
151BspLeaf::BspLeaf(BspInterior *parent):
152BspNode(parent), mViewCell(NULL), mPvs(NULL)
153{}
154
155
156
157BspLeaf::BspLeaf(BspInterior *parent, ViewCellLeaf *viewCell):
158BspNode(parent), mViewCell(viewCell), mPvs(NULL)
159{
160}
161
162
163/*********************************************************************/
164/*                       class BspTree implementation                */
165/*********************************************************************/
166
167BspTree::BspTree(): 
168mRoot(NULL),
169mUseAreaForPvs(false),
170mGenerateViewCells(true),
171mTimeStamp(1)
172{
173        Randomize(); // initialise random generator for heuristics
174
175        mOutOfBoundsCell = GetOrCreateOutOfBoundsCell();
176
177        //-- termination criteria for autopartition
178        Environment::GetSingleton()->GetIntValue("BspTree.Termination.maxDepth", mTermMaxDepth);
179        Environment::GetSingleton()->GetIntValue("BspTree.Termination.minPvs", mTermMinPvs);
180        Environment::GetSingleton()->GetIntValue("BspTree.Termination.minPolygons", mTermMinPolys);
181        Environment::GetSingleton()->GetIntValue("BspTree.Termination.minRays", mTermMinRays);
182        Environment::GetSingleton()->GetFloatValue("BspTree.Termination.minProbability", mTermMinProbability); 
183        Environment::GetSingleton()->GetFloatValue("BspTree.Termination.maxRayContribution", mTermMaxRayContribution);
184        Environment::GetSingleton()->GetFloatValue("BspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
185
186        //-- factors for bsp tree split plane heuristics
187        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.verticalSplits", mVerticalSplitsFactor);
188        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.largestPolyArea", mLargestPolyAreaFactor);
189        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.blockedRays", mBlockedRaysFactor);
190        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.leastRaySplits", mLeastRaySplitsFactor);
191        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.balancedRays", mBalancedRaysFactor);
192        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.pvs", mPvsFactor);
193        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.leastSplits" , mLeastSplitsFactor);
194        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.balancedPolys", mBalancedPolysFactor);
195        Environment::GetSingleton()->GetFloatValue("BspTree.Factor.balancedViewCells", mBalancedViewCellsFactor);
196        Environment::GetSingleton()->GetFloatValue("BspTree.Termination.ct_div_ci", mCtDivCi);
197
198        //-- termination criteria for axis aligned split
199        Environment::GetSingleton()->GetFloatValue("BspTree.Termination.AxisAligned.ct_div_ci", mAxisAlignedCtDivCi);
200        Environment::GetSingleton()->GetFloatValue("BspTree.Termination.maxCostRatio", mMaxCostRatio);
201        Environment::GetSingleton()->GetIntValue("BspTree.Termination.AxisAligned.minPolys",
202                                                         mTermMinPolysForAxisAligned);
203        Environment::GetSingleton()->GetIntValue("BspTree.Termination.AxisAligned.minRays",
204                                                         mTermMinRaysForAxisAligned);
205        Environment::GetSingleton()->GetIntValue("BspTree.Termination.AxisAligned.minObjects",
206                                                         mTermMinObjectsForAxisAligned);
207        //-- partition criteria
208        Environment::GetSingleton()->GetIntValue("BspTree.maxPolyCandidates", mMaxPolyCandidates);
209        Environment::GetSingleton()->GetIntValue("BspTree.maxRayCandidates", mMaxRayCandidates);
210        Environment::GetSingleton()->GetIntValue("BspTree.splitPlaneStrategy", mSplitPlaneStrategy);
211        Environment::GetSingleton()->GetFloatValue("BspTree.AxisAligned.splitBorder", mSplitBorder);
212        Environment::GetSingleton()->GetIntValue("BspTree.maxTests", mMaxTests);
213        Environment::GetSingleton()->GetIntValue("BspTree.Termination.maxViewCells", mMaxViewCells);
214
215        Environment::GetSingleton()->GetFloatValue("BspTree.Construction.epsilon", mEpsilon);
216
217        char subdivisionStatsLog[100];
218        Environment::GetSingleton()->GetStringValue("BspTree.subdivisionStats", subdivisionStatsLog);
219        mSubdivisionStats.open(subdivisionStatsLog);
220
221    Debug << "BSP max depth: " << mTermMaxDepth << endl;
222        Debug << "BSP min PVS: " << mTermMinPvs << endl;
223        Debug << "BSP min probability: " << mTermMinProbability << endl;
224        Debug << "BSP max polys: " << mTermMinPolys << endl;
225        Debug << "BSP max rays: " << mTermMinRays << endl;
226        Debug << "BSP max polygon candidates: " << mMaxPolyCandidates << endl;
227        Debug << "BSP max plane candidates: " << mMaxRayCandidates << endl;
228
229        Debug << "Split plane strategy: ";
230        if (mSplitPlaneStrategy & RANDOM_POLYGON)
231                Debug << "random polygon ";
232        if (mSplitPlaneStrategy & AXIS_ALIGNED)
233                Debug << "axis aligned ";
234        if (mSplitPlaneStrategy & LEAST_SPLITS)     
235                Debug << "least splits ";
236        if (mSplitPlaneStrategy & BALANCED_POLYS)
237                Debug << "balanced polygons ";
238        if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
239                Debug << "balanced view cells ";
240        if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
241                Debug << "largest polygon area ";
242        if (mSplitPlaneStrategy & VERTICAL_AXIS)
243                Debug << "vertical axis ";
244        if (mSplitPlaneStrategy & BLOCKED_RAYS)
245                Debug << "blocked rays ";
246        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
247                Debug << "least ray splits ";
248        if (mSplitPlaneStrategy & BALANCED_RAYS)
249                Debug << "balanced rays ";
250        if (mSplitPlaneStrategy & PVS)
251                Debug << "pvs";
252
253        Debug << endl;
254}
255
256
257const BspTreeStatistics &BspTree::GetStatistics() const
258{
259        return mStat;
260}
261
262
263int BspTree::SplitPolygons(const Plane3 &plane,
264                                                   PolygonContainer &polys,
265                                                   PolygonContainer &frontPolys,
266                                                   PolygonContainer &backPolys,
267                                                   PolygonContainer &coincident) const
268{
269        int splits = 0;
270
271#ifdef _Debug
272        Debug << "splitting polygons of node " << this << " with plane " << mPlane << endl;
273#endif
274
275        PolygonContainer::const_iterator it, it_end = polys.end();
276
277        for (it = polys.begin(); it != polys.end(); ++ it)     
278        {
279                Polygon3 *poly = *it;
280       
281                //-- classify polygon
282                const int cf = poly->ClassifyPlane(plane, mEpsilon);
283
284                switch (cf)
285                {
286                        case Polygon3::COINCIDENT:
287                                coincident.push_back(poly);
288                                break;                 
289                        case Polygon3::FRONT_SIDE:     
290                                frontPolys.push_back(poly);
291                                break;
292                        case Polygon3::BACK_SIDE:
293                                backPolys.push_back(poly);
294                                break;
295                        case Polygon3::SPLIT:
296                                {
297                                        Polygon3 *front_piece = new Polygon3(poly->mParent);
298                                        Polygon3 *back_piece = new Polygon3(poly->mParent);
299
300                                        //-- split polygon into front and back part
301                                        poly->Split(plane,
302                                                                *front_piece,
303                                                                *back_piece,
304                                                                mEpsilon);
305                                       
306                                        ++ splits; // increase number of splits
307
308                                        //-- inherit rays from parent polygon for blocked ray criterium
309                                        poly->InheritRays(*front_piece, *back_piece);
310                               
311                                        // check if polygons still valid
312                                        if (front_piece->Valid(mEpsilon))
313                                                frontPolys.push_back(front_piece);
314                                        else
315                                                DEL_PTR(front_piece);
316                               
317                                        if (back_piece->Valid(mEpsilon))
318                                                backPolys.push_back(back_piece);
319                                        else                           
320                                                DEL_PTR(back_piece);
321                               
322#ifdef _DEBUG
323                                        Debug << "split " << *poly << endl << *front_piece << endl << *back_piece << endl;
324#endif
325                                        DEL_PTR(poly);
326                                }
327                                break;
328                        default:
329                Debug << "SHOULD NEVER COME HERE\n";
330                                break;
331                }
332        }
333
334        return splits;
335}
336
337
338void BspTreeStatistics::Print(ostream &app) const
339{
340        app << "===== BspTree statistics ===============\n";
341
342        app << setprecision(4);
343
344        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
345
346        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
347
348        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
349
350        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
351
352        app << "#N_POLYSPLITS ( Number of polygon splits )\n" << polySplits << "\n";
353
354        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits[0] + splits[1] + splits[2] << endl;
355
356        app << "#N_SPLITS ( Number of splits in axes x y z)\n";
357
358        for (int i = 0; i < 3; ++ i)
359                app << splits[i] << " ";
360        app << endl;
361
362        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
363                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
364
365        app << "#N_PMINPVSLEAVES  ( Percentage of leaves with mininimal PVS )\n"
366                << minPvsNodes * 100 / (double)Leaves() << endl;
367
368        app << "#N_PMINRAYSLEAVES  ( Percentage of leaves with minimal number of rays)\n"
369                << minRaysNodes * 100 / (double)Leaves() << endl;
370
371        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
372                << maxCostNodes * 100 / (double)Leaves() << endl;
373
374        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
375                << minProbabilityNodes * 100 / (double)Leaves() << endl;
376
377        app << "#N_PMAXRAYCONTRIBLEAVES  ( Percentage of leaves with maximal ray contribution )\n"
378                <<      maxRayContribNodes * 100 / (double)Leaves() << endl;
379
380        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
381
382        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
383
384        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
385
386        app << "#N_INPUTPOLYGONS (number of input polygons )\n" << polys << endl;
387
388        app << "#N_INVALIDLEAVES (number of invalid leaves )\n" << invalidLeaves << endl;
389
390        app << "#N_RAYS (number of rays / leaf)\n" << AvgRays() << endl;
391        //app << "#N_PVS: " << pvs << endl;
392
393        app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" <<
394                 (polys + polySplits) / (double)polys << endl;
395       
396        app << "===== END OF BspTree statistics ==========\n";
397}
398
399
400BspTree::~BspTree()
401{
402        DEL_PTR(mRoot);
403
404        // TODO must be deleted if used!!
405        //if (mGenerateViewCells) DEL_PTR(mOutOfBoundsCell);
406}
407
408BspViewCell *BspTree::GetOutOfBoundsCell()
409{
410        return mOutOfBoundsCell;
411}
412
413
414BspNode *BspTree::GetRoot() const
415{
416        return mRoot;
417}
418
419
420BspViewCell *BspTree::GetOrCreateOutOfBoundsCell()
421{
422        if (!mOutOfBoundsCell)
423        {
424                mOutOfBoundsCell = new BspViewCell();
425                mOutOfBoundsCell->SetId(-1);
426                mOutOfBoundsCell->SetValid(false);
427        }
428
429        return mOutOfBoundsCell;
430}
431
432
433void BspTree::InsertViewCell(ViewCellLeaf *viewCell)
434{
435        PolygonContainer *polys = new PolygonContainer();
436
437        // don't generate new view cell, insert this one
438        mGenerateViewCells = false;
439        // extract polygons that guide the split process
440        mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell);
441        mBox.Include(viewCell->GetBox()); // add to BSP aabb
442
443        InsertPolygons(polys);
444}
445
446
447void BspTree::InsertPolygons(PolygonContainer *polys)
448{       
449        BspTraversalStack tStack;
450
451        // traverse existing tree or create new tree
452    if (!mRoot)
453                mRoot = new BspLeaf();
454
455        tStack.push(BspTraversalData(mRoot,
456                                                                 polys,
457                                                                 0,
458                                                                 mOutOfBoundsCell,
459                                                                 new BoundedRayContainer(),
460                                                                 0,
461                                                                 mUseAreaForPvs ? mBox.SurfaceArea() : mBox.GetVolume(),
462                                                                 new BspNodeGeometry()));
463
464        while (!tStack.empty())
465        {
466                // filter polygons donw the tree
467                BspTraversalData tData = tStack.top();
468            tStack.pop();
469                       
470                if (!tData.mNode->IsLeaf())
471                {
472                        BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
473
474                        //-- filter view cell polygons down the tree until a leaf is reached
475                        if (!tData.mPolygons->empty())
476                        {
477                                PolygonContainer *frontPolys = new PolygonContainer();
478                                PolygonContainer *backPolys = new PolygonContainer();
479                                PolygonContainer coincident;
480
481                                int splits = 0;
482               
483                                // split viewcell polygons with respect to split plane
484                                splits += SplitPolygons(interior->GetPlane(),
485                                                                                *tData.mPolygons,
486                                                                                *frontPolys,
487                                                                                *backPolys,
488                                                                                coincident);
489                               
490                                // extract view cells associated with the split polygons
491                                ViewCellLeaf *frontViewCell = GetOrCreateOutOfBoundsCell();
492                                ViewCellLeaf *backViewCell = GetOrCreateOutOfBoundsCell();
493                       
494                                BspTraversalData frontData(interior->GetFront(),
495                                                                                   frontPolys,
496                                                                                   tData.mDepth + 1,
497                                                                                   mOutOfBoundsCell,   
498                                                                                   tData.mRays,
499                                                                                   tData.mPvs,
500                                                                                   mUseAreaForPvs ? mBox.SurfaceArea() : mBox.GetVolume(),
501                                                                                   new BspNodeGeometry());
502
503                                BspTraversalData backData(interior->GetBack(),
504                                                                                  backPolys,
505                                                                                  tData.mDepth + 1,
506                                                                                  mOutOfBoundsCell,     
507                                                                                  tData.mRays,
508                                                                                  tData.mPvs,
509                                                                                   mUseAreaForPvs ? mBox.SurfaceArea() : mBox.GetVolume(),
510                                                                                  new BspNodeGeometry());
511
512                                if (!mGenerateViewCells)
513                                {
514                                        ExtractViewCells(frontData,
515                                                                         backData,
516                                                                         coincident,
517                                                                         interior->mPlane);
518                                }
519
520                                // don't need coincident polygons anymore
521                                CLEAR_CONTAINER(coincident);
522
523                                mStat.polySplits += splits;
524
525                                // push the children on the stack
526                                tStack.push(frontData);
527                                tStack.push(backData);
528                        }
529
530                        // cleanup
531                        DEL_PTR(tData.mPolygons);
532                        DEL_PTR(tData.mRays);
533                }
534                else
535                {
536                        // reached leaf => subdivide current viewcell
537                        BspNode *subRoot = Subdivide(tStack, tData);
538                }
539        }
540}
541
542
543int BspTree::AddMeshToPolygons(Mesh *mesh,
544                                                           PolygonContainer &polys,
545                                                           MeshInstance *parent)
546{
547        FaceContainer::const_iterator fi, fi_end = mesh->mFaces.end();
548       
549        // copy the face data to polygons
550        for (fi = mesh->mFaces.begin(); fi != fi_end; ++ fi)
551        {
552                Polygon3 *poly = new Polygon3((*fi), mesh);
553               
554                if (poly->Valid(mEpsilon))
555                {
556                        poly->mParent = parent; // set parent intersectable
557                        polys.push_back(poly);
558                }
559                else
560                        DEL_PTR(poly);
561        }
562        return (int)mesh->mFaces.size();
563}
564
565
566int BspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
567                                                          PolygonContainer &polys,
568                                                          int maxObjects)
569{
570        int limit = (maxObjects > 0) ?
571                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
572 
573        int polysSize = 0;
574
575        for (int i = 0; i < limit; ++ i)
576        {
577                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
578                {
579                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
580                        polysSize += AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
581                }
582        }
583
584        return polysSize;
585}
586
587
588int BspTree::AddToPolygonSoup(const ObjectContainer &objects,
589                                                          PolygonContainer &polys,
590                                                          int maxObjects,
591                                                          bool addToBbox)
592{
593        int limit = (maxObjects > 0) ?
594                Min((int)objects.size(), maxObjects) : (int)objects.size();
595 
596        for (int i = 0; i < limit; ++i)
597        {
598                Intersectable *object = objects[i];
599
600                Mesh *mesh = NULL;
601
602                switch (object->Type()) // extract the meshes
603                {
604                case Intersectable::MESH_INSTANCE:
605                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
606                        break;
607                case Intersectable::VIEW_CELL:
608                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
609                        break;
610                case Intersectable::TRANSFORMED_MESH_INSTANCE:
611                        {
612                                TransformedMeshInstance *mi = dynamic_cast<TransformedMeshInstance *>(object);
613
614                                if (!mi->GetMesh())     
615                                        break;
616                                mesh = new Mesh();
617                                mi->GetTransformedMesh(*mesh);
618                               
619                                break;
620                        }
621                default:
622                        Debug << "intersectable type not supported" << endl;
623                        break;
624                }
625               
626        if (mesh) // copy the mesh data to polygons
627                {
628                        if (addToBbox)
629                                mBox.Include(object->GetBox()); // add to BSP tree aabb
630                               
631                        AddMeshToPolygons(mesh, polys, mOutOfBoundsCell);
632
633                        // cleanup
634                        if (object->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
635                                DEL_PTR(mesh);
636                }       
637        }
638
639        return (int)polys.size();
640}
641
642
643void BspTree::Construct(const ViewCellContainer &viewCells)
644{
645        mStat.nodes = 1;
646        mBox.Initialize();      // initialise bsp tree bounding box
647
648        // copy view cell meshes into one big polygon soup
649        PolygonContainer *polys = new PolygonContainer();
650        mStat.polys = AddToPolygonSoup(viewCells, *polys);
651
652        // view cells are given
653        mGenerateViewCells = false;
654        // construct tree from the view cell polygons
655        Construct(polys, new BoundedRayContainer());
656}
657
658
659void BspTree::Construct(const ObjectContainer &objects)
660{
661        mStat.nodes = 1;
662        mBox.Initialize();      // initialise bsp tree bounding box
663       
664        PolygonContainer *polys = new PolygonContainer();
665
666        mGenerateViewCells = true;
667        // copy mesh instance polygons into one big polygon soup
668        mStat.polys = AddToPolygonSoup(objects, *polys);
669
670        // construct tree from polygon soup
671        Construct(polys, new BoundedRayContainer());
672}
673
674
675void BspTree::PreprocessPolygons(PolygonContainer &polys)
676{
677        // preprocess: throw out polygons coincident to the view space box (not needed)
678        PolygonContainer boxPolys;
679        mBox.ExtractPolys(boxPolys);
680        vector<Plane3> boxPlanes;
681
682        PolygonContainer::iterator pit, pit_end = boxPolys.end();
683
684        // extract planes of box
685        // TODO: can be done more elegantly than first extracting polygons
686        // and take their planes
687        for (pit = boxPolys.begin(); pit != pit_end; ++ pit)
688        {
689                boxPlanes.push_back((*pit)->GetSupportingPlane());
690        }
691
692        pit_end = polys.end();
693
694        for (pit = polys.begin(); pit != pit_end; ++ pit)
695        {
696                vector<Plane3>::const_iterator bit, bit_end = boxPlanes.end();
697               
698                for (bit = boxPlanes.begin(); (bit != bit_end) && (*pit); ++ bit)
699                {
700                        const int cf = (*pit)->ClassifyPlane(*bit, mEpsilon);
701
702                        if (cf == Polygon3::COINCIDENT)
703                        {
704                                DEL_PTR(*pit);
705                                //Debug << "coincident!!" << endl;
706                        }
707                }
708        }
709
710        // remove deleted entries
711        for (int i = 0; i < (int)polys.size(); ++ i)
712        {
713                while (!polys[i] && (i < (int)polys.size()))
714                {
715                        swap(polys[i], polys.back());
716                        polys.pop_back();
717                }
718        }
719
720        CLEAR_CONTAINER(boxPolys);
721}
722
723
724
725void BspTree::Construct(const RayContainer &sampleRays,
726                                                AxisAlignedBox3 *forcedBoundingBox)
727{
728    mStat.nodes = 1;
729        mBox.Initialize();      // initialise BSP tree bounding box
730       
731        if (forcedBoundingBox)
732                mBox = *forcedBoundingBox;
733
734        PolygonContainer *polys = new PolygonContainer();
735        BoundedRayContainer *rays = new BoundedRayContainer();
736
737        RayContainer::const_iterator rit, rit_end = sampleRays.end();
738
739        // generate view cells
740        mGenerateViewCells = true;
741
742        long startTime = GetTime();
743
744        Debug << "**** Extracting polygons from rays ****\n";
745
746        std::map<Face *, Polygon3 *> facePolyMap;
747
748        //-- extract polygons intersected by the rays
749        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
750        {
751                Ray *ray = *rit;
752       
753                // get ray-face intersection. Store polygon representing the rays together
754                // with rays intersecting the face.
755                if (!ray->intersections.empty())
756                {
757                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->intersections[0].mObject);
758
759                        Mesh *mesh;
760                        if (obj->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
761                        {
762                                TransformedMeshInstance *tmobj =
763                                        dynamic_cast<TransformedMeshInstance *>(obj);
764                       
765                                mesh = new Mesh();
766                                tmobj->GetTransformedMesh(*mesh);
767                        }
768                        else // MeshInstance
769                        {
770                                mesh = obj->GetMesh();
771                        }
772
773                        Face *face = mesh->mFaces[ray->intersections[0].mFace];
774                        std::map<Face *, Polygon3 *>::iterator it = facePolyMap.find(face);
775
776                        if (it != facePolyMap.end())
777                        {
778                                //store rays if needed for heuristics
779                                if (mSplitPlaneStrategy & BLOCKED_RAYS)
780                                        (*it).second->mPiercingRays.push_back(ray);
781                        }
782                        else
783                        {       
784                                //store rays if needed for heuristics
785                                Polygon3 *poly = new Polygon3(face, mesh);
786                                poly->mParent = obj;
787                                polys->push_back(poly);
788
789                                if (mSplitPlaneStrategy & BLOCKED_RAYS)
790                                        poly->mPiercingRays.push_back(ray);
791
792                                facePolyMap[face] = poly;
793                        }
794
795                        // cleanup
796                        if (obj->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
797                                DEL_PTR(mesh);
798                }
799        }
800       
801        facePolyMap.clear();
802
803        // compute bounding box
804        if (!forcedBoundingBox)
805                mBox.Include(*polys);
806
807        //-- store rays
808        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
809        {
810                Ray *ray = *rit;
811        ray->SetId(-1); // reset id
812
813                float minT, maxT;
814                if (mBox.GetRaySegment(*ray, minT, maxT))
815                        rays->push_back(new BoundedRay(ray, minT, maxT));
816        }
817
818        // throw out bad polygons
819        PreprocessPolygons(*polys);
820
821        mStat.polys = (int)polys->size();
822
823        Debug << "**** Finished polygon extraction ****" << endl;
824        Debug << (int)polys->size() << " polys extracted from " << (int)sampleRays.size() << " rays" << endl;
825        Debug << "extraction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
826
827        Construct(polys, rays);
828}
829
830
831void BspTree::Construct(const ObjectContainer &objects,
832                                                const RayContainer &sampleRays,
833                                                AxisAlignedBox3 *forcedBoundingBox)
834{
835    mStat.nodes = 1;
836        mBox.Initialize();      // initialise BSP tree bounding box
837       
838        if (forcedBoundingBox)
839                mBox = *forcedBoundingBox;
840
841        BoundedRayContainer *rays = new BoundedRayContainer();
842        PolygonContainer *polys = new PolygonContainer();
843       
844        mGenerateViewCells = true;
845
846        // copy mesh instance polygons into one big polygon soup
847        mStat.polys = AddToPolygonSoup(objects, *polys, 0, !forcedBoundingBox);
848
849
850        RayContainer::const_iterator rit, rit_end = sampleRays.end();
851
852        //-- store rays
853        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
854        {
855                Ray *ray = *rit;
856        ray->SetId(-1); // reset id
857
858                float minT, maxT;
859                if (mBox.GetRaySegment(*ray, minT, maxT))
860                        rays->push_back(new BoundedRay(ray, minT, maxT));
861        }
862
863        PreprocessPolygons(*polys);
864        Debug << "tree has " << (int)polys->size() << " polys, " << (int)sampleRays.size() << " rays" << endl;
865        Construct(polys, rays);
866}
867
868
869void BspTree::Construct(PolygonContainer *polys, BoundedRayContainer *rays)
870{
871        BspTraversalStack tStack;
872
873        mRoot = new BspLeaf();
874
875        // constrruct root node geometry
876        BspNodeGeometry *geom = new BspNodeGeometry();
877        ConstructGeometry(mRoot, *geom);
878
879        BspTraversalData tData(mRoot,
880                                                   polys,
881                                                   0,
882                                                   GetOrCreateOutOfBoundsCell(),
883                                                   rays,
884                                                   ComputePvsSize(*rays),
885                                                   mUseAreaForPvs ? geom->GetArea() : geom->GetVolume(),
886                                                   geom);
887
888        mTotalCost = tData.mPvs * tData.mProbability / mBox.GetVolume();
889        mTotalPvsSize = tData.mPvs;
890       
891        mSubdivisionStats
892                        << "#ViewCells\n1\n" <<  endl
893                        << "#RenderCostDecrease\n0\n" << endl
894                        << "#TotalRenderCost\n" << mTotalCost << endl
895                        << "#AvgRenderCost\n" << mTotalPvsSize << endl;
896
897        tStack.push(tData);
898
899        // used for intermediate time measurements and progress
900        long interTime = GetTime();     
901        int nleaves = 500;
902
903        mStat.Start();
904        cout << "Constructing bsp tree ...\n";
905        long startTime = GetTime();
906        while (!tStack.empty())
907        {
908                tData = tStack.top();
909
910            tStack.pop();
911
912                // subdivide leaf node
913                BspNode *r = Subdivide(tStack, tData);
914
915                if (r == mRoot)
916            Debug << "BSP tree construction time spent at root: "
917                                  << TimeDiff(startTime, GetTime())*1e-3 << " secs" << endl;
918
919                if (mStat.Leaves() >= nleaves)
920                {
921                        nleaves += 500;
922                       
923                        cout << "leaves=" << mStat.Leaves() << endl;
924                        Debug << "needed "
925                                  << TimeDiff(interTime, GetTime())*1e-3
926                                  << " secs to create 500 leaves" << endl;
927                        interTime = GetTime();
928                }
929        }
930
931        cout << "finished\n";
932
933        mStat.Stop();
934}
935
936
937bool BspTree::TerminationCriteriaMet(const BspTraversalData &data) const
938{
939        return
940                (((int)data.mPolygons->size() <= mTermMinPolys) ||
941                 ((int)data.mRays->size() <= mTermMinRays) ||
942                 (data.mPvs <= mTermMinPvs) ||
943                 (data.mProbability <= mTermMinProbability) ||
944                 (data.mDepth >= mTermMaxDepth) ||
945                 (mStat.Leaves() >= mMaxViewCells) ||
946                 (data.GetAvgRayContribution() > mTermMaxRayContribution));
947}
948
949
950BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData)
951{
952        //-- terminate traversal 
953        if (TerminationCriteriaMet(tData))             
954        {
955                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
956       
957                BspViewCell *viewCell;
958
959                // generate new view cell for each leaf
960                if (mGenerateViewCells)
961                {
962                        viewCell = new BspViewCell();
963                }
964                else
965                {
966                        // add view cell to leaf
967                        viewCell = dynamic_cast<BspViewCell *>(tData.mViewCell);
968                }
969
970                leaf->SetViewCell(viewCell);
971                viewCell->mLeaf = leaf;
972
973                //float probability = max(0.0f, tData.mProbability);
974                float probability = tData.mProbability;
975
976                if (mUseAreaForPvs)
977                        viewCell->SetArea(probability);
978                else
979                        viewCell->SetVolume(probability);
980
981                //-- add pvs
982                if (viewCell != mOutOfBoundsCell)
983                {
984                        int conSamp = 0, sampCon = 0;
985                        AddToPvs(leaf, *tData.mRays, conSamp, sampCon);
986                       
987                        mStat.contributingSamples += conSamp;
988                        mStat.sampleContributions += sampCon;
989                }
990
991                if (1)
992                        EvaluateLeafStats(tData);
993               
994                //-- clean up
995               
996                // discard polygons
997                CLEAR_CONTAINER(*tData.mPolygons);
998                // discard rays
999                CLEAR_CONTAINER(*tData.mRays);
1000
1001                delete tData.mPolygons;
1002                delete tData.mRays;
1003                delete tData.mGeometry;
1004
1005                return leaf;
1006        }
1007
1008        //-- continue subdivision
1009        PolygonContainer coincident;
1010       
1011        BspTraversalData tFrontData(NULL, new PolygonContainer(), tData.mDepth + 1, mOutOfBoundsCell,
1012                                                                new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
1013        BspTraversalData tBackData(NULL, new PolygonContainer(), tData.mDepth + 1, mOutOfBoundsCell,
1014                                                           new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
1015
1016
1017        // create new interior node and two leaf nodes
1018        BspInterior *interior =
1019                SubdivideNode(tData, tFrontData, tBackData, coincident);
1020
1021
1022        if (1)
1023        {
1024                int pvsData = tData.mPvs;
1025
1026                float cData = (float)pvsData * tData.mProbability;
1027                float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
1028                float cBack = (float)tBackData.mPvs * tBackData.mProbability;
1029
1030                float costDecr = (cFront + cBack - cData) / mBox.GetVolume();
1031               
1032                mTotalCost += costDecr;
1033                mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - pvsData;
1034
1035                mSubdivisionStats
1036                        << "#ViewCells\n" << mStat.Leaves() << endl
1037                        << "#RenderCostDecrease\n" << -costDecr << endl
1038                        << "#TotalRenderCost\n" << mTotalCost << endl
1039                        << "#AvgRenderCost\n" << mTotalPvsSize / mStat.Leaves() << endl;
1040        }
1041
1042        // extract view cells from coincident polygons according to plane normal
1043    // only if front or back polygons are empty
1044        if (!mGenerateViewCells)
1045        {
1046                ExtractViewCells(tFrontData,
1047                                                 tBackData,
1048                                                 coincident,
1049                                                 interior->mPlane);                     
1050        }
1051
1052        // don't need coincident polygons anymory
1053        CLEAR_CONTAINER(coincident);
1054
1055        // push the children on the stack
1056        tStack.push(tFrontData);
1057        tStack.push(tBackData);
1058
1059        // cleanup
1060        DEL_PTR(tData.mNode);
1061
1062        DEL_PTR(tData.mPolygons);
1063        DEL_PTR(tData.mRays);
1064        DEL_PTR(tData.mGeometry);               
1065       
1066        return interior;
1067}
1068
1069
1070void BspTree::ExtractViewCells(BspTraversalData &frontData,
1071                                                           BspTraversalData &backData,
1072                                                           const PolygonContainer &coincident,
1073                                                           const Plane3 &splitPlane) const
1074{
1075        // if not empty, tree is further subdivided => don't have to find view cell
1076        bool foundFront = !frontData.mPolygons->empty();
1077        bool foundBack = !frontData.mPolygons->empty();
1078
1079        PolygonContainer::const_iterator it =
1080                coincident.begin(), it_end = coincident.end();
1081
1082        //-- find first view cells in front and back leafs
1083        for (; !(foundFront && foundBack) && (it != it_end); ++ it)
1084        {
1085                if (DotProd((*it)->GetNormal(), splitPlane.mNormal) > 0)
1086                {
1087                        backData.mViewCell = dynamic_cast<ViewCellLeaf *>((*it)->mParent);
1088                        foundBack = true;
1089                }
1090                else
1091                {
1092                        frontData.mViewCell = dynamic_cast<ViewCellLeaf *>((*it)->mParent);
1093                        foundFront = true;
1094                }
1095        }
1096}
1097
1098
1099BspInterior *BspTree::SubdivideNode(BspTraversalData &tData,
1100                                                                        BspTraversalData &frontData,
1101                                                                        BspTraversalData &backData,
1102                                                                        PolygonContainer &coincident)
1103{
1104        mStat.nodes += 2;
1105       
1106        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);   
1107       
1108        // select subdivision plane
1109        BspInterior *interior = new BspInterior(SelectPlane(leaf, tData));
1110       
1111       
1112#ifdef _DEBUG
1113        Debug << interior << endl;
1114#endif
1115       
1116        // subdivide rays into front and back rays
1117        SplitRays(interior->mPlane, *tData.mRays, *frontData.mRays, *backData.mRays);
1118
1119        // subdivide polygons with plane
1120        mStat.polySplits += SplitPolygons(interior->GetPlane(),
1121                                                                          *tData.mPolygons,
1122                                                                          *frontData.mPolygons,
1123                                                                          *backData.mPolygons,
1124                                                                          coincident);
1125       
1126
1127    // compute pvs
1128        frontData.mPvs = ComputePvsSize(*frontData.mRays);
1129        backData.mPvs = ComputePvsSize(*backData.mRays);
1130
1131        // split geometry and compute area
1132        if (1)
1133        {
1134                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
1135                                                                           *backData.mGeometry,
1136                                                                           interior->mPlane,
1137                                                                           mBox,
1138                                                                           //0.000000000001);
1139                                                                           mEpsilon);
1140       
1141               
1142                if (mUseAreaForPvs)
1143                {
1144                        frontData.mProbability = frontData.mGeometry->GetArea();
1145                        backData.mProbability = backData.mGeometry->GetArea();
1146                }
1147                else
1148                {
1149                        frontData.mProbability = frontData.mGeometry->GetVolume();
1150                        backData.mProbability = tData.mProbability - frontData.mProbability;
1151                }
1152        }
1153
1154        //-- create front and back leaf
1155
1156        BspInterior *parent = leaf->GetParent();
1157
1158        // replace a link from node's parent
1159        if (!leaf->IsRoot())
1160        {
1161                parent->ReplaceChildLink(leaf, interior);
1162                interior->SetParent(parent);
1163        }
1164        else // new root
1165        {
1166                mRoot = interior;
1167        }
1168
1169        // and setup child links
1170        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
1171       
1172        frontData.mNode = interior->GetFront();
1173        backData.mNode = interior->GetBack();
1174       
1175        interior->mTimeStamp = mTimeStamp ++;
1176       
1177        //DEL_PTR(leaf);
1178        return interior;
1179}
1180
1181
1182void BspTree::SortSubdivisionCandidates(const PolygonContainer &polys,
1183                                                                  const int axis,
1184                                                                  vector<SortableEntry> &splitCandidates) const
1185{
1186        splitCandidates.clear();
1187
1188        int requestedSize = 2 * (int)polys.size();
1189        // creates a sorted split candidates array 
1190        splitCandidates.reserve(requestedSize);
1191
1192        PolygonContainer::const_iterator it, it_end = polys.end();
1193
1194        AxisAlignedBox3 box;
1195
1196        // insert all queries
1197        for(it = polys.begin(); it != it_end; ++ it)
1198        {
1199                box.Initialize();
1200                box.Include(*(*it));
1201               
1202                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it));
1203                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it));
1204        }
1205
1206        stable_sort(splitCandidates.begin(), splitCandidates.end());
1207}
1208
1209
1210float BspTree::BestCostRatio(const PolygonContainer &polys,
1211                                                         const AxisAlignedBox3 &box,
1212                                                         const int axis,
1213                                                         float &position,
1214                                                         int &objectsBack,
1215                                                         int &objectsFront) const
1216{
1217        vector<SortableEntry> splitCandidates;
1218
1219        SortSubdivisionCandidates(polys, axis, splitCandidates);
1220       
1221        // go through the lists, count the number of objects left and right
1222        // and evaluate the following cost funcion:
1223        // C = ct_div_ci  + (ol + or)/queries
1224       
1225        int objectsLeft = 0, objectsRight = (int)polys.size();
1226       
1227        float minBox = box.Min(axis);
1228        float maxBox = box.Max(axis);
1229        float boxArea = box.SurfaceArea();
1230 
1231        float minBand = minBox + mSplitBorder * (maxBox - minBox);
1232        float maxBand = minBox + (1.0f - mSplitBorder) * (maxBox - minBox);
1233       
1234        float minSum = 1e20f;
1235        vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end();
1236
1237        for(ci = splitCandidates.begin(); ci != ci_end; ++ ci)
1238        {
1239                switch ((*ci).type)
1240                {
1241                        case SortableEntry::POLY_MIN:
1242                                ++ objectsLeft;
1243                                break;
1244                        case SortableEntry::POLY_MAX:
1245                            -- objectsRight;
1246                                break;
1247                        default:
1248                                break;
1249                }
1250               
1251                if ((*ci).value > minBand && (*ci).value < maxBand)
1252                {
1253                        AxisAlignedBox3 lbox = box;
1254                        AxisAlignedBox3 rbox = box;
1255                        lbox.SetMax(axis, (*ci).value);
1256                        rbox.SetMin(axis, (*ci).value);
1257
1258                        const float sum = objectsLeft * lbox.SurfaceArea() +
1259                                                          objectsRight * rbox.SurfaceArea();
1260     
1261                        if (sum < minSum)
1262                        {
1263                                minSum = sum;
1264                                position = (*ci).value;
1265
1266                                objectsBack = objectsLeft;
1267                                objectsFront = objectsRight;
1268                        }
1269                }
1270        }
1271 
1272        const float oldCost = (float)polys.size();
1273        const float newCost = mAxisAlignedCtDivCi + minSum / boxArea;
1274        const float ratio = newCost / oldCost;
1275
1276
1277#if 0
1278  Debug << "====================" << endl;
1279  Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox)
1280      << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl;
1281#endif
1282  return ratio;
1283}
1284
1285bool BspTree::SelectAxisAlignedPlane(Plane3 &plane,
1286                                                                         const PolygonContainer &polys) const
1287{
1288        AxisAlignedBox3 box;
1289        box.Initialize();
1290       
1291        // create bounding box of region
1292        box.Include(polys);
1293       
1294        int objectsBack = 0, objectsFront = 0;
1295        int axis = 0;
1296        float costRatio = MAX_FLOAT;
1297        Vector3 position;
1298
1299        //-- area subdivision
1300        for (int i = 0; i < 3; ++ i)
1301        {
1302                float p = 0;
1303                float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront);
1304               
1305                if (r < costRatio)
1306                {
1307                        costRatio = r;
1308                        axis = i;
1309                        position = p;
1310                }
1311        }
1312       
1313        if (costRatio >= mMaxCostRatio)
1314                return false;
1315
1316        Vector3 norm(0,0,0); norm[axis] = 1.0f;
1317        plane = Plane3(norm, position);
1318
1319        return true;
1320}
1321
1322
1323Plane3 BspTree::SelectPlane(BspLeaf *leaf, BspTraversalData &data)
1324{
1325        if ((!mMaxPolyCandidates || data.mPolygons->empty()) &&
1326                (!mMaxRayCandidates || data.mRays->empty()))
1327        {
1328                Debug << "Warning: No autopartition polygon candidate available\n";
1329       
1330                // return axis aligned split
1331                AxisAlignedBox3 box;
1332                box.Initialize();
1333       
1334                // create bounding box of region
1335                box.Include(*data.mPolygons);
1336
1337                const int axis = box.Size().DrivingAxis();
1338                const Vector3 position = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
1339
1340                Vector3 norm(0,0,0); norm[axis] = 1.0f;
1341                return Plane3(norm, position);
1342        }
1343       
1344        if ((mSplitPlaneStrategy & AXIS_ALIGNED) &&
1345                ((int)data.mPolygons->size() > mTermMinPolysForAxisAligned) &&
1346                ((int)data.mRays->size() > mTermMinRaysForAxisAligned) &&
1347                ((mTermMinObjectsForAxisAligned < 0) ||
1348                 (Polygon3::ParentObjectsSize(*data.mPolygons) > mTermMinObjectsForAxisAligned)))
1349        {
1350                Plane3 plane;
1351                if (SelectAxisAlignedPlane(plane, *data.mPolygons))
1352                        return plane;
1353        }
1354
1355        // simplest strategy: just take next polygon
1356        if (mSplitPlaneStrategy & RANDOM_POLYGON)
1357        {
1358        if (!data.mPolygons->empty())
1359                {
1360                        Polygon3 *nextPoly =
1361                                (*data.mPolygons)[(int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1))];
1362                        return nextPoly->GetSupportingPlane();
1363                }
1364                else
1365                {
1366                        const int candidateIdx = (int)RandomValue(0, (Real)((int)data.mRays->size() - 1));
1367                        BoundedRay *bRay = (*data.mRays)[candidateIdx];
1368
1369                        Ray *ray = bRay->mRay;
1370                                               
1371                        const Vector3 minPt = ray->Extrap(bRay->mMinT);
1372                        const Vector3 maxPt = ray->Extrap(bRay->mMaxT);
1373
1374                        const Vector3 pt = (maxPt + minPt) * 0.5;
1375
1376                        const Vector3 normal = ray->GetDir();
1377                       
1378                        return Plane3(normal, pt);
1379                }
1380
1381                return Plane3();
1382        }
1383
1384        // use heuristics to find appropriate plane
1385        return SelectPlaneHeuristics(leaf, data);
1386}
1387
1388
1389Plane3 BspTree::ChooseCandidatePlane(const BoundedRayContainer &rays) const
1390{       
1391        const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1392        BoundedRay *bRay = rays[candidateIdx];
1393        Ray *ray = bRay->mRay;
1394
1395        const Vector3 minPt = ray->Extrap(bRay->mMinT);
1396        const Vector3 maxPt = ray->Extrap(bRay->mMaxT);
1397
1398        const Vector3 pt = (maxPt + minPt) * 0.5;
1399
1400        const Vector3 normal = ray->GetDir();
1401                       
1402        return Plane3(normal, pt);
1403}
1404
1405Plane3 BspTree::ChooseCandidatePlane2(const BoundedRayContainer &rays) const
1406{       
1407        Vector3 pt[3];
1408        int idx[3];
1409        int cmaxT = 0;
1410        int cminT = 0;
1411        bool chooseMin = false;
1412
1413        for (int j = 0; j < 3; j ++)
1414        {
1415                idx[j] = (int)RandomValue(0, Real((int)rays.size() * 2 - 1));
1416                               
1417                if (idx[j] >= (int)rays.size())
1418                {
1419                        idx[j] -= (int)rays.size();             
1420                        chooseMin = (cminT < 2);
1421                }
1422                else
1423                        chooseMin = (cmaxT < 2);
1424
1425                BoundedRay *bRay = rays[idx[j]];
1426                pt[j] = chooseMin ? bRay->mRay->Extrap(bRay->mMinT) :
1427                                                        bRay->mRay->Extrap(bRay->mMaxT);
1428        }       
1429                       
1430        return Plane3(pt[0], pt[1], pt[2]);
1431}
1432
1433Plane3 BspTree::ChooseCandidatePlane3(const BoundedRayContainer &rays) const
1434{       
1435        Vector3 pt[3];
1436       
1437        int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1438        int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1439
1440        // check if rays different
1441        if (idx1 == idx2)
1442                idx2 = (idx2 + 1) % (int)rays.size();
1443
1444        const BoundedRay *ray1 = rays[idx1];
1445        const BoundedRay *ray2 = rays[idx2];
1446
1447        // normal vector of the plane parallel to both lines
1448        const Vector3 norm =
1449                Normalize(CrossProd(ray1->mRay->GetDir(), ray2->mRay->GetDir()));
1450
1451        const Vector3 orig1 = ray1->mRay->Extrap(ray1->mMinT);
1452        const Vector3 orig2 = ray2->mRay->Extrap(ray2->mMinT);
1453
1454        // vector from line 1 to line 2
1455        const Vector3 vd = orig1 - orig2;
1456       
1457        // project vector on normal to get distance
1458        const float dist = DotProd(vd, norm);
1459
1460        // point on plane lies halfway between the two planes
1461        const Vector3 planePt = orig1 + norm * dist * 0.5;
1462
1463        return Plane3(norm, planePt);
1464}
1465
1466
1467Plane3 BspTree::SelectPlaneHeuristics(BspLeaf *leaf, BspTraversalData &data)
1468{
1469        float lowestCost = MAX_FLOAT;
1470        Plane3 bestPlane;
1471        // intermediate plane
1472        Plane3 plane;
1473
1474        const int limit = Min((int)data.mPolygons->size(), mMaxPolyCandidates);
1475        int maxIdx = (int)data.mPolygons->size();
1476       
1477        for (int i = 0; i < limit; ++ i)
1478        {
1479                // assure that no index is taken twice
1480                const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));
1481                               
1482                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
1483
1484                // swap candidate to the end to avoid testing same plane
1485                std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);
1486                //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];
1487
1488                // evaluate current candidate
1489                const float candidateCost =
1490                        SplitPlaneCost(poly->GetSupportingPlane(), data);
1491
1492                if (candidateCost < lowestCost)
1493                {
1494                        bestPlane = poly->GetSupportingPlane();
1495                        lowestCost = candidateCost;
1496                }
1497        }
1498       
1499        //-- choose candidate planes extracted from rays
1500        for (int i = 0; i < mMaxRayCandidates; ++ i)
1501        {
1502                plane = ChooseCandidatePlane3(*data.mRays);
1503                const float candidateCost = SplitPlaneCost(plane, data);
1504
1505                if (candidateCost < lowestCost)
1506                {
1507                        bestPlane = plane;     
1508                        lowestCost = candidateCost;
1509                }
1510        }
1511
1512#ifdef _DEBUG
1513        Debug << "plane lowest cost: " << lowestCost << endl;
1514#endif
1515       
1516        return bestPlane;
1517}
1518
1519
1520float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1521                                                          const PolygonContainer &polys) const
1522{
1523        float val = 0;
1524
1525        float sumBalancedPolys = 0;
1526        float sumSplits = 0;
1527        float sumPolyArea = 0;
1528        float sumBalancedViewCells = 0;
1529        float sumBlockedRays = 0;
1530        float totalBlockedRays = 0;
1531        //float totalArea = 0;
1532        int totalViewCells = 0;
1533
1534        // need three unique ids for each type of view cell
1535        // for balanced view cells criterium
1536        ViewCell::NewMail();
1537        const int backId = ViewCell::sMailId;
1538        ViewCell::NewMail();
1539        const int frontId = ViewCell::sMailId;
1540        ViewCell::NewMail();
1541        const int frontAndBackId = ViewCell::sMailId;
1542
1543        bool useRand;
1544        int limit;
1545
1546        // choose test polyongs randomly if over threshold
1547        if ((int)polys.size() > mMaxTests)
1548        {
1549                useRand = true;
1550                limit = mMaxTests;
1551        }
1552        else
1553        {
1554                useRand = false;
1555                limit = (int)polys.size();
1556        }
1557
1558        for (int i = 0; i < limit; ++ i)
1559        {
1560                const int testIdx = useRand ? (int)RandomValue(0, (Real)(limit - 1)) : i;
1561
1562                Polygon3 *poly = polys[testIdx];
1563
1564        const int classification =
1565                        poly->ClassifyPlane(candidatePlane, mEpsilon);
1566
1567                if (mSplitPlaneStrategy & BALANCED_POLYS)
1568                        sumBalancedPolys += sBalancedPolysTable[classification];
1569               
1570                if (mSplitPlaneStrategy & LEAST_SPLITS)
1571                        sumSplits += sLeastPolySplitsTable[classification];
1572
1573                if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
1574                {
1575                        if (classification == Polygon3::COINCIDENT)
1576                                sumPolyArea += poly->GetArea();
1577                        //totalArea += area;
1578                }
1579               
1580                if (mSplitPlaneStrategy & BLOCKED_RAYS)
1581                {
1582                        const float blockedRays = (float)poly->mPiercingRays.size();
1583               
1584                        if (classification == Polygon3::COINCIDENT)
1585                                sumBlockedRays += blockedRays;
1586                       
1587                        totalBlockedRays += blockedRays;
1588                }
1589
1590                // assign view cells to back or front according to classificaion
1591                if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1592                {
1593                        MeshInstance *viewCell = poly->mParent;
1594               
1595                        // assure that we only count a view cell
1596                        // once for the front and once for the back side of the plane
1597                        if (classification == Polygon3::FRONT_SIDE)
1598                        {
1599                                if ((viewCell->mMailbox != frontId) &&
1600                                        (viewCell->mMailbox != frontAndBackId))
1601                                {
1602                                        sumBalancedViewCells += 1.0;
1603
1604                                        if (viewCell->mMailbox != backId)
1605                                                viewCell->mMailbox = frontId;
1606                                        else
1607                                                viewCell->mMailbox = frontAndBackId;
1608                                       
1609                                        ++ totalViewCells;
1610                                }
1611                        }
1612                        else if (classification == Polygon3::BACK_SIDE)
1613                        {
1614                                if ((viewCell->mMailbox != backId) &&
1615                                    (viewCell->mMailbox != frontAndBackId))
1616                                {
1617                                        sumBalancedViewCells -= 1.0;
1618
1619                                        if (viewCell->mMailbox != frontId)
1620                                                viewCell->mMailbox = backId;
1621                                        else
1622                                                viewCell->mMailbox = frontAndBackId;
1623
1624                                        ++ totalViewCells;
1625                                }
1626                        }
1627                }
1628        }
1629
1630        const float polysSize = (float)polys.size() + Limits::Small;
1631
1632        // all values should be approx. between 0 and 1 so they can be combined
1633        // and scaled with the factors according to their importance
1634        if (mSplitPlaneStrategy & BALANCED_POLYS)
1635                val += mBalancedPolysFactor * fabs(sumBalancedPolys) / polysSize;
1636       
1637        if (mSplitPlaneStrategy & LEAST_SPLITS) 
1638                val += mLeastSplitsFactor * sumSplits / polysSize;
1639
1640        if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
1641                // HACK: polys.size should be total area so scaling is between 0 and 1
1642                val += mLargestPolyAreaFactor * (float)polys.size() / sumPolyArea;
1643
1644        if (mSplitPlaneStrategy & BLOCKED_RAYS)
1645                if (totalBlockedRays != 0)
1646                        val += mBlockedRaysFactor * (totalBlockedRays - sumBlockedRays) / totalBlockedRays;
1647
1648        if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1649                val += mBalancedViewCellsFactor * fabs(sumBalancedViewCells) /
1650                        ((float)totalViewCells + Limits::Small);
1651       
1652        return val;
1653}
1654
1655
1656inline void BspTree::GenerateUniqueIdsForPvs()
1657{
1658        Intersectable::NewMail(); sBackId = Intersectable::sMailId;
1659        Intersectable::NewMail(); sFrontId = Intersectable::sMailId;
1660        Intersectable::NewMail(); sFrontAndBackId = Intersectable::sMailId;
1661}
1662
1663
1664float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1665                                                          const BoundedRayContainer &rays,
1666                                                          const int pvs,
1667                                                          const float probability,
1668                                                          const BspNodeGeometry &cell) const
1669{
1670        float val = 0;
1671
1672        float sumBalancedRays = 0;
1673        float sumRaySplits = 0;
1674
1675        int frontPvs = 0;
1676        int backPvs = 0;
1677
1678        // probability that view point lies in child
1679        float pOverall = 0;
1680        float pFront = 0;
1681        float pBack = 0;
1682
1683        const bool pvsUseLen = false;
1684
1685       
1686        if (mSplitPlaneStrategy & PVS)
1687        {
1688                // create unique ids for pvs heuristics
1689                GenerateUniqueIdsForPvs();
1690
1691                // construct child geometry with regard to the candidate split plane
1692                BspNodeGeometry geomFront;
1693                BspNodeGeometry geomBack;
1694
1695                const bool splitSuccessFull =
1696                        cell.SplitGeometry(geomFront,
1697                                                           geomBack,
1698                                                           candidatePlane,
1699                                                           mBox,
1700                                                           mEpsilon);
1701
1702                if (mUseAreaForPvs)
1703                {
1704                        pFront = geomFront.GetArea();
1705                        pBack = geomBack.GetArea();
1706                }
1707                else
1708                {
1709                        pFront = geomFront.GetVolume();
1710                        pBack = pOverall - pFront;
1711                }
1712               
1713               
1714                // give penalty to unbalanced split
1715                if (1 &&
1716                        (!splitSuccessFull || (pFront <= 0) || (pBack <= 0) ||
1717                        !geomFront.Valid() || !geomBack.Valid()))
1718                {
1719                        //Debug << "error f: " << pFront << " b: " << pBack << endl;
1720                        return 99999.9f;
1721                }
1722
1723                pOverall = probability;
1724        }
1725                       
1726        bool useRand;
1727        int limit;
1728
1729        // choose test polyongs randomly if over threshold
1730        if ((int)rays.size() > mMaxTests)
1731        {
1732                useRand = true;
1733                limit = mMaxTests;
1734        }
1735        else
1736        {
1737                useRand = false;
1738                limit = (int)rays.size();
1739        }
1740
1741        for (int i = 0; i < limit; ++ i)
1742        {
1743                const int testIdx = useRand ? (int)RandomValue(0, (Real)(limit - 1)) : i;
1744       
1745                BoundedRay *bRay = rays[testIdx];
1746
1747                Ray *ray = bRay->mRay;
1748                const float minT = bRay->mMinT;
1749                const float maxT = bRay->mMaxT;
1750
1751                Vector3 entP, extP;
1752
1753                const int cf =
1754                        ray->ClassifyPlane(candidatePlane, minT, maxT, entP, extP);
1755
1756                if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1757                {
1758                        sumBalancedRays += sBalancedRaysTable[cf];
1759                }
1760               
1761                if (mSplitPlaneStrategy & BALANCED_RAYS)
1762                {
1763                        sumRaySplits += sLeastRaySplitsTable[cf];
1764                }
1765
1766                if (mSplitPlaneStrategy & PVS)
1767                {
1768                        // in case the ray intersects an object
1769                        // assure that we only count the object
1770                        // once for the front and once for the back side of the plane
1771                       
1772                        // add the termination object
1773                        if (!ray->intersections.empty())
1774                                AddObjToPvs(ray->intersections[0].mObject, cf, frontPvs, backPvs);
1775                       
1776                        // add the source object
1777                        AddObjToPvs(ray->sourceObject.mObject, cf, frontPvs, backPvs);
1778                }
1779        }
1780
1781        const float raysSize = (float)rays.size() + Limits::Small;
1782
1783        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1784                val += mLeastRaySplitsFactor * sumRaySplits / raysSize;
1785
1786        if (mSplitPlaneStrategy & BALANCED_RAYS)
1787                val += mBalancedRaysFactor * fabs(sumBalancedRays) /  raysSize;
1788
1789        const float denom = pOverall * (float)pvs + Limits::Small;
1790
1791        if (mSplitPlaneStrategy & PVS)
1792        {
1793                val += mPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / denom;
1794        }
1795
1796       
1797#ifdef _DEBUG
1798        Debug << "totalpvs: " << pvs << " ptotal: " << pOverall
1799                  << " frontpvs: " << frontPvs << " pFront: " << pFront
1800                  << " backpvs: " << backPvs << " pBack: " << pBack << endl << endl;
1801#endif
1802       
1803        return val;
1804}
1805
1806void BspTree::AddObjToPvs(Intersectable *obj,
1807                                                  const int cf,
1808                                                  int &frontPvs,
1809                                                  int &backPvs) const
1810{
1811        if (!obj)
1812                return;
1813        // TODO: does this really belong to no pvs?
1814        //if (cf == Ray::COINCIDENT) return;
1815
1816        // object belongs to both PVS
1817        const bool bothSides = (cf == Ray::FRONT_BACK) ||
1818                                                   (cf == Ray::BACK_FRONT) ||
1819                                                   (cf == Ray::COINCIDENT);
1820
1821        if ((cf == Ray::FRONT) || bothSides)
1822        {
1823                if ((obj->mMailbox != sFrontId) &&
1824                        (obj->mMailbox != sFrontAndBackId))
1825                {
1826                        ++ frontPvs;
1827
1828                        if (obj->mMailbox == sBackId)
1829                                obj->mMailbox = sFrontAndBackId;       
1830                        else
1831                                obj->mMailbox = sFrontId;                                                               
1832                }
1833        }
1834       
1835        if ((cf == Ray::BACK) || bothSides)
1836        {
1837                if ((obj->mMailbox != sBackId) &&
1838                        (obj->mMailbox != sFrontAndBackId))
1839                {
1840                        ++ backPvs;
1841
1842                        if (obj->mMailbox == sFrontId)
1843                                obj->mMailbox = sFrontAndBackId;
1844                        else
1845                                obj->mMailbox = sBackId;                               
1846                }
1847        }
1848}
1849
1850
1851float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1852                                                          BspTraversalData &data) const
1853{
1854        float val = 0;
1855
1856        if (mSplitPlaneStrategy & VERTICAL_AXIS)
1857        {
1858                Vector3 tinyAxis(0,0,0); tinyAxis[mBox.Size().TinyAxis()] = 1.0f;
1859                // we put a penalty on the dot product between the "tiny" vertical axis
1860                // and the split plane axis
1861                val += mVerticalSplitsFactor *
1862                           fabs(DotProd(candidatePlane.mNormal, tinyAxis));
1863        }
1864
1865        // the following criteria loop over all polygons to find the cost value
1866        if ((mSplitPlaneStrategy & BALANCED_POLYS)      ||
1867                (mSplitPlaneStrategy & LEAST_SPLITS)        ||
1868                (mSplitPlaneStrategy & LARGEST_POLY_AREA)   ||
1869                (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) ||
1870                (mSplitPlaneStrategy & BLOCKED_RAYS))
1871        {
1872                val += SplitPlaneCost(candidatePlane, *data.mPolygons);
1873        }
1874
1875        // the following criteria loop over all rays to find the cost value
1876        if ((mSplitPlaneStrategy & BALANCED_RAYS)      ||
1877                (mSplitPlaneStrategy & LEAST_RAY_SPLITS)   ||
1878                (mSplitPlaneStrategy & PVS))
1879        {
1880                val += SplitPlaneCost(candidatePlane, *data.mRays, data.mPvs,
1881                                                          data.mProbability, *data.mGeometry);
1882        }
1883
1884        // return linear combination of the sums
1885        return val;
1886}
1887
1888void BspTree::CollectLeaves(vector<BspLeaf *> &leaves) const
1889{
1890        stack<BspNode *> nodeStack;
1891        nodeStack.push(mRoot);
1892 
1893        while (!nodeStack.empty())
1894        {
1895                BspNode *node = nodeStack.top();
1896   
1897                nodeStack.pop();
1898   
1899                if (node->IsLeaf())
1900                {
1901                        BspLeaf *leaf = (BspLeaf *)node;               
1902                        leaves.push_back(leaf);
1903                }
1904                else
1905                {
1906                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1907
1908                        nodeStack.push(interior->GetBack());
1909                        nodeStack.push(interior->GetFront());
1910                }
1911        }
1912}
1913
1914
1915AxisAlignedBox3 BspTree::GetBoundingBox() const
1916{
1917        return mBox;
1918}
1919
1920
1921void BspTree::EvaluateLeafStats(const BspTraversalData &data)
1922{
1923        // the node became a leaf -> evaluate stats for leafs
1924        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
1925
1926        // store maximal and minimal depth
1927        if (data.mDepth > mStat.maxDepth)
1928                mStat.maxDepth = data.mDepth;
1929
1930        if (data.mDepth < mStat.minDepth)
1931                mStat.minDepth = data.mDepth;
1932
1933        // accumulate depth to compute average depth
1934        mStat.accumDepth += data.mDepth;
1935        // accumulate rays to compute rays /  leaf
1936        mStat.accumRays += (int)data.mRays->size();
1937
1938        if (data.mDepth >= mTermMaxDepth)
1939                ++ mStat.maxDepthNodes;
1940
1941        if (data.mPvs < mTermMinPvs)
1942                ++ mStat.minPvsNodes;
1943
1944        if ((int)data.mRays->size() < mTermMinRays)
1945                ++ mStat.minRaysNodes;
1946
1947        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
1948                ++ mStat.maxRayContribNodes;
1949       
1950        if (data.mProbability <= mTermMinProbability)
1951                ++ mStat.minProbabilityNodes;
1952
1953#ifdef _DEBUG
1954        Debug << "BSP stats: "
1955                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
1956                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
1957                  << "Probability: " << data.mProbability << " (min: " << mTermMinProbability << "), "
1958                  << "#polygons: " << (int)data.mPolygons->size() << " (max: " << mTermMinPolys << "), "
1959                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
1960                  << "#pvs: " << leaf->GetViewCell()->GetPvs().CountObjectsInPvs() << "=, "
1961                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
1962#endif
1963}
1964
1965
1966int BspTree::_CastRay(Ray &ray)
1967{
1968        int hits = 0;
1969 
1970        stack<BspRayTraversalData> tStack;
1971 
1972        float maxt, mint;
1973
1974        if (!mBox.GetRaySegment(ray, mint, maxt))
1975                return 0;
1976
1977        ViewCell::NewMail();
1978
1979        Vector3 entp = ray.Extrap(mint);
1980        Vector3 extp = ray.Extrap(maxt);
1981 
1982        BspNode *node = mRoot;
1983        BspNode *farChild = NULL;
1984       
1985        while (1)
1986        {
1987                if (!node->IsLeaf())
1988                {
1989                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1990                       
1991                        Plane3 splitPlane = in->GetPlane();
1992                        const int entSide = splitPlane.Side(entp);
1993                        const int extSide = splitPlane.Side(extp);
1994
1995                        if (entSide < 0)
1996                        {
1997                                node = in->GetBack();
1998
1999                                if(extSide <= 0) // plane does not split ray => no far child
2000                                        continue;
2001                                       
2002                                farChild = in->GetFront(); // plane splits ray
2003
2004                        } else if (entSide > 0)
2005                        {
2006                                node = in->GetFront();
2007
2008                                if (extSide >= 0) // plane does not split ray => no far child
2009                                        continue;
2010
2011                                farChild = in->GetBack(); // plane splits ray                   
2012                        }
2013                        else // ray and plane are coincident
2014                        {
2015                                // WHAT TO DO IN THIS CASE ?
2016                                //break;
2017                                node = in->GetFront();
2018                                continue;
2019                        }
2020
2021                        // push data for far child
2022                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
2023
2024                        // find intersection of ray segment with plane
2025                        float t;
2026                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
2027                        maxt *= t;
2028                       
2029                } else // reached leaf => intersection with view cell
2030                {
2031                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2032     
2033                        if (!leaf->mViewCell->Mailed())
2034                        {
2035                                //ray.bspIntersections.push_back(Ray::BspIntersection(maxt, leaf));
2036                                leaf->mViewCell->Mail();
2037                                ++ hits;
2038                        }
2039                       
2040                        //-- fetch the next far child from the stack
2041                        if (tStack.empty())
2042                                break;
2043     
2044                        entp = extp;
2045                        mint = maxt; // NOTE: need this?
2046
2047                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
2048                                break;
2049
2050                        BspRayTraversalData &s = tStack.top();
2051
2052                        node = s.mNode;
2053                        extp = s.mExitPoint;
2054                        maxt = s.mMaxT;
2055
2056                        tStack.pop();
2057                }
2058        }
2059
2060        return hits;
2061}
2062
2063
2064int BspTree::CastLineSegment(const Vector3 &origin,
2065                                                         const Vector3 &termination,
2066                                                         ViewCellContainer &viewcells)
2067{
2068        int hits = 0;
2069        stack<BspRayTraversalData> tStack;
2070
2071        float mint = 0.0f, maxt = 1.0f;
2072
2073        //ViewCell::NewMail();
2074
2075        Vector3 entp = origin;
2076        Vector3 extp = termination;
2077
2078        BspNode *node = mRoot;
2079        BspNode *farChild = NULL;
2080
2081
2082        const float thresh = 1 ? 1e-6f : 0.0f;
2083
2084        while (1)
2085        {
2086                if (!node->IsLeaf()) 
2087                {
2088                        BspInterior *in = dynamic_cast<BspInterior *>(node);
2089
2090                        Plane3 splitPlane = in->GetPlane();
2091                       
2092                        const int entSide = splitPlane.Side(entp, thresh);
2093                        const int extSide = splitPlane.Side(extp, thresh);
2094
2095                        if (entSide < 0)
2096                        {
2097                                node = in->GetBack();
2098                               
2099                                // plane does not split ray => no far child
2100                                if (extSide <= 0)
2101                                        continue;
2102 
2103                                farChild = in->GetFront(); // plane splits ray
2104                        }
2105                        else if (entSide > 0)
2106                        {
2107                                node = in->GetFront();
2108
2109                                if (extSide >= 0) // plane does not split ray => no far child
2110                                        continue;
2111
2112                                farChild = in->GetBack(); // plane splits ray
2113                        }
2114                        else // one of the ray end points is on the plane
2115                        {       // NOTE: what to do if ray is coincident with plane?
2116                                if (extSide < 0)
2117                                        node = in->GetBack();
2118                                else //if (extSide > 0)
2119                                        node = in->GetFront();
2120                                //else break; // coincident => count no intersections
2121
2122                                continue; // no far child
2123                        }
2124
2125                        // push data for far child
2126                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
2127               
2128                        // find intersection of ray segment with plane
2129                        float t;
2130                        extp = splitPlane.FindIntersection(origin, extp, &t);
2131                        maxt *= t; 
2132                }
2133                else
2134                {
2135                        // reached leaf => intersection with view cell
2136                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2137               
2138                        if (!leaf->mViewCell->Mailed())
2139                        {
2140                                viewcells.push_back(leaf->mViewCell);
2141                                leaf->mViewCell->Mail();
2142                                ++ hits;
2143                        }
2144               
2145                        //-- fetch the next far child from the stack
2146                        if (tStack.empty())
2147                                break;
2148           
2149                        entp = extp;
2150                        mint = maxt; // NOTE: need this?
2151               
2152                        BspRayTraversalData &s = tStack.top();
2153               
2154                        node = s.mNode;
2155                        extp = s.mExitPoint;
2156                        maxt = s.mMaxT;
2157               
2158                        tStack.pop();
2159                }
2160        }
2161
2162        return hits;
2163}
2164
2165
2166void BspTree::CollectViewCells(ViewCellContainer &viewCells) const
2167{
2168        stack<BspNode *> nodeStack;
2169        nodeStack.push(mRoot);
2170
2171        ViewCell::NewMail();
2172
2173        while (!nodeStack.empty())
2174        {
2175                BspNode *node = nodeStack.top();
2176                nodeStack.pop();
2177
2178                if (node->IsLeaf())
2179                {
2180                        ViewCellLeaf *viewCell = dynamic_cast<BspLeaf *>(node)->mViewCell;
2181
2182                        if (!viewCell->Mailed())
2183                        {
2184                                viewCell->Mail();
2185                                viewCells.push_back(viewCell);
2186                        }
2187                }
2188                else
2189                {
2190                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2191
2192                        nodeStack.push(interior->GetFront());
2193                        nodeStack.push(interior->GetBack());
2194                }
2195        }
2196}
2197
2198
2199BspTreeStatistics &BspTree::GetStat()
2200{
2201        return mStat;
2202}
2203
2204
2205float BspTree::AccumulatedRayLength(BoundedRayContainer &rays) const
2206{
2207        float len = 0;
2208
2209        BoundedRayContainer::const_iterator it, it_end = rays.end();
2210
2211        for (it = rays.begin(); it != it_end; ++ it)
2212        {
2213                len += SqrDistance((*it)->mRay->Extrap((*it)->mMinT),
2214                                                   (*it)->mRay->Extrap((*it)->mMaxT));
2215        }
2216
2217        return len;
2218}
2219
2220
2221int BspTree::SplitRays(const Plane3 &plane,
2222                                           BoundedRayContainer &rays,
2223                                           BoundedRayContainer &frontRays,
2224                                           BoundedRayContainer &backRays)
2225{
2226        int splits = 0;
2227       
2228        while (!rays.empty())
2229        {
2230                BoundedRay *bRay = rays.back();
2231                Ray *ray = bRay->mRay;
2232                float minT = bRay->mMinT;
2233                float maxT = bRay->mMaxT;
2234
2235                rays.pop_back();
2236       
2237                Vector3 entP, extP;
2238
2239                const int cf =
2240                        ray->ClassifyPlane(plane, minT, maxT, entP, extP);
2241               
2242                // set id to ray classification
2243                ray->SetId(cf);
2244
2245                switch (cf)
2246                {
2247                case Ray::COINCIDENT: // TODO: should really discard ray?
2248                        frontRays.push_back(bRay);
2249                        //DEL_PTR(bRay);
2250                        break;
2251                case Ray::BACK:
2252                        backRays.push_back(bRay);
2253                        break;
2254                case Ray::FRONT:
2255                        frontRays.push_back(bRay);
2256                        break;
2257                case Ray::FRONT_BACK:
2258                        {
2259                                // find intersection of ray segment with plane
2260                                const float t = plane.FindT(ray->GetLoc(), extP);
2261                               
2262                                const float newT = t * maxT;
2263
2264                                frontRays.push_back(new BoundedRay(ray, minT, newT));
2265                                backRays.push_back(new BoundedRay(ray, newT, maxT));
2266
2267                                DEL_PTR(bRay);
2268                        }
2269                        break;
2270                case Ray::BACK_FRONT:
2271                        {
2272                                // find intersection of ray segment with plane
2273                                const float t = plane.FindT(ray->GetLoc(), extP);
2274                                const float newT = t * bRay->mMaxT;
2275
2276                                backRays.push_back(new BoundedRay(ray, minT, newT));
2277                                frontRays.push_back(new BoundedRay(ray, newT, maxT));
2278
2279                                DEL_PTR(bRay);
2280
2281                                ++ splits;
2282                        }
2283                        break;
2284                default:
2285                        Debug << "Should not come here 4" << endl;
2286                        break;
2287                }
2288        }
2289
2290        return splits;
2291}
2292
2293void BspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
2294{
2295        BspNode *lastNode;
2296
2297        do
2298        {
2299                lastNode = n;
2300
2301                // want to get planes defining geometry of this node => don't take
2302                // split plane of node itself
2303                n = n->GetParent();
2304
2305                if (n)
2306                {
2307                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
2308                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
2309
2310            if (interior->GetBack() != lastNode)
2311                                halfSpace.ReverseOrientation();
2312
2313                        halfSpaces.push_back(halfSpace);
2314                }
2315        }
2316        while (n);
2317}
2318
2319
2320
2321void BspTree::ConstructGeometry(ViewCell *vc,
2322                                                                BspNodeGeometry &vcGeom) const
2323{
2324        ViewCellContainer leaves;
2325        mViewCellsTree->CollectLeaves(vc, leaves);
2326
2327        ViewCellContainer::const_iterator it, it_end = leaves.end();
2328
2329        for (it = leaves.begin(); it != it_end; ++ it)
2330        {
2331                BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf;
2332                ConstructGeometry(l, vcGeom);
2333        }
2334}
2335
2336
2337void BspTree::ConstructGeometry(BspNode *n,
2338                                                                BspNodeGeometry &geom) const
2339{
2340        vector<Plane3> halfSpaces;
2341        ExtractHalfSpaces(n, halfSpaces);
2342
2343        PolygonContainer candidatePolys;
2344        vector<Plane3> candidatePlanes;
2345
2346        vector<Plane3>::const_iterator pit, pit_end = halfSpaces.end();
2347
2348        // bounded planes are added to the polygons
2349        for (pit = halfSpaces.begin(); pit != pit_end; ++ pit)
2350        {
2351                Polygon3 *p = GetBoundingBox().CrossSection(*pit);
2352
2353                if (p->Valid(mEpsilon))
2354                {
2355                        candidatePolys.push_back(p);
2356                        candidatePlanes.push_back(*pit);
2357                }
2358        }
2359
2360        // add faces of bounding box (also could be faces of the cell)
2361        for (int i = 0; i < 6; ++ i)
2362        {
2363                VertexContainer vertices;
2364
2365                for (int j = 0; j < 4; ++ j)
2366                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
2367
2368                Polygon3 *poly = new Polygon3(vertices);
2369
2370                candidatePolys.push_back(poly);
2371                candidatePlanes.push_back(poly->GetSupportingPlane());
2372        }
2373
2374        for (int i = 0; i < (int)candidatePolys.size(); ++ i)
2375        {
2376                // polygon is split by all other planes
2377                for (int j = 0; (j < (int)halfSpaces.size()) && candidatePolys[i]; ++ j)
2378                {
2379                        if (i == j) // polygon and plane are coincident
2380                                continue;
2381
2382                        VertexContainer splitPts;
2383                        Polygon3 *frontPoly, *backPoly;
2384
2385                        const int cf =
2386                                candidatePolys[i]->ClassifyPlane(halfSpaces[j],
2387                                                                                                 mEpsilon);
2388
2389                        switch (cf)
2390                        {
2391                                case Polygon3::SPLIT:
2392                                        frontPoly = new Polygon3();
2393                                        backPoly = new Polygon3();
2394
2395                                        candidatePolys[i]->Split(halfSpaces[j],
2396                                                                                         *frontPoly,
2397                                                                                         *backPoly,
2398                                                                                         mEpsilon);
2399
2400                                        DEL_PTR(candidatePolys[i]);
2401
2402                                        if (backPoly->Valid(mEpsilon))
2403                                                candidatePolys[i] = backPoly;
2404                                        else
2405                                                DEL_PTR(backPoly);
2406
2407                                        // outside, don't need this
2408                                        DEL_PTR(frontPoly);
2409                                        break;
2410                                // polygon outside of halfspace
2411                                case Polygon3::FRONT_SIDE:
2412                                        DEL_PTR(candidatePolys[i]);
2413                                        break;
2414                                // just take polygon as it is
2415                                case Polygon3::BACK_SIDE:
2416                                case Polygon3::COINCIDENT:
2417                                default:
2418                                        break;
2419                        }
2420                }
2421
2422                if (candidatePolys[i])
2423                {
2424                        geom.Add(candidatePolys[i], candidatePlanes[i]);
2425                }
2426        }
2427}
2428
2429
2430void BspTree::SetViewCellsManager(ViewCellsManager *vcm)
2431{
2432        mViewCellsManager = vcm;
2433}
2434
2435
2436typedef pair<BspNode *, BspNodeGeometry *> bspNodePair;
2437
2438
2439int BspTree::FindNeighbors(BspNode *n,
2440                                                   vector<BspLeaf *> &neighbors,
2441                                                   const bool onlyUnmailed) const
2442{
2443        stack<bspNodePair> nodeStack;
2444       
2445        BspNodeGeometry nodeGeom;
2446        ConstructGeometry(n, nodeGeom);
2447       
2448        // split planes from the root to this node
2449        // needed to verify that we found neighbor leaf
2450        // TODO: really needed?
2451        vector<Plane3> halfSpaces;
2452        ExtractHalfSpaces(n, halfSpaces);
2453
2454
2455        BspNodeGeometry *rgeom = new BspNodeGeometry();
2456        ConstructGeometry(mRoot, *rgeom);
2457
2458        nodeStack.push(bspNodePair(mRoot, rgeom));
2459
2460        while (!nodeStack.empty())
2461        {
2462                BspNode *node = nodeStack.top().first;
2463                BspNodeGeometry *geom = nodeStack.top().second;
2464       
2465                nodeStack.pop();
2466
2467                if (node->IsLeaf())
2468                {
2469                        // test if this leaf is in valid view space
2470                        if (node->TreeValid() &&
2471                                (node != n) &&
2472                                (!onlyUnmailed || !node->Mailed()))
2473                        {
2474                                bool isAdjacent = true;
2475
2476                                if (1)
2477                                {
2478                                        // test all planes of current node if still adjacent
2479                                        for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
2480                                        {
2481                                                const int cf =
2482                                                        Polygon3::ClassifyPlane(geom->GetPolys(),
2483                                                                                                        halfSpaces[i],
2484                                                                                                        mEpsilon);
2485
2486                                                if (cf == Polygon3::FRONT_SIDE)
2487                                                {
2488                                                        isAdjacent = false;
2489                                                }
2490                                        }
2491                                }
2492                                else
2493                                {
2494                                        // TODO: why is this wrong??
2495                                        // test all planes of current node if still adjacent
2496                                        for (int i = 0; (i < nodeGeom.Size()) && isAdjacent; ++ i)
2497                                        {
2498                                                Polygon3 *poly = nodeGeom.GetPolys()[i];
2499
2500                                                const int cf =
2501                                                        Polygon3::ClassifyPlane(geom->GetPolys(),
2502                                                                                                        poly->GetSupportingPlane(),
2503                                                                                                        mEpsilon);
2504
2505                                                if (cf == Polygon3::FRONT_SIDE)
2506                                                {
2507                                                        isAdjacent = false;
2508                                                }
2509                                        }
2510                                }
2511                                // neighbor was found
2512                                if (isAdjacent)
2513                                {       
2514                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
2515                                }
2516                        }
2517                }
2518                else
2519                {
2520                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2521
2522                        const int cf = Polygon3::ClassifyPlane(nodeGeom.GetPolys(),
2523                                                                                                   interior->GetPlane(),
2524                                                                                                   mEpsilon);
2525                       
2526                        BspNode *front = interior->GetFront();
2527                        BspNode *back = interior->GetBack();
2528           
2529                        BspNodeGeometry *fGeom = new BspNodeGeometry();
2530                        BspNodeGeometry *bGeom = new BspNodeGeometry();
2531
2532                        geom->SplitGeometry(*fGeom,
2533                                                                *bGeom,
2534                                                                interior->GetPlane(),
2535                                                                mBox,
2536                                                                //0.0000001f);
2537                                                                mEpsilon);
2538               
2539                        if (cf == Polygon3::BACK_SIDE)
2540                        {
2541                                nodeStack.push(bspNodePair(interior->GetBack(), bGeom));
2542                                DEL_PTR(fGeom);
2543                        }
2544                        else
2545                        {
2546                                if (cf == Polygon3::FRONT_SIDE)
2547                                {
2548                                        nodeStack.push(bspNodePair(interior->GetFront(), fGeom));
2549                                        DEL_PTR(bGeom);
2550                                }
2551                                else
2552                                {       // random decision
2553                                        nodeStack.push(bspNodePair(front, fGeom));
2554                                        nodeStack.push(bspNodePair(back, bGeom));
2555                                }
2556                        }
2557                }
2558       
2559                DEL_PTR(geom);
2560        }
2561
2562        return (int)neighbors.size();
2563}
2564
2565
2566BspLeaf *BspTree::GetRandomLeaf(const bool onlyUnmailed)
2567{
2568        stack<BspNode *> nodeStack;
2569       
2570        nodeStack.push(mRoot);
2571
2572        int mask = rand();
2573       
2574        while (!nodeStack.empty())
2575        {
2576                BspNode *node = nodeStack.top();
2577                nodeStack.pop();
2578               
2579                if (node->IsLeaf())
2580                {
2581                        if ( (!onlyUnmailed || !node->Mailed()) )
2582                                return dynamic_cast<BspLeaf *>(node);
2583                }
2584                else
2585                {
2586                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2587
2588                        // random decision
2589                        if (mask & 1)
2590                                nodeStack.push(interior->GetBack());
2591                        else
2592                                nodeStack.push(interior->GetFront());
2593
2594                        mask = mask >> 1;
2595                }
2596        }
2597       
2598        return NULL;
2599}
2600
2601
2602void BspTree::AddToPvs(BspLeaf *leaf,
2603                                           const BoundedRayContainer &rays,
2604                                           int &sampleContributions,
2605                                           int &contributingSamples)
2606{
2607        sampleContributions = 0;
2608        contributingSamples = 0;
2609
2610    BoundedRayContainer::const_iterator it, it_end = rays.end();
2611
2612        ViewCellLeaf *vc = leaf->GetViewCell();
2613
2614        // add contributions from samples to the PVS
2615        for (it = rays.begin(); it != it_end; ++ it)
2616        {
2617                int contribution = 0;
2618                Ray *ray = (*it)->mRay;
2619                float relContribution;
2620                if (!ray->intersections.empty())
2621                  contribution += vc->GetPvs().AddSample(ray->intersections[0].mObject,
2622                                                                                                 1.0f,
2623                                                                                                 relContribution);
2624               
2625                if (ray->sourceObject.mObject)
2626                        contribution += vc->GetPvs().AddSample(ray->sourceObject.mObject,
2627                                                                                                   1.0f,
2628                                                                                                   relContribution);
2629               
2630                if (contribution)
2631                {
2632                        sampleContributions += contribution;
2633                        ++ contributingSamples;
2634                }
2635
2636                //if (ray->mFlags & Ray::STORE_BSP_INTERSECTIONS)
2637                //      ray->bspIntersections.push_back(Ray::BspIntersection((*it)->mMinT, this));
2638        }
2639}
2640
2641
2642int BspTree::ComputePvsSize(const BoundedRayContainer &rays) const
2643{
2644        int pvsSize = 0;
2645
2646        BoundedRayContainer::const_iterator rit, rit_end = rays.end();
2647
2648        Intersectable::NewMail();
2649
2650        for (rit = rays.begin(); rit != rays.end(); ++ rit)
2651        {
2652                Ray *ray = (*rit)->mRay;
2653               
2654                if (!ray->intersections.empty())
2655                {
2656                        if (!ray->intersections[0].mObject->Mailed())
2657                        {
2658                                ray->intersections[0].mObject->Mail();
2659                                ++ pvsSize;
2660                        }
2661                }
2662                if (ray->sourceObject.mObject)
2663                {
2664                        if (!ray->sourceObject.mObject->Mailed())
2665                        {
2666                                ray->sourceObject.mObject->Mail();
2667                                ++ pvsSize;
2668                        }
2669                }
2670        }
2671
2672        return pvsSize;
2673}
2674
2675
2676float BspTree::GetEpsilon() const
2677{
2678        return mEpsilon;
2679}
2680
2681
2682int BspTree::CollectMergeCandidates(const vector<BspLeaf *> leaves,
2683                                                                        vector<MergeCandidate> &candidates)
2684{
2685        BspLeaf::NewMail();
2686       
2687        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
2688
2689        int numCandidates = 0;
2690
2691        // find merge candidates and push them into queue
2692        for (it = leaves.begin(); it != it_end; ++ it)
2693        {
2694                BspLeaf *leaf = *it;
2695               
2696                // the same leaves must not be part of two merge candidates
2697                leaf->Mail();
2698                vector<BspLeaf *> neighbors;
2699                FindNeighbors(leaf, neighbors, true);
2700
2701                vector<BspLeaf *>::const_iterator nit, nit_end = neighbors.end();
2702
2703                // TODO: test if at least one ray goes from one leaf to the other
2704                for (nit = neighbors.begin(); nit != nit_end; ++ nit)
2705                {
2706                        if ((*nit)->GetViewCell() != leaf->GetViewCell())
2707                        {
2708                                MergeCandidate mc(leaf->GetViewCell(), (*nit)->GetViewCell());
2709                                candidates.push_back(mc);
2710
2711                                ++ numCandidates;
2712                                if ((numCandidates % 1000) == 0)
2713                                {
2714                                        cout << "collected " << numCandidates << " merge candidates" << endl;
2715                                }
2716                        }
2717                }
2718        }
2719
2720        Debug << "merge queue: " << (int)candidates.size() << endl;
2721        Debug << "leaves in queue: " << numCandidates << endl;
2722       
2723
2724        return (int)leaves.size();
2725}
2726
2727
2728int BspTree::CollectMergeCandidates(const VssRayContainer &rays,
2729                                                                        vector<MergeCandidate> &candidates)
2730{
2731        ViewCell::NewMail();
2732        long startTime = GetTime();
2733       
2734        map<BspLeaf *, vector<BspLeaf*> > neighborMap;
2735        ViewCellContainer::const_iterator iit;
2736
2737        int numLeaves = 0;
2738       
2739        BspLeaf::NewMail();
2740
2741        for (int i = 0; i < (int)rays.size(); ++ i)
2742        { 
2743                VssRay *ray = rays[i];
2744       
2745                // traverse leaves stored in the rays and compare and
2746                // merge consecutive leaves (i.e., the neighbors in the tree)
2747                if (ray->mViewCells.size() < 2)
2748                        continue;
2749
2750                iit = ray->mViewCells.begin();
2751                BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*(iit ++));
2752                BspLeaf *leaf = bspVc->mLeaf;
2753               
2754                // traverse intersections
2755                // consecutive leaves are neighbors => add them to queue
2756                for (; iit != ray->mViewCells.end(); ++ iit)
2757                {
2758                        // next pair
2759                        BspLeaf *prevLeaf = leaf;
2760                        bspVc = dynamic_cast<BspViewCell *>(*iit);
2761            leaf = bspVc->mLeaf;
2762
2763                        // view space not valid or same view cell
2764                        if (!leaf->TreeValid() || !prevLeaf->TreeValid() ||
2765                                (leaf->GetViewCell() == prevLeaf->GetViewCell()))
2766                                continue;
2767
2768                vector<BspLeaf *> &neighbors = neighborMap[leaf];
2769                       
2770                        bool found = false;
2771
2772                        // both leaves inserted in queue already =>
2773                        // look if double pair already exists
2774                        if (leaf->Mailed() && prevLeaf->Mailed())
2775                        {
2776                                vector<BspLeaf *>::const_iterator it, it_end = neighbors.end();
2777                               
2778                for (it = neighbors.begin(); !found && (it != it_end); ++ it)
2779                                        if (*it == prevLeaf)
2780                                                found = true; // already in queue
2781                        }
2782               
2783                        if (!found)
2784                        {
2785                                // this pair is not in map yet
2786                                // => insert into the neighbor map and the queue
2787                                neighbors.push_back(prevLeaf);
2788                                neighborMap[prevLeaf].push_back(leaf);
2789
2790                                leaf->Mail();
2791                                prevLeaf->Mail();
2792               
2793                                MergeCandidate mc(leaf->GetViewCell(), prevLeaf->GetViewCell());
2794                               
2795                                candidates.push_back(mc);
2796
2797                                if (((int)candidates.size() % 1000) == 0)
2798                                {
2799                                        cout << "collected " << (int)candidates.size() << " merge candidates" << endl;
2800                                }
2801                        }
2802        }
2803        }
2804
2805        Debug << "neighbormap size: " << (int)neighborMap.size() << endl;
2806        Debug << "merge queue: " << (int)candidates.size() << endl;
2807        Debug << "leaves in queue: " << numLeaves << endl;
2808
2809
2810        //-- collect the leaves which haven't been found by ray casting
2811#if 0
2812        cout << "finding additional merge candidates using geometry" << endl;
2813        vector<BspLeaf *> leaves;
2814        CollectLeaves(leaves, true);
2815        Debug << "found " << (int)leaves.size() << " new leaves" << endl << endl;
2816        CollectMergeCandidates(leaves, candidates);
2817#endif
2818
2819        return numLeaves;
2820}
2821
2822
2823
2824
2825/***************************************************************/
2826/*              BspNodeGeometry Implementation                 */
2827/***************************************************************/
2828
2829
2830BspNodeGeometry::BspNodeGeometry(const BspNodeGeometry &rhs)
2831{
2832        mPolys.reserve(rhs.mPolys.size());
2833        mPlanes.reserve(rhs.mPolys.size());
2834
2835        PolygonContainer::const_iterator it, it_end = rhs.mPolys.end();
2836
2837        int i = 0;
2838
2839        for (it = rhs.mPolys.begin(); it != it_end; ++ it, ++i)
2840        {
2841                Polygon3 *poly = *it;
2842                Add(new Polygon3(*poly), rhs.mPlanes[i]);
2843        }
2844}
2845
2846
2847BspNodeGeometry& BspNodeGeometry::operator=(const BspNodeGeometry& g)
2848{
2849    if (this == &g)
2850                return *this;
2851 
2852        CLEAR_CONTAINER(mPolys);
2853
2854        mPolys.reserve(g.mPolys.size());
2855        mPlanes.reserve(g.mPolys.size());
2856
2857        PolygonContainer::const_iterator it, it_end = g.mPolys.end();
2858
2859        int i = 0;
2860
2861        for (it = g.mPolys.begin(); it != it_end; ++ it, ++ i)
2862        {
2863                Polygon3 *poly = *it;
2864                Add(new Polygon3(*poly), g.mPlanes[i]);
2865        }
2866
2867        return *this;
2868}
2869
2870
2871BspNodeGeometry::BspNodeGeometry(const PolygonContainer &polys)
2872{
2873        mPolys = polys;
2874        mPlanes.reserve(polys.size());
2875       
2876        PolygonContainer::const_iterator it, it_end = polys.end();
2877
2878        for (it = polys.begin(); it != it_end; ++ it)
2879        {
2880                Polygon3 *poly = *it;
2881                mPlanes.push_back(poly->GetSupportingPlane());
2882        }
2883}
2884
2885
2886BspNodeGeometry::~BspNodeGeometry()
2887{
2888        CLEAR_CONTAINER(mPolys);
2889}
2890
2891
2892int BspNodeGeometry::Size() const
2893{
2894        return (int)mPolys.size();
2895}
2896
2897
2898const PolygonContainer &BspNodeGeometry::GetPolys()
2899{
2900        return mPolys;
2901}
2902
2903
2904void BspNodeGeometry::Add(Polygon3 *p, const Plane3 &plane)
2905{
2906    mPolys.push_back(p);
2907        mPlanes.push_back(plane);
2908}
2909
2910
2911float BspNodeGeometry::GetArea() const
2912{
2913        return Polygon3::GetArea(mPolys);
2914}
2915
2916
2917float BspNodeGeometry::GetVolume() const
2918{
2919        //-- compute volume using tetrahedralization of the geometry
2920        //   and adding the volume of the single tetrahedrons
2921        float volume = 0;
2922        const float f = 1.0f / 6.0f;
2923
2924        PolygonContainer::const_iterator pit, pit_end = mPolys.end();
2925
2926        // note: can take arbitrary point, e.g., the origin. However,
2927        // we rather take the center of mass to prevents precision errors
2928        const Vector3 center = CenterOfMass();
2929
2930        for (pit = mPolys.begin(); pit != pit_end; ++ pit)
2931        {
2932                Polygon3 *poly = *pit;
2933                const Vector3 v0 = poly->mVertices[0] - center;
2934
2935                for (int i = 1; i < (int)poly->mVertices.size() - 1; ++ i)
2936                {
2937                        const Vector3 v1 = poly->mVertices[i] - center;
2938                        const Vector3 v2 = poly->mVertices[i + 1] - center;
2939
2940                        // more robust version using abs and the center of mass
2941                        volume += fabs (f * (DotProd(v0, CrossProd(v1, v2))));
2942                }
2943        }
2944
2945        return volume;
2946}
2947
2948
2949void BspNodeGeometry::GetBoundingBox(AxisAlignedBox3 &box) const
2950{
2951        box.Initialize();
2952        box.Include(mPolys);
2953}
2954
2955
2956int BspNodeGeometry::Side(const Plane3 &plane, const float eps) const
2957{
2958        PolygonContainer::const_iterator it, it_end = mPolys.end();
2959
2960        bool onFrontSide = false;
2961        bool onBackSide = false;
2962
2963        for (it = mPolys.begin(); it != it_end; ++ it)
2964        {
2965        const int side = (*it)->Side(plane, eps);
2966
2967                if (side == -1)
2968                        onBackSide = true;
2969                else if (side == 1)
2970                        onFrontSide = true;
2971               
2972                if ((side == 0) || (onBackSide && onFrontSide))
2973                        return 0;
2974        }
2975
2976        if (onFrontSide)
2977                return 1;
2978
2979        return -1;
2980}
2981
2982
2983int BspNodeGeometry::ComputeIntersection(const AxisAlignedBox3 &box) const
2984{
2985        // 1: box does not intersect geometry
2986        // 0: box intersects geometry
2987        // -1: box contains geometry
2988
2989        AxisAlignedBox3 boundingBox;
2990        GetBoundingBox(boundingBox);
2991
2992        // no intersections with bounding box
2993        if (!Overlap(box, boundingBox))
2994        {
2995                return 1;
2996        }
2997
2998        // box cotains bounding box of geometry >=> contains geometry
2999        if (box.Includes(boundingBox))
3000                return -1;
3001
3002        int result = 0;
3003
3004        // test geometry planes for intersections
3005        vector<Plane3>::const_iterator it, it_end = mPlanes.end();
3006
3007        for (it = mPlanes.begin(); it != it_end; ++ it)
3008        {               
3009                const int side = box.Side(*it);
3010               
3011                // box does not intersects geometry
3012                if (side == 1)
3013                {
3014                        return 1;
3015                }
3016                //if (side == 0) result = 0;
3017  }
3018
3019  return result;
3020}
3021
3022
3023Vector3 BspNodeGeometry::CenterOfMass() const
3024{
3025        int n = 0;
3026
3027        Vector3 center(0,0,0);
3028
3029        PolygonContainer::const_iterator pit, pit_end = mPolys.end();
3030
3031        for (pit = mPolys.begin(); pit != pit_end; ++ pit)
3032        {
3033                Polygon3 *poly = *pit;
3034               
3035                VertexContainer::const_iterator vit, vit_end = poly->mVertices.end();
3036
3037                for(vit = poly->mVertices.begin(); vit != vit_end; ++ vit)
3038                {
3039                        center += *vit;
3040                        ++ n;
3041                }
3042        }
3043
3044        //Debug << "center: " << center << " new " << center / (float)n << endl;
3045
3046        return center / (float)n;
3047}
3048
3049
3050bool BspNodeGeometry::Valid() const
3051{
3052        if (mPolys.size() < 4)
3053                return false;
3054       
3055        return true;
3056}
3057
3058void IncludeNodeGeomInMesh(const BspNodeGeometry &geom, Mesh &mesh)
3059{
3060        // add single polygons to mesh
3061        PolygonContainer::const_iterator it, it_end = geom.mPolys.end();
3062       
3063        for (it = geom.mPolys.begin(); it != geom.mPolys.end(); ++ it)
3064        {
3065                Polygon3 *poly = (*it);
3066                IncludePolyInMesh(*poly, mesh);
3067        }
3068}
3069
3070
3071bool BspNodeGeometry::SplitGeometry(BspNodeGeometry &front,
3072                                                                        BspNodeGeometry &back,
3073                                                                        const Plane3 &splitPlane,
3074                                                                        const AxisAlignedBox3 &box,
3075                                                                        const float epsilon) const
3076{       
3077        //-- trivial cases
3078        if (0)
3079        {
3080                const int cf = Side(splitPlane, epsilon);
3081
3082                if (cf == -1)
3083                {
3084                        back = *this;
3085                        return false;
3086                }
3087                else if (cf == 1)
3088                {
3089                        front = *this;
3090                        return false;
3091                }
3092        }
3093
3094        // get cross section of new polygon
3095        Polygon3 *planePoly = box.CrossSection(splitPlane);
3096       
3097        // split polygon with all other polygons
3098        planePoly = SplitPolygon(planePoly, epsilon);
3099
3100        bool splitsGeom = (planePoly != NULL);
3101
3102        //-- new polygon splits all other polygons
3103        for (int i = 0; i < (int)mPolys.size()/* && planePoly*/; ++ i)
3104        {
3105                /// don't use epsilon here to get exact split planes
3106                const int cf =
3107                        mPolys[i]->ClassifyPlane(splitPlane, epsilon);
3108                       
3109                switch (cf)
3110                {
3111                        case Polygon3::SPLIT:
3112                                {
3113                                        Polygon3 *poly = new Polygon3(mPolys[i]->mVertices);
3114
3115                                        Polygon3 *frontPoly = new Polygon3();
3116                                        Polygon3 *backPoly = new Polygon3();
3117                               
3118                                        poly->Split(splitPlane,
3119                                                                *frontPoly,
3120                                                                *backPoly,
3121                                                                epsilon);
3122
3123                                        DEL_PTR(poly);
3124
3125                                        if (frontPoly->Valid(epsilon))
3126                                        {
3127                                                front.Add(frontPoly, mPlanes[i]);
3128                                        }
3129                                        else
3130                                        {
3131                                                //Debug << "no f! " << endl;
3132                                                DEL_PTR(frontPoly);
3133                                        }
3134
3135                                        if (backPoly->Valid(epsilon))
3136                                        {
3137                                                back.Add(backPoly, mPlanes[i]);
3138                                        }
3139                                        else
3140                                        {
3141                                                //Debug << "no b! " << endl;
3142                                                DEL_PTR(backPoly);
3143                                        }
3144                                }
3145                               
3146                                break;
3147                        case Polygon3::BACK_SIDE:
3148                                back.Add(new Polygon3(mPolys[i]->mVertices), mPlanes[i]);
3149                                break;
3150                        case Polygon3::FRONT_SIDE:
3151                                front.Add(new Polygon3(mPolys[i]->mVertices), mPlanes[i]);
3152                                break;
3153                        // only put into back container (split should have no effect ...)
3154                        case Polygon3::COINCIDENT:
3155                                //Debug << "error should not come here" << endl;
3156                                splitsGeom = false;
3157
3158                                if (DotProd(mPlanes[i].mNormal, splitPlane.mNormal > 0))
3159                                        back.Add(new Polygon3(mPolys[i]->mVertices), mPlanes[i]);
3160                                else
3161                    front.Add(new Polygon3(mPolys[i]->mVertices), mPlanes[i]);
3162                                break;
3163                        default:
3164                                break;
3165                }
3166        }
3167
3168        //-- finally add the new polygon to the child node geometries
3169        if (planePoly)
3170        {
3171        // add polygon with reverse orientation to front cell
3172                Plane3 reversePlane(splitPlane);
3173                reversePlane.ReverseOrientation();
3174
3175                // add polygon with normal pointing into positive half space to back cell
3176                back.Add(planePoly, splitPlane);
3177                //back.mPolys.push_back(planePoly);
3178
3179                Polygon3 *reversePoly = planePoly->CreateReversePolygon();
3180                front.Add(reversePoly, reversePlane);
3181                //Debug << "poly normal : " << reversePoly->GetSupportingPlane().mNormal << " split plane normal " << reversePlane.mNormal << endl;
3182        }
3183       
3184
3185        return splitsGeom;
3186}
3187
3188
3189Polygon3 *BspNodeGeometry::SplitPolygon(Polygon3 *planePoly,
3190                                                                                const float epsilon) const
3191{
3192        if (!planePoly->Valid(epsilon))
3193        {
3194                //Debug << "not valid!!" << endl;
3195                DEL_PTR(planePoly);
3196        }
3197        // polygon is split by all other planes
3198        for (int i = 0; (i < (int)mPolys.size()) && planePoly; ++ i)
3199        {
3200                //Plane3 plane = mPolys[i]->GetSupportingPlane();
3201                Plane3 plane = mPlanes[i];
3202
3203                /// don't use epsilon here to get exact split planes
3204                const int cf =
3205                        planePoly->ClassifyPlane(plane, epsilon);
3206                       
3207                // split new polygon with all previous planes
3208                switch (cf)
3209                {
3210                        case Polygon3::SPLIT:
3211                                {
3212                                        Polygon3 *frontPoly = new Polygon3();
3213                                        Polygon3 *backPoly = new Polygon3();
3214
3215                                        planePoly->Split(plane,
3216                                                                         *frontPoly,
3217                                                                         *backPoly,
3218                                                                         epsilon);
3219                                       
3220                                        // don't need anymore
3221                                        DEL_PTR(planePoly);
3222                                        DEL_PTR(frontPoly);
3223
3224                                        // back polygon is belonging to geometry
3225                                        if (backPoly->Valid(epsilon))
3226                                                planePoly = backPoly;
3227                                        else
3228                                                DEL_PTR(backPoly);
3229                                }
3230                                break;
3231                        case Polygon3::FRONT_SIDE:
3232                                DEL_PTR(planePoly);
3233                break;
3234                        // polygon is taken as it is
3235                        case Polygon3::BACK_SIDE:
3236                        case Polygon3::COINCIDENT:
3237                        default:
3238                                break;
3239                }
3240        }
3241
3242        return planePoly;
3243}
3244
3245
3246ViewCell *BspTree::GetViewCell(const Vector3 &point)
3247{
3248  if (mRoot == NULL)
3249        return NULL;
3250 
3251
3252  stack<BspNode *> nodeStack;
3253  nodeStack.push(mRoot);
3254 
3255  ViewCellLeaf *viewcell = NULL;
3256 
3257  while (!nodeStack.empty())  {
3258        BspNode *node = nodeStack.top();
3259        nodeStack.pop();
3260       
3261        if (node->IsLeaf()) {
3262          viewcell = dynamic_cast<BspLeaf *>(node)->mViewCell;
3263          break;
3264        } else {
3265         
3266          BspInterior *interior = dynamic_cast<BspInterior *>(node);
3267               
3268          // random decision
3269          if (interior->GetPlane().Side(point) < 0)
3270                nodeStack.push(interior->GetBack());
3271          else
3272                nodeStack.push(interior->GetFront());
3273        }
3274  }
3275 
3276  return viewcell;
3277}
3278
3279
3280bool BspTree::Export(ofstream &stream)
3281{
3282        ExportNode(mRoot, stream);
3283
3284        return true;
3285}
3286
3287
3288void BspTree::ExportNode(BspNode *node, ofstream &stream)
3289{
3290        if (node->IsLeaf())
3291        {
3292                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3293                       
3294                int id = -1;
3295                if (leaf->GetViewCell() != mOutOfBoundsCell)
3296                        id = leaf->GetViewCell()->GetId();
3297
3298                stream << "<Leaf viewCellId=\"" << id << "\" />" << endl;
3299        }
3300        else
3301        {
3302                BspInterior *interior = dynamic_cast<BspInterior *>(node);
3303       
3304                Plane3 plane = interior->GetPlane();
3305                stream << "<Interior plane=\"" << plane.mNormal.x << " "
3306                           << plane.mNormal.y << " " << plane.mNormal.z << " "
3307                           << plane.mD << "\">" << endl;
3308
3309                ExportNode(interior->GetBack(), stream);
3310                ExportNode(interior->GetFront(), stream);
3311
3312                stream << "</Interior>" << endl;
3313        }
3314}
3315
3316}
Note: See TracBrowser for help on using the repository browser.