public WorldWindowImpl() { this.sceneController = (SceneController) WorldWind.createConfigurationComponent(AVKey.SCENE_CONTROLLER_CLASS_NAME); // Set up to initiate a repaint whenever a file is retrieved and added to the local file store. WorldWind.getDataFileStore().addPropertyChangeListener(this); }
/** * @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); } }
private void sendRequests() { Runnable task = this.requestQ.poll(); while (task != null) { if (!WorldWind.getTaskService().isFull()) { WorldWind.getTaskService().addTask(task); } task = this.requestQ.poll(); } }
/** * Thread's off a task to determine whether the resource is local or remote and then retrieves it * either from disk cache or a remote server. * * @param dc the current draw context. */ protected void requestResource(DrawContext dc) { if (WorldWind.getTaskService().isFull()) return; KMLLink link = this.model.getLink(); if (link == null) return; String address = link.getAddress(dc); if (address != null) address = address.trim(); if (WWUtil.isEmpty(address)) return; WorldWind.getTaskService().addTask(new RequestTask(this, address)); }
/** * Causes resources used by the World Window to be freed. The World Window cannot be used once * this method is called. An OpenGL context for the window must be current. */ public void shutdown() { WorldWind.getDataFileStore().removePropertyChangeListener(this); if (this.inputHandler != null) { this.inputHandler.dispose(); this.inputHandler = new NoOpInputHandler(); } // Clear the texture cache if (this.getGpuResourceCache() != null) this.getGpuResourceCache().clear(); // Dispose all the layers // TODO: Need per-window dispose for layers if (this.getModel() != null && this.getModel().getLayers() != null) { for (Layer layer : this.getModel().getLayers()) { try { layer.dispose(); } catch (Exception e) { Logging.logger() .log( java.util.logging.Level.SEVERE, Logging.getMessage("WorldWindowGLCanvas.ExceptionWhileShuttingDownWorldWindow"), e); } } } SceneController sc = this.getSceneController(); if (sc != null) sc.dispose(); }
protected boolean loadTile(Tile tile, java.net.URL url) { if (WWIO.isFileOutOfDate(url, this.placeNameServiceSet.getExpiryTime())) { // The file has expired. Delete it then request download of newer. this.getDataFileStore().removeFile(url); String message = Logging.getMessage("generic.DataFileExpired", url); Logging.logger().fine(message); return false; } PlaceNameChunk tileData; synchronized (this.fileLock) { tileData = readTileData(tile, url); } if (tileData == null) { // Assume that something's wrong with the file and delete it. this.getDataFileStore().removeFile(url); tile.getPlaceNameService() .markResourceAbsent(tile.getPlaceNameService().getTileNumber(tile.row, tile.column)); String message = Logging.getMessage("generic.DeletedCorruptDataFile", url); Logging.logger().fine(message); return false; } tile.setDataChunk(tileData); WorldWind.getMemoryCache(Tile.class.getName()).add(tile.getFileCachePath(), tile); return true; }
/** * Resolves a reference to a local element identified by address and identifier, where {@code * linkBase} identifies a document, including the current document, and {@code linkRef} is the id * of the desired element. * * <p>If {@code linkBase} refers to a local COLLADA file and {@code linkRef} is non-null, the * return value is the element identified by {@code linkRef}. If {@code linkRef} is null, the * return value is a parsed {@link ColladaRoot} for the COLLADA file identified by {@code * linkBase}. Otherwise, {@code linkBase} is returned. * * @param linkBase the address of the document containing the requested element. * @param linkRef the element's identifier. * @return the requested element, or null if the element is not found. * @throws IllegalArgumentException if the address is null. */ protected Object resolveLocalReference(String linkBase, String linkRef) { if (linkBase == null) { String message = Logging.getMessage("nullValue.DocumentSourceIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } try { File file = new File(linkBase); if (!file.exists()) return null; // Determine whether the file is a COLLADA document. If not, just return the file path. if (!WWIO.isContentType(file, ColladaConstants.COLLADA_MIME_TYPE)) return file.toURI().toString(); // Attempt to open and parse the COLLADA file. ColladaRoot refRoot = ColladaRoot.createAndParse(file); // An exception is thrown if parsing fails, so no need to check for null. // Add the parsed file to the session cache so it doesn't have to be parsed again. WorldWind.getSessionCache().put(linkBase, refRoot); // Now check the newly opened COLLADA file for the referenced item, if a reference was // specified. if (linkRef != null) return refRoot.getItemByID(linkRef); else return refRoot; } catch (Exception e) { String message = Logging.getMessage("generic.UnableToResolveReference", linkBase + "/" + linkRef); Logging.logger().warning(message); return null; } }
public ByteBuffer run(Retriever retriever) { if (!retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL)) return null; HTTPRetriever htr = (HTTPRetriever) retriever; if (htr.getResponseCode() == HttpURLConnection.HTTP_NO_CONTENT) { // Mark tile as missing to avoid excessive attempts MercatorTiledImageLayer.this.levels.markResourceAbsent(tile); return null; } if (htr.getResponseCode() != HttpURLConnection.HTTP_OK) return null; URLRetriever r = (URLRetriever) retriever; ByteBuffer buffer = r.getBuffer(); String suffix = WWIO.makeSuffixForMimeType(htr.getContentType()); if (suffix == null) { return null; // TODO: log error } String path = tile.getPath().substring(0, tile.getPath().lastIndexOf(".")); path += suffix; final File outFile = WorldWind.getDataFileStore().newFile(path); if (outFile == null) return null; try { WWIO.saveBuffer(buffer, outFile); return buffer; } catch (IOException e) { e.printStackTrace(); // TODO: log error return null; } }
/** * Resolves a reference to a remote element identified by address and identifier, where {@code * linkBase} identifies a remote document, and {@code linkRef} is the id of the desired element. * This method retrieves resources asynchronously using the {@link * gov.nasa.worldwind.cache.FileStore}. * * <p>The return value is null if the file is not yet available in the FileStore. If {@code * linkBase} refers to a COLLADA file and {@code linkRef} is non-null, the return value is the * element identified by {@code linkRef}. If {@code linkBase} refers to a COLLADA file and {@code * linkRef} is null, the return value is a parsed {@link ColladaRoot} for the COLLADA file * identified by {@code linkBase}. Otherwise the return value is a {@link URL} to the file in the * file cache. * * @param linkBase the address of the document containing the requested element. * @param linkRef the element's identifier. * @return URL to the requested file, parsed ColladaRoot, or COLLADA element. Returns null if the * document is not yet available in the FileStore. * @throws IllegalArgumentException if the {@code linkBase} is null. */ public Object resolveRemoteReference(String linkBase, String linkRef) { if (linkBase == null) { String message = Logging.getMessage("nullValue.DocumentSourceIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } try { // See if it's in the cache. If not, requestFile will start another thread to retrieve it and // return null. URL url = WorldWind.getDataFileStore().requestFile(linkBase); if (url == null) return null; // It's in the cache. If it's a COLLADA file try to parse it so we can search for the // specified reference. // If it's not COLLADA, just return the url for the cached file. String contentType = WorldWind.getDataFileStore().getContentType(linkBase); if (contentType == null) { String suffix = WWIO.getSuffix(linkBase.split(";")[0]); // strip of trailing garbage if (!WWUtil.isEmpty(suffix)) contentType = WWIO.makeMimeTypeForSuffix(suffix); } if (!this.canParseContentType(contentType)) return url; // If the file is a COLLADA document, attempt to open it. We can't open it as a File with // createAndParse // because the ColladaRoot that will be created needs to have the remote address in order to // resolve any // relative references within it. ColladaRoot refRoot = this.parseCachedColladaFile(url, linkBase); // Add the parsed file to the session cache so it doesn't have to be parsed again. WorldWind.getSessionCache().put(linkBase, refRoot); // Now check the newly opened COLLADA file for the referenced item, if a reference was // specified. if (linkRef != null) return refRoot.getItemByID(linkRef); else return refRoot; } catch (Exception e) { String message = Logging.getMessage("generic.UnableToResolveReference", linkBase + "/" + linkRef); Logging.logger().warning(message); return null; } }
public List<Tile> getTiles() { if (tileKeys.isEmpty()) { Tile[] tiles = buildTiles(this.placeNameService, this); // load tileKeys for (Tile t : tiles) { tileKeys.add(t.getFileCachePath()); WorldWind.getMemoryCache(Tile.class.getName()).add(t.getFileCachePath(), t); } return Arrays.asList(tiles); } else { List<Tile> dataTiles = new ArrayList<Tile>(); for (String s : tileKeys) { Tile t = (Tile) WorldWind.getMemoryCache(Tile.class.getName()).getObject(s); if (t != null) { dataTiles.add(t); } } return dataTiles; } }
/** * If this instance's image source is a <code>BufferedImage</code>, creates and returns the * texture, otherwise creates a task in a separate thread to retrieve it from its local or remote * location. * * @param dc the current draw context. * @return the new texture, or null if the texture is not yet available. */ protected Texture requestTexture(DrawContext dc) { if (this.isBufferedImageSource()) return this.makeBufferedImageTexture(dc); if (this.getTextureData() != null && this.getTexture(dc) == null) return this.makeTextureFromTextureData(dc); if (WorldWind.getTaskService().isFull()) return null; Runnable task = this.createRequestTask(); if (WorldWind.getTaskService().contains(task)) return null; // Use either the current layer or the layer list as the listener to notify when the request // completes. The // latter is used when the image source is requested during ordered rendering and the current // layer is null. this.listener = dc.getCurrentLayer() != null ? dc.getCurrentLayer() : dc.getLayers(); WorldWind.getTaskService().addTask(task); return null; }
/* * Load cache locations */ private void loadData() { // load combo with WW caches // List<File> caches = WorldWind.getDataFileCache().getCacheLocations(); List<? extends File> caches = WorldWind.getDataFileStore().getLocations(); for (File file : caches) { combo.add(file.toString()); } // load table w/ 1st location files // loadTable(caches.get(0)); }
protected void downloadTile(final Tile tile, DownloadPostProcessor postProcessor) { if (!this.isNetworkRetrievalEnabled()) return; if (!WorldWind.getRetrievalService().isAvailable()) return; java.net.URL url; try { url = tile.getRequestURL(); if (WorldWind.getNetworkStatus().isHostUnavailable(url)) return; } catch (java.net.MalformedURLException e) { Logging.logger() .log( java.util.logging.Level.SEVERE, Logging.getMessage("layers.PlaceNameLayer.ExceptionCreatingUrl", tile), e); return; } Retriever retriever; if ("http".equalsIgnoreCase(url.getProtocol()) || "https".equalsIgnoreCase(url.getProtocol())) { if (postProcessor == null) postProcessor = new DownloadPostProcessor(this, tile); retriever = new HTTPRetriever(url, postProcessor); } else { Logging.logger() .severe( Logging.getMessage("layers.PlaceNameLayer.UnknownRetrievalProtocol", url.toString())); return; } // Apply any overridden timeouts. Integer cto = AVListImpl.getIntegerValue(this, AVKey.URL_CONNECT_TIMEOUT); if (cto != null && cto > 0) retriever.setConnectTimeout(cto); Integer cro = AVListImpl.getIntegerValue(this, AVKey.URL_READ_TIMEOUT); if (cro != null && cro > 0) retriever.setReadTimeout(cro); Integer srl = AVListImpl.getIntegerValue(this, AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT); if (srl != null && srl > 0) retriever.setStaleRequestLimit(srl); WorldWind.getRetrievalService().runRetriever(retriever, tile.getPriority()); }
public WWPanel(Dimension size) { this.wwd = new WorldWindowGLCanvas(); this.wwd.setSize(size); this.wwd.setModel((Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME)); this.setLayout(new BorderLayout(5, 5)); this.add(this.wwd, BorderLayout.CENTER); StatusBar statusBar = new StatusBar(); statusBar.setEventSource(wwd); this.add(statusBar, BorderLayout.SOUTH); }
@Override protected boolean handleElevations( Globe globe, TextureTile tile, Sector sector, BufferWrapper[] elevations) { int width = tile.getLevel().getTileWidth(); int height = tile.getLevel().getTileHeight(); double[] minmax = getMinMax(elevations[4], elevationModel.getMissingDataSignal()); byte[][] bytes = elevationsToTexture(width, height, globe, sector, elevations, minmax[0], minmax[1]); File file = WorldWind.getDataFileStore().newFile(tile.getPath()); return saveTexture(file, bytes, width, height, minmax[0], minmax[1]); }
private BufferedImage requestImage(MercatorTextureTile tile, String mimeType) throws URISyntaxException { String pathBase = tile.getPath().substring(0, tile.getPath().lastIndexOf(".")); String suffix = WWIO.makeSuffixForMimeType(mimeType); String path = pathBase + suffix; URL url = WorldWind.getDataFileStore().findFile(path, false); if (url == null) // image is not local return null; if (WWIO.isFileOutOfDate(url, tile.getLevel().getExpiryTime())) { // The file has expired. Delete it. WorldWind.getDataFileStore().removeFile(url); String message = Logging.getMessage("generic.DataFileExpired", url); Logging.logger().fine(message); } else { try { File imageFile = new File(url.toURI()); BufferedImage image = ImageIO.read(imageFile); if (image == null) { String message = Logging.getMessage("generic.ImageReadFailed", imageFile); throw new RuntimeException(message); } this.levels.unmarkResourceAbsent(tile); return image; } catch (IOException e) { // Assume that something's wrong with the file and delete it. gov.nasa.worldwind.WorldWind.getDataFileStore().removeFile(url); this.levels.markResourceAbsent(tile); String message = Logging.getMessage("generic.DeletedCorruptDataFile", url); Logging.logger().info(message); } } return null; }
/** * Resolves a reference to a local or remote file or element. If the link refers to an element in * the current document, this method returns that element. If the link refers to a remote * document, this method will initiate asynchronous retrieval of the document, and return a URL of * the downloaded document in the file cache, if it is available locally. If the link identifies a * COLLADA document, the document will be returned as a parsed ColladaRoot. * * @param link the address of the document or element to resolve. This may be a full URL, a URL * fragment that identifies an element in the current document ("#myElement"), or a URL and a * fragment identifier ("http://server.com/model.dae#myElement"). * @return the requested element, or null if the element is not found. * @throws IllegalArgumentException if the address is null. */ public Object resolveReference(String link) { if (link == null) { String message = Logging.getMessage("nullValue.DocumentSourceIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } try { String[] linkParts = link.split("#"); String linkBase = linkParts[0]; String linkRef = linkParts.length > 1 ? linkParts[1] : null; // See if it's a reference to an internal element. if (WWUtil.isEmpty(linkBase) && !WWUtil.isEmpty(linkRef)) return this.getItemByID(linkRef); // Interpret the path relative to the current document. String path = this.getSupportFilePath(linkBase); if (path == null) path = linkBase; // See if it's an already found and parsed COLLADA file. Object o = WorldWind.getSessionCache().get(path); if (o != null && o instanceof ColladaRoot) return linkRef != null ? ((ColladaRoot) o).getItemByID(linkRef) : o; URL url = WWIO.makeURL(path); if (url == null) { // See if the reference can be resolved to a local file. o = this.resolveLocalReference(path, linkRef); } // If we didn't find a local file, treat it as a remote reference. if (o == null) o = this.resolveRemoteReference(path, linkRef); if (o != null) return o; // If the reference was not resolved as a remote reference, look for a local element // identified by the // reference string. This handles the case of malformed internal references that omit the # // sign at the // beginning of the reference. return this.getItemByID(link); } catch (Exception e) { String message = Logging.getMessage("generic.UnableToResolveReference", link); Logging.logger().warning(message); } return null; }
/** * Create a layer described by an XML layer description. * * @param domElement the XML element describing the layer to create. * @param params any parameters to apply when creating the layer. * @return a new layer * @throws WWUnrecognizedException if the layer type or service type given in the describing * element is unrecognized. * @see #createTiledImageLayer(org.w3c.dom.Element, gov.nasa.worldwind.avlist.AVList). */ protected Layer createFromLayerDocument(Element domElement, AVList params) { String className = WWXML.getText(domElement, "@className"); if (className != null && className.length() > 0) { Layer layer = (Layer) WorldWind.createComponent(className); String actuate = WWXML.getText(domElement, "@actuate"); layer.setEnabled(WWUtil.isEmpty(actuate) || actuate.equals("onLoad")); WWXML.invokePropertySetters(layer, domElement); return layer; } AVList props = WWXML.copyProperties(domElement, null); if (props != null) { // Copy params and add any properties for this layer to the copy if (params != null) props.setValues(params); params = props; } Layer layer; String href = WWXML.getText(domElement, "@href"); if (href != null && href.length() > 0) { Object o = this.createFromConfigSource(href, params); if (o == null) return null; if (!(o instanceof Layer)) { String msg = Logging.getMessage("LayerFactory.UnexpectedTypeForLayer", o.getClass().getName()); throw new WWRuntimeException(msg); } layer = (Layer) o; } else { String layerType = WWXML.getText(domElement, "@layerType"); if (layerType != null && layerType.equals("TiledImageLayer")) { layer = this.createTiledImageLayer(domElement, params); } else { String msg = Logging.getMessage("generic.UnrecognizedLayerType", layerType); throw new WWUnrecognizedException(msg); } } if (layer != null) { String actuate = WWXML.getText(domElement, "@actuate"); layer.setEnabled(actuate != null && actuate.equals("onLoad")); WWXML.invokePropertySetters(layer, domElement); } return layer; }
/** Setup the WorldWindow. */ protected void setupWWD() { // Create the default model as described in the current worldwind // properties. Model worldModel = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME); getWWD().setModel(worldModel); // Deal with rendering exceptions - graphics not good enough getWWD() .addRenderingExceptionListener( new RenderingExceptionListener() { public void exceptionThrown(Throwable t) { if (t instanceof WWAbsentRequirementException) { String message = "Computer does not meet minimum graphics requirements.\n"; message += "Please install up-to-date graphics driver and try again.\n"; message += "Reason: " + t.getMessage() + "\n"; message += "This program will end when you press OK."; JOptionPane.showMessageDialog( MapPanel.this, message, "Unable to Start Program", JOptionPane.ERROR_MESSAGE); System.exit(-1); } } }); // getWWD().addRenderingListener(new RenderingListener() { // // @Override // public void stageChanged(RenderingEvent arg0) { // System.out.println("MapPanel.renderingListener.stateChanged(): "+ arg0); // // } // // }); // Setup a select listener for the worldmap click-and-go feature getWWD().addSelectListener(new ClickAndGoSelectListener(getWWD(), WorldMapLayer.class)); // Put the world window in the center add(getWWD(), BorderLayout.CENTER); }
/** * @param classNameKey the key identifying the component * * @return the new component * * @throws IllegalStateException if no name could be found which corresponds to <code>classNameKey</code> * @throws IllegalArgumentException if <code>classNameKey<code> is null * @throws WWRuntimeException if the component could not be created */ public static Object createConfigurationComponent(String classNameKey) throws IllegalStateException, IllegalArgumentException { if (classNameKey == null || classNameKey.length() == 0) { Logging.logger().severe("nullValue.ClassNameKeyNullZero"); throw new IllegalArgumentException(Logging.getMessage("nullValue.ClassNameKeyNullZero")); } String name = Configuration.getStringValue(classNameKey); if (name == null) { Logging.logger() .log(Level.SEVERE, "WorldWind.NoClassNameInConfigurationForKey", classNameKey); throw new WWRuntimeException( Logging.getMessage("WorldWind.NoClassNameInConfigurationForKey", classNameKey)); } try { return WorldWind.createComponent(name.trim()); } catch (Throwable e) { Logging.logger().log(Level.SEVERE, "WorldWind.UnableToCreateClassForConfigurationKey", name); throw new IllegalStateException( Logging.getMessage("WorldWind.UnableToCreateClassForConfigurationKey", name), e); } }
public TestlocWorldFrame(String wdPath) { mapDirPath = wdPath; initFilelist(); Model roundModel = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME); globeMapPanel = new MapPanel(roundModel, true); roundModel.getLayers().getLayerByName("Bing Imagery").setEnabled(true); LayerPanel layerPanel = new LayerPanel(globeMapPanel.wwd); globeDisplayAdapter = new DisplayAdapter(globeMapPanel.wwd, pointBuilderListener, MouseEvent.BUTTON1, 5, true); mapRenderLayer = new RenderableLayer(); mapRenderLayer.setName("Surface Images"); mapRenderLayer.setPickEnabled(false); LayerList layers = new LayerList(); layers.add(mapRenderLayer); Model flatModel = new BasicModel(new EarthFlat(), layers); ((EarthFlat) flatModel.getGlobe()).setProjection(FlatGlobe.PROJECTION_LAT_LON); mapMapPanel = new MapPanel(flatModel, false); mapDisplayAdapter = new DisplayAdapter( mapMapPanel.wwd, markerBuilderListener, MouseEvent.BUTTON3, 50000, false); try { globeMapPanel.add(new GazetteerPanel(globeMapPanel.wwd, null), BorderLayout.NORTH); } catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } mapSelectionList = new JList<String>(trackNames); mapSelectionList.addListSelectionListener(listListener); JLabel lblStepsize = new JLabel("Stepsize:"); textFieldStepsize = new JTextField(); textFieldStepsize.setText("5"); btnStep = new JButton("Step"); btnStep.addMouseListener(stepListener); btnStepToMarker = new JButton("to Marker"); btnStepToMarker.addMouseListener(notImplementedListener); slider = new JSlider(); slider.setValue(0); slider.addMouseListener(sliderListener); JLabel lblDstFallofExp = new JLabel("Distance Fallof:"); textFieldDistFallofExp = new JTextField(); textFieldDistFallofExp.setText(String.valueOf(7)); JLabel lblTriDissimilarity = new JLabel("Tri Dissimilarity:"); textFieldTriDissimilarity = new JTextField(); textFieldTriDissimilarity.setText(String.valueOf(0.50)); JLabel lblMinTriAngle = new JLabel("Min Tri Angle:"); textFieldMinTriAngle = new JTextField(); textFieldMinTriAngle.setText(String.valueOf(4.2)); JLabel lblBadTriPen = new JLabel("Bad Tri Penalty:"); textFieldBadTriPen = new JTextField(); textFieldBadTriPen.setText(String.valueOf(0.10)); btnDisplayTriangles = new JButton("Display Triangles"); btnDisplayTriangles.addMouseListener(notImplementedListener); btnRefresh = new JButton("Refresh"); btnRefresh.addMouseListener(parameterRefreshListener); tglbtnMouseMode = new JToggleButton("Mode: Move"); tglbtnMouseMode.addMouseListener(toggleAction); JButton btnNewFile = new JButton("New File"); btnNewFile.addMouseListener(newFileListener); JButton btnSaveFile = new JButton("Save File"); btnSaveFile.addMouseListener(saveFileListener); // Window Builder generated stuff JPanel settings = new JPanel(); GroupLayout groupLayout = new GroupLayout(settings); groupLayout.setHorizontalGroup( groupLayout .createParallelGroup(Alignment.TRAILING) .addGroup( groupLayout .createSequentialGroup() .addContainerGap() .addGroup( groupLayout .createParallelGroup(Alignment.LEADING) .addGroup( groupLayout .createSequentialGroup() .addComponent(lblStepsize) .addGroup( groupLayout .createParallelGroup(Alignment.LEADING) .addGroup( groupLayout .createSequentialGroup() .addGap(421) .addComponent(lblTriDissimilarity) .addPreferredGap(ComponentPlacement.RELATED) .addComponent( textFieldTriDissimilarity, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(lblBadTriPen) .addPreferredGap(ComponentPlacement.RELATED) .addComponent( textFieldBadTriPen, GroupLayout.PREFERRED_SIZE, 34, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(btnRefresh) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(btnNewFile) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(btnSaveFile)) .addGroup( groupLayout .createSequentialGroup() .addGap(12) .addComponent( textFieldStepsize, GroupLayout.PREFERRED_SIZE, 66, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(lblDstFallofExp) .addPreferredGap(ComponentPlacement.RELATED) .addComponent( textFieldDistFallofExp, GroupLayout.PREFERRED_SIZE, 35, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(lblMinTriAngle) .addPreferredGap(ComponentPlacement.RELATED) .addComponent( textFieldMinTriAngle, GroupLayout.PREFERRED_SIZE, 42, GroupLayout.PREFERRED_SIZE)))) .addGroup( groupLayout .createSequentialGroup() .addComponent( btnStep, GroupLayout.PREFERRED_SIZE, 67, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(btnStepToMarker) .addPreferredGap(ComponentPlacement.RELATED) .addComponent( tglbtnMouseMode, GroupLayout.PREFERRED_SIZE, 128, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent( btnDisplayTriangles, GroupLayout.PREFERRED_SIZE, 161, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent( slider, GroupLayout.DEFAULT_SIZE, 1062, Short.MAX_VALUE))) .addContainerGap())); groupLayout.setVerticalGroup( groupLayout .createParallelGroup(Alignment.LEADING) .addGroup( groupLayout .createSequentialGroup() .addContainerGap() .addGroup( groupLayout .createParallelGroup(Alignment.BASELINE) .addComponent(lblStepsize) .addComponent( textFieldStepsize, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(lblDstFallofExp) .addComponent( textFieldDistFallofExp, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(lblMinTriAngle) .addComponent( textFieldMinTriAngle, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(lblTriDissimilarity) .addComponent( textFieldTriDissimilarity, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(lblBadTriPen) .addComponent( textFieldBadTriPen, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(btnRefresh) .addComponent(btnNewFile) .addComponent(btnSaveFile)) .addPreferredGap(ComponentPlacement.RELATED) .addGroup( groupLayout .createParallelGroup(Alignment.TRAILING) .addGroup( groupLayout .createParallelGroup(Alignment.BASELINE) .addComponent(btnStep) .addComponent(btnStepToMarker) .addComponent(tglbtnMouseMode) .addComponent(btnDisplayTriangles)) .addComponent( slider, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))); settings.setLayout(groupLayout); JSplitPane globeSplit = new JSplitPane(); globeSplit.setOrientation(JSplitPane.HORIZONTAL_SPLIT); globeSplit.setLeftComponent(layerPanel); globeSplit.setRightComponent(globeMapPanel); globeSplit.setOneTouchExpandable(true); globeSplit.setContinuousLayout(true); globeSplit.setDividerLocation(0); JSplitPane imgSplit = new JSplitPane(); imgSplit.setOrientation(JSplitPane.HORIZONTAL_SPLIT); imgSplit.setLeftComponent(mapMapPanel); imgSplit.setRightComponent(mapSelectionList); imgSplit.setOneTouchExpandable(true); imgSplit.setContinuousLayout(true); JSplitPane layer2Split = new JSplitPane(); layer2Split.setOrientation(JSplitPane.HORIZONTAL_SPLIT); layer2Split.setLeftComponent(globeSplit); layer2Split.setRightComponent(imgSplit); layer2Split.setOneTouchExpandable(true); layer2Split.setContinuousLayout(true); layer2Split.setResizeWeight(0.5); this.add(settings, BorderLayout.NORTH); this.add(layer2Split, BorderLayout.CENTER); this.pack(); this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH); enableSettingsMode(false); }
protected void importImagery() { try { // Read the data and save it in a temp file. File sourceFile = ExampleUtil.saveResourceToTempFile(IMAGE_PATH, ".tif"); // Create a raster reader to read this type of file. The reader is created from the // currently // configured factory. The factory class is specified in the Configuration, and a different // one can be // specified there. DataRasterReaderFactory readerFactory = (DataRasterReaderFactory) WorldWind.createConfigurationComponent(AVKey.DATA_RASTER_READER_FACTORY_CLASS_NAME); DataRasterReader reader = readerFactory.findReaderFor(sourceFile, null); // Before reading the raster, verify that the file contains imagery. AVList metadata = reader.readMetadata(sourceFile, null); if (metadata == null || !AVKey.IMAGE.equals(metadata.getStringValue(AVKey.PIXEL_FORMAT))) throw new Exception("Not an image file."); // Read the file into the raster. read() returns potentially several rasters if there are // multiple // files, but in this case there is only one so just use the first element of the returned // array. DataRaster[] rasters = reader.read(sourceFile, null); if (rasters == null || rasters.length == 0) throw new Exception("Can't read the image file."); DataRaster raster = rasters[0]; // Determine the sector covered by the image. This information is in the GeoTIFF file or // auxiliary // files associated with the image file. final Sector sector = (Sector) raster.getValue(AVKey.SECTOR); if (sector == null) throw new Exception("No location specified with image."); // Request a sub-raster that contains the whole image. This step is necessary because only // sub-rasters // are reprojected (if necessary); primary rasters are not. int width = raster.getWidth(); int height = raster.getHeight(); // getSubRaster() returns a sub-raster of the size specified by width and height for the // area indicated // by a sector. The width, height and sector need not be the full width, height and sector // of the data, // but we use the full values of those here because we know the full size isn't huge. If it // were huge // it would be best to get only sub-regions as needed or install it as a tiled image layer // rather than // merely import it. DataRaster subRaster = raster.getSubRaster(width, height, sector, null); // Tne primary raster can be disposed now that we have a sub-raster. Disposal won't affect // the // sub-raster. raster.dispose(); // Verify that the sub-raster can create a BufferedImage, then create one. if (!(subRaster instanceof BufferedImageRaster)) throw new Exception("Cannot get BufferedImage."); BufferedImage image = ((BufferedImageRaster) subRaster).getBufferedImage(); // The sub-raster can now be disposed. Disposal won't affect the BufferedImage. subRaster.dispose(); // Create a SurfaceImage to display the image over the specified sector. final SurfaceImage si1 = new SurfaceImage(image, sector); // On the event-dispatch thread, add the imported data as an SurfaceImageLayer. SwingUtilities.invokeLater( new Runnable() { public void run() { // Add the SurfaceImage to a layer. SurfaceImageLayer layer = new SurfaceImageLayer(); layer.setName("Imported Surface Image"); layer.setPickEnabled(false); layer.addRenderable(si1); // Add the layer to the model and update the application's layer panel. insertBeforeCompass(AppFrame.this.getWwd(), layer); AppFrame.this.getLayerPanel().update(AppFrame.this.getWwd()); // Set the view to look at the imported image. ExampleUtil.goTo(getWwd(), sector); } }); } catch (Exception e) { e.printStackTrace(); } }
public boolean initialize(MapSource mapSource) throws IOException, WMSServiceException { if (null == mapSource) { String msg = Logging.getMessage("nullValue.MapSourceIsNull"); Logging.logger().severe(msg); throw new WMSServiceException(msg); } this.mapSource = mapSource; this.params = mapSource.getParameters(); if (null == params) { String msg = Logging.getMessage("nullValue.AVListIsNull"); Logging.logger().severe(msg); throw new WMSServiceException(msg); } if (!params.hasKey(AVKey.FILE_NAME)) { String msg = Logging.getMessage("nullValue.ParamsIsNull"); Logging.logger().severe(msg); throw new WMSServiceException(msg); } this.sourceFile = new File(params.getStringValue(AVKey.FILE_NAME)); if (!this.sourceFile.exists()) { String msg = Logging.getMessage("generic.FileNotFound", this.sourceFile.getAbsolutePath()); Logging.logger().severe(msg); throw new FileNotFoundException(msg); } AVList fileParams = this.params.copy(); try { this.readerFactory = (DataRasterReaderFactory) WorldWind.createConfigurationComponent(AVKey.DATA_RASTER_READER_FACTORY_CLASS_NAME); } catch (Exception e) { this.readerFactory = new BasicDataRasterReaderFactory(); } DataRasterReader reader = this.readerFactory.findReaderFor(this.sourceFile, fileParams, readers); if (reader == null) { String msg = Logging.getMessage("nullValue.ReaderIsNull", this.sourceFile); Logging.logger().severe(msg); throw new WMSServiceException(msg); } reader.readMetadata(this.sourceFile, fileParams); this.params.setValues(fileParams); if (!this.params.hasKey(AVKey.SECTOR)) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new WMSServiceException(msg); } this.BBOX = (Sector) this.params.getValue(AVKey.SECTOR); if (0d == this.BBOX.getDeltaLatDegrees() || 0d == this.BBOX.getDeltaLonDegrees()) { String msg = Logging.getMessage("generic.SectorSizeInvalid"); Logging.logger().severe(msg); throw new WMSServiceException(msg); } int height = 0; if (!this.params.hasKey(AVKey.HEIGHT)) { String msg = Logging.getMessage("generic.InvalidHeight", 0); Logging.logger().severe(msg); throw new WMSServiceException(msg); } else { Object o = this.params.getValue(AVKey.HEIGHT); double d = Double.parseDouble("" + o); height = (int) d; } if (!this.params.hasKey(AVKey.WIDTH)) { String msg = Logging.getMessage("generic.InvalidWidth", 0); Logging.logger().severe(msg); throw new WMSServiceException(msg); } this.isElevation = (this.params.hasKey(AVKey.PIXEL_FORMAT) && AVKey.ELEVATION.equals(this.params.getValue(AVKey.PIXEL_FORMAT))); if (this.params.hasKey(AVKey.MISSING_DATA_SIGNAL)) { try { Object o = this.params.getValue(AVKey.MISSING_DATA_SIGNAL); double d = Double.parseDouble("" + o); this.nodataSignal = (short) d; } catch (Exception e) { this.nodataSignal = (this.isElevation) ? Short.MIN_VALUE : 0; } } else { this.nodataSignal = (this.isElevation) ? Short.MIN_VALUE : 0; } if (this.params.hasKey(AVKey.MISSING_DATA_REPLACEMENT)) { try { Object o = this.params.getValue(AVKey.MISSING_DATA_REPLACEMENT); double d = Double.parseDouble("" + o); this.nodataReplacement = (short) d; } catch (Exception e) { Logging.logger().finest(e.getMessage()); this.nodataReplacement = (this.isElevation) ? Short.MIN_VALUE : 0; } } else { this.nodataReplacement = (this.isElevation) ? Short.MIN_VALUE : 0; } if (this.isElevation) { if (this.params.hasKey(AVKey.ELEVATION_UNIT)) { try { String unit = this.params.getStringValue(AVKey.ELEVATION_UNIT); this.convertFeetToMeters = "feet".equalsIgnoreCase(unit); } catch (Exception e) { Logging.logger().finest(e.getMessage()); } } } // if PIXEL_HEIGHT is specified, we are not overriding it // because UTM images will have different pixel size if (!this.params.hasKey(AVKey.PIXEL_HEIGHT)) { this.pixelHeight = this.BBOX.getDeltaLatDegrees() / (double) height; } else { try { Object o = this.params.getValue(AVKey.PIXEL_HEIGHT); this.pixelHeight = Double.parseDouble("" + o); } catch (Exception e) { Logging.logger().finest(e.getMessage()); } } this.rasters = reader.read(this.sourceFile, this.params); if (null == this.rasters || 0 == this.rasters.length) { String msg = Logging.getMessage("nullValue.RasterIsNull"); Logging.logger().severe(msg); throw new WMSServiceException(msg); } return true; }
@Override protected boolean loadTexture(TextureTile tile, URL textureURL) { if (!(tile instanceof MinMaxTextureTile)) { Logging.logger().severe("Tile is not instance of " + MinMaxTextureTile.class); getLevels().markResourceAbsent(tile); return false; } synchronized (fileLock) { InputStream is = null; try { is = textureURL.openStream(); DataInputStream dis = new DataInputStream(is); int width = dis.readInt(); int height = dis.readInt(); int bands = dis.readInt(); double minElevation = dis.readDouble(); double maxElevation = dis.readDouble(); byte[][] bytes = new byte[bands][]; for (int i = 0; i < bands; i++) { bytes[i] = new byte[width * height]; is.read(bytes[i]); } DataBuffer db = new DataBufferByte(bytes, width * height); SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_BYTE, width, height, bands); Raster raster = Raster.createRaster(sm, db, null); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); image.setData(raster); TextureData textureData = TextureIO.newTextureData(image, isUseMipMaps()); if (textureData == null) { throw new Exception("Could not create texture data for " + textureURL); } ((MinMaxTextureTile) tile).setMinElevation(minElevation); ((MinMaxTextureTile) tile).setMaxElevation(maxElevation); tile.setTextureData(textureData); // if (tile.getLevelNumber() != 0 || !this.isRetainLevelZeroTiles()) addTileToCache(tile); getLevels().unmarkResourceAbsent(tile); firePropertyChange(AVKey.LAYER, null, this); return true; } catch (Exception e) { // Assume that something's wrong with the file and delete it. gov.nasa.worldwind.WorldWind.getDataFileStore().removeFile(textureURL); getLevels().markResourceAbsent(tile); String message = Logging.getMessage("generic.DeletedCorruptDataFile", textureURL); Logging.logger().info(message + ":" + e.getLocalizedMessage()); return false; } finally { if (is != null) { try { is.close(); } catch (IOException e) { } } } } }
/** * Reinitialize World Wind to its initial ready state. Shut down and restart all World Wind * services and clear all World Wind memory caches. Cache memory will be released at the next JVM * garbage collection. * * <p>Call this method to reduce World Wind's current resource usage to its initial, empty state. * This is typically required by applets when the user leaves the applet page. * * <p>The state of any open {@link WorldWindow} objects is indeterminate subsequent to invocation * of this method. The core WorldWindow objects attempt to shut themselves down cleanly during the * call, but their resulting window state is undefined. * * <p>World Wind can continue to be used after calling this method. */ public static synchronized void shutDown() { instance.wwo.firePropertyChange(SHUTDOWN_EVENT, null, -1); instance.dispose(); instance = new WorldWind(); }
protected boolean isTileInMemoryWithData() { Tile t = (Tile) WorldWind.getMemoryCache(Tile.class.getName()).getObject(this.getFileCachePath()); return !(t == null || t.getDataChunk() == null); }
/** * Represents a texture derived from a lazily loaded image source such as an image file or a {@link * java.awt.image.BufferedImage}. * * <p>The interface contains a method, {@link #isTextureInitializationFailed()} to determine whether * the instance failed to convert an image source to a texture. If such a failure occurs, the method * returns true and no further attempts are made to create the texture. * * <p>This class performs lazy retrieval and loading of an image source, attempting to retrieve and * load the image source only when the {@link #bind(DrawContext)} or {@link * #applyInternalTransform(DrawContext)} methods are called. If the image source is a {@link * BufferedImage} the associated {@link Texture} object is created and available immediately when * <code>bind</code> or <code>applyInternalTransform</code> are called. If the image source is a * local file or remote stream (URL), retrieval and loading is performed on a separate thread from * the EDT. * * @author tag * @version $Id$ */ public class LazilyLoadedTexture extends AVListImpl implements WWTexture { /** The original image source specified at construction. */ protected Object imageSource; /** The mip-map flag specified at construction. */ protected boolean useMipMaps; /** The current anisotropy flag. */ protected boolean useAnisotropy = true; /** The texture width, if the width is known. Otherwise it's -1. */ protected Integer width; /** The texture height, if the height is known. Otherwise it's -1. */ protected Integer height; /** The texture's texture coordinates, as determined by JOGL when the texture is created. */ protected TextureCoords texCoords; /** * The texture data created as the image source is read. It's removed - set to null - once the * textures is fully created. This intermediate texture data is necessary because the image source * is read in a non-EDT thread. This field is <code>volatile</code> in order to synchronize atomic * access among threads. This field is not used if the image source is <code>BufferedImage</code>. */ protected volatile TextureData textureData; // if non-null, then must be converted to a Texture /** Indicates that texture initialization failed. This texture should not be used if true. */ protected boolean textureInitializationFailed = false; /** Indicates whether the image read from the image source has mip-map data. */ protected boolean hasMipmapData = false; /** * Identifies the {@link gov.nasa.worldwind.cache.FileStore} of the supporting file cache for this * model. */ protected FileStore fileStore = WorldWind.getDataFileStore(); /** * Provides a semaphore to synchronize access to the texture file if duplicate request tasks are * active. */ protected final Object fileLock = new Object(); /** * The object to notify when an image is eventually loaded in memory. The current layer at the * time the image source is requested is assigned to this field. */ protected PropertyChangeListener listener; /** * Constructs a texture object for a specified image source. Requests that mip-maps be used. * * @param imageSource the source of the image, either a file path {@link String} or a {@link * java.awt.image.BufferedImage}. * @throws IllegalArgumentException if the <code>imageSource</code> is null. */ public LazilyLoadedTexture(Object imageSource) { this(imageSource, true); } /** * Constructs a texture object for a specified image source. * * @param imageSource the source of the image, either a file path {@link String} or a {@link * java.awt.image.BufferedImage}. * @param useMipMaps Indicates whether to generate and use mip-maps for the image. * @throws IllegalArgumentException if the <code>imageSource</code> is null. */ public LazilyLoadedTexture(Object imageSource, boolean useMipMaps) { initialize(imageSource, useMipMaps, null); } /** * Initializes this object's fields during construction. * * @param imageSource the image source. * @param useMipMaps the mip-map flag. * @param listener the change listener. * @throws IllegalArgumentException if the image source is null. */ protected void initialize( Object imageSource, boolean useMipMaps, PropertyChangeListener listener) { if (imageSource == null) { String message = Logging.getMessage("nullValue.ImageSource"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.imageSource = imageSource; this.useMipMaps = useMipMaps; if (listener != null) this.addPropertyChangeListener(listener); } public Object getImageSource() { return this.imageSource; } /** * Indicates whether the image source is a <code>BufferedImage</code> * * @return true if the image source is a <code>BufferedImage</code>, otherwise false. */ protected boolean isBufferedImageSource() { return this.getImageSource() instanceof BufferedImage; } /** * Indicates the texture's width, which is the same as the image source's width. The width is * known only after the image source has been retrieved from disk or network and read as <code> * TextureData</code>. It's value is -1 until then. * * @return the texture's width if the texture has been retrieved, otherwise -1. */ public int getWidth() { return this.width != null ? this.width : -1; } /** * Indicates the texture's height, which is the same as the image source's height. The height is * known only after the image source has been retrieved from disk or network and read as <code> * TextureData</code>. It's value is -1 until then. * * @return the texture's height if the texture has been retrieved, otherwise -1. */ public int getHeight() { return this.height != null ? this.height : -1; } /** * {@inheritDoc} * * <p>This method behaves identically to {@link #getWidth()}. The <code>DrawContext</code> * argument is not used. * * @param dc this parameter is not used by this class. * @return the texture's width if the texture has been retrieved, otherwise -1. */ public int getWidth(DrawContext dc) { return this.getWidth(); } /** * {@inheritDoc} * * <p>This method behaves identically to {@link #getHeight()}. The <code>DrawContext</code> * argument is not used. * * @param dc this parameter is not used by this class. * @return the texture's height if the texture has been retrieved, otherwise -1. */ public int getHeight(DrawContext dc) { return this.getHeight(); } /** * Indicates whether the texture should use mip-maps. If they are not available in the source * image they are created. * * @return true if mip-maps are used, false if not. */ public boolean isUseMipMaps() { return this.useMipMaps; } public TextureCoords getTexCoords() { return this.texCoords; } public boolean isTextureCurrent(DrawContext dc) { return this.getTexture(dc) != null; } /** * Indicates whether texture anisotropy is applied to the texture when rendered. * * @return useAnisotropy true if anisotropy is to be applied, otherwise false. */ public boolean isUseAnisotropy() { return this.useAnisotropy; } /** * Specifies whether texture anisotropy is applied to the texture when rendered. * * @param useAnisotropy true if anisotropy is to be applied, otherwise false. */ public void setUseAnisotropy(boolean useAnisotropy) { this.useAnisotropy = useAnisotropy; } /** * Indicates whether an attempt was made to retrieve and read the texture but it failed. If this * flag is true, this texture should not be used. * * @return true if texture retrieval or creation failed, otherwise true, even if the image source * has not yet been retrieved. */ public boolean isTextureInitializationFailed() { return this.textureInitializationFailed; } /** * Returns the {@link Texture} associated with this instance. * * @param dc the current draw context. * @return this instance's texture, or null if the texture does not currently exist. */ protected Texture getTexture(DrawContext dc) { if (this.getImageSource() == null) return null; Texture texture = dc.getTextureCache().getTexture(this.getImageSource()); if (this.width == null && texture != null) { this.width = texture.getWidth(); this.height = texture.getHeight(); this.texCoords = texture.getImageTexCoords(); } return texture; } /** * Returns this texture's texture data if it has been retrieved but a <code>Texture</code> has not * yet been created for it. * * <p>If this object's texture data field is non-null, a new texture is created from the texture * data when the tile is next bound or otherwise initialized. This object's texture data field is * then set to null. * * @return the texture data, which may be null indicating that the image source has not been read * or that a texture has been created. */ protected TextureData getTextureData() { return this.textureData; } /** * Specifies texture data for the tile. If texture data is non-null, a new texture is created from * the texture data when the tile is next bound. * * <p>When a texture is created from the texture data, the texture data field is set to null to * indicate that the data has been converted to a texture and its resources may be released. * * @param textureData the texture data, which may be null. */ protected void setTextureData(TextureData textureData) { this.textureData = textureData; if (textureData != null && textureData.getMipmapData() != null) this.hasMipmapData = true; } /** * Binds this instance's {@link Texture} to the <code>GLContext</code> if the texture has been * created, otherwise initiates image source retrieval and texture creation in a separate thread. * * @param dc the current draw context. * @return true if the texture was bound, otherwise false. */ public boolean bind(DrawContext dc) { if (this.isTextureInitializationFailed()) return false; if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } Texture texture = this.getTexture(dc); if (texture == null) texture = this.requestTexture(dc); if (texture != null) { texture.bind(); return true; } else { return false; } } public void applyInternalTransform(DrawContext dc) { if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } Texture texture = this.getTexture(dc); if (texture == null) texture = this.requestTexture(dc); if (texture == null) return; if (texture.getMustFlipVertically()) { GL gl = GLContext.getCurrent().getGL(); gl.glMatrixMode(GL.GL_TEXTURE); gl.glLoadIdentity(); gl.glScaled(1, -1, 1); gl.glTranslated(0, -1, 0); } } /** * If this instance's image source is a <code>BufferedImage</code>, creates and returns the * texture, otherwise creates a task in a separate thread to retrieve it from its local or remote * location. * * @param dc the current draw context. * @return the new texture, or null if the texture is not yet available. */ protected Texture requestTexture(DrawContext dc) { if (this.isBufferedImageSource()) return this.makeBufferedImageTexture(dc); if (this.getTextureData() != null && this.getTexture(dc) == null) return this.makeTextureFromTextureData(dc); if (WorldWind.getTaskService().isFull()) return null; Runnable task = this.createRequestTask(); if (WorldWind.getTaskService().contains(task)) return null; // Use either the current layer or the layer list as the listener to notify when the request // completes. The // latter is used when the image source is requested during ordered rendering and the current // layer is null. this.listener = dc.getCurrentLayer() != null ? dc.getCurrentLayer() : dc.getLayers(); WorldWind.getTaskService().addTask(task); return null; } /** * Returns an object that implements the Runnable interface, and who's <code>run</code> method * retrieves and loads this texture's image source. * * @return a new request task that retrieves and loads this texture's image source. */ protected Runnable createRequestTask() { return new RequestTask(this); } /** * Creates this instance's {@link Texture} if the image source is a <code>BufferedImage<code>. * * @param dc the current draw context. * * @return the newly created texture, or null if the texture was not created. * * @throws IllegalStateException if the image source is null or not a <code>BufferedImage</code>. */ protected Texture makeBufferedImageTexture(DrawContext dc) { if (this.getImageSource() == null || !(this.getImageSource() instanceof BufferedImage)) { String message = Logging.getMessage("generic.NotABufferedImage"); Logging.logger().severe(message); throw new IllegalStateException(message); } try { TextureData td = TextureIO.newTextureData((BufferedImage) this.getImageSource(), this.isUseMipMaps()); if (td == null) return null; this.setTextureData(td); return this.makeTextureFromTextureData(dc); } catch (Exception e) { String msg = Logging.getMessage("generic.IOExceptionDuringTextureInitialization"); Logging.logger().log(java.util.logging.Level.SEVERE, msg, e); this.textureInitializationFailed = true; return null; } } /** * Creates a {@link Texture} from this instance's {@link TextureData} if the <code>TextureData * </code> exists. * * @param dc the current draw context. * @return the newly created texture, or null if this instance has no current <code>TextureData * </code> or if texture creation failed. */ protected Texture makeTextureFromTextureData(DrawContext dc) { if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } if (this.getTextureData() == null) // texture not in cache yet texture data is null, can't initialize { String msg = Logging.getMessage("nullValue.TextureDataIsNull"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } try { Texture texture = TextureIO.newTexture(this.getTextureData()); if (texture == null) { this.textureInitializationFailed = true; return null; } this.width = texture.getWidth(); this.height = texture.getHeight(); this.texCoords = texture.getImageTexCoords(); this.setTextureParameters(dc, texture); // Cache the texture and release the texture data. dc.getTextureCache().put(this.getImageSource(), texture); this.setTextureData(null); return texture; } catch (Exception e) { String name = this.isBufferedImageSource() ? "BufferedImage" : this.getImageSource().toString(); String msg = Logging.getMessage("generic.ExceptionAttemptingToCreateTexture", name); Logging.logger().log(java.util.logging.Level.SEVERE, msg, e); return null; } } /** * Sets a specified texture's OpenGL <code>Texture</code> parameters. * * @param dc the current draw context. * @param texture the texture whose parameters to set. */ protected void setTextureParameters(DrawContext dc, Texture texture) { // Enable the appropriate mip-mapping texture filters if the caller has specified that // mip-mapping should be // enabled, and the texture itself supports mip-mapping. boolean useMipMapFilter = this.useMipMaps && (this.getTextureData().getMipmapData() != null || texture.isUsingAutoMipmapGeneration()); GL gl = dc.getGL(); gl.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, useMipMapFilter ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); if (this.isUseAnisotropy() && useMipMapFilter) { double maxAnisotropy = dc.getGLRuntimeCapabilities().getMaxTextureAnisotropy(); if (dc.getGLRuntimeCapabilities().isUseAnisotropicTextureFilter() && maxAnisotropy >= 2.0) { gl.glTexParameterf( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, (float) maxAnisotropy); } } } protected void notifyTextureLoaded() { if (this.listener != null) { this.listener.propertyChange(new PropertyChangeEvent(this, AVKey.TEXTURE, null, this)); this.listener = null; // forget the listener to avoid dangling references } } /** * Attempts to find this texture's image file locally, and if that fails attempts to find it * remotely. */ protected static class RequestTask implements Runnable { /** The BasicWWTexture associated with this request. */ protected final LazilyLoadedTexture wwTexture; /** * Construct a request task for a specified BasicWWTexture. * * @param wwTexture the texture object for which to construct the request task. */ protected RequestTask(LazilyLoadedTexture wwTexture) { if (wwTexture == null) { String message = Logging.getMessage("nullValue.TextureIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.wwTexture = wwTexture; } public void run() { if (Thread.currentThread().isInterrupted()) return; // the task was cancelled because it's a duplicate or for some other reason URL fileUrl = this.wwTexture.fileStore.requestFile(this.wwTexture.getImageSource().toString()); if (fileUrl != null) { if (this.wwTexture.loadTextureData(fileUrl)) { this.wwTexture.notifyTextureLoaded(); } } } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final RequestTask that = (RequestTask) o; return !(this.wwTexture != null ? !this.wwTexture.equals(that.wwTexture) : that.wwTexture != null); } public int hashCode() { return (this.wwTexture != null ? this.wwTexture.hashCode() : 0); } public String toString() { return this.wwTexture.getImageSource().toString(); } } /** * Loads the image from disk into memory. If successful, texture data is created and available via * {@link #getTextureData()}. * * @param fileUrl the URL of the image file. * @return true if the image was successfully loaded, otherwise false. */ protected boolean loadTextureData(URL fileUrl) { TextureData td; synchronized (this.fileLock) { td = readImage(fileUrl); if (td != null) this.setTextureData(td); } return this.getTextureData() != null; } /** * Reads and returns a {@link TextureData} for an image from a specified file URL. * * @param fileUrl the URL of the image file to read. * @return a <code>TextureData</code> instance for the image. */ protected TextureData readImage(URL fileUrl) { try { return TextureIO.newTextureData(fileUrl, this.isUseMipMaps(), null); } catch (Exception e) { String msg = Logging.getMessage( "layers.TextureLayer.ExceptionAttemptingToReadTextureFile", this.getImageSource()); Logging.logger().log(java.util.logging.Level.SEVERE, msg, e); this.textureInitializationFailed = true; return null; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LazilyLoadedTexture that = (LazilyLoadedTexture) o; //noinspection RedundantIfStatement if (imageSource != null ? !imageSource.equals(that.imageSource) : that.imageSource != null) return false; return true; } @Override public int hashCode() { return imageSource != null ? imageSource.hashCode() : 0; } }