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

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