[Source] [X3D-Earth] Xj3D property setting for origin manager, for inclusion in X3D-Edit

Rex Melton rex.melton at comcast.net
Mon Jun 8 05:52:28 PDT 2009


Hi Rune,

Thanks for the info. I will certainly review it closely when I have a 
chance to return to tuning up our geospatial component implementation.

Unfortunately, I will not be attending the conference in Darmstadt. So I 
will not have the opportunity to meet with you.

However, feel free to abuse Alan Hudson in my stead :-)

-Rex

Rune Aasgard wrote:
> I have worked with similar problems in my Virtual Globe 
> http://www.virtual-globe.info/ and http://norgei3d.no/ (Good JWS 
> application example showing terrain with buildings and trees: 
> http://www.virtual-globe.info/VirtualGlobeStarter.php?dataset=http://www.virtual-globe.info/test/grotte.vgml&viewpoint=5.745274546100676,58.85572300948739,122.23931567609378,217.73784441355252,-13.401403950398965&libs=Xj3D 
> <http://www.virtual-globe.info/VirtualGlobeStarter.php?dataset=http://www.virtual-globe.info/test/grotte.vgml&viewpoint=5.745274546100676,58.85572300948739,122.23931567609378,217.73784441355252,-13.401403950398965&libs=Xj3D>) 
> and I believe you may find some inspiration in my implementation. It 
> solves the problem with long computations that may halt the rendering 
> for more that the acceptetd frame-to-frame interval.
>  
> From the OriginManager:
> <code>
>     // Handling of the hi-resolution origin
>     /// The hi resolution origin
>     private Point3d origin = new Point3d();
>     private Point3d new_origin = new Point3d();
>     /// Listeners that expect to be told when the hi-res origin changes
>        // WeakReferences are used to assure that deleted objects are 
> not retained from GC by the OriginManager
>     private final ArrayList<WeakReference<OriginUpdateListener>> 
> originUpdateListeners = new ArrayList();
>     private final ArrayList<WeakReference<OriginUpdateListener>> 
> originRequestListeners = new ArrayList();
>     private final ArrayList<WeakReference<OriginUpdateListener>> 
> originCompleteListeners = new ArrayList();
>    
>     /**
>      * Check if the hires origin is sufficiently close to the 
> interesting areas
>      * @param p Point to test
>      * @param tol Acceptable tolerance (vWorld scale size)
>      */
>     public void testOrigin(Point3d p, float tol) {
>         synchronized (originRequestListeners) {
>             if (originRequestListeners.isEmpty()) {
>                 double orig_dist = origin.distance(p);
>                
>                 // Move origin?
>                 if (orig_dist*1e-5f > tol) {
>                     new_origin.set(p);
>                     // System.err.println("Flytter origin: " + origin);
>                     synchronized (originUpdateListeners) {
>                         
> originRequestListeners.addAll(originUpdateListeners);
>                     }
>                 }
>             } else {
>                 Iterator<WeakReference<OriginUpdateListener>> i = 
> originRequestListeners.iterator();
>                 while (i.hasNext()) {
>                     WeakReference<OriginUpdateListener> ref = i.next();
>                     OriginUpdateListener l = ref.get();
>                     if (l == null)
>                           i.remove();
>                     else if (l.requestUpdateOrigin(new_origin)) {
>                         i.remove();
>                         originCompleteListeners.add(ref);
>                     }
>                 }
>             }
>             if (originRequestListeners.isEmpty()) {
>                 origin.set(new_origin);
>                 // Call listeners
>                 synchronized (originCompleteListeners) {
>                     for (WeakReference<OriginUpdateListener> ref : 
> originCompleteListeners) {
>                        OriginUpdateListener l = ref.get();
>                        if (l != null)
>                             l.updateOrigin(origin);
>                        }
>                     originCompleteListeners.clear();
>                 }    
>             }
>         }
>     }
>    
>    
>     /**
>      * Add origin update listeners
>      * @param l
>      */
>     public void addOriginUpdateListener(OriginUpdateListener l) {
>         // l.requestUpdateOrigin(origin);
>         // l.updateOrigin(origin);
>         synchronized (originUpdateListeners) {
>             originUpdateListeners.add(new WeakReference(l));
>         }
>         synchronized (originRequestListeners) {
>             originRequestListeners.add(new WeakReference(l));
>         }
>     }
> </code>
>  
> The testOrigin method is called once each frame in this way:
>  
> <code>
>         navigator.getEye(camera_pos);
>         float tol = Math.max(0.01f, (float) 
> navigator.getTerrainHeight() * (float) (fov * Math.PI / 180. / 
> canvas.getWidth()) * pixel_factor);
>         getOriginManager().testOrigin(camera_pos, tol);
> </code>
>  
> As you can see it uses parameters describing the view system 
> resolution (canvas size, fov, camera height over terrain) to compute a 
> premissible numerical error tolerance.
>  
> The recalculation of the origin is done as a two step process to allow 
> some objects to do long background processing that may take several 
> frames to complete. This allows the recalculation of large terrain 
> models without visible halts in the framerate.
>  
> All objects that have interest in the origin implements the 
> OriginUpdateListener interface and registers with the origin manager. 
> The OriginUpdateListener has two methods:
> <code>
> /**
>  * Listener interface for objects that have to recalculate geometry 
> because of
>  * changes in the origin
>  * @author runaas
>  */
> public interface OriginUpdateListener {
>     /**
>      * For objects requiering long calculations this method starts the
>      * computation, returns false while the calculations are running 
> and finally
>      * returns true when the calculations are complete.
>      * Objects that don't require calculations running over several 
> frames simply return true.
>      * @param p The new origin
>      * @return true if the update computations are completed
>      */
>     boolean requestUpdateOrigin(Point3d p);
>     /**
>      * Complete the origin update process, make new graphic information
>      * current etc...
>      * @param p The new origin
>      */
>     void updateOrigin(Point3d p);
> }
> </code>
>  
> The requestUpdateOrigin is polled repeatedly (each frame) until it 
> returns true. No visible changes in the objects should be performed at 
> this stage.
>  
> Finally when all objects have returned "true" the updateOrigin method 
> of all objects is called, and the origin is really changed.
>  
> Typically a simple object containng only a transform matrix is 
> implemented like this:
>  
> <code>
>     public void updateOrigin(Point3d origin) {
>         this.origin.set(origin);
>         updateTransform();
>     }
>    
>     public boolean requestUpdateOrigin(Point3d origin) {
>         return true;
>     }
> </code>
>  
> While a more complex object that requires long recomputations would be 
> something like this:
>  
> <code>
>     RenderData render_data;
>     RenderData new_render_data;
>  
>     private void computeRenderData(RenderData rd) {
>         // ..... long and complex computations  ....
>     }
>  
>     private class Updater implements Runnable {
>         Point3d origin;
>         boolean is_completed = false;
>         Updater(Point3d origin) {
>             this.origin = origin;
>         }
>         public void run() {
>             computeRenderData(origin, new_render_data);
>             synchronized (this) {
>                 is_completed = true;
>             }
>         }
>         public synchronized boolean isCompleted() {
>             return is_completed;
>         }
>     }
>     private Updater updater = null;
>     public void      updateOrigin(Point3d p) {
>         updater = null;
>         render_data.set(new_render_data);
>     }
>     public boolean requestUpdateOrigin(Point3d p) {
>         if (updater == null) {
>             updater = new Updater(p);
>             new Thread(updater).start();
>         }
>         return updater.isCompleted();
>     }
> </code>
>  
> I'm coming to web3d in Darmstadt, and I would like to attend the 
> earth3d workshop. By the way, I'm planning to raise some noise 
> pestering you with questions of why you have not based the geographic 
> coordinate format in X3D on GML??????? I believe the ISO standard for 
> 3D graphics would be much more useful if there was some 
> interoperability with the ISO standard for geographic information....
>  
> Rune Aasgaard
>  



More information about the Source mailing list