source: GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.cpp @ 1329

Revision 1329, 19.4 KB checked in by mattausch, 18 years ago (diff)
Line 
1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "ViewCell.h"
6#include "Plane3.h"
7#include "HierarchyManager.h"
8#include "Mesh.h"
9#include "common.h"
10#include "Environment.h"
11#include "Polygon3.h"
12#include "Ray.h"
13#include "AxisAlignedBox3.h"
14#include "Exporter.h"
15#include "Plane3.h"
16#include "ViewCellsManager.h"
17#include "Beam.h"
18#include "KdTree.h"
19#include "IntersectableWrapper.h"
20#include "VspTree.h"
21#include "OspTree.h"
22#include "BvHierarchy.h"
23
24
25namespace GtpVisibilityPreprocessor {
26
27
28#define USE_FIXEDPOINT_T 0
29
30
31/*******************************************************************/
32/*              class HierarchyManager implementation              */
33/*******************************************************************/
34
35
36HierarchyManager::HierarchyManager(VspTree *vspTree,
37                                                                   const int objectSpaceSubdivisionType):
38mObjectSpaceSubdivisionType(objectSpaceSubdivisionType),
39mVspTree(vspTree),
40mOspTree(NULL),
41mBvHierarchy(NULL)
42{
43        switch(mObjectSpaceSubdivisionType)
44        {
45        case KD_BASED_OBJ_SUBDIV:
46                mOspTree = new OspTree();
47                mOspTree->mVspTree = mVspTree;
48               
49                Debug << "creating osp tree" << endl;
50                break;
51        case BV_BASED_OBJ_SUBDIV:
52        mBvHierarchy = new BvHierarchy();
53                mBvHierarchy->mVspTree = mVspTree;
54               
55                Debug << "creating bv hierachy" << endl;
56                break;
57        default:
58                break;
59        }
60
61        if (mVspTree)
62                mVspTree->mHierarchyManager = this;
63
64        ParseEnvironment();
65}
66
67
68HierarchyManager::HierarchyManager(VspTree *vspTree, KdTree *kdTree):
69mObjectSpaceSubdivisionType(KD_BASED_OBJ_SUBDIV),
70mVspTree(vspTree),
71mBvHierarchy(NULL)
72{
73        mOspTree = new OspTree(*kdTree);
74        mOspTree->mVspTree = mVspTree;
75
76        Debug << "creating osp tree" << endl;
77
78        if (mVspTree)
79                mVspTree->mHierarchyManager = this;
80
81        ParseEnvironment();
82}
83
84
85void HierarchyManager::ParseEnvironment()
86{
87        char subdivisionStatsLog[100];
88        Environment::GetSingleton()->GetStringValue("Hierarchy.subdivisionStats",
89                subdivisionStatsLog);
90        mSubdivisionStats.open(subdivisionStatsLog);
91
92        Environment::GetSingleton()->GetFloatValue(
93                "Hierarchy.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);
94        Environment::GetSingleton()->GetIntValue(
95                "Hierarchy.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);
96
97        Environment::GetSingleton()->GetIntValue(
98                "Hierarchy.Termination.maxLeaves", mTermMaxLeaves);
99
100        Environment::GetSingleton()->GetIntValue(
101                "Hierarchy.Construction.type", mConstructionType);
102
103        Environment::GetSingleton()->GetIntValue(
104                "Hierarchy.Construction.minDepthForOsp", mMinDepthForObjectSpaceSubdivion);
105       
106        Environment::GetSingleton()->GetBoolValue(
107                "Hierarchy.Construction.repairQueue", mRepairQueue);
108
109        Debug << "******** Hierachy Manager Parameters ***********" << endl;
110        Debug << "max leaves: " << mTermMaxLeaves << endl;
111        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
112        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
113        Debug << "construction type: " << mConstructionType << endl;
114        Debug << "min depth for object space subdivision: " << mMinDepthForObjectSpaceSubdivion << endl;
115        Debug << "repair queue: " << mRepairQueue << endl;
116}
117
118
119HierarchyManager::~HierarchyManager()
120{
121        DEL_PTR(mOspTree);
122        //DEL_PTR(mVspTree);
123        DEL_PTR(mBvHierarchy);
124}
125
126
127void HierarchyManager::SetViewCellsManager(ViewCellsManager *vcm)
128{
129        mVspTree->SetViewCellsManager(vcm);
130
131        if (mOspTree)
132                mOspTree->SetViewCellsManager(vcm);
133        if (mBvHierarchy)
134                mBvHierarchy->SetViewCellsManager(vcm);
135}
136
137
138void HierarchyManager::SetViewCellsTree(ViewCellsTree *vcTree)
139{
140        mVspTree->SetViewCellsTree(vcTree);
141}
142
143
144SubdivisionCandidate *HierarchyManager::NextSubdivisionCandidate()
145{
146        SubdivisionCandidate *splitCandidate = mTQueue.Top();
147        mTQueue.Pop();
148
149        return splitCandidate;
150}
151
152
153void HierarchyManager::EvalSubdivisionStats(const SubdivisionCandidate &tData)
154{
155        const float costDecr = tData.GetRenderCostDecrease();
156
157        switch (mObjectSpaceSubdivisionType)
158        {
159        case KD_BASED_OBJ_SUBDIV:
160                AddSubdivisionStats(mOspTree->mOspStats.Leaves() + mVspTree->mVspStats.Leaves(),
161                                                        costDecr,
162                                                        mTotalCost
163                                                        );
164                break;
165        case BV_BASED_OBJ_SUBDIV:
166                AddSubdivisionStats(mBvHierarchy->mBvhStats.Leaves() + mVspTree->mVspStats.Leaves(),
167                                                        costDecr,
168                                                        mTotalCost
169                                                        );
170                break;
171        default:
172                AddSubdivisionStats(mVspTree->mVspStats.Leaves(),
173                                                        costDecr,
174                                                        mTotalCost
175                                                        );
176                break;
177        }
178}
179
180
181void HierarchyManager::AddSubdivisionStats(const int splits,
182                                                                                   const float renderCostDecr,
183                                                                                   const float totalRenderCost)
184{
185        mSubdivisionStats
186                        << "#Splits\n" << splits << endl
187                        << "#RenderCostDecrease\n" << renderCostDecr << endl
188                        << "#TotalRenderCost\n" << totalRenderCost << endl;
189                        //<< "#AvgRenderCost\n" << avgRenderCost << endl;
190}
191
192
193bool HierarchyManager::GlobalTerminationCriteriaMet(SubdivisionCandidate *candidate) const
194{
195        return (0
196                || (mHierarchyStats.Leaves() >= mTermMaxLeaves)
197                //|| (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
198                ||      candidate->GlobalTerminationCriteriaMet()
199                );
200}
201
202
203void HierarchyManager::Construct(const VssRayContainer &sampleRays,
204                                                                 const ObjectContainer &objects,
205                                                                 AxisAlignedBox3 *forcedViewSpace)
206{
207       
208        mHierarchyStats.Reset();
209        mHierarchyStats.Start();
210       
211        mTotalCost = (float)objects.size();
212        Debug << "setting total cost to " << mTotalCost << endl;
213
214        const long startTime = GetTime();
215        cout << "Constructing view space / object space tree ... \n";
216       
217        // use objects for evaluating vsp tree construction in the first levels
218        // of the subdivision
219        mSavedObjectSpaceSubdivisionType = mObjectSpaceSubdivisionType;
220        mObjectSpaceSubdivisionType = NO_OBJ_SUBDIV;
221
222        // start with view space subdivison: prepare vsp tree for traversal
223        if (StartViewSpaceSubdivision())
224        {
225                mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
226                PrepareViewSpaceSubdivision(sampleRays, objects, forcedViewSpace);
227        }
228       
229        // start object space subdivision immediately?
230        if (StartObjectSpaceSubdivision())
231        {
232                mObjectSpaceSubdivisionType = mSavedObjectSpaceSubdivisionType;
233                PrepareObjectSpaceSubdivision(sampleRays, objects);
234        }
235
236        // process object space candidates
237        RunConstruction(sampleRays, objects, forcedViewSpace);
238       
239        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
240        mHierarchyStats.Stop();
241        mVspTree->mVspStats.Stop();
242}
243
244
245void HierarchyManager::PrepareViewSpaceSubdivision(const VssRayContainer &sampleRays,
246                                                                                                   const ObjectContainer &objects,
247                                                                                                   AxisAlignedBox3 *forcedViewSpace)
248{
249        RayInfoContainer *viewSpaceRays = new RayInfoContainer();
250        SubdivisionCandidate *vsc =
251                mVspTree->PrepareConstruction(sampleRays, forcedViewSpace, *viewSpaceRays);
252
253        mTQueue.Push(vsc);
254}
255
256
257void HierarchyManager::PrepareObjectSpaceSubdivision(const VssRayContainer &sampleRays,
258                                                                                                         const ObjectContainer &objects)
259{
260        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
261        {
262                PrepareOspTree(sampleRays, objects);
263        }
264        else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
265        {
266                PrepareBvHierarchy(sampleRays, objects);
267        }
268}
269
270
271void HierarchyManager::PrepareBvHierarchy(const VssRayContainer &sampleRays,
272                                                                                  const ObjectContainer &objects)
273
274{
275        cout << "starting bv hierarchy construction ... " << endl;
276
277        mBvHierarchy->CreateRoot(objects);
278
279        // compute first candidate
280        SubdivisionCandidate *sc =
281                mBvHierarchy->PrepareConstruction(sampleRays, objects);
282
283        mTotalCost = mBvHierarchy->mTotalCost;
284        Debug << "reseting cost, new total cost: " << mTotalCost << endl;
285
286    mTQueue.Push(sc);
287}
288
289
290void HierarchyManager::PrepareOspTree(const VssRayContainer &sampleRays,
291                                                                          const ObjectContainer &objects)
292{
293        RayInfoContainer *objectSpaceRays = new RayInfoContainer();
294
295        cout << "starting osp tree construction ... " << endl;
296
297        // start with one big kd cell - all objects can be seen from everywhere
298        // note: only true for view space = object space
299
300        // compute first candidate
301        SubdivisionCandidate *osc =
302                mOspTree->PrepareConstruction(sampleRays, objects, *objectSpaceRays);
303
304        mTotalCost = mOspTree->mTotalCost;
305        Debug << "reseting cost, new total cost: " << mTotalCost << endl;
306       
307    mTQueue.Push(osc);
308}
309
310
311bool HierarchyManager::ApplySubdivisionCandidate(SubdivisionCandidate *sc)
312{
313        const bool globalTerminationCriteriaMet = GlobalTerminationCriteriaMet(sc);
314        const bool vspSplit = (sc->Type() == SubdivisionCandidate::VIEW_SPACE);
315
316        if (vspSplit)
317        {
318                VspNode *n = mVspTree->Subdivide(mTQueue, sc, globalTerminationCriteriaMet);
319
320                if (n->IsLeaf()) // local or global termination criteria failed
321                        return false;
322        }
323        else
324        {
325                if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
326                {
327                        KdNode *n = mOspTree->Subdivide(mTQueue, sc, globalTerminationCriteriaMet);
328
329                        if (n->IsLeaf()) // local or global termination criteria failed
330                                return false;
331                }
332                else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
333                {
334                        BvhNode *n = mBvHierarchy->Subdivide(mTQueue, sc, globalTerminationCriteriaMet);
335
336                        if (n->IsLeaf()) // local or global termination criteria failed
337                                return false;
338                }
339        }
340        return true;//!globalTerminationCriteriaMet;
341}
342
343
344bool HierarchyManager::StartObjectSpaceSubdivision() const
345{
346        const bool ospDepthReached =
347                (mMinDepthForObjectSpaceSubdivion <= mVspTree->mVspStats.maxDepth);
348   
349        return !ObjectSpaceSubdivisionConstructed() &&
350                   (mTQueue.Empty() || ((mConstructionType == INTERLEAVED) && ospDepthReached));
351}
352
353
354bool HierarchyManager::StartViewSpaceSubdivision() const
355{
356        const bool vspDepthReached =
357                (mMinDepthForObjectSpaceSubdivion <= mVspTree->mVspStats.maxDepth);
358   
359        return !ViewSpaceSubdivisionConstructed() &&
360                   (mTQueue.Empty() || ((mConstructionType == INTERLEAVED) && vspDepthReached));
361}
362
363
364void HierarchyManager::RunConstruction(const VssRayContainer &sampleRays,
365                                                                           const ObjectContainer &objects,
366                                                                           AxisAlignedBox3 *forcedViewSpace)
367{
368        mHierarchyStats.nodes = 0;
369        mGlobalCostMisses = 0;
370
371        int i = 0;
372        while (!FinishedConstruction())
373        {
374                mCurrentCandidate = NextSubdivisionCandidate();   
375                mTotalCost -= mCurrentCandidate->GetRenderCostDecrease();
376
377                // cost ratio of cost decrease / totalCost
378                const float costRatio = mCurrentCandidate->GetRenderCostDecrease() / mTotalCost;
379
380                //Debug << "ratio: " << costRatio << " min ratio: " << mTermMinGlobalCostRatio << endl;
381                if (costRatio < mTermMinGlobalCostRatio)
382                {
383                        ++ mGlobalCostMisses;
384                }
385               
386                //-- subdivide leaf node
387                if (ApplySubdivisionCandidate(mCurrentCandidate))
388                {
389                        cout << "subdividing candidate " << ++ i << " of type " << mCurrentCandidate->Type() << endl;
390                        mHierarchyStats.nodes += 2;
391
392                        // subdivision successful
393                        EvalSubdivisionStats(*mCurrentCandidate);
394               
395                        // reevaluate candidates affected by the split for view space splits,
396                        // this would be object space splits and other way round
397                        if (mRepairQueue) RepairQueue();
398                }
399
400                // we use objects for evaluating vsp tree construction until
401                // a certain depth once a certain depth existiert ....
402                if (StartObjectSpaceSubdivision())
403                {
404                        mObjectSpaceSubdivisionType = mSavedObjectSpaceSubdivisionType;
405
406                        cout << "starting object space subdivision at depth "
407                                 << mVspTree->mVspStats.maxDepth << " ("
408                                 << mMinDepthForObjectSpaceSubdivion << ") " << endl;
409
410                        PrepareObjectSpaceSubdivision(sampleRays, objects);
411
412                        cout << "reseting queue ... ";
413                        ResetQueue();
414                        cout << "finished" << endl;
415                }
416
417                if (StartViewSpaceSubdivision())
418                {
419                        mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
420
421                        cout << "starting view space subdivision at depth "
422                                 << mVspTree->mVspStats.maxDepth << " ("
423                                 << mMinDepthForObjectSpaceSubdivion << ") " << endl;
424
425                        PrepareViewSpaceSubdivision(sampleRays, objects, forcedViewSpace);
426
427                        cout << "reseting queue ... ";
428                        ResetQueue();
429                        cout << "finished" << endl;
430                }
431
432                DEL_PTR(mCurrentCandidate);
433        }
434
435        mObjectSpaceSubdivisionType = mSavedObjectSpaceSubdivisionType;
436}
437
438
439bool HierarchyManager::FinishedConstruction() const
440{
441        return mTQueue.Empty();
442}
443
444
445bool HierarchyManager::ObjectSpaceSubdivisionConstructed() const
446{
447        switch (mObjectSpaceSubdivisionType)
448        {
449        case KD_BASED_OBJ_SUBDIV:
450                return mOspTree && mOspTree->GetRoot();
451        case BV_BASED_OBJ_SUBDIV:
452                return mBvHierarchy && mOspTree->GetRoot();
453        default:
454        return false;
455        }
456}
457
458
459bool HierarchyManager::ViewSpaceSubdivisionConstructed() const
460{
461        return mVspTree && mVspTree->GetRoot();
462}
463
464
465void HierarchyManager::CollectObjectSpaceDirtyList(SubdivisionCandidateContainer &dirtyList)
466{
467        switch (mObjectSpaceSubdivisionType)
468        {
469        case KD_BASED_OBJ_SUBDIV:
470                {
471                        OspTree::OspSubdivisionCandidate *sc =
472                                dynamic_cast<OspTree::OspSubdivisionCandidate *>(mCurrentCandidate);
473
474                        mOspTree->CollectDirtyCandidates(sc, dirtyList);
475                        break;
476                }
477        case BV_BASED_OBJ_SUBDIV:
478                {
479                        BvHierarchy::BvhSubdivisionCandidate *sc =
480                                dynamic_cast<BvHierarchy::BvhSubdivisionCandidate *>(mCurrentCandidate);
481
482                        mBvHierarchy->CollectDirtyCandidates(sc, dirtyList);
483                        break;
484                }
485        default:
486                break;
487        }
488}
489
490
491void HierarchyManager::CollectViewSpaceDirtyList(SubdivisionCandidateContainer &dirtyList)
492{
493        VspTree::VspSubdivisionCandidate *sc =
494                dynamic_cast<VspTree::VspSubdivisionCandidate *>(mCurrentCandidate);
495
496        mVspTree->CollectDirtyCandidates(sc, dirtyList);
497}
498
499
500void HierarchyManager::CollectDirtyCandidates(SubdivisionCandidateContainer &dirtyList)
501{
502        // we have either a object space or view space split
503        if (mCurrentCandidate->Type() == SubdivisionCandidate::VIEW_SPACE)
504        {
505                CollectViewSpaceDirtyList(dirtyList);
506        }
507        else // object space split
508        {
509                CollectObjectSpaceDirtyList(dirtyList);
510        }
511}
512
513
514void HierarchyManager::RepairQueue()
515{
516        // for each update of the view space partition:
517        // the candidates from object space partition which
518        // have been afected by the view space split (the kd split candidates
519        // which saw the view cell which was split) must be reevaluated
520        // (maybe not locally, just reinsert them into the queue)
521        //
522        // vice versa for the view cells
523        // for each update of the object space partition
524        // reevaluate split candidate for view cells which saw the split kd cell
525        //
526        // the priority queue update can be solved by implementing a binary heap
527        // (explicit data structure, binary tree)
528        // *) inserting and removal is efficient
529        // *) search is not efficient => store queue position with each
530        // split candidate
531
532        // collect list of "dirty" candidates
533        long startTime = GetTime();
534   
535        vector<SubdivisionCandidate *> dirtyList;
536        CollectDirtyCandidates(dirtyList);
537        cout << "repairing " << (int)dirtyList.size() << " candidates ... ";
538       
539        //-- reevaluate the dirty list
540        SubdivisionCandidateContainer::const_iterator sit, sit_end = dirtyList.end();
541       
542        for (sit = dirtyList.begin(); sit != sit_end; ++ sit)
543        {
544                SubdivisionCandidate* sc = *sit;
545                const float rcd = sc->GetRenderCostDecrease();
546               
547                mTQueue.Erase(sc); // erase from queue
548                sc->EvalPriority(); // reevaluate
549               
550                /*
551                Debug << "candidate " << sc << " reevaluated\n"
552                          << "render cost decrease diff " <<  rcd - sc->GetRenderCostDecrease()
553                          << " old: " << rcd << " new " << sc->GetRenderCostDecrease() << endl;*/
554                if (0)
555                {
556                        const float rcDiff =  rcd - sc->GetRenderCostDecrease();
557                        mTotalCost += rcDiff;
558                }
559                mTQueue.Push(sc); // reinsert
560        }
561
562        long endTime = GetTime();
563        Real timeDiff = TimeDiff(startTime, endTime);
564
565        mHierarchyStats.repairTime += timeDiff;
566
567        cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
568}
569
570
571void HierarchyManager::ResetQueue()
572{
573        SubdivisionCandidateContainer mCandidateBuffer;
574
575        // remove from queue
576        while (!mTQueue.Empty())
577        {
578                SubdivisionCandidate *candidate = NextSubdivisionCandidate();
579                candidate->EvalPriority(); // reevaluate
580                cout << ".";
581                mCandidateBuffer.push_back(candidate);
582        }
583
584        // put back into queue
585        SubdivisionCandidateContainer::const_iterator sit, sit_end = mCandidateBuffer.end();
586    for (sit = mCandidateBuffer.begin(); sit != sit_end; ++ sit)
587        {cout << ":";
588                mTQueue.Push(*sit);
589        }
590}
591
592
593void HierarchyManager::ExportObjectSpaceHierarchy(OUT_STREAM &stream)
594{
595        // the type of the view cells hierarchy
596        switch (mObjectSpaceSubdivisionType)
597        {
598        case KD_BASED_OBJ_SUBDIV:
599                stream << "<ObjectSpaceHierarchy type=\"osp\">" << endl;
600                mOspTree->Export(stream);
601                stream << endl << "</ObjectSpaceHierarchy>" << endl;
602                break;         
603        case BV_BASED_OBJ_SUBDIV:
604                stream << "<ObjectSpaceHierarchy type=\"bvh\">" << endl;
605                mBvHierarchy->Export(stream);
606                stream << endl << "</ObjectSpaceHierarchy>" << endl;
607                break;
608        }
609}
610
611
612bool HierarchyManager::AddSampleToPvs(Intersectable *obj,
613                                                                          const Vector3 &hitPoint,
614                                                                          ViewCell *vc,
615                                                                          const float pdf,
616                                                                          float &contribution) const
617{
618        if (!obj) return false;
619
620        switch (mObjectSpaceSubdivisionType)
621        {
622        case NO_OBJ_SUBDIV:
623                // potentially visible objects
624                return vc->AddPvsSample(obj, pdf, contribution);
625        case KD_BASED_OBJ_SUBDIV:
626                {
627                        // potentially visible kd cells
628                        KdLeaf *leaf = mOspTree->GetLeaf(hitPoint/*ray->mOriginNode*/);
629                        return mOspTree->AddLeafToPvs(leaf, vc, pdf, contribution);
630                }
631        case BV_BASED_OBJ_SUBDIV:
632                {
633                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
634                        return mBvHierarchy->AddLeafToPvs(leaf, vc, pdf, contribution);
635                }
636        default:
637                return false;
638        }
639}
640
641
642void HierarchyManager::PrintHierarchyStatistics(ofstream &stream) const
643{
644        stream << mHierarchyStats << endl;
645
646        stream << "\nview space:" << endl << endl;
647        stream << mVspTree->GetStatistics() << endl;
648        stream << "\nobject space:" << endl << endl;
649        switch (mObjectSpaceSubdivisionType)
650        {
651        case KD_BASED_OBJ_SUBDIV:
652                {
653                        stream << mOspTree->GetStatistics() << endl;
654                        break;
655                }
656        case BV_BASED_OBJ_SUBDIV:
657                {
658                        stream << mBvHierarchy->GetStatistics() << endl;
659                        break;
660                }
661        default:
662                break;
663        }
664}
665
666
667void HierarchyManager::ExportObjectSpaceHierarchy(Exporter *exporter,
668                                                                                                  const ObjectContainer &objects) const
669{
670        switch (mObjectSpaceSubdivisionType)
671        {
672        case KD_BASED_OBJ_SUBDIV:
673                {
674                        ExportOspTree(exporter, objects);
675                        break;
676                }
677        case BV_BASED_OBJ_SUBDIV:
678                {
679                        ExportBvHierarchy(exporter, objects);
680                        break;
681                }
682        default:
683                break;
684        }
685}
686
687
688void HierarchyManager::ExportBvHierarchy(Exporter *exporter,
689                                                                                 const ObjectContainer &objects) const
690{
691        exporter->SetWireframe();
692        exporter->ExportBvHierarchy(*mBvHierarchy, 0);
693}
694
695
696void HierarchyManager::ExportOspTree(Exporter *exporter,
697                                                                         const ObjectContainer &objects) const
698{
699        if (0) exporter->ExportGeometry(objects);
700                       
701        exporter->SetWireframe();
702        exporter->ExportOspTree(*mOspTree, 0);
703}
704
705
706void HierarchyStatistics::Print(ostream &app) const
707{
708        app << "=========== Hierarchy statistics ===============\n";
709
710        app << setprecision(4);
711
712        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
713       
714        app << "#N_RTIME  ( Repair time [s] )\n" << repairTime * 1e-3f << " \n";
715
716        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
717
718        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
719
720        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
721
722        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
723       
724        app << "========== END OF Hierarchy statistics ==========\n";
725}
726
727
728}
Note: See TracBrowser for help on using the repository browser.