placenamelayer.java

来自「world wind java sdk 源码」· Java 代码 · 共 1,493 行 · 第 1/4 页

JAVA
1,493
字号
/*
Copyright (C) 2001, 2006 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.layers.placename;

import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.cache.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.layers.*;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.retrieve.*;
import gov.nasa.worldwind.util.*;

import java.net.URL;
import java.nio.*;
import java.nio.channels.ClosedByInterruptException;
import java.util.*;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.logging.Level;

/**
 * @author Paul Collins
 * @version $Id: PlaceNameLayer.java 10925 2009-05-06 22:22:50Z dcollins $
 */
public class PlaceNameLayer extends AbstractLayer implements BulkRetrievable
{
    private final PlaceNameServiceSet placeNameServiceSet;
    private PriorityBlockingQueue<Runnable> requestQ = new PriorityBlockingQueue<Runnable>(64);
    private Vec4 referencePoint;
    private final Object fileLock = new Object();
    private boolean cullNames = false;

    protected static final double LEVEL_A = 0x1 << 25;
    protected static final double LEVEL_B = 0x1 << 24;
    protected static final double LEVEL_C = 0x1 << 23;
    protected static final double LEVEL_D = 0x1 << 22;
    protected static final double LEVEL_E = 0x1 << 21;
    protected static final double LEVEL_F = 0x1 << 20;
    protected static final double LEVEL_G = 0x1 << 19;
    protected static final double LEVEL_H = 0x1 << 18;
    protected static final double LEVEL_I = 0x1 << 17;
    protected static final double LEVEL_J = 0x1 << 16;
    protected static final double LEVEL_K = 0x1 << 15;
    protected static final double LEVEL_L = 0x1 << 14;
    protected static final double LEVEL_M = 0x1 << 13;
    protected static final double LEVEL_N = 0x1 << 12;
    protected static final double LEVEL_O = 0x1 << 11;
    protected static final double LEVEL_P = 0x1 << 10;
    protected static final LatLon GRID_1x1 = new LatLon(Angle.fromDegrees(180d), Angle.fromDegrees(360d));
    protected static final LatLon GRID_4x8 = new LatLon(Angle.fromDegrees(45d), Angle.fromDegrees(45d));
    protected static final LatLon GRID_8x16 = new LatLon(Angle.fromDegrees(22.5d), Angle.fromDegrees(22.5d));
    protected static final LatLon GRID_16x32 = new LatLon(Angle.fromDegrees(11.25d), Angle.fromDegrees(11.25d));
    protected static final LatLon GRID_36x72 = new LatLon(Angle.fromDegrees(5d), Angle.fromDegrees(5d));
    protected static final LatLon GRID_72x144 = new LatLon(Angle.fromDegrees(2.5d), Angle.fromDegrees(2.5d));
    protected static final LatLon GRID_144x288 = new LatLon(Angle.fromDegrees(1.25d), Angle.fromDegrees(1.25d));
    protected static final LatLon GRID_288x576 = new LatLon(Angle.fromDegrees(0.625d), Angle.fromDegrees(0.625d));

    private List<NavigationTile> navTiles = new ArrayList<NavigationTile>();    //top navigation tiles for each service

    /**
     * @param placeNameServiceSet the set of PlaceNameService objects that PlaceNameLayer will render.
     * @throws IllegalArgumentException if  {@link gov.nasa.worldwind.layers.placename.PlaceNameServiceSet} is null
     */
    public PlaceNameLayer(PlaceNameServiceSet placeNameServiceSet)
    {
        if (placeNameServiceSet == null)
        {
            String message = Logging.getMessage("nullValue.PlaceNameServiceSetIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        //  
        this.placeNameServiceSet = placeNameServiceSet.deepCopy();
        for (int i = 0; i < this.placeNameServiceSet.getServiceCount(); i++)
        {
            //todo do this for long as well and pick min
            int calc1 = (int) (PlaceNameService.TILING_SECTOR.getDeltaLatDegrees()/this.placeNameServiceSet.getService(i).getTileDelta().getLatitude().getDegrees());
            int numLevels=(int)Math.log(calc1);
            navTiles.add(new NavigationTile(this.placeNameServiceSet.getService(i), PlaceNameService.TILING_SECTOR, numLevels, "top"));
        }

        if (!WorldWind.getMemoryCacheSet().containsCache(Tile.class.getName()))
        {
            long size = Configuration.getLongValue(AVKey.PLACENAME_LAYER_CACHE_SIZE, 2000000L);
            MemoryCache cache = new BasicMemoryCache((long) (0.85 * size), size);
            cache.setName("Placename Tiles");
            WorldWind.getMemoryCacheSet().addCache(Tile.class.getName(), cache);
        }
    }

    public boolean isCullNames()
    {
        return cullNames;
    }

    public void setCullNames(boolean cullNames)
    {
        this.cullNames = cullNames;
        placeNameRenderer.setCullTextEnabled(cullNames);
    }

    public final PlaceNameServiceSet getPlaceNameServiceSet()
    {
        return this.placeNameServiceSet;
    }

    private PriorityBlockingQueue<Runnable> getRequestQ()
    {
        return this.requestQ;
    }

    // ============== Tile Assembly ======================= //
    // ============== Tile Assembly ======================= //
    // ============== Tile Assembly ======================= //

    private class NavigationTile
    {
        String id;
        private PlaceNameService placeNameService;
        public Sector navSector;
        private List<NavigationTile> subNavTiles= new ArrayList<NavigationTile>();
        private List<Integer> tileKeys = new ArrayList<Integer>();
        private int level;

        NavigationTile(PlaceNameService placeNameService, Sector sector, int levels, String id)
        {
            this.placeNameService = placeNameService;
            this.id=id;
            this.navSector = sector;
            level=levels;
        }

        private void buildSubNavTiles()
        {
            if (level > 0)
            {
               //split sector, create a navTile for each quad
                Sector[] subSectors=this.navSector.subdivide();
                for( int j=0; j<subSectors.length; j++)
                {
                     subNavTiles.add(new NavigationTile(placeNameService, subSectors[j], level-1, this.id+"."+j));
                }
            }
        }

        public List<NavigationTile> navTilesVisible(DrawContext dc, double minDistSquared, double maxDistSquared)
        {
            ArrayList<NavigationTile> navList=new ArrayList<NavigationTile>();
            if (this.isNavSectorVisible(dc, minDistSquared, maxDistSquared))
            {
                if ( this.level > 0 && !this.hasSubTiles())
                    this.buildSubNavTiles();

                if (this.hasSubTiles())
                {
                    for(NavigationTile nav: subNavTiles)
                    {
                        navList.addAll(nav.navTilesVisible(dc, minDistSquared, maxDistSquared));
                    }
                }else  //at bottom level navigation tile
                {
                    navList.add(this);
                }
            }

            return navList;
        }

        //Added for bulk download, does not use eye position to determine visibility
        //todo validate sector
        public List<NavigationTile> navTilesVisible(Sector sector)
        {
            ArrayList<NavigationTile> navList=new ArrayList<NavigationTile>();
            if (navSector.intersects(sector))
            {
                if ( this.level > 0 && !this.hasSubTiles())
                    this.buildSubNavTiles();

                if (this.hasSubTiles())
                {
                    for(NavigationTile nav: subNavTiles)
                    {
                        navList.addAll(nav.navTilesVisible(sector));
                    }
                }else  //at bottom level navigation tile
                {
                    navList.add(this);
                }
            }

            return navList;
        }

        private int estimateNumberTilesinSector(Sector searchSector)
        {
            final Angle dLat = placeNameService.getTileDelta().getLatitude();
            final Angle dLon = placeNameService.getTileDelta().getLongitude();

            // Determine the row and column offset from the global tiling origin for the southwest tile corner
            int firstRow = Tile.computeRow(dLat, this.navSector.getMinLatitude());
            int firstCol = Tile.computeColumn(dLon, this.navSector.getMinLongitude());
            int lastRow = Tile.computeRow(dLat, this.navSector.getMaxLatitude().subtract(dLat));
            int lastCol = Tile.computeColumn(dLon, this.navSector.getMaxLongitude().subtract(dLon));

            int tileCount=0;
            Angle p1 = Tile.computeRowLatitude(firstRow, dLat);
            boolean needToCheckDisk = true;
            for (int row = 0; row <= lastRow-firstRow; row++)
            {
                Angle p2;
                p2 = p1.add(dLat);

                Angle t1 = Tile.computeColumnLongitude(firstCol, dLon);
                for (int col = 0; col <= lastCol-firstCol; col++)
                {
                    Angle t2;
                    t2 = t1.add(dLon);
                    Sector tileSector = new Sector(p1, p2, t1, t2);

                    if (tileSector.intersects(searchSector))
                    {
                        if (needToCheckDisk)
                        {
                            //now check if on disk
                            String filePath = this.placeNameService.createFileCachePathFromTile(row+firstRow, col+firstCol);
                            final java.net.URL tileURL = WorldWind.getDataFileStore().findFile(filePath, false);
                            if (tileURL == null)
                                needToCheckDisk=false; //looked and found nothing
                            else
                                return 0;  //found one, assume rest are there
                        }

                        tileCount++;
                    }
                    t1 = t2;
                }
                p1 = p2;
            }

            return tileCount;
        }
        //end added for bulk download


        public List<NavigationTile> getSubNavTiles()
        {
            ArrayList<NavigationTile> navList=new ArrayList<NavigationTile>();
            for(NavigationTile nav: subNavTiles)
            {
                    navList.add(nav);
            }
            return navList;
        }

        public boolean hasSubTiles()
        {
            return !subNavTiles.isEmpty();
        }

        private boolean isNavSectorVisible(DrawContext dc, double minDistanceSquared, double maxDistanceSquared)
        {
            if (!navSector.intersects(dc.getVisibleSector()))
                return false;

            View view = dc.getView();
            Position eyePos = view.getEyePosition();
            if (eyePos == null)
                return false;

            //check for eyePos over globe
            if (Double.isNaN(eyePos.getLatitude().getDegrees()) || Double.isNaN(eyePos.getLongitude().getDegrees()))
                return false;

            Angle lat = clampAngle(eyePos.getLatitude(), navSector.getMinLatitude(),
                navSector.getMaxLatitude());
            Angle lon = clampAngle(eyePos.getLongitude(), navSector.getMinLongitude(),
                navSector.getMaxLongitude());
            Vec4 p = dc.getGlobe().computePointFromPosition(lat, lon, 0d);
            double distSquared = dc.getView().getEyePoint().distanceToSquared3(p);
            //noinspection RedundantIfStatement
            if (minDistanceSquared > distSquared || maxDistanceSquared < distSquared)
                return false;

            return true;
        }

        public List<Tile> getTiles()
        {
           if (tileKeys.isEmpty())
           {
               Tile[] tiles=buildTiles(this.placeNameService, this);
               //load tileKeys
               for (Tile t: tiles)
               {
                   tileKeys.add(t.getHashInt());
                   WorldWind.getMemoryCache(Tile.class.getName()).add(t.getHashInt(), t);
               }
               return Arrays.asList(tiles);
           }
           else
           {
               List<Tile> dataTiles=new ArrayList<Tile>();
               for ( Integer s : tileKeys )
               {
                   Tile t = (Tile) WorldWind.getMemoryCache(Tile.class.getName()).getObject(s);
                   if (t != null)
                   {
                       dataTiles.add(t);
                   }
               }
               return dataTiles;
           }
        }
    }

    private static class Tile implements Cacheable
    {
        final PlaceNameService placeNameService;
        final Sector sector;
        final int row;
        final int column;
        private Integer hashInt=null;
        // Computed data.
        String fileCachePath = null;
        double extentVerticalExaggeration = Double.MIN_VALUE;
        private Vec4 centroid; // Cartesian coordinate of lat/lon center
        private double priority = Double.MAX_VALUE; // Default is minimum priority
        private PlaceNameChunk dataChunk=null;

        Tile(PlaceNameService placeNameService, Sector sector, int row, int column)
        {
            this.placeNameService = placeNameService;
            this.sector = sector;
            this.row = row;
            this.column = column;
            this.fileCachePath = this.placeNameService.createFileCachePathFromTile(this.row, this.column);
            this.hashInt = this.computeHash();
        }

        public void setDataChunk(PlaceNameChunk chunk)
        {
            dataChunk = chunk;
        }

        public PlaceNameChunk getDataChunk()
        {
            return dataChunk;
        }

        public long getSizeInBytes()
        {

            long result = 32; //references

            result += this.getSector().getSizeInBytes();
            if (this.getFileCachePath() != null)
                result += this.getFileCachePath().length();

            if (dataChunk != null)
            {
                result += dataChunk.estimatedMemorySize;
            }

            return result;
        }

        static int computeRow(Angle delta, Angle latitude)
        {
            if (delta == null || latitude == null)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?