source: trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.cpp @ 473

Revision 473, 44.7 KB checked in by mattausch, 19 years ago (diff)

worked on new features,
removed Random Bug (took only 32000 values),
removed bug when choosing new candidates (totally wrong)
introduced new candidate plane method
implemented priority queue for vsp bsp

Line 
1#include "Plane3.h"
2#include "VspBspTree.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 <stack>
11#include <time.h>
12#include <iomanip>
13#include "Exporter.h"
14#include "Plane3.h"
15#include "ViewCellBsp.h"
16
17//-- static members
18/** Evaluates split plane classification with respect to the plane's
19        contribution for a minimum number of ray splits.
20*/
21const float VspBspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};
22/** Evaluates split plane classification with respect to the plane's
23        contribution for balanced rays.
24*/
25const float VspBspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0};
26
27
28int VspBspTree::sFrontId = 0;
29int VspBspTree::sBackId = 0;
30int VspBspTree::sFrontAndBackId = 0;
31
32
33/****************************************************************/
34/*                  class VspBspTree implementation             */
35/****************************************************************/
36
37VspBspTree::VspBspTree():
38mRoot(NULL),
39mPvsUseArea(true),
40mNumCriteria(0)
41{
42        mRootCell = new BspViewCell();
43
44        Randomize(); // initialise random generator for heuristics
45
46        //-- termination criteria for autopartition
47        environment->GetIntValue("VspBspTree.Termination.maxDepth", mTermMaxDepth);
48        environment->GetIntValue("VspBspTree.Termination.minPvs", mTermMinPvs);
49        environment->GetIntValue("VspBspTree.Termination.minRays", mTermMinRays);
50        environment->GetFloatValue("VspBspTree.Termination.minArea", mTermMinArea);     
51        environment->GetFloatValue("VspBspTree.Termination.maxRayContribution", mTermMaxRayContribution);
52        environment->GetFloatValue("VspBspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
53        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
54        environment->GetIntValue("VspBspTree.Termination.missTolerance", mTermMissTolerance);
55
56        //-- factors for bsp tree split plane heuristics
57        environment->GetFloatValue("VspBspTree.Factor.balancedRays", mBalancedRaysFactor);
58        environment->GetFloatValue("VspBspTree.Factor.pvs", mPvsFactor);
59        environment->GetFloatValue("VspBspTree.Termination.ct_div_ci", mCtDivCi);
60
61        //-- termination criteria for axis aligned split
62        environment->GetFloatValue("VspBspTree.Termination.AxisAligned.ct_div_ci", mAxisAlignedCtDivCi);
63        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
64       
65        environment->GetIntValue("VspBspTree.Termination.AxisAligned.minRays",
66                                                         mTermMinRaysForAxisAligned);
67       
68        //-- partition criteria
69        environment->GetIntValue("VspBspTree.maxPolyCandidates", mMaxPolyCandidates);
70        environment->GetIntValue("VspBspTree.maxRayCandidates", mMaxRayCandidates);
71        environment->GetIntValue("VspBspTree.splitPlaneStrategy", mSplitPlaneStrategy);
72        environment->GetFloatValue("VspBspTree.AxisAligned.splitBorder", mAxisAlignedSplitBorder);
73
74        environment->GetFloatValue("VspBspTree.Construction.epsilon", mEpsilon);
75        environment->GetIntValue("VspBspTree.maxTests", mMaxTests);
76
77        // maximum number of view cells
78        environment->GetIntValue("ViewCells.maxViewCells", mMaxViewCells);
79
80        //--
81        Debug << "******* VSP BSP options ******** " << endl;
82    Debug << "max depth: " << mTermMaxDepth << endl;
83        Debug << "min PVS: " << mTermMinPvs << endl;
84        Debug << "min area: " << mTermMinArea << endl;
85        Debug << "min rays: " << mTermMinRays << endl;
86        Debug << "max ray contri: " << mTermMaxRayContribution << endl;
87        //Debug << "VSP BSP mininam accumulated ray lenght: ", mTermMinAccRayLength) << endl;
88        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
89        Debug << "miss tolerance: " << mTermMissTolerance << endl;
90        Debug << "max view cells: " << mMaxViewCells << endl;
91        Debug << "max polygon candidates: " << mMaxPolyCandidates << endl;
92        Debug << "max plane candidates: " << mMaxRayCandidates << endl;
93
94        Debug << "Split plane strategy: ";
95        if (mSplitPlaneStrategy & RANDOM_POLYGON)
96                Debug << "random polygon ";
97
98        if (mSplitPlaneStrategy & AXIS_ALIGNED)
99        {
100                ++ mNumCriteria;
101                Debug << "axis aligned ";
102        }
103        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
104        {
105                ++ mNumCriteria;
106                Debug << "least ray splits ";
107        }
108        if (mSplitPlaneStrategy & BALANCED_RAYS)
109        {
110                ++ mNumCriteria;
111                Debug << "balanced rays ";
112        }
113        if (mSplitPlaneStrategy & PVS)
114        {
115                ++ mNumCriteria;
116                Debug << "pvs";
117        }
118
119        Debug << endl;
120}
121
122
123const BspTreeStatistics &VspBspTree::GetStatistics() const
124{
125        return mStat;
126}
127
128
129VspBspTree::~VspBspTree()
130{
131        DEL_PTR(mRoot);
132        DEL_PTR(mRootCell);
133}
134
135int VspBspTree::AddMeshToPolygons(Mesh *mesh,
136                                                                  PolygonContainer &polys,
137                                                                  MeshInstance *parent)
138{
139        FaceContainer::const_iterator fi;
140       
141        // copy the face data to polygons
142        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
143        {
144                Polygon3 *poly = new Polygon3((*fi), mesh);
145               
146                if (poly->Valid(mEpsilon))
147                {
148                        poly->mParent = parent; // set parent intersectable
149                        polys.push_back(poly);
150                }
151                else
152                        DEL_PTR(poly);
153        }
154        return (int)mesh->mFaces.size();
155}
156
157int VspBspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
158                                                          PolygonContainer &polys,
159                                                          int maxObjects)
160{
161        int limit = (maxObjects > 0) ?
162                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
163 
164        int polysSize = 0;
165
166        for (int i = 0; i < limit; ++ i)
167        {
168                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
169                {
170                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
171                        polysSize +=
172                                AddMeshToPolygons(viewCells[i]->GetMesh(),
173                                                                  polys,
174                                                                  viewCells[i]);
175                }
176        }
177
178        return polysSize;
179}
180
181int VspBspTree::AddToPolygonSoup(const ObjectContainer &objects,
182                                                                 PolygonContainer &polys,
183                                                                 int maxObjects)
184{
185        int limit = (maxObjects > 0) ?
186                Min((int)objects.size(), maxObjects) : (int)objects.size();
187 
188        for (int i = 0; i < limit; ++i)
189        {
190                Intersectable *object = objects[i];//*it;
191                Mesh *mesh = NULL;
192
193                switch (object->Type()) // extract the meshes
194                {
195                case Intersectable::MESH_INSTANCE:
196                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
197                        break;
198                case Intersectable::VIEW_CELL:
199                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
200                        break;
201                        // TODO: handle transformed mesh instances
202                default:
203                        Debug << "intersectable type not supported" << endl;
204                        break;
205                }
206               
207        if (mesh) // copy the mesh data to polygons
208                {
209                        mBox.Include(object->GetBox()); // add to BSP tree aabb
210                        AddMeshToPolygons(mesh, polys, mRootCell);
211                }
212        }
213
214        return (int)polys.size();
215}
216
217void VspBspTree::Construct(const VssRayContainer &sampleRays)
218{
219    mStat.nodes = 1;
220        mBox.Initialize();      // initialise BSP tree bounding box
221       
222        PolygonContainer polys;
223        RayInfoContainer *rays = new RayInfoContainer();
224
225        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
226
227        long startTime = GetTime();
228
229        Debug << "**** Extracting polygons from rays ****\n";
230
231        Intersectable::NewMail();
232
233        //-- extract polygons intersected by the rays
234        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
235        {
236                VssRay *ray = *rit;
237       
238                if (ray->mTerminationObject && !ray->mTerminationObject->Mailed())
239                {
240                        ray->mTerminationObject->Mail();
241                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mTerminationObject);
242                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
243                }
244
245                if (ray->mOriginObject && !ray->mOriginObject->Mailed())
246                {
247                        ray->mOriginObject->Mail();
248                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mOriginObject);
249                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
250                }
251        }
252
253        // compute bounding box
254        Polygon3::IncludeInBox(polys, mBox);
255
256        //-- store rays
257        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
258        {
259                VssRay *ray = *rit;
260               
261                float minT, maxT;
262
263                // TODO: not very efficient to implictly cast between rays types ...
264                if (mBox.GetRaySegment(*ray, minT, maxT))
265                {
266                        float len = ray->Length();
267                       
268                        if (!len)
269                                len = Limits::Small;
270                       
271                        rays->push_back(RayInfo(ray, minT / len, maxT / len));
272                }
273        }
274
275        mStat.polys = (int)polys.size();
276
277        Debug << "**** Finished polygon extraction ****" << endl;
278        Debug << (int)polys.size() << " polys extracted from " << (int)sampleRays.size() << " rays" << endl;
279        Debug << "extraction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
280
281        Construct(polys, rays);
282
283        // clean up polygons
284        CLEAR_CONTAINER(polys);
285}
286
287void VspBspTree::Construct(const PolygonContainer &polys, RayInfoContainer *rays)
288{
289        VspBspTraversalStack tStack;
290
291        mRoot = new BspLeaf();
292
293        // constrruct root node geometry
294        BspNodeGeometry *geom = new BspNodeGeometry();
295        ConstructGeometry(mRoot, *geom);
296
297        VspBspTraversalData tData(mRoot,
298                                                          new PolygonContainer(polys),
299                                                          0,
300                                                          rays,
301                              ComputePvsSize(*rays),
302                                                          geom->GetArea(),
303                                                          geom);
304
305        tStack.push(tData);
306
307        mStat.Start();
308        cout << "Contructing vsp bsp tree ... ";
309
310        long startTime = GetTime();
311       
312        while (!tStack.empty())
313        {
314                tData = tStack.top();
315
316            tStack.pop();
317
318                // subdivide leaf node
319                BspNode *r = Subdivide(tStack, tData);
320
321                if (r == mRoot)
322                        Debug << "VSP BSP tree construction time spent at root: "
323                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
324        }
325
326        cout << "finished\n";
327
328        mStat.Stop();
329}
330
331bool VspBspTree::TerminationCriteriaMet(const VspBspTraversalData &data,
332                                                                                const int numLeaves) const
333{
334        return
335                (((int)data.mRays->size() <= mTermMinRays) ||
336                 (data.mPvs <= mTermMinPvs)   ||
337                 (data.mArea <= mTermMinArea) ||
338                 (numLeaves >= mMaxViewCells) ||
339                // (data.GetAvgRayContribution() >= mTermMaxRayContribution) ||
340                 (data.mDepth >= mTermMaxDepth));
341}
342
343BspNode *VspBspTree::Subdivide(VspBspTraversalStack &tStack,
344                                                           VspBspTraversalData &tData)
345{
346        BspNode *newNode = tData.mNode;
347
348        if (!TerminationCriteriaMet(tData, (int)tStack.size()))
349        {
350                PolygonContainer coincident;
351       
352                VspBspTraversalData tFrontData;
353                VspBspTraversalData tBackData;
354
355                // create new interior node and two leaf nodes
356                // or return leaf as it is (if maxCostRatio missed)
357                newNode = SubdivideNode(tData, tFrontData, tBackData, coincident);
358
359                if (!newNode->IsLeaf()) //-- continue subdivision
360                {
361                        // push the children on the stack
362                        tStack.push(tFrontData);
363                        tStack.push(tBackData);
364
365                        // delete old leaf node
366                        DEL_PTR(tData.mNode);   
367                }
368        }
369       
370        //-- terminate traversal 
371        if (newNode->IsLeaf())
372        {
373                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
374       
375                // create new view cell for this leaf
376                BspViewCell *viewCell = new BspViewCell();
377                leaf->SetViewCell(viewCell);
378                viewCell->mLeaves.push_back(leaf);
379
380                //-- update pvs
381                int conSamp = 0, sampCon = 0;
382                AddToPvs(leaf, *tData.mRays, conSamp, sampCon);
383                       
384                mStat.contributingSamples += conSamp;
385                mStat.sampleContributions += sampCon;
386               
387                EvaluateLeafStats(tData);
388        }
389       
390               
391        //-- cleanup
392        DEL_PTR(tData.mPolygons);
393        DEL_PTR(tData.mRays);
394        DEL_PTR(tData.mGeometry);
395
396        return newNode;
397}
398
399BspNode *VspBspTree::SubdivideNode(VspBspTraversalData &tData,
400                                                                   VspBspTraversalData &frontData,
401                                                                   VspBspTraversalData &backData,
402                                                                   PolygonContainer &coincident)
403{
404        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
405
406        int maxCostMisses = tData.mMaxCostMisses;
407
408        // select subdivision plane
409        Plane3 splitPlane;
410        if (!SelectPlane(splitPlane, leaf, tData))
411        {
412                ++ maxCostMisses;
413
414                /*if (maxCostMisses >= mTermMissTolerance)
415                {
416                        // terminate branch because of max cost
417                        ++ mStat.maxCostNodes;
418            return leaf;
419                }*/
420        }
421
422        mStat.nodes += 2;
423
424        //-- subdivide further
425        BspInterior *interior = new BspInterior(splitPlane);
426
427#ifdef _DEBUG
428        Debug << interior << endl;
429#endif
430       
431        //-- the front and back traversal data is filled with the new values
432        frontData.mPolygons = new PolygonContainer();
433        frontData.mDepth = tData.mDepth + 1;
434        frontData.mRays = new RayInfoContainer();
435        frontData.mGeometry = new BspNodeGeometry();
436
437        backData.mPolygons = new PolygonContainer();
438        backData.mDepth = tData.mDepth + 1;
439        backData.mRays = new RayInfoContainer();
440        backData.mGeometry = new BspNodeGeometry();
441
442        // subdivide rays
443        SplitRays(interior->GetPlane(),
444                          *tData.mRays,
445                          *frontData.mRays,
446                          *backData.mRays);
447       
448        // subdivide polygons
449        mStat.splits += SplitPolygons(interior->GetPlane(),
450                                                                  *tData.mPolygons,
451                                          *frontData.mPolygons,
452                                                                  *backData.mPolygons,
453                                                                  coincident);
454
455       
456        // how often was max cost ratio missed in this branch?
457        frontData.mMaxCostMisses = maxCostMisses;
458        backData.mMaxCostMisses = maxCostMisses;
459
460        // compute pvs
461        frontData.mPvs = ComputePvsSize(*frontData.mRays);
462        backData.mPvs = ComputePvsSize(*backData.mRays);
463
464        // split geometry and compute area
465        if (1)
466        {
467                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
468                                                                           *backData.mGeometry,
469                                                                           interior->GetPlane(),
470                                                                           mBox,
471                                                                           mEpsilon);
472       
473                // area is normalized with view space area
474                frontData.mArea = frontData.mGeometry->GetArea() / mBox.SurfaceArea();
475                backData.mArea = backData.mGeometry->GetArea() / mBox.SurfaceArea();
476        }
477
478        // compute accumulated ray length
479        //frontData.mAccRayLength = AccumulatedRayLength(*frontData.mRays);
480        //backData.mAccRayLength = AccumulatedRayLength(*backData.mRays);
481
482        //-- create front and back leaf
483
484        BspInterior *parent = leaf->GetParent();
485
486        // replace a link from node's parent
487        if (!leaf->IsRoot())
488        {
489                parent->ReplaceChildLink(leaf, interior);
490                interior->SetParent(parent);
491        }
492        else // new root
493        {
494                mRoot = interior;
495        }
496
497        // and setup child links
498        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
499       
500        frontData.mNode = interior->GetFront();
501        backData.mNode = interior->GetBack();
502
503        //DEL_PTR(leaf);
504        return interior;
505}
506
507void VspBspTree::AddToPvs(BspLeaf *leaf,
508                                                  const RayInfoContainer &rays,
509                                                  int &sampleContributions,
510                                                  int &contributingSamples)
511{
512        sampleContributions = 0;
513        contributingSamples = 0;
514
515    RayInfoContainer::const_iterator it, it_end = rays.end();
516
517        ViewCell *vc = leaf->GetViewCell();
518
519        // add contributions from samples to the PVS
520        for (it = rays.begin(); it != it_end; ++ it)
521        {
522                int contribution = 0;
523                VssRay *ray = (*it).mRay;
524                       
525                if (ray->mTerminationObject)
526                        contribution += vc->GetPvs().AddSample(ray->mTerminationObject);
527               
528                if (ray->mOriginObject)
529                        contribution += vc->GetPvs().AddSample(ray->mOriginObject);
530
531                if (contribution)
532                {
533                        sampleContributions += contribution;
534                        ++ contributingSamples;
535                }
536                //leaf->mVssRays.push_back(ray);
537        }
538}
539
540void VspBspTree::SortSplitCandidates(const PolygonContainer &polys,
541                                                                         const int axis,
542                                                                         vector<SortableEntry> &splitCandidates) const
543{
544        splitCandidates.clear();
545 
546        const int requestedSize = 2 * (int)polys.size();
547       
548        // creates a sorted split candidates array 
549        splitCandidates.reserve(requestedSize);
550 
551        PolygonContainer::const_iterator it, it_end = polys.end();
552
553        AxisAlignedBox3 box;
554
555        // insert all queries
556        for(it = polys.begin(); it != it_end; ++ it)
557        {
558                box.Initialize();
559                box.Include(*(*it));
560         
561                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it));
562                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it));
563        }
564 
565        stable_sort(splitCandidates.begin(), splitCandidates.end());
566}
567
568
569float VspBspTree::BestCostRatio(const PolygonContainer &polys,
570                                                                const AxisAlignedBox3 &box,
571                                                                const int axis,
572                                                                float &position,
573                                                                int &objectsBack,
574                                int &objectsFront) const
575{
576        vector<SortableEntry> splitCandidates;
577
578        SortSplitCandidates(polys, axis, splitCandidates);
579       
580        // go through the lists, count the number of objects left and right
581        // and evaluate the following cost funcion:
582        // C = ct_div_ci  + (ol + or)/queries
583       
584        int objectsLeft = 0, objectsRight = (int)polys.size();
585       
586        float minBox = box.Min(axis);
587        float maxBox = box.Max(axis);
588        float boxArea = box.SurfaceArea();
589 
590        float minBand = minBox + mAxisAlignedSplitBorder * (maxBox - minBox);
591        float maxBand = minBox + (1.0f - mAxisAlignedSplitBorder) * (maxBox - minBox);
592       
593        float minSum = 1e20f;
594        vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end();
595
596        for(ci = splitCandidates.begin(); ci != ci_end; ++ ci)
597        {
598                switch ((*ci).type)
599                {
600                        case SortableEntry::POLY_MIN:
601                                ++ objectsLeft;
602                                break;
603                        case SortableEntry::POLY_MAX:
604                            -- objectsRight;
605                                break;
606                        default:
607                                break;
608                }
609               
610                if ((*ci).value > minBand && (*ci).value < maxBand)
611                {
612                        AxisAlignedBox3 lbox = box;
613                        AxisAlignedBox3 rbox = box;
614                        lbox.SetMax(axis, (*ci).value);
615                        rbox.SetMin(axis, (*ci).value);
616
617                        float sum = objectsLeft * lbox.SurfaceArea() +
618                                                objectsRight * rbox.SurfaceArea();
619     
620                        if (sum < minSum)
621                        {
622                                minSum = sum;
623                                position = (*ci).value;
624
625                                objectsBack = objectsLeft;
626                                objectsFront = objectsRight;
627                        }
628                }
629        }
630 
631        const float oldCost = (float)polys.size();
632        const float newCost = mAxisAlignedCtDivCi + minSum / boxArea;
633        const float ratio = newCost / oldCost;
634
635
636#if 0
637  Debug << "====================" << endl;
638  Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox)
639      << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl;
640#endif
641  return ratio;
642}
643
644bool VspBspTree::SelectAxisAlignedPlane(Plane3 &plane,
645                                        const PolygonContainer &polys) const
646{
647        AxisAlignedBox3 box;
648        box.Initialize();
649       
650        // create bounding box of region
651        Polygon3::IncludeInBox(polys, box);
652       
653        int objectsBack = 0, objectsFront = 0;
654        int axis = 0;
655        float costRatio = MAX_FLOAT;
656        Vector3 position;
657
658        //-- area subdivision
659        for (int i = 0; i < 3; ++ i)
660        {
661                float p = 0;
662                const float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront);
663               
664                if (r < costRatio)
665                {
666                        costRatio = r;
667                        axis = i;
668                        position = p;
669                }
670        }
671       
672        if (costRatio >= mTermMaxCostRatio)
673                return false;
674
675        Vector3 norm(0,0,0); norm[axis] = 1.0f;
676        plane = Plane3(norm, position);
677
678        return true;
679}
680
681bool VspBspTree::SelectPlane(Plane3 &plane,
682                                                         BspLeaf *leaf,
683                                                         VspBspTraversalData &data)
684{
685        if ((mSplitPlaneStrategy & AXIS_ALIGNED) &&
686                ((int)data.mRays->size() > mTermMinRaysForAxisAligned))
687        {       // TODO: candidates should be rays
688                return SelectAxisAlignedPlane(plane, *data.mPolygons);
689        }
690
691        // simplest strategy: just take next polygon
692        if (mSplitPlaneStrategy & RANDOM_POLYGON)
693        {
694        if (!data.mPolygons->empty())
695                {
696                        const int randIdx = (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1));
697                        Polygon3 *nextPoly = (*data.mPolygons)[randIdx];
698
699                        plane = nextPoly->GetSupportingPlane();
700                        return true;
701                }
702                else
703                {
704                        //-- choose plane on midpoint of a ray
705                        const int candidateIdx = (int)RandomValue(0, (Real)((int)data.mRays->size() - 1));
706                                                                       
707                        const Vector3 minPt = (*data.mRays)[candidateIdx].ExtrapOrigin();
708                        const Vector3 maxPt = (*data.mRays)[candidateIdx].ExtrapTermination();
709
710                        const Vector3 pt = (maxPt + minPt) * 0.5;
711
712                        const Vector3 normal = (*data.mRays)[candidateIdx].mRay->GetDir();
713                       
714                        plane = Plane3(normal, pt);
715                        return true;
716                }
717
718                return false;
719        }
720
721        // use heuristics to find appropriate plane
722        return SelectPlaneHeuristics(plane, leaf, data);
723}
724
725Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const
726{       
727        const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));
728       
729        const Vector3 minPt = rays[candidateIdx].ExtrapOrigin();
730        const Vector3 maxPt = rays[candidateIdx].ExtrapTermination();
731
732        const Vector3 pt = (maxPt + minPt) * 0.5;
733        const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir());
734
735        return Plane3(normal, pt);
736}
737
738Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const
739{       
740        Vector3 pt[3];
741       
742        int idx[3];
743        int cmaxT = 0;
744        int cminT = 0;
745        bool chooseMin = false;
746
747        for (int j = 0; j < 3; ++ j)
748        {
749                idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1));
750                       
751                if (idx[j] >= (int)rays.size())
752                {
753                        idx[j] -= (int)rays.size();
754                               
755                        chooseMin = (cminT < 2);
756                }
757                else
758                        chooseMin = (cmaxT < 2);
759
760                RayInfo rayInf = rays[idx[j]];
761                pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination();
762        }       
763
764        return Plane3(pt[0], pt[1], pt[2]);
765}
766
767Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const
768{       
769        Vector3 pt[3];
770       
771        int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
772        int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
773
774        // check if rays different
775        if (idx1 == idx2)
776                idx2 = (idx2 + 1) % (int)rays.size();
777
778        const RayInfo ray1 = rays[idx1];
779        const RayInfo ray2 = rays[idx2];
780
781        // normal vector of the plane parallel to both lines
782        const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir()));
783
784        // vector from line 1 to line 2
785        const Vector3 vd = (ray2.ExtrapOrigin() - ray1.ExtrapOrigin());
786       
787        // project vector on normal to get distance
788        const float dist = DotProd(vd, norm);
789
790        // point on plane lies halfway between the two planes
791        const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5;
792
793        return Plane3(norm, planePt);
794}
795
796bool VspBspTree::SelectPlaneHeuristics(Plane3 &bestPlane,
797                                                                           BspLeaf *leaf,
798                                                                           VspBspTraversalData &data)
799{
800        float lowestCost = MAX_FLOAT;
801        // intermediate plane
802        Plane3 plane;
803
804        const int limit = Min((int)data.mPolygons->size(), mMaxPolyCandidates);
805        int maxIdx = (int)data.mPolygons->size();
806       
807        for (int i = 0; i < limit; ++ i)
808        {
809                // assure that no index is taken twice
810                const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));
811                //Debug << "current Idx: " << maxIdx << " cand idx " << candidateIdx << endl;
812
813                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
814               
815                // swap candidate to the end to avoid testing same plane
816                std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);
817
818                //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];
819
820                // evaluate current candidate
821                const float candidateCost =
822                        SplitPlaneCost(poly->GetSupportingPlane(), data);
823
824                if (candidateCost < lowestCost)
825                {
826                        bestPlane = poly->GetSupportingPlane();
827                        lowestCost = candidateCost;
828                }
829        }
830       
831        //Debug << "lowest: " << lowestCost << endl;
832
833        //-- choose candidate planes extracted from rays
834        // we use different methods chosen with
835        // equal probability
836        for (int i = 0; i < mMaxRayCandidates; ++ i)
837        {
838                plane = ChooseCandidatePlane3(*data.mRays);
839
840                const float candidateCost = SplitPlaneCost(plane, data);
841
842                if (candidateCost < lowestCost)
843                {
844                        bestPlane = plane;     
845                        lowestCost = candidateCost;
846                }
847        }
848
849        // cost ratio miss
850        if (lowestCost > mTermMaxCostRatio)
851                return false;
852
853#ifdef _DEBUG
854        Debug << "plane lowest cost: " << lowestCost << endl;
855#endif
856
857        return true;
858}
859
860
861inline void VspBspTree::GenerateUniqueIdsForPvs()
862{
863        Intersectable::NewMail(); sBackId = ViewCell::sMailId;
864        Intersectable::NewMail(); sFrontId = ViewCell::sMailId;
865        Intersectable::NewMail(); sFrontAndBackId = ViewCell::sMailId;
866}
867
868float VspBspTree::SplitPlaneCost(const Plane3 &candidatePlane,
869                                                                 const VspBspTraversalData &data)
870{
871        float cost = 0;
872
873        float sumBalancedRays = 0;
874        float sumRaySplits = 0;
875       
876        int frontPvs = 0;
877        int backPvs = 0;
878
879        // probability that view point lies in child
880        float pOverall = 0;
881        float pFront = 0;
882        float pBack = 0;
883
884        const bool pvsUseLen = false;
885
886        if (mSplitPlaneStrategy & PVS)
887        {
888                // create unique ids for pvs heuristics
889                GenerateUniqueIdsForPvs();
890       
891                if (mPvsUseArea) // use front and back cell areas to approximate volume
892                {       
893                        // construct child geometry with regard to the candidate split plane
894                        BspNodeGeometry frontCell;
895                        BspNodeGeometry backCell;
896               
897                        data.mGeometry->SplitGeometry(frontCell,
898                                                                                  backCell,
899                                                                                  candidatePlane,
900                                                                                  mBox,
901                                                                                  mEpsilon);
902               
903                        pFront = frontCell.GetArea();
904                        pBack = backCell.GetArea();
905
906                        pOverall = data.mArea;
907                }
908        }
909               
910        int limit;
911        bool useRand;
912
913        // choose test polyongs randomly if over threshold
914        if ((int)data.mRays->size() > mMaxTests)
915        {
916                useRand = true;
917                limit = mMaxTests;
918        }
919        else
920        {
921                useRand = false;
922                limit = (int)data.mRays->size();
923        }
924
925        for (int i = 0; i < limit; ++ i)
926        {
927                const int testIdx = useRand ? (int)RandomValue(0, (Real)(limit - 1)) : i;
928                RayInfo rayInf = (*data.mRays)[testIdx];
929
930                VssRay *ray = rayInf.mRay;
931                float t;
932                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
933
934                if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
935                {
936                        sumBalancedRays += cf;
937                }
938               
939                if (mSplitPlaneStrategy & BALANCED_RAYS)
940                {
941                        if (cf == 0)
942                                ++ sumRaySplits;
943                }
944
945                if (mSplitPlaneStrategy & PVS)
946                {
947                        // in case the ray intersects an object
948                        // assure that we only count the object
949                        // once for the front and once for the back side of the plane
950                       
951                        // add the termination object
952                        AddObjToPvs(ray->mTerminationObject, cf, frontPvs, backPvs);
953                       
954                        // add the source object
955                        AddObjToPvs(ray->mOriginObject, cf, frontPvs, backPvs);
956                       
957                        // use number or length of rays to approximate volume
958                        if (!mPvsUseArea)
959                        {
960                                float len = 1;
961
962                                if (pvsUseLen) // use length of rays
963                                        len = rayInf.SqrSegmentLength();
964                       
965                                pOverall += len;
966
967                                if (cf == 1)
968                                        pFront += len;
969                                if (cf == -1)
970                                        pBack += len;
971                                if (cf == 0)
972                                {
973                                        // use length of rays to approximate volume
974                                        if (pvsUseLen)
975                                        {
976                                                float newLen = len *
977                                                        (rayInf.GetMaxT() - t) /
978                                                        (rayInf.GetMaxT() - rayInf.GetMinT());
979               
980                                                if (candidatePlane.Side(rayInf.ExtrapOrigin()) <= 0)
981                                                {
982                                                        pBack += newLen;
983                                                        pFront += len - newLen;
984                                                }
985                                                else
986                                                {
987                                                        pFront += newLen;
988                                                        pBack += len - newLen;
989                                                }
990                                        }
991                                        else
992                                        {
993                                                ++ pFront;
994                                                ++ pBack;
995                                        }
996                                }
997                        }
998                }
999        }
1000
1001        const float raysSize = (float)data.mRays->size() + Limits::Small;
1002       
1003        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1004                cost += mLeastRaySplitsFactor * sumRaySplits / raysSize;
1005
1006        if (mSplitPlaneStrategy & BALANCED_RAYS)
1007                cost += mBalancedRaysFactor * fabs(sumBalancedRays) /  raysSize;
1008       
1009        // pvs criterium
1010        if (mSplitPlaneStrategy & PVS)
1011        {
1012                const float oldCost = pOverall * (float)data.mPvs + Limits::Small;
1013
1014                cost += mPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / oldCost;
1015
1016                // give penalty to unbalanced split
1017                if (0)
1018                if (((pFront * 0.2 + Limits::Small) > pBack) ||
1019                        (pFront < (pBack * 0.2 + Limits::Small)))
1020                        cost += 0.5;
1021        }
1022
1023#ifdef _DEBUG
1024//      Debug << "totalpvs: " << pvs << " ptotal: " << pOverall
1025//                << " frontpvs: " << frontPvs << " pFront: " << pFront
1026//                << " backpvs: " << backPvs << " pBack: " << pBack << endl << endl;
1027#endif
1028
1029        // normalize by number of criteria
1030        return cost / (float)(mNumCriteria + Limits::Small);
1031}
1032
1033void VspBspTree::AddObjToPvs(Intersectable *obj,
1034                                                         const int cf,
1035                                                         int &frontPvs,
1036                                                         int &backPvs) const
1037{
1038        if (!obj)
1039                return;
1040        // TODO: does this really belong to no pvs?
1041        //if (cf == Ray::COINCIDENT) return;
1042
1043        // object belongs to both PVS
1044        if (cf >= 0)
1045        {
1046                if ((obj->mMailbox != sFrontId) &&
1047                        (obj->mMailbox != sFrontAndBackId))
1048                {
1049                        ++ frontPvs;
1050
1051                        if (obj->mMailbox == sBackId)
1052                                obj->mMailbox = sFrontAndBackId;       
1053                        else
1054                                obj->mMailbox = sFrontId;                                                               
1055                }
1056        }
1057       
1058        if (cf <= 0)
1059        {
1060                if ((obj->mMailbox != sBackId) &&
1061                        (obj->mMailbox != sFrontAndBackId))
1062                {
1063                        ++ backPvs;
1064
1065                        if (obj->mMailbox == sFrontId)
1066                                obj->mMailbox = sFrontAndBackId;
1067                        else
1068                                obj->mMailbox = sBackId;                               
1069                }
1070        }
1071}
1072
1073void VspBspTree::CollectLeaves(vector<BspLeaf *> &leaves) const
1074{
1075        stack<BspNode *> nodeStack;
1076        nodeStack.push(mRoot);
1077 
1078        while (!nodeStack.empty())
1079        {
1080                BspNode *node = nodeStack.top();
1081   
1082                nodeStack.pop();
1083   
1084                if (node->IsLeaf())
1085                {
1086                        BspLeaf *leaf = (BspLeaf *)node;               
1087                        leaves.push_back(leaf);
1088                }
1089                else
1090                {
1091                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1092
1093                        nodeStack.push(interior->GetBack());
1094                        nodeStack.push(interior->GetFront());
1095                }
1096        }
1097}
1098
1099AxisAlignedBox3 VspBspTree::GetBoundingBox() const
1100{
1101        return mBox;
1102}
1103
1104BspNode *VspBspTree::GetRoot() const
1105{
1106        return mRoot;
1107}
1108
1109void VspBspTree::EvaluateLeafStats(const VspBspTraversalData &data)
1110{
1111        // the node became a leaf -> evaluate stats for leafs
1112        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
1113
1114        // store maximal and minimal depth
1115        if (data.mDepth > mStat.maxDepth)
1116                mStat.maxDepth = data.mDepth;
1117
1118        if (data.mDepth < mStat.minDepth)
1119                mStat.minDepth = data.mDepth;
1120
1121        // accumulate depth to compute average depth
1122        mStat.accumDepth += data.mDepth;
1123       
1124
1125        if (data.mDepth >= mTermMaxDepth)
1126                ++ mStat.maxDepthNodes;
1127
1128        if (data.mPvs < mTermMinPvs)
1129                ++ mStat.minPvsNodes;
1130
1131        if ((int)data.mRays->size() < mTermMinRays)
1132                ++ mStat.minRaysNodes;
1133
1134        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
1135                ++ mStat.maxRayContribNodes;
1136       
1137        if (data.mGeometry->GetArea() <= mTermMinArea)
1138                ++ mStat.minAreaNodes;
1139
1140#ifdef _DEBUG
1141        Debug << "BSP stats: "
1142                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
1143                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
1144                  << "Area: " << data.mArea << " (min: " << mTermMinArea << "), "
1145                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
1146                  << "#pvs: " << leaf->GetViewCell()->GetPvs().GetSize() << "=, "
1147                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
1148#endif
1149}
1150
1151int VspBspTree::CastRay(Ray &ray)
1152{
1153        int hits = 0;
1154 
1155        stack<BspRayTraversalData> tStack;
1156 
1157        float maxt, mint;
1158
1159        if (!mBox.GetRaySegment(ray, mint, maxt))
1160                return 0;
1161
1162        Intersectable::NewMail();
1163
1164        Vector3 entp = ray.Extrap(mint);
1165        Vector3 extp = ray.Extrap(maxt);
1166 
1167        BspNode *node = mRoot;
1168        BspNode *farChild = NULL;
1169       
1170        while (1)
1171        {
1172                if (!node->IsLeaf())
1173                {
1174                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1175
1176                        Plane3 splitPlane = in->GetPlane();
1177                        const int entSide = splitPlane.Side(entp);
1178                        const int extSide = splitPlane.Side(extp);
1179
1180                        if (entSide < 0)
1181                        {
1182                                node = in->GetBack();
1183
1184                                if(extSide <= 0) // plane does not split ray => no far child
1185                                        continue;
1186                                       
1187                                farChild = in->GetFront(); // plane splits ray
1188
1189                        } else if (entSide > 0)
1190                        {
1191                                node = in->GetFront();
1192
1193                                if (extSide >= 0) // plane does not split ray => no far child
1194                                        continue;
1195
1196                                farChild = in->GetBack(); // plane splits ray                   
1197                        }
1198                        else // ray and plane are coincident
1199                        {
1200                                // WHAT TO DO IN THIS CASE ?
1201                                //break;
1202                                node = in->GetFront();
1203                                continue;
1204                        }
1205
1206                        // push data for far child
1207                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1208
1209                        // find intersection of ray segment with plane
1210                        float t;
1211                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
1212                        maxt *= t;
1213                       
1214                } else // reached leaf => intersection with view cell
1215                {
1216                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1217     
1218                        if (!leaf->GetViewCell()->Mailed())
1219                        {
1220                                //ray.bspIntersections.push_back(Ray::VspBspIntersection(maxt, leaf));
1221                                leaf->GetViewCell()->Mail();
1222                                ++ hits;
1223                        }
1224                       
1225                        //-- fetch the next far child from the stack
1226                        if (tStack.empty())
1227                                break;
1228     
1229                        entp = extp;
1230                        mint = maxt; // NOTE: need this?
1231
1232                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
1233                                break;
1234
1235                        BspRayTraversalData &s = tStack.top();
1236
1237                        node = s.mNode;
1238                        extp = s.mExitPoint;
1239                        maxt = s.mMaxT;
1240
1241                        tStack.pop();
1242                }
1243        }
1244
1245        return hits;
1246}
1247
1248bool VspBspTree::Export(const string filename)
1249{
1250        Exporter *exporter = Exporter::GetExporter(filename);
1251
1252        if (exporter)
1253        {
1254                //exporter->ExportVspBspTree(*this);
1255                return true;
1256        }       
1257
1258        return false;
1259}
1260
1261void VspBspTree::CollectViewCells(ViewCellContainer &viewCells) const
1262{
1263        stack<BspNode *> nodeStack;
1264        nodeStack.push(mRoot);
1265
1266        ViewCell::NewMail();
1267
1268        while (!nodeStack.empty())
1269        {
1270                BspNode *node = nodeStack.top();
1271                nodeStack.pop();
1272
1273                if (node->IsLeaf())
1274                {
1275                        ViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
1276
1277                        if (!viewCell->Mailed())
1278                        {
1279                                viewCell->Mail();
1280                                viewCells.push_back(viewCell);
1281                        }
1282                }
1283                else
1284                {
1285                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1286
1287                        nodeStack.push(interior->GetFront());
1288                        nodeStack.push(interior->GetBack());
1289                }
1290        }
1291}
1292
1293void VspBspTree::EvaluateViewCellsStats(ViewCellsStatistics &stat) const
1294{
1295        stat.Reset();
1296
1297        stack<BspNode *> nodeStack;
1298        nodeStack.push(mRoot);
1299
1300        ViewCell::NewMail();
1301
1302        // exclude root cell
1303        mRootCell->Mail();
1304
1305        while (!nodeStack.empty())
1306        {
1307                BspNode *node = nodeStack.top();
1308                nodeStack.pop();
1309
1310                if (node->IsLeaf())
1311                {
1312                        ++ stat.leaves;
1313
1314                        BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
1315
1316                        if (!viewCell->Mailed())
1317                        {
1318                                viewCell->Mail();
1319                               
1320                                ++ stat.viewCells;
1321                                const int pvsSize = viewCell->GetPvs().GetSize();
1322
1323                stat.pvs += pvsSize;
1324
1325                                if (pvsSize < 1)
1326                                        ++ stat.emptyPvs;
1327
1328                                if (pvsSize > stat.maxPvs)
1329                                        stat.maxPvs = pvsSize;
1330
1331                                if (pvsSize < stat.minPvs)
1332                                        stat.minPvs = pvsSize;
1333
1334                                if ((int)viewCell->mLeaves.size() > stat.maxLeaves)
1335                                        stat.maxLeaves = (int)viewCell->mLeaves.size();         
1336                        }
1337                }
1338                else
1339                {
1340                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1341
1342                        nodeStack.push(interior->GetFront());
1343                        nodeStack.push(interior->GetBack());
1344                }
1345        }
1346}
1347
1348BspTreeStatistics &VspBspTree::GetStat()
1349{
1350        return mStat;
1351}
1352
1353float VspBspTree::AccumulatedRayLength(const RayInfoContainer &rays) const
1354{
1355        float len = 0;
1356
1357        RayInfoContainer::const_iterator it, it_end = rays.end();
1358
1359        for (it = rays.begin(); it != it_end; ++ it)
1360                len += (*it).SegmentLength();
1361
1362        return len;
1363}
1364
1365int VspBspTree::SplitRays(const Plane3 &plane,
1366                                                  RayInfoContainer &rays,
1367                                                  RayInfoContainer &frontRays,
1368                                                  RayInfoContainer &backRays)
1369{
1370        int splits = 0;
1371
1372        while (!rays.empty())
1373        {
1374                RayInfo bRay = rays.back();
1375                rays.pop_back();
1376
1377                VssRay *ray = bRay.mRay;
1378                float t;
1379
1380                        // get classification and receive new t
1381                const int cf = bRay.ComputeRayIntersection(plane, t);
1382       
1383                switch (cf)
1384                {
1385                case -1:
1386                        backRays.push_back(bRay);
1387                        break;
1388                case 1:
1389                        frontRays.push_back(bRay);
1390                        break;
1391                case 0:
1392                        //-- split ray
1393                        //--  look if start point behind or in front of plane
1394                        if (plane.Side(bRay.ExtrapOrigin()) <= 0)
1395                        {       
1396                                backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1397                                frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1398                        }
1399                        else
1400                        {
1401                                frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1402                                backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1403                        }
1404                        break;
1405                default:
1406                        Debug << "Should not come here 4" << endl;
1407                        break;
1408                }
1409        }
1410
1411        return splits;
1412}
1413
1414void VspBspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
1415{
1416        BspNode *lastNode;
1417
1418        do
1419        {
1420                lastNode = n;
1421
1422                // want to get planes defining geometry of this node => don't take
1423                // split plane of node itself
1424                n = n->GetParent();
1425               
1426                if (n)
1427                {
1428                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
1429                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
1430
1431            if (interior->GetFront() != lastNode)
1432                                halfSpace.ReverseOrientation();
1433
1434                        halfSpaces.push_back(halfSpace);
1435                }
1436        }
1437        while (n);
1438}
1439
1440void VspBspTree::ConstructGeometry(BspNode *n,
1441                                                                   BspNodeGeometry &cell) const
1442{
1443        PolygonContainer polys;
1444        ConstructGeometry(n, polys);
1445        cell.mPolys = polys;
1446}
1447
1448void VspBspTree::ConstructGeometry(BspNode *n,
1449                                                                   PolygonContainer &cell) const
1450{
1451        vector<Plane3> halfSpaces;
1452        ExtractHalfSpaces(n, halfSpaces);
1453
1454        PolygonContainer candidatePolys;
1455
1456        // bounded planes are added to the polygons (reverse polygons
1457        // as they have to be outfacing
1458        for (int i = 0; i < (int)halfSpaces.size(); ++ i)
1459        {
1460                Polygon3 *p = GetBoundingBox().CrossSection(halfSpaces[i]);
1461               
1462                if (p->Valid(mEpsilon))
1463                {
1464                        candidatePolys.push_back(p->CreateReversePolygon());
1465                        DEL_PTR(p);
1466                }
1467        }
1468
1469        // add faces of bounding box (also could be faces of the cell)
1470        for (int i = 0; i < 6; ++ i)
1471        {
1472                VertexContainer vertices;
1473       
1474                for (int j = 0; j < 4; ++ j)
1475                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
1476
1477                candidatePolys.push_back(new Polygon3(vertices));
1478        }
1479
1480        for (int i = 0; i < (int)candidatePolys.size(); ++ i)
1481        {
1482                // polygon is split by all other planes
1483                for (int j = 0; (j < (int)halfSpaces.size()) && candidatePolys[i]; ++ j)
1484                {
1485                        if (i == j) // polygon and plane are coincident
1486                                continue;
1487
1488                        VertexContainer splitPts;
1489                        Polygon3 *frontPoly, *backPoly;
1490
1491                        const int cf =
1492                                candidatePolys[i]->ClassifyPlane(halfSpaces[j],
1493                                                                                                 mEpsilon);
1494                       
1495                        switch (cf)
1496                        {
1497                                case Polygon3::SPLIT:
1498                                        frontPoly = new Polygon3();
1499                                        backPoly = new Polygon3();
1500
1501                                        candidatePolys[i]->Split(halfSpaces[j],
1502                                                                                         *frontPoly,
1503                                                                                         *backPoly,
1504                                                                                         mEpsilon);
1505
1506                                        DEL_PTR(candidatePolys[i]);
1507
1508                                        if (frontPoly->Valid(mEpsilon))
1509                                                candidatePolys[i] = frontPoly;
1510                                        else
1511                                                DEL_PTR(frontPoly);
1512
1513                                        DEL_PTR(backPoly);
1514                                        break;
1515                                case Polygon3::BACK_SIDE:
1516                                        DEL_PTR(candidatePolys[i]);
1517                                        break;
1518                                // just take polygon as it is
1519                                case Polygon3::FRONT_SIDE:
1520                                case Polygon3::COINCIDENT:
1521                                default:
1522                                        break;
1523                        }
1524                }
1525               
1526                if (candidatePolys[i])
1527                        cell.push_back(candidatePolys[i]);
1528        }
1529}
1530
1531void VspBspTree::ConstructGeometry(BspViewCell *vc, PolygonContainer &vcGeom) const
1532{
1533        vector<BspLeaf *> leaves = vc->mLeaves;
1534
1535        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
1536
1537        for (it = leaves.begin(); it != it_end; ++ it)
1538                ConstructGeometry(*it, vcGeom);
1539}
1540
1541int VspBspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
1542                                                   const bool onlyUnmailed) const
1543{
1544        PolygonContainer cell;
1545
1546        ConstructGeometry(n, cell);
1547
1548        stack<BspNode *> nodeStack;
1549        nodeStack.push(mRoot);
1550               
1551        // planes needed to verify that we found neighbor leaf.
1552        vector<Plane3> halfSpaces;
1553        ExtractHalfSpaces(n, halfSpaces);
1554
1555        while (!nodeStack.empty())
1556        {
1557                BspNode *node = nodeStack.top();
1558                nodeStack.pop();
1559
1560                if (node->IsLeaf())
1561                {
1562            if (node != n && (!onlyUnmailed || !node->Mailed()))
1563                        {
1564                                // test all planes of current node if candidate really
1565                                // is neighbour
1566                                PolygonContainer neighborCandidate;
1567                                ConstructGeometry(node, neighborCandidate);
1568                               
1569                                bool isAdjacent = true;
1570                                for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
1571                                {
1572                                        const int cf =
1573                                                Polygon3::ClassifyPlane(neighborCandidate,
1574                                                                                                halfSpaces[i],
1575                                                                                                mEpsilon);
1576
1577                                        if (cf == Polygon3::BACK_SIDE)
1578                                                isAdjacent = false;
1579                                }
1580
1581                                if (isAdjacent)
1582                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
1583
1584                                CLEAR_CONTAINER(neighborCandidate);
1585                        }
1586                }
1587                else
1588                {
1589                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1590       
1591                        const int cf = Polygon3::ClassifyPlane(cell,
1592                                                                                                   interior->GetPlane(),
1593                                                                                                   mEpsilon);
1594
1595                        if (cf == Polygon3::FRONT_SIDE)
1596                                nodeStack.push(interior->GetFront());
1597                        else
1598                                if (cf == Polygon3::BACK_SIDE)
1599                                        nodeStack.push(interior->GetBack());
1600                                else
1601                                {
1602                                        // random decision
1603                                        nodeStack.push(interior->GetBack());
1604                                        nodeStack.push(interior->GetFront());
1605                                }
1606                }
1607        }
1608       
1609        CLEAR_CONTAINER(cell);
1610        return (int)neighbors.size();
1611}
1612
1613BspLeaf *VspBspTree::GetRandomLeaf(const Plane3 &halfspace)
1614{
1615    stack<BspNode *> nodeStack;
1616        nodeStack.push(mRoot);
1617       
1618        int mask = rand();
1619 
1620        while (!nodeStack.empty())
1621        {
1622                BspNode *node = nodeStack.top();
1623                nodeStack.pop();
1624         
1625                if (node->IsLeaf())
1626                {
1627                        return dynamic_cast<BspLeaf *>(node);
1628                }
1629                else
1630                {
1631                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1632                       
1633                        BspNode *next;
1634       
1635                        PolygonContainer cell;
1636
1637                        // todo: not very efficient: constructs full cell everytime
1638                        ConstructGeometry(interior, cell);
1639
1640                        const int cf = Polygon3::ClassifyPlane(cell, halfspace, mEpsilon);
1641
1642                        if (cf == Polygon3::BACK_SIDE)
1643                                next = interior->GetFront();
1644                        else
1645                                if (cf == Polygon3::FRONT_SIDE)
1646                                        next = interior->GetFront();
1647                        else
1648                        {
1649                                // random decision
1650                                if (mask & 1)
1651                                        next = interior->GetBack();
1652                                else
1653                                        next = interior->GetFront();
1654                                mask = mask >> 1;
1655                        }
1656
1657                        nodeStack.push(next);
1658                }
1659        }
1660       
1661        return NULL;
1662}
1663
1664BspLeaf *VspBspTree::GetRandomLeaf(const bool onlyUnmailed)
1665{
1666        stack<BspNode *> nodeStack;
1667       
1668        nodeStack.push(mRoot);
1669
1670        int mask = rand();
1671       
1672        while (!nodeStack.empty())
1673        {
1674                BspNode *node = nodeStack.top();
1675                nodeStack.pop();
1676               
1677                if (node->IsLeaf())
1678                {
1679                        if ( (!onlyUnmailed || !node->Mailed()) )
1680                                return dynamic_cast<BspLeaf *>(node);
1681                }
1682                else
1683                {
1684                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1685
1686                        // random decision
1687                        if (mask & 1)
1688                                nodeStack.push(interior->GetBack());
1689                        else
1690                                nodeStack.push(interior->GetFront());
1691
1692                        mask = mask >> 1;
1693                }
1694        }
1695       
1696        return NULL;
1697}
1698
1699int VspBspTree::ComputePvsSize(const RayInfoContainer &rays) const
1700{
1701        int pvsSize = 0;
1702
1703        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1704
1705        Intersectable::NewMail();
1706
1707        for (rit = rays.begin(); rit != rays.end(); ++ rit)
1708        {
1709                VssRay *ray = (*rit).mRay;
1710               
1711                if (ray->mOriginObject)
1712                {
1713                        if (!ray->mOriginObject->Mailed())
1714                        {
1715                                ray->mOriginObject->Mail();
1716                                ++ pvsSize;
1717                        }
1718                }
1719                if (ray->mTerminationObject)
1720                {
1721                        if (!ray->mTerminationObject->Mailed())
1722                        {
1723                                ray->mTerminationObject->Mail();
1724                                ++ pvsSize;
1725                        }
1726                }
1727        }
1728
1729        return pvsSize;
1730}
1731
1732float VspBspTree::GetEpsilon() const
1733{
1734        return mEpsilon;
1735}
1736
1737BspViewCell *VspBspTree::GetRootCell() const
1738{
1739        return mRootCell;
1740}
1741
1742int VspBspTree::SplitPolygons(const Plane3 &plane,
1743                                                          PolygonContainer &polys,
1744                                                          PolygonContainer &frontPolys,
1745                                                          PolygonContainer &backPolys,
1746                                                          PolygonContainer &coincident) const
1747{
1748        int splits = 0;
1749
1750        while (!polys.empty())
1751        {
1752                Polygon3 *poly = polys.back();
1753                polys.pop_back();
1754
1755                // classify polygon
1756                const int cf = poly->ClassifyPlane(plane, mEpsilon);
1757
1758                switch (cf)
1759                {
1760                        case Polygon3::COINCIDENT:
1761                                coincident.push_back(poly);
1762                                break;                 
1763                        case Polygon3::FRONT_SIDE:     
1764                                frontPolys.push_back(poly);
1765                                break;
1766                        case Polygon3::BACK_SIDE:
1767                                backPolys.push_back(poly);
1768                                break;
1769                        case Polygon3::SPLIT:
1770                                backPolys.push_back(poly);
1771                                frontPolys.push_back(poly);
1772                                ++ splits;
1773                                break;
1774                        default:
1775                Debug << "SHOULD NEVER COME HERE\n";
1776                                break;
1777                }
1778        }
1779
1780        return splits;
1781}
1782
1783
1784int VspBspTree::CastLineSegment(const Vector3 &origin,
1785                                                                const Vector3 &termination,
1786                                                                vector<ViewCell *> &viewcells)
1787{
1788        int hits = 0;
1789        stack<BspRayTraversalData> tStack;
1790 
1791        float mint = 0.0f, maxt = 1.0f;
1792 
1793        Intersectable::NewMail();
1794 
1795        Vector3 entp = origin;
1796        Vector3 extp = termination;
1797 
1798        BspNode *node = mRoot;
1799        BspNode *farChild = NULL;
1800 
1801        while (1)
1802        {
1803                if (!node->IsLeaf()) 
1804                {
1805                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1806         
1807                        Plane3 splitPlane = in->GetPlane();
1808                        const int entSide = splitPlane.Side(entp);
1809                        const int extSide = splitPlane.Side(extp);
1810         
1811                        if (entSide < 0)
1812                        {
1813                                node = in->GetBack();
1814               
1815                                if(extSide <= 0) // plane does not split ray => no far child
1816                                        continue;
1817               
1818                                farChild = in->GetFront(); // plane splits ray
1819                        } else if (entSide > 0)
1820                        {
1821                                node = in->GetFront();
1822                 
1823                                if (extSide >= 0) // plane does not split ray => no far child
1824                                        continue;
1825                 
1826                                farChild = in->GetBack(); // plane splits ray                   
1827                        }
1828                        else // ray and plane are coincident
1829                        {
1830                                // WHAT TO DO IN THIS CASE ?
1831                                //break;
1832                                node = in->GetFront();
1833                                continue;
1834                        }
1835         
1836                        // push data for far child
1837                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1838         
1839                        // find intersection of ray segment with plane
1840                        float t;
1841                        extp = splitPlane.FindIntersection(origin, extp, &t);
1842                        maxt *= t;
1843         
1844                } else
1845                {
1846                        // reached leaf => intersection with view cell
1847                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1848         
1849                        if (!leaf->GetViewCell()->Mailed())
1850                        {
1851                                viewcells.push_back(leaf->GetViewCell());
1852                                leaf->GetViewCell()->Mail();
1853                                ++ hits;
1854                        }
1855         
1856                        //-- fetch the next far child from the stack
1857                        if (tStack.empty())
1858                                break;
1859     
1860                        entp = extp;
1861                        mint = maxt; // NOTE: need this?
1862         
1863                       
1864                        BspRayTraversalData &s = tStack.top();
1865           
1866                        node = s.mNode;
1867                        extp = s.mExitPoint;
1868                        maxt = s.mMaxT;
1869         
1870                        tStack.pop();
1871                }
1872        }
1873        return hits;
1874}
Note: See TracBrowser for help on using the repository browser.