Dear Java3D community,

Recently I had to fight against the getBounds() routine of the Node class
that forced me to implement my own version.

The problem is that I absolutely need the maximum and minimum coordinates
of a loaded VRML object. To load the object I use the Xj3D package taken
from the cvs around the 10 October 2000. If I ask for the bounds of the
loaded object I get a BoundingSphere. Converting the Bounds in an object
with:
Bounds b = object.getBounds() ;
BoundingBox bbox = new BoundingBox(b) ;

is not working good at all because the created box is surrounding not only
the object but also the bounding  sphere itself resulting in a bigger
size.  I understand that it's not possible to know where a bound is coming
from and make the previous piece of code work, I would have implemented it
like this myself :-)
I also understand that there is not reason to prefer the return of a Box
instead of a Sphere for the .getBounds() method; what is best depends on
the shape of the objet.

So I decided to write a deepscan-first-recursive-geometry-analizer
routine to get the coordinates I need.
The function takes as input a node and the results are the "lower" and
"upper" points of the desired BoundingBox.

To make this the routine recursively scan the scenegraph. When a Shape3D
object is found the Geometry is retrieved and analyzed.
To achieve this I use of the "instanceof" method to know
wich subtype of the Geometry class I'm dealing with. Depending from this
type different actions are taken.

Problem 1. If in future releases new Geometry subtypes will be added, the
routine will need to be updated. Are there good reasons to think that
there will _never_ be another Geometry subtype? The obvious answer seems
to be not, but... :-)

Problem 2. I don't know how to deal with the Raster and CompressedGeometry
classes because of lack of knowledge and time. So the routine works god
for my case but is incomplete.


Conclusion. I leave this little piece of code to the community, I guess it
can be nice to put it on j3d.org or something similar. Also maybe someone
might want to finish the routine supporting the Raster and
CompressedGeometry types and share it with the others.


Suggestion: Do you think is it possible with the current design supply
the Node class with a method like "int .getBestBoundingType()" returning
an index of the  bound type returned by .getBounds()?


regards,
Fabrizio Nunnari


--
http://digilander.iol.it/fnunnari

   Fabrizio Nunnari <[EMAIL PROTECTED]>
 -Student at Computer Science Department of Turin (Italy)-
Voodoo Chile of DeGeNeRaTiOn  for the Amiga scene --> Coder
    /** Recursive procedure that, starting from a node, scans the subtree
     * and the contained geometries to get the maximum and minimum coordinates.
     * The resulting values will be stared inthe provided points as an upper
     * and lower corner in BoundingBox style.
     * If no geometries are found in the tree the lower point components
     * will be set to Double.MAX_VALUE and the upper ones to Double.MIN_VALUES.
     * Be carefull to use it only on a non-live scene graph or be sure that
     * all the geometries have the READ capability bit set: the
     * capability bits are not tested and you can have run-time exceptions.
     */
    void getBoundingBox(Node node, Point3d lower, Point3d upper) {
        /* The idea is:
         * set the bounds to extreme impossible values and make restrictions
         * while finding new points in the nodes.
         */

        /* Initialize to extreme values */
        Point3d l = 
            new Point3d(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE) ;
        Point3d u =
            new Point3d(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE) ;

        // start the recursive analysis
        this.getBoundingBoxScanNode(node, l, u) ;
        
        // put the resulting values in output
        lower.set(l) ;
        upper.set(u) ;

        // debug -- System.out.println("Resulting BBox for node "+node+": "
        //                 +lower+"; "+upper) ;
    }

    /** Support method for getBoundingBox to recurse into a scene graph.
     */
    void getBoundingBoxScanNode(Node node, Point3d lower, Point3d upper) {
        // debug -- System.out.println("getBoundingBoxScanNode("
        //                 +node+", "+lower+", "+upper+")") ;
        if(node instanceof Group) {
            Group group = (Group)node ;
            
            java.util.Enumeration children = group.getAllChildren() ;
            while(children.hasMoreElements()) {
                Node n = (Node)children.nextElement() ;
                getBoundingBoxScanNode(n, lower, upper) ;
            }

        } else if(node instanceof Shape3D) {
            Shape3D shape = (Shape3D)node ;
            Geometry geometry = shape.getGeometry() ;

            this.getBoundingBoxScanGeometry(geometry, lower, upper) ;
        }
    }

    /** Support method for getBoundingBox to analyze geometry.
     */
    void getBoundingBoxScanGeometry(Geometry geometry,
                                    Point3d lower,
                                    Point3d upper) {

        if(geometry instanceof GeometryArray) {
            GeometryArray g = (GeometryArray)geometry ;
            /* Taking them by reference is saving time, but not every object
             * is supporting it :-(
             */
            int n = g.getVertexCount() ;
            double[] coords = new double[n*3] ;
            g.getCoordinates(0, coords) ;
            /* For every point let's adjust the bounds. */
            Point3d p = new Point3d() ;
            for(int i=0 ; i<n ; i++) {
                p.x = coords[i*3] ;
                p.y = coords[i*3+1] ;
                p.z = coords[i*3+2] ;
                this.getBoundingBoxCompare(p, lower, upper) ;
            }

        } else if(geometry instanceof Text3D) {
            Text3D t = (Text3D)geometry ;
            /* Taking the BoundingBox is the only thing I can do
             * for this kind of Geometry. Fortunately it's working
             * quite good.
             */
            BoundingBox bbox = new BoundingBox() ;
            t.getBoundingBox(bbox) ;
            Point3d p = new Point3d() ;
            bbox.getLower(p) ;
            this.getBoundingBoxCompare(p, lower, upper) ;
            bbox.getUpper(p) ;
            this.getBoundingBoxCompare(p, lower, upper) ;
            
        } else if(geometry instanceof CompressedGeometry) {

            System.err.println("getBoundingBox: "
                               + "Compressed Geometry not supported yet!!!") ;

        } else if(geometry instanceof Raster) {

            System.err.println("getBoundingBox: Raster not supported yet!!!") ;

        } else {

            System.err.println("getBoundingBox: "
                               + "Unexpected Geometry type "+geometry) ;

        }
    }


    /** Support method to getBoundingBox to compare a point with the actual
     * limits.
     */
    void getBoundingBoxCompare(Point3d p, Point3d lower, Point3d upper) {
        if(p.x < lower.x) lower.x = p.x ;
        if(p.y < lower.y) lower.y = p.y ;
        if(p.z < lower.z) lower.z = p.z ;
        if(p.x > upper.x) upper.x = p.x ;
        if(p.y > upper.y) upper.y = p.y ;
        if(p.z > upper.z) upper.z = p.z ;       
    }

Reply via email to