From fba5af471c0ad2248e89c60240799c6e5000fac0 Mon Sep 17 00:00:00 2001 From: Eugene Maksymenko Date: Wed, 29 Jun 2022 19:17:04 +0300 Subject: [PATCH] Separate first level delta in Level Set for latitude and longitude. --- .../worldwind/globe/BasicTessellator.java | 2 +- .../layer/BlueMarbleLandsatLayer.java | 2 +- .../nasa/worldwind/layer/LayerFactory.java | 7 ++-- .../layer/mercator/MercatorImageTile.java | 4 +-- .../mercator/MercatorTiledImageLayer.java | 8 +++-- .../java/gov/nasa/worldwind/util/Level.java | 12 ++++--- .../gov/nasa/worldwind/util/LevelSet.java | 25 ++++++-------- .../nasa/worldwind/util/LevelSetConfig.java | 12 +++---- .../java/gov/nasa/worldwind/util/Tile.java | 33 ++++++++++--------- .../worldwind/globe/BasicTerrainTest.java | 2 +- 10 files changed, 55 insertions(+), 52 deletions(-) diff --git a/worldwind/src/main/java/gov/nasa/worldwind/globe/BasicTessellator.java b/worldwind/src/main/java/gov/nasa/worldwind/globe/BasicTessellator.java index 7df48be31..bab566746 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/globe/BasicTessellator.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/globe/BasicTessellator.java @@ -33,7 +33,7 @@ public class BasicTessellator implements Tessellator, TileFactory { // ~0.6 meter resolution - protected LevelSet levelSet = new LevelSet(new Sector().setFullSphere(), new Location(-90, -180), 90, 20, 32, 32); + protected LevelSet levelSet = new LevelSet(new Sector().setFullSphere(), new Location(-90, -180), new Location(90, 90), 20, 32, 32); protected double detailControl = 80; diff --git a/worldwind/src/main/java/gov/nasa/worldwind/layer/BlueMarbleLandsatLayer.java b/worldwind/src/main/java/gov/nasa/worldwind/layer/BlueMarbleLandsatLayer.java index bfc3825c1..8c9d17046 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/layer/BlueMarbleLandsatLayer.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/layer/BlueMarbleLandsatLayer.java @@ -85,7 +85,7 @@ public BlueMarbleLandsatLayer(String serviceAddress) { @Override public Tile createTile(Sector sector, Level level, int row, int column) { - double radiansPerPixel = Math.toRadians(level.tileDelta) / level.tileHeight; + double radiansPerPixel = Math.toRadians(level.tileDelta.latitude) / level.tileHeight; double metersPerPixel = radiansPerPixel * WorldWind.WGS84_SEMI_MAJOR_AXIS; if (metersPerPixel < 2.0e3) { // switch to Landsat at 2km resolution diff --git a/worldwind/src/main/java/gov/nasa/worldwind/layer/LayerFactory.java b/worldwind/src/main/java/gov/nasa/worldwind/layer/LayerFactory.java index d741cd338..ae8d45daa 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/layer/LayerFactory.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/layer/LayerFactory.java @@ -280,7 +280,10 @@ protected void createFromGeoPackageAsync(String pathName, Layer layer, Callback tileMatrixSet.getMaxY() - tileMatrixSet.getMinY(), tileMatrixSet.getMaxX() - tileMatrixSet.getMinX()); config.tileOrigin.set(tileMatrixSet.getMinY(), tileMatrixSet.getMinX()); - config.firstLevelDelta = (tileMatrixSet.getMaxY() - tileMatrixSet.getMinY()) / tileMatrix.valueAt(0).getMatrixHeight(); + config.firstLevelDelta.set( + (tileMatrixSet.getMaxY() - tileMatrixSet.getMinY()) / tileMatrix.valueAt(0).getMatrixHeight(), + (tileMatrixSet.getMaxX() - tileMatrixSet.getMinX()) / tileMatrix.valueAt(0).getMatrixWidth() + ); config.numLevels = tileMatrix.keyAt(tileMatrix.size() - 1) - tileMatrix.keyAt(0) + 1; TiledSurfaceImage surfaceImage = new TiledSurfaceImage(); @@ -681,7 +684,7 @@ protected LevelSet createWmtsLevelSet(WmtsLayer wmtsLayer, CompatibleTileMatrixS } int imageSize = tileMatrixSet.getTileMatrices().get(0).getTileHeight(); - return new LevelSet(boundingBox, new Location(-90, -180), 90, compatibleTileMatrixSet.tileMatrices.size(), imageSize, imageSize); + return new LevelSet(boundingBox, new Location(-90, -180), new Location(90, 90), compatibleTileMatrixSet.tileMatrices.size(), imageSize, imageSize); } protected String buildWmtsKvpTemplate(String kvpServiceAddress, String layer, String format, String styleIdentifier, String tileMatrixSet) { diff --git a/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorImageTile.java b/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorImageTile.java index 03eccaa62..b69cbc474 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorImageTile.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorImageTile.java @@ -53,8 +53,8 @@ static void assembleMercatorTilesForLevel(Level level, TileFactory tileFactory, // NOTE LevelSet.sector is final Sector attribute and thus can not be cast to MercatorSector! MercatorSector sector = MercatorSector.fromSector(level.parent.sector); Location tileOrigin = level.parent.tileOrigin; - double dLat = level.tileDelta / 2; - double dLon = level.tileDelta; + double dLat = level.tileDelta.latitude; + double dLon = level.tileDelta.longitude; int firstRow = Tile.computeRow(dLat, sector.minLatitude(), tileOrigin.latitude); int lastRow = Tile.computeLastRow(dLat, sector.maxLatitude(), tileOrigin.latitude); diff --git a/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorTiledImageLayer.java b/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorTiledImageLayer.java index cfb33e7a6..8fd07bf9d 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorTiledImageLayer.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorTiledImageLayer.java @@ -22,10 +22,12 @@ public MercatorTiledImageLayer(String name, int numLevels, int firstLevelOffset, this.setPickEnabled(false); this.firstLevelOffset = firstLevelOffset; + MercatorSector sector = MercatorSector.fromDegrees(-1.0, 1.0, - FULL_SPHERE / 2, FULL_SPHERE / 2); + Location tileOrigin = new Location(sector.minLatitude(), sector.minLongitude()); + int n = 1 << firstLevelOffset; + Location firstLevelDelta = new Location(sector.deltaLatitude() / n, sector.deltaLongitude() / n); MercatorTiledSurfaceImage surfaceImage = new MercatorTiledSurfaceImage(); - surfaceImage.setLevelSet(new LevelSet( - MercatorSector.fromDegrees(-1.0, 1.0, - FULL_SPHERE / 2, FULL_SPHERE / 2), new Location(-90, -180), - FULL_SPHERE / (1 << firstLevelOffset), numLevels - firstLevelOffset, tileSize, tileSize)); + surfaceImage.setLevelSet(new LevelSet(sector, tileOrigin, firstLevelDelta, numLevels - firstLevelOffset, tileSize, tileSize)); surfaceImage.setTileFactory(this); if(!overlay) { surfaceImage.setImageOptions(new ImageOptions(WorldWind.RGB_565)); // reduce memory usage by using a 16-bit configuration with no alpha diff --git a/worldwind/src/main/java/gov/nasa/worldwind/util/Level.java b/worldwind/src/main/java/gov/nasa/worldwind/util/Level.java index 911bb836b..ac0ffa42f 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/util/Level.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/util/Level.java @@ -5,6 +5,8 @@ package gov.nasa.worldwind.util; +import gov.nasa.worldwind.geom.Location; + /** * Represents a level of a specific resolution in a {@link LevelSet}. */ @@ -35,7 +37,7 @@ public class Level { /** * The geographic width and height in degrees of tiles within this level. */ - public final double tileDelta; + public final Location tileDelta; /** * The parent LevelSet's tileWidth. @@ -54,21 +56,21 @@ public class Level { * @param levelNumber the level's ordinal within its parent level set * @param tileDelta the geographic width and height in degrees of tiles within this level */ - public Level(LevelSet parent, int levelNumber, double tileDelta) { + public Level(LevelSet parent, int levelNumber, Location tileDelta) { if (parent == null) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "Level", "constructor", "The parent level set is null")); } - if (tileDelta <= 0) { + if (tileDelta == null || tileDelta.latitude <= 0 || tileDelta.longitude <= 0) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "Level", "constructor", "The tile delta is zero")); } this.parent = parent; this.levelNumber = levelNumber; - this.levelWidth = (int) Math.round(parent.tileWidth * parent.sector.deltaLongitude() / tileDelta); - this.levelHeight = (int) Math.round(parent.tileHeight * parent.sector.deltaLatitude() / tileDelta); + this.levelWidth = (int) Math.round(parent.tileWidth * parent.sector.deltaLongitude() / tileDelta.longitude); + this.levelHeight = (int) Math.round(parent.tileHeight * parent.sector.deltaLatitude() / tileDelta.latitude); this.tileDelta = tileDelta; this.tileWidth = parent.tileWidth; this.tileHeight = parent.tileHeight; diff --git a/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSet.java b/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSet.java index e94fdfdf7..71c1b5798 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSet.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSet.java @@ -25,9 +25,9 @@ public class LevelSet { public final Location tileOrigin = new Location(); /** - * The geographic width and height in degrees of tiles in the first level (lowest resolution) of this level set. + * The geographic width and height in degrees of tiles in the first level (the lowest resolution) of this level set. */ - public final double firstLevelDelta; + public final Location firstLevelDelta = new Location(); /** * The width in pixels of images associated with tiles in this level set, or the number of sample points in the @@ -51,7 +51,6 @@ public class LevelSet { * firstLevel and lastLevel always return null. */ public LevelSet() { - this.firstLevelDelta = 0; this.tileWidth = 0; this.tileHeight = 0; this.levels = new Level[0]; @@ -74,7 +73,7 @@ public LevelSet() { * * @throws IllegalArgumentException If any argument is null, or if any dimension is zero */ - public LevelSet(Sector sector, Location tileOrigin, double firstLevelDelta, int numLevels, int tileWidth, int tileHeight) { + public LevelSet(Sector sector, Location tileOrigin, Location firstLevelDelta, int numLevels, int tileWidth, int tileHeight) { if (sector == null) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "missingSector")); @@ -85,7 +84,7 @@ public LevelSet(Sector sector, Location tileOrigin, double firstLevelDelta, int Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "missingTileOrigin")); } - if (firstLevelDelta <= 0) { + if (firstLevelDelta == null || firstLevelDelta.latitude <= 0 || firstLevelDelta.longitude <= 0) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "invalidTileDelta")); } @@ -102,7 +101,7 @@ public LevelSet(Sector sector, Location tileOrigin, double firstLevelDelta, int this.sector.set(sector); this.tileOrigin.set(tileOrigin); - this.firstLevelDelta = firstLevelDelta; + this.firstLevelDelta.set(firstLevelDelta); this.tileWidth = tileWidth; this.tileHeight = tileHeight; this.levels = new Level[numLevels]; @@ -129,12 +128,7 @@ public LevelSet(LevelSetConfig config) { Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "missingSector")); } - if (config.tileOrigin == null) { - throw new IllegalArgumentException( - Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "missingTileOrigin")); - } - - if (config.firstLevelDelta <= 0) { + if (config.firstLevelDelta.latitude <= 0 || config.firstLevelDelta.longitude <= 0) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "invalidTileDelta")); } @@ -151,7 +145,7 @@ public LevelSet(LevelSetConfig config) { this.sector.set(config.sector); this.tileOrigin.set(config.tileOrigin); - this.firstLevelDelta = config.firstLevelDelta; + this.firstLevelDelta.set(config.firstLevelDelta); this.tileWidth = config.tileWidth; this.tileHeight = config.tileHeight; this.levels = new Level[config.numLevels]; @@ -160,7 +154,8 @@ public LevelSet(LevelSetConfig config) { protected void assembleLevels() { for (int i = 0, len = this.levels.length; i < len; i++) { - double delta = firstLevelDelta / (1 << i); + int n = 1 << i; + Location delta = new Location(firstLevelDelta.latitude / n, firstLevelDelta.longitude / n); this.levels[i] = new Level(this, i, delta); } } @@ -209,7 +204,7 @@ public Level levelForResolution(double radiansPerPixel) { } double degreesPerPixel = Math.toDegrees(radiansPerPixel); - double firstLevelDegreesPerPixel = this.firstLevelDelta / Math.min(this.tileWidth, this.tileHeight); + double firstLevelDegreesPerPixel = Math.max(this.firstLevelDelta.longitude / this.tileWidth, this.firstLevelDelta.latitude / this.tileHeight); double level = Math.log(firstLevelDegreesPerPixel / degreesPerPixel) / Math.log(2); // fractional level address int levelNumber = (int) Math.round(level); // nearest neighbor level diff --git a/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSetConfig.java b/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSetConfig.java index f8876bf6a..83e189ccc 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSetConfig.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/util/LevelSetConfig.java @@ -25,9 +25,9 @@ public class LevelSetConfig { public final Location tileOrigin = new Location(-90, -180); /** - * The geographic width and height in degrees of tiles in the first level (lowest resolution) of the level set. + * The geographic width and height in degrees of tiles in the first level (the lowest resolution) of the level set. */ - public double firstLevelDelta = 90; + public final Location firstLevelDelta = new Location(90, 90); /** * The number of levels in the level set. @@ -69,12 +69,12 @@ public LevelSetConfig() { * sample points in the latitudinal direction of elevation tiles associate with the level * set */ - public LevelSetConfig(Sector sector, double firstLevelDelta, int numLevels, int tileWidth, int tileHeight) { + public LevelSetConfig(Sector sector, Location firstLevelDelta, int numLevels, int tileWidth, int tileHeight) { if (sector != null) { this.sector.set(sector); } - this.firstLevelDelta = firstLevelDelta; + this.firstLevelDelta.set(firstLevelDelta); this.numLevels = numLevels; this.tileWidth = tileWidth; this.tileHeight = tileHeight; @@ -97,7 +97,7 @@ public int numLevelsForResolution(double radiansPerPixel) { } double degreesPerPixel = Math.toDegrees(radiansPerPixel); - double firstLevelDegreesPerPixel = this.firstLevelDelta / Math.min(this.tileWidth, this.tileHeight); + double firstLevelDegreesPerPixel = Math.max(this.firstLevelDelta.longitude / this.tileWidth, this.firstLevelDelta.latitude / this.tileHeight); double level = Math.log(firstLevelDegreesPerPixel / degreesPerPixel) / Math.log(2); // fractional level address int levelNumber = (int) Math.ceil(level); // ceiling captures the resolution @@ -126,7 +126,7 @@ public int numLevelsForMinResolution(double radiansPerPixel) { } double degreesPerPixel = Math.toDegrees(radiansPerPixel); - double firstLevelDegreesPerPixel = this.firstLevelDelta / this.tileHeight; + double firstLevelDegreesPerPixel = Math.max(this.firstLevelDelta.longitude / this.tileWidth, this.firstLevelDelta.latitude / this.tileHeight); double level = Math.log(firstLevelDegreesPerPixel / degreesPerPixel) / Math.log(2); // fractional level address int levelNumber = (int) Math.floor(level); // floor prevents exceeding the min scale diff --git a/worldwind/src/main/java/gov/nasa/worldwind/util/Tile.java b/worldwind/src/main/java/gov/nasa/worldwind/util/Tile.java index 319ea0c9e..2e57fb498 100755 --- a/worldwind/src/main/java/gov/nasa/worldwind/util/Tile.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/util/Tile.java @@ -109,7 +109,7 @@ public Tile(Sector sector, Level level, int row, int column) { this.row = row; this.column = column; this.tileKey = level.levelNumber + "." + row + "." + column; - this.texelSizeFactor = Math.toRadians(level.tileDelta / level.tileWidth) * Math.cos(Math.toRadians(sector.centroidLatitude())); + this.texelSizeFactor = Math.toRadians(level.tileDelta.longitude / level.tileWidth) * Math.cos(Math.toRadians(sector.centroidLatitude())); } /** @@ -217,15 +217,15 @@ public static Collection assembleTilesForLevel(Level level, TileFactory ti Sector sector = level.parent.sector; Location tileOrigin = level.parent.tileOrigin; - double tileDelta = level.tileDelta; + Location tileDelta = level.tileDelta; - int firstRow = Tile.computeRow(tileDelta, sector.minLatitude(), tileOrigin.latitude); - int lastRow = Tile.computeLastRow(tileDelta, sector.maxLatitude(), tileOrigin.latitude); - int firstCol = Tile.computeColumn(tileDelta, sector.minLongitude(), tileOrigin.longitude); - int lastCol = Tile.computeLastColumn(tileDelta, sector.maxLongitude(), tileOrigin.longitude); + int firstRow = Tile.computeRow(tileDelta.latitude, sector.minLatitude(), tileOrigin.latitude); + int lastRow = Tile.computeLastRow(tileDelta.latitude, sector.maxLatitude(), tileOrigin.latitude); + int firstCol = Tile.computeColumn(tileDelta.longitude, sector.minLongitude(), tileOrigin.longitude); + int lastCol = Tile.computeLastColumn(tileDelta.longitude, sector.maxLongitude(), tileOrigin.longitude); - double firstRowLat = tileOrigin.latitude + firstRow * tileDelta; - double firstRowLon = tileOrigin.longitude + firstCol * tileDelta; + double firstRowLat = tileOrigin.latitude + firstRow * tileDelta.latitude; + double firstRowLon = tileOrigin.longitude + firstCol * tileDelta.longitude; double lat = firstRowLat; double lon; @@ -233,13 +233,13 @@ public static Collection assembleTilesForLevel(Level level, TileFactory ti lon = firstRowLon; for (int col = firstCol; col <= lastCol; col++) { - Sector tileSector = new Sector(lat, lon, tileDelta, tileDelta); + Sector tileSector = new Sector(lat, lon, tileDelta.latitude, tileDelta.longitude); result.add(tileFactory.createTile(tileSector, level, row, col)); - lon += tileDelta; + lon += tileDelta.longitude; } - lat += tileDelta; + lat += tileDelta.latitude; } return result; @@ -334,26 +334,27 @@ public Tile[] subdivide(TileFactory tileFactory) { double lonMin = this.sector.minLongitude(); double latMid = this.sector.centroidLatitude(); double lonMid = this.sector.centroidLongitude(); - double childDelta = this.level.tileDelta * 0.5; + double childDeltaLat = this.level.tileDelta.latitude * 0.5; + double childDeltaLon = this.level.tileDelta.longitude * 0.5; int childRow = 2 * this.row; int childCol = 2 * this.column; - Sector childSector = new Sector(latMin, lonMin, childDelta, childDelta); + Sector childSector = new Sector(latMin, lonMin, childDeltaLat, childDeltaLon); children[0] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Southwest childRow = 2 * this.row; childCol = 2 * this.column + 1; - childSector = new Sector(latMin, lonMid, childDelta, childDelta); + childSector = new Sector(latMin, lonMid, childDeltaLat, childDeltaLon); children[1] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Southeast childRow = 2 * this.row + 1; childCol = 2 * this.column; - childSector = new Sector(latMid, lonMin, childDelta, childDelta); + childSector = new Sector(latMid, lonMin, childDeltaLat, childDeltaLon); children[2] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Northwest childRow = 2 * this.row + 1; childCol = 2 * this.column + 1; - childSector = new Sector(latMid, lonMid, childDelta, childDelta); + childSector = new Sector(latMid, lonMid, childDeltaLat, childDeltaLon); children[3] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Northeast return children; diff --git a/worldwind/src/test/java/gov/nasa/worldwind/globe/BasicTerrainTest.java b/worldwind/src/test/java/gov/nasa/worldwind/globe/BasicTerrainTest.java index 2eebe1267..f12f46d2e 100644 --- a/worldwind/src/test/java/gov/nasa/worldwind/globe/BasicTerrainTest.java +++ b/worldwind/src/test/java/gov/nasa/worldwind/globe/BasicTerrainTest.java @@ -82,7 +82,7 @@ public void setUp() { this.terrain = new BasicTerrain(); // Add a terrain tile used to the mocked terrain - LevelSet levelSet = new LevelSet(new Sector().setFullSphere(), new Location(-90, -180), 1.0, 1, 5, 5); // tiles with 5x5 vertices + LevelSet levelSet = new LevelSet(new Sector().setFullSphere(), new Location(-90, -180), new Location(1.0, 1.0), 1, 5, 5); // tiles with 5x5 vertices TerrainTile tile = new TerrainTile(new Sector(0, 0, 1, 1), levelSet.firstLevel(), 90, 180); ((BasicTerrain) this.terrain).addTile(tile);