]> git.mxchange.org Git - simgear.git/commitdiff
Extend Canvas to retrieve bounding box of groups
authorThomas Geymayer <tomgey@gmail.com>
Tue, 4 Dec 2012 22:58:08 +0000 (23:58 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Tue, 4 Dec 2012 22:58:08 +0000 (23:58 +0100)
simgear/canvas/elements/CanvasElement.cxx
simgear/canvas/elements/CanvasElement.hxx
simgear/canvas/elements/CanvasGroup.cxx
simgear/canvas/elements/CanvasGroup.hxx
simgear/canvas/elements/CanvasPath.cxx
simgear/canvas/elements/CanvasPath.hxx

index 7b8a8c6b74f26b8c3af07d053fc690f66fff6b4e..0ca940d1376ae3667581776fae65f8964ea3ca3a 100644 (file)
@@ -316,6 +316,12 @@ namespace canvas
     _bounding_box[3]->setFloatValue(bb._max.y());
   }
 
+  //----------------------------------------------------------------------------
+  osg::BoundingBox Element::getTransformedBounds(const osg::Matrix& m) const
+  {
+    return osg::BoundingBox();
+  }
+
   //----------------------------------------------------------------------------
   Element::Element( const CanvasWeakPtr& canvas,
                     const SGPropertyNode_ptr& node,
index 0f4b31edf6a4d1a48c12b66f1e301c1a8d1d569a..9067c7295172dd89f0d49b953074b7efa5156aec 100644 (file)
@@ -96,6 +96,11 @@ namespace canvas
        */
       void setBoundingBox(const osg::BoundingBox& bb);
 
+      /**
+       * Get bounding box with children/drawables transformed by passed matrix
+       */
+      virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
+
     protected:
 
       enum Attributes
index 0740026828c721d9146eeba92e56ea6a3e793514..e8158edf476c9a7838e93d4a65eba354b9c82b76 100644 (file)
@@ -132,6 +132,28 @@ namespace canvas
     return false;
   }
 
+  //----------------------------------------------------------------------------
+  osg::BoundingBox Group::getTransformedBounds(const osg::Matrix& m) const
+  {
+    osg::BoundingBox bb;
+
+    BOOST_FOREACH( ChildList::value_type child, _children )
+    {
+      if( !child.second->getMatrixTransform()->getNodeMask() )
+        continue;
+
+      bb.expandBy
+      (
+        child.second->getTransformedBounds
+        (
+          child.second->getMatrixTransform()->getMatrix() * m
+        )
+      );
+    }
+
+    return bb;
+  }
+
   //----------------------------------------------------------------------------
   void Group::childAdded(SGPropertyNode* child)
   {
index 38cb0cc90205f59ba9e23ad1c3e28264f74cd1c2..02ea7e8b82873edd6fb42858828c01be5615ed3e 100644 (file)
@@ -58,6 +58,8 @@ namespace canvas
 
       virtual bool traverse(EventVisitor& visitor);
 
+      virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
+
     protected:
 
       typedef std::map<std::string, ElementFactory> ChildFactories;
index ebcb45ff7445db89e3297c8df64d6bf7c5260a3a..9fde6782480117cce5eb7930edc271b18efc68d0 100644 (file)
@@ -32,6 +32,25 @@ namespace canvas
   typedef std::vector<VGubyte>  CmdList;
   typedef std::vector<VGfloat>  CoordList;
 
+
+  static const VGubyte shCoordsPerCommand[] = {
+    0, /* VG_CLOSE_PATH */
+    2, /* VG_MOVE_TO */
+    2, /* VG_LINE_TO */
+    1, /* VG_HLINE_TO */
+    1, /* VG_VLINE_TO */
+    4, /* VG_QUAD_TO */
+    6, /* VG_CUBIC_TO */
+    2, /* VG_SQUAD_TO */
+    4, /* VG_SCUBIC_TO */
+    5, /* VG_SCCWARC_TO */
+    5, /* VG_SCWARC_TO */
+    5, /* VG_LCCWARC_TO */
+    5  /* VG_LCWARC_TO */
+  };
+  static const VGubyte shNumCommands = sizeof(shCoordsPerCommand)
+                                     / sizeof(shCoordsPerCommand[0]);
+
   /**
    * Helper to split and convert comma/whitespace separated floating point
    * values
@@ -255,6 +274,91 @@ namespace canvas
         glPopClientAttrib();
       }
 
+      osg::BoundingBox getTransformedBounds(const osg::Matrix& mat) const
+      {
+        osg::BoundingBox bb;
+
+        osg::Vec2f cur; // VG "Current point" (in local coordinates)
+        VGubyte cmd_index = 0;
+        for( size_t i = 0,              ci = 0;
+                    i < _cmds.size() && ci < _coords.size();
+                  ++i,                  ci += shCoordsPerCommand[cmd_index] )
+        {
+          VGubyte rel = _cmds[i] & 1,
+                  cmd = _cmds[i] & ~1;
+
+          cmd_index = cmd / 2;
+          if( cmd_index >= shNumCommands )
+            return osg::BoundingBox();
+
+          const VGubyte max_coords = 3;
+          osg::Vec2f points[max_coords];
+          VGubyte num_coords = 0;
+
+          switch( cmd )
+          {
+            case VG_CLOSE_PATH:
+              break;
+            case VG_MOVE_TO:
+            case VG_LINE_TO:
+            case VG_SQUAD_TO:
+              // x0, y0
+              points[ num_coords++ ].set(_coords[ci], _coords[ci + 1]);
+              break;
+            case VG_HLINE_TO:
+              // x0
+              points[ num_coords++ ].set( _coords[ci] + (rel ? cur.x() : 0),
+                                          cur.y() );
+              // We have handled rel/abs already, so no need to do it again...
+              rel = 0;
+              break;
+            case VG_VLINE_TO:
+              // y0
+              points[ num_coords++ ].set( cur.x(),
+                                          _coords[ci] + (rel ? cur.y() : 0) );
+              // We have handled rel/abs already, so no need to do it again...
+              rel = 0;
+              break;
+            case VG_QUAD_TO:
+            case VG_SCUBIC_TO:
+              // x0,y0,x1,y1
+              points[ num_coords++ ].set(_coords[ci    ], _coords[ci + 1]);
+              points[ num_coords++ ].set(_coords[ci + 2], _coords[ci + 3]);
+              break;
+            case VG_CUBIC_TO:
+              // x0,y0,x1,y1,x2,y2
+              points[ num_coords++ ].set(_coords[ci    ], _coords[ci + 1]);
+              points[ num_coords++ ].set(_coords[ci + 2], _coords[ci + 3]);
+              points[ num_coords++ ].set(_coords[ci + 4], _coords[ci + 5]);
+              break;
+            case VG_SCCWARC_TO:
+            case VG_SCWARC_TO:
+            case VG_LCCWARC_TO:
+            case VG_LCWARC_TO:
+              // rh,rv,rot,x0,y0
+              points[ num_coords++ ].set(_coords[ci + 3], _coords[ci + 4]);
+              break;
+            default:
+              SG_LOG(SG_GL, SG_WARN, "Unknown VG command: " << (int)cmd);
+              return osg::BoundingBox();
+          }
+
+          assert(num_coords <= max_coords);
+          for(VGubyte i = 0; i < num_coords; ++i)
+          {
+            if( rel )
+              points[i] += cur;
+
+            bb.expandBy( transformPoint(mat, points[i]) );
+          }
+
+          if( num_coords > 0 )
+            cur = points[ num_coords - 1 ];
+        }
+
+        return bb;
+      }
+
       /**
        * Compute the bounding box
        */
@@ -309,6 +413,17 @@ namespace canvas
       std::vector<VGfloat>  _stroke_dash;
       VGCapStyle            _stroke_linecap;
 
+      osg::Vec3f transformPoint( const osg::Matrix& m,
+                                 osg::Vec2f pos ) const
+      {
+        return osg::Vec3
+        (
+          m(0, 0) * pos[0] + m(1, 0) * pos[1] + m(3, 0),
+          m(0, 1) * pos[0] + m(1, 1) * pos[1] + m(3, 1),
+          0
+        );
+      }
+
       /**
        * Initialize/Update the OpenVG path
        */
@@ -396,6 +511,12 @@ namespace canvas
     Element::update(dt);
   }
 
+  //----------------------------------------------------------------------------
+  osg::BoundingBox Path::getTransformedBounds(const osg::Matrix& m) const
+  {
+    return _path->getTransformedBounds(m);
+  }
+
   //----------------------------------------------------------------------------
   void Path::childRemoved(SGPropertyNode* child)
   {
index 42854772aef3f06e7e63e3f49a604ad209e41e85..2cde2dc905b555935ccf2a904447bf98a4ae8037 100644 (file)
@@ -37,6 +37,8 @@ namespace canvas
 
       virtual void update(double dt);
 
+      virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
+
     protected:
 
       enum PathAttributes