All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.render.SurfaceIcons 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.render;

import com.jogamp.opengl.util.texture.TextureCoords;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.util.SurfaceTileDrawContext;

import com.jogamp.opengl.*;
import java.awt.geom.*;
import java.util.*;

/**
 * Renders an icon image over the terrain surface in many locations.
 *
 * @author Patrick Murris
 * @version $Id: SurfaceIcons.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class SurfaceIcons extends SurfaceIcon
{
    private Iterable locations;

    public SurfaceIcons(Object imageSource, Iterable locations)
    {
        super(imageSource);
        this.setLocations(locations);
    }

    public Iterable getLocations()
    {
        return this.locations;
    }

    public void setLocations(Iterable newLocations)
    {
        this.locations = newLocations;
        this.onPropertyChanged();
    }

    protected List computeSectors(DrawContext dc)
    {
        if (this.locations == null || !this.locations.iterator().hasNext())
            return null;

        // Compute all locations bounding sector, then add some padding for the icon half diagonal extent
        Sector sector = Sector.boundingSector(this.locations);
        // Compute padding
        double minCosLat = Math.min(sector.getMinLatitude().cos(), sector.getMaxLatitude().cos());
        minCosLat = Math.max(minCosLat, .01); // avoids division by zero at the poles
        Rectangle2D iconDimension = this.computeDrawDimension(dc, sector.getCentroid());
        double diagonalLength = Math.sqrt(iconDimension.getWidth() * iconDimension.getWidth()
            + iconDimension.getHeight() * iconDimension.getHeight());
        double padLatRadians = diagonalLength / 2 / dc.getGlobe().getRadius();
        double padLonRadians = diagonalLength / 2 / dc.getGlobe().getRadius() / minCosLat;
        // Apply padding to sector
        Angle minLat = sector.getMinLatitude().subtractRadians(padLatRadians);
        Angle maxLat = sector.getMaxLatitude().addRadians(padLatRadians);
        Angle minLon = sector.getMinLongitude().subtractRadians(padLonRadians);
        Angle maxLon = sector.getMaxLongitude().addRadians(padLatRadians);

        return this.computeNormalizedSectors(new Sector(minLat, maxLat, minLon, maxLon));
    }

    protected void drawIcon(DrawContext dc, SurfaceTileDrawContext sdc)
    {
        if (this.locations == null)
            return;

        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        double drawScale = 1;
        TextureCoords textureCoords = new TextureCoords(0, 0, 1, 1);

        // Compute draw scale only once if not maintaining strict appearance
        if (!this.isMaintainAppearance())
            drawScale = this.computeDrawScale(dc, sdc, null);
        // Determine which locations are to be drawn
        Iterable drawLocations = this.computeDrawLocations(dc, sdc);
        // Draw icons
        for (LatLon location : drawLocations)
        {
            gl.glPushMatrix();

            if (this.isMaintainAppearance())
                drawScale = this.computeDrawScale(dc, sdc, location);
            this.applyDrawTransform(dc, sdc, location, drawScale);
            gl.glScaled(this.imageWidth, this.imageHeight, 1d);
            dc.drawUnitQuad(textureCoords);

            gl.glPopMatrix();
        }
    }

    protected Iterable computeDrawLocations(DrawContext dc, SurfaceTileDrawContext sdc)
    {
        ArrayList drawList = new ArrayList();
        double safeDistanceDegreesSquared = Math.pow(this.computeSafeRadius(dc, sdc).degrees, 2);
        for (LatLon location : this.getLocations())
        {
            if (this.computeLocationDistanceDegreesSquared(sdc.getSector(), location) <= safeDistanceDegreesSquared)
                drawList.add(location);
        }
        return drawList;
    }

    protected Angle computeSafeRadius(DrawContext dc, SurfaceTileDrawContext sdc)
    {
        double regionPixelSize = this.computeDrawPixelSize(dc, sdc);
        Angle sectorRadius = this.computeSectorRadius(sdc.getSector());
        Angle iconRadius = this.computeIconRadius(dc, regionPixelSize, sdc.getSector());
        return sectorRadius.add(iconRadius);
    }

    protected Angle computeSectorRadius(Sector sector)
    {
        double dLat = sector.getDeltaLatRadians();
        double dLon = sector.getDeltaLonRadians();
        return Angle.fromRadians(Math.sqrt(dLat * dLat + dLon * dLon) / 2);
    }

    protected Angle computeIconRadius(DrawContext dc, double regionPixelSize, Sector drawSector)
    {
        double minCosLat = Math.min(drawSector.getMinLatitude().cos(), drawSector.getMaxLatitude().cos());
        if (minCosLat < 0.001)
            return Angle.POS180;

        Rectangle2D iconDimension = this.computeDrawDimension(regionPixelSize); // Meter
        double dLat = iconDimension.getHeight() / dc.getGlobe().getRadius();
        double dLon = iconDimension.getWidth() / dc.getGlobe().getRadius() / minCosLat;
        return Angle.fromRadians(Math.sqrt(dLat * dLat + dLon * dLon) / 2);
    }

    protected double computeLocationDistanceDegreesSquared(Sector drawSector, LatLon location)
    {
        double lonOffset = computeHemisphereOffset(drawSector, location);
        double dLat = location.getLatitude().degrees - drawSector.getCentroid().getLatitude().degrees;
        double dLon = location.getLongitude().degrees - drawSector.getCentroid().getLongitude().degrees + lonOffset;
        return dLat * dLat + dLon * dLon;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy