gov.nasa.worldwind.formats.vpf.VPFLayer Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.formats.vpf;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.layers.AbstractLayer;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.*;
import java.beans.*;
import java.util.*;
import java.util.concurrent.*;
/**
* Renders elements from a VPF database.
*
* @author Patrick Murris
* @version $Id: VPFLayer.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class VPFLayer extends AbstractLayer
{
public static final String LIBRARY_CHANGED = "VPFLayer.LibraryChanged";
public static final String COVERAGE_CHANGED = "VPFLayer.CoverageChanged";
// Reference
protected VPFDatabase db;
protected ArrayList libraries;
// Renderables
protected double drawDistance = 1e6;
protected int maxTilesToDraw = 4;
protected boolean drawTileExtents = false;
protected ArrayList symbols = new ArrayList();
protected ArrayList textObjects = new ArrayList();
protected ArrayList renderableObjects = new ArrayList();
// Renderers
protected GeographicTextRenderer textRenderer = new GeographicTextRenderer();
protected VPFSymbolSupport symbolSupport = new VPFSymbolSupport(GeoSymConstants.GEOSYM, "image/png");
// Threaded requests
protected Queue requestQ = new PriorityBlockingQueue(4);
protected Queue disposalQ = new ConcurrentLinkedQueue();
// --- Inner classes ----------------------------------------------------------------------
protected static final VPFTile NULL_TILE = new VPFTile(-1, "NullTile", new VPFBoundingBox(0, 0, 0, 0));
protected static class VPFLibraryRenderable
{
protected boolean enabled = false;
protected VPFLayer layer;
protected VPFLibrary library;
protected VPFCoverageRenderable referenceCoverage;
protected ArrayList coverages = new ArrayList();
protected ArrayList currentTiles = new ArrayList();
public VPFLibraryRenderable(VPFLayer layer, VPFLibrary library)
{
this.layer = layer;
this.library = library;
for (VPFCoverage cov : this.library.getCoverages())
{
if (cov.getName().equalsIgnoreCase(VPFConstants.LIBRARY_REFERENCE_COVERAGE))
this.referenceCoverage = new VPFCoverageRenderable(this.layer, cov);
else
this.coverages.add(new VPFCoverageRenderable(this.layer, cov));
}
if (this.referenceCoverage != null)
{
this.referenceCoverage.enabled = true;
}
}
public void assembleSymbols(DrawContext dc, double drawDistance, int maxTilesToDraw)
{
if (!this.enabled)
return;
this.assembleVisibleTiles(dc, drawDistance, maxTilesToDraw);
if (this.referenceCoverage != null)
{
this.referenceCoverage.assembleSymbols(null);
}
for (VPFCoverageRenderable cr : this.coverages)
{
cr.assembleSymbols((cr.coverage.isTiled() ? this.currentTiles : null));
}
}
public void drawTileExtents(DrawContext dc)
{
for (VPFTile tile : this.currentTiles)
{
Extent extent = tile.getExtent(dc.getGlobe(), dc.getVerticalExaggeration());
if (extent instanceof Renderable)
((Renderable) extent).render(dc);
}
}
public void setCoverageEnabled(VPFCoverage coverage, boolean enabled)
{
VPFCoverageRenderable cr = this.getCoverageRenderable(coverage);
if (cr != null)
cr.enabled = enabled;
this.layer.firePropertyChange(AVKey.LAYER, null, this.layer);
}
public VPFCoverageRenderable getCoverageRenderable(VPFCoverage coverage)
{
for (VPFCoverageRenderable cr : this.coverages)
{
if (cr.coverage.getFilePath().equals(coverage.getFilePath()))
return cr;
}
return null;
}
protected void assembleVisibleTiles(DrawContext dc, double drawDistance, int maxTilesToDraw)
{
this.currentTiles.clear();
if (!this.library.hasTiledCoverages())
return;
Frustum frustum = dc.getView().getFrustumInModelCoordinates();
Vec4 eyePoint = dc.getView().getEyePoint();
for (VPFTile tile : this.library.getTiles())
{
Extent extent = tile.getExtent(dc.getGlobe(), dc.getVerticalExaggeration());
double d = extent.getCenter().distanceTo3(eyePoint) - extent.getRadius();
if (d < drawDistance && frustum.intersects(extent))
this.currentTiles.add(tile);
}
// Trim down list to four closest tiles
while (this.currentTiles.size() > maxTilesToDraw)
{
int idx = -1;
double maxDistance = 0;
for (int i = 0; i < this.currentTiles.size(); i++)
{
Extent extent = this.currentTiles.get(i).getExtent(dc.getGlobe(), dc.getVerticalExaggeration());
double distance = dc.getView().getEyePoint().distanceTo3(extent.getCenter());
if (distance > maxDistance)
{
maxDistance = distance;
idx = i;
}
}
this.currentTiles.remove(idx);
}
}
}
protected static class VPFCoverageRenderable
{
protected boolean enabled = false;
protected VPFLayer layer;
protected VPFCoverage coverage;
protected Map tileCache;
public VPFCoverageRenderable(VPFLayer layer, VPFCoverage coverage)
{
this.layer = layer;
this.coverage = coverage;
this.tileCache = Collections.synchronizedMap(new BoundedHashMap(6, true)
{
protected boolean removeEldestEntry(Map.Entry eldest)
{
if (!super.removeEldestEntry(eldest))
return false;
dispose(eldest.getValue());
return true;
}
});
}
public void assembleSymbols(Iterable extends VPFTile> tiles)
{
if (!this.enabled)
return;
if (tiles == null)
{
this.doAssembleSymbols(NULL_TILE);
return;
}
for (VPFTile tile : tiles)
{
this.doAssembleSymbols(tile);
}
}
protected void doAssembleSymbols(VPFTile tile)
{
VPFSymbolCollection symbolCollection = this.tileCache.get(tile);
if (symbolCollection != null)
{
this.layer.symbols.addAll(symbolCollection.getSymbols());
}
else
{
this.layer.requestQ.add(new RequestTask(this, tile));
}
}
protected void dispose(VPFSymbolCollection renderInfo)
{
this.layer.disposalQ.add(renderInfo);
}
}
protected static class VPFSymbolCollection implements Disposable
{
public static final VPFSymbolCollection EMPTY_SYMBOL_COLLECTION = new VPFSymbolCollection(null);
protected final ArrayList symbols = new ArrayList();
public VPFSymbolCollection(Collection extends VPFSymbol> symbols)
{
if (symbols != null)
this.symbols.addAll(symbols);
}
public Collection getSymbols()
{
return Collections.unmodifiableCollection(this.symbols);
}
public void dispose()
{
for (VPFSymbol s : this.symbols)
{
if (s == null)
continue;
if (s.getMapObject() instanceof Disposable)
{
((Disposable) s.getMapObject()).dispose();
}
}
this.symbols.clear();
}
}
protected VPFSymbolCollection loadTileSymbols(VPFCoverage coverage, VPFTile tile)
{
VPFPrimitiveDataFactory primitiveDataFactory = new VPFBasicPrimitiveDataFactory(tile);
VPFPrimitiveData primitiveData = primitiveDataFactory.createPrimitiveData(coverage);
// The PrimitiveDataFactory returns null when there are no primitive data tables for this coverage tile. We
// return the constant EMPTY_SYMBOL_COLLECTION to indicate that we have successfully loaded nothing the empty
// contents of this coverage tile.
if (primitiveData == null)
{
return VPFSymbolCollection.EMPTY_SYMBOL_COLLECTION;
}
VPFBasicSymbolFactory symbolFactory = new VPFBasicSymbolFactory(tile, primitiveData);
symbolFactory.setStyleSupport(this.symbolSupport);
ArrayList list = new ArrayList();
// Create coverage renderables for one tile - if tile is null gets all coverage
VPFFeatureClass[] array = VPFUtils.readFeatureClasses(coverage, new VPFFeatureTableFilter());
for (VPFFeatureClass cls : array)
{
Collection extends VPFSymbol> symbols = cls.createFeatureSymbols(symbolFactory);
if (symbols != null)
list.addAll(symbols);
}
return new VPFSymbolCollection(list);
}
protected static class RequestTask implements Runnable, Comparable
{
protected VPFCoverageRenderable coverageRenderable;
protected VPFTile tile;
protected RequestTask(VPFCoverageRenderable coverageRenderable, VPFTile tile)
{
this.coverageRenderable = coverageRenderable;
this.tile = tile;
}
public void run()
{
VPFSymbolCollection symbols = this.coverageRenderable.layer.loadTileSymbols(
this.coverageRenderable.coverage, (this.tile != NULL_TILE) ? this.tile : null);
this.coverageRenderable.tileCache.put(this.tile, symbols);
this.coverageRenderable.layer.firePropertyChange(AVKey.LAYER, null, this.coverageRenderable.layer);
}
/**
* @param that the task to compare
*
* @return -1 if this
less than that
, 1 if greater than, 0 if equal
*
* @throws IllegalArgumentException if that
is null
*/
public int compareTo(RequestTask that)
{
if (that == null)
{
String msg = Logging.getMessage("nullValue.RequestTaskIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
return 0;
}
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
RequestTask that = (RequestTask) o;
if (coverageRenderable != null ? !coverageRenderable.equals(that.coverageRenderable)
: that.coverageRenderable != null)
return false;
//noinspection RedundantIfStatement
if (tile != null ? !tile.equals(that.tile) : that.tile != null)
return false;
return true;
}
public int hashCode()
{
int result = coverageRenderable != null ? coverageRenderable.hashCode() : 0;
result = 31 * result + (tile != null ? tile.hashCode() : 0);
return result;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("coverageRenderable=").append(this.coverageRenderable.coverage.getName());
sb.append(", tile=").append(this.tile);
return sb.toString();
}
}
// --- VPF Layer ----------------------------------------------------------------------
public VPFLayer()
{
this(null);
}
public VPFLayer(VPFDatabase db)
{
this.setName("VPF Layer");
this.setPickEnabled(false);
if (db != null)
this.setVPFDatabase(db);
this.textRenderer.setCullTextEnabled(true);
this.textRenderer.setEffect(AVKey.TEXT_EFFECT_OUTLINE);
}
public VPFDatabase getVPFDatabase()
{
return this.db;
}
public void setVPFDatabase(VPFDatabase db)
{
this.db = db;
this.initialize();
this.db.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent event)
{
if (event.getPropertyName().equals(LIBRARY_CHANGED))
{
VPFLibrary library = (VPFLibrary) event.getSource();
boolean enabled = (Boolean) event.getNewValue();
setLibraryEnabled(library, enabled);
}
else if (event.getPropertyName().equals(COVERAGE_CHANGED))
{
VPFCoverage coverage = (VPFCoverage) event.getSource();
boolean enabled = (Boolean) event.getNewValue();
setCoverageEnabled(coverage, enabled);
}
}
});
}
protected void initialize()
{
this.libraries = new ArrayList();
for (VPFLibrary lib : db.getLibraries())
{
this.libraries.add(new VPFLibraryRenderable(this, lib));
}
}
public void setCoverageEnabled(VPFCoverage coverage, boolean enabled)
{
for (VPFLibraryRenderable lr : this.libraries)
{
lr.setCoverageEnabled(coverage, enabled);
}
}
public void doPreRender(DrawContext dc)
{
// Assemble renderables lists
this.assembleRenderables(dc);
// Handle object disposal.
this.handleDisposal();
// Pre render renderable objects.
for (Renderable r : this.renderableObjects)
{
if (r instanceof PreRenderable)
((PreRenderable) r).preRender(dc);
}
}
public void doRender(DrawContext dc)
{
for (Renderable r : this.renderableObjects) // Other renderables
{
r.render(dc);
}
this.textRenderer.render(dc, this.textObjects); // Geo text
if (this.drawTileExtents)
{
for (VPFLibraryRenderable lr : this.libraries)
{
lr.drawTileExtents(dc);
}
}
}
public void setLibraryEnabled(VPFLibrary library, boolean enabled)
{
VPFLibraryRenderable lr = this.getLibraryRenderable(library);
if (lr != null)
lr.enabled = enabled;
this.firePropertyChange(AVKey.LAYER, null, this);
}
public VPFLibraryRenderable getLibraryRenderable(VPFLibrary library)
{
for (VPFLibraryRenderable lr : this.libraries)
{
if (lr.library.getFilePath().equals(library.getFilePath()))
return lr;
}
return null;
}
public Iterable getActiveSymbols()
{
return this.symbols;
}
protected void assembleRenderables(DrawContext dc)
{
this.symbols.clear();
this.textObjects.clear();
this.renderableObjects.clear();
for (VPFLibraryRenderable lr : this.libraries)
{
lr.assembleSymbols(dc, this.drawDistance, this.maxTilesToDraw);
}
this.sortSymbols(this.symbols);
// Dispatch renderable according to its class
for (VPFSymbol symbol : this.symbols)
{
if (symbol.getMapObject() instanceof GeographicText)
this.textObjects.add((GeographicText) symbol.getMapObject());
else if (symbol.getMapObject() instanceof Renderable)
this.renderableObjects.add((Renderable) symbol.getMapObject());
}
this.sendRequests();
this.requestQ.clear();
}
protected void sortSymbols(List list)
{
Collections.sort(list, new VPFSymbolComparator());
}
protected void handleDisposal()
{
Disposable disposable;
while ((disposable = this.disposalQ.poll()) != null)
{
disposable.dispose();
}
}
protected void sendRequests()
{
Runnable task;
while ((task = this.requestQ.poll()) != null)
{
if (!WorldWind.getTaskService().isFull())
{
WorldWind.getTaskService().addTask(task);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy