/* 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.geom.Extent; import gov.nasa.worldwind.geom.LatLon; import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.render.DrawContext; import gov.nasa.worldwind.util.AbsentResourceList; import gov.nasa.worldwind.util.Logging; import gov.nasa.worldwind.util.Tile; import java.awt.*; /** * @author Paul Collins * @version $Id: PlaceNameService.java 4701 2008-03-13 23:36:50Z dcollins $ */ public class PlaceNameService { // Data retrieval and caching attributes. private final String service; private final String dataset; private final String fileCachePath; private static final String FORMAT_SUFFIX = ".xml.gz"; // Geospatial attributes. private final Sector sector; private final LatLon tileDelta; private Extent extent = null; private double extentVerticalExaggeration = Double.MIN_VALUE; // Display attributes. private final java.awt.Font font; private boolean enabled; private java.awt.Color color; private java.awt.Color backgroundColor; private double minDisplayDistance; private double maxDisplayDistance; private int numColumns; private static final int MAX_ABSENT_TILE_TRIES = 2; private static final int MIN_ABSENT_TILE_CHECK_INTERVAL = 10000; private final AbsentResourceList absentTiles = new AbsentResourceList(MAX_ABSENT_TILE_TRIES, MIN_ABSENT_TILE_CHECK_INTERVAL); /** * @param service * @param dataset * @param fileCachePath * @param sector * @param tileDelta * @param font * @throws IllegalArgumentException if any parameter is null */ public PlaceNameService(String service, String dataset, String fileCachePath, Sector sector, LatLon tileDelta, java.awt.Font font) { // Data retrieval and caching attributes. this.service = service; this.dataset = dataset; this.fileCachePath = fileCachePath; // Geospatial attributes. this.sector = sector; this.tileDelta = tileDelta; // Display attributes. this.font = font; this.enabled = true; this.color = java.awt.Color.white; this.minDisplayDistance = Double.MIN_VALUE; this.maxDisplayDistance = Double.MAX_VALUE; String message = this.validate(); if (message != null) { Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.numColumns = this.numColumnsInLevel(); } /** * @param row * @param column * @return * @throws IllegalArgumentException if either <code>row</code> or <code>column</code> is less than zero */ public String createFileCachePathFromTile(int row, int column) { if (row < 0 || column < 0) { String message = Logging.getMessage("PlaceNameService.RowOrColumnOutOfRange", row, column); Logging.logger().severe(message); throw new IllegalArgumentException(message); } StringBuilder sb = new StringBuilder(this.fileCachePath); sb.append(java.io.File.separator).append(this.dataset); sb.append(java.io.File.separator).append(row); sb.append(java.io.File.separator).append(row).append('_').append(column); sb.append(FORMAT_SUFFIX); String path = sb.toString(); return path.replaceAll("[:*?<>|]", ""); } private int numColumnsInLevel() { int firstCol = Tile.computeColumn(this.tileDelta.getLongitude(), sector.getMinLongitude()); int lastCol = Tile.computeColumn(this.tileDelta.getLongitude(), sector.getMaxLongitude().subtract(this.tileDelta.getLongitude())); return lastCol - firstCol + 1; } public long getTileNumber(int row, int column) { return row * this.numColumns + column; } /** * @param sector * @return * @throws java.net.MalformedURLException * @throws IllegalArgumentException if <code>sector</code> is null */ public java.net.URL createServiceURLFromSector(Sector sector) throws java.net.MalformedURLException { if (sector == null) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } StringBuilder sb = new StringBuilder(this.service); if (sb.charAt(sb.length() - 1) != '?') sb.append('?'); sb.append("version=1.0.0&TypeName=").append(dataset); sb.append("&Request=GetFeature"); sb.append("&Service=WFS"); sb.append("&OUTPUTFORMAT=GML2-GZIP"); sb.append("&BBOX="); sb.append(sector.getMinLongitude().getDegrees()).append(','); sb.append(sector.getMinLatitude().getDegrees()).append(','); sb.append(sector.getMaxLongitude().getDegrees()).append(','); sb.append(sector.getMaxLatitude().getDegrees()); return new java.net.URL(sb.toString()); } public synchronized final PlaceNameService deepCopy() { PlaceNameService copy = new PlaceNameService(this.service, this.dataset, this.fileCachePath, this.sector, this.tileDelta, this.font); copy.enabled = this.enabled; copy.color = this.color; copy.minDisplayDistance = this.minDisplayDistance; copy.maxDisplayDistance = this.maxDisplayDistance; return copy; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || this.getClass() != o.getClass()) return false; final PlaceNameService other = (PlaceNameService) o; if (this.service != null ? !this.service.equals(other.service) : other.service != null) return false; if (this.dataset != null ? !this.dataset.equals(other.dataset) : other.dataset != null) return false; if (this.fileCachePath != null ? !this.fileCachePath.equals(other.fileCachePath) : other.fileCachePath != null) return false; if (this.sector != null ? !this.sector.equals(other.sector) : other.sector != null) return false; if (this.tileDelta != null ? !this.tileDelta.equals(other.tileDelta) : other.tileDelta != null) return false; if (this.font != null ? !this.font.equals(other.font) : other.font != null) return false; if (this.color != null ? !this.color.equals(other.color) : other.color != null) return false; if (this.backgroundColor != null ? !this.backgroundColor.equals(other.backgroundColor) : other.backgroundColor != null) return false; if (this.minDisplayDistance != other.minDisplayDistance) return false; //noinspection RedundantIfStatement if (this.maxDisplayDistance != other.maxDisplayDistance) return false; return true; } public synchronized final java.awt.Color getColor() { return this.color; } public synchronized final Color getBackgroundColor() { if (this.backgroundColor == null) this.backgroundColor = suggestBackgroundColor(this.color); return this.backgroundColor; } private Color suggestBackgroundColor(Color foreground) { float[] compArray = new float[4]; Color.RGBtoHSB(foreground.getRed(), foreground.getGreen(), foreground.getBlue(), compArray); int colorValue = compArray[2] < 0.5f ? 255 : 0; int alphaValue = foreground.getAlpha(); return new Color(colorValue, colorValue, colorValue, alphaValue); } public final String getDataset() { return this.dataset; } /** * @param dc * @return * @throws IllegalArgumentException if <code>dc</code> is null */ public final Extent getExtent(DrawContext dc) { if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (this.extent == null || this.extentVerticalExaggeration != dc.getVerticalExaggeration()) { this.extentVerticalExaggeration = dc.getVerticalExaggeration(); this.extent = dc.getGlobe().computeBoundingCylinder(this.extentVerticalExaggeration, this.sector); } return extent; } public final String getFileCachePath() { return this.fileCachePath; } public final java.awt.Font getFont() { return this.font; } public synchronized final double getMaxDisplayDistance() { return this.maxDisplayDistance; } public synchronized final double getMinDisplayDistance() { return this.minDisplayDistance; } public final LatLon getTileDelta() { return tileDelta; } public final Sector getSector() { return this.sector; } public final String getService() { return this.service; } @Override public int hashCode() { int result; result = (service != null ? service.hashCode() : 0); result = 29 * result + (this.dataset != null ? this.dataset.hashCode() : 0); result = 29 * result + (this.fileCachePath != null ? this.fileCachePath.hashCode() : 0); result = 29 * result + (this.sector != null ? this.sector.hashCode() : 0); result = 29 * result + (this.tileDelta != null ? this.tileDelta.hashCode() : 0); result = 29 * result + (this.font != null ? this.font.hashCode() : 0); result = 29 * result + (this.color != null ? this.color.hashCode() : 0); result = 29 * result + ((Double) minDisplayDistance).hashCode(); result = 29 * result + ((Double) maxDisplayDistance).hashCode(); return result; } public synchronized final boolean isEnabled() { return this.enabled; } /** * @param color * @throws IllegalArgumentException if <code>color</code> is null */ public synchronized final void setColor(java.awt.Color color) { if (color == null) { String message = Logging.getMessage("nullValue.ColorIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.color = color; } public synchronized final void setBackgroundColor(java.awt.Color backgroundColor) { this.backgroundColor = backgroundColor; } public synchronized final void setEnabled(boolean enabled) { this.enabled = enabled; } /** * @param maxDisplayDistance * @throws IllegalArgumentException if <code>maxDisplayDistance</code> is less than the current minimum display * distance */ public synchronized final void setMaxDisplayDistance(double maxDisplayDistance) { if (maxDisplayDistance < this.minDisplayDistance) { String message = Logging.getMessage("PlaceNameService.MaxDisplayDistanceLessThanMinDisplayDistance", maxDisplayDistance, this.minDisplayDistance); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.maxDisplayDistance = maxDisplayDistance; } /** * @param minDisplayDistance * @throws IllegalArgumentException if <code>minDisplayDistance</code> is less than the current maximum display * distance */ public synchronized final void setMinDisplayDistance(double minDisplayDistance) { if (minDisplayDistance > this.maxDisplayDistance) { String message = Logging.getMessage("PlaceNameService.MinDisplayDistanceGrtrThanMaxDisplayDistance", minDisplayDistance, this.maxDisplayDistance); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.minDisplayDistance = minDisplayDistance; } public synchronized final void markResourceAbsent(long tileNumber) { this.absentTiles.markResourceAbsent(tileNumber); } public synchronized final boolean isResourceAbsent(long resourceNumber) { return this.absentTiles.isResourceAbsent(resourceNumber); } public synchronized final void unmarkResourceAbsent(long tileNumber) { this.absentTiles.unmarkResourceAbsent(tileNumber); } /** * Determines if this <code>PlaceNameService'</code> constructor arguments are valid. * * @return null if valid, otherwise a <code>String</code> containing a description of why it is invalid. */ public final String validate() { String msg = ""; if (this.service == null) { msg += Logging.getMessage("nullValue.ServiceIsNull") + ", "; } if (this.dataset == null) { msg += Logging.getMessage("nullValue.DataSetIsNull") + ", "; } if (this.fileCachePath == null) { msg += Logging.getMessage("nullValue.FileCachePathIsNull") + ", "; } if (this.sector == null) { msg += Logging.getMessage("nullValue.SectorIsNull") + ", "; } if (this.tileDelta == null) { msg += Logging.getMessage("nullValue.TileDeltaIsNull") + ", "; } if (this.font == null) { msg += Logging.getMessage("nullValue.FontIsNull") + ", "; } if (msg.length() == 0) { return null; } return msg; } }