/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.layers.geometry.types.airspace;
import gov.nasa.worldwind.avlist.AVList;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.Renderable;
import gov.nasa.worldwind.render.airspaces.AbstractAirspace;
import gov.nasa.worldwind.render.airspaces.Airspace;
import gov.nasa.worldwind.render.airspaces.Polygon;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import au.gov.ga.earthsci.worldwind.common.layers.geometry.GeometryLayer;
import au.gov.ga.earthsci.worldwind.common.layers.geometry.Shape;
import au.gov.ga.earthsci.worldwind.common.layers.geometry.types.GeometryLayerBase;
import au.gov.ga.earthsci.worldwind.common.layers.styled.StyleAndText;
import au.gov.ga.earthsci.worldwind.common.util.AVKeyMore;
import au.gov.ga.earthsci.worldwind.common.util.Validate;
/**
* An implementation of the {@link GeometryLayer} interface that renders each
* shape as a separate {@link Airspace}.
*
* @author James Navin (james.navin@ga.gov.au)
*/
public class AirspaceGeometryLayer extends GeometryLayerBase implements GeometryLayer
{
private List<AirspaceShape> airspaceShapes = new ArrayList<AirspaceShape>();
public AirspaceGeometryLayer(AVList params)
{
super(params);
}
@Override
public Iterable<? extends Shape> getShapes()
{
return airspaceShapes;
}
@Override
public void addShape(Shape shape)
{
synchronized (airspaceShapes)
{
if (shape == null)
{
return;
}
airspaceShapes.add(new AirspaceShape(shape));
}
}
@Override
public void renderGeometry(DrawContext dc)
{
synchronized (airspaceShapes)
{
for (AirspaceShape airspaceShape : airspaceShapes)
{
airspaceShape.render(dc);
}
}
}
/**
* A container class that associates a {@link Shape} with a renderable
* {@link Airspace}.
*/
private class AirspaceShape implements Shape, Renderable
{
private AtomicBoolean dirty = new AtomicBoolean(true);
private AbstractAirspace airspace;
private Shape shapeDelegate;
public AirspaceShape(Shape shape)
{
Validate.notNull(shape, "A shape is required");
this.shapeDelegate = shape;
}
@Override
public String getId()
{
return shapeDelegate.getId();
}
@Override
public List<? extends ShapePoint> getPoints()
{
return shapeDelegate.getPoints();
}
@Override
public void addPoint(Position p, AVList attributeValues)
{
shapeDelegate.addPoint(p, attributeValues);
dirty.set(true);
}
@Override
public void addPoint(ShapePoint p)
{
shapeDelegate.addPoint(p);
dirty.set(true);
}
@Override
public Type getType()
{
return shapeDelegate.getType();
}
/**
* Generates the airspace used to render the associated shape
*/
private void generateAirspace()
{
switch (shapeDelegate.getType())
{
case LINE:
{
airspace = new ShapeOutlineCurtain(getPoints());
break;
}
case POLYGON:
{
airspace = new Polygon(getPoints());
break;
}
}
applyStyleToAirspace();
dirty.set(false);
}
private void applyStyleToAirspace()
{
StyleAndText style = getStyleProvider().getStyle(AirspaceGeometryLayer.this);
if (style == null)
{
applyDefaultStyleToAirspace();
}
else
{
style.style.setPropertiesFromAttributes((URL) getValue(AVKeyMore.CONTEXT_URL),
AirspaceGeometryLayer.this, airspace, airspace.getAttributes(), airspace.getRenderer());
}
}
/**
* Apply some sensible defaults to the airspace in case no style was
* found
*/
private void applyDefaultStyleToAirspace()
{
airspace.setTerrainConforming(true, false);
airspace.setAltitudes(0, 100000);
airspace.getAttributes().setOpacity(0.5);
airspace.getAttributes().setOutlineWidth(2.0d);
airspace.getRenderer().setEnableAntialiasing(true);
}
@Override
public void render(DrawContext dc)
{
if (dirty.get())
{
generateAirspace();
}
airspace.render(dc);
}
}
}