Statistics
| Revision:

gvsig-3d / 2.1 / trunk / org.gvsig.view3d / org.gvsig.view3d.swing / org.gvsig.view3d.swing.impl / src / main / java / org / gvsig / view3d / swing / impl / DefaultSynchronizer.java @ 633

History | View | Annotate | Download (16.7 KB)

1
package org.gvsig.view3d.swing.impl;
2

    
3
import gov.nasa.worldwind.WorldWindow;
4
import gov.nasa.worldwind.geom.Angle;
5
import gov.nasa.worldwind.geom.Box;
6
import gov.nasa.worldwind.geom.Position;
7
import gov.nasa.worldwind.geom.Sector;
8
import gov.nasa.worldwind.globes.ElevationModel;
9
import gov.nasa.worldwind.layers.Layer;
10
import gov.nasa.worldwind.layers.LayerList;
11
import gov.nasa.worldwind.terrain.CompoundElevationModel;
12
import gov.nasa.worldwind.view.orbit.OrbitView;
13

    
14
import java.awt.geom.Point2D;
15
import java.util.Map;
16
import java.util.WeakHashMap;
17

    
18
import org.gvsig.fmap.crs.CRSFactory;
19
import org.gvsig.fmap.geom.primitive.Envelope;
20
import org.gvsig.fmap.mapcontext.MapContext;
21
import org.gvsig.fmap.mapcontext.ViewPort;
22
import org.gvsig.fmap.mapcontext.events.ColorEvent;
23
import org.gvsig.fmap.mapcontext.events.ExtentEvent;
24
import org.gvsig.fmap.mapcontext.events.ProjectionEvent;
25
import org.gvsig.fmap.mapcontext.events.listeners.ViewPortListener;
26
import org.gvsig.fmap.mapcontext.layers.CancelationException;
27
import org.gvsig.fmap.mapcontext.layers.FLayer;
28
import org.gvsig.fmap.mapcontext.layers.FLayers;
29
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
30
import org.gvsig.fmap.mapcontext.layers.LayerCollectionListener;
31
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
32
import org.gvsig.fmap.mapcontext.layers.LayerListener;
33
import org.gvsig.fmap.mapcontext.layers.LayerPositionEvent;
34
import org.gvsig.view3d.lib.api.View3DLocator;
35
import org.gvsig.view3d.lib.api.properties.LayerProperties3D;
36
import org.gvsig.view3d.swing.api.View3DSwingLocator;
37
import org.gvsig.view3d.swing.api.View3DSwingManager;
38
import org.gvsig.view3d.swing.api.exceptions.ConversionLayerException;
39
import org.gvsig.view3d.swing.api.properties.GeneralProperties3D;
40
import org.gvsig.view3d.swing.api.properties.MapControlProperties3D;
41
import org.slf4j.Logger;
42
import org.slf4j.LoggerFactory;
43

    
44
/**
45
 * This entity manages layer collection and layer events to synchronize WW
46
 * layers.
47
 * 
48
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
49
 *
50
 */
51
public class DefaultSynchronizer {
52

    
53
    private static final Logger LOG = LoggerFactory.getLogger(DefaultSynchronizer.class);
54

    
55
    private Map<FLayer, Object> register = new WeakHashMap<FLayer, Object>();
56

    
57
    private DefaultMapControl3D mapControl3D;
58
    private MapContext mapContext;
59
    private WorldWindow wwd;
60

    
61
    protected DefaultSynchronizer(DefaultMapControl3D theMapControl3D, MapContext theMapContext,
62
        WorldWindow wwd) {
63

    
64
        this.mapControl3D = theMapControl3D;
65
        this.mapContext = theMapContext;
66
        this.wwd = wwd;
67

    
68
        addLayerCollectionListener(mapContext.getLayers());
69
        addViewPortListener(mapContext.getViewPort());
70
        addLayerListener(mapContext.getLayers());
71
    }
72

    
73
    private void addLayerListener(FLayer layer) {
74
        if (layer == null) {
75
            return;
76
        }
77
        layer.addLayerListener(getLayerListener());
78
    }
79

    
80
    private void addLayerCollectionListener(FLayers layers) {
81

    
82
        if (layers == null) {
83
            return;
84
        }
85

    
86
        layers.addLayerCollectionListener(new LayerCollectionListener() {
87

    
88
            public void layerAdded(LayerCollectionEvent e) {
89

    
90
                if (mapControl3D.getProperties().getAutoLayerSynchronize()) {
91
                    FLayer affectedLayer = e.getAffectedLayer();
92
                    try {
93
                        addLayer(affectedLayer);
94
                        // Add layer listener to new layer
95
                        addLayerListener(affectedLayer);
96
                    } catch (ConversionLayerException e1) {
97
                        LOG.error("Synchronizer can not add {} layer to 3D view",
98
                            affectedLayer.getName());
99
                        return;
100
                    }
101
                }
102
            }
103

    
104
            public void layerAdding(LayerCollectionEvent e) throws CancelationException {
105
            }
106

    
107
            public void layerMoved(LayerPositionEvent e) {
108

    
109
                if (mapControl3D.getProperties().getAutoLayerSynchronize()) {
110
                    FLayer affectedLayer = e.getAffectedLayer();
111
                    int oldPos = e.getOldPos();
112
                    int newPos = e.getNewPos();
113

    
114
                    // Only move layer is layer has changed position.
115
                    if (oldPos != newPos) {
116
                        try {
117
                            moveLayer(affectedLayer, oldPos, newPos);
118
                        } catch (ConversionLayerException e1) {
119
                            LOG.error("Synchronizer can not move {} layer", affectedLayer.getName());
120
                            return;
121
                        }
122
                    }
123
                }
124
            }
125

    
126
            public void layerMoving(LayerPositionEvent e) throws CancelationException {
127
            }
128

    
129
            public void layerRemoved(LayerCollectionEvent e) {
130
                if (mapControl3D.getProperties().getAutoLayerSynchronize()) {
131
                    FLayer affectedLayer = e.getAffectedLayer();
132
                    removeLayer(affectedLayer);
133
                }
134
            }
135

    
136
            public void layerRemoving(LayerCollectionEvent e) throws CancelationException {
137
            }
138

    
139
            public void visibilityChanged(LayerCollectionEvent e) throws CancelationException {
140

    
141
                if (mapControl3D.getProperties().getAutoLayerSynchronize()) {
142
                    FLayer affectedLayer = e.getAffectedLayer();
143

    
144
                    if (getTileImageLayer(affectedLayer) != null) {
145
                        getTileImageLayer(affectedLayer).setEnabled(affectedLayer.isVisible());
146
                    }
147
                }
148
            }
149
        });
150
    }
151

    
152
    private LayerListener getLayerListener() {
153
        return new LayerListener() {
154

    
155
            public void activationChanged(LayerEvent e) {
156
            }
157

    
158
            public void drawValueChanged(LayerEvent e) {
159

    
160
                if (mapControl3D.getProperties().getAutoLayerSynchronize()) {
161
                    FLayer layer = e.getSource();
162
                    LayerProperties3D layerProperties = View3DLocator.getManager().getLayerProperties(layer);
163
                    
164
                    // If load mode change reload layer. FIXME: Change this when there are more load modes.
165
                    if (layerProperties.getElevation() == false && getElevationModel(layer) != null){
166
                        reloadLayer(layer, wwd.getModel().getLayers().size());
167
                        return;
168
                    } else if( layerProperties.getElevation() == true && getTileImageLayer(layer) != null) {
169
                        CompoundElevationModel compoundElevation =
170
                            (CompoundElevationModel) wwd.getModel().getGlobe().getElevationModel();
171
                        reloadLayer(layer, compoundElevation.getElevationModels().size());
172
                        return;
173
                    }
174
                    
175
                    // Set expire time to invalidate tile cache layer.
176
                    if (getTileImageLayer(layer) != null) {
177
                        getTileImageLayer(layer).setExpiryTime(System.currentTimeMillis());
178
                    } else if (getElevationModel(layer) != null) {
179
                        getElevationModel(layer).setExpiryTime(System.currentTimeMillis());
180
                    }
181
                }
182
            }
183

    
184
            public void editionChanged(LayerEvent e) {
185
                // After edition finish it is necessary to reopen store to
186
                // refresh layer
187
                if (mapControl3D.getProperties().getAutoLayerSynchronize()) {
188
                    FLayer layer = e.getSource();
189
                    if (!layer.isEditing()) {
190
                        reloadLayer(layer);
191
                    }
192
                }
193
            }
194

    
195
            public void nameChanged(LayerEvent e) {
196
            }
197

    
198
            public void visibilityChanged(LayerEvent e) {
199
                if (mapControl3D.getProperties().getAutoLayerSynchronize()) {
200
                    FLayer affectedLayer = e.getSource();
201

    
202
                    if (getTileImageLayer(affectedLayer) != null) {
203
                        getTileImageLayer(affectedLayer).setEnabled(affectedLayer.isVisible());
204
                    }
205
                }
206
            }
207
        };
208
    }
209
    
210
    private void reloadLayer(FLayer layer){
211
        int index = getLayerIndex(layer);
212
        reloadLayer(layer, index);
213
    }
214
    
215
    private void reloadLayer(FLayer layer, int index){
216
        removeLayer(layer);
217
        try {
218
            addLayer(layer, index);
219
        } catch (ConversionLayerException e1) {
220
            LOG.error("Can not add convert {} layer to update it after edition",
221
                layer.getName(), e1);
222
        }
223
    }
224

    
225
    private void addViewPortListener(ViewPort viewPort) {
226

    
227
        viewPort.addViewPortListener(new ViewPortListener() {
228

    
229
            public void projectionChanged(ProjectionEvent e) {
230
            }
231

    
232
            public void extentChanged(ExtentEvent e) {
233
                MapControlProperties3D properties = mapControl3D.getProperties();
234
                boolean autoViewSynchronize = properties.getAutoViewPortSynchronize();
235
                if (autoViewSynchronize) {
236
                    synchronizeViewPorts();
237
                }
238
            }
239

    
240
            public void backColorChanged(ColorEvent e) {
241
            }
242
        });
243
    }
244

    
245
    private Layer getTileImageLayer(FLayer layer) {
246

    
247
        if (this.register.get(layer) instanceof Layer) {
248
            return (Layer) this.register.get(layer);
249
        }
250

    
251
        return null;
252
    }
253

    
254
    private ElevationModel getElevationModel(FLayer layer) {
255

    
256
        if (this.register.get(layer) instanceof ElevationModel) {
257
            return (ElevationModel) this.register.get(layer);
258
        }
259

    
260
        return null;
261
    }
262

    
263
    protected void synchronizeViewPorts() {
264

    
265
        // Convert envelope to WorldWind sector
266
        ViewPort viewPort = this.mapContext.getViewPort();
267
        Envelope envelope = viewPort.getEnvelope();
268
        Sector sector = Sector.FULL_SPHERE;
269

    
270
        if (envelope != null) {
271

    
272
            if (!viewPort.getProjection().equals(CRSFactory.getCRS("EPSG:4326"))) {
273
                envelope =
274
                    envelope
275
                        .convert(viewPort.getProjection().getCT(CRSFactory.getCRS("EPSG:4326")));
276
            }
277

    
278
            sector = getSector(envelope);
279
        }
280

    
281
        // Create a bounding box for the specified sector in order to estimate
282
        // its size in model coordinates.
283
        Box extent =
284
            Sector.computeBoundingBox(wwd.getModel().getGlobe(),
285
                mapControl3D.getVerticalExaggeration(), sector);
286

    
287
        // Estimate the distance between the center position and the eye
288
        // position that is necessary to cause the sector to
289
        // fill a viewport with the specified field of view. Note that we change
290
        // the distance between the center and eye
291
        // position here, and leave the field of view constant.
292
        Angle fov = wwd.getView().getFieldOfView();
293
        double zoom = extent.getRadius() / fov.cosHalfAngle() / fov.tanHalfAngle();
294

    
295
        View3DSwingManager swingManager = View3DSwingLocator.getManager();
296
        GeneralProperties3D general3dProperties = swingManager.getGeneral3DProperties();
297

    
298
        if (general3dProperties.getViewPortAnimation()) {
299
            wwd.getView().goTo(new Position(sector.getCentroid(), 0d), zoom);
300
        } else {
301
            ((OrbitView) wwd.getView()).setCenterPosition(new Position(sector.getCentroid(), 0d));
302
            ((OrbitView) wwd.getView()).setZoom(zoom);
303
            wwd.redraw();
304
        }
305
    }
306

    
307
    void setViewPortEnvelope(Envelope envelope) {
308
        
309
        // Convert envelope to WorldWind sector
310
        Sector sector = getSector(envelope);
311
        
312
        // Create a bounding box for the specified sector in order to estimate
313
        // its size in model coordinates.
314
        Box extent = Sector.computeBoundingBox(wwd.getModel().getGlobe(),
315
            mapControl3D.getVerticalExaggeration(), sector);
316
        
317
        // Estimate the distance between the center position and the eye
318
        // position that is necessary to cause the sector to
319
        // fill a viewport with the specified field of view. Note that we change
320
        // the distance between the center and eye
321
        // position here, and leave the field of view constant.
322
        Angle fov = wwd.getView().getFieldOfView();
323
        double zoom = extent.getRadius() / fov.cosHalfAngle() / fov.tanHalfAngle();
324
        
325
        View3DSwingManager swingManager = View3DSwingLocator.getManager();
326
        GeneralProperties3D general3dProperties = swingManager.getGeneral3DProperties();
327
        
328
        if(general3dProperties.getViewPortAnimation()){
329
            wwd.getView().goTo(new Position(sector.getCentroid(), 0d), zoom);
330
        } else {
331
            ((OrbitView) wwd.getView()).setCenterPosition(new Position(sector
332
                .getCentroid(), 0d));
333
            ((OrbitView) wwd.getView()).setZoom(zoom);
334
            wwd.redraw();
335
        }
336
    }
337

    
338
    private Sector getSector(Envelope envelope) {
339

    
340
        Point2D p1 = null;
341
        Point2D p2 = null;
342

    
343
        p1 = new Point2D.Double(envelope.getMinimum(0), envelope.getMinimum(1));
344
        p2 = new Point2D.Double(envelope.getMaximum(0), envelope.getMaximum(1));
345

    
346
        double minLatitude =
347
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees ? Angle.NEG90.degrees
348
                : p1.getY();
349
        double maxLatitude =
350
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees ? Angle.POS90.degrees
351
                : p2.getY();
352
        double minLongitude =
353
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees ? Angle.NEG180.degrees
354
                : p1.getX();
355
        double maxLongitude =
356
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees ? Angle.POS180.degrees
357
                : p2.getX();
358

    
359
        Sector sector =
360
            new Sector(Sector.fromDegrees(minLatitude, maxLatitude, minLongitude, maxLongitude));
361

    
362
        return sector;
363
    }
364

    
365
    private int getLayerIndex(FLayer layer) {
366

    
367
        if (getTileImageLayer(layer) != null) {
368

    
369
            Layer tileImageLayer = getTileImageLayer(layer);
370
            return this.wwd.getModel().getLayers().indexOf(tileImageLayer);
371

    
372
        } else if (getElevationModel(layer) != null) {
373

    
374
            ElevationModel elevationModel = getElevationModel(layer);
375
            CompoundElevationModel compoundElevationModel =
376
                (CompoundElevationModel) wwd.getModel().getGlobe().getElevationModel();
377
            return compoundElevationModel.getElevationModels().indexOf(elevationModel);
378

    
379
        }
380

    
381
        return 0;
382
    }
383

    
384
    private void addLayer(FLayer layer) throws ConversionLayerException {
385
        this.mapControl3D.addGvSIGLayer(layer);
386
    }
387

    
388
    private void addLayer(FLayer layer, int pos) throws ConversionLayerException {
389
        this.mapControl3D.addGvSIGLayer(layer, pos);
390
    }
391

    
392
    private void removeLayer(FLayer layer) {
393

    
394
        ElevationModel eModel = getElevationModel(layer);
395
        Layer tiledImageLayer = getTileImageLayer(layer);
396

    
397
        if (eModel != null) {
398
            CompoundElevationModel compoundEModel =
399
                (CompoundElevationModel) wwd.getModel().getGlobe().getElevationModel();
400
            compoundEModel.removeElevationModel(eModel);
401
        } else if (tiledImageLayer != null) {
402
            wwd.getModel().getLayers().remove(tiledImageLayer);
403
        }
404
        
405
        this.register.remove(layer);
406
    }
407

    
408
    private void moveLayer(FLayer layer, int oldPos, int newPos) throws ConversionLayerException {
409
        int index = getLayerIndex(layer);
410
        int newIndex = index + (newPos - oldPos);
411
        LayerList layerList = this.wwd.getModel().getLayers();
412

    
413
        if (getTileImageLayer(layer) != null) {
414
            layerList.remove(getTileImageLayer(layer));
415
            if (newIndex <= layerList.size()) {
416
                layerList.add(newIndex, getTileImageLayer(layer));
417
            } else {
418
                LOG.warn("Error getting new index of layer. Layer will be added at {}",
419
                    layerList.size());
420
                layerList.add(getTileImageLayer(layer));
421
            }
422
        } else if (getElevationModel(layer) != null) {
423
            CompoundElevationModel compoundEModel =
424
                (CompoundElevationModel) wwd.getModel().getGlobe().getElevationModel();
425
            compoundEModel.removeElevationModel(getElevationModel(layer));
426
            if (newIndex <= compoundEModel.getElevationModels().size()) {
427
                compoundEModel.addElevationModel(newIndex, getElevationModel(layer));
428
            } else {
429
                LOG.warn("Error getting new index of layer. Layer will be added at {}",
430
                    compoundEModel.getElevationModels().size());
431
                compoundEModel.addElevationModel(getElevationModel(layer));
432
            }
433
        }
434
    }
435

    
436
    protected void registerLayer(FLayer layer, Object wwLayer) {
437
        register.put(layer, wwLayer);
438
    }
439
}