From 42d2bc6a3fdc04100c84836e59476a5cc0c976f2 Mon Sep 17 00:00:00 2001
From: Ansgar Philippsen <ansgar.philippsen@gmail.com>
Date: Wed, 13 Jul 2011 08:32:08 -0400
Subject: [PATCH] fixes to primlist and scene autoslab/bounding box problems

(BZDNG 288 and 289)
---
 modules/geom/src/aligned_cuboid.cc |  24 ------
 modules/geom/src/aligned_cuboid.hh |  15 ++--
 modules/gfx/src/prim_list.cc       |   3 +
 modules/gfx/src/scene.cc           | 122 ++++++++++++++++++-----------
 4 files changed, 89 insertions(+), 75 deletions(-)

diff --git a/modules/geom/src/aligned_cuboid.cc b/modules/geom/src/aligned_cuboid.cc
index 3440e2359..ebd772733 100644
--- a/modules/geom/src/aligned_cuboid.cc
+++ b/modules/geom/src/aligned_cuboid.cc
@@ -22,34 +22,10 @@
 
 namespace geom {
 
-AlignedCuboid::AlignedCuboid(const Vec3& mmin, const Vec3& mmax):
-  min_(mmin), max_(mmax)
-{ }
-
-Vec3 AlignedCuboid::GetSize() const
-{
-  return max_-min_;
-}
-
-const Vec3& AlignedCuboid::GetMin() const
-{
-  return min_;
-}
-
-const Vec3& AlignedCuboid::GetMax() const
-{
-  return max_;
-}
-
 AlignedCuboid Union(const AlignedCuboid& lhs, const AlignedCuboid& rhs)
 {
   return AlignedCuboid(Min(lhs.GetMin(), rhs.GetMin()), 
                        Max(lhs.GetMax(), rhs.GetMax()));
 }
 
-Vec3 AlignedCuboid::GetCenter() const
-{
-  return (min_+max_)*0.5;
 }
-
-}
\ No newline at end of file
diff --git a/modules/geom/src/aligned_cuboid.hh b/modules/geom/src/aligned_cuboid.hh
index fc2d72ab6..8937ce4c3 100644
--- a/modules/geom/src/aligned_cuboid.hh
+++ b/modules/geom/src/aligned_cuboid.hh
@@ -34,15 +34,20 @@ namespace geom {
 /// For an arbitrarily oriented cuboid see \ref Cuboid
 class DLLEXPORT_OST_GEOM AlignedCuboid {
 public:
-  AlignedCuboid(const Vec3& mmin, const Vec3& mmax);
+  AlignedCuboid(const Vec3& mmin, const Vec3& mmax) :min_(mmin), max_(mmax) {}
   
-  Vec3 GetSize() const;
+  Vec3 GetSize() const {return max_-min_;}
   
-  const Vec3& GetMin() const;
+  Real GetVolume() const {
+    Vec3 s=max_-min_;
+    return s[0]*s[1]*s[2];
+  }
+
+  const Vec3& GetMin() const {return min_;}
   
-  const Vec3& GetMax() const;
+  const Vec3& GetMax() const {return max_;}
   
-  Vec3 GetCenter() const;
+  Vec3 GetCenter() const {return 0.5*(max_+min_);}
 private:
   Vec3 min_;
   Vec3 max_;
diff --git a/modules/gfx/src/prim_list.cc b/modules/gfx/src/prim_list.cc
index 95ed64cfb..888246f96 100644
--- a/modules/gfx/src/prim_list.cc
+++ b/modules/gfx/src/prim_list.cc
@@ -53,6 +53,9 @@ void PrimList::Clear()
 
 geom::AlignedCuboid PrimList::GetBoundingBox() const
 {
+  if(points_.empty() && lines_.empty() && spheres_.empty() && cyls_.empty()) {
+    return geom::AlignedCuboid(geom::Vec3(-1,-1,-1),geom::Vec3(1,1,1));
+  }
   geom::Vec3 minc(std::numeric_limits<float>::max(),
                   std::numeric_limits<float>::max(),
                   std::numeric_limits<float>::max());
diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc
index af9731371..9eadc47c5 100644
--- a/modules/gfx/src/scene.cc
+++ b/modules/gfx/src/scene.cc
@@ -1109,46 +1109,54 @@ namespace {
 class BBCalc: public GfxNodeVisitor
 {
 public:
+  BBCalc(const geom::Vec3& mmin, const geom::Vec3& mmax, const mol::Transform& tf): 
+    minc(mmin),maxc(mmax),tf(tf),valid(false) {}
+
   bool VisitNode(GfxNode* node, const Stack& st) {
     return node->IsVisible(); // only descend into visible nodes
   }
   void VisitObject(GfxObj* obj, const Stack& st) {
     if(obj->IsVisible()) {
       geom::AlignedCuboid bb=obj->GetBoundingBox();
-      Vec3 t1 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMin()[1],bb.GetMin()[2]));
-      Vec3 t2 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMax()[1],bb.GetMin()[2]));
-      Vec3 t3 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMax()[1],bb.GetMin()[2]));
-      Vec3 t4 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMin()[1],bb.GetMin()[2]));
-      Vec3 t5 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMin()[1],bb.GetMax()[2]));
-      Vec3 t6 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMax()[1],bb.GetMax()[2]));
-      Vec3 t7 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMax()[1],bb.GetMax()[2]));
-      Vec3 t8 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMin()[1],bb.GetMax()[2]));
-      minc = Min(minc,Min(t1,Min(t2,Min(t3,Min(t4,Min(t5,Min(t6,Min(t7,t8))))))));
-      maxc = Max(maxc,Max(t1,Max(t2,Max(t3,Max(t4,Max(t5,Max(t6,Max(t7,t8))))))));
+      if(bb.GetVolume()>0.0) {
+        Vec3 t1 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMin()[1],bb.GetMin()[2]));
+        Vec3 t2 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMax()[1],bb.GetMin()[2]));
+        Vec3 t3 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMax()[1],bb.GetMin()[2]));
+        Vec3 t4 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMin()[1],bb.GetMin()[2]));
+        Vec3 t5 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMin()[1],bb.GetMax()[2]));
+        Vec3 t6 = tf.Apply(Vec3(bb.GetMin()[0],bb.GetMax()[1],bb.GetMax()[2]));
+        Vec3 t7 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMax()[1],bb.GetMax()[2]));
+        Vec3 t8 = tf.Apply(Vec3(bb.GetMax()[0],bb.GetMin()[1],bb.GetMax()[2]));
+        minc = Min(minc,Min(t1,Min(t2,Min(t3,Min(t4,Min(t5,Min(t6,Min(t7,t8))))))));
+        maxc = Max(maxc,Max(t1,Max(t2,Max(t3,Max(t4,Max(t5,Max(t6,Max(t7,t8))))))));
+        valid=true;
+      }
     }
   }
 
   Vec3 minc,maxc;
   mol::Transform tf;
+  bool valid;
 };
 
 }
 
 geom::AlignedCuboid Scene::GetBoundingBox(const mol::Transform& tf) const
 {
-  BBCalc bbcalc;
-
-  bbcalc.tf = tf;
-  bbcalc.minc = Vec3(std::numeric_limits<float>::max(),
-                           std::numeric_limits<float>::max(),
-                           std::numeric_limits<float>::max());
-  bbcalc.maxc = Vec3(-std::numeric_limits<float>::max(),
-                           -std::numeric_limits<float>::max(),
-                           -std::numeric_limits<float>::max());
+  BBCalc bbcalc(Vec3(std::numeric_limits<float>::max(),
+                     std::numeric_limits<float>::max(),
+                     std::numeric_limits<float>::max()),
+                Vec3(-std::numeric_limits<float>::max(),
+                     -std::numeric_limits<float>::max(),
+                     -std::numeric_limits<float>::max()),
+                tf);
 
   Apply(bbcalc);
 
-  return geom::AlignedCuboid(bbcalc.minc,bbcalc.maxc);
+  if(bbcalc.valid) {
+    return geom::AlignedCuboid(bbcalc.minc,bbcalc.maxc);
+  }
+  return geom::AlignedCuboid(geom::Vec3(),geom::Vec3());
 }
 
 mol::Transform Scene::GetTransform() const
@@ -1587,13 +1595,18 @@ namespace {
 class LimCalc: public GfxNodeVisitor
 {
 public:
+  LimCalc(): minc(),maxc(),transform(),valid(false) {}
   void VisitObject(GfxObj* obj, const Stack& st) {
     if(obj->IsVisible()) {
       obj->ProcessLimits(minc,maxc, transform);
+      // this is buggy - ProcessLimits should really return a boolean 
+      // indicating whether it could succesfully apply limits or not
+      valid=true;
     }
   }
   Vec3 minc,maxc;
   mol::Transform transform;
+  bool valid;
 };
 
 } // anon ns
@@ -1608,23 +1621,31 @@ void Scene::AutoslabMax()
 {
   geom::AlignedCuboid bb =this->GetBoundingBox(transform_);
 
-  Vec3 cen = transform_.Apply(transform_.GetCenter());
-
-  float bmax = std::max(std::abs(cen[0]-bb.GetMin()[0]),
-                        std::abs(cen[0]-bb.GetMax()[0]));
-  bmax = std::max(bmax,float(std::abs(cen[1]-bb.GetMin()[1])));
-  bmax = std::max(bmax,float(std::abs(cen[1]-bb.GetMax()[1])));
-  bmax = std::max(bmax,float(std::abs(cen[2]-bb.GetMin()[2])));
-  bmax = std::max(bmax,float(std::abs(cen[2]-bb.GetMax()[2])));
-
-  float nnear = -(cen[2]+bmax*1.5);
-  float nfar = -(cen[2]-bmax*1.5);
+  if(bb.GetVolume()==0.0) {
+    znear_=1;
+    zfar_=100;
+    set_near(1);
+    set_far(100);
+  } else {
 
-  // necessary code duplication due to awkward slab limit impl
-  znear_=nnear;
-  zfar_=nfar;
-  set_near(nnear);
-  set_far(nfar);
+    Vec3 cen = transform_.Apply(transform_.GetCenter());
+    
+    float bmax = std::max(std::abs(cen[0]-bb.GetMin()[0]),
+                          std::abs(cen[0]-bb.GetMax()[0]));
+    bmax = std::max(bmax,float(std::abs(cen[1]-bb.GetMin()[1])));
+    bmax = std::max(bmax,float(std::abs(cen[1]-bb.GetMax()[1])));
+    bmax = std::max(bmax,float(std::abs(cen[2]-bb.GetMin()[2])));
+    bmax = std::max(bmax,float(std::abs(cen[2]-bb.GetMax()[2])));
+    
+    float nnear = -(cen[2]+bmax*1.5);
+    float nfar = -(cen[2]-bmax*1.5);
+    
+    // necessary code duplication due to awkward slab limit impl
+    znear_=nnear;
+    zfar_=nfar;
+    set_near(nnear);
+    set_far(nfar);
+  }
   ResetProjection();
 }
 
@@ -1991,11 +2012,17 @@ void Scene::do_autoslab()
   if(do_autoslab_fast_) {
     geom::AlignedCuboid bb =this->GetBoundingBox(transform_);
     // necessary code duplication due to awkward slab limit impl
-    znear_=-(bb.GetMax()[2]-1.0);
-    zfar_=-(bb.GetMin()[2]+1.0);
-    set_near(-(bb.GetMax()[2]-1.0));
-    set_far(-(bb.GetMin()[2]+1.0));
-    ResetProjection();
+    if(bb.GetVolume()==0.0) {
+      // skip if empty BB
+      return;
+    } else {
+      float mynear=-(bb.GetMax()[2])-1.0;
+      float myfar=-(bb.GetMin()[2])+1.0;
+      znear_=mynear;
+      zfar_=myfar;
+      set_near(mynear);
+      set_far(myfar);
+    }
   } else {
     LimCalc limcalc;
     limcalc.transform=transform_;
@@ -2006,14 +2033,17 @@ void Scene::do_autoslab()
                               -std::numeric_limits<float>::max(),
                               -std::numeric_limits<float>::max());
     this->Apply(limcalc);
-    float mynear=std::max(float(0.0), std::min(float(-limcalc.minc[2]),float(-limcalc.maxc[2])))-float(2.0);
-    float myfar=std::max(float(-limcalc.minc[2]),float(-limcalc.maxc[2]))+float(2.0);
+    if(!limcalc.valid) {
+      return;
+    }
+    float mynear=std::max(float(0.0), std::min(float(-limcalc.minc[2]),float(-limcalc.maxc[2])))-float(1.0);
+    float myfar=std::max(float(-limcalc.minc[2]),float(-limcalc.maxc[2]))+float(1.0);
     znear_=mynear;
     zfar_=myfar;
-    set_near(znear_);
-    set_far(zfar_);
-    ResetProjection();
+    set_near(mynear);
+    set_far(myfar);
   }
+  ResetProjection();
   RequestRedraw();
 }
 
-- 
GitLab