From 5ce877c30ebfcee9d4995ffd6597667315dc6688 Mon Sep 17 00:00:00 2001 From: Joel Aaron Cohen Date: Tue, 27 Nov 2007 12:28:11 -0500 Subject: [PATCH] Update to Worldwind release 20070920 --- ErrorStrings.properties | 443 ------- ErrorStrings_de_DE.properties | 6 - ErrorStrings_ja.properties | 2 - ErrorStrings_zh_CN.properties | 8 - ThreadStrings.properties | 6 - applet/WWJApplet.java | 244 ++++ applet/WWJAppletMinimal.java | 89 ++ applet/WWJAppletsNotes.html | 456 +++++++ applet/index_applet.html | 46 + applet/index_applet_cookie.html | 184 +++ applet/index_applet_fullscreen.html | 21 + config/worldwind.properties | 6 +- gov/nasa/worldwind/AVKey.java | 105 -- gov/nasa/worldwind/AVList.java | 128 -- gov/nasa/worldwind/AVListImpl.java | 387 ------ gov/nasa/worldwind/AbsentResourceList.java | 84 -- gov/nasa/worldwind/AbstractFileCache.java | 500 -------- gov/nasa/worldwind/AbstractView.java | 640 ---------- gov/nasa/worldwind/BasicDataFileCache.java | 35 - gov/nasa/worldwind/BasicElevationModel.java | 694 ----------- gov/nasa/worldwind/BasicFrameController.java | 91 -- gov/nasa/worldwind/BasicMemoryCache.java | 411 ------- gov/nasa/worldwind/BasicOrbitView.java | 410 ------- gov/nasa/worldwind/BasicRetrievalService.java | 507 -------- gov/nasa/worldwind/Cacheable.java | 26 - gov/nasa/worldwind/Configuration.java | 3 +- gov/nasa/worldwind/DDSConverter.java | 725 ----------- gov/nasa/worldwind/DrawContext.java | 274 ----- gov/nasa/worldwind/DrawContextImpl.java | 379 ------ gov/nasa/worldwind/ElevationModel.java | 130 -- gov/nasa/worldwind/FileCache.java | 34 - gov/nasa/worldwind/FrameController.java | 20 - gov/nasa/worldwind/GeoRSSParser.java | 569 --------- gov/nasa/worldwind/Globe.java | 46 - gov/nasa/worldwind/HTTPRetriever.java | 61 - gov/nasa/worldwind/IconRenderer.java | 605 --------- gov/nasa/worldwind/InputHandler.java | 26 - gov/nasa/worldwind/Layer.java | 34 - gov/nasa/worldwind/LayerList.java | 316 ----- gov/nasa/worldwind/Level.java | 329 ----- gov/nasa/worldwind/LevelSet.java | 234 ---- gov/nasa/worldwind/Material.java | 103 -- gov/nasa/worldwind/MemoryCache.java | 174 --- gov/nasa/worldwind/OrderedRenderable.java | 16 - gov/nasa/worldwind/Pedestal.java | 44 - gov/nasa/worldwind/PickSupport.java | 114 -- gov/nasa/worldwind/Pickable.java | 16 - gov/nasa/worldwind/PickedObject.java | 131 -- gov/nasa/worldwind/PickedObjectList.java | 61 - gov/nasa/worldwind/PlaceName.java | 41 - gov/nasa/worldwind/PlaceNameRenderer.java | 332 ----- gov/nasa/worldwind/PlaceNameService.java | 391 ------ gov/nasa/worldwind/PlaceNameServiceSet.java | 81 -- gov/nasa/worldwind/PositionEvent.java | 54 - gov/nasa/worldwind/PositionListener.java | 18 - gov/nasa/worldwind/Renderable.java | 25 - gov/nasa/worldwind/RenderingEvent.java | 40 - gov/nasa/worldwind/RenderingListener.java | 18 - gov/nasa/worldwind/RetrievalFuture.java | 16 - gov/nasa/worldwind/RetrievalPostProcessor.java | 16 - gov/nasa/worldwind/RetrievalService.java | 30 - .../worldwind/RetrieveToFilePostProcessor.java | 82 -- gov/nasa/worldwind/Retriever.java | 58 - gov/nasa/worldwind/SectorGeometry.java | 30 - gov/nasa/worldwind/SectorGeometryList.java | 124 -- gov/nasa/worldwind/SelectEvent.java | 92 -- gov/nasa/worldwind/SelectListener.java | 18 - gov/nasa/worldwind/StringUtil.java | 23 - gov/nasa/worldwind/SurfaceTileRenderer.java | 309 ----- gov/nasa/worldwind/Tessellator.java | 16 - gov/nasa/worldwind/ThreadedTaskService.java | 172 --- gov/nasa/worldwind/Tile.java | 407 ------ gov/nasa/worldwind/TileKey.java | 205 ---- gov/nasa/worldwind/ToolTipRenderer.java | 275 ----- gov/nasa/worldwind/Track.java | 20 - gov/nasa/worldwind/TrackPoint.java | 30 - gov/nasa/worldwind/TrackPointIterator.java | 22 - gov/nasa/worldwind/TrackPointIteratorImpl.java | 99 -- gov/nasa/worldwind/TrackRenderer.java | 409 ------ gov/nasa/worldwind/TrackSegment.java | 16 - gov/nasa/worldwind/URLRetriever.java | 487 -------- gov/nasa/worldwind/UserFacingIcon.java | 195 --- gov/nasa/worldwind/Version.java | 4 +- gov/nasa/worldwind/View.java | 422 ------- .../worldwind/WWDuplicateRequestException.java | 19 - gov/nasa/worldwind/WWIO.java | 357 ------ gov/nasa/worldwind/WWIcon.java | 59 - gov/nasa/worldwind/WWRuntimeException.java | 33 - gov/nasa/worldwind/WorldWindowGLAutoDrawable.java | 17 +- gov/nasa/worldwind/avlist/AVKey.java | 7 +- gov/nasa/worldwind/awt/InterpolatorTimer.java | 303 ----- .../worldwind/examples/ApplicationTemplate.java | 75 +- gov/nasa/worldwind/examples/GlobalGridLayer.java | 59 - .../worldwind/examples/WMSCapabilitiesParsing.java | 360 ------ gov/nasa/worldwind/examples/WMSLayers.java | 114 -- gov/nasa/worldwind/formats/gpx/GpxTrackPoint.java | 22 +- .../formats/nitfs/AbstractRpf2DdsCompress.java | 28 - .../worldwind/formats/nitfs/Cadrg2DdsCompress.java | 44 - .../worldwind/formats/nitfs/Cib2DdsCompress.java | 59 - .../formats/nitfs/NitfsDataExtensionSegment.java | 21 - .../formats/nitfs/NitfsExtendedHeaderSegment.java | 21 - .../worldwind/formats/nitfs/NitfsFileHeader.java | 275 ----- .../worldwind/formats/nitfs/NitfsImageBand.java | 126 -- .../worldwind/formats/nitfs/NitfsImageSegment.java | 654 ---------- .../worldwind/formats/nitfs/NitfsLabelSegment.java | 21 - gov/nasa/worldwind/formats/nitfs/NitfsMessage.java | 208 ---- .../nitfs/NitfsReservedExtensionSegment.java | 21 - .../formats/nitfs/NitfsRuntimeException.java | 56 - gov/nasa/worldwind/formats/nitfs/NitfsSegment.java | 41 - .../worldwind/formats/nitfs/NitfsSegmentType.java | 35 - .../formats/nitfs/NitfsSymbolSegment.java | 21 - .../worldwind/formats/nitfs/NitfsTextSegment.java | 21 - .../nitfs/NitfsUserDefinedHeaderSegment.java | 30 - gov/nasa/worldwind/formats/nitfs/NitfsUtil.java | 133 -- .../worldwind/formats/nitfs/Rpf2DdsCompress.java | 18 - .../worldwind/formats/nmea/NmeaTrackPoint.java | 22 +- gov/nasa/worldwind/formats/rpf/RpfColorMap.java | 111 -- gov/nasa/worldwind/formats/rpf/RpfDataSeries.java | 198 --- gov/nasa/worldwind/formats/rpf/RpfFile.java | 42 - .../worldwind/formats/rpf/RpfFileComponents.java | 44 - .../formats/rpf/RpfFrameFileComponents.java | 166 --- .../formats/rpf/RpfFrameFileIndexSection.java | 193 --- .../rpf/RpfFrameFilenameFormatException.java | 32 - .../formats/rpf/RpfFrameFilenameUtil.java | 222 ---- .../worldwind/formats/rpf/RpfFrameProperties.java | 119 -- .../formats/rpf/RpfFramePropertyType.java | 68 - .../worldwind/formats/rpf/RpfHeaderSection.java | 43 - gov/nasa/worldwind/formats/rpf/RpfImageFile.java | 188 --- gov/nasa/worldwind/formats/rpf/RpfImageType.java | 20 - .../worldwind/formats/rpf/RpfLocationSection.java | 303 ----- gov/nasa/worldwind/formats/rpf/RpfProducer.java | 107 -- gov/nasa/worldwind/formats/rpf/RpfTocCrawler.java | 294 ----- gov/nasa/worldwind/formats/rpf/RpfTocFile.java | 75 -- .../formats/rpf/RpfUserDefinedHeaderSegment.java | 37 - gov/nasa/worldwind/formats/rpf/RpfZone.java | 539 -------- gov/nasa/worldwind/geom/LatLon.java | 221 +++- gov/nasa/worldwind/geom/Matrix4.java | 857 ------------- gov/nasa/worldwind/geom/Point.java | 556 --------- gov/nasa/worldwind/geom/Polyline.java | 349 ------ gov/nasa/worldwind/geom/Quadrilateral.java | 239 ---- gov/nasa/worldwind/geom/Sector.java | 10 +- gov/nasa/worldwind/geom/SurfacePolygon.java | 147 --- gov/nasa/worldwind/geom/SurfacePolyline.java | 31 - gov/nasa/worldwind/geom/SurfaceQuadrilateral.java | 51 - gov/nasa/worldwind/geom/SurfaceShape.java | 371 ------ gov/nasa/worldwind/geom/ViewFrustum.java | 182 --- gov/nasa/worldwind/globes/Earth.java | 6 +- gov/nasa/worldwind/globes/EarthElevationModel.java | 7 +- gov/nasa/worldwind/globes/EllipsoidalGlobe.java | 24 +- gov/nasa/worldwind/layers/CompassLayer.java | 32 +- .../layers/Earth/PoliticalBoundariesLayer.java | 86 -- .../worldwind/layers/Earth/USGSUrbanAreaOrtho.java | 7 +- gov/nasa/worldwind/layers/PlaceNameLayer.java | 871 ------------- gov/nasa/worldwind/layers/RpfLayer.java | 1297 -------------------- gov/nasa/worldwind/layers/TextureTile.java | 45 +- gov/nasa/worldwind/layers/TiledImageLayer.java | 336 +++-- gov/nasa/worldwind/layers/TrackLayer.java | 106 +- .../worldwind/layers/placename/PlaceNameLayer.java | 11 +- .../layers/placename/PlaceNameRenderer.java | 4 +- gov/nasa/worldwind/render/Material.java | 20 +- gov/nasa/worldwind/render/Polyline.java | 6 +- gov/nasa/worldwind/render/SurfaceShape.java | 93 +- gov/nasa/worldwind/render/SurfaceTile.java | 5 +- gov/nasa/worldwind/render/SurfaceTileRenderer.java | 6 +- gov/nasa/worldwind/tracks/TrackPoint.java | 8 +- gov/nasa/worldwind/tracks/TrackRenderer.java | 414 ------- gov/nasa/worldwind/util/Level.java | 15 +- gov/nasa/worldwind/util/LevelSet.java | 64 +- gov/nasa/worldwind/util/Tile.java | 8 +- gov/nasa/worldwind/view/AbstractView.java | 36 +- gov/nasa/worldwind/view/BasicOrbitView.java | 162 ++- gov/nasa/worldwind/view/OrbitViewModel.java | 62 +- images/400x230-splash-wwr.png | Bin 155227 -> 0 bytes worldwinddemo/BasicDemo.java | 2 +- worldwinddemo/StatusBar.java | 113 -- 175 files changed, 2112 insertions(+), 25379 deletions(-) delete mode 100644 ErrorStrings.properties delete mode 100644 ErrorStrings_de_DE.properties delete mode 100644 ErrorStrings_ja.properties delete mode 100644 ErrorStrings_zh_CN.properties delete mode 100644 ThreadStrings.properties create mode 100644 applet/WWJApplet.java create mode 100644 applet/WWJAppletMinimal.java create mode 100644 applet/WWJAppletsNotes.html create mode 100644 applet/index_applet.html create mode 100644 applet/index_applet_cookie.html create mode 100644 applet/index_applet_fullscreen.html delete mode 100644 gov/nasa/worldwind/AVKey.java delete mode 100644 gov/nasa/worldwind/AVList.java delete mode 100644 gov/nasa/worldwind/AVListImpl.java delete mode 100644 gov/nasa/worldwind/AbsentResourceList.java delete mode 100644 gov/nasa/worldwind/AbstractFileCache.java delete mode 100644 gov/nasa/worldwind/AbstractView.java delete mode 100644 gov/nasa/worldwind/BasicDataFileCache.java delete mode 100644 gov/nasa/worldwind/BasicElevationModel.java delete mode 100644 gov/nasa/worldwind/BasicFrameController.java delete mode 100644 gov/nasa/worldwind/BasicMemoryCache.java delete mode 100644 gov/nasa/worldwind/BasicOrbitView.java delete mode 100644 gov/nasa/worldwind/BasicRetrievalService.java delete mode 100644 gov/nasa/worldwind/Cacheable.java delete mode 100644 gov/nasa/worldwind/DDSConverter.java delete mode 100644 gov/nasa/worldwind/DrawContext.java delete mode 100644 gov/nasa/worldwind/DrawContextImpl.java delete mode 100644 gov/nasa/worldwind/ElevationModel.java delete mode 100644 gov/nasa/worldwind/FileCache.java delete mode 100644 gov/nasa/worldwind/FrameController.java delete mode 100644 gov/nasa/worldwind/GeoRSSParser.java delete mode 100644 gov/nasa/worldwind/Globe.java delete mode 100644 gov/nasa/worldwind/HTTPRetriever.java delete mode 100644 gov/nasa/worldwind/IconRenderer.java delete mode 100644 gov/nasa/worldwind/InputHandler.java delete mode 100644 gov/nasa/worldwind/Layer.java delete mode 100644 gov/nasa/worldwind/LayerList.java delete mode 100644 gov/nasa/worldwind/Level.java delete mode 100644 gov/nasa/worldwind/LevelSet.java delete mode 100644 gov/nasa/worldwind/Material.java delete mode 100644 gov/nasa/worldwind/MemoryCache.java delete mode 100644 gov/nasa/worldwind/OrderedRenderable.java delete mode 100644 gov/nasa/worldwind/Pedestal.java delete mode 100644 gov/nasa/worldwind/PickSupport.java delete mode 100644 gov/nasa/worldwind/Pickable.java delete mode 100644 gov/nasa/worldwind/PickedObject.java delete mode 100644 gov/nasa/worldwind/PickedObjectList.java delete mode 100644 gov/nasa/worldwind/PlaceName.java delete mode 100644 gov/nasa/worldwind/PlaceNameRenderer.java delete mode 100644 gov/nasa/worldwind/PlaceNameService.java delete mode 100644 gov/nasa/worldwind/PlaceNameServiceSet.java delete mode 100644 gov/nasa/worldwind/PositionEvent.java delete mode 100644 gov/nasa/worldwind/PositionListener.java delete mode 100644 gov/nasa/worldwind/Renderable.java delete mode 100644 gov/nasa/worldwind/RenderingEvent.java delete mode 100644 gov/nasa/worldwind/RenderingListener.java delete mode 100644 gov/nasa/worldwind/RetrievalFuture.java delete mode 100644 gov/nasa/worldwind/RetrievalPostProcessor.java delete mode 100644 gov/nasa/worldwind/RetrievalService.java delete mode 100644 gov/nasa/worldwind/RetrieveToFilePostProcessor.java delete mode 100644 gov/nasa/worldwind/Retriever.java delete mode 100644 gov/nasa/worldwind/SectorGeometry.java delete mode 100644 gov/nasa/worldwind/SectorGeometryList.java delete mode 100644 gov/nasa/worldwind/SelectEvent.java delete mode 100644 gov/nasa/worldwind/SelectListener.java delete mode 100644 gov/nasa/worldwind/StringUtil.java delete mode 100644 gov/nasa/worldwind/SurfaceTileRenderer.java delete mode 100644 gov/nasa/worldwind/Tessellator.java delete mode 100644 gov/nasa/worldwind/ThreadedTaskService.java delete mode 100644 gov/nasa/worldwind/Tile.java delete mode 100644 gov/nasa/worldwind/TileKey.java delete mode 100644 gov/nasa/worldwind/ToolTipRenderer.java delete mode 100644 gov/nasa/worldwind/Track.java delete mode 100644 gov/nasa/worldwind/TrackPoint.java delete mode 100644 gov/nasa/worldwind/TrackPointIterator.java delete mode 100644 gov/nasa/worldwind/TrackPointIteratorImpl.java delete mode 100644 gov/nasa/worldwind/TrackRenderer.java delete mode 100644 gov/nasa/worldwind/TrackSegment.java delete mode 100644 gov/nasa/worldwind/URLRetriever.java delete mode 100644 gov/nasa/worldwind/UserFacingIcon.java delete mode 100644 gov/nasa/worldwind/View.java delete mode 100644 gov/nasa/worldwind/WWDuplicateRequestException.java delete mode 100644 gov/nasa/worldwind/WWIO.java delete mode 100644 gov/nasa/worldwind/WWIcon.java delete mode 100644 gov/nasa/worldwind/WWRuntimeException.java delete mode 100644 gov/nasa/worldwind/awt/InterpolatorTimer.java delete mode 100644 gov/nasa/worldwind/examples/GlobalGridLayer.java delete mode 100644 gov/nasa/worldwind/examples/WMSCapabilitiesParsing.java delete mode 100644 gov/nasa/worldwind/examples/WMSLayers.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/AbstractRpf2DdsCompress.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/Cadrg2DdsCompress.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/Cib2DdsCompress.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsDataExtensionSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsExtendedHeaderSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsFileHeader.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsImageBand.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsImageSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsLabelSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsMessage.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsReservedExtensionSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsRuntimeException.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsSegmentType.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsSymbolSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsTextSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsUserDefinedHeaderSegment.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/NitfsUtil.java delete mode 100644 gov/nasa/worldwind/formats/nitfs/Rpf2DdsCompress.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfColorMap.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfDataSeries.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFile.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFileComponents.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFrameFileComponents.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFrameFileIndexSection.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFrameFilenameFormatException.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFrameFilenameUtil.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFrameProperties.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfFramePropertyType.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfHeaderSection.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfImageFile.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfImageType.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfLocationSection.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfProducer.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfTocCrawler.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfTocFile.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfUserDefinedHeaderSegment.java delete mode 100644 gov/nasa/worldwind/formats/rpf/RpfZone.java delete mode 100644 gov/nasa/worldwind/geom/Matrix4.java delete mode 100644 gov/nasa/worldwind/geom/Point.java delete mode 100644 gov/nasa/worldwind/geom/Polyline.java delete mode 100644 gov/nasa/worldwind/geom/Quadrilateral.java delete mode 100644 gov/nasa/worldwind/geom/SurfacePolygon.java delete mode 100644 gov/nasa/worldwind/geom/SurfacePolyline.java delete mode 100644 gov/nasa/worldwind/geom/SurfaceQuadrilateral.java delete mode 100644 gov/nasa/worldwind/geom/SurfaceShape.java delete mode 100644 gov/nasa/worldwind/geom/ViewFrustum.java delete mode 100644 gov/nasa/worldwind/layers/Earth/PoliticalBoundariesLayer.java delete mode 100644 gov/nasa/worldwind/layers/PlaceNameLayer.java delete mode 100644 gov/nasa/worldwind/layers/RpfLayer.java delete mode 100644 gov/nasa/worldwind/tracks/TrackRenderer.java delete mode 100644 images/400x230-splash-wwr.png delete mode 100644 worldwinddemo/StatusBar.java diff --git a/ErrorStrings.properties b/ErrorStrings.properties deleted file mode 100644 index 86b68fb..0000000 --- a/ErrorStrings.properties +++ /dev/null @@ -1,443 +0,0 @@ -#README: This file has several sections: -# o Generic punctuation characters that can be used in messages -# o Generic terms that can be used in messages -# o Generic error/warning/log messages -# o Class-specific error/warning/log messages - -#*********************************************************************************************** -# PLEASE KEEP THESE IN ALPHABETICAL ORDER * (except for the term, generic and nullValue blocks) -#*********************************************************************************************** - -# Punctuation characters -punctuation.space=\u0020 - -# Generic terms -term.cacheFolder=cache folder -term.datasetName=dataset name -term.expiryTime=expiryTime -term.formatSuffix=format suffix -term.levelNumber=level number -term.levelName=level name -term.numLevels=number of levels -term.numEMptyLevels=number of empty levels -term.sector=sector -term.service=service -term.tileDelta=tile delta -term.tileHeight=tile height -term.tileURLBuilder=tile URL builder -term.tileWidth=tile width -term.unknown=unknown - -# Generic errors -generic.AllUsersWindowsProfileNotKnown=The user-shared Windows profile cannot be determined. -generic.angleOutOfRange=Angle out of range -generic.arrayInvalidLength=Array invalid length -generic.CantCreateCacheFile=Unable to create cache file for \u0020 -generic.columnIndexOutOfRange=Column index out of range -generic.CorruptFile=File is corrupt\u0020 -generic.DataFileExpired=Deleting out of date data file\u0020 -generic.DeletedCorruptDataFile=Deleted corrupted data file\u0020 -generic.deltaAngleOutOfRange=Delta angle out of range -generic.IOExceptionDuringTextureInitialization=IOException during texture initialization -generic.ExceptionWhilePickingIcon=Exception while picking icon\u0020 -generic.ExceptionWhileRenderingIcon=Exception while rendering icon\u0020 -generic.ExceptionWhileRenderingLayer=Exception while rendering layer\u0020 -generic.EnumNotFound=Cannot find enumeration:\u0020 -generic.fileNotFound=File not found -generic.InsufficientPositions=Insufficient number of positions -generic.InvalidHint=Hint value is not recognized -generic.indexOutOfRange=Index out of range -generic.invalidIndex=Invalid index -generic.NoSurfaceGeometry=No surface geometry to render -generic.NumTextureUnitsLessThanOne=The number of texture units specified is less than 1 -generic.rowIndexOutOfRange=Row index out of range -generic.TextureIOException=TextureIO exception while reading file\u0020 -generic.unknown=Unknown -generic.UnknownOperatingSystem=The operating system this program is running on is not recognized. -generic.UnsupportedOperation=The operation is not supported:\u0020 -generic.UsersHomeDirectoryNotKnown=This user's home director cannot be determined. -generic.UsersWindowsProfileNotKnown=The user's Windows profile cannot be determined. -generic.ValueOutOfRange=Value is out of range:\u0020 - -# Null argument/value messages -nullValue.ActionEventIsNull=Action event is null -nullValue.AngleIsNull=Angle is null -nullValue.ArrayIsNull=char array is null -nullValue.AttributeKeyIsNull=Attribute key is null -nullValue.AttributesIsNull=Attributes is null -nullValue.BufferNull=Buffer is null -nullValue.ByteBufferIsNull=ByteBuffer is null -nullValue.CacheEntryIsNull=Cache Entry is null -nullValue.CenterIsNull=Center is null -nullValue.CenterPointIsNull=Center point is null -nullValue.CharacterIsNull=Character is null -nullValue.CollectionIsNull=Collection is null -nullValue.ColorIsNull=Color is null -nullValue.CompassPositionIsNull=Compass position is null -nullValue.ConnectionIsNull=Connection is null -nullValue.DataSetIsNull=Dataset is null -nullValue.DestNull=Destination is null -nullValue.DeviceIsNull=Device is null -nullValue.DirectionIsNull=Direction is null -nullValue.DisplayStyleIsNull=Display style is null -nullValue.DocumentIsNull=Document is null -nullValue.DrawContextIsNull=Drawing context is null -nullValue.ElementNameIsNull=Element name is null -nullValue.ElevationsIsNull=Elevations is null -nullValue.ElevationModelIsNull=Elevation Model is null -nullValue.EndPointIsNull=End point is null -nullValue.EntriesIsNull=Entries is null -nullValue.EventIsNull=Event is null -nullValue.ExtentIsNull=Extent is null -nullValue.FileCachePathIsNull=File cache path is null of zero length -nullValue.FileIsNull=File is null -nullValue.FilePathIsNull=File path is null -nullValue.FontIsNull=Font is null -nullValue.FontRenderContextIsNull=Font Render Context is null -nullValue.FOVIsNull=Field of view is null -nullValue.FrameControllerIsNull=FrameController is null -nullValue.FrustumIsNull=Frustum is null -nullValue.GeometryIsNull=Geometry is null -nullValue.GetMethodIsNull=Attribute query listener is null -nullValue.GetMethodReferenceIsNull=Get method reference is null -nullValue.GLIsNull=GL is null -nullValue.GLContextIsNull=GLContext is null -nullValue.GLContextNotCurrent=GLContext is not current -nullValue.GlobeIsNull=Globe is null -nullValue.Icon=Icon is null -nullValue.IconIterator=Icon iterator is null -nullValue.IconFilePath=Icon file path is null -nullValue.InputAnglesNull=One or more input angles are null -nullValue.InputFileNameIsNull=Input file name is null -nullValue.InputStreamIsNull=InputStream is null -nullValue.IntersectionPointIsNull=Intersection point is null -nullValue.Iterator=Iterator is null -nullValue.KeyIsNull=Key is null -nullValue.LatLonIsNull=LatLon is null -nullValue.LatitudeOrLongitudeIsNull=Latitude or longitude is null -nullValue.LayerIsNull=Layer is null -nullValue.LayersIsNull=Layers is null -nullValue.LayerParams=Layer parameters -nullValue.LevelIsNull=Level is null -nullValue.LevelSetIsNull=Level set is null -nullValue.LevelZeroTileDeltaIsNull=Level zero tile delta is null -nullValue.LineIsNull=Line is null -nullValue.ListenerIsNull=Listener is null -nullValue.LNameIsNull=lname is null -nullValue.MaterialIsNull=Material is null -nullValue.MatrixIsNull=Matrix is null -nullValue.MimeTypeIsNull=MimeType is null -nullValue.ModelIsNull=Model is null -nullValue.ObjectIsNull=Object is null -nullValue.OrderedRenderable=Ordered renderable is null -nullValue.OriginIsNull=Origin is null -nullValue.org.xml.sax.AttributesIsNull=org.xml.sax.Attributes is null -nullValue.PathIsNull=Path is null -nullValue.PickedObjectList=Picked objec list is null -nullValue.PickedObject=Picked object is null -nullValue.PickPoint=Pick point is null -nullValue.PlaceNameServiceIsNull=PlaceNameService is null -nullValue.PlaceNameServiceSetIsNull=PlaceNameServiceSet set is null -nullValue.PlaneIsNull=Plane is null -nullValue.PointIsNull=Point is null -nullValue.PointsArrayIsNull=Points array is null -nullValue.PostProcessorIsNull=PostProcessor is null -nullValue.PolarPointArrayIsNull=PolarPoint array is null -nullValue.PositionsListIsNull=Positions list is null -nullValue.PositionIsNull=Position is null -nullValue.PropertyNameIsNull=Property name is null -nullValue.PropertyChangeEventIsNull=Property change event is null -nullValue.PropertyChangeListenerIsNull=Property change listener is null -nullValue.QNameIsNull=qname is null -nullValue.QuaternionIsNull=Quaternion is null -nullValue.RequestTaskIsNull=Request task is null -nullValue.RetrieverIsNull=Retriever is null -nullValue.RenderInfoIsNull=Geometry rendering info is null -nullValue.RetrieverNameIsNull=Retriever name is null -nullValue.RotationAngleIsNull=Rotation angle is null -nullValue.RpfFrameExtendedPropertiesIsNull=RpfFrameExtendedProperties is null -nullValue.RpfFramePropertiesIsNull=RpfFramePropreties is null -nullValue.RpfDataSeriesIsNull=RpfDataSeries is null -nullValue.RpfFramePropertyTypeIsNull=RpfFramePropertyType is null -nullValue.RpfProducerIsNull=RpfProducer is null -nullValue.RpfTocFileIsNull=RpfTocFile is null -nullValue.RpfZoneIsNull=RpfZone is null -nullValue.RunnableIsNull=Runnable is null -nullValue.SectorIsNull=Sector is null -nullValue.SectorGeometryListIsNull=SectorGeometryList is null -nullValue.ServiceIsNull=Service is null -nullValue.SelectionListener=SelectionListener is null -nullValue.SetMethodIsNull=Attribute change listener is null -nullValue.SetMethodReferenceIsNull=Set method reference is null -nullValue.Shape=Shape is null -nullValue.StringIsNull=String is null -nullValue.TextureDataIsNull=TextureData is null -nullValue.TextureIsNull=Texture is null -nullValue.ThreadIsNull=Thread is null -nullValue.TileIsNull=Tile is null -nullValue.TileIterableIsNull=Tile iterable is null -nullValue.TileDeltaIsNull=Tile Delta is null -nullValue.TimeIsNull=Time is null -nullValue.TracksIsNull=Track list is null -nullValue.TracksPointsIteratorNull=Track points iterator is null -nullValue.URIIsNull=URI is null -nullValue.URLIsNull=URL is null -nullValue.VectorIsNull=Vector is null -nullValue.VertexBufferNull=Vertex buffer is null -nullValue.ViewIsNull=View is null -nullValue.visibleSectorNull=Visible sector is null -nullValue.ShellCommandIsNullOrEmpty=Shell command is null or empty - - -iterator.NoMoreTrackPoints=No more track points -iterator.RemoveNotSupported=Remove operation not supported - -AbstractView.FieldOfViewIsNull=Field-of-view is null -AbstractView.FrustumIsNull=Frustum is null -AbstractView.ModelViewIsNull=Model-view matrix is null -AbstractView.NoGlobeSpecifiedInDrawingContext=No globe specified in drawing context -AbstractView.ProjectionIsNull=Projection-matrix is null -AbstractView.ReferenceMatrixStackIsEmpty=Reference matrix stack is empty -AbstractView.DrawingContextGLIsNull=Drawing context GL instance is null -AbstractView.ViewportIsNull=Viewport is null -AbstractView.ViewportWidthLessThanOrEqualZero=Viewport width is less than or equal to zero - -AVAAccessibleImpl.AttributeValueForKeyIsNotAString=Attribute value for key is not a String. Key:\u0020 - -awt.AWTInputHandler.EventSourceNotAComponent=Event source is not an instance of java.awt.Component -awt.InterpolatorTimer.DelayLessThanZero=Initial delay or delay is less than zero -awt.InterpolatorTimer.PeriodLessThanZero=period is less than zero -awt.InterpolatorTimer.DifferentMixTypes=Begin and end are different types -awt.InterpolatorTimer.ErrorThresholdLessThanZero=Error threshold is less than zero -awt.InterpolatorTimer.StepCoefficientLessThanZero=Step coefficient is less than zero -awt.InterpolatorTimer.ViewPropertiesIsNull=ViewProperties is null -awt.KeyPollTimer.PeriodLessThanZero=Period is less than zero -awt.WorldWindowGLSurface.UnabletoCreateWindow=Unable to create WorldWindow - -BasicMemoryCache.nullListenerAdded=attemped to add null listener to BasicCache -BasicMemoryCache.nullListenerRemoved=attempted to remove null listener from BasicCache - -BasicOrbitView.NullSurfacePoint=Point on surface is null -BasicOrbitView.NoGlobeSpecified=No globe specified in AbstractView -BasicOrbitView.InvalidConstraints=Invalid constraint argument(s) - -BasicElevationModel.AttemptToSetGlobeTwice=Attemped to set globe. Globe may only be set once -BasicElevationModel.DensityBelowZero=Density is below zero -BasicElevationModel.ExceptionComputingElevation=Exception computing elevation at\u0020 - -BasicFrameController.ExceptionWhilePickingInLayer=Exception while picking in layer\u0020 -BasicFrameController.ExceptionWhileApplyingView=Exception while applying view -BasicFrameController.ExceptionWhileRenderingLayer=Exception while rendering layer\u0020 -BasicFrameController.ExceptionWhileTessellatingGlobe=Exception while tessellating globe - -BasicMemoryCache.CacheItemNotAdded=Cache item not added - -BasicModel.LayerNotFound=Layer not found:\u0020 - -BasicRetrievalService.ResourceRejected=Retrieval service rejected resource\u0020 -BasicRetrievalService.EnteringBeforeExecute=Entering beforeExecute" -BasicRetrievalService.CancellingDuplicateRetrieval=Cancelling duplicate retrieval of\u0020 -BasicRetrievalService.CancellingTooOldRetrieval=Cancelling request too long on the retrieval queue for\u0020 -BasicRetrievalService.LeavingBeforeExecute=Leaving beforeExecute -BasicRetrievalService.EnteringAfterExecute=Entering afterExecute -BasicRetrievalService.ExceptionDuringRetrieval=Exception during retrieval of\u0020 -BasicRetrievalService.ExecutionExceptionDuringRetrieval=Execution exception during retrieval of\u0020 -BasicRetrievalService.RetrievalOf_1=Retrieval of\u0020 -BasicRetrievalService.WasInterrupted_2=\u0020was interrupted -BasicRetrievalService.WasCancelled_2=\u0020was cancelled -BasicRetrievalService.LeavingAfterExecute=Leaving afterExecute -BasicRetrievalService.ExcptnRetrievingContentSizes=Exception retrieving content sizes from Retriever\u0020 -BasicRetrievalService.RetrieverPoolSizeIsLessThanOne=Retriever pool size is less than 1 -BasicRetrievalService.UncaughtExceptionDuringRetrieval=Uncaught exception during retrieval on thread\u0020 - -BasicSceneController.GLContextNullStartRedisplay=GLContext is null at start of repaint -BasicSceneController.GLContextNullStartPick=GLContext is null at start of pick -BasicSceneController.NoFrameControllerStartRepaint=No frame controller at start of repaint -BasicSceneController.NoFrameControllerStartPick=No frame controller at start of picking -BasicSceneController.ExceptionDuringRendering=Exception encountered while repainting -BasicSceneController.ExceptionDuringPick=Exception encountered while picking - -BasicView.NoModelExtentOnViewReset=No model extent on view reset - -Color.ValueTooHigh=Color value is too high, must be less than or equal to 1 -Color.ValueTooLow=Color value is too low, must be greater than or equal to 0 - -Configuration.ConversionError=Error parsing configuration value\u0020 -Configuration.UnavailablePropsFile=Unavailable properties file\u0020 -Configuration.ExceptionReadingPropsFile=Exception while reading properties file\u0020 - -DDSConverter.UnsupportedMimeType=Unsupported mime type\u0020 -DDSConverter.NoFileOrNoPermission=File does not exist or does not have read permission - -FileCache.ConfigurationNotFound=The specified cache configuration cannot be found:\u0020 -FileCache.CacheLocationInvalid=A configured cache location is invalid\u0020 -FileCache.CacheLocationIsFile=A configured cache location is a file but must be a directory\u0020 -FileCache.CannotRemoveWriteLocationFromSearchList=Cannot remove file-cache write location from the cache's search list -FileCache.ExceptionCreatingURLForFile=Exception creating URL for file\u0020 -FileCache.ExceptionRemovingFile=Exception removing \u0020 -FileCache.NoConfiguration=A cache configuration is specified. -FileCache.NoFileCacheReadLocations=No readable cache locations were found. -FileCache.NoFileCacheWriteLocation=No writable locations exist for the file cache. Continuing without caching. - -geom.Cylinder.RadiusIsZeroOrNegative=Radius is zero or negative -geom.Cylinder.AxisNormalVectorIsNullOrZero=Axis normal vector is null or zero -geom.Cylinder.CylinderHeightOrDepthIsNegative=Cylinder height or depth is negative -geom.Cylinder.CylinderHeightIsZero=Cylinder height is zero - -geom.Frustum.NearPlaneDistanceIsLessThanOrEqualToZero=Near plane distance is less than or equal to zero -geom.Frustum.FarPlaneDistanceIsLessThanOrEqualToZero=Far plane distance is less than or equal to zero -geom.Frustum.FarPlaneDistanceIsLessThanNearPlaneDistance=Far plane distance is less than near plane distance -geom.Line.DirectionIsZeroVector=Direction is zero vector -geom.Plane.VectorIsZero=Vector is zero -geom.Sphere.NoPointsSpecified=No points specified for sphere -geom.Sphere.RadiusIsZeroOrNegative=Radius is zero or negative -geom.Ellipsoid.SemiAxisZeroOrNegative=One or more semi-axes is zero or negative -geom.Matrix4.ArrayTooShort=Array is too short -geom.ViewFrusutm.ClippingDistanceOutOfRange=Clipping distance(s) are out of range, or opposing clip distances cross -geom.ViewFrustum.FieldOfViewIsNull=Field-of-view is null -geom.ViewFrustum.FieldOfViewOutOfRange=Field-of-view is less than 0, or greater than 180 - -GeoRSS.MissingValue=GeoRSS item is missing a value\u0020 -GeoRSS.ExceptionParsing=Exception while parsing GeoRSS content\u0020 -GeoRSS.InvalidCoordinateCount=GeoRSS shape coordinates are not approrpriate for the specified shape\u0020 -GeoRSS.IOExceptionParsing=IO exception while parsing GeoRSS content\u0020 -GeoRSS.MissingElement=GeoRSS item is missing required element\u0020 -GeoRSS.MissingElementContent=GeoRSS item is missing required element content for\u0020 -GeoRSS.NoCoordinates=GeoRSS shape contains no coordinate values for\u0020 -GeoRSS.NoShapes=No recognizable shapes in GeoRSS content\u0020 -GeoRSS.NumberFormatException=GeoRSS shape contains unrecognizable value\u0020 -GeoRSS.ParserConfigurationException=Exception while creating GeoRSS parser - -HTTPRetriever.ExceptionWhileQueryingResponseCode=Exception while querying response code for\u0020 -HTTPRetriever.ExceptionWhileQueryingResponseMessage=Exception while querying response message -HTTPRetriever.ResponseCode=Response code\u0020 -HTTPRetriever.ResponseContentLength=, content-length\u0020 -HTTPRetriever.Retrieving=\u0020retrieving\u0020 - -layers.AbstractLayer.NoGlobeSpecifiedInDrawingContext=No globe specified in drawing context -layers.AbstractLayer.NoViewSpecifiedInDrawingContext=No view specified in drawing context -layers.CompassLayer.Name=Compass -layers.IconLayer.Name=Nasa Icons -layers.InvalidPickColorRead=Invalid pick color read from frame buffer -layers.GraticuleLayer.Name=Graticule -layers.Earth.BlueMarbleLayer.Name=Blue Marble -layers.Earth.DOESantaBarbaraLayer.Name=Santa Barbara -layers.Earth.DOEWashingtonDCLayer.Name=Washington, D.C. -layers.Earth.GraticuleLayer.Name=Graticule -layers.Earth.PlaceName.Name=Place Names -layers.Earth.LandsatVisibleColorLayer.Name=Landsat Visible Color -layers.Earth.Landsat7VisibleColorLayer.Name=Landsat 7 Visible Color -layers.Earth.LandsatI3Layer.Name=i\u00b3 Landsat -layers.Earth.USGSDigitalOrtho.Name=USGS Digital Ortho -layers.Earth.USGSUrbanAreaOrtho.Name=USGS Urban Area Ortho -layers.Earth.PoliticalBoundaries.Name=Political Boundaries -layers.LevelSet.InvalidLevelSet=Invalid level set:\u0020 -layers.LevelSet.InvalidLevelDescriptorFields=Invalid level descriptor fields:\u0020 -layers.LevelSet.LevelsNotContiguous=levels are not contiguous -layers.LevelSet.LevelListIsEmpty=level list is empty -layers.MeridianAndParallelLinesLayer.OpacityOutOfRange=Opacity out of range -layers.PlaceNameLayer.ExceptionAttemptingToDownloadFile=Exception while attempting to download file -layers.PlaceNameLayer.ExceptionAttemptingToReadFile=Exception attempting to read file\u0020 -layers.PlaceNameLayer.ExceptionSavingRetrievedFile=Exception while saving retrieved file to\u0020 -layers.PlaceNameLayer.ExceptionRenderingTile=Exception while rendering place names tile -layers.PlaceNameLayer.Name=Place Names -layers.RenderableLayer.Name=Renderable -layers.RpfLayer.BadFrameInput=Bad frame-file input:\u0020 -layers.RpfLayer.DownloadInterrupted=Download interrupted for:\u0020 -layers.RpfLayer.ExceptionParsingFileName=Exception while parsing frame file-name:\u0020 -layers.ShapeLayer.Name=Shape -layers.TextureLayer.Name=Texture -layers.TextureLayer.ExceptionAttemptingToReadTextureFile=Exception attempting to read texture file -layers.TextureLayer.ExceptionCreatingTextureUrl=Exception creating texture URL for\u0020 -layers.TextureLayer.ExceptionSavingRetrievedTextureFile=Exception while saving retrieved texture file to\u0020 -layers.TextureLayer.MinPixelsPerTexelTooLow=Minimum pixels per texel must be at least zero -layers.TextureLayer.TargetPixelsPerTexelTooLow=Target pixels per texel must be at least zero -layers.TextureLayer.MaxPixelsPerTexelTooLow=Max pixels per texel must be at least zero -layers.TextureTile.MinDistanceToEyeNegative=Minimum distance to eye must be at least zero -layers.TrackLayer.IOExceptionDuringInitialization=IOException during track initialization -layers.TrackLayer.Name=Track - -NitfsReader.NoFileOrNoPermission=File does not exist or does not have read permission\u0020 -NitfsReader.UnknownOrUnsupportedNitfsFormat=Unknown or unsupported NITFS file format\u0020 - -PlaceNameService.MaxDisplayDistanceLessThanMinDisplayDistance=Max display distance is less than minimum display distance -PlaceNameService.MinDisplayDistanceGrtrThanMaxDisplayDistance=Min display distance is greater than max display distance -PlaceNameService.RowOrColumnOutOfRange=Row or column out of range - -RetrieveToFilePostProcessor.NullBufferPostprocessing=Null buffer postprocessing\u0020 -RetrieveToFilePostProcessor.ErrorPostprocessing=Error postprocessing - -RpfDataSeries.InavlidRpfDataType=Rpf data type is invalid:\u0020 -RpfDataSeries.InvalidScaleOrGSD=Scale or Ground Sample Distance is invalid:\u0020 - -RpfFrameFilenameUtil.BadFilenameLength=Illegal filename length:\u0020 -RpfFrameFilenameUtil.Base34Error=Illegal base34 encoding -RpfFrameFilenameUtil.EnumNotFound=Illegal data-series, zone, or producer code -RpfFrameFilenameUtil.IntegerNotParsed=Illegal frame-number or version number -RpfFrameFilenameUtil.UnknownRpfDataType=Unknown Rpf data-type constant:\u0020 - -RpfFrameProperties.BadFrameNumber=Frame-number is less than zero:\u0020 -RpfFrameProperties.BadVersion=Version is less than zero:\u0020 - -RpfZone.UnknownRpfDataType=Unknown Rpf data-type constant:\u0020 - -RpfTocCrawler.BadStart=Attempted to start running or stopped crawler -RpfTocCrawler.ExceptionParsingFilename=Exception while parsing filename:\u0020 - -tessellators.GnomicTessellation.Geometry.illegalParamT=Parameter "double t" is either larger than 1 or less than 0 -tessellators.GnomicTessellation.Geometry.illegalParamS=Parameter "double s" is either larger than 1 or less than 0 - -ThreadedTaskService.CancellingDuplicateTask=Cancelling duplicate task of\u0020 -ThreadedTaskService.EnteringAfterExecute=Entering afterExecute -ThreadedTaskService.EnteringBeforeExecute=Entering beforeExecute" -ThreadedTaskService.LeavingBeforeExecute=Leaving beforeExecute -ThreadedTaskService.UncaughtExceptionDuringTask=Uncaught exception during task on thread\u0020 -ThreadedTaskService.ResourceRejected=Task service rejected resource\u0020 - -TiledElevationModel.ExceptionAttemptingToReadTextureFile=Exception attempting to read elevation file\u0020 -TiledElevationModel.ExceptionCreatingElevationsUrl=Exception creating elevations URL for\u0020 -TiledElevationModel.ExceptionSavingRetrievedElevationFile=Exception while saving retrieved elevation file to\u0020 - -TileKey.levelIsLessThanZero=Level is less than zero -TileKey.cacheNameIsNullOrEmpty=cache name is null or empty - -URLRetriever.ConnectTimeoutLessThanZero=Connect timeout is less than 0 -URLRetriever.ContentLengthIsGrtrThanMaxSizeFor=Content length is greater than maximum size for\u0020 -URLRetriever.ContentLengthIsLessThanMinSizeFor=Content length is less than minimum size for\u0020 -URLRetriever.ErrorAttemptingToRetrieve=Error attempting to retrieve\u0020 -URLRetriever.ErrorOpeningConnection=Error opening connection to\u0020 -URLRetriever.ErrorPostProcessing=Error postprocessing\u0020 -URLRetriever.ErrorReadingFromConnection=Error reading from connection to\u0020 -URLRetriever.ExceptionClosingInputStreamToConnection=Exception closing InputStream to connection\u0020 -URLRetriever.InputStreamFromConnectionNull=InputStream is null from connection to\u0020 -URLRetriever.InputStreamNullFor=InputStream is null for\u0020 -URLRetriever.NoZipEntryFor=No zip entry for\u0020 -URLRetriever.NullReturnedFromOpenConnection=Null returned from openConnection for\u0020 -URLRetriever.RetrievalInterruptedFor=Retrieval interrupted for\u0020 -URLRetriever.ZIPFileSizeLessThanMinSize=ZIP file size is less than minimum size for\u0020 -URLRetriever.ZIPFileSizeGrtrThanMaxSize=ZIP file size is greater than maximum size for\u0020 - -#WorldWind.ClassNameKeyNulZero=Class name key is null or zero length -#WorldWind.ExceptionCreatingComponent=Exception while creating World Wind component\u0020 -#WorldWind.ErrorCreatingComponent=Error while creating World Wind component\u0020 -#WorldWind.NoClassNameInConfigurationForKey=No class name in configuration for key\u0020 -#WorldWind.UnableToCreateClassForConfigurationKey=Unable to create class for configuration key\u0020 - -WorldWindowGLCanvas.DisplayEventListenersDisplayChangedMethodCalled=Display event listener's displayChanged() method called -WorldWindowGLCanvas.ExceptionAttemptingRepaintWorldWindow=Exception while attempting to repaint WorldWindow -WorldWindowGLCanvas.GLAutoDrawableNullToConstructor=GLAutoDrawable is null to WorldWindowGLCanvas constructor -WorldWindowGLCanvas.ScnCntrllerNullOnRepaint=Scene controller is null at repaint - -WorldWindowGLAutoDrawable.ExceptionDuringGLEventListenerDisplay=Exception during call to GL event display listener -WorldWindowGLAutoDrawable.ExceptionDuringGLEventListenerInit=Exception during call to GL event init listener -WorldWindowGLAutoDrawable.ExceptionDuringGLEventListenerReshape=Exception during call to GL event reshape listener -WorldWindowGLAutoDrawable.ExceptionDuringGLEventListenerDisplayChanged=Exception during call to GL event display-changed listener - -WWIO.ErrorSavingBufferTo=Error saving buffer to\u0020 -WWIO.ErrorTryingToClose=Error trying to close\u0020 -WWIO.ExceptionValidatingFileExpiration=Exception attempting to check file expiration for\u0020 -WWIO.NumberBytesTransferLessThanOne=Number of bytes to transfer is less than 1 -WWIO.UnableToAcquireLockFor=Unable to acquire lock for\u0020 -WWIO.ZipFileIsEmpty=ZIP file is empty\u0020 -WWIO.ZipFileEntryNIF=ZIP file entry not in file\u0020 - diff --git a/ErrorStrings_de_DE.properties b/ErrorStrings_de_DE.properties deleted file mode 100644 index aca2c1c..0000000 --- a/ErrorStrings_de_DE.properties +++ /dev/null @@ -1,6 +0,0 @@ -awt.WorldWindowGLSurface.UnabletoCreateWindow=Unf\u00e4hig, WorldWindow zu schaffen - - -nullValue.AngleIsNull=Winkel ist ung\u00fcltig - -nullValue.BoundingBoxIsNull=Ein oder mehr begrenzende Kasten-Punkte sind ung\u00fcltig diff --git a/ErrorStrings_ja.properties b/ErrorStrings_ja.properties deleted file mode 100644 index 7b932a6..0000000 --- a/ErrorStrings_ja.properties +++ /dev/null @@ -1,2 +0,0 @@ - -nullValue.AngleIsNull=\u89d2\u5ea6\u306f\u30d6\u30e9\u30f3\u30af\u3067\u3042\u308b diff --git a/ErrorStrings_zh_CN.properties b/ErrorStrings_zh_CN.properties deleted file mode 100644 index 734d39b..0000000 --- a/ErrorStrings_zh_CN.properties +++ /dev/null @@ -1,8 +0,0 @@ -awt.WorldWindowGLSurface.UnabletoCreateWindow=\u65e0\u6cd5\u521b\u9020\u4e16\u754c\u7a97\u53e3 - - -nullValue.AngleIsNull=\u89d2\u5ea6\u662f\u7a7a\u7684 - - - - diff --git a/ThreadStrings.properties b/ThreadStrings.properties deleted file mode 100644 index 513687a..0000000 --- a/ThreadStrings.properties +++ /dev/null @@ -1,6 +0,0 @@ -BasicRetrievalService.RUNNING_THREAD_NAME_PREFIX=Running World Wind Retriever:\u0020 -BasicRetrievalService.IDLE_THREAD_NAME_PREFIX=Idle World Wind Retriever -BasicRetrievalService.WorldWindRetrievalProgress=World Wind Retrieval Progress\u0020 - -ThreadedTaskService.RUNNING_THREAD_NAME_PREFIX=Running World Wind Task:\u0020 -ThreadedTaskService.IDLE_THREAD_NAME_PREFIX=Idle World Wind Task diff --git a/applet/WWJApplet.java b/applet/WWJApplet.java new file mode 100644 index 0000000..369dd6a --- /dev/null +++ b/applet/WWJApplet.java @@ -0,0 +1,244 @@ +package applet; +/* +Copyright (C) 2001, 2006, 2007 United States Government +as represented by the Administrator of the +National Aeronautics and Space Administration. +All Rights Reserved. +*/ + +import gov.nasa.worldwind.*; +import gov.nasa.worldwind.avlist.AVKey; +import gov.nasa.worldwind.awt.WorldWindowGLCanvas; +import gov.nasa.worldwind.event.*; +import gov.nasa.worldwind.examples.StatusBar; +import gov.nasa.worldwind.geom.*; +import gov.nasa.worldwind.globes.Globe; +import gov.nasa.worldwind.layers.Earth.*; +import gov.nasa.worldwind.layers.*; +import gov.nasa.worldwind.view.*; +import netscape.javascript.JSObject; + +import javax.swing.*; +import java.awt.*; + +/** + * Provides a base application framework for simple WorldWind applets. + * + * A simple applet which runs World Wind with a StatusBar at the bottom + * and lets javascript set some view attributes. + * + * @author Patrick Murris + * @version $Id: + */ + +public class WWJApplet extends JApplet +{ + private WorldWindowGLCanvas wwd; + private StatusBar statusBar; + + public WWJApplet() + { + } + + public void init() + { + try + { + // Create World Window GL Canvas + this.wwd = new WorldWindowGLCanvas(); + this.getContentPane().add(this.wwd, BorderLayout.CENTER); + + // Create the default model as described in the current worldwind properties. + Model m = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME); + this.wwd.setModel(m); + + // Add a fog layer to the model layer list, before the Blue Marble + insertBeforeLayerName(this.wwd, new FogLayer(), "Blue Marble"); + + // Add a BMNG base layer to the model layer list, before the Blue Marble + insertBeforeLayerName(this.wwd, new BMNGOneImage(), "Blue Marble"); + + // Add the status bar + this.statusBar = new StatusBar(); + this.getContentPane().add(statusBar, BorderLayout.PAGE_END); + + // Forward events to the status bar to provide the cursor position info. + this.statusBar.setEventSource(this.wwd); + + // Setup a select listener for the worldmap click-and-go feature + this.wwd.addSelectListener(new SelectListener() + { + public void selected(SelectEvent event) + { + if (event.getEventAction().equals(SelectEvent.LEFT_CLICK)) + { + if (event.hasObjects()) + { + if (event.getTopObject() instanceof WorldMapLayer) + { + // Left click on World Map : iterate view to target position + Position targetPos = event.getTopPickedObject().getPosition(); + OrbitView view = (OrbitView)WWJApplet.this.wwd.getView(); + Globe globe = WWJApplet.this.wwd.getModel().getGlobe(); + // Use a PanToIterator + view.applyStateIterator(FlyToOrbitViewStateIterator.createPanToIterator( + view, globe, new LatLon(targetPos.getLatitude(), targetPos.getLongitude()), + Angle.ZERO, Angle.ZERO, targetPos.getElevation())); + } + } + } + } + }); + + // Call javascript appletInit() + try + { + JSObject win = JSObject.getWindow(this); + win.call("appletInit", null); + } + catch(Exception e) {} + } + catch (Throwable e) + { + e.printStackTrace(); + } + } + + public void start() + { + // Call javascript appletStart() + try + { + JSObject win = JSObject.getWindow(this); + win.call("appletStart", null); + } + catch(Exception e) {} + } + + public void stop() + { + // Call javascript appletSop() + try + { + JSObject win = JSObject.getWindow(this); + win.call("appletStop", null); + } + catch(Exception e) {} + + // Shut down World Wind + WorldWind.shutDown(); + } + + /** + * Adds a layer to WW current layerlist, before a named layer + * Target name can be a part of the layer name + * @param wwd + * @param layer + * @param targetName + */ + public static void insertBeforeLayerName(WorldWindow wwd, Layer layer, String targetName) + { + // Insert the layer into the layer list just before the target layer. + int targetPosition = 0; + LayerList layers = wwd.getModel().getLayers(); + for (Layer l : layers) + { + if (l.getName().indexOf(targetName) != -1) + { + targetPosition = layers.indexOf(l); + break; + } + } + layers.add(targetPosition, layer); + } + + // ============== Public API - Javascript ======================= // + + /** + * Move the current view position + * @param lat the target latitude in decimal degrees + * @param lon the target longitude in decimal degrees + */ + public void gotoLatLon(double lat, double lon) + { + this.gotoLatLon(lat, lon, Double.NaN, 0, 0); + } + + /** + * Move the current view position, zoom, heading and pitch + * @param lat the target latitude in decimal degrees + * @param lon the target longitude in decimal degrees + * @param zoom the target eye distance in meters + * @param heading the target heading in decimal degrees + * @param pitch the target pitch in decimal degrees + */ + public void gotoLatLon(double lat, double lon, double zoom, double heading, double pitch) + { + OrbitView view = (OrbitView)this.wwd.getView(); + Globe globe = this.wwd.getModel().getGlobe(); + //view.setLatLon(new LatLon(Angle.fromDegrees(lat), Angle.fromDegrees(lon))); + //view.firePropertyChange(AVKey.VIEW, null, view); + if(!Double.isNaN(lat) || !Double.isNaN(lon) || !Double.isNaN(zoom)) + { + lat = Double.isNaN(lat) ? view.getLookAtLatitude().degrees : lat; + lon = Double.isNaN(lon) ? view.getLookAtLongitude().degrees : lon; + zoom = Double.isNaN(zoom) ? view.getZoom() : zoom; + heading = Double.isNaN(heading) ? view.getHeading().degrees : heading; + pitch = Double.isNaN(pitch) ? view.getPitch().degrees : pitch; + view.applyStateIterator(FlyToOrbitViewStateIterator.createPanToIterator( + view, globe, LatLon.fromDegrees(lat, lon), Angle.fromDegrees(heading), Angle.fromDegrees(pitch), zoom)); + } + } + + /** + * Set the current view heading and pitch + * @param heading the traget heading in decimal degrees + * @param pitch the target pitch in decimal degrees + */ + public void setHeadingAndPitch(double heading, double pitch) + { + OrbitView view = (OrbitView)this.wwd.getView(); + if(!Double.isNaN(heading) || !Double.isNaN(pitch)) + { + heading = Double.isNaN(heading) ? view.getHeading().degrees : heading; + pitch = Double.isNaN(pitch) ? view.getPitch().degrees : pitch; + + view.applyStateIterator(ScheduledOrbitViewStateIterator.createHeadingAndPitchIterator( + view, Angle.fromDegrees(heading), Angle.fromDegrees(pitch))); + } + } + + /** + * Set the current view zoom + * @param zoom the target eye distance in meters + */ + public void setZoom(double zoom) + { + OrbitView view = (OrbitView)this.wwd.getView(); + if(!Double.isNaN(zoom)) + { + view.applyStateIterator(ScheduledOrbitViewStateIterator.createZoomIterator( + view, zoom)); + } + } + + /** + * Get the WorldWindowGLCanvas + * @return the current WorldWindowGLCanvas + */ + public WorldWindowGLCanvas getWW() + { + return this.wwd; + } + + /** + * Get the current OrbitView + * @return the current OrbitView + */ + public OrbitView getOrbitView() + { + return (OrbitView)this.wwd.getView(); + } + +} + diff --git a/applet/WWJAppletMinimal.java b/applet/WWJAppletMinimal.java new file mode 100644 index 0000000..33f9497 --- /dev/null +++ b/applet/WWJAppletMinimal.java @@ -0,0 +1,89 @@ +package applet; + +import gov.nasa.worldwind.*; +import gov.nasa.worldwind.avlist.AVKey; +import gov.nasa.worldwind.awt.WorldWindowGLCanvas; +import gov.nasa.worldwind.examples.StatusBar; +import gov.nasa.worldwind.layers.*; +import gov.nasa.worldwind.layers.Earth.BMNGOneImage; + +import javax.swing.*; +import java.awt.*; + +/** + * Provides a base application framework for simple WorldWind applets. + * + * A simple applet which runs World Wind with a StatusBar at the bottom + * + * @author Patrick Murris + * @version $Id: + */ + +public class WWJAppletMinimal extends JApplet { + + private WorldWindowGLCanvas wwd; + private StatusBar statusBar; + + public WWJAppletMinimal() + { + } + + public void init() + { + try + { + // Create World Window GL Canvas + this.wwd = new WorldWindowGLCanvas(); + this.getContentPane().add(this.wwd, BorderLayout.CENTER); + + // Create the default model as described in the current worldwind properties. + Model m = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME); + this.wwd.setModel(m); + + // Add a BMNG base layer to the model layer list, before the Blue Marble + insertBeforeLayerName(this.wwd, new BMNGOneImage(), "Blue Marble"); + + // Add the status bar + this.statusBar = new StatusBar(); + this.getContentPane().add(this.statusBar, BorderLayout.PAGE_END); + + // Forward events to the status bar to provide the cursor position info. + this.statusBar.setEventSource(this.wwd); + + } + catch (Throwable e) + { + e.printStackTrace(); + } + } + + public void stop() + { + // Shut down World Wind + WorldWind.shutDown(); + } + + /** + * Adds a layer to WW current layerlist, before a named layer + * Target name can be a part of the layer name + * @param wwd + * @param layer + * @param targetName + */ + public static void insertBeforeLayerName(WorldWindow wwd, Layer layer, String targetName) + { + // Insert the layer into the layer list just before the target layer. + int targetPosition = 0; + LayerList layers = wwd.getModel().getLayers(); + for (Layer l : layers) + { + if (l.getName().indexOf(targetName) != -1) + { + targetPosition = layers.indexOf(l); + break; + } + } + layers.add(targetPosition, layer); + } + +} diff --git a/applet/WWJAppletsNotes.html b/applet/WWJAppletsNotes.html new file mode 100644 index 0000000..8b77ffe --- /dev/null +++ b/applet/WWJAppletsNotes.html @@ -0,0 +1,456 @@ + + +NASA World Wind Java Applet Notes + + + + + + + +

NASA World Wind Java Applets

+Last modified september 14, 2007 + +

Introduction

+This document is intended to help developers through the process of assembling and deploying a World Wind Java applet using Sun's JNLPAppletLauncher. +

+

+ + +

Requirements

+ +

+As for the whole World Wind Java project, please check the following points : +

+ +

+JOGL applet setup can be tested with this sample Gears 3D JOGL animation applet:
+https://jogl-demos.dev.java.net/applettest.html +

+ + +

Compiling and running a WWJ applet

+ +

+All you need to deploy a WWJ applet is a web page with the proper html declarations, the WWJ SDK archive worldwind.jar, and possibly your special implementation of one of the applet templates in its own archive, eg. myapplet.jar. +

+
+    myapplet.html          Web page that loads the applet
+    myapplet.jar           Optional applet class in its own archive
+    worldwind.jar          World Wind Java SDK, including applet templates
+
+

+With the JNLPAppletLauncher, all other needed components can be fetched from external servers : the launcher itself applet-laucher.jar, and the JOGL librairies jogl.jar and gluegen-rt.jar. The appropriate binaries will be downloaded and cached according to the client platform by the launcher. +

+

+To compile and deploy a WW applet, follow the steps below : +

+
    +
  1. Use one of the world wind applet templates from the SDK (see code sample below).
  2. +
  3. Compile and export worldwind.jar and, if needed, a separate jar for the applet.
  4. +
  5. Sign all jars (see Signing below).
  6. +
  7. Copy the jar(s) to your deployement folder.
  8. +
  9. Run with a web page using the JNLPAppletLauncher (see below)
  10. +
+

+Important note for Mac : as of september 2007, the Java plugin for mac is still in version 5 - whereas other plateforms can run java 6. If you want to cover all plateforms you need to compile for java 5. +

+

If your applet uses a custom World Wind configuration file, within a static block of your applet and before + calling any World Wind method or constructor set the gov.nasa.worldwind.config.file + Java property to the path of your configuration file (see code sample below). + The path must be relative to the applet's classpath, + and the configuration file must be included in the applet's signed jar file. World Wind opens the file via +java.lang.Class.getResourceAsStream().

+ +

Known issues

+ +

First use :

+ + +

After navigating to other pages and coming back

+

+PRESUMABLY FIXED - 2007-07-27 : Applet is 'shut down' whenever the user navigates to another page. When coming back, it is restarted like a new one. +

+ + + +

Code samples

+ + +

WWJ Applet minimal class template

+ +
+import gov.nasa.worldwind.examples.StatusBar;
+import gov.nasa.worldwind.*;
+import gov.nasa.worldwind.geom.*;
+import gov.nasa.worldwind.layers.*;
+import gov.nasa.worldwind.awt.*;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class WWJApplet extends JApplet
+{
+    private WorldWindowGLCanvas wwd;
+    private StatusBar statusBar;
+
+    public WWJApplet()
+    {
+    }
+
+    public void init()
+    {
+        try
+        {
+            // Create World Window GL Canvas
+            this.wwd = new WorldWindowGLCanvas();
+            this.getContentPane().add(this.wwd, BorderLayout.CENTER);
+
+            // Create the default model as described in the current worldwind properties.
+            Model m = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME);
+            this.wwd.setModel(m);
+
+            // Add the status bar
+            this.statusBar = new StatusBar();
+            this.getContentPane().add(statusBar, BorderLayout.PAGE_END);
+
+            // Forward events to the status bar to provide the cursor position info.
+            this.statusBar.setEventSource(this.wwd);
+
+        }
+        catch (Throwable e)
+        {
+            e.printStackTrace();
+        }
+    }
+    
+    public void stop()
+    {
+        // Shutdown World Wind
+        WorldWind.shutDown();
+    }
+}
+
+
+ + +

If the applet uses a custom World Wind configuration file, the following would be added to the + WWJApplet class above:

+
+ static + { + System.setProperty("gov.nasa.worldwind.config.file", "config/myWorldWindConfiguration.properties"); + } +
+
+

This property must be set prior to any other World Wind method invocation or object construction. +In this example, the properties file would be contained at the above path within the applet's jar file.

+ +

Preloading a blue marble base image from the 'images' SDK folder

+

+When a wwj applet is started the first time with an empty cache, the globe will not show until the level zero tiles of blue marble are downloaded. +

+

+To avoid this delay - and big void, add in the layer list, before 'blue marble' a full sphere SurfaceImage of a lower resolution whole earth blue marble image, that is embedded in the worldwind jar - and thus preloaded with the applet. +

+

+In the applet init() +

+
+            // Add a BMNG base layer to the model layer list, before the Blue Marble
+            insertBeforeLayerName(this.wwd, new BMNGOneImage(), "Blue Marble");
+
+

+Additional methods +

+
+    public static void insertBeforeLayerName(WorldWindow wwd, Layer layer, String targetName)
+    {
+        // Insert the layer into the layer list just before the target layer.
+        int targetPosition = 0;
+        LayerList layers = wwd.getModel().getLayers();
+        for (Layer l : layers)
+        {
+            if (l.getName().indexOf(targetName) != -1)
+            {
+                targetPosition = layers.indexOf(l);
+                break;
+            }
+        }
+        layers.add(targetPosition, layer);
+    }
+
+ + +

Using JNLPAppletLauncher

+ +

+Here is the htlm code to use in a web page to run the sample WWJApplet from the SDK applet package. Note that all achives are referenced with absolute urls to Sun's servers except the worldwind.jar that is located on another server - probably with this web page, but it could be anywhere. +

+

+"Note that this example does not specify a codebase, instead specifying all of its archive tag elements with absolute URLs (split here for readability; in a real applet tag they must be all on one line). Note also the use of the noddraw.check parameter to disable the use of DirectDraw since using JOGL implies the use of OpenGL." +

+ +
+ <applet code="org.jdesktop.applet.util.JNLPAppletLauncher"
+      width=600
+      height=400
+      archive="http://download.java.net/media/applet-launcher/applet-launcher.jar,
+               http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar,
+               http://download.java.net/media/gluegen/webstart/gluegen-rt.jar,
+               http://my.web.server.com/WWJApplet/worldwind.jar">
+   <param name="codebase_lookup" value="false">
+   <param name="subapplet.classname" value="applet.WWJApplet">
+   <param name="subapplet.displayname" value="World Wind Applet">
+   <param name="noddraw.check" value="true">
+   <param name="progressbar" value="true">
+   <param name="jnlpNumExtensions" value="1">
+   <param name="jnlpExtension1"
+          value="http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp">
+ </applet>
+
+
+

+If the applet code is in a separate archive, just add a reference to it in the archive attribute of the applet tag - like after worldind.jar, and specify the proper path in the subapplet.classname parameter: +

+
+ <applet code="org.jdesktop.applet.util.JNLPAppletLauncher"
+      width=600
+      height=400
+      archive="http://download.java.net/media/applet-launcher/applet-launcher.jar,
+               http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar,
+               http://download.java.net/media/gluegen/webstart/gluegen-rt.jar,
+               http://my.web.server.com/WWJApplet/worldwind.jar,
+               http://my.web.server.com/WWJApplet/myapplet.jar">
+   <param name="codebase_lookup" value="false">
+   <param name="subapplet.classname" value="domain.your.path.myApplet">
+...
+ </applet>
+
+
+ +

+Ref : https://applet-launcher.dev.java.net/ +

+ + + + +

Applet vs object tag

+ +

+Note : the applet tag is considered deprecated in favor of the object tag : +

+
+DEPRECATED EXAMPLE:
+The following sample Java applet:
+
+<APPLET code="AudioItem" width="15" height="15">
+   <PARAM name="snd" value="Hello.au|Welcome.au">
+   Java applet that plays a welcoming sound.
+</APPLET>
+
+may be rewritten as follows with OBJECT:
+
+<OBJECT codetype="application/java"
+        classid="AudioItem" 
+        width="15" height="15">
+   <PARAM name="snd" value="Hello.au|Welcome.au">
+   Java applet that plays a welcoming sound.
+</OBJECT>
+
+

+Ref: HTML 4.01 Specifications, December 1999 : Applet
+http://www.w3.org/TR/1999/REC-html401-19991224/struct/objects.html#h-13.4 +

+ +

Communication between the web page and the applet

+ +

Passing parameters to the applet

+ +

+Initial values can be passed to the applet using the param tag of the applet or oject tags: +

+
+  <param name="paramName" value="some value">
+
+

+From the applet class a parameter value can be retreived with the getParameter() method: +

+
+  String paramValue = getParameter("paramName");
+
+ + + +

Javascript to the applet

+ +

+To allow javascript to 'talk' to the applet, first add an id attribute to the applet tag : +

+

+    <applet
+         id="wwjApplet"
+         code="org.jdesktop.applet.util.JNLPAppletLauncher"
+         width=600
+         height=400
+    ... >
+
+

+To call an applet java method from javascript : +

+
+  // Call someAppletMethod() via the launcher getSubApplet() method
+    
+  document.getElementById('wwjApplet').getSubApplet().someAppletMethod();
+
+

+Note the use of the launcher getSubApplet() method to get at the applet itself - javascript is really calling the launcher. +

+

+Important note for Mac : for javascript to be able to 'talk' to the applet, the applet-launcher.jar must be hosted on the same server as the applet. This means that if you need to have javascript/applet interaction across plateforms, you need to host a copy of applet-launcher.jar - and keep it up to date. +

+

+Ref: Java Plugin Guide : JavaScript to Java Communication (Scripting)
+http://java.sun.com/j2se/1.5.0/docs/guide/plugin/developer_guide/js_java.html +

+ + +

Applet to javascript and the document object

+ +To allow the applet to access javascript or the document object, add the mayscript attribute to the applet tag : +

+
+    <applet
+         mayscript
+         code="org.jdesktop.applet.util.JNLPAppletLauncher"
+         width=600
+         height=400
+    ... >
+
+
+

+To perform a call to javascript from the applet class use JSObject.getWindow(): +

+
+  import netscape.javascript.*;
+  ...
+
+  JSObject win = JSObject.getWindow(this);
+  win.call("functionName", null);  // calls javascript functionName()
+
+  or
+
+  win.eval("alert('An alert message')"); // evaluates and executes some javascript code as a string
+
+

+Ref: Java Plugin Guide : Java-to-Javascript Communication
+http://java.sun.com/j2se/1.5.0/docs/guide/plugin/developer_guide/java_js.html +

+ + + + +

Signing archive files

+ +

+To sign your archive files, you need to use keytool and jarsigner from your JDK bin folder. +

+

+Assuming the path to keytool and jarsigner is in the PATH environment variable. +

+

+Create a certificate (once): +

+
+.../WWJ Applet>keytool -genkey -keyalg rsa -alias yourname
+
+Enter pw : ******
+
+.../WWJ Applet>keytool -export -alias yourname -file yourname.crt
+
+ +

+Signing a jar : +

+
+.../WWJ Applet>jarsigner worldwind.jar yourname
+
+Enter pw : ******
+
+ +

+Note : this example creates the certificate in the same folder as the applet. This is not necessary. +

+

+Ref: How to Sign Applets Using RSA-Signed Certificates
+
http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/rsa_signing.html +

+ + + +

Security Policy

+ +

+This code bit may be usefull in some situations. +

+
+        Policy.setPolicy(new Policy() {
+            public void refresh() {
+            }
+
+            public PermissionCollection getPermissions(CodeSource arg0) {
+                Permissions perms = new Permissions();
+                perms.add(new AllPermission());
+                return (perms);
+            }
+        });   
+
+ + + +

WWJ Applet examples

+ +

+IGE, France
+http://www.ige.fr/3d/WW/WWJ.php +

+

+Pred, France
+http://atpred.free.fr/applet.html +

+

+GIS Solution, Italy
+http://www.gis-solution.com/WWApplet/WWApplet.htm +

+ +

Document history

+

+July 2007 - Patrick Murris
+First version +

+ + + + + diff --git a/applet/index_applet.html b/applet/index_applet.html new file mode 100644 index 0000000..b4df588 --- /dev/null +++ b/applet/index_applet.html @@ -0,0 +1,46 @@ + + +NASA World Wind Java Applet Test Page - Simple javascript controls + + + + + + + + + + + + + +
+ +Location: + + + +
+ +Distance: + + + + + +
+ +Looking: + + + + + +
+ +
+ + + + diff --git a/applet/index_applet_cookie.html b/applet/index_applet_cookie.html new file mode 100644 index 0000000..9303fdc --- /dev/null +++ b/applet/index_applet_cookie.html @@ -0,0 +1,184 @@ + + +NASA World Wind Java Applet Test Page - Javascript saved locations with a cookie + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + +
+
+
+
+ +
+
+ + +
+Distance:
+ +
+
+
+
+
+
+ +Looking:
+
+
+
+
+
+
+ +
+ + + + diff --git a/applet/index_applet_fullscreen.html b/applet/index_applet_fullscreen.html new file mode 100644 index 0000000..6b7d59d --- /dev/null +++ b/applet/index_applet_fullscreen.html @@ -0,0 +1,21 @@ + + +NASA World Wind Java Applet Test Page - Full page + + + + + + + + + + + + + + + + + diff --git a/config/worldwind.properties b/config/worldwind.properties index 7ecd262..b63a949 100644 --- a/config/worldwind.properties +++ b/config/worldwind.properties @@ -1,10 +1,12 @@ # Default World Wind Configuration Properties -# @version $Id: worldwind.properties 2455 2007-07-28 00:32:43Z tgaskins $ +# @version $Id: worldwind.properties 2915 2007-09-19 06:01:49Z tgaskins $ # Specify configuration values here to override World Wind's default values. # Lines starting with # are comments and ignored by World Wind. # gov.nasa.worldwind.avkey.DataFileCacheClassName=gov.nasa.worldwind.cache.BasicDataFileCache gov.nasa.worldwind.avkey.DataFileCacheConfigurationFileName=config/DataFileCache.xml +gov.nasa.worldwind.avkey.ExtremeElevations.SRTM30Plus.FileName=config/SRTM30Plus_ExtremeElevations_2.bil +gov.nasa.worldwind.avkey.BMNGOneImagePath=images/BMNG_world.topo.bathy.200405.3.2048x1024.jpg gov.nasa.worldwind.avkey.GlobeClassName=gov.nasa.worldwind.globes.Earth gov.nasa.worldwind.avkey.WorldWindowClassName=gov.nasa.worldwind.WorldWindowGLAutoDrawable gov.nasa.worldwind.avkey.InputHandlerClassName=gov.nasa.worldwind.awt.AWTInputHandler @@ -32,7 +34,7 @@ gov.nasa.worldwind.avkey.RetrievalStaleRequestLimit=9000 gov.nasa.worldwind.avkey.TaskPoolSize=4 gov.nasa.worldwind.avkey.TaskQueueSize=5 gov.nasa.worldwind.avkey.VerticalExaggeration=1 -gov.nasa.worldwind.avkey.TextureCacheSize=50000000 +gov.nasa.worldwind.avkey.TextureCacheSize=80000000 gov.nasa.worldwind.avkey.URLConnectTimeout=8000 gov.nasa.worldwind.avkey.URLReadTimeout=5000 gov.nasa.worldwind.avkey.ElevationTileCacheSize=5000000 diff --git a/gov/nasa/worldwind/AVKey.java b/gov/nasa/worldwind/AVKey.java deleted file mode 100644 index 32d3800..0000000 --- a/gov/nasa/worldwind/AVKey.java +++ /dev/null @@ -1,105 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: AVKey.java 2075 2007-06-17 20:20:22Z garakl $ - */ -public interface AVKey // TODO: Eliminate unused constants, if any -{ - final String CACHE_NAME = "gov.nasa.worldwind.avkey.CacheNameKey"; - final String CACHE_SIZE = "gov.nasa.worldwind.avkey.CacheSize"; - final String CACHE_LOW_WATER = "gov.nasa.worldwind.avkey.CacheLowWater"; - - final String ELEVATION_MODEL = "gov.nasa.worldwind.avkey.ElevationModel"; - final String EXTENT = "gov.nasa.worldwind.avkey.Extent"; - - final String DATA_FILE_CACHE_CLASS_NAME = "gov.nasa.worldwind.avkey.DataFileCacheClassName"; - final String DATA_FILE_CACHE_CONFIGURATION_FILE_NAME = - "gov.nasa.worldwind.avkey.DataFileCacheConfigurationFileName"; - final String DATASET_NAME = "gov.nasa.worldwind.avkey.DatasetNameKey"; - - final String DISPLAY_NAME = "gov.nasa.worldwind.avkey.DisplayName"; - final String DISPLAY_ICON = "gov.nasa.worldwind.avkey.DisplayIcon"; - - final String EXPIRY_TIME = "gov.nasa.worldwind.avkey.ExpiryTime"; - - final String FORMAT_SUFFIX = "gov.nasa.worldwind.avkey.FormatSuffixKey"; - final String FOV = "gov.nasa.worldwind.avkey.FieldOfView"; - - final String FRAME_CONTROLLER = "gov.nasa.worldwind.avkey.FrameControllerObject"; - final String FRAME_CONTROLLER_CLASS_NAME = "gov.nasa.worldwind.avkey.FrameControllerClassName"; - - final String FRAME_RATE = "gov.nasa.worldwind.avkey.FrameRate"; - final String FRAME_TIME = "gov.nasa.worldwind.avkey.FrameTime"; - - final String GLOBE = "gov.nasa.worldwind.avkey.GlobeObject"; - final String GLOBE_CLASS_NAME = "gov.nasa.worldwind.avkey.GlobeClassName"; - - final String IMAGE_FORMAT = "gov.nasa.worldwind.avkey.ImageFormat"; - final String INITIAL_LATITUDE = "gov.nasa.worldwind.avkey.InitialLatitude"; - final String INITIAL_LONGITUDE = "gov.nasa.worldwind.avkey.InitialLongitude"; - final String INPUT_HANDLER_CLASS_NAME = "gov.nasa.worldwind.avkey.InputHandlerClassName"; - - final String LAYER = "gov.nasa.worldwind.avkey.LayerObject"; - final String LAYER_NAMES = "gov.nasa.worldwind.avkey.LayerNames"; - final String LAYERS = "gov.nasa.worldwind.avkey.LayersObject"; - final String LAYERS_CLASS_NAMES = "gov.nasa.worldwind.avkey.LayerClassNames"; - final String LEVEL_NAME = "gov.nasa.worldwind.avkey.LevelNameKey"; - final String LEVEL_NUMBER = "gov.nasa.worldwind.avkey.LevelNumberKey"; - final String LEVEL_ZERO_TILE_DELTA = "gov.nasa.worldwind.avkey.LevelZeroTileDelta"; - final String LOGGER_NAME = "gov.nasa.worldwind.avkey.LoggerName"; - - final String MAX_ABSENT_TILE_ATTEMPTS = "gov.nasa.worldwind.avkey.MaxAbsentTileAttempts"; - final String MIN_ABSENT_TILE_CHECK_INTERVAL = "gov.nasa.worldwind.avkey.MinAbsentTileCheckInterval"; - - final String MEMORY_CACHE_CLASS_NAME = "gov.nasa.worldwind.avkey.MemoryCacheClassName"; - - final String MODEL = "gov.nasa.worldwind.avkey.ModelObject"; - final String MODEL_CLASS_NAME = "gov.nasa.worldwind.avkey.ModelClassName"; - - final String NUM_EMPTY_LEVELS = "gov.nasa.worldwind.avkey.NumEmptyLevels"; - final String NUM_LEVELS = "gov.nasa.worldwind.avkey.NumLevels"; - - final String PICKED_OBJECT = "gov.nasa.worldwind.avkey.PickedObject"; - final String PICKED_OBJECT_ID = "gov.nasa.worldwind.avkey.PickedObject.ID"; - final String PICKED_OBJECT_PARENT_LAYER = "gov.nasa.worldwind.avkey.PickedObject.ParentLayer"; - final String PICKED_OBJECT_PARENT_LAYER_NAME = "gov.nasa.worldwind.avkey.PickedObject.ParentLayer.Name"; - - final String POSITION = "gov.nasa.worldwind.avkey.Position"; - - final String RETRIEVAL_POOL_SIZE = "gov.nasa.worldwind.avkey.RetrievalPoolSize"; - final String RETRIEVAL_QUEUE_SIZE = "gov.nasa.worldwind.avkey.RetrievalQueueSize"; - final String RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT = "gov.nasa.worldwind.avkey.RetrievalStaleRequestLimit"; - final String RETRIEVAL_SERVICE_CLASS_NAME = "gov.nasa.worldwind.avkey.RetrievalServiceClassName"; - - final String RETRIEVER_STATE = "gov.nasa.worldwind.avkey.RetrieverState"; - - final String SCENE_CONTROLLER = "gov.nasa.worldwind.avkey.SceneControllerObject"; - final String SCENE_CONTROLLER_CLASS_NAME = "gov.nasa.worldwind.avkey.SceneControllerClassName"; - final String SECTOR = "gov.nasa.worldwind.avKey.Sector"; - final String SENDER = "gov.nasa.worldwind.avkey.Sender"; - final String SERVICE = "gov.nasa.worldwind.avkey.ServiceURLKey"; - final String STYLE_NAMES = "gov.nasa.worldwind.avkey.StyleNames"; - - final String THREADED_TASK_POOL_SIZE = "gov.nasa.worldwind.avkey.ThreadedTaskPoolSize"; - final String THREADED_TASK_QUEUE_SIZE = "gov.nasa.worldwind.avkey.ThreadedTaskQueueSize"; - final String THREADED_TASK_SERVICE_CLASS_NAME = "gov.nasa.worldwind.avkey.ThreadedTaskServiceClassName"; - final String TILE_DELTA = "gov.nasa.worldwind.avkey.TileDeltaKey"; - final String TILE_HEIGHT = "gov.nasa.worldwind.avkey.TileHeightKey"; - final String TILE_URL_BUILDER = "gov.nasa.worldwind.avkey.TileURLBuilder"; - final String TILE_WIDTH = "gov.nasa.worldwind.avkey.TileWidthKey"; - final String TILE_RETRIEVER = "gov.nasa.worldwind.avkey.TileRetriever"; - - final String URL_CONNECT_TIMEOUT = "gov.nasa.worldwind.avkey.URLConnectTimeout"; - final String URL_READ_TIMEOUT = "gov.nasa.worldwind.avkey.URLReadTimeout"; - - final String VERTICAL_EXAGGERATION = "gov.nasa.worldwind.avkey.VerticalExaggeration"; - final String VIEW = "gov.nasa.worldwind.avkey.ViewObject"; - final String VIEW_CLASS_NAME = "gov.nasa.worldwind.avkey.ViewClassName"; -} diff --git a/gov/nasa/worldwind/AVList.java b/gov/nasa/worldwind/AVList.java deleted file mode 100644 index db788e0..0000000 --- a/gov/nasa/worldwind/AVList.java +++ /dev/null @@ -1,128 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * An interface for managing an attribute-value pair collection. - * - * @author Tom Gaskins - * @version $Id: AVList.java 2215 2007-07-04 15:38:23Z tgaskins $ - */ -public interface AVList -{ - /** - * Adds a key/value pair to the list. Replaces an existing key/value pair if the list already contains the key. - * - * @param key the attribute name. May not be null. - * @param value the attribute value. May be null, in which case any existing value for the key is - * removed from the collection. - * @throws NullPointerException if key is null. - */ - void setValue(String key, Object value); - - void setValues(AVList avList); - - /** - * Returns the value for a specified key. - * - * @param key the attribute name. May not be null. - * @return the attribute value if one exists in the collection, otherwise null. - * @throws NullPointerException if key is null. - */ - Object getValue(String key); - - /** - * Returns the value for a specified key. The value must be a {@link String}. - * - * @param key the attribute name. May not be null. - * @return the attribute value if one exists in the collection, otherwise null. - * @throws NullPointerException if key is null. - * @throws WWRuntimeException if the value in the collection is not a String type. - */ - String getStringValue(String key); - - Set>getValues(); - - /** - * Indicates whether a key is in the collection. - * - * @param key the attribute name. May not be null. - * @return true if the key exists in the collection, otherwise false. - * @throws NullPointerException if key is null. - */ - boolean hasKey(String key); - - /** - * Removes a specified key from the collection if the key exists, otherwise returns without affecting the - * collection. - * - * @param key the attribute name. May not be null. - * @throws NullPointerException if key is null. - */ - void removeKey(String key); - - /** - * Adds a property change listener for the specified key. - * @param propertyName the key to associate the listener with. - * @param listener the listener to associate with the key. - * @throws IllegalArgumentException if either propertyName or listener is null - * @see java.beans.PropertyChangeSupport - */ - void addPropertyChangeListener(String propertyName, java.beans.PropertyChangeListener listener); - - /** - * Removes a property change listener associated with the specified key. - * @param propertyName the key associated with the change listener. - * @param listener the listener to remove. - * @throws IllegalArgumentException if either propertyName or listener is null - * @see java.beans.PropertyChangeSupport - */ - void removePropertyChangeListener(String propertyName, java.beans.PropertyChangeListener listener); - - /** - * Adds the specified all-property property change listener that will be called for all list changes. - * @param listener the listener to call. - * @throws IllegalArgumentException if listener is null - * @see java.beans.PropertyChangeSupport - */ - void addPropertyChangeListener(java.beans.PropertyChangeListener listener); - - /** - * Removes the specified all-property property change listener. - * @param listener the listener to remove. - * @throws IllegalArgumentException if listener is null - * @see java.beans.PropertyChangeSupport - */ - void removePropertyChangeListener(java.beans.PropertyChangeListener listener); - - /** - * Calls all property change listeners associated with the specified key. - * No listeners are called if odValue and newValue are equal and non-null. - * @param propertyName the key - * @param oldValue the value associated with the key before the even causing the firing. - * @param newValue the new value associated with the key. - * @throws IllegalArgumentException if propertyName is null - * @see java.beans.PropertyChangeSupport - */ - void firePropertyChange(String propertyName, Object oldValue, Object newValue); - - /** - * Calls all registered property change listeners with the specified property change event. - * @param propertyChangeEvent the event - * @throws IllegalArgumentException if propertyChangeEvent is null - * @see java.beans.PropertyChangeSupport - */ - void firePropertyChange(java.beans.PropertyChangeEvent propertyChangeEvent); - - /** - * Returns a shallow copy of this AVList instance: the keys and values themselves are not cloned. - * @return a shallow copy of this AVList. - */ - AVList copy(); -} diff --git a/gov/nasa/worldwind/AVListImpl.java b/gov/nasa/worldwind/AVListImpl.java deleted file mode 100644 index c164873..0000000 --- a/gov/nasa/worldwind/AVListImpl.java +++ /dev/null @@ -1,387 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * An implementation class for the {@link AVList} interface. Classes implementing AVList can subclass or - * aggreate this class to provide default AVList functionality. This class maintains a hash table of - * attribute-value pairs. - *

- * This class implements a notification mechanism for attribute-value changes. The mechanism provides a means for - * objects to observe attribute changes or queries for certain keys without explicitly monitoring all keys. See {@link - * java.beans.PropertyChangeSupport}. - * - * @author Tom Gaskins - * @version $Id: AVListImpl.java 2215 2007-07-04 15:38:23Z tgaskins $ - */ -public class AVListImpl implements AVList, java.beans.PropertyChangeListener -{ - // TODO: Make thread-safe - /** - * Available to sub-classes for further exposure of property-change functionality. - */ - protected final java.beans.PropertyChangeSupport changeSupport;// = new java.beans.PropertyChangeSupport(this); - - // To avoid unnecessary overhead, this object's hash map is created only if needed. - private java.util.Map avList; - - /** - * Creates an empty attribute-value list. - */ - public AVListImpl() - { - this.changeSupport = new java.beans.PropertyChangeSupport(this); - } - - /** - * Constructor enabling aggregation - * @param sourceBean The bean to be given as the soruce for any events. - */ - public AVListImpl(Object sourceBean) - { - // TODO: check arg for non-null - this.changeSupport = new java.beans.PropertyChangeSupport(sourceBean); - } - - private boolean hasAvList() - { - return this.avList != null; - } - - private void createAvList() - { - if (!this.hasAvList()) - { - this.avList = new java.util.HashMap(); - } - } - - private java.util.Map avList(boolean createIfNone) - { - if (createIfNone && !this.hasAvList()) - this.createAvList(); - - return this.avList; - } - - public final Object getValue(String key) - { - if (key == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AttributeKeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.hasAvList()) - return this.avList.get(key); - - return null; - } - - public Set> getValues() - { - return this.hasAvList() ? this.avList.entrySet() : null; - } - - public final String getStringValue(String key) - { - if (key == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.AttributeKeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalStateException(msg); - } - try - { - return (String) this.getValue(key); - } - catch (ClassCastException e) - { - String msg = WorldWind.retrieveErrMsg("AVAAccessibleImpl.AttributeValueForKeyIsNotAString") + key; - - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new WWRuntimeException(msg, e); - } - } - - public final void setValue(String key, Object value) - { - if (key == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AttributeKeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - // Capture the existing value if there is one, then set the new value. - this.avList(true).put(key, value); - } - - public final void setValues(AVList list) - { - if (list == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AttributesIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - Set> entries = list.getValues(); - for (Map.Entry entry : entries) - this.setValue(entry.getKey(), entry.getValue()); - } - - public final boolean hasKey(String key) - { - if (key == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.KeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return this.hasAvList() && this.avList.containsKey(key); - } - - public final void removeKey(String key) - { - if (key == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.KeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.hasKey(key)) - this.avList.remove(key); - } - - public AVList copy() - { - AVListImpl clone = new AVListImpl(); - - clone.createAvList(); - clone.avList.putAll(this.avList); - - return clone; - } - - public void addPropertyChangeListener(String propertyName, java.beans.PropertyChangeListener listener) - { - if (propertyName == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PropertyNameIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (listener == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ListenerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.changeSupport.addPropertyChangeListener(propertyName, listener); - } - - public void removePropertyChangeListener(String propertyName, java.beans.PropertyChangeListener listener) - { - if (propertyName == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PropertyNameIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (listener == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ListenerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.changeSupport.removePropertyChangeListener(propertyName, listener); - } - - public void addPropertyChangeListener(java.beans.PropertyChangeListener listener) - { - if (listener == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ListenerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.changeSupport.addPropertyChangeListener(listener); - } - - public void removePropertyChangeListener(java.beans.PropertyChangeListener listener) - { - if (listener == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ListenerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.changeSupport.removePropertyChangeListener(listener); - } - - public void firePropertyChange(java.beans.PropertyChangeEvent propertyChangeEvent) - { - if (propertyChangeEvent == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PropertyChangeEventIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.changeSupport.firePropertyChange(propertyChangeEvent); - } - - public void firePropertyChange(String propertyName, Object oldValue, Object newValue) - { - if (propertyName == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PropertyNameIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.changeSupport.firePropertyChange(propertyName, oldValue, newValue); - } - - /** - * The property change listener for this instance. - * Recieves property change notifications that this instance has registered with other proprty change notifiers. - * @param propertyChangeEvent the event - * @throws IllegalArgumentException if propertyChangeEvent is null - */ - public void propertyChange(java.beans.PropertyChangeEvent propertyChangeEvent) - { - if (propertyChangeEvent == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PropertyChangeEventIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - // Notify all *my* listeners of the change that I caught - this.changeSupport.firePropertyChange(propertyChangeEvent); - } - - - // Static AVList utilities. - public static String getStringValue(AVList avList, String key, String defaultValue) - { - String v = getStringValue(avList, key); - return v != null ? v : defaultValue; - } - - public static String getStringValue(AVList avList, String key) - { - try - { - return avList.getStringValue(key); - } - catch (Exception e) - { - return null; - } - } - - public static Integer getIntegerValue(AVList avList, String key, Integer defaultValue) - { - Integer v = getIntegerValue(avList, key); - return v != null ? v : defaultValue; - } - - public static Integer getIntegerValue(AVList avList, String key) - { - Object o = avList.getValue(key); - if (o == null) - return null; - - if (o instanceof Integer) - return (Integer) o; - - String v = getStringValue(avList, key); - if (v == null) - return null; - - try - { - return Integer.parseInt(v); - } - catch (NumberFormatException e) - { - String message = WorldWind.retrieveErrMsg("Configuration.ConversionError") + v; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - - return null; - } - } - - public static Long getLongValue(AVList avList, String key, Long defaultValue) - { - Long v = getLongValue(avList, key); - return v != null ? v : defaultValue; - } - - public static Long getLongValue(AVList avList, String key) - { - Object o = avList.getValue(key); - if (o == null) - return null; - - if (o instanceof Long) - return (Long) o; - - String v = getStringValue(avList, key); - if (v == null) - return null; - - try - { - return Long.parseLong(v); - } - catch (NumberFormatException e) - { - String message = WorldWind.retrieveErrMsg("Configuration.ConversionError") + v; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - - return null; - } - } - - public static Double getDoubleValue(AVList avList, String key, Double defaultValue) - { - Double v = getDoubleValue(avList, key); - return v != null ? v : defaultValue; - } - - public static Double getDoubleValue(AVList avList, String key) - { - Object o = avList.getValue(key); - if (o == null) - return null; - - if (o instanceof Double) - return (Double) o; - - String v = getStringValue(avList, key); - if (v == null) - return null; - - try - { - return Double.parseDouble(v); - } - catch (NumberFormatException e) - { - String message = WorldWind.retrieveErrMsg("Configuration.ConversionError") + v; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - - return null; - } - } -} diff --git a/gov/nasa/worldwind/AbsentResourceList.java b/gov/nasa/worldwind/AbsentResourceList.java deleted file mode 100644 index c7cb4d8..0000000 --- a/gov/nasa/worldwind/AbsentResourceList.java +++ /dev/null @@ -1,84 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id$ - */ -public class AbsentResourceList -{ - // Absent resources: A resource is deemed absent if a specified maximum number of attempts have been made to retrieve it. - // Retrieval attempts are governed by a minimum time interval between successive attempts. If an attempt is made - // within this interval, the resource is still deemed to be absent until the interval expires. - private static final int DEFAULT_MAX_ABSENT_RESOURCE_TRIES = 2; - private static final int DEFAULT_MIN_ABSENT_RESOURCE_CHECK_INTERVAL = 10000; - - private int maxTries = DEFAULT_MAX_ABSENT_RESOURCE_TRIES; - private int minCheckInterval = DEFAULT_MIN_ABSENT_RESOURCE_CHECK_INTERVAL; - - private static class AbsentResoureEntry - { - long timeOfLastMark; // meant to be the time of the most recent attempt to find the resource - int numTries; - } - - private final java.util.concurrent.ConcurrentHashMap possiblyAbsent = - new java.util.concurrent.ConcurrentHashMap(); - - private java.util.SortedSet definitelyAbsent = java.util.Collections.synchronizedSortedSet( - new java.util.TreeSet()); - - public AbsentResourceList() - { - } - - public AbsentResourceList(int maxTries, int minCheckInterval) - { - this.maxTries = Math.max(maxTries, 1); - this.minCheckInterval = Math.max(minCheckInterval, 500); - } - - public final void markResourceAbsent(long resourceID) - { - if (this.definitelyAbsent.contains(resourceID)) - return; - - AbsentResoureEntry entry = this.possiblyAbsent.get(resourceID); - if (entry == null) - this.possiblyAbsent.put(resourceID, entry = new AbsentResoureEntry()); - - ++entry.numTries; - entry.timeOfLastMark = System.currentTimeMillis(); - - if (entry.numTries >= this.maxTries) - { - this.definitelyAbsent.add(resourceID); - this.possiblyAbsent.remove(resourceID); - // entry can now be garbage collected - } - } - - public final boolean isResourceAbsent(long resourceID) - { - if (this.definitelyAbsent.contains(resourceID)) - return true; - - AbsentResoureEntry entry = this.possiblyAbsent.get(resourceID); - //noinspection SimplifiableIfStatement - if (entry == null) - return false; - - return (System.currentTimeMillis() - entry.timeOfLastMark) < this.minCheckInterval; - } - - public final void unmarkResourceAbsent(long resourceID) - { - this.definitelyAbsent.remove(resourceID); - this.possiblyAbsent.remove(resourceID); - } -} diff --git a/gov/nasa/worldwind/AbstractFileCache.java b/gov/nasa/worldwind/AbstractFileCache.java deleted file mode 100644 index df1ad85..0000000 --- a/gov/nasa/worldwind/AbstractFileCache.java +++ /dev/null @@ -1,500 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id: AbstractFileCache.java 748 2007-02-03 19:22:54Z tgaskins $ - */ -public class AbstractFileCache implements FileCache -{ - private final java.util.LinkedList cacheDirs = new java.util.LinkedList(); - private java.io.File cacheWriteDir = null; - - public AbstractFileCache() - { - } - - protected void initialize(java.io.InputStream xmlConfigStream) - { - javax.xml.parsers.DocumentBuilderFactory docBuilderFactory = - javax.xml.parsers.DocumentBuilderFactory.newInstance(); - - try - { - javax.xml.parsers.DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); - org.w3c.dom.Document doc = docBuilder.parse(xmlConfigStream); - - // The order of the following two calls is important, because building the writable location may entail - // creating a location that's included in the specified read locations. - this.buildWritePaths(doc); - this.buildReadPaths(doc); - - if (this.cacheWriteDir == null) - { - String message = WorldWind.retrieveErrMsg("FileCache.NoFileCacheWriteLocation"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - - if (this.cacheDirs.size() == 0) - { - // This should not happen because the writable cache is added to the read list, but check nonetheless - String message = WorldWind.retrieveErrMsg("FileCache.NoFileCacheReadLocations"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - } - catch (javax.xml.parsers.ParserConfigurationException e) - { - e.printStackTrace(); - } - catch (org.xml.sax.SAXException e) - { - e.printStackTrace(); - } - catch (java.io.IOException e) - { - e.printStackTrace(); - } - } - - public void addCacheLocation(String newPath) - { - this.addCacheLocation(this.cacheDirs.size(), newPath); - } - - public void addCacheLocation(int index, String newPath) - { - if (newPath == null || newPath.length() == 0) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileCachePathIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (index < 0) - { - String message = WorldWind.retrieveErrMsg("generic.invalidIndex"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (index > 0 && index > this.cacheDirs.size()) - index = this.cacheDirs.size(); - - java.io.File newFile = new java.io.File(newPath); - - if (this.cacheDirs.contains(newFile)) - this.cacheDirs.remove(newFile); - - this.cacheDirs.add(index, newFile); - } - - public void removeCacheLocation(String newPath) - { - if (newPath == null || newPath.length() == 0) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileCachePathIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - // Just warn and return. - return; - } - - java.io.File newFile = new java.io.File(newPath); - - if (newFile.equals(this.cacheWriteDir)) - { - String message = WorldWind.retrieveErrMsg("FileCache.CannotRemoveWriteLocationFromSearchList"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.cacheDirs.remove(new java.io.File(newPath)); - } - - public java.util.List getCacheLocations() - { - // Return a copy. - return new java.util.LinkedList(this.cacheDirs); - } - - public java.io.File getWriteLocation() - { - return this.cacheWriteDir; - } - - private void buildReadPaths(org.w3c.dom.Node dataFileCacheNode) - { - javax.xml.xpath.XPathFactory pathFactory = javax.xml.xpath.XPathFactory.newInstance(); - javax.xml.xpath.XPath pathFinder = pathFactory.newXPath(); - - try - { - org.w3c.dom.NodeList locationNodes = (org.w3c.dom.NodeList) pathFinder.evaluate( - "/dataFileCache/readLocations/location", - dataFileCacheNode.getFirstChild(), - javax.xml.xpath.XPathConstants.NODESET); - for (int i = 0; i < locationNodes.getLength(); i++) - { - org.w3c.dom.Node location = locationNodes.item(i); - String prop = pathFinder.evaluate("@property", location); - String wwDir = pathFinder.evaluate("@wwDir", location); - String append = pathFinder.evaluate("@append", location); - - String path = buildLocationPath(prop, append, wwDir); - if (path == null) - { - String message = WorldWind.retrieveErrMsg("FileCache.CacheLocationInvalid"); - message += prop != null ? prop : WorldWind.retrieveErrMsg("generic.unknown"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - continue; - } - - // Even paths that don't exist or are otherwise problematic are added to the list because they may - // become readable during the session. E.g., removable media. So add them to the search list. - - java.io.File pathFile = new java.io.File(path); - if (pathFile.exists() && !pathFile.isDirectory()) - { - String message = WorldWind.retrieveErrMsg("FileCache.CacheLocationIsFile"); - message += pathFile.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINER, message); - } - - if (!this.cacheDirs.contains(pathFile)) // filter out duplicates - { - this.cacheDirs.add(pathFile); - } - } - } - catch (javax.xml.xpath.XPathExpressionException e) - { - e.printStackTrace(); - } - } - - private void buildWritePaths(org.w3c.dom.Node dataFileCacheNode) - { - javax.xml.xpath.XPathFactory pathFactory = javax.xml.xpath.XPathFactory.newInstance(); - javax.xml.xpath.XPath pathFinder = pathFactory.newXPath(); - - try - { - org.w3c.dom.NodeList locationNodes = (org.w3c.dom.NodeList) pathFinder.evaluate( - "/dataFileCache/writeLocations/location", - dataFileCacheNode.getFirstChild(), - javax.xml.xpath.XPathConstants.NODESET); - for (int i = 0; i < locationNodes.getLength(); i++) - { - org.w3c.dom.Node location = locationNodes.item(i); - String prop = pathFinder.evaluate("@property", location); - String wwDir = pathFinder.evaluate("@wwDir", location); - String append = pathFinder.evaluate("@append", location); - String create = pathFinder.evaluate("@create", location); - - String path = buildLocationPath(prop, append, wwDir); - if (path == null) - { - String message = WorldWind.retrieveErrMsg("FileCache.CacheLocationInvalid"); - message += prop != null ? prop : WorldWind.retrieveErrMsg("generic.unknown"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - continue; - } - - java.io.File pathFile = new java.io.File(path); - if (!pathFile.exists() && create != null && (create.contains("t") || create.contains("T"))) - { - pathFile.mkdirs(); - } - - if (pathFile.isDirectory() && pathFile.canWrite() && pathFile.canRead()) - { - this.cacheWriteDir = pathFile; - this.cacheDirs.addFirst(pathFile); // writable location is always first in search path - break; // only need one - } - } - } - catch (javax.xml.xpath.XPathExpressionException e) - { - e.printStackTrace(); - } - } - - private static String buildLocationPath(String property, String append, String wwDir) - { - String path = propertyToPath(property); - - if (append != null && append.length() != 0) - path = appendPathPart(path, append.trim()); - - if (wwDir != null && wwDir.length() != 0) - path = appendPathPart(path, wwDir.trim()); - - return path; - } - - private static String appendPathPart(String firstPart, String secondPart) - { - if (secondPart == null || secondPart.length() == 0) - return firstPart; - if (firstPart == null || secondPart.length() == 0) - return secondPart; - - firstPart = stripTrailingSeparator(firstPart); - secondPart = stripLeadingSeparator(secondPart); - - return firstPart + System.getProperty("file.separator") + secondPart; - } - - private static String stripTrailingSeparator(String s) - { - if (s.endsWith("/") || s.endsWith("\\")) - return s.substring(0, s.length() - 1); - else - return s; - } - - private static String stripLeadingSeparator(String s) - { - if (s.startsWith("/") || s.startsWith("\\")) - return s.substring(1, s.length()); - else - return s; - } - - private static String propertyToPath(String propName) - { - if (propName == null || propName.length() == 0) - return null; - - String prop = System.getProperty(propName); - if (prop != null) - return prop; - - if (propName.equalsIgnoreCase("gov.nasa.worldwind.platform.alluser.cache")) - return determineAllUserCacheDir(); - - if (propName.equalsIgnoreCase("gov.nasa.worldwind.platform.user.cache")) - return determineSingleUserCacheDir(); - - return null; - } - - private static String determineAllUserCacheDir() - { - if (gov.nasa.worldwind.Configuration.isMacOS()) - { - return "/Library/Caches"; - } - else if (gov.nasa.worldwind.Configuration.isWindowsOS()) - { - String path = System.getenv("ALLUSERSPROFILE"); - if (path == null) - { - String message = WorldWind.retrieveErrMsg("generic.AllUsersWindowsProfileNotKnown"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - return path + "\\Application Data"; - } - else if (gov.nasa.worldwind.Configuration.isLinuxOS() || gov.nasa.worldwind.Configuration.isUnixOS() || gov.nasa - .worldwind.Configuration - .isSolarisOS()) - { - return "/var/cache/"; - } - else - { - String message = WorldWind.retrieveErrMsg("generic.UnknownOperatingSystem"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - } - - private static String determineSingleUserCacheDir() - { - String home = getUserHomeDir(); - if (home == null) - { - String message = WorldWind.retrieveErrMsg("generic.UsersHomeDirectoryNotKnown"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - String path = null; - - if (gov.nasa.worldwind.Configuration.isMacOS()) - { - path = "/Library/Caches"; - } - else if (gov.nasa.worldwind.Configuration.isWindowsOS()) - { - path = System.getenv("USERPROFILE"); - if (path == null) - { - String message = WorldWind.retrieveErrMsg("generic.UsersWindowsProfileNotKnown"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - path += "\\Application Data"; - } - else if (gov.nasa.worldwind.Configuration.isLinuxOS() || gov.nasa.worldwind.Configuration.isUnixOS() || gov.nasa - .worldwind.Configuration - .isSolarisOS()) - { - path = "/var/cache/"; - } - else - { - String message = WorldWind.retrieveErrMsg("generic.UnknownOperatingSystem"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - - if (path == null) - return null; - - return home + path; - } - - private static String getUserHomeDir() - { - return System.getProperty("user.home"); - } - - public boolean contains(String fileName) - { - if (fileName == null) - return false; - - for (java.io.File cacheDir : this.cacheDirs) - { - java.io.File file; - if (fileName.startsWith(cacheDir.getAbsolutePath())) - file = new java.io.File(fileName); - else - file = this.cachePathForFile(cacheDir, fileName); - - if (file.exists()) - return true; - } - - return false; - } - - private java.io.File cachePathForFile(java.io.File file, String fileName) - { - return new java.io.File(file.getAbsolutePath() + "/" + fileName); - } - - private String makeFullPath(java.io.File dir, String fileName) - { - return dir.getAbsolutePath() + "/" + fileName; - } - - /** - * @param fileName the name to give the newly created file - * @return a handle to the newly created file if it could be created and added to the cache, otherwise null - * @throws IllegalArgumentException if fileName is null - */ - public java.io.File newFile(String fileName) - { - if (fileName == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FilePathIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.cacheWriteDir != null) - { - String fullPath = this.makeFullPath(this.cacheWriteDir, fileName); - java.io.File file = new java.io.File(fullPath); - if (file.getParentFile().exists()) - return file; - else if (file.getParentFile().mkdirs()) - return file; - else - return null; - } - - return null; - } - - /** - * @param fileName the name of the file to find - * @param checkClassPath if true, the class path is first searched for the file, otherwise the class - * path is not searched unless it's one of the explicit paths in the cache search directories - * @return a handle to the requested file if it exists in the cache, otherwise null - * @throws IllegalArgumentException if fileName is null - */ - public java.net.URL findFile(String fileName, boolean checkClassPath) - { - if (fileName == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FilePathIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (checkClassPath) - { - java.net.URL url = this.getClass().getClassLoader().getResource(fileName); - if (url != null) - return url; - } - - for (java.io.File dir : this.cacheDirs) - { - if (!dir.exists()) - continue; - - java.io.File file = new java.io.File(this.makeFullPath(dir, fileName)); - if (file.exists()) - { - try - { - return file.toURI().toURL(); - } - catch (java.net.MalformedURLException e) - { - String message = WorldWind.retrieveErrMsg("FileCache.ExceptionCreatingURLForFile"); - WorldWind.logger().log(java.util.logging.Level.FINE, message + file.getPath()); - } - } - } - - return null; - } - - /** - * @param url the "file:" URL of the file to remove from the cache - * @throws IllegalArgumentException if url is null - */ - public void removeFile(java.net.URL url) - { - if (url == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.URLIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - try - { - java.io.File file = new java.io.File(url.toURI()); - - if (file.exists()) - file.delete(); - } - catch (java.net.URISyntaxException e) - { - String message = WorldWind.retrieveErrMsg("FileCache.ExceptionRemovingFile"); - WorldWind.logger().log(java.util.logging.Level.FINE, message + url); - } - } -} \ No newline at end of file diff --git a/gov/nasa/worldwind/AbstractView.java b/gov/nasa/worldwind/AbstractView.java deleted file mode 100644 index a063bca..0000000 --- a/gov/nasa/worldwind/AbstractView.java +++ /dev/null @@ -1,640 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import javax.media.opengl.glu.*; -import java.util.logging.Level; - -/** - * @author Paul Collins - * @version $Id: AbstractView.java 2126 2007-06-21 21:00:42Z dcollins $ - */ -public abstract class AbstractView extends WWObjectImpl implements View -{ - // Shared attributes. - private boolean isInitialized = false; - private final double[] matrixArray = new double[32]; - private final double[] vecArray = new double[4]; - private final int[] viewportArray = new int[4]; - - // ============== Viewing State ======================= // - // ============== Viewing State ======================= // - // ============== Viewing State ======================= // - - // Current OpenGL viewing state. - private Matrix modelView; - private Matrix projection; - private java.awt.Rectangle viewport; - - public void apply(DrawContext dc) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (dc.getGL() == null) - { - String message = WorldWind.retrieveErrMsg("AbstractView.DrawingContextGLIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - if (dc.getGlobe() == null) - { - String message = WorldWind.retrieveErrMsg("layers.AbstractLayer.NoGlobeSpecifiedInDrawingContext"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - if (this.isViewUpdateable(dc)) - this.updateViewingState(dc); - - this.doApply(dc); - } - - public boolean isViewUpdateable(DrawContext dc) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return !dc.isPickingMode(); - } - - private void updateViewingState(DrawContext dc) - { - this.clearAttributes(); - this.drawContext = dc; - - // Get the current OpenGL viewport state. - dc.getGL().glGetIntegerv(GL.GL_VIEWPORT, this.viewportArray, 0); - this.viewport = new java.awt.Rectangle( - this.viewportArray[0], - this.viewportArray[1], - this.viewportArray[2], - this.viewportArray[3]); - - if (!this.isInitialized) - this.initialize(dc); - this.isInitialized = true; - - this.updateStateIterators(dc); - } - - protected void loadModelViewProjection(DrawContext dc, Matrix modelView, Matrix projection) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (dc.getGL() == null) - { - String message = WorldWind.retrieveErrMsg("AbstractView.DrawingContextGLIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - if (modelView == null) - { - String message = WorldWind.retrieveErrMsg("AbstractView.ModelViewIsNull"); - WorldWind.logger().log(Level.FINE, message); - } - - if (projection == null) - { - String message = WorldWind.retrieveErrMsg("AbstractView.ProjectionIsNull"); - WorldWind.logger().log(Level.FINE, message); - } - - this.modelView = modelView; - this.projection = projection; - - GL gl = dc.getGL(); - // Store the current matrix-mode state. - final int matrixMode = this.getMatrixMode(gl); - - // Apply the model-view matrix to the current OpenGL context held by 'dc'. - this.modelView.toArray(this.matrixArray, 0, false); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glLoadMatrixd(this.matrixArray, 0); - - // Apply the projection matrix to the current OpenGL context held by 'dc'. - this.projection.toArray(this.matrixArray, 0, false); - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glLoadMatrixd(this.matrixArray, 0); - - // Restore matrix-mode state. - gl.glMatrixMode(matrixMode); - } - - protected abstract void doApply(DrawContext dc); - - public Matrix pushReferenceCenter(DrawContext dc, Vec4 referenceCenter) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (dc.getGL() == null) - { - String message = WorldWind.retrieveErrMsg("AbstractView.DrawingContextGLIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - if (referenceCenter == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - - // Compute a new model-view matrix with origin at referenceCenter. - Matrix matrix = null; - if (this.modelView != null) - matrix = this.modelView.multiply(Matrix.fromTranslation(referenceCenter)); - - GL gl = dc.getGL(); - // Store the current matrix-mode state. - final int matrixMode = this.getMatrixMode(gl); - - if (matrixMode != GL.GL_MODELVIEW) - gl.glMatrixMode(GL.GL_MODELVIEW); - - // Push and load a new model-view matrix to the current OpenGL context held by 'dc'. - gl.glPushMatrix(); - if (matrix != null) - { - matrix.toArray(this.matrixArray, 0, false); - gl.glLoadMatrixd(this.matrixArray, 0); - } - - // Restore matrix-mode state. - if (matrixMode != GL.GL_MODELVIEW) - gl.glMatrixMode(matrixMode); - - return matrix; - } - - public void popReferenceCenter(DrawContext dc) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (dc.getGL() == null) - { - String message = WorldWind.retrieveErrMsg("AbstractView.DrawingContextGLIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - GL gl = dc.getGL(); - // Store the current matrix-mode state. - final int matrixMode = this.getMatrixMode(gl); - - // Pop a model-view matrix off the current OpenGL context held by 'dc'. - if (matrixMode != GL.GL_MODELVIEW) - gl.glMatrixMode(GL.GL_MODELVIEW); - - // Pop the top model-view matrix. - gl.glPopMatrix(); - - // Restore matrix-mode state. - if (matrixMode != GL.GL_MODELVIEW) - gl.glMatrixMode(matrixMode); - } - - private final int[] matrixModeArray = new int[1]; - - private int getMatrixMode(GL gl) - { - gl.glGetIntegerv(GL.GL_MATRIX_MODE, this.matrixModeArray, 0); - return this.matrixModeArray[0]; - } - - // ============== Runtime Initialization ======================= // - // ============== Runtime Initialization ======================= // - // ============== Runtime Initialization ======================= // - - private void initialize(DrawContext dc) - { - this.fieldOfView = getInitialFieldOfView(dc, this.fieldOfView); - this.doInitialize(dc); - } - - protected void doInitialize(DrawContext dc) - { - } - - protected static Angle getInitialFieldOfView(DrawContext dc, Angle clientValue) - { - // Use value specified by client. - if (clientValue != null) - return clientValue; - - // Use value from configuration. - Double configValue = Configuration.getDoubleValue(AVKey.FOV); - if (configValue != null) - return Angle.fromDegrees(configValue); - - // Fallback to zero. - return Angle.fromDegrees(45.0); - } - - protected static Angle getInitialLatitude(DrawContext dc, Angle clientValue) - { - // Use value specified by client. - if (clientValue != null) - return clientValue; - - // Use value from configuration. - Double configValue = Configuration.getDoubleValue(AVKey.INITIAL_LATITUDE); - if (configValue != null) - return Angle.fromDegrees(configValue); - - // Fallback to zero. - return Angle.ZERO; - } - - protected static Angle getInitialLongitude(DrawContext dc, Angle clientValue) - { - // Use value specified by client. - if (clientValue != null) - return clientValue; - - // Use value from configuration. - Double configValue = Configuration.getDoubleValue(AVKey.INITIAL_LONGITUDE); - if (configValue != null) - return Angle.fromDegrees(configValue); - - // Use longitude of system time-zone. - java.util.TimeZone tz = java.util.Calendar.getInstance().getTimeZone(); - if (tz != null) - return Angle.fromDegrees(180.0 * tz.getOffset(System.currentTimeMillis()) / (12.0 * 3.6e6)); - - // Fallback to zero. - return Angle.ZERO; - } - - protected static Angle getInitialHeading(DrawContext dc, Angle clientValue) - { - // Use value specified by client. - if (clientValue != null) - return clientValue; - - // Use value from configuration. - Double configValue = Configuration.getDoubleValue("null"); - if (configValue != null) - return Angle.fromDegrees(configValue); - - // Fallback to zero. - return Angle.ZERO; - } - - protected static Angle getInitialPitch(DrawContext dc, Angle clientValue) - { - // Use value specified by client. - if (clientValue != null) - return clientValue; - - // Use value from configuration. - Double configValue = Configuration.getDoubleValue("null"); - if (configValue != null) - return Angle.fromDegrees(configValue); - - // Fallback to zero. - return Angle.ZERO; - } - - protected static double getInitialAltitude(DrawContext dc, double clientValue) - { - // Use value specified by client. - if (clientValue >= 0.0) - return clientValue; - - // Use value from configuration. - Double configValue = Configuration.getDoubleValue("null"); - if (configValue != null) - return configValue; - - // Use globe radius with coefficient. - if (dc != null && dc.getGlobe() != null) - return 3.0 * dc.getGlobe().getRadius(); - - // Fallback to zero. - return 0.0; - } - - // ============== Attribute Accessors ======================= // - // ============== Attribute Accessors ======================= // - // ============== Attribute Accessors ======================= // - - // Current DrawContext state. - private DrawContext drawContext = null; - // Cached viewing attribute computations. - private Vec4 eye = null; - private Vec4 up = null; - private Vec4 forward = null; - private Frustum frustumInModelCoords = null; - private Angle fieldOfView = null; - private double pixelSizeScale = -1; - private double horizonDistance = -1; - - private void clearAttributes() - { - this.drawContext = null; - this.eye = null; - this.up = null; - this.forward = null; - this.frustumInModelCoords = null; - this.pixelSizeScale = -1; - this.horizonDistance = -1; - } - - protected DrawContext getDrawContext() - { - return this.drawContext; - } - - public Matrix getModelViewMatrix() - { - return this.modelView; - } - - public Matrix getProjectionMatrix() - { - return this.projection; - } - - public java.awt.Rectangle getViewport() - { - return new java.awt.Rectangle(this.viewport); - } - - public Frustum getFrustumInModelCoordinates() - { - if (this.frustumInModelCoords == null) - { - // Compute the current model-view coordinate frustum. - Frustum frust = this.getFrustum(); - if (frust != null && this.modelView != null) - this.frustumInModelCoords = frust.transformBy(this.modelView.getTranspose()); - } - return this.frustumInModelCoords; - } - - public Angle getFieldOfView() - { - return this.fieldOfView; - } - - public void setFieldOfView(Angle newFov) - { - if (newFov == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.fieldOfView = newFov; - } - - public Vec4 getEyePoint() - { - if (this.eye == null) - { - Matrix modelViewInv; - if (this.modelView != null && (modelViewInv = this.modelView.getInverse()) != null) - this.eye = Vec4.UNIT_W.transformBy4(modelViewInv); - } - return this.eye; - } - - public Vec4 getUpVector() - { - if (this.up == null) - { - Matrix modelViewInv; - if (this.modelView != null && (modelViewInv = this.modelView.getInverse()) != null) - this.up = Vec4.UNIT_Y.transformBy4(modelViewInv); - } - return this.up; - } - - public Vec4 getForwardVector() - { - if (this.forward == null) - { - Matrix modelViewInv; - if (this.modelView != null && (modelViewInv = this.modelView.getInverse()) != null) - this.forward = Vec4.UNIT_NEGATIVE_Z.transformBy4(modelViewInv); - } - return this.forward; - } - - // ============== State Iterators ======================= // - // ============== State Iterators ======================= // - // ============== State Iterators ======================= // - - private ViewStateIterator viewStateIterator = null; - - public void iterateOver(ViewStateIterator viewStateIterator) - { - if (viewStateIterator == null) - { - this.stopIterating(); - return; - } - - this.viewStateIterator = viewStateIterator.coalesceWith(this, this.viewStateIterator); - this.firePropertyChange(AVKey.VIEW, null, this); - } - - public boolean isIterating() - { - return this.viewStateIterator != null; - } - - public void stopIterating() - { - this.viewStateIterator = null; - } - - private void updateStateIterators(DrawContext dc) - { - if (!this.isIterating()) - return; - - if (this.viewStateIterator.hasNextState(this)) - { - this.viewStateIterator.nextState(this); - this.firePropertyChange(AVKey.VIEW, null, this); - } - else - { - this.stopIterating(); - } - } - - // ============== Utilities ======================= // - // ============== Utilities ======================= // - // ============== Utilities ======================= // - - // GLU - private final GLU glu = new GLU(); - - // TODO: this should be expressed in OpenGL screen coordinates, not toolkit (e.g. AWT) coordinates - public Line computeRayFromScreenPoint(double x, double y) - { - if (this.viewport == null) - return null; - double invY = this.viewport.height - y - 1; // TODO: should be computed by caller - Vec4 a = this.unProject(new Vec4(x, invY, 0, 0)); - Vec4 b = this.unProject(new Vec4(x, invY, 1, 0)); - if (a == null || b == null) - return null; - return new Line(a, b.subtract3(a).normalize3()); - } - - public Position computePositionFromScreenPoint(double x, double y) - { - Line line = this.computeRayFromScreenPoint(x, y); - if (line == null) - return null; - - if (this.drawContext == null) - return null; - - Globe globe = this.drawContext.getGlobe(); - if (globe == null) - return null; - - return globe.getIntersectionPosition(line); - } - - public double computePixelSizeAtDistance(double distance) - { - if (this.pixelSizeScale < 0) - { - // Compute the current coefficient for computing the size of a pixel. - if (this.fieldOfView != null && this.viewport.width > 0) - this.pixelSizeScale = 2 * this.fieldOfView.tanHalfAngle() / (double) this.viewport.width; - else if (this.viewport.width > 0) - this.pixelSizeScale = 1 / (double) this.viewport.width; - } - if (this.pixelSizeScale < 0) - return -1; - return this.pixelSizeScale * Math.abs(distance); - } - - public double computeHorizonDistance() - { - if (this.horizonDistance < 0) - { - if (this.drawContext == null) - return this.horizonDistance; - - Globe globe = this.drawContext.getGlobe(); - if (globe == null) - return this.horizonDistance; - - this.horizonDistance = this.computeHorizonDistance(globe, this.drawContext.getVerticalExaggeration(), - this.getEyePoint()); - } - return this.horizonDistance; - } - - protected double computeHorizonDistance(Globe globe, double verticalExaggeration, Vec4 eyeVec) - { - if (globe == null || eyeVec == null) - return -1; - - // Compute the current (approximate) distance from eye to globe horizon. - Position eyePosition = globe.computePositionFromPoint(eyeVec); - double elevation = verticalExaggeration - * globe.getElevation(eyePosition.getLatitude(), eyePosition.getLongitude()); - Vec4 surface = globe.computePointFromPosition(eyePosition.getLatitude(), eyePosition.getLongitude(), - elevation); - double altitude = eyeVec.getLength3() - surface.getLength3(); - double radius = globe.getMaximumRadius(); - return Math.sqrt(altitude * (2 * radius + altitude)); - } - - public Vec4 project(Vec4 modelPoint) - { - if (modelPoint == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.modelView == null || this.projection == null || this.viewport == null) - return null; - - this.modelView.toArray(this.matrixArray, 0, false); - this.projection.toArray(this.matrixArray, 16, false); - - if (!this.glu.gluProject( - modelPoint.x, modelPoint.y, modelPoint.z, - this.matrixArray, 0, - this.matrixArray, 16, - this.viewportArray, 0, - this.vecArray, 0)) - { - return null; - } - - return Vec4.fromArray3(this.vecArray, 0); - } - - public Vec4 unProject(Vec4 windowPoint) - { - if (windowPoint == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.modelView == null || this.projection == null || this.viewport == null) - return null; - - this.modelView.toArray(this.matrixArray, 0, false); - this.projection.toArray(this.matrixArray, 16, false); - - if (!this.glu.gluUnProject( - windowPoint.x, windowPoint.y, windowPoint.z, - this.matrixArray, 0, - this.matrixArray, 16, - this.viewportArray, 0, - this.vecArray, 0)) - { - return null; - } - - return Vec4.fromArray3(this.vecArray, 0); - } -} diff --git a/gov/nasa/worldwind/BasicDataFileCache.java b/gov/nasa/worldwind/BasicDataFileCache.java deleted file mode 100644 index 2f884c2..0000000 --- a/gov/nasa/worldwind/BasicDataFileCache.java +++ /dev/null @@ -1,35 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: BasicDataFileCache.java 1792 2007-05-08 21:28:37Z tgaskins $ - */ -public class BasicDataFileCache extends AbstractFileCache -{ - public BasicDataFileCache() - { - String cachePathName = Configuration.getStringValue(AVKey.DATA_FILE_CACHE_CONFIGURATION_FILE_NAME); - if (cachePathName == null) - { - String message = WorldWind.retrieveErrMsg("FileCache.NoConfiguration"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - java.io.InputStream is = this.getClass().getClassLoader().getResourceAsStream(cachePathName); - if (is == null) - { - String message = WorldWind.retrieveErrMsg("FileCache.ConfigurationNotFound"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - this.initialize(is); - } -} diff --git a/gov/nasa/worldwind/BasicElevationModel.java b/gov/nasa/worldwind/BasicElevationModel.java deleted file mode 100644 index 8fc4380..0000000 --- a/gov/nasa/worldwind/BasicElevationModel.java +++ /dev/null @@ -1,694 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.net.*; -import java.nio.*; -import java.io.*; - -// Implementation notes, not for API doc: -// -// Implements an elevation model based on a quad tree of elevation tiles. Meant to be subclassed by very specific -// classes, e.g. Earth/SRTM. A Descriptor passed in at construction gives the configuration parameters. Eventually -// Descriptor will be replaced by an XML configuration document. -// -// A "tile" corresponds to one tile of the data set, which has a corresponding unique row/column address in the data -// set. An inner class implements Tile. An inner class also implements TileKey, which is used to address the -// corresponding Tile in the memory cache. - -// Clients of this class get elevations from it by first getting an Elevations object for a specific Sector, then -// querying that object for the elevation at individual lat/lon positions. The Elevations object captures information -// that is used to compute elevations. See in-line comments for a description. -// -// When an elevation tile is needed but is not in memory, a task is threaded off to find it. If it's in the file cache -// then it's loaded by the task into the memory cache. If it's not in the file cache then a retrieval is initiated by -// the task. The disk is never accessed during a call to getElevations(sector, resolution) because that method is -// likely being called when a frame is being rendered. The details of all this are in-line below. - -/** - * This class represents a single tile in the data set and contains the information that needs to be cached. - * - * @author Tom Gaskins - * @version $Id: BasicElevationModel.java 2211 2007-07-03 22:15:13Z tgaskins $ - */ -public class BasicElevationModel extends WWObjectImpl implements ElevationModel -{ - private boolean isEnabled = true; - private final LevelSet levels; - private final double minElevation; - private final double maxElevation; - private long numExpectedValues = 0; - private final Object fileLock = new Object(); - private java.util.concurrent.ConcurrentHashMap levelZeroTiles = - new java.util.concurrent.ConcurrentHashMap(); - private gov.nasa.worldwind.MemoryCache memoryCache = new gov.nasa.worldwind.BasicMemoryCache(8000000, 10000000); - - private static final class Tile extends gov.nasa.worldwind.Tile implements Cacheable - { - private java.nio.ShortBuffer elevations; // the elevations themselves - - private Tile(Sector sector, Level level, int row, int col) - { - super(sector, level, row, col); - } - } - - /** - * @param levels - * @param minElevation - * @param maxElevation - * @throws IllegalArgumentException if levels is null or invalid - */ - public BasicElevationModel(LevelSet levels, double minElevation, double maxElevation) - { - if (levels == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LevelSetIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.levels = new LevelSet(levels); // the caller's levelSet may change internally, so we copy it. - this.minElevation = minElevation; - this.maxElevation = maxElevation; - } - - public boolean isEnabled() - { - return this.isEnabled; - } - - public void setEnabled(boolean enabled) - { - this.isEnabled = enabled; - } - - public LevelSet getLevels() - { - return this.levels; - } - - public final double getMaximumElevation() - { - return this.maxElevation; - } - - public final double getMinimumElevation() - { - return this.minElevation; - } - - public long getNumExpectedValuesPerTile() - { - return numExpectedValues; - } - - public void setNumExpectedValuesPerTile(long numExpectedValues) - { - this.numExpectedValues = numExpectedValues; - } - - // Create the tile corresponding to a specified key. - private Tile createTile(TileKey key) - { - Level level = this.levels.getLevel(key.getLevelNumber()); - - // Compute the tile's SW lat/lon based on its row/col in the level's data set. - Angle dLat = level.getTileDelta().getLatitude(); - Angle dLon = level.getTileDelta().getLongitude(); - - Angle minLatitude = Tile.computeRowLatitude(key.getRow(), dLat); - Angle minLongitude = Tile.computeColumnLongitude(key.getColumn(), dLon); - - Sector tileSector = new Sector(minLatitude, minLatitude.add(dLat), minLongitude, minLongitude.add(dLon)); - - return new Tile(tileSector, level, key.getRow(), key.getColumn()); - } - - // Thread off a task to determine whether the file is local or remote and then retrieve it either from the file - // cache or a remote server. - private void requestTile(TileKey key) - { - if (WorldWind.threadedTaskService().isFull()) - return; - - RequestTask request = new RequestTask(key, this); - WorldWind.threadedTaskService().addTask(request); - } - - private static class RequestTask implements Runnable - { - private final BasicElevationModel elevationModel; - private final TileKey tileKey; - - private RequestTask(TileKey tileKey, BasicElevationModel elevationModel) - { - this.elevationModel = elevationModel; - this.tileKey = tileKey; - } - - public final void run() - { - // check to ensure load is still needed - if (this.elevationModel.areElevationsInMemory(this.tileKey)) - return; - - Tile tile = this.elevationModel.createTile(this.tileKey); - final java.net.URL url = WorldWind.dataFileCache().findFile(tile.getPath(), false); - if (url != null) - { - if (this.elevationModel.loadElevations(tile, url)) - { - this.elevationModel.levels.unmarkResourceAbsent(tile); - this.elevationModel.firePropertyChange(AVKey.ELEVATION_MODEL, null, this); - return; - } - else - { - // Assume that something's wrong with the file and delete it. - gov.nasa.worldwind.WorldWind.dataFileCache().removeFile(url); - this.elevationModel.levels.markResourceAbsent(tile); - String message = WorldWind.retrieveErrMsg("generic.DeletedCorruptDataFile") + url; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - } - - this.elevationModel.downloadElevations(tile); - } - - public final boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final RequestTask that = (RequestTask) o; - - //noinspection RedundantIfStatement - if (this.tileKey != null ? !this.tileKey.equals(that.tileKey) : that.tileKey != null) - return false; - - return true; - } - - public final int hashCode() - { - return (this.tileKey != null ? this.tileKey.hashCode() : 0); - } - - public final String toString() - { - return this.tileKey.toString(); - } - } - - // Reads a tile's elevations from the file cache and adds the tile to the memory cache. - private boolean loadElevations(Tile tile, java.net.URL url) - { - java.nio.ShortBuffer elevations = this.readElevations(url); - if (elevations == null) - return false; - - if (this.numExpectedValues > 0 && elevations.capacity() != this.numExpectedValues) - return false; // corrupt file - - tile.elevations = elevations; - this.addTileToCache(tile, elevations); - - return true; - } - - private void addTileToCache(Tile tile, java.nio.ShortBuffer elevations) - { - // Level 0 tiles are held in the model itself; other levels are placed in the memory cache. - if (tile.getLevelNumber() == 0) - this.levelZeroTiles.putIfAbsent(tile.getTileKey(), tile); - else - this.memoryCache.add(tile.getTileKey(), tile, elevations.limit() * 2); - } - - private boolean areElevationsInMemory(TileKey key) - { - Tile tile = this.getTileFromMemory(key); - return (tile != null && tile.elevations != null); - } - - private Tile getTileFromMemory(TileKey tileKey) - { - if (tileKey.getLevelNumber() == 0) - return this.levelZeroTiles.get(tileKey); - else - return (Tile) this.memoryCache.getObject(tileKey); - } - - // Read elevations from the file cache. Don't be confused by the use of a URL here: it's used so that files can - // be read using System.getResource(URL), which will draw the data from a jar file in the classpath. - // TODO: Look into possibly moving the mapping to a URL into WWIO. - private java.nio.ShortBuffer readElevations(java.net.URL url) - { - try - { - java.nio.ByteBuffer buffer; - synchronized (this.fileLock) - { - buffer = gov.nasa.worldwind.WWIO.readURLContentToBuffer(url); - } - buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN); // TODO: byte order is format dependent - return buffer.asShortBuffer(); - } - catch (java.io.IOException e) - { - String message = WorldWind.retrieveErrMsg("TiledElevationModel.ExceptionAttemptingToReadTextureFile"); - WorldWind.logger().log(java.util.logging.Level.FINE, message + url); - return null; - } - } - - private void downloadElevations(final Tile tile) - { - if (WorldWind.retrievalService().isFull()) - return; - - java.net.URL url = null; - try - { - url = tile.getResourceURL(); - } - catch (java.net.MalformedURLException e) - { - String message = WorldWind.retrieveErrMsg("TiledElevationModel.ExceptionCreatingElevationsUrl"); - WorldWind.logger().log(java.util.logging.Level.FINE, message + url, e); - return; - } - - URLRetriever retriever = new HTTPRetriever(url, new DownloadPostProcessor(tile, this)); - if (WorldWind.retrievalService().contains(retriever)) - return; - - WorldWind.retrievalService().runRetriever(retriever, 0d); - } - - /** - * @param dc - * @param sector - * @param density - * @return - * @throws IllegalArgumentException if dc is null, sector is null or density is - * negative - */ - public final int getTargetResolution(DrawContext dc, Sector sector, int density) - { - if (!this.isEnabled) - return 0; - - if (dc == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (sector == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (density < 0) - { - String msg = WorldWind.retrieveErrMsg("BasicElevationModel.DensityBelowZero"); - WorldWind.logger().log(java.util.logging.Level.FINEST, msg); - } - - LatLon c = this.levels.getSector().getCentroid(); - double radius = dc.getGlobe().getRadiusAt(c.getLatitude(), c.getLongitude()); - double sectorWidth = sector.getDeltaLatRadians() * radius; - double targetSize = 0.8 * sectorWidth / (density); // TODO: make scale of density configurable - - for (Level level : this.levels.getLevels()) - { - if (level.getTexelSize(radius) < targetSize) - { - return level.getLevelNumber(); - } - } - - return this.levels.getNumLevels(); // finest resolution available - } - - private static class DownloadPostProcessor implements RetrievalPostProcessor - { - private Tile tile; - private BasicElevationModel elevationModel; - - public DownloadPostProcessor(Tile tile, BasicElevationModel elevationModel) - { - // don't validate - constructor is only available to classes with private access. - this.tile = tile; - this.elevationModel = elevationModel; - } - - /** - * @param retriever - * @return - * @throws IllegalArgumentException if retriever is null - */ - public ByteBuffer run(Retriever retriever) - { - if (retriever == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - try - { - if (!retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL)) - return null; - - if (retriever instanceof HTTPRetriever) - { - HTTPRetriever htr = (HTTPRetriever) retriever; - if (htr.getResponseCode() != HttpURLConnection.HTTP_OK) - { - // Mark tile as missing so avoid excessive attempts - this.elevationModel.levels.markResourceAbsent(this.tile); - return null; - } - } - - URLRetriever r = (URLRetriever) retriever; - ByteBuffer buffer = r.getBuffer(); - - final File outFile = WorldWind.dataFileCache().newFile(tile.getPath()); - if (outFile == null) - { - String msg = WorldWind.retrieveErrMsg("generic.CantCreateCacheFile") - + this.tile.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - return null; - } - - if (outFile.exists()) - return buffer; - - if (buffer != null) - { - synchronized (elevationModel.fileLock) - { - WWIO.saveBuffer(buffer, outFile); - } - return buffer; - } - } - catch (java.io.IOException e) - { - String message = WorldWind.retrieveErrMsg("TiledElevationModel.ExceptionSavingRetrievedElevationFile"); - WorldWind.logger().log(java.util.logging.Level.FINE, message + tile.getPath(), e); - } - finally - { - this.elevationModel.firePropertyChange(AVKey.ELEVATION_MODEL, null, this); - } - return null; - } - } - - private static class BasicElevations implements ElevationModel.Elevations - { - private final int resolution; - private final Sector sector; - private final BasicElevationModel elevationModel; - private java.util.Set tiles; - - private BasicElevations(Sector sector, int resolution, BasicElevationModel elevationModel) - { - this.sector = sector; - this.resolution = resolution; - this.elevationModel = elevationModel; - } - - public int getResolution() - { - return this.resolution; - } - - public Sector getSector() - { - return this.sector; - } - - public boolean hasElevations() - { - return this.tiles != null && this.tiles.size() > 0; - } - - public double getElevation(double latRadians, double lonRadians) - { - if (this.tiles == null) - return 0; - - try - { - // TODO: Tiles are sorted by level/row/column. Use that to find containing sector faster. - for (BasicElevationModel.Tile tile : this.tiles) - { - if (tile.getSector().containsRadians(latRadians, lonRadians)) - return this.elevationModel.lookupElevation(latRadians, lonRadians, tile); - } - - return 0; - } - catch (Exception e) - { - // Throwing an exception within what's likely to be the caller's geometry creation loop - // would be hard to recover from, and a reasonable response to the exception can be done here. - String message = WorldWind.retrieveErrMsg("BasicElevationModel.ExceptionComputingElevation"); - message += "(" + latRadians + ", " + lonRadians + ")"; - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - - return 0; - } - } - } - - /** - * @param latitude - * @param longitude - * @return - * @throws IllegalArgumentException if latitude or longitude is null - */ - public final double getElevation(Angle latitude, Angle longitude) - { - if (!this.isEnabled()) - return 0; - - if (latitude == null || longitude == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - // TODO: Make level to draw elevations from configurable - final TileKey tileKey = new TileKey(latitude, longitude, this.levels.getLastLevel()); - Tile tile = this.getTileFromMemory(tileKey); - - if (tile == null) - { - int fallbackRow = tileKey.getRow(); - int fallbackCol = tileKey.getColumn(); - for (int fallbackLevelNum = tileKey.getLevelNumber() - 1; fallbackLevelNum >= 0; fallbackLevelNum--) - { - fallbackRow /= 2; - fallbackCol /= 2; - TileKey fallbackKey = new TileKey(fallbackLevelNum, fallbackRow, fallbackCol, - this.levels.getLevel(fallbackLevelNum).getCacheName()); - tile = this.getTileFromMemory(fallbackKey); - if (tile != null) - break; - } - } - - if (tile == null) - { - final TileKey zeroKey = new TileKey(latitude, longitude, this.levels.getFirstLevel()); - this.requestTile(zeroKey); - - return 0; - } - - return this.lookupElevation(latitude.radians, longitude.radians, tile); - } - - /** - * @param sector - * @param resolution - * @return - * @throws IllegalArgumentException if sector is null - */ - public final Elevations getElevations(Sector sector, int resolution) - { - if (sector == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (!this.isEnabled()) - return new BasicElevations(sector, Integer.MIN_VALUE, this); - - // Collect all the elevation tiles intersecting the input sector. If a desired tile is not curently - // available, choose its next lowest resolution parent that is available. - final Level targetLevel = this.levels.getLevel(resolution); - - LatLon delta = this.levels.getLevel(resolution).getTileDelta(); - final int nwRow = Tile.computeRow(delta.getLatitude(), sector.getMaxLatitude()); - final int nwCol = Tile.computeColumn(delta.getLongitude(), sector.getMinLongitude()); - final int seRow = Tile.computeRow(delta.getLatitude(), sector.getMinLatitude()); - final int seCol = Tile.computeColumn(delta.getLongitude(), sector.getMaxLongitude()); - - java.util.TreeSet tiles = new java.util.TreeSet(); - java.util.ArrayList requested = new java.util.ArrayList(); - - boolean missingTargetTiles = false; - boolean missingLevelZeroTiles = false; - for (int row = seRow; row <= nwRow; row++) - { - for (int col = nwCol; col <= seCol; col++) - { - TileKey key = new TileKey(resolution, row, col, targetLevel.getCacheName()); - Tile tile = this.getTileFromMemory(key); - if (tile != null) - { - tiles.add(tile); - continue; - } - - missingTargetTiles = true; - this.requestTile(key); - - // Determine the fallback to use. Simultaneously determine a fallback to request that is - // the next resolution higher than the fallback chosen, if any. This will progressively - // refine the display until the desired resolution tile arrives. - TileKey fallbackToRequest = null; - TileKey fallbackKey = null; - - int fallbackRow = row; - int fallbackCol = col; - for (int fallbackLevelNum = key.getLevelNumber() - 1; fallbackLevelNum >= 0; fallbackLevelNum--) - { - fallbackRow /= 2; - fallbackCol /= 2; - fallbackKey = new TileKey(fallbackLevelNum, fallbackRow, fallbackCol, this.levels.getLevel( - fallbackLevelNum).getCacheName()); - tile = this.getTileFromMemory(fallbackKey); - if (tile != null) - { - if (!tiles.contains(tile)) - tiles.add(tile); - break; - } - else - { - if (fallbackLevelNum == 0) - missingLevelZeroTiles = true; - fallbackToRequest = fallbackKey; // keep track of lowest level to request - } - } - - if (fallbackToRequest != null) - { - if (!requested.contains(fallbackKey)) - { - this.requestTile(fallbackKey); - requested.add(fallbackKey); // keep track to avoid overhead of duplicte requests - } - } - } - } - - BasicElevations elevations; - -// int lev = tiles.size() > 0 ? tiles.first().getLevelNumber() : 0; -// System.out.printf("%d tiles, target = %d (%d, %d), level %d, target = %d\n", tiles.size(), -// (1 + nwRow - seRow) * (1 + seCol - nwCol), nwRow - seRow, seCol - nwCol, -// lev, targetLevel.getLevelNumber()); - - if (missingLevelZeroTiles || tiles.isEmpty()) - { - // Integer.MIN_VALUE is a signal for no in-memory tile for a given region of the sector. - elevations = new BasicElevations(sector, Integer.MIN_VALUE, this); - } - else if (missingTargetTiles) - { - // Use the level of the the lowest resolution found as the resolution for this elevation set. - // The list of tiles is sorted first by level, so use the level of the list's first entry. - elevations = new BasicElevations(sector, tiles.first().getLevelNumber(), this); - } - else - { - elevations = new BasicElevations(sector, resolution, this); - } - - elevations.tiles = tiles; - - return elevations; - } - - public final Elevations getElevationsAtResolution(Sector sector, int resolution) - { - int targetResolution = Math.min(resolution, this.getLevels().getLastLevel().getLevelNumber()); - Elevations elevs = this.getElevations(sector, targetResolution); - return elevs.getResolution() == targetResolution ? elevs : null; - } - - public final Elevations getBestElevations(Sector sector) - { - return this.getElevationsAtResolution(sector, this.getLevels().getLastLevel().getLevelNumber()); - } - - private double lookupElevation(final double latRadians, final double lonRadians, final Tile tile) - { - Sector sector = tile.getSector(); - final int tileHeight = tile.getLevel().getTileHeight(); - final int tileWidth = tile.getLevel().getTileWidth(); - final double sectorDeltaLat = sector.getDeltaLat().radians; - final double sectorDeltaLon = sector.getDeltaLon().radians; - final double dLat = sector.getMaxLatitude().radians - latRadians; - final double dLon = lonRadians - sector.getMinLongitude().radians; - final double sLat = dLat / sectorDeltaLat; - final double sLon = dLon / sectorDeltaLon; - - int j = (int) ((tileHeight - 1) * sLat); - int i = (int) ((tileWidth - 1) * sLon); - int k = j * tileWidth + i; - - double eLeft = tile.elevations.get(k); - double eRight = i < (tileWidth - 1) ? tile.elevations.get(k + 1) : eLeft; - - double dw = sectorDeltaLon / (tileWidth - 1); - double dh = sectorDeltaLat / (tileHeight - 1); - double ssLon = (dLon - i * dw) / dw; - double ssLat = (dLat - j * dh) / dh; - - double eTop = eLeft + ssLon * (eRight - eLeft); - - if (j < tileHeight - 1 && i < tileWidth - 1) - { - eLeft = tile.elevations.get(k + tileWidth); - eRight = tile.elevations.get(k + tileWidth + 1); - } - - double eBot = eLeft + ssLon * (eRight - eLeft); - return eTop + ssLat * (eBot - eTop); - } -} diff --git a/gov/nasa/worldwind/BasicFrameController.java b/gov/nasa/worldwind/BasicFrameController.java deleted file mode 100644 index 3f26fb8..0000000 --- a/gov/nasa/worldwind/BasicFrameController.java +++ /dev/null @@ -1,91 +0,0 @@ -/* -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; - -import javax.media.opengl.*; - -/** - * @author Tom Gaskins - * @version $Id: BasicFrameController.java 1941 2007-06-02 08:52:28Z tgaskins $ - */ -public class BasicFrameController implements FrameController -{ - public void initializeFrame(DrawContext dc) - { - if (null == dc) - { - String msg = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - javax.media.opengl.GL gl = dc.getGL(); - - gl.glPushAttrib(GL.GL_VIEWPORT_BIT | GL.GL_ENABLE_BIT | GL.GL_TRANSFORM_BIT); - - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPushMatrix(); - gl.glLoadIdentity(); - - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPushMatrix(); - gl.glLoadIdentity(); - - gl.glEnable(GL.GL_DEPTH_TEST); - } - - public void finalizeFrame(DrawContext dc) - { - if (null == dc) - { - String msg = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - GL gl = dc.getGL(); - - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPopMatrix(); - - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPopMatrix(); - - gl.glPopAttrib(); - - gl.glFlush(); - -// checkGLErrors(dc); - } - - /** - * Called to check for openGL errors. This method includes a "round-trip" between the application and renderer, - * which is slow. Therefore, this method is excluded from the "normal" render pass. It is here as a matter of - * convenience to developers, and is not part of the API. - * - * @param dc the relevant DrawContext - */ - @SuppressWarnings({"UNUSED_SYMBOL", "UnusedDeclaration"}) - private void checkGLErrors(DrawContext dc) - { - GL gl = dc.getGL(); - int err = gl.glGetError(); - if (err != GL.GL_NO_ERROR) - { - String msg = dc.getGLU().gluErrorString(err); - msg += err; - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - } - } - - public void clearFrame(DrawContext dc) - { - java.awt.Color cc = dc.getClearColor(); - dc.getGL().glClearColor(cc.getRed(), cc.getGreen(), cc.getBlue(), cc.getAlpha()); - dc.getGL().glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - } -} diff --git a/gov/nasa/worldwind/BasicMemoryCache.java b/gov/nasa/worldwind/BasicMemoryCache.java deleted file mode 100644 index 61d9657..0000000 --- a/gov/nasa/worldwind/BasicMemoryCache.java +++ /dev/null @@ -1,411 +0,0 @@ -/* -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; - -//TODO: write class javadoc description. Remember to include info on: synchronisation, lowWater. - -/** - * @author Eric Dalgliesh - * @version $Id: BasicMemoryCache.java 1792 2007-05-08 21:28:37Z tgaskins $ - */ -public final class BasicMemoryCache implements MemoryCache -{ - private static long FALLBACK_CACHE_SIZE = 60000000; // less than applet default max heap size - - private static class CacheEntry implements Comparable - { - Object key; - Object clientObject; - private long lastUsed; - private long clientObjectSize; - - CacheEntry(Object key, Object clientObject, long clientObjectSize) - { - this.key = key; - this.clientObject = clientObject; - this.lastUsed = System.nanoTime(); - this.clientObjectSize = clientObjectSize; - } - - /** - * @param that - * @return - * @throws IllegalArgumentException if that is null - */ - public int compareTo(CacheEntry that) - { - if (that == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.CacheEntryIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - return this.lastUsed < that.lastUsed ? -1 : this.lastUsed == that.lastUsed ? 0 : 1; - } - - public String toString() - { - return key.toString() + " " + clientObject.toString() + " " + lastUsed + " " + clientObjectSize; - } - } - - private java.util.concurrent.ConcurrentHashMap entries; - private java.util.concurrent.CopyOnWriteArrayList listeners; - private Long capacityInBytes; - private Long currentUsedCapacity; - private Long lowWater; - - /** - * Contructs a new self-configuring cache. Configuration can be done manually later. - */ - public BasicMemoryCache() - { - this.entries = new java.util.concurrent.ConcurrentHashMap(); - this.listeners = new java.util.concurrent.CopyOnWriteArrayList(); - this.capacityInBytes = Configuration.getLongValue(AVKey.CACHE_SIZE, FALLBACK_CACHE_SIZE); - this.lowWater = Configuration.getLongValue(AVKey.CACHE_LOW_WATER, (long)(0.7 * FALLBACK_CACHE_SIZE)); - this.currentUsedCapacity = (long) 0; - } - - /** - * Constructs a new cache using capacity for maximum size, and loWater for the low water. - * - * @param loWater the low water level - * @param capacity the maximum capacity - */ - public BasicMemoryCache(long loWater, long capacity) - { - this.entries = new java.util.concurrent.ConcurrentHashMap(); - this.listeners = new java.util.concurrent.CopyOnWriteArrayList(); - this.capacityInBytes = capacity; - this.lowWater = loWater; - this.currentUsedCapacity = (long) 0; - } - - /** - * @return the number of objects currently stored in this cache - */ - public int getNumObjects() - { - return this.entries.size(); - } - - /** - * @return the capacity of the cache in bytes - */ - public long getCapacity() - { - return this.capacityInBytes; - } - - /** - * @return the number of bytes that the cache currently holds - */ - public synchronized long getUsedCapacity() - { - return this.currentUsedCapacity; - } - - /** - * @return the amount of free space left in the cache (in bytes) - */ - public synchronized long getFreeCapacity() - { - return this.capacityInBytes - this.currentUsedCapacity; - } - - /** - * Adds a cache listener, MemoryCache listeners are used to notify classes when an item is removed from the cache. - * - * @param listener The new CacheListener - * @throws IllegalArgumentException is listener is null - */ - public synchronized void addCacheListener(MemoryCache.CacheListener listener) - { - if (listener == null) - { - String message = WorldWind.retrieveErrMsg("BasicMemoryCache.nullListenerAdded"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.listeners.add(listener); - } - - /** - * Removes a cache listener, objects using this listener will no longer receive notification of cache events. - * - * @param listener The CacheListener to remove - * @throws IllegalArgumentException if listener is null - */ - public synchronized void removeCacheListener(MemoryCache.CacheListener listener) - { - if (listener == null) - { - String message = WorldWind.retrieveErrMsg("BasicMemoryCache.nullListenerRemoved"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.listeners.remove(listener); - } - - /** - * Sets the new capacity (in bytes) for the cache. When decreasing cache size, it is recommended to check that the - * lowWater variable is suitable. If the capacity infringes on items stored in the cache, these items are removed. - * Setting a new low water is up to the user, that is, it remains unchanged and may be higher than the maximum - * capacity. When the low water level is higher than or equal to the maximum capacity, it is ignored, which can lead - * to poor performance when adding entries. - * - * @param newCapacity the new capacity of the cache. - */ - public synchronized void setCapacity(long newCapacity) - { - this.makeSpace(this.capacityInBytes - newCapacity); - this.capacityInBytes = newCapacity; - } - - /** - * Sets the new low water level in bytes, which controls how aggresively the cache discards items. - *

- * When the cache fills, it removes items until it reaches the low water level. - *

- * Setting a high loWater level will increase cache misses, but decrease average add time, but setting a low loWater - * will do the opposite. - * - * @param loWater the new low water level in bytes. - */ - public synchronized void setLowWater(long loWater) - { - if (loWater < this.capacityInBytes && loWater >= 0) - { - this.lowWater = loWater; - } - } - - /** - * Returns the low water level in bytes. When the cache fills, it removes items until it reaches the low water - * level. - * - * @return the low water level in bytes. - */ - public long getLowWater() - { - return this.lowWater; - } - - /** - * Returns true if the cache contains the item referenced by key. No guarantee is made as to whether or not the item - * will remain in the cache for any period of time. - *

- * This function does not cause the object referenced by the key to be marked as accessed. getObject() - * should be used for that purpose - * - * @param key The key of a specific object - * @return true if the cache holds the item referenced by key - * @throws IllegalArgumentException if key is null - */ - public boolean contains(Object key) - { - if (key == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.KeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - return this.entries.containsKey(key); - } - - /** - * Adds an object to the cache. The add fails if the object or key is null, or if the size is zero, negative or - * greater than the maximmum capacity - * - * @param key The unique reference key that identifies this object. - * @param clientObject The actual object to be cached. - * @param clientObjectSize The size of the object in bytes. - * @return returns true if clientObject was added, false otherwise. - */ - public synchronized boolean add(Object key, Object clientObject, long clientObjectSize) - { - if (key == null || clientObject == null || clientObjectSize <= 0 || clientObjectSize > this.capacityInBytes) - { - String msg = WorldWind.retrieveErrMsg("BasicMemoryCache.CacheItemNotAdded"); - WorldWind.logger().log(java.util.logging.Level.FINER, msg); - - return false; - // the logic behind not throwing an exception is that whether we throw an exception or not, - // the object won't be added. This doesn't matter because that object could be removed before - // it is accessed again anyway. - } - - CacheEntry existing = this.entries.get(key); - if (existing != null) // replacing - { - this.removeEntry(existing); - } - - if (this.currentUsedCapacity + clientObjectSize > this.capacityInBytes) - { - this.makeSpace(clientObjectSize); - } - - this.currentUsedCapacity += clientObjectSize; - BasicMemoryCache.CacheEntry entry = new BasicMemoryCache.CacheEntry(key, clientObject, clientObjectSize); - this.entries.putIfAbsent(entry.key, entry); - return true; - } - - public synchronized boolean add(Object key, gov.nasa.worldwind.Cacheable clientObject) - { - return this.add(key, clientObject, clientObject.getSizeInBytes()); - } - - /** - * Remove the object reference by key from the cache. If no object with the corresponding key is found, this method - * returns immediately. - * - * @param key the key of the object to be removed - * @throws IllegalArgumentException if key is null - */ - public synchronized void remove(Object key) - { - if (key == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.KeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINER, msg); - - return; - } - - CacheEntry entry = this.entries.get(key); - if (entry != null) - this.removeEntry(entry); - } - - /** - * Obtain the object referenced by key without removing it. Apart from adding an object, this is the only way to - * mark an object as recently used. - * - * @param key The key for the object to be found. - * @return the object referenced by key if it is present, null otherwise. - * @throws IllegalArgumentException if key is null - */ - public synchronized Object getObject(Object key) - { - if (key == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.KeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINER, msg); - - return null; - } - - CacheEntry entry = this.entries.get(key); - - if (entry == null) - return null; - - entry.lastUsed = System.nanoTime(); // nanoTime overflows once every 292 years - // which will result in a slowing of the cache - // until ww is restarted or the cache is cleared. - return entry.clientObject; - } - - /** - * Obtain a list of all the keys in the cache. - * - * @return a Set of all keys in the cache. - */ - public java.util.Set getKeySet() - { - return this.entries.keySet(); - } - - /** - * Empties the cache. - */ - public synchronized void clear() - { - for (CacheEntry entry : this.entries.values()) - { - this.removeEntry(entry); - } - } - - /** - * Removes entry from the cache. To remove an entry using its key, use remove() - * - * @param entry The entry (as opposed to key) of the item to be removed - */ - private synchronized void removeEntry(CacheEntry entry) - { - // all removal passes through this function, - // so the reduction in "currentUsedCapacity" and listener notification is done here - - if (this.entries.remove(entry.key) != null) // returns null if entry does not exist - { - this.currentUsedCapacity -= entry.clientObjectSize; - - for (MemoryCache.CacheListener listener : this.listeners) - { - listener.entryRemoved(entry.key, entry.clientObject); - } - } - } - - /** - * Makes at least spaceRequired space in the cache. If spaceRequired is less than (capacity-lowWater), - * makes more space. Does nothing if capacity is less than spaceRequired. - * - * @param spaceRequired the amount of space required. - */ - private void makeSpace(long spaceRequired) - { - if (spaceRequired > this.capacityInBytes || spaceRequired < 0) - return; - - CacheEntry[] timeOrderedEntries = new CacheEntry[this.entries.size()]; - java.util.Arrays.sort(this.entries.values().toArray(timeOrderedEntries)); - - int i = 0; - while (this.getFreeCapacity() < spaceRequired || this.getUsedCapacity() > this.lowWater) - { - if (i < timeOrderedEntries.length) - { - this.removeEntry(timeOrderedEntries[i++]); - } - } - } - - /** - * a String representation of this object is returned.  This representation consists of maximum - * size, current used capacity and number of currently cached items. - * - * @return a String representation of this object - */ - @Override - public synchronized String toString() - { - return "MemoryCache max size = " + this.getCapacity() + " current size = " + this.currentUsedCapacity - + " number of items: " + this.getNumObjects(); - } - - @Override - protected void finalize() throws Throwable - { - try - { - // clear doesn't throw any checked exceptions - // but this is in case of an unchecked exception - // basically, we don't want to exit without calling super.finalize - this.clear(); - } - finally - { - super.finalize(); - } - } -} diff --git a/gov/nasa/worldwind/BasicOrbitView.java b/gov/nasa/worldwind/BasicOrbitView.java deleted file mode 100644 index 68d2fea..0000000 --- a/gov/nasa/worldwind/BasicOrbitView.java +++ /dev/null @@ -1,410 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.util.logging.Level; - -/** - * @author dcollins - * @version $Id: BasicOrbitView.java 2126 2007-06-21 21:00:42Z dcollins $ - */ -public class BasicOrbitView extends AbstractView -{ - // Viewing attributes. - private Matrix modelView = Matrix.IDENTITY; - private Matrix projection = Matrix.IDENTITY; - private Frustum frustum = null; - private double collisionRadius = -1; - // Attribute constants. - private static final double MIN_NEAR_CLIP_DISTANCE = 10.0; - - // ============== Viewing State ======================= // - // ============== Viewing State ======================= // - // ============== Viewing State ======================= // - - protected void doApply(DrawContext dc) - { - // Update viewing state. - if (!dc.isPickingMode()) - { - this.updateViewingState(dc); - this.updateAttributes(dc); - } - // Set current GL viewing state. - this.loadModelViewProjection(dc, this.modelView, this.projection); - } - - protected void doInitialize(DrawContext dc) - { - this.initializeAttributes(dc); - } - - public Frustum getFrustum() - { - return this.frustum; - } - - private void updateViewingState(DrawContext dc) - { - // Update the model-view matrix. - this.modelView = this.computeModelViewMatrix(dc); - - // Compute current viewing attributes. - Vec4 eyeVec = Vec4.UNIT_W.transformBy4(this.modelView.getInverse()); - double nearClipDist = this.computeNearClipDistance(dc, eyeVec); - double farClipDist = this.computeFarClipDistance(dc, eyeVec); - - Angle fov = this.getFieldOfView(); - java.awt.Rectangle viewport = this.getViewport(); - // Update the frustum and projection-matrix from a standard perspective projection. - this.projection = Matrix.fromPerspective( - fov, - viewport.width, viewport.height, - nearClipDist, farClipDist); - this.frustum = Frustum.fromPerspective( - fov, viewport.width, viewport.height, - nearClipDist, farClipDist); - - // Update the collision radius. - if (this.collisionRadius < 0.0) - this.collisionRadius = this.computeCollisionRadius(MIN_NEAR_CLIP_DISTANCE); - } - - // ============== Attribute Accessors ======================= // - // ============== Attribute Accessors ======================= // - // ============== Attribute Accessors ======================= // - - // Geographic coordinate data. - private Angle focusLat = null; - private Angle focusLon = null; - private double eyeDist = -1; - private Angle heading = null; - private Angle pitch = null; - private double altitude = -1; - - private void initializeAttributes(DrawContext dc) - { - this.focusLat = getInitialLatitude(dc, this.focusLat); - this.focusLon = getInitialLongitude(dc, this.focusLon); - this.altitude = getInitialAltitude(dc, this.altitude); - this.eyeDist = this.altitude; - this.heading = getInitialHeading(dc, this.heading); - this.pitch = getInitialPitch(dc, this.pitch); - } - - private void updateAttributes(DrawContext dc) - { - } - - public Angle getLatitude() - { - return this.focusLat; - } - - public void setLatitude(Angle newLatitude) - { - if (newLatitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.focusLat = this.normalizeLatitude(newLatitude); - } - - public Angle getLongitude() - { - return this.focusLon; - } - - public void setLongitude(Angle newLongitude) - { - if (newLongitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.focusLon = this.normalizeLongitude(newLongitude); - } - - public double getAltitude() - { - return this.altitude; - } - - public void setAltitude(double newAltitude) - { - throw new UnsupportedOperationException(); - } - - public void setLatLon(LatLon newLatLon) - { - if (newLatLon == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LatLonIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.setLatitude(newLatLon.getLatitude()); - this.setLongitude(newLatLon.getLongitude()); - } - - public void setLatLonAltitude(Position newPosition) - { - throw new UnsupportedOperationException(); - } - - public Angle getHeading() - { - return this.heading; - } - - public void setHeading(Angle newHeading) - { - if (newHeading == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.heading = this.normalizeHeading(newHeading); - } - - public Angle getPitch() - { - return this.pitch; - } - - public void setPitch(Angle newPitch) - { - if (newPitch == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.pitch = this.normalizePitch(newPitch); - } - - public Angle getRoll() - { - return Angle.ZERO; - } - - public void setRoll(Angle newRoll) - { - } - - public double getZoom() - { - return this.eyeDist; - } - - public void setZoom(double newZoom) - { - this.eyeDist = this.normalizeZoom(newZoom); - } - - // ============== Attribute Normalizing ======================= // - // ============== Attribute Normalizing ======================= // - // ============== Attribute Normalizing ======================= // - - public Angle normalizeLatitude(Angle latitude) - { - return clamp(latitude, Angle.NEG90, Angle.POS90); - } - - public Angle normalizeLongitude(Angle longitude) - { - return normalize(longitude, Angle.NEG180, Angle.POS180); - } - - public double normalizeAltitude(double altitude) - { - return altitude; - } - - public Angle normalizeHeading(Angle heading) - { - if (heading == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - return normalize(heading, Angle.ZERO, Angle.POS360); - } - - public Angle normalizePitch(Angle pitch) - { - return clamp(pitch, Angle.ZERO, Angle.POS90); - } - - public Angle normalizeRoll(Angle roll) - { - return roll; - } - - public double normalizeZoom(double zoom) - { - return Math.max(this.collisionRadius, zoom); - } - - private static Angle clamp(Angle value, Angle min, Angle max) - { - if (value.compareTo(min) < 0) - return min; - else if (value.compareTo(max) > 0) - return max; - return value; - } - - private static Angle normalize(Angle value, Angle min, Angle max) - { - if (value.compareTo(min) < 0) - return value.add(max).subtract(min); - else if (value.compareTo(max) > 0) - return value.subtract(max).add(min); - return value; - } - - // ============== Viewing Transforms ======================= // - // ============== Viewing Transforms ======================= // - // ============== Viewing Transforms ======================= // - - private Matrix computeModelViewMatrix(DrawContext dc) - { - Globe globe = dc.getGlobe(); - if (globe == null) - return null; - - Vec4 focusPoint = globe.computePointFromPosition(this.focusLat, this.focusLon, 0); - if (focusPoint == null) - { - String message = WorldWind.retrieveErrMsg("BasicOrbitView.NullSurfacePoint"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalStateException(message); - } - - Matrix modelView = lookAt(this.focusLat, this.focusLon, focusPoint.getLength3(), - this.eyeDist, this.heading, this.pitch); - Vec4 eyeVec = Vec4.UNIT_W.transformBy4(modelView.getInverse()); - Position polarEye = globe.computePositionFromPoint(eyeVec); - - Vec4 surfacePoint = computeSurfacePoint(dc, polarEye.getLatitude(), polarEye.getLongitude()); - if (surfacePoint != null) - { - double distanceToSurface = eyeVec.getLength3() - this.collisionRadius - surfacePoint.getLength3(); - if (distanceToSurface < 0.0) - { - Vec4 surfaceNormal = eyeVec.normalize3(); - Vec4 newEye = Vec4.fromLine3(Vec4.ZERO, eyeVec.getLength3() - distanceToSurface, surfaceNormal); - Vec4 forward = eyeVec.subtract3(focusPoint); - Vec4 newForward = newEye.subtract3(focusPoint); - double dot = forward.dot3(newForward) / (forward.getLength3() * newForward.getLength3()); - if (dot >= -1.0 && dot <= 1.0) - { - double pitchChange = Math.acos(dot); - this.pitch = clamp(this.pitch.subtract(Angle.fromRadians(pitchChange)), Angle.ZERO, Angle.POS90); - this.eyeDist = Math.max(this.collisionRadius, newForward.getLength3()); - modelView = lookAt(this.focusLat, this.focusLon, focusPoint.getLength3(), this.eyeDist, - this.heading, this.pitch); - } - } - } - - // Compute the current eyeVec altitude above sea level (Globe radius). - eyeVec = Vec4.UNIT_W.transformBy4(modelView.getInverse()); - polarEye = globe.computePositionFromPoint(eyeVec); - this.altitude = eyeVec.getLength3() - globe.getRadiusAt(polarEye.getLatitude(), polarEye.getLongitude()); - - return modelView; - } - - private static Matrix lookAt(Angle focusX, Angle focusY, double focusDistance, - double tiltDistance, Angle tiltZ, Angle tiltX) - { - Matrix m = Matrix.IDENTITY; - // Translate model away from eye. - m = m.multiply(Matrix.fromTranslation(0, 0, -tiltDistance)); - // Apply tilt by rotating about X axis at pivot point. - m = m.multiply(Matrix.fromRotationX(tiltX.multiply(-1))); - m = m.multiply(Matrix.fromRotationZ(tiltZ)); - m = m.multiply(Matrix.fromTranslation(0, 0, -focusDistance)); - // Rotate model to lat/lon of eye point. - m = m.multiply(Matrix.fromRotationX(focusX)); - m = m.multiply(Matrix.fromRotationY(focusY.multiply(-1))); - return m; - } - - // ============== Utilities ======================= // - // ============== Utilities ======================= // - // ============== Utilities ======================= // - - private double computeNearClipDistance(DrawContext dc, Vec4 eyeVec) - { - Angle fov = this.getFieldOfView(); - if (fov == null) - return MIN_NEAR_CLIP_DISTANCE; - - // Compute the most distant near clipping plane. - double tanHalfFov = fov.tanHalfAngle(); - return Math.max( - MIN_NEAR_CLIP_DISTANCE, - this.altitude / (2 * Math.sqrt(2 * tanHalfFov * tanHalfFov + 1))); - } - - private double computeFarClipDistance(DrawContext dc, Vec4 eyeVec) - { - // Compute the closest allowable far clipping plane distance. - return this.computeHorizonDistance(dc.getGlobe(), dc.getVerticalExaggeration(), eyeVec); - } - - private double computeCollisionRadius(double nearClipDistance) - { - final double MIN_COLLISION_RADIUS = 1; - - java.awt.Rectangle viewport = this.getViewport(); - Angle fov = this.getFieldOfView(); - if (viewport == null || fov == null) - return MIN_COLLISION_RADIUS; - - if (nearClipDistance <= 0) - nearClipDistance = MIN_COLLISION_RADIUS; - - // Compute the distance between the eye, and any corner on the near clipping rectangle. - double tanHalfFov = fov.tanHalfAngle(); - double clipRectX = nearClipDistance * tanHalfFov; - double clipRectY = viewport.height * clipRectX / (double) viewport.width; - return 1 + Math.sqrt(clipRectX * clipRectX + clipRectY * clipRectY + nearClipDistance * nearClipDistance); - } - - private static Vec4 computeSurfacePoint(DrawContext dc, Angle lat, Angle lon) - { - SectorGeometryList sg = dc.getSurfaceGeometry(); - if (sg != null) - { - Vec4 vec = sg.getSurfacePoint(lat, lon); - if (vec != null) - return vec; - } - - Globe globe = dc.getGlobe(); - if (globe == null) - return null; - - double elevation = dc.getVerticalExaggeration() * globe.getElevation(lat, lon); - return globe.computePointFromPosition(lat, lon, elevation); - } - - public LatLon computeVisibleLatLonRange() - { - return null; // TODO - } -} diff --git a/gov/nasa/worldwind/BasicRetrievalService.java b/gov/nasa/worldwind/BasicRetrievalService.java deleted file mode 100644 index 0e7bae5..0000000 --- a/gov/nasa/worldwind/BasicRetrievalService.java +++ /dev/null @@ -1,507 +0,0 @@ -/* -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; - -/** - * Performs threaded retrieval of data. - * - * @author Tom Gaskins - * @version $Id: BasicRetrievalService.java 1985 2007-06-09 00:33:37Z tgaskins $ - */ -public final class BasicRetrievalService extends WWObjectImpl - implements RetrievalService, Thread.UncaughtExceptionHandler -{ - // These constants are last-ditch values in case Configuration lacks defaults - private static final int DEFAULT_QUEUE_SIZE = 100; - private static final int DEFAULT_POOL_SIZE = 5; - private static final long DEFAULT_STALE_REQUEST_LIMIT = 30000; // milliseconds - private static final int DEFAULT_TIME_PRIORITY_GRANULARITY = 500; // milliseconds - - private static final String RUNNING_THREAD_NAME_PREFIX = WorldWind.retrieveMessage( - "BasicRetrievalService.RUNNING_THREAD_NAME_PREFIX", "ThreadStrings"); - private static final String IDLE_THREAD_NAME_PREFIX = WorldWind.retrieveMessage( - "BasicRetrievalService.IDLE_THREAD_NAME_PREFIX", "ThreadStrings"); - - private RetrievalExecutor executor; // thread pool for running retrievers - private java.util.concurrent.ConcurrentLinkedQueue activeTasks; // tasks currently allocated a thread - private int queueSize; // maximum queue size - - /** - * Encapsulates a single threaded retrieval as a {@link java.util.concurrent.FutureTask}. - */ - private static class RetrievalTask extends java.util.concurrent.FutureTask - implements RetrievalFuture, Comparable - { - private Retriever retriever; - private double priority; // retrieval secondary priority (primary priority is submit time) - - private RetrievalTask(Retriever retriever, double priority) - { - super(retriever); - this.retriever = retriever; - this.priority = priority; - } - - public double getPriority() - { - return priority; - } - - public Retriever getRetriever() - { - return this.retriever; - } - - public void setException(Throwable throwable) - { - super.setException(throwable); - } - - @Override - public void run() - { - if (this.isDone() || this.isCancelled()) - return; - - super.run(); - } - - /** - * @param that the task to compare with this one - * @return 0 if task priorities are equal, -1 if priority of this is less than that, 1 otherwise - * @throws IllegalArgumentException if that is null - */ - public int compareTo(RetrievalTask that) - { - if (that == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (this.priority > 0 && that.priority > 0) // only secondary priority used if either is negative - { - // Requests submitted within different time-granularity periods are ordered exclusive of their - // client-specified priority. - long now = System.currentTimeMillis(); - long thisElapsedTime = now - this.retriever.getSubmitTime(); - long thatElapsedTime = now - that.retriever.getSubmitTime(); - if (((thisElapsedTime - thatElapsedTime) / DEFAULT_TIME_PRIORITY_GRANULARITY) != 0) - return thisElapsedTime < thatElapsedTime ? -1 : 1; - } - - // The client-pecified priority is compared for requests submitted within the same granularity period. - return this.priority == that.priority ? 0 : this.priority < that.priority ? -1 : 1; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final RetrievalTask that = (RetrievalTask) o; - - // Tasks are equal if their retrievers are equivalent - return this.retriever.equals(that.retriever); - // Priority and submint time are not factors in equality - } - - public int hashCode() - { - return this.retriever.getName().hashCode(); - } - } - - public void uncaughtException(Thread thread, Throwable throwable) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.UncaughtExceptionDuringRetrieval") - + thread.getName(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - - private class RetrievalExecutor extends java.util.concurrent.ThreadPoolExecutor - { - private static final long THREAD_TIMEOUT = 2; // keep idle threads alive this many seconds - private long staleRequestLimit; // reject requests older than this - - private RetrievalExecutor(int poolSize, int queueSize) - { - super(poolSize, poolSize, THREAD_TIMEOUT, java.util.concurrent.TimeUnit.SECONDS, - new java.util.concurrent.PriorityBlockingQueue(queueSize), - new java.util.concurrent.ThreadFactory() - { - public Thread newThread(Runnable runnable) - { - Thread thread = new Thread(runnable); - thread.setDaemon(true); - thread.setPriority(Thread.MIN_PRIORITY); - thread.setUncaughtExceptionHandler(BasicRetrievalService.this); - return thread; - } - }, new java.util.concurrent.ThreadPoolExecutor.DiscardPolicy() // abandon task when queue is full - { - // This listener is invoked only when the executor queue is a bounded queue and runs out of room. - // If the queue is a java.util.concurrent.PriorityBlockingQueue, this listener is never invoked. - public void rejectedExecution(Runnable runnable, - java.util.concurrent.ThreadPoolExecutor threadPoolExecutor) - { - // Interposes logging for rejected execution - RetrievalTask task = (RetrievalTask) runnable; - String name = task.getRetriever().getName(); - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.ResourceRejected") + name; - WorldWind.logger().log(java.util.logging.Level.FINER, message); - - super.rejectedExecution(runnable, threadPoolExecutor); - } - }); - - this.staleRequestLimit = Configuration.getLongValue(AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT, - DEFAULT_STALE_REQUEST_LIMIT); - } - - /** - * @param thread the thread the task is running on - * @param runnable the Retriever running on the thread - * @throws IllegalArgumentException if either thread or runnable is null - */ - protected void beforeExecute(Thread thread, Runnable runnable) - { - WorldWind.logger().log(java.util.logging.Level.FINEST, WorldWind.retrieveErrMsg( - "BasicRetrievalService.EnteringBeforeExecute")); - - if (thread == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ThreadIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (runnable == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RunnableIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - RetrievalTask task = (RetrievalTask) runnable; - - task.retriever.setBeginTime(System.currentTimeMillis()); - long limit = task.retriever.getStaleRequestLimit() >= 0 - ? task.retriever.getStaleRequestLimit() : this.staleRequestLimit; - if (task.retriever.getBeginTime() - task.retriever.getSubmitTime() > limit) - { - // Task has been sitting on the queue too long - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.CancellingTooOldRetrieval") - + task.getRetriever().getName(); - WorldWind.logger().log(java.util.logging.Level.FINER, message); - task.cancel(true); - } - - if (BasicRetrievalService.this.activeTasks.contains(task)) - { - // Task is a duplicate - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.CancellingDuplicateRetrieval") + task - .getRetriever().getName(); - WorldWind.logger().log(java.util.logging.Level.FINER, message); - task.cancel(true); - } - - BasicRetrievalService.this.activeTasks.add(task); - - thread.setName(RUNNING_THREAD_NAME_PREFIX + task.getRetriever().getName()); - thread.setPriority(Thread.MIN_PRIORITY); // Subordinate thread priority to rendering - thread.setUncaughtExceptionHandler(BasicRetrievalService.this); - - super.beforeExecute(thread, runnable); - - WorldWind.logger().log(java.util.logging.Level.FINEST, WorldWind.retrieveErrMsg( - "BasicRetrievalService.LeavingBeforeExecute")); - } - - /** - * @param runnable the Retriever running on the thread - * @param throwable an exception thrown during retrieval, will be null if no exception occurred - * @throws IllegalArgumentException if runnable is null - */ - protected void afterExecute(Runnable runnable, Throwable throwable) - { - WorldWind.logger().log(java.util.logging.Level.FINEST, WorldWind.retrieveErrMsg( - "BasicRetrievalService.EnteringAfterExecute")); - - if (runnable == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RunnableIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - super.afterExecute(runnable, throwable); - - RetrievalTask task = (RetrievalTask) runnable; - BasicRetrievalService.this.activeTasks.remove(task); - task.retriever.setEndTime(System.currentTimeMillis()); - - try - { - if (throwable != null) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.ExceptionDuringRetrieval") + task - .getRetriever().getName(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, throwable); - } - - task.get(); // Wait for task to finish, cancel or break - } - catch (java.util.concurrent.ExecutionException e) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.ExecutionExceptionDuringRetrieval") - + task.getRetriever().getName(); - if (e.getCause() instanceof java.net.SocketTimeoutException) - { - WorldWind.logger() - .log(java.util.logging.Level.FINE, message + " " + e.getCause().getLocalizedMessage()); - } - else - { - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - } - } - catch (InterruptedException e) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.RetrievalOf_1") - + task.getRetriever().getName() + WorldWind - .retrieveErrMsg("BasicRetrievalService.WasInterrupted_2"); - - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - } - catch (java.util.concurrent.CancellationException e) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.RetrievalOf_1") - + task.getRetriever().getName() + WorldWind.retrieveErrMsg("BasicRetrievalService.WasCancelled_2"); - - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - finally - { - - Thread.currentThread().setName(IDLE_THREAD_NAME_PREFIX); - - WorldWind.logger().log(java.util.logging.Level.FINEST, WorldWind.retrieveErrMsg( - "BasicRetrievalService.LeavingAfterExecute")); - } - } - } - - public BasicRetrievalService() - { - Integer poolSize = Configuration.getIntegerValue(AVKey.RETRIEVAL_POOL_SIZE, DEFAULT_POOL_SIZE); - this.queueSize = Configuration.getIntegerValue(AVKey.RETRIEVAL_QUEUE_SIZE, DEFAULT_QUEUE_SIZE); - - // this.executor runs the retrievers, each in their own thread - this.executor = new RetrievalExecutor(poolSize, this.queueSize); - - // this.activeTasks holds the list of currently executing tasks (*not* those pending on the queue) - this.activeTasks = new java.util.concurrent.ConcurrentLinkedQueue(); - } - - /** - * @param retriever the retriever to run - * @return a future object that can be used to query the request status of cancel the request. - * @throws IllegalArgumentException if retrieer is null or has no name - */ - public RetrievalFuture runRetriever(Retriever retriever) - { - if (retriever == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (retriever.getName() == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RetrieverNameIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - // Add with secondary priority that removes most recently added requests first. - return this.runRetriever(retriever, (double) (Long.MAX_VALUE - System.currentTimeMillis())); - } - - /** - * @param retriever the retriever to run - * @param priority the secondary priority of the retriever, or negative if it is to be the primary priority - * @return a future object that can be used to query the request status of cancel the request. - * @throws IllegalArgumentException if retriever is null or has no name - */ - public synchronized RetrievalFuture runRetriever(Retriever retriever, double priority) - { - if (retriever == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (retriever.getName() == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RetrieverNameIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.isFull()) - { - String name = retriever.getName(); - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.ResourceRejected") + name; - WorldWind.logger().log(java.util.logging.Level.FINER, message); - } - - RetrievalTask task = new RetrievalTask(retriever, priority); - retriever.setSubmitTime(System.currentTimeMillis()); - - // Do not queue duplicates. - if (this.activeTasks.contains(task) || this.executor.getQueue().contains(task)) - return null; - - this.executor.execute(task); - - return task; - } - - /** - * @param poolSize the number of threads in the thread pool - * @throws IllegalArgumentException if poolSize is non-positive - */ - public void setRetrieverPoolSize(int poolSize) - { - if (poolSize < 1) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.RetrieverPoolSizeIsLessThanOne"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.executor.setCorePoolSize(poolSize); - this.executor.setMaximumPoolSize(poolSize); - } - - public int getRetrieverPoolSize() - { - return this.executor.getCorePoolSize(); - } - - private boolean hasRetrievers() - { - Thread[] threads = new Thread[Thread.activeCount()]; - int numThreads = Thread.enumerate(threads); - for (int i = 0; i < numThreads; i++) - { - if (threads[i].getName().startsWith(RUNNING_THREAD_NAME_PREFIX)) - return true; - } - return false; - } - - public boolean hasActiveTasks() - { - return this.hasRetrievers(); - } - - public boolean isFull() - { - return this.executor.getQueue().size() >= this.queueSize; - } - - public int getNumRetrieversPending() - { - // Could use same method to determine active tasks as hasRetrievers() above, but this method only advisory. - return this.activeTasks.size() + this.executor.getQueue().size(); - } - - /** - * @param retriever the retriever to check - * @return true if the retriever is being run or pending execution - * @throws IllegalArgumentException if retriever is null - */ - public boolean contains(Retriever retriever) - { - if (retriever == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - RetrievalTask task = new RetrievalTask(retriever, 0d); - return (this.activeTasks.contains(task) || this.executor.getQueue().contains(task)); - } - - public double getProgress() - { - int totalContentLength = 0; - int totalBytesRead = 0; - - for (RetrievalTask task : this.activeTasks) - { - if (task.isDone()) - continue; - - Retriever retriever = task.getRetriever(); - try - { - double tcl = retriever.getContentLength(); - if (tcl > 0) - { - totalContentLength += tcl; - totalBytesRead += retriever.getContentLengthRead(); - } - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.ExcptnRetrievingContentSizes") + ( - retriever.getName() != null ? retriever.getName() : ""); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - } - } - - for (Runnable runnable : this.executor.getQueue()) - { - gov.nasa.worldwind.BasicRetrievalService.RetrievalTask task = - (gov.nasa.worldwind.BasicRetrievalService.RetrievalTask) runnable; - - Retriever retriever = task.getRetriever(); - try - { - double tcl = retriever.getContentLength(); - if (tcl > 0) - { - totalContentLength += tcl; - totalBytesRead += retriever.getContentLengthRead(); - } - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("BasicRetrievalService.ExcptnRetrievingContentSizes") + ( - retriever.getName() != null ? retriever.getName() : ""); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - } - } - - // Compute an aggregated progress notification. - - double progress; - - if (totalContentLength < 1) - progress = 0; - else - progress = Math.min(100.0, 100.0 * (double) totalBytesRead / (double) totalContentLength); - - return progress; - } -} diff --git a/gov/nasa/worldwind/Cacheable.java b/gov/nasa/worldwind/Cacheable.java deleted file mode 100644 index 3ca5e8f..0000000 --- a/gov/nasa/worldwind/Cacheable.java +++ /dev/null @@ -1,26 +0,0 @@ -package gov.nasa.worldwind; -/* -Copyright (C) 2001, 2006 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Tom Gaskins - * @version $Id: Cacheable.java 403 2006-12-13 02:33:18Z ericdalgliesh $ - */ -public interface Cacheable -{ - // TODO: search for size queries that do not used this interface and change them to do so. - // currently (22 Nov 2006), only BasicElevationModel.addTileToCache(Tile, ShortBuffer) does not use Cacheable - - /** - * Retrieves the approximate size of this object in bytes. Implementors are encouraged to calculate the exact size - * for smaller objects, but use approximate values for objects that include such large components that the - * approximation would produce an error so small that the extra computation would be wasteful. - * - * @return this Cacheable object's size in bytes - */ - long getSizeInBytes(); -} diff --git a/gov/nasa/worldwind/Configuration.java b/gov/nasa/worldwind/Configuration.java index 74d2c88..24a2877 100644 --- a/gov/nasa/worldwind/Configuration.java +++ b/gov/nasa/worldwind/Configuration.java @@ -6,7 +6,7 @@ All Rights Reserved. */ /** * - @version $Id: Configuration.java 2471 2007-07-31 21:50:57Z tgaskins $ + @version $Id: Configuration.java 2915 2007-09-19 06:01:49Z tgaskins $ @author Tom Gaskins */ package gov.nasa.worldwind; @@ -68,6 +68,7 @@ public class Configuration // Singleton + "," + gov.nasa.worldwind.layers.Earth.EarthNASAPlaceNameLayer.class.getName() + "," + gov.nasa.worldwind.layers.CompassLayer.class.getName() ); + defaults.setProperty(AVKey.BMNG_ONE_IMAGE_PATH, "images/BMNG_world.topo.bathy.200405.3.2048x1024.jpg"); java.util.TimeZone tz = java.util.Calendar.getInstance().getTimeZone(); if (tz != null) diff --git a/gov/nasa/worldwind/DDSConverter.java b/gov/nasa/worldwind/DDSConverter.java deleted file mode 100644 index 6ebb406..0000000 --- a/gov/nasa/worldwind/DDSConverter.java +++ /dev/null @@ -1,725 +0,0 @@ -/* -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; - -import java.awt.image.*; -import java.nio.*; -import java.io.*; - -/** - * @author Tom Gaskins - * @version $Id: DDSConverter.java 2027 2007-06-14 02:41:44Z tgaskins $ - */ -public class DDSConverter -{ - static final int DDSD_CAPS = 0x0001; - static final int DDSD_HEIGHT = 0x0002; - static final int DDSD_WIDTH = 0x0004; - static final int DDSD_PIXELFORMAT = 0x1000; - static final int DDSD_MIPMAPCOUNT = 0x20000; - static final int DDSD_LINEARSIZE = 0x80000; - static final int DDPF_FOURCC = 0x0004; - static final int DDSCAPS_TEXTURE = 0x1000; - - protected static class Color - { - private int r, g, b; - - public Color() - { - this.r = this.g = this.b = 0; - } - - public Color(int r, int g, int b) - { - this.r = r; - this.g = g; - this.b = b; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final gov.nasa.worldwind.DDSConverter.Color color = (gov.nasa.worldwind.DDSConverter.Color) o; - - if (b != color.b) - return false; - if (g != color.g) - return false; - //noinspection RedundantIfStatement - if (r != color.r) - return false; - - return true; - } - - public int hashCode() - { - int result; - result = r; - result = 29 * result + g; - result = 29 * result + b; - return result; - } - } - - public static ByteBuffer convertToDDS(ByteBuffer image, String mimeType) throws IOException - { - if (image == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.ByteBufferIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (mimeType == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.MimeTypeIsNull"); - gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - String suffix = WWIO.getSuffixForMimeType(mimeType); - if (suffix == null) - { - String message = WorldWind.retrieveErrMsg("DDSConverter.UnsupportedMimeType") + mimeType; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - File tempFile = WWIO.saveBufferToTempFile(image, suffix); - - return convertToDDS(tempFile); - } - - public static ByteBuffer convertToDDS(File file) throws IOException - { - if (file == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (!file.exists() || !file.canRead()) - { - String message = WorldWind.retrieveErrMsg("DDSConverter.NoFileOrNoPermission"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file); - if (image == null) - { - return null; - } - - // Don't waste the space for transparency if - if (image.getColorModel().hasAlpha()) - return convertToDxt3(image); - else - return convertToDxt1NoTransparency(image); - } - - public static ByteBuffer convertToDxt1NoTransparency(ByteBuffer image, String mimeType) - throws IOException - { - if (image == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.ByteBufferIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (mimeType == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.MimeTypeIsNull"); - gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - String suffix = WWIO.getSuffixForMimeType(mimeType); - if (suffix == null) - { - String message = WorldWind.retrieveErrMsg("DDSConverter.UnsupportedMimeType") + mimeType; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - File tempFile = WWIO.saveBufferToTempFile(image, suffix); - - return convertToDxt1NoTransparency(tempFile); - } - - public static ByteBuffer convertToDxt1NoTransparency(File file) throws IOException - { - if (file == null) - { // - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (!file.exists() || !file.canRead()) - { - String message = WorldWind.retrieveErrMsg("DDSConverter.NoFileOrNoPermission"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file); - - if (image == null) - { - return null; // TODO: log - } - - return convertToDxt1NoTransparency(image); - } - - public static ByteBuffer convertToDxt1NoTransparency(BufferedImage image) - { - if (image == null) - { - return null; - } - - int[] pixels = new int[16]; - int bufferSize = 128 + image.getWidth() * image.getHeight() / 2; - ByteBuffer buffer = ByteBuffer.allocate(bufferSize); - buffer.order(ByteOrder.LITTLE_ENDIAN); - buildHeaderDxt1(buffer, image.getWidth(), image.getHeight()); - - int numTilesWide = image.getWidth() / 4; - int numTilesHigh = image.getHeight() / 4; - for (int i = 0; i < numTilesHigh; i++) - { - for (int j = 0; j < numTilesWide; j++) - { - java.awt.image.BufferedImage originalTile = image.getSubimage(j * 4, i * 4, 4, 4); - originalTile.getRGB(0, 0, 4, 4, pixels, 0, 4); - Color[] colors = getColors888(pixels); - - for (int k = 0; k < pixels.length; k++) - { - pixels[k] = getPixel565(colors[k]); - colors[k] = getColor565(pixels[k]); - } - - int[] extremaIndices = determineExtremeColors(colors); - if (pixels[extremaIndices[0]] < pixels[extremaIndices[1]]) - { - int t = extremaIndices[0]; - extremaIndices[0] = extremaIndices[1]; - extremaIndices[1] = t; - } - - buffer.putShort((short) pixels[extremaIndices[0]]); - buffer.putShort((short) pixels[extremaIndices[1]]); - - long bitmask = computeBitMask(colors, extremaIndices); - buffer.putInt((int) bitmask); - } - } - - return buffer; - } - - public static ByteBuffer convertToDxt3(ByteBuffer image, String mimeType) - throws IOException - { - if (image == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.ByteBufferIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (mimeType == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.MimeTypeIsNull"); - gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - String suffix = WWIO.getSuffixForMimeType(mimeType); - if (suffix == null) - { - String message = WorldWind.retrieveErrMsg("DDSConverter.UnsupportedMimeType") + mimeType; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - File tempFile = WWIO.saveBufferToTempFile(image, suffix); - - return convertToDxt3(tempFile); - } - - public static ByteBuffer convertToDxt3(File file) throws IOException - { - if (file == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (!file.exists() || !file.canRead()) - { - String message = WorldWind.retrieveErrMsg("DDSConverter.NoFileOrNoPermission"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file); - if (image == null) - { - return null; - } - - return convertToDxt3(image); - } - - public static ByteBuffer convertToDxt3(BufferedImage image) throws IOException - { - if (image == null) - return null; // TODO: arg check - - // Don't waste the space for transparency if - if (!image.getColorModel().hasAlpha()) - return convertToDxt1NoTransparency(image); - - int[] pixels = new int[16]; - int bufferSize = 128 + image.getWidth() * image.getHeight(); - ByteBuffer buffer = ByteBuffer.allocate(bufferSize); - buffer.order(ByteOrder.LITTLE_ENDIAN); - buildHeaderDxt3(buffer, image.getWidth(), image.getHeight()); - - int numTilesWide = image.getWidth() / 4; - int numTilesHigh = image.getHeight() / 4; - for (int i = 0; i < numTilesHigh; i++) - { - for (int j = 0; j < numTilesWide; j++) - { - java.awt.image.BufferedImage originalTile = image.getSubimage(j * 4, i * 4, 4, 4); - originalTile.getRGB(0, 0, 4, 4, pixels, 0, 4); - Color[] colors = getColors888(pixels); - - // Store the alhpa table. - for (int k = 0; k < pixels.length; k += 2) - { - buffer.put((byte) ((pixels[k] >>> 24) | (pixels[k + 1] >>> 28))); - } - - for (int k = 0; k < pixels.length; k++) - { - pixels[k] = getPixel565(colors[k]); - colors[k] = getColor565(pixels[k]); - } - - int[] extremaIndices = determineExtremeColors(colors); - if (pixels[extremaIndices[0]] < pixels[extremaIndices[1]]) - { - int t = extremaIndices[0]; - extremaIndices[0] = extremaIndices[1]; - extremaIndices[1] = t; - } - - buffer.putShort((short) pixels[extremaIndices[0]]); - buffer.putShort((short) pixels[extremaIndices[1]]); - - long bitmask = computeBitMask(colors, extremaIndices); - buffer.putInt((int) bitmask); - } - } - - return buffer; - } - - protected static void buildHeaderDxt1(ByteBuffer buffer, int width, int height) - { - buffer.rewind(); - buffer.put((byte) 'D'); - buffer.put((byte) 'D'); - buffer.put((byte) 'S'); - buffer.put((byte) ' '); - buffer.putInt(124); - int flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT | DDSD_LINEARSIZE; - buffer.putInt(flag); - buffer.putInt(height); - buffer.putInt(width); - buffer.putInt(width * height / 2); - buffer.putInt(0); // depth - buffer.putInt(0); // mipmap count - buffer.position(buffer.position() + 44); // 11 unused double-words - buffer.putInt(32); // pixel format size - buffer.putInt(DDPF_FOURCC); - buffer.put((byte) 'D'); - buffer.put((byte) 'X'); - buffer.put((byte) 'T'); - buffer.put((byte) '1'); - buffer.putInt(0); // bits per pixel for RGB (non-compressed) formats - buffer.putInt(0); // rgb bit masks for RGB formats - buffer.putInt(0); // rgb bit masks for RGB formats - buffer.putInt(0); // rgb bit masks for RGB formats - buffer.putInt(0); // alpha mask for RGB formats - buffer.putInt(DDSCAPS_TEXTURE); - buffer.putInt(0); // ddsCaps2 - buffer.position(buffer.position() + 12); // 3 unused double-words - } - - protected static void buildHeaderDxt3(ByteBuffer buffer, int width, int height) - { - buffer.rewind(); - buffer.put((byte) 'D'); - buffer.put((byte) 'D'); - buffer.put((byte) 'S'); - buffer.put((byte) ' '); - buffer.putInt(124); - int flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT | DDSD_LINEARSIZE; - buffer.putInt(flag); - buffer.putInt(height); - buffer.putInt(width); - buffer.putInt(width * height); - buffer.putInt(0); // depth - buffer.putInt(0); // mipmap count - buffer.position(buffer.position() + 44); // 11 unused double-words - buffer.putInt(32); // pixel format size - buffer.putInt(DDPF_FOURCC); - buffer.put((byte) 'D'); - buffer.put((byte) 'X'); - buffer.put((byte) 'T'); - buffer.put((byte) '3'); - buffer.putInt(0); // bits per pixel for RGB (non-compressed) formats - buffer.putInt(0); // rgb bit masks for RGB formats - buffer.putInt(0); // rgb bit masks for RGB formats - buffer.putInt(0); // rgb bit masks for RGB formats - buffer.putInt(0); // alpha mask for RGB formats - buffer.putInt(DDSCAPS_TEXTURE); - buffer.putInt(0); // ddsCaps2 - buffer.position(buffer.position() + 12); // 3 unused double-words - } - - protected static int[] determineExtremeColors(Color[] colors) - { - int farthest = Integer.MIN_VALUE; - int[] ex = new int[2]; - - for (int i = 0; i < colors.length - 1; i++) - { - for (int j = i + 1; j < colors.length; j++) - { - int d = distance(colors[i], colors[j]); - if (d > farthest) - { - farthest = d; - ex[0] = i; - ex[1] = j; - } - } - } - - return ex; - } - - protected static long computeBitMask(Color[] colors, int[] extremaIndices) - { - Color[] colorPoints = new Color[] {null, null, new Color(), new Color()}; - colorPoints[0] = colors[extremaIndices[0]]; - colorPoints[1] = colors[extremaIndices[1]]; - if (colorPoints[0].equals(colorPoints[1])) - return 0; - -// colorPoints[0].r = (colorPoints[0].r & 0xF8) | (colorPoints[0].r >> 5 ); -// colorPoints[0].g = (colorPoints[0].g & 0xFC) | (colorPoints[0].g >> 6 ); -// colorPoints[0].b = (colorPoints[0].b & 0xF8) | (colorPoints[0].b >> 5 ); -// -// colorPoints[1].r = (colorPoints[1].r & 0xF8) | (colorPoints[1].r >> 5 ); -// colorPoints[1].g = (colorPoints[1].g & 0xFC) | (colorPoints[1].g >> 6 ); -// colorPoints[1].b = (colorPoints[1].b & 0xF8) | (colorPoints[1].b >> 5 ); - - colorPoints[2].r = (2 * colorPoints[0].r + colorPoints[1].r + 1) / 3; - colorPoints[2].g = (2 * colorPoints[0].g + colorPoints[1].g + 1) / 3; - colorPoints[2].b = (2 * colorPoints[0].b + colorPoints[1].b + 1) / 3; - colorPoints[3].r = (colorPoints[0].r + 2 * colorPoints[1].r + 1) / 3; - colorPoints[3].g = (colorPoints[0].g + 2 * colorPoints[1].g + 1) / 3; - colorPoints[3].b = (colorPoints[0].b + 2 * colorPoints[1].b + 1) / 3; - - long bitmask = 0; - for (int i = 0; i < colors.length; i++) - { - int closest = Integer.MAX_VALUE; - int mask = 0; - for (int j = 0; j < colorPoints.length; j++) - { - int d = distance(colors[i], colorPoints[j]); - if (d < closest) - { - closest = d; - mask = j; - } - } - bitmask |= mask << i * 2; - } - - return bitmask; - } - - protected static int getPixel565(Color color) - { - int r = color.r >> 3; - int g = color.g >> 2; - int b = color.b >> 3; - return r << 11 | g << 5 | b; - } - - protected static Color getColor565(int pixel) - { - Color color = new Color(); - - color.r = (int) (((long) pixel) & 0xf800) >> 11; - color.g = (int) (((long) pixel) & 0x07e0) >> 5; - color.b = (int) (((long) pixel) & 0x001f); - - return color; - } - - protected static Color getColor888(int r8g8b8) - { - return new Color( - (int) (((long) r8g8b8) & 0xff0000) >> 16, - (int) (((long) r8g8b8) & 0x00ff00) >> 8, - (int) (((long) r8g8b8) & 0x0000ff) - ); - } - - protected static Color[] getColors888(int[] pixels) - { - Color[] colors = new Color[pixels.length]; - - for (int i = 0; i < pixels.length; i++) - { - colors[i] = new Color(); - colors[i].r = (int) (((long) pixels[i]) & 0xff0000) >> 16; - colors[i].g = (int) (((long) pixels[i]) & 0x00ff00) >> 8; - colors[i].b = (int) (((long) pixels[i]) & 0x0000ff); - } - - return colors; - } - - protected static int distance(Color ca, Color cb) - { - return (cb.r - ca.r) * (cb.r - ca.r) + (cb.g - ca.g) * (cb.g - ca.g) + (cb.b - ca.b) * (cb.b - ca.b); - } - - protected static void equalTransparentCase(TransparentColor[] colors, int[] extremaIndices, short value) - { - // we want extremaIndices[0] to be greater than extremaIndices[1] - - if (value == 0) - { - // transparent - colors[extremaIndices[0]] = TransparentColor.OFF_TRANSPARENT; - } - /*else - { - // not transparent anywhere - it's all one colour, so we don't need to bother making changes - }*/ - - } - - protected static int distance(TransparentColor ca, TransparentColor cb) - { - return (cb.r - ca.r) * (cb.r - ca.r) + (cb.g - ca.g) * (cb.g - ca.g) + (cb.b - ca.b) * (cb.b - ca.b) - + (cb.a - ca.a) * (cb.a - ca.a); - } - -// public static void main(String[] args) -// { -// try -// { -// String fileName = "testdata/0000_0001"; -// ByteBuffer buffer = convertToDxt1NoTransparency(new File(fileName + ".jpg")); -// buffer.rewind(); -// FileOutputStream fos = new FileOutputStream(fileName + ".dds"); -// channels.FileChannel channel = fos.getChannel(); -// channel.write(buffer); -// } -// catch (IOException e) -// { -// e.printStackTrace(); -// } -// -// return; -// } - - protected static long computeBitMask(TransparentColor[] colors, int[] extremaIndices) - { - TransparentColor[] colorPoints = {null, null, new TransparentColor(), new TransparentColor()}; - - colorPoints[0] = colors[extremaIndices[0]]; - colorPoints[1] = colors[extremaIndices[1]]; - - colorPoints[2].r = (colorPoints[0].r + colorPoints[1].r) / 2; - colorPoints[2].g = (colorPoints[0].g + colorPoints[1].g) / 2; - colorPoints[2].b = (colorPoints[0].b + colorPoints[1].b) / 2; - colorPoints[2].a = 1; - - colorPoints[3].r = 0; - colorPoints[3].g = 0; - colorPoints[3].b = 0; - colorPoints[3].a = 0; - - long bitmask = 0; - for (int i = 0; i < colors.length; i++) - { - int closest = Integer.MAX_VALUE; - int mask = 0; - if (colors[i].a == 0) - { - mask = 3; - } - else - { - for (int j = 0; j < colorPoints.length; j++) - { - int d = distance(colors[i], colorPoints[j]); - if (d < closest) - { - closest = d; - mask = j; - } - } - } - bitmask |= mask << i * 2; - } - - return bitmask; - } - - protected static short getShort5551(TransparentColor color) - { - short s = 0; - s |= ((color.r & 0x0f8) << 8) | ((color.g & 0x0f8) << 4) | ((color.b & 0x0f8) >> 3) | ((color.a & 0x0f8) >> 7); -// System.out.println(Integer.toBinaryString(s)); - return s; - } - - protected static int[] determineExtremeColors(TransparentColor[] colors) - { - int farthest = Integer.MIN_VALUE; - int[] ex = {0, 0}; - - for (int i = 0; i < colors.length - 1; i++) - { - for (int j = i + 1; j < colors.length; j++) - { - int d = distance(colors[i], colors[j]); - if (d > farthest) - { - farthest = d; - ex[0] = i; - ex[1] = j; - } - } - } - - return ex; - } - - protected static TransparentColor[] getColors5551(int[] pixels) - { - TransparentColor colors[] = new TransparentColor[pixels.length]; - - for (int i = 0; i < pixels.length; i++) - { - colors[i] = generateColor5551(pixels[i]); - } - return colors; - } - - protected static TransparentColor generateColor5551(int pixel) - { - short alpha = (short) (pixel >> 24); - if ((alpha & 0xf0) == 0) - { - return TransparentColor.TRANSPARENT; - } - - // ok, it's not transparent - that's already been ruled out. - - TransparentColor tc = new TransparentColor(); - tc.a = 0x000000ff; - tc.r = (pixel & 0x00ff0000) >> 16; - tc.g = (pixel & 0x0000ff00) >> 8; - tc.b = (pixel & 0x000000ff); - - return tc; - } - - protected static class TransparentColor - { - private static final TransparentColor TRANSPARENT = new TransparentColor(0, 0, 0, 0); - private static final TransparentColor OFF_TRANSPARENT = new TransparentColor(0, 0, 1, 0); - private int r, g, b, a; - - private TransparentColor() - { - } - - private TransparentColor(int r, int g, int b, int a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final gov.nasa.worldwind.DDSConverter.TransparentColor that = - (gov.nasa.worldwind.DDSConverter.TransparentColor) o; - - if (a != that.a) - return false; - if (b != that.b) - return false; - if (g != that.g) - return false; - //noinspection RedundantIfStatement - if (r != that.r) - return false; - - return true; - } - - public int hashCode() - { - int result; - result = r; - result = 29 * result + g; - result = 29 * result + b; - result = 29 * result + a; - return result; - } - - public String toString() - { - return "TransColor argb: " + this.a + ", " + this.r + ", " + this.g + ", " + this.b; - } - } -} diff --git a/gov/nasa/worldwind/DrawContext.java b/gov/nasa/worldwind/DrawContext.java deleted file mode 100644 index fae9d69..0000000 --- a/gov/nasa/worldwind/DrawContext.java +++ /dev/null @@ -1,274 +0,0 @@ -/* -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; - -import com.sun.opengl.util.texture.*; -import gov.nasa.worldwind.geom.*; - -/** - * @author Tom Gaskins - * @version $Id: DrawContext.java 1994 2007-06-11 16:33:33Z dcollins $ - */ -public interface DrawContext extends WWObject -{ - /** - * Assigns this DrawContext a new javax.media.opengl.GLContext. May throw a - * NullPointerException if glContext is null. - * - * @param glContext the new javax.media.opengl.GLContext - * @throws NullPointerException if glContext is null - * @since 1.5 - */ - void setGLContext(javax.media.opengl.GLContext glContext); - - /** - * Retrieves this DrawContexts javax.media.opengl.GLContext. If this method returns null, - * then there are potentially no active GLContexts and rendering should be aborted. - * - * @return this DrawContexts javax.media.opengl.GLContext. - * @since 1.5 - */ - javax.media.opengl.GLContext getGLContext(); - - /** - * Retrieves the current javax.media.opengl.GL. A GL or GLU is required for - * all graphical rendering in World Wind Raptor. - * - * @return the current GL if available, null otherwise - * @since 1.5 - */ - javax.media.opengl.GL getGL(); - - /** - * Retrieves the current javax.media.opengl.glu.GLU. A GLU or GL is required - * for all graphical rendering in World Wind Raptor. - * - * @return the current GLU if available, null otherwise - * @since 1.5 - */ - javax.media.opengl.glu.GLU getGLU(); - - /** - * Retrieves the currentjavax.media.opengl.GLDrawable. A GLDrawable can be used to create - * a GLContext, which can then be used for rendering. - * - * @return the current GLDrawable, null if none available - * @since 1.5 - */ - javax.media.opengl.GLDrawable getGLDrawable(); - - /** - * Retrieves the drawable width of this DrawContext. - * - * @return the drawable width of this DrawCOntext - * @since 1.5 - */ - int getDrawableWidth(); - - /** - * Retrieves the drawable height of this DrawContext. - * - * @return the drawable height of this DrawCOntext - * @since 1.5 - */ - int getDrawableHeight(); - - /** - * Initializes this DrawContext. This method should be called at the beginning of each frame to prepare - * the DrawContext for the coming render pass. - * - * @param glContext the javax.media.opengl.GLContext to use for this render pass - * @since 1.5 - */ - void initialize(javax.media.opengl.GLContext glContext); - - /** - * Assigns a new View. Some layers cannot function properly with a null View. It is - * recommended that the View is never set to null during a normal render pass. - * - * @param view the enw View - * @since 1.5 - */ - void setView(View view); - - /** - * Retrieves the current View, which may be null. - * - * @return the current View, which may be null - * @since 1.5 - */ - View getView(); - - /** - * Assign a new Model. Some layers cannot function properly with a null Model. It is - * recommended that the Model is never set to null during a normal render pass. - * - * @param model the new Model - * @since 1.5 - */ - void setModel(Model model); - - /** - * Retrieves the current Model, which may be null. - * - * @return the current Model, which may be null - * @since 1.5 - */ - Model getModel(); - - /** - * Retrieves the current Globe, which may be null. - * - * @return the current Globe, which may be null - * @since 1.5 - */ - Globe getGlobe(); - - /** - * Retrieves a list containing all the current layers. No guarantee is made about the order of the layers. - * - * @return a LayerList containing all the current layers - * @since 1.5 - */ - LayerList getLayers(); - - /** - * Retrieves a Sector which is at least as large as the current visible sector. The value returned is - * the value passed to SetVisibleSector. This method may return null. - * - * @return a Sector at least the size of the curernt visible sector, null if unavailable - * @since 1.5 - */ - gov.nasa.worldwind.geom.Sector getVisibleSector(); - - /** - * Sets the visible Sector. The new visible sector must completely encompass the Sector which is - * visible on the display. - * - * @param s the new visible Sector - * @since 1.5 - */ - void setVisibleSector(gov.nasa.worldwind.geom.Sector s); - - /** - * Sets the vertical exaggeration. Vertical exaggeration affects the appearance of areas with varied elevation. A - * vertical exaggeration of zero creates a surface which exactly fits the shape of the underlying - * Globe. A vertical exaggeration of 3 will create mountains and valleys which are three times as - * high/deep as they really are. - * - * @param verticalExaggeration the new vertical exaggeration. - * @since 1.5 - */ - void setVerticalExaggeration(double verticalExaggeration); - - /** - * Retrieves the current vertical exaggeration. Vertical exaggeration affects the appearance of areas with varied - * elevation. A vertical exaggeration of zero creates a surface which exactly fits the shape of the underlying - * Globe. A vertical exaggeration of 3 will create mountains and valleys which are three times as - * high/deep as they really are. - * - * @return the current vertical exaggeration - * @since 1.5 - */ - double getVerticalExaggeration(); - - // not used (12th January 2007) - final static String HIGH_PRIORITY = "gov.nasa.worldwind.DrawContext.HighPriority"; - final static String LOW_PRIORITY = "gov.nasa.worldwind.DrawContext.LowPriority"; - - /** - * Retrieves a list of all the sectors rendered so far this frame. - * - * @return a SectorGeometryList containing every SectorGeometry rendered so far this - * render pass. - * @since 1.5 - */ - SectorGeometryList getSurfaceGeometry(); - - // -// /** -// * Sets the average render time per frame in milliseconds. -// * -// * @param timeMillis the new average time in milliseconds -// * @since 1.5 -// */ -// void setAverageRenderTimeMillis(double timeMillis); -// -// /** -// * Retrieves the current average render time for a frame. The average render time can be used to calculate the -// * framerate. -// * -// * @return the current average render time for a frame -// * @since 1.5 -// */ -// double getAverageRenderTimeMillis(); - - /** - * Returns the list of objects picked during the most recent pick traversal. - * - * @return the list of picked objects - */ - gov.nasa.worldwind.PickedObjectList getPickedObjects(); - - /** - * Adds a collection of picked objects to the current picked-object list - * - * @param pickedObjects the objects to add - */ - void addPickedObjects(PickedObjectList pickedObjects); - - /** - * Adds a single insatnce of the picked object to the current picked-object list - * - * @param pickedObject the object to add - */ - void addPickedObject(PickedObject pickedObject); - - /** - * Returns a unique color to serve as a pick identifier during picking. - * - * @return a unique pick color - */ - java.awt.Color getUniquePickColor(); - - java.awt.Color getClearColor(); - - /** - * Enables color picking mode - */ - void enablePickingMode(); - - /** - * Returns true if the Picking mode is active, otherwise return false - * - * @return true for Picking mode, otherwise false - */ - boolean isPickingMode(); - - /** - * Disables color picking mode - */ - void disablePickingMode(); - - void addOrderedRenderable(OrderedRenderable orderedRenderable); - - java.util.Queue getOrderedRenderables(); - - void drawUnitQuad(); - - void drawUnitQuad(TextureCoords texCoords); - - int getNumTextureUnits(); - - void setNumTextureUnits(int numTextureUnits); - - void setSurfaceGeometry(SectorGeometryList surfaceGeometry); - - Vec4 getPointOnGlobe(Angle latitude, Angle longitude); - - SurfaceTileRenderer getSurfaceTileRenderer(); -} diff --git a/gov/nasa/worldwind/DrawContextImpl.java b/gov/nasa/worldwind/DrawContextImpl.java deleted file mode 100644 index 4778dbd..0000000 --- a/gov/nasa/worldwind/DrawContextImpl.java +++ /dev/null @@ -1,379 +0,0 @@ -/* -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; - -import com.sun.opengl.util.texture.*; -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import java.util.*; - -/** - * @author Tom Gaskins - * @version $Id: DrawContextImpl.java 1994 2007-06-11 16:33:33Z dcollins $ - */ -public class DrawContextImpl extends WWObjectImpl implements DrawContext -{ - private javax.media.opengl.GLContext glContext; - private javax.media.opengl.glu.GLU glu = new javax.media.opengl.glu.GLU(); - private View view; - private Model model; - private Globe globe; - private double verticalExaggeration = 1d; - private gov.nasa.worldwind.geom.Sector visibleSector; - private SectorGeometryList surfaceGeometry;// = new SectorGeometryList(); - private gov.nasa.worldwind.PickedObjectList pickedObjects = new gov.nasa.worldwind.PickedObjectList(); - private int uniquePickNumber = 0; - private java.awt.Color clearColor = new java.awt.Color(0, 0, 0, 0); - private boolean isPickingMode = false; - private int numTextureUnits = -1; - private SurfaceTileRenderer surfaceTileRenderer = new SurfaceTileRenderer(); - - PriorityQueue orderedRenderables = new PriorityQueue(100, - new Comparator() - { - public int compare(OrderedRenderable orA, OrderedRenderable orB) - { - double eA = orA.getDistanceFromEye(); - double eB = orB.getDistanceFromEye(); - - return eA > eB ? -1 : eA == eB ? 0 : 1; - } - }); - - public final javax.media.opengl.GL getGL() - { - return this.getGLContext().getGL(); - } - - public final javax.media.opengl.glu.GLU getGLU() - { - return this.glu; - } - - public final javax.media.opengl.GLContext getGLContext() - { - return this.glContext; - } - - public final int getDrawableHeight() - { - return this.getGLDrawable().getHeight(); - } - - public final int getDrawableWidth() - { - return this.getGLDrawable().getWidth(); - } - - public final javax.media.opengl.GLDrawable getGLDrawable() - { - return this.getGLContext().getGLDrawable(); - } - - public final void initialize(javax.media.opengl.GLContext glContext) - { - if (glContext == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.GLContextIsNull"); - gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.glContext = glContext; - this.visibleSector = null; - if (this.surfaceGeometry != null) - this.surfaceGeometry.clear(); - this.surfaceGeometry = null; - - this.pickedObjects.clear(); - this.orderedRenderables.clear(); - this.uniquePickNumber = 0; - - if (this.numTextureUnits < 1) - this.numTextureUnits = queryMaxTextureUnits(glContext); - } - - private static int queryMaxTextureUnits(GLContext glContext) - { - int[] mtu = new int[1]; - glContext.getGL().glGetIntegerv(GL.GL_MAX_TEXTURE_UNITS, mtu, 0); - return mtu[0]; - } - - public final void setModel(gov.nasa.worldwind.Model model) - { - this.model = model; - if (this.model == null) - return; - - Globe g = this.model.getGlobe(); - if (g != null) - this.globe = g; - } - - public final Model getModel() - { - return this.model; - } - - public final LayerList getLayers() - { - return this.model.getLayers(); - } - - public final Sector getVisibleSector() - { - return this.visibleSector; - } - - public final void setVisibleSector(Sector s) - { - // don't check for null - it is possible that no globe is active, no view is active, no sectors visible, etc. - this.visibleSector = s; - } - - public void setSurfaceGeometry(SectorGeometryList surfaceGeometry) - { - this.surfaceGeometry = surfaceGeometry; - } - - public SectorGeometryList getSurfaceGeometry() - { - return surfaceGeometry; - } - - public final Globe getGlobe() - { - return this.globe != null ? this.globe : this.model.getGlobe(); - } - - public final void setView(gov.nasa.worldwind.View view) - { - this.view = view; - } - - public final View getView() - { - return this.view; - } - - public final void setGLContext(javax.media.opengl.GLContext glContext) - { - if (glContext == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.GLContextIsNull"); - gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.glContext = glContext; - } - - public final double getVerticalExaggeration() - { - return verticalExaggeration; - } - - public final void setVerticalExaggeration(double verticalExaggeration) - { - this.verticalExaggeration = verticalExaggeration; - } - - /** - * Add picked objects to the current list of picked objects. - * - * @param pickedObjects the list of picked objects to add - * @throws IllegalArgumentException if pickedObjects is null - */ - public void addPickedObjects(gov.nasa.worldwind.PickedObjectList pickedObjects) - { - if (pickedObjects == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PickedObjectList"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (this.pickedObjects == null) - { - this.pickedObjects = pickedObjects; - return; - } - - for (gov.nasa.worldwind.PickedObject po : pickedObjects) - { - this.pickedObjects.add(po); - } - } - - /** - * Adds a single insatnce of the picked object to the current picked-object list - * - * @param pickedObject the object to add - * @throws IllegalArgumentException if picked Object is null - */ - public void addPickedObject(PickedObject pickedObject) - { - if (null == pickedObject) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PickedObject"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (null == this.pickedObjects) - this.pickedObjects = new gov.nasa.worldwind.PickedObjectList(); - - this.pickedObjects.add(pickedObject); - } - - public gov.nasa.worldwind.PickedObjectList getPickedObjects() - { - return this.pickedObjects; - } - - public java.awt.Color getUniquePickColor() - { - this.uniquePickNumber++; - int clearColorCode = this.getClearColor().getRGB(); - - if (clearColorCode == this.uniquePickNumber) - this.uniquePickNumber++; - - if (this.uniquePickNumber >= 0x00FFFFFF) - { - this.uniquePickNumber = 1; // no black, no white - if (clearColorCode == this.uniquePickNumber) - this.uniquePickNumber++; - } - - return new java.awt.Color(this.uniquePickNumber, true); // has alpha - } - - public java.awt.Color getClearColor() - { - return this.clearColor; - } - - /** - * Returns true if the Picking mode is active, otherwise return false - * - * @return true for Picking mode, otherwise false - */ - public boolean isPickingMode() - { - return this.isPickingMode; - } - - /** - * Enables color picking mode - */ - public void enablePickingMode() - { - this.isPickingMode = true; - } - - /** - * Disables color picking mode - */ - public void disablePickingMode() - { - this.isPickingMode = false; - } - - public void addOrderedRenderable(OrderedRenderable orderedRenderable) - { - if (null == orderedRenderable) - { - String msg = WorldWind.retrieveErrMsg("nullValue.OrderedRenderable"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - return; // benign event - } - - this.orderedRenderables.add(orderedRenderable); - } - - public java.util.Queue getOrderedRenderables() - { - return this.orderedRenderables; - } - - public void drawUnitQuad() - { - GL gl = this.getGL(); - - gl.glBegin(GL.GL_QUADS); // TODO: use a vertex array or vertex buffer - gl.glVertex2d(0d, 0d); - gl.glVertex2d(1, 0d); - gl.glVertex2d(1, 1); - gl.glVertex2d(0d, 1); - gl.glEnd(); - } - - public void drawUnitQuad(TextureCoords texCoords) - { - GL gl = this.getGL(); - - gl.glBegin(GL.GL_QUADS); // TODO: use a vertex array or vertex buffer - gl.glTexCoord2d(texCoords.left(), texCoords.bottom()); - gl.glVertex2d(0d, 0d); - gl.glTexCoord2d(texCoords.right(), texCoords.bottom()); - gl.glVertex2d(1, 0d); - gl.glTexCoord2d(texCoords.right(), texCoords.top()); - gl.glVertex2d(1, 1); - gl.glTexCoord2d(texCoords.left(), texCoords.top()); - gl.glVertex2d(0d, 1); - gl.glEnd(); - } - - public int getNumTextureUnits() - { - return numTextureUnits; - } - - public void setNumTextureUnits(int numTextureUnits) - { - // TODO: validate arg for >= 1 - this.numTextureUnits = numTextureUnits; - } - - public Vec4 getPointOnGlobe(Angle latitude, Angle longitude) - { - if (latitude == null || longitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LatitudeOrLongitudeIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (!this.getVisibleSector().contains(latitude, longitude)) - return null; - - SectorGeometryList sectorGeometry = this.getSurfaceGeometry(); - if (sectorGeometry != null) - { - Vec4 p = sectorGeometry.getSurfacePoint(latitude, longitude); - if (p != null) - return p; - } - - return null; - -// Globe globe = this.getGlobe(); -// if (globe == null) -// return null; -// -// double elevation = this.getVerticalExaggeration() * globe.getElevation(latitude, longitude); -// return this.getGlobe().computeSurfacePoint(latitude, longitude, elevation); - } - - public SurfaceTileRenderer getSurfaceTileRenderer() - { - return this.surfaceTileRenderer; - } -} diff --git a/gov/nasa/worldwind/ElevationModel.java b/gov/nasa/worldwind/ElevationModel.java deleted file mode 100644 index 82a651d..0000000 --- a/gov/nasa/worldwind/ElevationModel.java +++ /dev/null @@ -1,130 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - *

- * Provides the elevations of all points on a {@link Globe} . Every Globe has an elevation model - * implementing this interface. - *

- * Elevations are organized by {@link Sector}. Elevation models return an {@link Elevations} object for requested - * sectors. This object is then used to query elevations at latitude/longitude positions within that sector. - *

- * An ElevationModel typically approximates elevations at multiple levels of spatial resolution. For any - * given viewing position the model determines an appropriate target resolution. That target resolution may not be - * immediately achievable, however, because the corresponding elevation data might not be locally available and must be - * retrieved from a remote location. When this is the case, the Elevations object returned for a sector - * holds the resolution achievable with the data currently available. That resolution may not be the same as the target - * resolution. The target resolution and the actual resolution are made available in the interface so that users of this - * class may use the resolution values to compare previously computed elevation sectors with newly computed ones, and - * thereby enable effective caching of elevations computed for the sector. - *

- * - * @author Tom Gaskins - * @version $Id: ElevationModel.java 2211 2007-07-03 22:15:13Z tgaskins $ - */ -public interface ElevationModel extends WWObject -{ - boolean isEnabled(); - - void setEnabled(boolean enable); - - /** - * Returns the maximum elevation contained in the elevevation model. This value is the height of the highest point - * on the globe. - * - * @return The maximum elevation of the model - */ - double getMaximumElevation(); - - /** - * Returns the minimum elevation contained in the elevevation model. This value is the height of the lowest point on - * the globe. It may be negative, indicating a value below mean surface level. (Sea level in the case of Earth.) - * - * @return The minimum elevation of the model - */ - double getMinimumElevation(); - - /** - * Computes and returns an {@link Elevations} object for the specified {@link Sector} and target resolution. If the - * target resolution can not currently be achieved, the best available elevations are returned. - *

- * Implementing classes of ElevationModel interpret resolution in a class-specific way. - * See the descriptions of those classes to learn their use of this value. The elevations returned are in the form - * of an {@link Elevations} object. Specific elevations are returned by that object. - * - * @param sector the sector to return elevations for. - * @param resolution a value interpreted in a class-specific way by implementing classes. - * @return An object representing the elevations for the specified sector. Its resolution value will be either the - * specified resolution or the best available alternative. - */ - Elevations getElevations(Sector sector, int resolution); - - /** - * Returns the resolution appropriate to the given {@link Sector} and view parameters. The view parameters are read - * from the specified {@link DrawContext}. Implementing classes of ElevationModel interpret - * resolution in class-specific ways. See the descriptions of subclasses to learn their use of this - * value. This method is used to determine the resolution the model will use if all resources are available to - * compute that resolution. It is subsequently passed to {@link #getElevations(Sector, int)} when a sector's - * resolutions are queried. - * - * @param dc the draw context to read the view and rendering parameters from. - * @param sector the {@link Sector} to compute the target resolution for. - * @return The appropriate resolution for the sector and draw context values. - */ - int getTargetResolution(DrawContext dc, Sector sector, int density); - - double getElevation(Angle latitude, Angle longitude); - - Elevations getBestElevations(Sector sector); - - Elevations getElevationsAtResolution(Sector sector, int resolution); - - /** - * The Elevations interface provides elevations at specified latitude and longitude positions. Objects - * implementing this interface are created by {@link ElevationModel#getElevations(Sector, int)}. - */ - public interface Elevations - { - /** - * Indicates whether the object contains useful elevations. An Elevations instance may exist - * without holding any elevations. This can occur when the resources needed to determine elevations are not yet - * local. This method enables the detection of that case. Callers typically use it to avoid time-consuming - * computations that require valid elevations. - * - * @return true if a call to {@link #getElevation(double, double)} will return valid elevations, - * otherwise false indicating that the value 0 will always be returned from that method. - */ - boolean hasElevations(); - - /** - * Returns the elevation at a specific latitude and longitude, each specified in radians. - * - * @param latRadians the position's latitude in radians, in the range [-π/2, +π/2]. - * @param lonRadians the position's longitude in radians, in the range [-π, +π]. - * @return The elevation at the given position, or 0 if elevations are not available. - */ - double getElevation(double latRadians, double lonRadians); - - /** - * Returns the resolution value of the elevations. The meaning and use of this value is defined by subclasses of - * ElevationModel. - * - * @return the resolution associated with this. - */ - int getResolution(); - - /** - * Returns the {@link Sector} the elevations pertain to. - * - * @return The sector the elevations pertain to. - */ - Sector getSector(); - } -} diff --git a/gov/nasa/worldwind/FileCache.java b/gov/nasa/worldwind/FileCache.java deleted file mode 100644 index 7fcdc88..0000000 --- a/gov/nasa/worldwind/FileCache.java +++ /dev/null @@ -1,34 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: FileCache.java 748 2007-02-03 19:22:54Z tgaskins $ - */ -public interface FileCache -{ - public static final String OS_SPECIFIC_DATA_PATH = "FileCache.OSSpecificDataPathKey"; - - public boolean contains(String fileName); - - public java.io.File newFile(String fileName); - - java.net.URL findFile(String fileName, boolean checkClassPath); - - void removeFile(java.net.URL url); - - void addCacheLocation(String newPath); - - void removeCacheLocation(String newPath); - - java.util.List getCacheLocations(); - - java.io.File getWriteLocation(); - - void addCacheLocation(int index, String newPath); -} diff --git a/gov/nasa/worldwind/FrameController.java b/gov/nasa/worldwind/FrameController.java deleted file mode 100644 index d811d0f..0000000 --- a/gov/nasa/worldwind/FrameController.java +++ /dev/null @@ -1,20 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: FrameController.java 1941 2007-06-02 08:52:28Z tgaskins $ - */ -public interface FrameController -{ - void initializeFrame(DrawContext dc); - - void finalizeFrame(DrawContext dc); - - void clearFrame(DrawContext dc); -} diff --git a/gov/nasa/worldwind/GeoRSSParser.java b/gov/nasa/worldwind/GeoRSSParser.java deleted file mode 100644 index f3717c7..0000000 --- a/gov/nasa/worldwind/GeoRSSParser.java +++ /dev/null @@ -1,569 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; -import org.w3c.dom.*; -import org.xml.sax.*; - -import javax.xml.parsers.*; -import javax.xml.namespace.*; -import java.io.*; -import java.util.*; - -/** - * @author tag - * @version $Id: GeoRSSParser.java 1686 2007-05-02 21:58:49Z tgaskins $ - */ - -public class GeoRSSParser -{ - public static final String GEORSS_URI = "http://www.georss.org/georss"; - public static final String GML_URI = "http://www.opengis.net/gml"; - - public static List parseFragment(String fragmentString, NamespaceContext nsc) - { - return parseShapes(fixNamespaceQualification(fragmentString)); - } - - public static List parseShapes(String docString) - { - if (docString == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (docString.length() < 1) // avoid empty strings - return null; - - try - { - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - docBuilderFactory.setNamespaceAware(true); - DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); - Document doc = docBuilder.parse(new InputSource(new StringReader(docString))); - - List shapes = parseShapes(doc); - - if (shapes == null || shapes.size() < 1) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.NoShapes") + docString; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - return shapes; - } - catch (ParserConfigurationException e) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.ParserConfigurationException"); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - throw new WWRuntimeException(message, e); - } - catch (IOException e) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.IOExceptionParsing") + docString; - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - throw new WWRuntimeException(message, e); - } - catch (SAXException e) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.IOExceptionParsing") + docString; - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - throw new WWRuntimeException(message, e); - } - } - - private static String fixNamespaceQualification(String xmlString) - { - String lcaseString = xmlString.toLowerCase(); - StringBuffer qualifiers = new StringBuffer(); - - if (lcaseString.contains("georss:") && !lcaseString.contains(GEORSS_URI)) - { - qualifiers.append(" xmlns:georss=\""); - qualifiers.append(GEORSS_URI); - qualifiers.append("\""); - } - - if (lcaseString.contains("gml:") && !lcaseString.contains(GML_URI)) - { - qualifiers.append(" xmlns:gml=\""); - qualifiers.append(GML_URI); - qualifiers.append("\""); - } - - if (qualifiers.length() > 0) - { - StringBuffer sb = new StringBuffer(); - sb.append(""); - sb.append(xmlString); - sb.append(""); - - return sb.toString(); - } - - return xmlString; - } - - private static String surroundWithNameSpaces(String docString) - { - StringBuffer sb = new StringBuffer(); - sb.append(""); - sb.append(docString); - sb.append(""); -// System.out.println(sb.toString()); - - return sb.toString(); - } - - public static List parseShapes(File file) - { - if (file == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - try - { - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - docBuilderFactory.setNamespaceAware(false); - DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); - Document doc = docBuilder.parse(file); - - List shapes = parseShapes(doc); - - if (shapes == null || shapes.size() < 1) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.NoShapes") + file.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - return shapes; - } - catch (ParserConfigurationException e) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.ParserConfigurationException"); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - throw new WWRuntimeException(message, e); - } - catch (IOException e) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.IOExceptionParsing") + file.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - throw new WWRuntimeException(message, e); - } - catch (SAXException e) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.IOExceptionParsing") + file.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - throw new WWRuntimeException(message, e); - } - } - - public static List parseShapes(Document xmlDoc) - { - if (xmlDoc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DocumentIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - ArrayList shapeNodes = new ArrayList(); - ArrayList attributeNodes = new ArrayList(); - - // Shapes - NodeList nodes = xmlDoc.getElementsByTagNameNS(GEORSS_URI, "where"); - if (nodes != null && nodes.getLength() > 0) - addNodes(shapeNodes, nodes); - - nodes = xmlDoc.getElementsByTagNameNS(GEORSS_URI, "point"); - if (nodes != null && nodes.getLength() > 0) - addNodes(shapeNodes, nodes); - - nodes = xmlDoc.getElementsByTagNameNS(GEORSS_URI, "line"); - if (nodes != null && nodes.getLength() > 0) - addNodes(shapeNodes, nodes); - - nodes = xmlDoc.getElementsByTagNameNS(GEORSS_URI, "polygon"); - if (nodes != null && nodes.getLength() > 0) - addNodes(shapeNodes, nodes); - - nodes = xmlDoc.getElementsByTagNameNS(GEORSS_URI, "box"); - if (nodes != null && nodes.getLength() > 0) - addNodes(shapeNodes, nodes); - - // Attributes - nodes = xmlDoc.getElementsByTagNameNS(GEORSS_URI, "radius"); - if (nodes != null && nodes.getLength() > 0) - addNodes(attributeNodes, nodes); - - nodes = xmlDoc.getElementsByTagNameNS(GEORSS_URI, "elev"); - if (nodes != null && nodes.getLength() > 0) - addNodes(attributeNodes, nodes); - - ArrayList shapes = new ArrayList(); - - if (shapeNodes.size() < 1) - return null; // No warning here. Let the calling method inform of this case. - - for (Node node : shapeNodes) - { - Renderable shape = null; - String localName = node.getLocalName(); - - if (localName.equals("point")) - shape = makePointShape(node, attributeNodes); - - else if (localName.equals("where")) - shape = makeWhereShape(node); - - else if (localName.equals("line")) - shape = makeLineShape(node, attributeNodes); - - else if (localName.equals("polygon")) - shape = makePolygonShape(node, attributeNodes); - - else if (localName.equals("box")) - shape = makeBoxShape(node, attributeNodes); - - if (shape != null) - shapes.add(shape); - } - - return shapes; - } - - private static void addNodes(ArrayList nodeList, NodeList nodes) - { - for (int i = 0; i < nodes.getLength(); i++) - { - nodeList.add(nodes.item(i)); - } - } - - private static Renderable makeWhereShape(Node node) - { - Node typeNode = findChildByLocalName(node, "Polygon"); - if (typeNode != null) - return makeGMLPolygonShape(typeNode); - - typeNode = findChildByLocalName(node, "Envelope"); - if (typeNode != null) - return makeGMLEnvelopeShape(typeNode); - - typeNode = findChildByLocalName(node, "LineString"); - if (typeNode != null) - return makeGMLineStringShape(typeNode); - - typeNode = findChildByLocalName(node, "Point"); - if (typeNode != null) - return makeGMLPointShape(typeNode); - - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElementContent") + " where"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - private static Renderable makeGMLPolygonShape(Node node) - { - Node n = findChildByLocalName(node, "exterior"); - if (n == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElement") + " exterior"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - n = findChildByLocalName(n, "LinearRing"); - if (n == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElement") + " LinearRing"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - return makePolygonShape(n, null); - } - - private static Renderable makePolygonShape(Node node, Iterable attrs) - { - String valuesString = node.getTextContent(); - if (valuesString == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.NoCoordinates" + node.getLocalName()); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - ArrayList values = getDoubleValues(valuesString); - if (values.size() < 8 || values.size() % 2 != 0) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + node.getLocalName()); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - ArrayList positions = new ArrayList(); - for (int i = 0; i < values.size(); i += 2) - { - positions.add(LatLon.fromDegrees(values.get(i), values.get(i + 1))); - } - - double elevation = attrs != null ? getElevation(node, attrs) : 0d; - if (elevation != 0) - { - Polyline pl = new Polyline(positions, elevation); - pl.setFilled(true); - pl.setFollowGreatCircles(true); - - return pl; - } - else - { - return new SurfacePolygon(positions); - } - } - - private static Renderable makeGMLEnvelopeShape(Node node) - { - Node n = findChildByLocalName(node, "lowerCorner"); - if (n == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElement") + " lowerCorner"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - String lowerCornerString = n.getTextContent(); - if (lowerCornerString == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElementContent") + " lowerCorner"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - n = findChildByLocalName(node, "upperCorner"); - if (n == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElement") + " upperCorner"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - String upperCornerString = n.getTextContent(); - if (upperCornerString == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElementContent") + " upperCorner"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - ArrayList lv = getDoubleValues(lowerCornerString); - if (lv.size() != 2) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + " lowerCorner"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - ArrayList uv = getDoubleValues(upperCornerString); - if (uv.size() != 2) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + " upperCorner"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - return new SurfaceQuadrilateral(Sector.fromDegrees(lv.get(0), uv.get(0), lv.get(1), uv.get(1))); - } - - private static Renderable makeBoxShape(Node node, Iterable attrs) - { - String valuesString = node.getTextContent(); - if (valuesString == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.NoCoordinates" + node.getLocalName()); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - ArrayList p = getDoubleValues(valuesString); - if (p.size() != 4) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + node.getLocalName()); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - double elevation = getElevation(node, attrs); - if (elevation != 0) - return new Quadrilateral(LatLon.fromDegrees(p.get(0), p.get(1)), - LatLon.fromDegrees(p.get(2), p.get(3)), elevation); - else - return new SurfaceQuadrilateral(Sector.fromDegrees(p.get(0), p.get(2), p.get(1), p.get(3))); - } - - private static Renderable makeGMLineStringShape(Node node) - { - Node n = findChildByLocalName(node, "posList"); - if (n == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElement") + " posList"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - return makeLineShape(n, null); - } - - private static Renderable makeLineShape(Node node, Iterable attrs) - { - String valuesString = node.getTextContent(); - if (valuesString == null) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.NoCoordinates" + node.getLocalName()); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - ArrayList values = getDoubleValues(valuesString); - if (values.size() < 4) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.InvalidCoordinateCount" + node.getLocalName()); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - return null; - } - - ArrayList positions = new ArrayList(); - for (int i = 0; i < values.size(); i += 2) - { - positions.add(LatLon.fromDegrees(values.get(i), values.get(i + 1))); - } - - double elevation = attrs != null ? getElevation(node, attrs) : 0d; - if (elevation != 0) - { - Polyline pl = new Polyline(positions, elevation); - pl.setFollowGreatCircles(true); - return pl; - } - else - { - return new SurfacePolyline(positions); - } - } - - @SuppressWarnings({"UnusedDeclaration"}) - private static Renderable makeGMLPointShape(Node node) - { - return null; // No shape provided for points. Expect app to use icons. - } - - @SuppressWarnings({"UnusedDeclaration"}) - private static Renderable makePointShape(Node node, Iterable attrs) - { - return null; // No shape provided for points. Expect app to use icons. - } - - private static Node findChildByLocalName(Node parent, String localName) - { - NodeList children = parent.getChildNodes(); - if (children == null || children.getLength() < 1) - return null; - - for (int i = 0; i < children.getLength(); i++) - { - String ln = children.item(i).getLocalName(); - if (ln != null && ln.equals(localName)) - return children.item(i); - } - - return null; - } - - private static Node findSiblingAttribute(String attrName, Iterable attribs, Node shapeNode) - { - for (Node attrib : attribs) - { - if (!attrib.getLocalName().equals(attrName)) - continue; - - if (attrib.getParentNode().equals(shapeNode.getParentNode())) - return attrib; - } - - return null; - } - - private static ArrayList getDoubleValues(String stringValues) - { - String[] tokens = stringValues.trim().split("[ ,\n]"); - if (tokens.length < 1) - return null; - - ArrayList arl = new ArrayList(); - for (String s : tokens) - { - if (s == null || s.length() < 1) - continue; - - double d; - try - { - d = Double.parseDouble(s); - } - catch (NumberFormatException e) - { - String message = WorldWind.retrieveErrMsg("GeoRSS.NumberFormatException" + s); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - continue; - } - - arl.add(d); - } - - return arl; - } - - private static double getElevation(Node shapeNode, Iterable attrs) - { - double elevation = 0d; - - Node elevNode = findSiblingAttribute("elev", attrs, shapeNode); - if (elevNode != null) - { - ArrayList ev = getDoubleValues(elevNode.getTextContent()); - if (ev != null && ev.size() > 0) - { - elevation = ev.get(0); - } - else - { - String message = WorldWind.retrieveErrMsg("GeoRSS.MissingElementContent") + " elev"; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - } - - return elevation; - } -} diff --git a/gov/nasa/worldwind/Globe.java b/gov/nasa/worldwind/Globe.java deleted file mode 100644 index 0a47c4d..0000000 --- a/gov/nasa/worldwind/Globe.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * @author Tom Gaskins - * @version $Id: Globe.java 1992 2007-06-10 01:23:31Z dcollins $ - */ -public interface Globe extends WWObject, Extent -{ - Vec4 computePointFromPosition(Angle latitude, Angle longitude, double metersElevation); - - Vec4 computeSurfaceNormalAtPoint(Vec4 p); - - ElevationModel getElevationModel(); - - Extent getExtent(); - - double getEquatorialRadius(); - - double getPolarRadius(); - - double getMaximumRadius(); - - double getRadiusAt(Angle latitude, Angle longitude); - - double getElevation(Angle latitude, Angle longitude); - - double getMaxElevation(); - - double getMinElevation(); - - Position getIntersectionPosition(Line line); - - double getEccentricitySquared(); - - Position computePositionFromPoint(Vec4 point); - - Vec4 computePointFromPosition(Position position); -} diff --git a/gov/nasa/worldwind/HTTPRetriever.java b/gov/nasa/worldwind/HTTPRetriever.java deleted file mode 100644 index 3bb10c2..0000000 --- a/gov/nasa/worldwind/HTTPRetriever.java +++ /dev/null @@ -1,61 +0,0 @@ -/* -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; - -import java.net.*; -import java.nio.*; - -/** - * @author Tom Gaskins - * @version $Id: HTTPRetriever.java 1724 2007-05-05 04:05:40Z tgaskins $ - */ -public class HTTPRetriever extends URLRetriever -{ - private int responseCode; - private String responseMessage; - - public HTTPRetriever(URL url, RetrievalPostProcessor postProcessor) - { - super(url, postProcessor); - } - - public int getResponseCode() - { - return this.responseCode; - } - - public String getResponseMessage() - { - return this.responseMessage; - } - - protected ByteBuffer doRead(URLConnection connection) throws Exception - { - if (connection == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ConnectionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - HttpURLConnection htpc = (HttpURLConnection) connection; - this.responseCode = htpc.getResponseCode(); - this.responseMessage = htpc.getResponseMessage(); - String contentType = connection.getContentType(); - - WorldWind.logger().log(java.util.logging.Level.FINER, WorldWind.retrieveErrMsg("HTTPRetriever.ResponseCode") - + this.responseCode - + WorldWind.retrieveErrMsg("HTTPRetriever.ResponseContentLength") + connection.getContentLength() - + (contentType != null ? " " + contentType : " content type not returned") - + WorldWind.retrieveErrMsg("HTTPRetriever.Retrieving") + connection.getURL()); - - if (this.responseCode == HttpURLConnection.HTTP_OK) - return super.doRead(connection); - - return null; - } -} diff --git a/gov/nasa/worldwind/IconRenderer.java b/gov/nasa/worldwind/IconRenderer.java deleted file mode 100644 index 8123f2b..0000000 --- a/gov/nasa/worldwind/IconRenderer.java +++ /dev/null @@ -1,605 +0,0 @@ -/* -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; - -import com.sun.opengl.util.j2d.*; -import com.sun.opengl.util.texture.*; -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import java.awt.*; -import java.awt.image.*; -import java.util.*; - -/** - * @author tag - * @version $Id: IconRenderer.java 2227 2007-07-06 21:48:11Z tgaskins $ - */ -public class IconRenderer implements Disposable -{ - // TODO: Periodically clean unused textures from the texture map. - private java.util.HashMap iconTextures = new java.util.HashMap(); - private Pedestal pedestal; - private PickSupport pickSupport = new PickSupport(); - private HashMap toolTipRenderers = new HashMap(); - - public IconRenderer() - { - } - - public void dispose() - { - // TODO: This works only when a GL context is active. - for (Texture iconTexture : this.iconTextures.values()) - { - if (iconTexture != null) - iconTexture.dispose(); - } - } - - public Pedestal getPedestal() - { - return pedestal; - } - - public void setPedestal(Pedestal pedestal) - { - this.pedestal = pedestal; - } - - private static boolean isIconValid(WWIcon icon, boolean checkPosition) - { - if (icon == null || icon.getImageSource() == null) - return false; - - //noinspection RedundantIfStatement - if (checkPosition && icon.getPosition() == null) - return false; - - return true; - } - - public void pick(DrawContext dc, Iterable icons, java.awt.Point pickPoint, Layer layer) - { - this.drawMany(dc, icons); - } - - public void pick(DrawContext dc, WWIcon icon, Vec4 iconPoint, java.awt.Point pickPoint, Layer layer) - { - if (!isIconValid(icon, false)) - return; - - this.drawOne(dc, icon, iconPoint); - } - - public void render(DrawContext dc, Iterable icons) - { - this.drawMany(dc, icons); - } - - public void render(DrawContext dc, WWIcon icon, Vec4 iconPoint) - { - if (!isIconValid(icon, false)) - return; - - this.drawOne(dc, icon, iconPoint); - } - - private void drawMany(DrawContext dc, Iterable icons) - { - if (dc == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (dc.getVisibleSector() == null) - return; - - SectorGeometryList geos = dc.getSurfaceGeometry(); - //noinspection RedundantIfStatement - if (geos == null) - return; - - if (icons == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.IconIterator"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - Iterator iterator = icons.iterator(); - - if (!iterator.hasNext()) - return; - - while (iterator.hasNext()) - { - WWIcon icon = iterator.next(); - if (!isIconValid(icon, true)) - continue; - - if (!icon.isVisible()) - continue; - - // Determine Cartesian position from the surface geometry if the icon is near the surface, - // otherwise draw it from the globe. - Position pos = icon.getPosition(); - Vec4 iconPoint = null; - if (pos.getElevation() < dc.getGlobe().getMaxElevation()) - iconPoint = dc.getSurfaceGeometry().getSurfacePoint(icon.getPosition()); - if (iconPoint == null) - iconPoint = dc.getGlobe().computePointFromPosition(icon.getPosition()); - - // The icons aren't drawn here, but added to the ordered queue to be drawn back-to-front. - double eyeDistance = dc.getView().getEyePoint().distanceTo3(iconPoint); - dc.addOrderedRenderable(new OrderedIcon(icon, iconPoint, eyeDistance)); - - if (icon.isShowToolTip()) - this.addToolTip(dc, icon, iconPoint); - } - } - - private void drawOne(DrawContext dc, WWIcon icon, Vec4 iconPoint) - { - if (dc == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (dc.getVisibleSector() == null) - return; - - SectorGeometryList geos = dc.getSurfaceGeometry(); - //noinspection RedundantIfStatement - if (geos == null) - return; - - if (!icon.isVisible()) - return; - - if (iconPoint == null) - { - Angle lat = icon.getPosition().getLatitude(); - Angle lon = icon.getPosition().getLongitude(); - - if (!dc.getVisibleSector().contains(lat, lon)) - return; - - iconPoint = dc.getSurfaceGeometry().getSurfacePoint(lat, lon, icon.getPosition().getElevation()); - if (iconPoint == null) - return; - } - - if (!dc.getView().getFrustumInModelCoordinates().contains(iconPoint)) - return; - - double horizon = dc.getView().computeHorizonDistance(); - double eyeDistance = dc.getView().getEyePoint().distanceTo3(iconPoint); - if (eyeDistance > horizon) - return; - - // The icon isn't drawn here, but added to the ordered queue to be drawn back-to-front. - dc.addOrderedRenderable(new OrderedIcon(icon, iconPoint, eyeDistance)); - - if (icon.isShowToolTip()) - this.addToolTip(dc, icon, iconPoint); - } - - private void addToolTip(DrawContext dc, WWIcon icon, Vec4 iconPoint) - { - if (icon.getToolTipFont() == null && icon.getToolTipText() == null) - return; - - final Vec4 screenPoint = dc.getView().project(iconPoint); - if (screenPoint == null) - return; - - OrderedText tip = new OrderedText(icon.getToolTipText(), icon.getToolTipFont(), screenPoint, - icon.getToolTipTextColor(), 0d); - dc.addOrderedRenderable(tip); - } - - private class OrderedText implements OrderedRenderable - { - Font font; - String text; - Vec4 point; - double eyeDistance; - java.awt.Point pickPoint; - Layer layer; - java.awt.Color color; - - OrderedText(String text, Font font, Vec4 point, java.awt.Color color, double eyeDistance) - { - this.text = text; - this.font = font; - this.point = point; - this.eyeDistance = eyeDistance; - this.color = color; - } - - OrderedText(String text, Font font, Vec4 point, java.awt.Point pickPoint, Layer layer, double eyeDistance) - { - this.text = text; - this.font = font; - this.point = point; - this.eyeDistance = eyeDistance; - this.pickPoint = pickPoint; - this.layer = layer; - } - - public double getDistanceFromEye() - { - return this.eyeDistance; - } - - public void render(DrawContext dc) - { - ToolTipRenderer tr = IconRenderer.this.toolTipRenderers.get(this.font); - if (tr == null) - { - if (this.font != null) - tr = new ToolTipRenderer(new TextRenderer(this.font, true, true)); - else - tr = new ToolTipRenderer(); - IconRenderer.this.toolTipRenderers.put(this.font, tr); - } - - Rectangle vp = dc.getView().getViewport(); - tr.setForeground(this.color); - tr.setUseSystemLookAndFeel(this.color == null); - tr.beginRendering(vp.width, vp.height, true); - tr.draw(this.text, (int) point.x, (int) point.y); - tr.endRendering(); - } - - public void pick(DrawContext dc, java.awt.Point pickPoint) - { - } - } - - private class OrderedIcon implements OrderedRenderable, Locatable - { - WWIcon icon; - Vec4 point; - double eyeDistance; - java.awt.Point pickPoint; - Layer layer; - - OrderedIcon(WWIcon icon, Vec4 point, double eyeDistance) - { - this.icon = icon; - this.point = point; - this.eyeDistance = eyeDistance; - } - - OrderedIcon(WWIcon icon, Vec4 point, java.awt.Point pickPoint, Layer layer, double eyeDistance) - { - this.icon = icon; - this.point = point; - this.eyeDistance = eyeDistance; - this.pickPoint = pickPoint; - this.layer = layer; - } - - public double getDistanceFromEye() - { - return this.eyeDistance; - } - - public Position getPosition() - { - return this.icon.getPosition(); - } - - public void render(DrawContext dc) - { - IconRenderer.this.beginDrawIcons(dc); - - try - { - IconRenderer.this.drawIcon(dc, this); - // Draw as many as we can in a batch to save ogl state switching. - while (dc.getOrderedRenderables().peek() instanceof OrderedIcon) - { - OrderedIcon oi = (OrderedIcon) dc.getOrderedRenderables().poll(); - IconRenderer.this.drawIcon(dc, oi); - } - } - catch (WWRuntimeException e) - { - String msg = WorldWind.retrieveErrMsg("generic.ExceptionWhileRenderingIcon"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg + ":" + e.getMessage()); - } - catch (Exception e) - { - String msg = WorldWind.retrieveErrMsg("generic.ExceptionWhileRenderingIcon"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg, e); - } - finally - { - IconRenderer.this.endDrawIcons(dc); - } - } - - public void pick(DrawContext dc, java.awt.Point pickPoint) - { - IconRenderer.this.pickSupport.clearPickList(); - IconRenderer.this.beginDrawIcons(dc); - try - { - IconRenderer.this.drawIcon(dc, this); - // Draw as many as we can in a batch to save ogl state switching. - while (dc.getOrderedRenderables().peek() instanceof OrderedIcon) - { - IconRenderer.this.drawIcon(dc, (OrderedIcon) dc.getOrderedRenderables().poll()); - } - } - catch (WWRuntimeException e) - { - String msg = WorldWind.retrieveErrMsg("generic.ExceptionWhileRenderingIcon"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg + ":" + e.getMessage()); - } - catch (Exception e) - { - String msg = WorldWind.retrieveErrMsg("generic.ExceptionWhilePickingIcon"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg, e); - } - finally - { - IconRenderer.this.endDrawIcons(dc); - IconRenderer.this.pickSupport.resolvePick(dc, pickPoint, layer); - IconRenderer.this.pickSupport.clearPickList(); // to ensure entries can be garbage collected - } - } - } - - private void beginDrawIcons(DrawContext dc) - { - GL gl = dc.getGL(); - - int attributeMask = - GL.GL_DEPTH_BUFFER_BIT // for depth test, depth mask and depth func - | GL.GL_TRANSFORM_BIT // for modelview and perspective - | GL.GL_VIEWPORT_BIT // for depth range - | GL.GL_CURRENT_BIT // for current color - | GL.GL_COLOR_BUFFER_BIT // for alpha test func and ref, and blend - | GL.GL_TEXTURE_BIT // for texture env - | GL.GL_DEPTH_BUFFER_BIT // for depth func - | GL.GL_ENABLE_BIT; // for enable/disable changes - gl.glPushAttrib(attributeMask); - - // Apply the depth buffer but don't change it. - gl.glEnable(GL.GL_DEPTH_TEST); - gl.glDepthMask(false); - - // Suppress any fully transparent image pixels - gl.glEnable(GL.GL_ALPHA_TEST); - gl.glAlphaFunc(GL.GL_GREATER, 0.001f); - - // Load a parallel projection with dimensions (viewportWidth, viewportHeight) - int[] viewport = new int[4]; - gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0); - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glOrtho(0d, viewport[2], 0d, viewport[3], -1d, 1d); - - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPushMatrix(); - - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - - if (dc.isPickingMode()) - { - this.pickSupport.beginPicking(dc); - - // Set up to replace the non-transparent texture colors with the single pick color. - gl.glEnable(GL.GL_TEXTURE_2D); - gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_COMBINE); - gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_SRC0_RGB, GL.GL_PREVIOUS); - gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_RGB, GL.GL_REPLACE); - } - else - { - gl.glEnable(GL.GL_TEXTURE_2D); - gl.glEnable(GL.GL_BLEND); - gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA); - } - } - - private void endDrawIcons(DrawContext dc) - { - if (dc.isPickingMode()) - this.pickSupport.endPicking(dc); - - GL gl = dc.getGL(); - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPopMatrix(); - - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPopMatrix(); - - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - - gl.glPopAttrib(); - } - - private Vec4 drawIcon(DrawContext dc, OrderedIcon uIcon) - { - if (uIcon.point == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - return null; - } - - WWIcon icon = uIcon.icon; - - final Vec4 screenPoint = dc.getView().project(uIcon.point); - if (screenPoint == null) - return null; - - Texture iconTexture = this.iconTextures.get(icon.getImageSource()); - if (iconTexture == null) - iconTexture = this.initializeTexture(dc, icon); - - double pedestalScale; - double pedestalSpacing; - Texture pedestalTexture = null; - if (pedestal != null) - { - pedestalScale = this.pedestal.getScale(); - pedestalSpacing = pedestal.getSpacingPixels(); - - pedestalTexture = this.iconTextures.get(pedestal.getPath()); - if (pedestalTexture == null) - pedestalTexture = this.initializeTexture(dc, pedestal); - } - else - { - pedestalScale = 0d; - pedestalSpacing = 0d; - } - - javax.media.opengl.GL gl = dc.getGL(); - - this.setDepthFunc(dc, screenPoint); - - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glLoadIdentity(); - - Dimension size = icon.getSize(); - double width = size != null ? size.getWidth() : iconTexture.getWidth(); - double height = size != null ? size.getHeight() : iconTexture.getHeight(); - gl.glTranslated(screenPoint.x - width / 2, screenPoint.y + (pedestalScale * height) + pedestalSpacing, 0d); - - if (icon.isHighlighted()) - { - double heightDelta = this.pedestal != null ? 0 : height / 2; // expand only above the pedestal - gl.glTranslated(width / 2, heightDelta, 0); - gl.glScaled(icon.getHighlightScale(), icon.getHighlightScale(), icon.getHighlightScale()); - gl.glTranslated(-width / 2, -heightDelta, 0); - } - - if (dc.isPickingMode()) - { - java.awt.Color color = dc.getUniquePickColor(); - int colorCode = color.getRGB(); - this.pickSupport.addPickableObject(colorCode, icon, uIcon.getPosition(), false); - gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); - } - - iconTexture.bind(); - TextureCoords texCoords = iconTexture.getImageTexCoords(); - gl.glScaled(width, height, 1d); - dc.drawUnitQuad(texCoords); - - if (pedestalTexture != null) - { - gl.glLoadIdentity(); - gl.glTranslated(screenPoint.x - (pedestalScale * (width / 2)), screenPoint.y, 0d); - gl.glScaled(width * pedestalScale, height * pedestalScale, 1d); - - pedestalTexture.bind(); - texCoords = pedestalTexture.getImageTexCoords(); - dc.drawUnitQuad(texCoords); - } - - return screenPoint; - } - - private void setDepthFunc(DrawContext dc, Vec4 screenPoint) - { - GL gl = dc.getGL(); - - if (dc.getView().getAltitude() < dc.getGlobe().getMaxElevation() * dc.getVerticalExaggeration()) - { - double depth = screenPoint.z - (8d * 0.00048875809d); - depth = depth < 0d ? 0d : (depth > 1d ? 1d : depth); - gl.glDepthFunc(GL.GL_LESS); - gl.glDepthRange(depth, depth); - } - else if (screenPoint.z >= 1d) - { - gl.glDepthFunc(GL.GL_EQUAL); - gl.glDepthRange(1d, 1d); - } - else - { - gl.glDepthFunc(GL.GL_ALWAYS); - } - } - - private Texture initializeTexture(DrawContext dc, WWIcon icon) - { - try - { - Texture iconTexture = null; - - if (icon.getImageSource() instanceof String) - { - String path = (String) icon.getImageSource(); - java.io.InputStream iconStream = this.getClass().getResourceAsStream("/" + path); - if (iconStream == null) - { - java.io.File iconFile = new java.io.File(path); - if (iconFile.exists()) - { - iconStream = new java.io.FileInputStream(iconFile); - } - } - iconTexture = TextureIO.newTexture(iconStream, true, null); - } - else if (icon.getImageSource() instanceof BufferedImage) - { - iconTexture = TextureIO.newTexture((BufferedImage) icon.getImageSource(), true); - } - else - { - // TODO: Log case of unknown image-source type. - } - - if (iconTexture == null) - { - // TODO: Log case. - return null; - } - - // Icons with the same path are assumed to be identical textures, so key the texture id off the path. - this.iconTextures.put(icon.getImageSource(), iconTexture); - iconTexture.bind(); - - GL gl = dc.getGL(); - gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR_MIPMAP_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); - - return iconTexture; - } - catch (java.io.IOException e) - { - String msg = WorldWind.retrieveErrMsg("generic.IOExceptionDuringTextureInitialization"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg, e); - throw new WWRuntimeException(msg, e); - } - } - - @Override - public String toString() - { - return WorldWind.retrieveErrMsg("layers.IconLayer.Name"); - } -} diff --git a/gov/nasa/worldwind/InputHandler.java b/gov/nasa/worldwind/InputHandler.java deleted file mode 100644 index 8228858..0000000 --- a/gov/nasa/worldwind/InputHandler.java +++ /dev/null @@ -1,26 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id$ - */ -public interface InputHandler extends AVList, java.beans.PropertyChangeListener -{ - void setEventSource(WorldWindow newWorldWindow); - - WorldWindow getEventSource(); - - void setHoverDelay(int delay); - - int getHoverDelay(); - - void addSelectListener(SelectListener listener); - - void removeSelectListener(SelectListener listener); -} diff --git a/gov/nasa/worldwind/Layer.java b/gov/nasa/worldwind/Layer.java deleted file mode 100644 index 2edb783..0000000 --- a/gov/nasa/worldwind/Layer.java +++ /dev/null @@ -1,34 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: Layer.java 1424 2007-04-07 04:08:12Z tgaskins $ - */ -public interface Layer extends WWObject, Disposable -{ - public boolean isEnabled(); - - public void setEnabled(boolean enabled); - - String getName(); - - void setName(String name); - - double getOpacity(); - - void setOpacity(double opacity); - - boolean isPickEnabled(); - - void setPickEnabled(boolean isPickable); - - public void render(DrawContext dc); - - public void pick(DrawContext dc, java.awt.Point pickPoint); -} diff --git a/gov/nasa/worldwind/LayerList.java b/gov/nasa/worldwind/LayerList.java deleted file mode 100644 index 9dca1c6..0000000 --- a/gov/nasa/worldwind/LayerList.java +++ /dev/null @@ -1,316 +0,0 @@ -package gov.nasa.worldwind; - -import java.util.*; -import java.util.concurrent.*; -import java.beans.*; - -/* -Copyright (C) 2001, 2006 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Tom Gaskins - * @version $Id: LayerList.java 2215 2007-07-04 15:38:23Z tgaskins $ - */ -public class LayerList extends CopyOnWriteArrayList implements WWObject -{ - private WWObjectImpl wwo = new WWObjectImpl(this); - - public LayerList() - { - } - - public LayerList(Layer[] layers) - { - if (layers == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LayersIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - for (Layer layer : layers) - { - this.add(layer); - } - } - - @Override - public Object clone() - { - LayerList newList = (LayerList) super.clone(); - newList.wwo = new WWObjectImpl(newList); - for (Layer l : newList) - l.removePropertyChangeListener(this); - - return newList; - } - - public boolean add(Layer layer) - { - if (layer == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LayerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - super.add(layer); - layer.addPropertyChangeListener(this); - this.firePropertyChange(AVKey.LAYERS, null, this); - - return true; - } - - public void add(int index, Layer layer) - { - if (layer == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LayerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - super.add(index, layer); - layer.addPropertyChangeListener(this); - this.firePropertyChange(AVKey.LAYERS, null, this); - } - - public void remove(Layer layer) - { - if (layer == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.LayerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (!this.contains(layer)) - return; - - layer.removePropertyChangeListener(this); - super.remove(layer); - this.firePropertyChange(AVKey.LAYERS, null, this); - } - - public Layer remove(int index) - { - Layer layer = get(index); - if (layer == null) - return null; - - layer.removePropertyChangeListener(this); - super.remove(index); - this.firePropertyChange(AVKey.LAYERS, null, this); - - return layer; - } - - public Layer get(int index) - { - return super.get(index); - } - - public Layer set(int index, Layer layer) - { - if (layer == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LayerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - Layer oldLayer = this.get(index); - if (oldLayer != null) - oldLayer.removePropertyChangeListener(this); - - super.set(index, layer); - layer.addPropertyChangeListener(this); - this.firePropertyChange(AVKey.LAYERS, null, this); - - return oldLayer; - } - - public boolean remove(Object o) - { - for (Layer layer : this) - { - if (layer.equals(o)) - layer.removePropertyChangeListener(this); - } - - boolean removed = super.remove(o); - if (removed) - this.firePropertyChange(AVKey.LAYERS, null, this); - - return removed; - } - - public boolean addIfAbsent(Layer layer) - { - for (Layer l : this) - { - if (l.equals(layer)) - return false; - } - - layer.addPropertyChangeListener(this); - - boolean added = super.addIfAbsent(layer); - if (added) - this.firePropertyChange(AVKey.LAYERS, null, this); - - return added; - } - - public boolean removeAll(Collection objects) - { - for (Layer layer : this) - layer.removePropertyChangeListener(this); - - boolean removed = super.removeAll(objects); - if (removed) - this.firePropertyChange(AVKey.LAYERS, null, this); - - return removed; - } - - public int addAllAbsent(Collection layers) - { - for (Layer layer : layers) - { - if (!this.contains(layer)) - layer.addPropertyChangeListener(this); - } - - int numAdded = super.addAllAbsent(layers); - if (numAdded > 0) - this.firePropertyChange(AVKey.LAYERS, null, this); - - return numAdded; - } - - public boolean addAll(Collection layers) - { - boolean added = super.addAll(layers); - if (added) - this.firePropertyChange(AVKey.LAYERS, null, this); - - return added; - } - - public boolean addAll(int i, Collection layers) - { - for (Layer layer : layers) - layer.addPropertyChangeListener(this); - - boolean added = super.addAll(i, layers); - if (added) - this.firePropertyChange(AVKey.LAYERS, null, this); - - return added; - } - - public boolean retainAll(Collection objects) - { - for (Layer layer : this) - { - if (!objects.contains(layer)) - layer.removePropertyChangeListener(this); - } - - boolean added = super.retainAll(objects); - if (added) - this.firePropertyChange(AVKey.LAYERS, null, this); - - return added; - } - - public Object getValue(String key) - { - return wwo.getValue(key); - } - - public Set> getValues() - { - return wwo.getValues(); - } - - public String getStringValue(String key) - { - return wwo.getStringValue(key); - } - - public void setValue(String key, Object value) - { - wwo.setValue(key, value); - } - - public void setValues(AVList avList) - { - wwo.setValues(avList); - } - - public boolean hasKey(String key) - { - return wwo.hasKey(key); - } - - public void removeKey(String key) - { - wwo.removeKey(key); - } - - public AVList copy() - { - return wwo.copy(); - } - - public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) - { - wwo.addPropertyChangeListener(propertyName, listener); - } - - public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) - { - wwo.removePropertyChangeListener(propertyName, listener); - } - - public void addPropertyChangeListener(PropertyChangeListener listener) - { - wwo.addPropertyChangeListener(listener); - } - - public void removePropertyChangeListener(PropertyChangeListener listener) - { - wwo.removePropertyChangeListener(listener); - } - - public void firePropertyChange(PropertyChangeEvent propertyChangeEvent) - { - wwo.firePropertyChange(propertyChangeEvent); - } - - public void firePropertyChange(String propertyName, Object oldValue, Object newValue) - { - wwo.firePropertyChange(propertyName, oldValue, newValue); - } - - public void propertyChange(PropertyChangeEvent propertyChangeEvent) - { - wwo.propertyChange(propertyChangeEvent); - } - - @Override - public String toString() - { - String r = ""; - for (Layer l : this) - { - r += l.toString() + ", "; - } - return r; - } -} diff --git a/gov/nasa/worldwind/Level.java b/gov/nasa/worldwind/Level.java deleted file mode 100644 index 00ed973..0000000 --- a/gov/nasa/worldwind/Level.java +++ /dev/null @@ -1,329 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.net.*; - -/** - * @author tag - * @version $Id: Level.java 2146 2007-06-26 07:24:14Z tgaskins $ - */ -public class Level implements Comparable -{ - private final AVList params; - private final int levelNumber; - private final String levelName; // null or empty level name signifies no data resources associated with this level - private final LatLon tileDelta; - private final int tileWidth; - private final int tileHeight; - private final String cacheName; - private final String service; - private final String dataset; - private final String formatSuffix; - private final double averageTexelSize; - private final String path; - private final TileUrlBuilder urlBuilder; - private long expiryTime = 0; - - // Absent tiles: A tile is deemed absent if a specified maximum number of attempts have been made to retrieve it. - // Retrieval attempts are governed by a minimum time interval between successive attempts. If an attempt is made - // within this interval, the tile is still deemed to be absent until the interval expires. - private final AbsentResourceList absentTiles; - int DEFAULT_MAX_ABSENT_TILE_ATTEMPTS = 2; - int DEFAULT_MIN_ABSENT_TILE_CHECK_INTERVAL = 10000; // milliseconds - - public Level(AVList params) - { - if (params == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.LayerParams"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.params = params.copy(); // Private copy to insulate from subsequent changes by the app - String message = this.validate(params); - if (message != null) - { - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - String ln = this.params.getStringValue(AVKey.LEVEL_NAME); - this.levelName = ln != null ? ln : ""; - - this.levelNumber = (Integer) this.params.getValue(AVKey.LEVEL_NUMBER); - this.tileDelta = (LatLon) this.params.getValue(AVKey.TILE_DELTA); - this.tileWidth = (Integer) this.params.getValue(AVKey.TILE_WIDTH); - this.tileHeight = (Integer) this.params.getValue(AVKey.TILE_HEIGHT); - this.cacheName = this.params.getStringValue(AVKey.CACHE_NAME); - this.service = this.params.getStringValue(AVKey.SERVICE); - this.dataset = this.params.getStringValue(AVKey.DATASET_NAME); - this.formatSuffix = this.params.getStringValue(AVKey.FORMAT_SUFFIX); - this.urlBuilder = (TileUrlBuilder) this.params.getValue(AVKey.TILE_URL_BUILDER); - this.expiryTime = AVListImpl.getLongValue(params, AVKey.EXPIRY_TIME, 0L); - - double averageTileSize = 0.5 * (this.tileWidth + this.tileHeight); - double averageTileDelta = - 0.5 * (this.tileDelta.getLatitude().getRadians() + this.tileDelta.getLongitude().getRadians()); - this.averageTexelSize = averageTileDelta / averageTileSize; - - this.path = this.cacheName + "/" + this.levelName; - - Integer maxAbsentTileAttempts = (Integer) this.params.getValue(AVKey.MAX_ABSENT_TILE_ATTEMPTS); - if (maxAbsentTileAttempts == null) - maxAbsentTileAttempts = DEFAULT_MAX_ABSENT_TILE_ATTEMPTS; - - Integer minAbsentTileCheckInterval = (Integer) this.params.getValue(AVKey.MIN_ABSENT_TILE_CHECK_INTERVAL); - if (minAbsentTileCheckInterval == null) - minAbsentTileCheckInterval = DEFAULT_MIN_ABSENT_TILE_CHECK_INTERVAL; - - this.absentTiles = new AbsentResourceList(maxAbsentTileAttempts, minAbsentTileCheckInterval); - } - - /** - * Determines whether the constructor arguments are valid. - * @param params the list of parameters to validate. - * @return null if valid, otherwise a String containing a description of why it's invalid. - */ - protected String validate(AVList params) - { - StringBuffer sb = new StringBuffer(); - - Object o = params.getValue(AVKey.LEVEL_NUMBER); - if (o == null || !(o instanceof Integer) || ((Integer) o) < 0) - sb.append(WorldWind.retrieveErrMsg("term.levelNumber")); - - o = params.getValue(AVKey.LEVEL_NAME); - if (o == null || !(o instanceof String)) - sb.append(WorldWind.retrieveErrMsg("term.levelName")); - - o = params.getValue(AVKey.TILE_WIDTH); - if (o == null || !(o instanceof Integer) || ((Integer) o) < 0) - sb.append(WorldWind.retrieveErrMsg("term.tileWidth")); - - o = params.getValue(AVKey.TILE_HEIGHT); - if (o == null || !(o instanceof Integer) || ((Integer) o) < 0) - sb.append(WorldWind.retrieveErrMsg("term.tileHeight")); - - o = params.getValue(AVKey.TILE_DELTA); - if (o == null || !(o instanceof LatLon)) - sb.append(WorldWind.retrieveErrMsg("term.tileDelta")); - - o = params.getValue(AVKey.CACHE_NAME); - if (o == null || !(o instanceof String) || ((String) o).length() < 1) - sb.append(WorldWind.retrieveErrMsg("term.cacheFolder")); - - o = params.getValue(AVKey.TILE_URL_BUILDER); - if (o == null || !(o instanceof TileUrlBuilder)) - sb.append(WorldWind.retrieveErrMsg("term.tileURLBuilder")); - - o = params.getValue(AVKey.EXPIRY_TIME); - if (o != null && (!(o instanceof Long) || ((Long) o) < 1)) - sb.append(WorldWind.retrieveErrMsg("term.expiryTime")); - - if (params.getStringValue(AVKey.LEVEL_NAME).length() > 0) - { - o = params.getValue(AVKey.SERVICE); - if (o == null || !(o instanceof String) || ((String) o).length() < 1) - sb.append(WorldWind.retrieveErrMsg("term.service")); - - o = params.getValue(AVKey.DATASET_NAME); - if (o == null || !(o instanceof String) || ((String) o).length() < 1) - sb.append(WorldWind.retrieveErrMsg("term.datasetName")); - - o = params.getValue(AVKey.FORMAT_SUFFIX); - if (o == null || !(o instanceof String) || ((String) o).length() < 1) - sb.append(WorldWind.retrieveErrMsg("term.formatSuffix")); - } - - if (sb.length() == 0) - return null; - - return sb.insert(0, WorldWind.retrieveErrMsg("layers.LevelSet.InvalidLevelDescriptorFields")).toString(); - } - - public final AVList getParams() - { - return params; - } - - public String getPath() - { - return this.path; - } - - public final int getLevelNumber() - { - return this.levelNumber; - } - - public String getLevelName() - { - return this.levelName; - } - - public LatLon getTileDelta() - { - return this.tileDelta; - } - - public final int getTileWidth() - { - return this.tileWidth; - } - - public final int getTileHeight() - { - return this.tileHeight; - } - - public final String getFormatSuffix() - { - return this.formatSuffix; - } - - public final String getService() - { - return this.service; - } - - public final String getDataset() - { - return this.dataset; - } - - public final String getCacheName() - { - return this.cacheName; - } - - public final double getTexelSize(double radius) - { - return radius * this.averageTexelSize; - } - - public final boolean isEmpty() - { - return this.levelName == null || this.levelName.equals(""); - } - - public final void markResourceAbsent(long tileNumber) - { - this.absentTiles.markResourceAbsent(tileNumber); - } - - public final boolean isResourceAbsent(long tileNumber) - { - return this.absentTiles.isResourceAbsent(tileNumber); - } - - public final void unmarkResourceAbsent(long tileNumber) - { - this.absentTiles.unmarkResourceAbsent(tileNumber); - } - - public final long getExpiryTime() - { - return expiryTime; - } - - public void setExpiryTime(long expiryTime) // TODO: remove - { - this.expiryTime = expiryTime; - } - -// public interface TileURLBuilder -// { -// public URL getURL(Tile tile) throws java.net.MalformedURLException; -// } - - /** - * Returns the URL necessary to retrieve the specified tile. - * @param tile the tile who's resources will be retrieved. - * @return the resource URL. - * @throws java.net.MalformedURLException if the URL cannot be formed from the tile's parameters. - * @throws IllegalArgumentException if tile is null. - */ - public java.net.URL getTileResourceURL(Tile tile) throws java.net.MalformedURLException - { - if (tile == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.TileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - return this.urlBuilder.getURL(tile); - } - - public int compareTo(Level that) - { - if (that == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.LevelIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - return this.levelNumber < that.levelNumber ? -1 : this.levelNumber == that.levelNumber ? 0 : 1; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final gov.nasa.worldwind.Level level = (gov.nasa.worldwind.Level) o; - - if (levelNumber != level.levelNumber) - return false; - if (tileHeight != level.tileHeight) - return false; - if (tileWidth != level.tileWidth) - return false; - if (cacheName != null ? !cacheName.equals(level.cacheName) : level.cacheName != null) - return false; - if (dataset != null ? !dataset.equals(level.dataset) : level.dataset != null) - return false; - if (formatSuffix != null ? !formatSuffix.equals(level.formatSuffix) : level.formatSuffix != null) - return false; - if (levelName != null ? !levelName.equals(level.levelName) : level.levelName != null) - return false; - if (service != null ? !service.equals(level.service) : level.service != null) - return false; - //noinspection RedundantIfStatement - if (tileDelta != null ? !tileDelta.equals(level.tileDelta) : level.tileDelta != null) - return false; - - return true; - } - - public int hashCode() - { - int result; - result = levelNumber; - result = 29 * result + (levelName != null ? levelName.hashCode() : 0); - result = 29 * result + (tileDelta != null ? tileDelta.hashCode() : 0); - result = 29 * result + tileWidth; - result = 29 * result + tileHeight; - result = 29 * result + (formatSuffix != null ? formatSuffix.hashCode() : 0); - result = 29 * result + (service != null ? service.hashCode() : 0); - result = 29 * result + (dataset != null ? dataset.hashCode() : 0); - result = 29 * result + (cacheName != null ? cacheName.hashCode() : 0); - return result; - } - - @Override - public String toString() - { - return this.path; - } -} diff --git a/gov/nasa/worldwind/LevelSet.java b/gov/nasa/worldwind/LevelSet.java deleted file mode 100644 index c044f49..0000000 --- a/gov/nasa/worldwind/LevelSet.java +++ /dev/null @@ -1,234 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.net.*; -import java.util.*; - -/** - * @author tag - * @version $Id: LevelSet.java 2092 2007-06-19 07:55:46Z garakl $ - */ -public class LevelSet extends WWObjectImpl -{ - private final Sector sector; - private final LatLon levelZeroTileDelta; - private final int numLevelZeroColumns; - private final java.util.ArrayList levels = new java.util.ArrayList(); - - public LevelSet(AVList params) - { - StringBuffer sb = new StringBuffer(); - - Object o = params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA); - if (o == null || !(o instanceof LatLon)) - sb.append(WorldWind.retrieveErrMsg("term.tileDelta")); - - o = params.getValue(AVKey.SECTOR); - if (o == null || !(o instanceof Sector)) - sb.append(WorldWind.retrieveErrMsg("term.sector")); - - int numLevels = 0; - o = params.getValue(AVKey.NUM_LEVELS); - if (o == null || !(o instanceof Integer) || (numLevels = (Integer) o) < 1) - sb.append(WorldWind.retrieveErrMsg("term.numLevels")); - - int numEmptyLevels = 0; - o = params.getValue(AVKey.NUM_EMPTY_LEVELS); - if (o == null || !(o instanceof Integer) || (numEmptyLevels = (Integer) o) < 0) - sb.append(WorldWind.retrieveErrMsg("term.numEMptyLevels")); - - if (sb.length() > 0) - { - String message = WorldWind.retrieveErrMsg("layers.LevelSet.InvalidLevelDescriptorFields") - + " " + sb.toString(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.levelZeroTileDelta = (LatLon) params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA); - this.sector = (Sector) params.getValue(AVKey.SECTOR); - - params = params.copy(); // copy so as not to modify the user's params - - TileUrlBuilder tub = (TileUrlBuilder) params.getValue(AVKey.TILE_URL_BUILDER); - if (tub == null) - { - params.setValue(AVKey.TILE_URL_BUILDER, new TileUrlBuilder() - { - public URL getURL(Tile tile) throws MalformedURLException - { - StringBuffer sb = new StringBuffer(tile.getLevel().getService()); - if (sb.lastIndexOf("?") != sb.length() - 1) - sb.append("?"); - sb.append("T="); - sb.append(tile.getLevel().getDataset()); - sb.append("&L="); - sb.append(tile.getLevel().getLevelName()); - sb.append("&X="); - sb.append(tile.getColumn()); - sb.append("&Y="); - sb.append(tile.getRow()); - - return new URL(sb.toString()); - } - }); - } - - for (int i = 0; i < numLevels; i++) - { - params.setValue(AVKey.LEVEL_NAME, i < numEmptyLevels ? "" : Integer.toString(i - numEmptyLevels)); - params.setValue(AVKey.LEVEL_NUMBER, i); - - Angle latDelta = this.levelZeroTileDelta.getLatitude().divide(Math.pow(2, i)); - Angle lonDelta = this.levelZeroTileDelta.getLongitude().divide(Math.pow(2, i)); - params.setValue(AVKey.TILE_DELTA, new LatLon(latDelta, lonDelta)); - - this.levels.add(new Level(params)); - } - - this.numLevelZeroColumns = - (int) Math.round(this.sector.getDeltaLon().divide(this.levelZeroTileDelta.getLongitude())); - } - - public LevelSet(LevelSet source) - { - if (source == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.LevelSetIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.levelZeroTileDelta = source.levelZeroTileDelta; - this.sector = source.sector; - this.numLevelZeroColumns = source.numLevelZeroColumns; - - for (Level level : source.levels) - { - this.levels.add(level); // Levels are final, so it's safe to copy references. - } - } - - public final Sector getSector() - { - return this.sector; - } - - public final LatLon getLevelZeroTileDelta() - { - return this.levelZeroTileDelta; - } - - public final ArrayList getLevels() - { - return this.levels; - } - - public final Level getLevel(int levelNumber) - { - return (levelNumber >= 0 && levelNumber < this.levels.size()) ? this.levels.get(levelNumber) : null; - } - - public final int getNumLevels() - { - return this.levels.size(); - } - - public final Level getFirstLevel() - { - return this.getLevel(0); - } - - public final Level getLastLevel() - { - return this.getLevel(this.getNumLevels() - 1); - } - - public final boolean isFinalLevel(int levelNum) - { - return levelNum == this.getNumLevels() - 1; - } - - public final boolean isLevelEmpty(int levelNumber) - { - return this.levels.get(levelNumber).isEmpty(); - } - - private int numColumnsInLevel(Level level) - { - int levelDelta = level.getLevelNumber() - this.getFirstLevel().getLevelNumber(); - double twoToTheN = Math.pow(2, levelDelta); - return (int) (twoToTheN * this.numLevelZeroColumns); - } - - private long getTileNumber(Tile tile) - { - return tile.getRow() * this.numColumnsInLevel(tile.getLevel()) + tile.getColumn(); - } - - /** - * Instructs the level set that a tile is likely to be absent. - * - * @param tile The tile to mark as having an absent resource. - * @throws IllegalArgumentException if tile is null - */ - public final void markResourceAbsent(Tile tile) - { - if (tile == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.TileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - tile.getLevel().markResourceAbsent(this.getTileNumber(tile)); - } - - /** - * Indicates whether a tile has been marked as absent. - * - * @param tile The tile in question. - * @return true if the tile is marked absent, otherwise false. - * @throws IllegalArgumentException if tile is null - */ - public final boolean isResourceAbsent(Tile tile) - { - if (tile == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.TileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (tile.getLevel().isEmpty()) - return true; - - int tileNumber = tile.getRow() * this.numColumnsInLevel(tile.getLevel()) + tile.getColumn(); - return tile.getLevel().isResourceAbsent(tileNumber); - } - - /** - * Removes the absent-tile mark associated with a tile, if one is associatied. - * - * @param tile The tile to unmark. - * @throws IllegalArgumentException if tile is null - */ - public final void unmarkResourceAbsent(Tile tile) - { - if (tile == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.TileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - tile.getLevel().unmarkResourceAbsent(this.getTileNumber(tile)); - } -} diff --git a/gov/nasa/worldwind/Material.java b/gov/nasa/worldwind/Material.java deleted file mode 100644 index 4c22855..0000000 --- a/gov/nasa/worldwind/Material.java +++ /dev/null @@ -1,103 +0,0 @@ -/* -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; - -import java.awt.Color; - -/** - * @author tag - * @version $Id: Material.java 1175 2007-03-07 21:16:55Z tgaskins $ - */ -public class Material -{ - public static final int SPECULAR = 0; - public static final int DIFFUSE = 1; - public static final int AMBIENT = 2; - public static final int EMISSION = 3; - - public static final Material WHITE = new Material(new Color(0.9f, 0.9f, 0.9f, 0.0f), new Color(0.8f, 0.8f, 0.8f, - 0.0f), new Color(0.2f, 0.2f, 0.2f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); - - public static final Material RED = new Material(new Color(0.75f, 0.0f, 0.0f, 0.0f), new Color(0.8f, 0.0f, 0.0f, - 0.0f), new Color(0.2f, 0.0f, 0.0f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); - - public static final Material GREEN = new Material(new Color(0.0f, 0.75f, 0.0f, 0.0f), new Color(0.0f, 0.8f, 0.0f, - 0.0f), new Color(0.0f, 0.2f, 0.0f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); - - public static final Material BLUE = new Material(new Color(0.0f, 0.0f, 0.75f, 0.0f), new Color(0.0f, 0.0f, 0.8f, - 0.0f), new Color(0.0f, 0.0f, 0.2f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); - - public static final Material YELLOW = new Material(new Color(0.75f, 0.75f, 0.55f, 0.0f), new Color(0.8f, 0.8f, 0.0f, - 0.0f), new Color(0.2f, 0.2f, 0.01f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); - - private final Color specular; - private final Color diffuse; - private final Color ambient; - private final Color emission; - private final float shininess; - - /** - * @param specular - * @param diffuse - * @param ambient - * @param emission - * @param shininess - * @throws IllegalArgumentException if specular, diffuse, ambient or - * emission is null - */ - public Material(Color specular, Color diffuse, Color ambient, Color emission, float shininess) - { - if (specular == null || diffuse == null || ambient == null || emission == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ColorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.specular = specular; - this.diffuse = diffuse; - this.ambient = ambient; - this.emission = emission; - this.shininess = shininess; - } - - public Color getSpecular() - { - return this.specular; - } - - public Color getDiffuse() - { - return this.diffuse; - } - - public Color getAmbient() - { - return this.ambient; - } - - public Color getEmission() - { - return this.emission; - } - - public float getShininess() - { - return this.shininess; - } - - public void apply(javax.media.opengl.GL gl, int face) - { - float[] rgba = new float[4]; - - gl.glMaterialfv(face, javax.media.opengl.GL.GL_SPECULAR, this.specular.getRGBComponents(rgba), 0); - gl.glMaterialfv(face, javax.media.opengl.GL.GL_DIFFUSE, this.diffuse.getRGBComponents(rgba), 0); - gl.glMaterialfv(face, javax.media.opengl.GL.GL_AMBIENT, this.ambient.getRGBComponents(rgba), 0); - gl.glMaterialf(face, javax.media.opengl.GL.GL_SHININESS, this.shininess); - gl.glMaterialfv(face, javax.media.opengl.GL.GL_EMISSION, this.emission.getRGBComponents(rgba), 0); - } -} diff --git a/gov/nasa/worldwind/MemoryCache.java b/gov/nasa/worldwind/MemoryCache.java deleted file mode 100644 index c6c147b..0000000 --- a/gov/nasa/worldwind/MemoryCache.java +++ /dev/null @@ -1,174 +0,0 @@ -/* -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; - -/** - * @author Eric Dalgliesh - * @version $Id: MemoryCache.java 403 2006-12-13 02:33:18Z ericdalgliesh $ - */ -public interface MemoryCache /*extends gov.nasa.worldwind.MemoryCache*/ -{ - /** - * retrieve an unordered Set of the keys of the objects in this MemoryCache. - * - * @return a Set containing all the keys in the cache. - */ - java.util.Set getKeySet(); - - /** - * Provides the interface for cache clients to be notified of key events. Currently the only key event is the - * removal of an entry from the cache. A client may need to know a removal instigated by the cache occurred in order - * to adjust its own state or to free resources associated with the removed entry. - */ - public interface CacheListener - { - public void entryRemoved(Object key, Object clientObject); - } - - /** - * Adds a new cacheListener, which will be sent notification whenever an entry is removed from the - * cache. - * - * @param listener the new MemoryCache.CacheListener - */ - void addCacheListener(CacheListener listener); - - /** - * Removes a CacheListener, notifications of events will no longer be sent to this listener. - * - * @param listener - */ - void removeCacheListener(gov.nasa.worldwind.MemoryCache.CacheListener listener); - - /** - * Discovers whether or not this cache contains the object referenced by key. Currently no interface exists - * to discover if an object resides in the cache by referencing itself. - * - * @param key the key which the object is referenced by. - * @return true if the key is found in the cache, false otherwise. - */ - boolean contains(Object key); - - /** - * Attempts to add the object clientObject, with size objectSize and referred to by - * key to the cache. objectSize is the size in bytes, but is not checked for accuracy. - * Returns whether or not the add was successful. - *

- * Note that the size passed in may be used, rather than the real size of the object. In some implementations, the - * accuracy of the space used calls will depend on the collection of these sizes, rather than actual size. - *

- * This method should be declared synchronized when it is implemented. - * - * @param key an object used to reference the cached item - * @param clientObject the item to be cached - * @param objectSize the size of the item in bytes. - * @return true if object was added, false otherwise - */ - boolean add(Object key, Object clientObject, long objectSize); - - /** - * Attempts to add the Cacheable object referenced by the key. No explicit size value is required as - * this method queries the Cacheable to discover the size. - *

- * This method should be declared synchronized when it is implemented. - * - * @param key - * @param clientObject - * @return true if object was added, false otherwise - * @see Cacheable - */ - boolean add(Object key, Cacheable clientObject); - - /** - * Remove an object from the MemoryCache referenced by key. If the object is already absent, this - * method simply returns without indicating the absence. - * - * @param key an Object used to represent the item to remove. - */ - void remove(Object key); - - /** - * Retrieves the requested item from the cache. If key is null or the item is not found, this method - * returns null. - * - * @param key an Object used to represent the item to retrieve - * @return the requested Object if found, null otherwise - */ - Object getObject(Object key); - - /** - * Empties the cache. After calling clear() on a MemoryCache, calls relating to used - * capacity and number of items should return zero and the free capacity should be the maximum capacity. - *

- * This method should be declared synchronized when it is implemented and should notify all - * CacheListeners of entries removed. - */ - void clear(); - - /* *************************************************************************/ - // capacity related accessors - - /** - * Retrieve the number of items stored in the MemoryCache. - * - * @return the number of items in the cache - */ - int getNumObjects(); - - /** - * Retrieves the maximum size of the cache in bytes. - * - * @return the maximum size of the MemoryCache in bytes. - */ - long getCapacity(); - - /** - * Retrieves the amount of used MemoryCache space. The value returned is in bytes. - * - * @return the long value of the number of bytes used by cached items. - */ - long getUsedCapacity(); - - /** - * Retrieves the available space for storing new items. - * - * @return the long value of the remaining space for storing cached items. - */ - long getFreeCapacity(); - - /** - * Retrieves the low water value of the MemoryCache. When a MemoryCache runs out of free - * space, it must remove some items if it wishes to add any more. It continues removing items until the low water - * level is reached. Not every MemoryCache necessarily uses the low water system, so this may not - * return a useful value. - * - * @return the low water value of the MemoryCache. - */ - long getLowWater(); - - /* *******************************************************************************/ - //capacity related mutators - - /** - * Sets the new low water capacity value for this MemoryCache. When a MemoryCache runs out - * of free space, it must remove some items if it wishes to add any more. It continues removing items until the low - * water level is reached. Not every MemoryCache necessarily uses the low water system, so this method - * may not have any actual effect in some implementations. - * - * @param loWater the new low water value in bytes - */ - void setLowWater(long loWater); - - /** - * Sets the maximum capacity for this cache in bytes. This capacity has no impact on the number of - * items stored in the MemoryCache, except that every item must have a positive size. Generally the - * used capacity is the total of the sizes of all stored items. - * - * @param capacity the new capacity in bytes - */ - void setCapacity(long capacity); -} diff --git a/gov/nasa/worldwind/OrderedRenderable.java b/gov/nasa/worldwind/OrderedRenderable.java deleted file mode 100644 index 65c5344..0000000 --- a/gov/nasa/worldwind/OrderedRenderable.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id$ - */ -public interface OrderedRenderable extends Renderable, Pickable -{ - double getDistanceFromEye(); -} diff --git a/gov/nasa/worldwind/Pedestal.java b/gov/nasa/worldwind/Pedestal.java deleted file mode 100644 index 997bc71..0000000 --- a/gov/nasa/worldwind/Pedestal.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * @author tag - * @version $Id$ - */ -public class Pedestal extends UserFacingIcon -{ - private double spacingPixels = 2d; - private double scale = 1d; - - public Pedestal(String iconPath, Position iconPosition) - { - super(iconPath, iconPosition); - } - - public double getSpacingPixels() - { - return spacingPixels; - } - - public void setSpacingPixels(double spacingPixels) - { - this.spacingPixels = spacingPixels; - } - - public double getScale() - { - return scale; - } - - public void setScale(double scale) - { - this.scale = scale; - } -} diff --git a/gov/nasa/worldwind/PickSupport.java b/gov/nasa/worldwind/PickSupport.java deleted file mode 100644 index 7fde5e5..0000000 --- a/gov/nasa/worldwind/PickSupport.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import com.sun.opengl.util.*; - -import javax.media.opengl.*; -import java.util.*; - -/** - * @author tag - * @version $Id: PickSupport.java 1754 2007-05-06 23:19:22Z tgaskins $ - */ -public class PickSupport -{ - private HashMap pickableObjects = new HashMap(); - - public void clearPickList() - { - this.pickableObjects.clear(); - } - - public void addPickableObject(int colorCode, Object o, Position position, boolean isTerrain) - { - this.pickableObjects.put(colorCode, new PickedObject(colorCode, o, position, isTerrain)); - } - - public void addPickableObject(int colorCode, Object o) - { - this.pickableObjects.put(colorCode, new PickedObject(colorCode, o)); - } - - public void addPickableObject(int colorCode, PickedObject po) - { - this.pickableObjects.put(colorCode, po); - } - - public PickedObject getTopObject(DrawContext dc, java.awt.Point pickPoint, Layer layer) - { - if (this.pickableObjects.isEmpty()) - return null; - - int colorCode = this.getTopColor(dc, pickPoint); - if (colorCode == dc.getClearColor().getRGB()) - return null; - - PickedObject pickedObject = pickableObjects.get(colorCode); - if (pickedObject == null) - return null; - - if (layer != null) - pickedObject.setParentLayer(layer); - - return pickedObject; - } - - public void resolvePick(DrawContext dc, java.awt.Point pickPoint, Layer layer) - { - PickedObject pickedObject = this.getTopObject(dc, pickPoint, layer); - if (pickedObject != null) - dc.addPickedObject(pickedObject); - - this.clearPickList(); - } - - public int getTopColor(DrawContext dc, java.awt.Point pickPoint) - { - GL gl = dc.getGL(); - - int[] viewport = new int[4]; - gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0); - - java.nio.ByteBuffer pixel = BufferUtil.newByteBuffer(3); - gl.glReadPixels(pickPoint.x, viewport[3] - pickPoint.y, 1, 1, - javax.media.opengl.GL.GL_RGB, GL.GL_UNSIGNED_BYTE, pixel); - - java.awt.Color topColor = null; - try - { - topColor = new java.awt.Color(pixel.get(0) & 0xff, pixel.get(1) & 0xff, pixel.get(2) & 0xff, 0); - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("layers.InvalidPickColorRead"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - - return topColor != null ? topColor.getRGB() : 0; - } - - public void beginPicking(DrawContext dc) - { - javax.media.opengl.GL gl = dc.getGL(); - - gl.glPushAttrib(GL.GL_ENABLE_BIT); - - gl.glDisable(GL.GL_DITHER); - gl.glDisable(GL.GL_LIGHTING); - gl.glDisable(GL.GL_FOG); - gl.glDisable(GL.GL_BLEND); - gl.glDisable(GL.GL_TEXTURE_2D); - } - - public void endPicking(DrawContext dc) - { - dc.getGL().glPopAttrib(); - } -} diff --git a/gov/nasa/worldwind/Pickable.java b/gov/nasa/worldwind/Pickable.java deleted file mode 100644 index 939ec86..0000000 --- a/gov/nasa/worldwind/Pickable.java +++ /dev/null @@ -1,16 +0,0 @@ -package gov.nasa.worldwind; -/* -Copyright (C) 2001, 2006 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author lado - * @version $Id: Pickable Feb 4, 2007 11:46:48 PM - */ -public interface Pickable -{ - public void pick(DrawContext dc, java.awt.Point pickPoint); -} diff --git a/gov/nasa/worldwind/PickedObject.java b/gov/nasa/worldwind/PickedObject.java deleted file mode 100644 index d0d66b2..0000000 --- a/gov/nasa/worldwind/PickedObject.java +++ /dev/null @@ -1,131 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * @author lado - * @version $Id: PickedObject Feb 5, 2007 12:47:00 AM - */ -public class PickedObject extends AVListImpl -{ - private final int colorCode; - private final Object userObject; - private boolean isOnTop = false; - private boolean isTerrain = false; - - public PickedObject(int colorCode, Object userObject) - { - super(); - this.colorCode = colorCode; - this.userObject = userObject; - this.isOnTop = false; - this.isTerrain = false; - } - - public PickedObject(int colorCode, Object userObject, Position position, boolean isTerrain) - { - super(); - - this.colorCode = colorCode; - this.userObject = userObject; - this.isOnTop = false; - this.isTerrain = isTerrain; - this.setPosition(position); - } - - public PickedObject(int colorCode, Object userObject, Angle lat, Angle lon, double elev, boolean isTerrain) - { - super(); - - this.colorCode = colorCode; - this.userObject = userObject; - this.isOnTop = false; - this.isTerrain = isTerrain; - this.setPosition(new Position(lat, lon, elev)); - } - - public int getColorCode() - { - return this.colorCode; - } - - public Object getObject() - { - return userObject; - } - - public void setOnTop() - { - this.isOnTop = true; - } - - public boolean isOnTop() - { - return this.isOnTop; - } - - public boolean isTerrain() - { - return this.isTerrain; - } - - public void setParentLayer(Layer layer) - { - this.setValue(AVKey.PICKED_OBJECT_PARENT_LAYER, layer); - } - - public Layer getParentLayer() - { - return (Layer) this.getValue(AVKey.PICKED_OBJECT_PARENT_LAYER); - } - - public void setPosition(Position position) - { - this.setValue(AVKey.POSITION, position); - } - - public Position getPosition() - { - return (Position) this.getValue(AVKey.POSITION); - } - - public boolean hasPosition() - { - return this.hasKey(AVKey.POSITION); - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - PickedObject that = (PickedObject) o; - - if (colorCode != that.colorCode) - return false; - if (isOnTop != that.isOnTop) - return false; - //noinspection RedundantIfStatement - if (userObject != null ? !userObject.equals(that.userObject) : that.userObject != null) - return false; - - return true; - } - - public int hashCode() - { - int result; - result = colorCode; - result = 31 * result + (userObject != null ? userObject.hashCode() : 0); - result = 31 * result + (isOnTop ? 1 : 0); - return result; - } -} diff --git a/gov/nasa/worldwind/PickedObjectList.java b/gov/nasa/worldwind/PickedObjectList.java deleted file mode 100644 index 6420bc1..0000000 --- a/gov/nasa/worldwind/PickedObjectList.java +++ /dev/null @@ -1,61 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id$ - */ -public class PickedObjectList extends java.util.ArrayList -{ - public PickedObjectList() - { - } - - public PickedObjectList(PickedObjectList list) // clone a shallow copy - { - super(list); - } - - public PickedObject getTopPickedObject() - { - int size = this.size(); - - if(1 < size) - { - for (PickedObject po : this) - { - if (po.isOnTop()) - return po; - } - } - - if(0 < size) - { // if we are here, then no objects were mark as 'top' - return this.get(0); - } - - return null; - } - - public Object getTopObject() - { - PickedObject po = this.getTopPickedObject(); - return po != null ? po.getObject() : null; - } - - public PickedObject getTerrainObject() - { - for (PickedObject po : this) - { - if (po.isTerrain()) - return po; - } - - return null; - } -} diff --git a/gov/nasa/worldwind/PlaceName.java b/gov/nasa/worldwind/PlaceName.java deleted file mode 100644 index 9fc6b11..0000000 --- a/gov/nasa/worldwind/PlaceName.java +++ /dev/null @@ -1,41 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.awt.*; - -/** - * @author dcollins - * @version $Id: PlaceName.java 1759 2007-05-07 19:27:49Z dcollins $ - */ -public interface PlaceName -{ - String getText(); - - void setText(String text); - - Position getPosition(); - - void setPosition(Position position); - - Font getFont(); - - void setFont(Font font); - - Color getColor(); - - void setColor(Color color); - - boolean isVisible(); - - void setVisible(boolean visible); - - WWIcon getIcon(); - - void setIcon(WWIcon icon); -} diff --git a/gov/nasa/worldwind/PlaceNameRenderer.java b/gov/nasa/worldwind/PlaceNameRenderer.java deleted file mode 100644 index c647839..0000000 --- a/gov/nasa/worldwind/PlaceNameRenderer.java +++ /dev/null @@ -1,332 +0,0 @@ -/* -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; - -import com.sun.opengl.util.j2d.*; -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import javax.media.opengl.glu.*; -import java.awt.*; -import java.awt.geom.*; -import java.util.*; -import java.util.logging.Level; - -/** - * @author dcollins - * @version $Id: PlaceNameRenderer.java 1994 2007-06-11 16:33:33Z dcollins $ - */ -public class PlaceNameRenderer implements Disposable -{ - private static final Font defaultFont = Font.decode("Arial-12-PLAIN"); - private static final Color defaultColor = Color.white; - private final Map textRenderers = new HashMap(); - private TextRenderer lastTextRenderer = null; - private final GLU glu = new GLU(); - - public PlaceNameRenderer() - { - } - - public void dispose() - { - for (TextRenderer textRenderer : textRenderers.values()) - { - if (textRenderer != null) - textRenderer.dispose(); - } - } - - public void render(DrawContext dc, Iterator placeNames, boolean enableDepthTest) - { - this.drawMany(dc, placeNames, enableDepthTest); - } - - public void render(DrawContext dc, PlaceName placeName, Vec4 placeNamePoint, boolean enableDepthTest) - { - if (!isNameValid(placeName, false)) - return; - - this.drawOne(dc, placeName, placeNamePoint, enableDepthTest); - } - - private void drawMany(DrawContext dc, Iterator placeNames, boolean enableDepthTest) - { - if (dc == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (dc.getVisibleSector() == null) - return; - - SectorGeometryList geos = dc.getSurfaceGeometry(); - if (geos == null) - return; - - if (placeNames == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.Iterator"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (!placeNames.hasNext()) - return; - - Frustum frustumInModelCoords = dc.getView().getFrustumInModelCoordinates(); - double horizon = dc.getView().computeHorizonDistance(); - - this.beginDrawNames(dc, enableDepthTest); - - while (placeNames.hasNext()) - { - PlaceName placeName = placeNames.next(); - if (!isNameValid(placeName, true)) - continue; - - if (!placeName.isVisible()) - continue; - - Angle lat = placeName.getPosition().getLatitude(); - Angle lon = placeName.getPosition().getLongitude(); - - if (!dc.getVisibleSector().contains(lat, lon)) - continue; - - Vec4 namePoint = geos.getSurfacePoint(lat, lon, placeName.getPosition().getElevation()); - if (namePoint == null) - continue; - - double eyeDistance = dc.getView().getEyePoint().distanceTo3(namePoint); - if (eyeDistance > horizon) - continue; - - if (!frustumInModelCoords.contains(namePoint)) - continue; - - this.drawName(dc, placeName, namePoint, enableDepthTest); - } - - this.endDrawNames(dc); - } - - private void drawOne(DrawContext dc, PlaceName placeName, Vec4 namePoint, boolean enableDepthTest) - { - if (dc == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (dc.getView() == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ViewIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (dc.getVisibleSector() == null) - return; - - SectorGeometryList geos = dc.getSurfaceGeometry(); - if (geos == null) - return; - - if (!placeName.isVisible()) - return; - - if (namePoint == null) - { - if (placeName.getPosition() == null) - return; - - Angle lat = placeName.getPosition().getLatitude(); - Angle lon = placeName.getPosition().getLongitude(); - - if (!dc.getVisibleSector().contains(lat, lon)) - return; - - namePoint = geos.getSurfacePoint(lat, lon, placeName.getPosition().getElevation()); - if (namePoint == null) - return; - } - - double horizon = dc.getView().computeHorizonDistance(); - double eyeDistance = dc.getView().getEyePoint().distanceTo3(namePoint); - if (eyeDistance > horizon) - return; - - if (!dc.getView().getFrustumInModelCoordinates().contains(namePoint)) - return; - - this.beginDrawNames(dc, enableDepthTest); - this.drawName(dc, placeName, namePoint, enableDepthTest); - this.endDrawNames(dc); - } - - private static boolean isNameValid(PlaceName placeName, boolean checkPosition) - { - if (placeName == null || placeName.getText() == null) - return false; - - //noinspection RedundantIfStatement - if (checkPosition && placeName.getPosition() == null) - return false; - - return true; - } - - private final int[] viewportArray = new int[4]; - - private void beginDrawNames(DrawContext dc, boolean enableDepthTest) - { - GL gl = dc.getGL(); - int attribBits = - GL.GL_ENABLE_BIT - | GL.GL_COLOR_BUFFER_BIT // for alpha test func and ref, and blend - | GL.GL_CURRENT_BIT // for current color - | GL.GL_TRANSFORM_BIT // for modelview and perspective - | (enableDepthTest ? GL.GL_VIEWPORT_BIT | GL.GL_DEPTH_BUFFER_BIT : 0); // for depth func, depth range - gl.glPushAttrib(attribBits); - - gl.glGetIntegerv(GL.GL_VIEWPORT, viewportArray, 0); - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPushMatrix(); - gl.glLoadIdentity(); - glu.gluOrtho2D(0, viewportArray[2], 0, viewportArray[3]); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - gl.glLoadIdentity(); - - // Enable the depth test but don't write to the depth buffer. - if (enableDepthTest) - { - gl.glEnable(GL.GL_DEPTH_TEST); - gl.glDepthFunc(GL.GL_LESS); - gl.glDepthMask(false); - } - else - { - gl.glDisable(GL.GL_DEPTH_TEST); - } - // Suppress polygon culling. - gl.glDisable(GL.GL_CULL_FACE); - // Suppress any fully transparent image pixels - final float ALPHA_EPSILON = 0.001f; - gl.glEnable(GL.GL_ALPHA_TEST); - gl.glAlphaFunc(GL.GL_GREATER, ALPHA_EPSILON); - } - - private void endDrawNames(DrawContext dc) - { - if (this.lastTextRenderer != null) - { - this.lastTextRenderer.end3DRendering(); - this.lastTextRenderer = null; - } - - GL gl = dc.getGL(); - - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPopMatrix(); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPopMatrix(); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - - gl.glPopAttrib(); - } - - private Vec4 drawName(DrawContext dc, PlaceName name, Vec4 namePoint, boolean enableDepthTest) - { - if (namePoint == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(Level.FINE, msg); - return null; - } - - final String text = name.getText(); - if (text == null) - return null; - - final Vec4 screenPoint = dc.getView().project(namePoint); - if (screenPoint == null) - return null; - - if (enableDepthTest) - this.setDepthFunc(dc, screenPoint); - - Font font = name.getFont(); - if (font == null) - font = defaultFont; - - TextRenderer textRenderer = this.textRenderers.get(font); - if (textRenderer == null) - textRenderer = this.initializeTextRenderer(font); - if (textRenderer != this.lastTextRenderer) - { - if (this.lastTextRenderer != null) - this.lastTextRenderer.end3DRendering(); - textRenderer.begin3DRendering(); - this.lastTextRenderer = textRenderer; - } - - Rectangle2D nameBound = textRenderer.getBounds(text); - int x = (int) (screenPoint.x - nameBound.getWidth() / 2d); - int y = (int) screenPoint.y; - - Color color = name.getColor(); - if (color == null) - color = defaultColor; - - this.setBackgroundColor(textRenderer, color); - textRenderer.draw(text, x + 1, y - 1); - textRenderer.setColor(color); - textRenderer.draw(text, x, y); - - return screenPoint; - } - - private void setDepthFunc(DrawContext dc, Vec4 screenPoint) - { - double depth = screenPoint.z - (8d * 0.00048875809d); - depth = (depth < 0) ? 0 : ((depth > 1) ? 1 : depth); - dc.getGL().glDepthRange(depth, depth); - } - - private final float[] compArray = new float[4]; - - private void setBackgroundColor(TextRenderer textRenderer, Color color) - { - Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), compArray); - if (compArray[2] > 0.5) - textRenderer.setColor(0, 0, 0, 0.7f); - else - textRenderer.setColor(1, 1, 1, 0.7f); - } - - private TextRenderer initializeTextRenderer(Font font) - { - TextRenderer textRenderer = new TextRenderer(font, true, true); - TextRenderer oldTextRenderer; - oldTextRenderer = this.textRenderers.put(font, textRenderer); - if (oldTextRenderer != null) - oldTextRenderer.dispose(); - return textRenderer; - } - - public String toString() - { - return WorldWind.retrieveErrMsg("layers.PlaceNameLayer.Name"); - } -} diff --git a/gov/nasa/worldwind/PlaceNameService.java b/gov/nasa/worldwind/PlaceNameService.java deleted file mode 100644 index 93af36d..0000000 --- a/gov/nasa/worldwind/PlaceNameService.java +++ /dev/null @@ -1,391 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * @author Paul Collins - * @version $Id: PlaceNameService.java 1759 2007-05-07 19:27:49Z 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 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) - { - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.numColumns = this.numColumnsInLevel(); - } - - /** - * @param row - * @param column - * @return - * @throws IllegalArgumentException if either row or column is less than zero - */ - public String createFileCachePathFromTile(int row, int column) - { - if (row < 0 || column < 0) - { - String message = WorldWind.retrieveErrMsg("PlaceNameService.RowOrColumnOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, 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); - - if (FORMAT_SUFFIX.charAt(0) != '.') - sb.append('.'); - 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 sector is null - */ - public java.net.URL createServiceURLFromSector(Sector sector) throws java.net.MalformedURLException - { - if (sector == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - StringBuilder sb = new StringBuilder(this.service); - if (sb.charAt(sb.length() - 1) != '?') - sb.append('?'); - sb.append("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.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 final String getDataset() - { - return this.dataset; - } - - /** - * @param dc - * @return - * @throws IllegalArgumentException if dc is null - */ - public final Extent getExtent(DrawContext dc) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.extent == null || this.extentVerticalExaggeration != dc.getVerticalExaggeration()) - { - this.extentVerticalExaggeration = dc.getVerticalExaggeration(); - this.extent = Sector.computeBoundingCylinder(dc.getGlobe(), 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 color is null - */ - public synchronized final void setColor(java.awt.Color color) - { - if (color == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.ColorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.color = color; - } - - public synchronized final void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - - /** - * @param maxDisplayDistance - * @throws IllegalArgumentException if maxDisplayDistance is less than the current minimum display - * distance - */ - public synchronized final void setMaxDisplayDistance(double maxDisplayDistance) - { - if (maxDisplayDistance < this.minDisplayDistance) - { - String message = WorldWind.retrieveErrMsg("PlaceNameService.MaxDisplayDistanceLessThanMinDisplayDistance"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.maxDisplayDistance = maxDisplayDistance; - } - - /** - * @param minDisplayDistance - * @throws IllegalArgumentException if minDisplayDistance is less than the current maximum display - * distance - */ - public synchronized final void setMinDisplayDistance(double minDisplayDistance) - { - if (minDisplayDistance > this.maxDisplayDistance) - { - String message = WorldWind.retrieveErrMsg("PlaceNameService.MinDisplayDistanceGrtrThanMaxDisplayDistance"); - WorldWind.logger().log(java.util.logging.Level.FINE, 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 PlaceNameService' constructor arguments are valid. - * - * @return null if valid, otherwise a String containing a description of why it is invalid. - */ - public final String validate() - { - String msg = ""; - if (this.service == null) - { - msg += WorldWind.retrieveErrMsg("nullValue.ServiceIsNull") + ", "; - } - if (this.dataset == null) - { - msg += WorldWind.retrieveErrMsg("nullValue.DataSetIsNull") + ", "; - } - if (this.fileCachePath == null) - { - msg += WorldWind.retrieveErrMsg("nullValue.FileCachePathIsNull") + ", "; - } - if (this.sector == null) - { - msg += WorldWind.retrieveErrMsg("nullValue.SectorIsNull") + ", "; - } - if (this.tileDelta == null) - { - msg += WorldWind.retrieveErrMsg("nullValue.TileDeltaIsNull") + ", "; - } - if (this.font == null) - { - msg += WorldWind.retrieveErrMsg("nullValue.FontIsNull") + ", "; - } - - if (msg.length() == 0) - { - return null; - } - - return msg; - } -} diff --git a/gov/nasa/worldwind/PlaceNameServiceSet.java b/gov/nasa/worldwind/PlaceNameServiceSet.java deleted file mode 100644 index e42ffbb..0000000 --- a/gov/nasa/worldwind/PlaceNameServiceSet.java +++ /dev/null @@ -1,81 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * @author Paul Collins - * @version $Id: PlaceNameServiceSet.java 1759 2007-05-07 19:27:49Z dcollins $ - */ -public class PlaceNameServiceSet -{ - private final List serviceList = new LinkedList(); - - public PlaceNameServiceSet() - { - } - - /** - * @param placeNameService - * @param replace - * @return - * @throws IllegalArgumentException if placeNameService is null - */ - public boolean addService(PlaceNameService placeNameService, boolean replace) - { - if (placeNameService == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PlaceNameServiceIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - for (int i = 0; i < this.serviceList.size(); i++) - { - final PlaceNameService other = this.serviceList.get(i); - if (placeNameService.getService().equals(other.getService()) && placeNameService.getDataset().equals( - other.getDataset())) - { - if (replace) - { - this.serviceList.set(i, placeNameService); - return true; - } - else - { - return false; - } - } - } - - this.serviceList.add(placeNameService); - return true; - } - - public final PlaceNameServiceSet deepCopy() - { - PlaceNameServiceSet copy = new PlaceNameServiceSet(); - - // Creates a deep copy of this.serviceList in copy.serviceList. - for (int i = 0; i < this.serviceList.size(); i++) - { - copy.serviceList.add(i, this.serviceList.get(i).deepCopy()); - } - - return copy; - } - - public final int getServiceCount() - { - return this.serviceList.size(); - } - - public final PlaceNameService getService(int index) - { - return this.serviceList.get(index); - } -} diff --git a/gov/nasa/worldwind/PositionEvent.java b/gov/nasa/worldwind/PositionEvent.java deleted file mode 100644 index 60d5a76..0000000 --- a/gov/nasa/worldwind/PositionEvent.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.util.*; - -/** - * @author tag - * @version $Id: PositionEvent.java 1941 2007-06-02 08:52:28Z tgaskins $ - */ -public class PositionEvent extends EventObject -{ - private final java.awt.Point screenPoint; - private final Position position; - private final Position previousPosition; - - public PositionEvent(Object source, java.awt.Point screenPoint, Position previousPosition, Position position) - { - super(source); - this.screenPoint = screenPoint; - this.position = position; - this.previousPosition = previousPosition; - } - - public java.awt.Point getScreenPoint() - { - return screenPoint; - } - - public Position getPosition() - { - return position; - } - - public Position getPreviousPosition() - { - return previousPosition; - } - - @Override - public String toString() - { - return this.getClass().getName() + " " - + (this.previousPosition != null ? this.previousPosition : "null") - + " --> " - + (this.position != null ? this.position : "null"); - } -} diff --git a/gov/nasa/worldwind/PositionListener.java b/gov/nasa/worldwind/PositionListener.java deleted file mode 100644 index 0bb9add..0000000 --- a/gov/nasa/worldwind/PositionListener.java +++ /dev/null @@ -1,18 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * @author tag - * @version $Id: PositionListener.java 1757 2007-05-07 09:17:09Z tgaskins $ - */ -public interface PositionListener extends EventListener -{ - public void moved(PositionEvent event); -} diff --git a/gov/nasa/worldwind/Renderable.java b/gov/nasa/worldwind/Renderable.java deleted file mode 100644 index cd03d57..0000000 --- a/gov/nasa/worldwind/Renderable.java +++ /dev/null @@ -1,25 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: Renderable.java 403 2006-12-13 02:33:18Z ericdalgliesh $ - */ -public interface Renderable -{ - /** - * Causes this Renderable to render itself using the DrawContext provided. The - * DrawContext provides the elevation model, openGl instance, globe and other information required for - * drawing. It is recommended that the DrawContext is non-null as most implementations do not support - * null DrawContexts. - * - * @param dc the DrawContext to be used - * @see DrawContext - */ - public void render(DrawContext dc); -} diff --git a/gov/nasa/worldwind/RenderingEvent.java b/gov/nasa/worldwind/RenderingEvent.java deleted file mode 100644 index 71f6da3..0000000 --- a/gov/nasa/worldwind/RenderingEvent.java +++ /dev/null @@ -1,40 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * @author tag - * @version $Id: RenderingEvent.java 1909 2007-05-30 20:50:03Z tgaskins $ - */ -public class RenderingEvent extends EventObject -{ - public static final String BEFORE_RENDERING = "gov.nasa.worldwind.RenderingEvent.BeforeRendering"; - public static final String BEFORE_BUFFER_SWAP = "gov.nasa.worldwind.RenderingEvent.BeforeBufferSwap"; - public static final String AFTER_BUFFER_SWAP = "gov.nasa.worldwind.RenderingEvent.AfterBufferSwap"; - - private String stage; - - public RenderingEvent(Object source, String stage) - { - super(source); - this.stage = stage; - } - - public String getStage() - { - return this.stage != null ? this.stage : "gov.nasa.worldwind.RenderingEvent.UnknownStage"; - } - - @Override - public String toString() - { - return this.getClass().getName() + " " - + this.stage != null ? this.stage : WorldWind.retrieveErrMsg("generic.unknown"); - } -} diff --git a/gov/nasa/worldwind/RenderingListener.java b/gov/nasa/worldwind/RenderingListener.java deleted file mode 100644 index d9ac0b5..0000000 --- a/gov/nasa/worldwind/RenderingListener.java +++ /dev/null @@ -1,18 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * @author tag - * @version $Id: RenderingListener.java 1757 2007-05-07 09:17:09Z tgaskins $ - */ -public interface RenderingListener extends EventListener -{ - public void stageChanged(RenderingEvent event); -} diff --git a/gov/nasa/worldwind/RetrievalFuture.java b/gov/nasa/worldwind/RetrievalFuture.java deleted file mode 100644 index ac2f244..0000000 --- a/gov/nasa/worldwind/RetrievalFuture.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: RetrievalFuture.java 403 2006-12-13 02:33:18Z ericdalgliesh $ - */ -public interface RetrievalFuture extends java.util.concurrent.Future -{ - public Retriever getRetriever(); -} diff --git a/gov/nasa/worldwind/RetrievalPostProcessor.java b/gov/nasa/worldwind/RetrievalPostProcessor.java deleted file mode 100644 index 1b55a1b..0000000 --- a/gov/nasa/worldwind/RetrievalPostProcessor.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: RetrievalPostProcessor.java 403 2006-12-13 02:33:18Z ericdalgliesh $ - */ -public interface RetrievalPostProcessor -{ - public java.nio.ByteBuffer run(Retriever retriever); -} diff --git a/gov/nasa/worldwind/RetrievalService.java b/gov/nasa/worldwind/RetrievalService.java deleted file mode 100644 index f407fe1..0000000 --- a/gov/nasa/worldwind/RetrievalService.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: RetrievalService.java 693 2007-01-31 19:11:01Z tgaskins $ - */ -public interface RetrievalService extends WWObject -{ - RetrievalFuture runRetriever(Retriever retriever); - - RetrievalFuture runRetriever(Retriever retriever, double priority); - - void setRetrieverPoolSize(int poolSize); - - int getRetrieverPoolSize(); - - boolean hasActiveTasks(); - - boolean isFull(); - - boolean contains(gov.nasa.worldwind.Retriever retriever); - - int getNumRetrieversPending(); -} diff --git a/gov/nasa/worldwind/RetrieveToFilePostProcessor.java b/gov/nasa/worldwind/RetrieveToFilePostProcessor.java deleted file mode 100644 index b378d2b..0000000 --- a/gov/nasa/worldwind/RetrieveToFilePostProcessor.java +++ /dev/null @@ -1,82 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: RetrieveToFilePostProcessor.java 510 2007-01-17 04:57:40Z ericdalgliesh $ - */ -public final class RetrieveToFilePostProcessor implements RetrievalPostProcessor -{ - java.io.File destination; - - /** - * @param destination - * @throws IllegalArgumentException if destination is null - */ - public RetrieveToFilePostProcessor(java.io.File destination) - { - if (destination == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DestNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.destination = destination; - } - - /** - * @param retriever - * @return - * @throws IllegalArgumentException if retriever is null - */ - public java.nio.ByteBuffer run(Retriever retriever) - { - if (retriever == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - try - { - java.nio.ByteBuffer buffer = retriever.getBuffer(); - if (buffer == null) - { - WorldWind.logger().log(java.util.logging.Level.FINE, WorldWind.retrieveErrMsg( - "RetrieveToFilePostProcessor.NullBufferPostprocessing") + retriever.getName()); - return null; - } - - java.io.FileOutputStream fos = null; - try - { - fos = new java.io.FileOutputStream(this.destination); - fos.getChannel().write(buffer); - return null; - } - catch (java.io.IOException e) - { - throw e; - } - finally - { - if (fos != null) - fos.close(); - } - } - catch (java.io.IOException e) - { - String message = WorldWind.retrieveErrMsg("RetrieveToFilePostProcessor.ErrorPostprocessing") + retriever - .getName(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new WWRuntimeException(message, e); - } - } -} diff --git a/gov/nasa/worldwind/Retriever.java b/gov/nasa/worldwind/Retriever.java deleted file mode 100644 index e422b36..0000000 --- a/gov/nasa/worldwind/Retriever.java +++ /dev/null @@ -1,58 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: Retriever.java 1985 2007-06-09 00:33:37Z tgaskins $ - */ -public interface Retriever extends WWObject, java.util.concurrent.Callable -{ - public final String RETRIEVER_STATE_NOT_STARTED = "gov.nasa.worldwind.RetrieverStatusNotStarted"; - public final String RETRIEVER_STATE_STARTED = "gov.nasa.worldwind.RetrieverStatusStarted"; - public final String RETRIEVER_STATE_CONNECTING = "gov.nasa.worldwind.RetrieverStatusConnecting"; - public final String RETRIEVER_STATE_READING = "gov.nasa.worldwind.RetrieverStatusReading"; - public final String RETRIEVER_STATE_INTERRUPTED = "gov.nasa.worldwind.RetrieverStatusInterrupted"; - public final String RETRIEVER_STATE_ERROR = "gov.nasa.worldwind.RetrieverStatusError"; - public final String RETRIEVER_STATE_SUCCESSFUL = "gov.nasa.worldwind.RetrieverStatusSuccessful"; - - public java.nio.ByteBuffer getBuffer(); - - public int getContentLength(); - - public int getContentLengthRead(); - - public String getName(); - - public String getState(); - - String getContentType(); - - long getSubmitTime(); - - void setSubmitTime(long submitTime); - - long getBeginTime(); - - void setBeginTime(long beginTime); - - long getEndTime(); - - void setEndTime(long endTime); - - int getConnectTimeout(); - - int getReadTimeout(); - - void setReadTimeout(int readTimeout); - - void setConnectTimeout(int connectTimeout); - - int getStaleRequestLimit(); - - void setStaleRequestLimit(int staleRequestLimit); -} diff --git a/gov/nasa/worldwind/SectorGeometry.java b/gov/nasa/worldwind/SectorGeometry.java deleted file mode 100644 index b0589d2..0000000 --- a/gov/nasa/worldwind/SectorGeometry.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * @author Tom Gaskins - * @version $Id: SectorGeometry.java 1994 2007-06-11 16:33:33Z dcollins $ - */ -public interface SectorGeometry extends Renderable, Pickable, Cacheable -{ - public Extent getExtent(); - - public Sector getSector(); - - public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset); - - public void pick(DrawContext dc, java.awt.Point pickPoint); - - void renderMultiTexture(DrawContext dc, int numTextureUnits); - - public void renderWireframe(DrawContext dc, boolean interior, boolean exterior); - - void renderBoundingVolume(DrawContext dc); -} diff --git a/gov/nasa/worldwind/SectorGeometryList.java b/gov/nasa/worldwind/SectorGeometryList.java deleted file mode 100644 index 9d471c5..0000000 --- a/gov/nasa/worldwind/SectorGeometryList.java +++ /dev/null @@ -1,124 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import java.awt.*; -import java.util.*; -import java.util.List; - -/** - * @author tag - * @version $Id: SectorGeometryList.java 1994 2007-06-11 16:33:33Z dcollins $ - */ -public class SectorGeometryList extends ArrayList -{ - private PickSupport pickSupport = new PickSupport(); - - public SectorGeometryList() - { - } - - public SectorGeometryList(SectorGeometryList list) - { - super(list); - } - - public List getIntersectingSectors(Sector sector) - { - ArrayList list = null; - - for (SectorGeometry sg : this) - { - if (sg.getSector().intersects(sector)) - { - if (list == null) - list = new ArrayList(); - list.add(sg); - } - else - { -// System.out.println("no intersection"); - } - } - - return list; - } - - public void pick(DrawContext dc, java.awt.Point pickPoint) - { - this.pickSupport.clearPickList(); - this.pickSupport.beginPicking(dc); - - GL gl = dc.getGL(); - gl.glPushAttrib(GL.GL_LIGHTING_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_ENABLE_BIT | GL.GL_CURRENT_BIT); - gl.glEnable(GL.GL_DEPTH_TEST); - gl.glShadeModel(GL.GL_FLAT); - gl.glDisable(GL.GL_CULL_FACE); - - try - { - // render each sector in unique color - for (SectorGeometry sector : this) - { - Color color = dc.getUniquePickColor(); - dc.getGL().glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); - sector.render(dc); - // lat/lon/elevation not used in this case - this.pickSupport.addPickableObject(color.getRGB(), sector, Position.ZERO, true); - } - - PickedObject pickedSector = this.pickSupport.getTopObject(dc, pickPoint, null); - if (pickedSector == null || pickedSector.getObject() == null) - return; // no sector picked - - SectorGeometry sector = (SectorGeometry) pickedSector.getObject(); - gl.glDepthFunc(GL.GL_LEQUAL); - sector.pick(dc, pickPoint); - } - finally - { - gl.glPopAttrib(); - this.pickSupport.endPicking(dc); - this.pickSupport.clearPickList(); - } - } - - public Vec4 getSurfacePoint(Position position) - { - return this.getSurfacePoint(position.getLatitude(), position.getLongitude(), position.getElevation()); - } - - public Vec4 getSurfacePoint(Angle latitude, Angle longitude) - { - return this.getSurfacePoint(latitude, longitude, 0d); - } - - public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset) - { - if (latitude == null || longitude == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.LatLonIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - for (SectorGeometry sg : this) - { - if (sg.getSector().contains(latitude, longitude)) - { - Vec4 point = sg.getSurfacePoint(latitude, longitude, metersOffset); - if (point != null) - return point; - } - } - - return null; - } -} diff --git a/gov/nasa/worldwind/SelectEvent.java b/gov/nasa/worldwind/SelectEvent.java deleted file mode 100644 index 090ecc6..0000000 --- a/gov/nasa/worldwind/SelectEvent.java +++ /dev/null @@ -1,92 +0,0 @@ -/* -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; - -import java.util.*; -import java.awt.event.*; -import java.awt.*; - -/** - * @author tag - * @version $Id: SelectEvent.java 2150 2007-06-26 07:40:58Z tgaskins $ - */ -public class SelectEvent extends EventObject -{ - public static final String LEFT_CLICK = "gov.nasa.worldwind.SelectEvent.LeftClick"; - public static final String LEFT_DOUBLE_CLICK = "gov.nasa.worldwind.SelectEvent.LeftDoubleClick"; - public static final String RIGHT_CLICK = "gov.nasa.worldwind.SelectEvent.RightClick"; - public static final String HOVER = "gov.nasa.worldwind.SelectEvent.Hover"; - public static final String ROLLOVER = "gov.nasa.worldwind.SelectEvent.Rollover"; - public static final String DRAG = "gov.nasa.worldwind.SelectEvent.Drag"; - public static final String DRAG_END = "gov.nasa.worldwind.SelectEvent.DragEnd"; - - private final String eventAction; - private final java.awt.Point pickPoint; - private final MouseEvent mouseEvent; - private final PickedObjectList pickedObjects; - - public SelectEvent(Object source, String eventAction, MouseEvent mouseEvent, PickedObjectList pickedObjects) - { - super(source); - this.eventAction = eventAction; - this.pickPoint = mouseEvent != null ? mouseEvent.getPoint() : null; - this.mouseEvent = mouseEvent; - this.pickedObjects = pickedObjects; - } - - public SelectEvent(Object source, String eventAction, java.awt.Point pickPoint, PickedObjectList pickedObjects) - { - super(source); - this.eventAction = eventAction; - this.pickPoint = pickPoint; - this.mouseEvent = null; - this.pickedObjects = pickedObjects; - } - - public String getEventAction() - { - return this.eventAction != null ? this.eventAction : "gov.nasa.worldwind.SelectEvent.UnknownEventAction"; - } - - public Point getPickPoint() - { - return pickPoint; - } - - public MouseEvent getMouseEvent() - { - return mouseEvent; - } - - public boolean hasObjects() - { - return this.pickedObjects != null && this.pickedObjects.size() > 0; - } - - public PickedObjectList getObjects() - { - return this.pickedObjects; - } - - public PickedObject getTopPickedObject() - { - return this.hasObjects() ? this.pickedObjects.getTopPickedObject() : null; - } - - public Object getTopObject() - { - PickedObject tpo = this.getTopPickedObject(); - return tpo != null ? tpo.getObject() : null; - } - - @Override - public String toString() - { - return this.getClass().getName() + " " - + this.eventAction != null ? this.eventAction : WorldWind.retrieveErrMsg("generic.unknown"); - } -} diff --git a/gov/nasa/worldwind/SelectListener.java b/gov/nasa/worldwind/SelectListener.java deleted file mode 100644 index 1091036..0000000 --- a/gov/nasa/worldwind/SelectListener.java +++ /dev/null @@ -1,18 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * @author tag - * @version $Id: SelectListener.java 1757 2007-05-07 09:17:09Z tgaskins $ - */ -public interface SelectListener extends EventListener -{ - public void selected(SelectEvent event); -} diff --git a/gov/nasa/worldwind/StringUtil.java b/gov/nasa/worldwind/StringUtil.java deleted file mode 100644 index 10f50fe..0000000 --- a/gov/nasa/worldwind/StringUtil.java +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright (C) 2001, 2006 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ -// @version $Id: StringUtil.java 1751 2007-05-06 21:21:44Z tgaskins $ - -package gov.nasa.worldwind; - -public class StringUtil -{ - public static final String EMPTY = ""; - - public static boolean Equals(String s1, String s2) - { - if(null == s1 && null == s2) - return true; - if(null == s1 || null == s2) - return false; - return s1.equals(s2); - } -} diff --git a/gov/nasa/worldwind/SurfaceTileRenderer.java b/gov/nasa/worldwind/SurfaceTileRenderer.java deleted file mode 100644 index 5ef655c..0000000 --- a/gov/nasa/worldwind/SurfaceTileRenderer.java +++ /dev/null @@ -1,309 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.layers.*; -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; - -import com.sun.opengl.util.texture.*; - -import java.nio.*; -import java.util.*; - -/** - * @author tag - * @version $Id: SurfaceTileRenderer.java 1884 2007-05-25 21:15:33Z dcollins $ - */ -public class SurfaceTileRenderer implements Disposable -{ - private static final int DEFAULT_ALPHA_TEXTURE_SIZE = 2; - - private Texture alphaTexture; - private Texture outlineTexture; - private boolean showImageTileOutlines = false; - - public void dispose() // TODO: but waiting to implement a global texture disposal system - { - } - - public boolean isShowImageTileOutlines() - { - return showImageTileOutlines; - } - - public void setShowImageTileOutlines(boolean showImageTileOutlines) - { - this.showImageTileOutlines = showImageTileOutlines; - } - - public void renderTile(DrawContext dc, TextureTile tile) - { - if (tile == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.TileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - ArrayList al = new ArrayList(1); - al.add(tile); - this.renderTiles(dc, al); - al.clear(); - } - - public void renderTiles(DrawContext dc, Iterable tiles) - { - if (tiles == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.TileIterableIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - GL gl = dc.getGL(); - - gl.glPushAttrib(GL.GL_COLOR_BUFFER_BIT // for alpha func - | GL.GL_ENABLE_BIT - | GL.GL_CURRENT_BIT - | GL.GL_DEPTH_BUFFER_BIT // for depth func - | GL.GL_TEXTURE_BIT // for texture env - | GL.GL_TRANSFORM_BIT); - - try - { - if (this.alphaTexture == null) - this.initAlphaTexture(DEFAULT_ALPHA_TEXTURE_SIZE); // TODO: choose size to match incoming tile sizes? - - boolean showOutlines = this.showImageTileOutlines && dc.getNumTextureUnits() > 2; - if (showOutlines && this.outlineTexture == null) - this.initOutlineTexture(128); - - gl.glEnable(GL.GL_DEPTH_TEST); - gl.glDepthFunc(GL.GL_LEQUAL); - - gl.glEnable(GL.GL_ALPHA_TEST); - gl.glAlphaFunc(GL.GL_GREATER, 0.01f); - - gl.glActiveTexture(GL.GL_TEXTURE0); - gl.glEnable(GL.GL_TEXTURE_2D); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - if (!dc.isPickingMode()) - { - gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE); - } - else - { - gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_COMBINE); - gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_SRC0_RGB, GL.GL_PREVIOUS); - gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_COMBINE_RGB, GL.GL_REPLACE); - } - - int numTexUnitsUsed = 2; - int alphaTextureUnit = GL.GL_TEXTURE1; - if (showOutlines) - { - numTexUnitsUsed = 3; - alphaTextureUnit = GL.GL_TEXTURE2; - gl.glActiveTexture(GL.GL_TEXTURE1); - gl.glEnable(GL.GL_TEXTURE_2D); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_ADD); - } - - gl.glActiveTexture(alphaTextureUnit); - gl.glEnable(GL.GL_TEXTURE_2D); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE); - - // For each current geometry tile, find the intersecting image tiles and render the geometry - // tile once for each intersecting image tile. -// System.out.printf("%d geo tiles\n", dc.getSurfaceGeometry().size()); - for (SectorGeometry sg : dc.getSurfaceGeometry()) - { - Iterable tilesToRender = this.getIntersectingTiles(sg, tiles); - if (tilesToRender == null) - continue; -// System.out.printf("%d, ", tilesToRender.length); - - // Pre-load info to compute the texture transform below - Sector st = sg.getSector(); - double geoDeltaLat = st.getDeltaLatRadians(); - double geoDeltaLon = st.getDeltaLonRadians(); - double geoMinLat = st.getMinLatitude().radians; - double geoMinLon = st.getMinLongitude().radians; - - // For each interesecting tile, establish the texture transform necessary to map the image tile - // into the geometry tile's texture space. Use an alpha texture as a mask to prevent changing the - // frame buffer where the image tile does not overlap the geometry tile. Render both the image and - // alpha textures via multi-texture rendering. - // TODO: Figure out how to apply multi-texture to more than one tile at a time, most likely via a - // fragment shader. - for (TextureTile tile : tilesToRender) - { - gl.glActiveTexture(GL.GL_TEXTURE0); - - if (tile.bindTexture(dc)) - { - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glLoadIdentity(); - tile.applyTextureTransform(dc); - - // Determine and apply texture transform to map image tile into geometry tile's texture space - Sector si = tile.getSector(); - double latScale = si.getDeltaLatRadians() > 0 ? geoDeltaLat / si.getDeltaLatRadians() : 1; - double lonScale = si.getDeltaLonRadians() > 0 ? geoDeltaLon / si.getDeltaLonRadians() : 1; - gl.glScaled(lonScale, latScale, 1d); - - double latShift = -(si.getMinLatitude().radians - geoMinLat) / geoDeltaLat; - double lonShift = -(si.getMinLongitude().radians - geoMinLon) / geoDeltaLon; - gl.glTranslated(lonShift, latShift, 0d); - - if (showOutlines) - { - gl.glActiveTexture(GL.GL_TEXTURE1); - this.outlineTexture.bind(); - - // Apply the same texture transform to the outline texture. The outline textures uses a - // different texture unit than the tile, so the transform made above does not carry over. - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glLoadIdentity(); - gl.glScaled(lonScale, latScale, 1d); - gl.glTranslated(lonShift, latShift, 0d); - } - - // Prepare the alpha texture to be used as a mask where texture coords are outside [0,1] - gl.glActiveTexture(alphaTextureUnit); - this.alphaTexture.bind(); - - // Apply the same texture transform to the alpha texture. The alpha texture uses a - // different texture unit than the tile, so the transform made above does not carry over. - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glLoadIdentity(); - gl.glScaled(lonScale, latScale, 1d); - gl.glTranslated(lonShift, latShift, 0d); - - // Render the geometry tile - sg.renderMultiTexture(dc, numTexUnitsUsed); - } - } - } -// System.out.println(); - - gl.glActiveTexture(alphaTextureUnit); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - gl.glDisable(GL.GL_TEXTURE_2D); - - gl.glActiveTexture(GL.GL_TEXTURE0); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - gl.glDisable(GL.GL_TEXTURE_2D); - - if (showOutlines) - { - gl.glActiveTexture(GL.GL_TEXTURE1); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - gl.glDisable(GL.GL_TEXTURE_2D); - } - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("generic.ExceptionWhileRenderingLayer"); - message += this.getClass().getName(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - } - finally - { - gl.glPopAttrib(); - } - } - - private Iterable getIntersectingTiles(SectorGeometry sg, Iterable tiles) - { - ArrayList intersectingTiles = null; - - for (TextureTile tile : tiles) - { - if (!tile.getSector().intersects(sg.getSector())) - continue; - - if (intersectingTiles == null) - intersectingTiles = new ArrayList(); - - intersectingTiles.add(tile); - } - - if (intersectingTiles == null) - return null; - - return intersectingTiles; - } - - private static void fillByteBuffer(ByteBuffer buffer, byte value) - { - for (int i = 0; i < buffer.capacity(); i++) - { - buffer.put(value); - } - } - - private void initAlphaTexture(int size) - { - ByteBuffer textureBytes = com.sun.opengl.util.BufferUtil.newByteBuffer(size * size); - fillByteBuffer(textureBytes, (byte) 0xff); - TextureData textureData = new TextureData(GL.GL_ALPHA, size, size, 0, GL.GL_ALPHA, - GL.GL_UNSIGNED_BYTE, false, false, false, textureBytes.rewind(), null); - this.alphaTexture = TextureIO.newTexture(textureData); - - this.alphaTexture.bind(); - this.alphaTexture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); - this.alphaTexture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); - this.alphaTexture.setTexParameteri(GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_BORDER); - this.alphaTexture.setTexParameteri(GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_BORDER); - // Assume the default border color of (0, 0, 0, 0). - } - - private void initOutlineTexture(int size) - { - ByteBuffer textureBytes = com.sun.opengl.util.BufferUtil.newByteBuffer(size * size); - for (int row = 0; row < size; row++) - { - for (int col = 0; col < size; col++) - { - byte p; - if (row == 0 || col == 0 || row == size - 1 || col == size - 1) - p = (byte) 0xff; - else - p = (byte) 0; - textureBytes.put(row * size + col, p); - } - } - - TextureData textureData = new TextureData(GL.GL_LUMINANCE, size, size, 0, GL.GL_LUMINANCE, - GL.GL_UNSIGNED_BYTE, false, false, false, textureBytes.rewind(), null); - this.outlineTexture = TextureIO.newTexture(textureData); - - this.outlineTexture.bind(); - this.outlineTexture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); - this.outlineTexture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); - this.outlineTexture.setTexParameteri(GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); - this.outlineTexture.setTexParameteri(GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); - } -} diff --git a/gov/nasa/worldwind/Tessellator.java b/gov/nasa/worldwind/Tessellator.java deleted file mode 100644 index 367c72f..0000000 --- a/gov/nasa/worldwind/Tessellator.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id: Tessellator.java 1230 2007-03-16 14:47:35Z tgaskins $ - */ -public interface Tessellator extends WWObject -{ - SectorGeometryList tessellate(DrawContext dc); -} diff --git a/gov/nasa/worldwind/ThreadedTaskService.java b/gov/nasa/worldwind/ThreadedTaskService.java deleted file mode 100644 index ed92db5..0000000 --- a/gov/nasa/worldwind/ThreadedTaskService.java +++ /dev/null @@ -1,172 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: ThreadedTaskService.java 1792 2007-05-08 21:28:37Z tgaskins $ - */ -public class ThreadedTaskService extends WWObjectImpl // TODO: Extract interface - implements Thread.UncaughtExceptionHandler -{ - static final private int DEFAULT_CORE_POOL_SIZE = 1; - static final private int DEFAULT_QUEUE_SIZE = 10; - private static final String RUNNING_THREAD_NAME_PREFIX = WorldWind.retrieveMessage( - "ThreadedTaskService.RUNNING_THREAD_NAME_PREFIX", "ThreadStrings"); - private static final String IDLE_THREAD_NAME_PREFIX = WorldWind.retrieveMessage( - "ThreadedTaskService.IDLE_THREAD_NAME_PREFIX", "ThreadStrings"); - private java.util.concurrent.ConcurrentLinkedQueue activeTasks; // tasks currently allocated a thread - private TaskExecutor executor; // thread pool for running retrievers - - public ThreadedTaskService() - { - Integer poolSize = Configuration.getIntegerValue(AVKey.THREADED_TASK_POOL_SIZE, DEFAULT_CORE_POOL_SIZE); - Integer queueSize = Configuration.getIntegerValue(AVKey.THREADED_TASK_QUEUE_SIZE, DEFAULT_QUEUE_SIZE); - - // this.executor runs the tasks, each in their own thread - this.executor = new TaskExecutor(poolSize, queueSize); - - // this.activeTasks holds the list of currently executing tasks - this.activeTasks = new java.util.concurrent.ConcurrentLinkedQueue(); - } - - public void uncaughtException(Thread thread, Throwable throwable) - { - if (throwable instanceof WWDuplicateRequestException) - return; - - String message = WorldWind.retrieveErrMsg("ThreadedTaskService.UncaughtExceptionDuringTask") + thread.getName(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - Thread.currentThread().getThreadGroup().uncaughtException(thread, throwable); - } - - private class TaskExecutor extends java.util.concurrent.ThreadPoolExecutor - { - private static final long THREAD_TIMEOUT = 2; // keep idle threads alive this many seconds - - private TaskExecutor(int poolSize, int queueSize) - { - super(poolSize, poolSize, THREAD_TIMEOUT, java.util.concurrent.TimeUnit.SECONDS, - new java.util.concurrent.ArrayBlockingQueue(queueSize), - new java.util.concurrent.ThreadFactory() - { - public Thread newThread(Runnable runnable) - { - Thread thread = new Thread(runnable); - thread.setDaemon(true); - thread.setPriority(Thread.MIN_PRIORITY); - thread.setUncaughtExceptionHandler(ThreadedTaskService.this); - return thread; - } - }, new java.util.concurrent.ThreadPoolExecutor.DiscardPolicy() // abandon task when queue is full - { - public void rejectedExecution(Runnable runnable, - java.util.concurrent.ThreadPoolExecutor threadPoolExecutor) - { - // Interposes logging for rejected execution - String message = WorldWind.retrieveErrMsg("ThreadedTaskService.ResourceRejected") + runnable; - WorldWind.logger().log(java.util.logging.Level.FINEST, message); - super.rejectedExecution(runnable, threadPoolExecutor); - } - }); - } - - protected void beforeExecute(Thread thread, Runnable runnable) - { - WorldWind.logger().log(java.util.logging.Level.FINEST, WorldWind.retrieveErrMsg( - "ThreadedTaskService.EnteringBeforeExecute")); - - if (thread == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ThreadIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (runnable == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RunnableIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (ThreadedTaskService.this.activeTasks.contains(runnable)) - { - String message = WorldWind.retrieveErrMsg("ThreadedTaskService.CancellingDuplicateTask") + runnable; - WorldWind.logger().log(java.util.logging.Level.FINER, message); - throw new WWDuplicateRequestException(message); - } - - ThreadedTaskService.this.activeTasks.add(runnable); - - if (RUNNING_THREAD_NAME_PREFIX != null) - thread.setName(RUNNING_THREAD_NAME_PREFIX + runnable); - thread.setPriority(Thread.MIN_PRIORITY); - thread.setUncaughtExceptionHandler(ThreadedTaskService.this); - - super.beforeExecute(thread, runnable); - - WorldWind.logger().log(java.util.logging.Level.FINEST, WorldWind.retrieveErrMsg( - "ThreadedTaskService.LeavingBeforeExecute")); - } - - protected void afterExecute(Runnable runnable, Throwable throwable) - { - WorldWind.logger().log(java.util.logging.Level.FINEST, WorldWind.retrieveErrMsg( - "ThreadedTaskService.EnteringAfterExecute")); - - if (runnable == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RunnableIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - super.afterExecute(runnable, throwable); - - ThreadedTaskService.this.activeTasks.remove(runnable); - - if (throwable == null && IDLE_THREAD_NAME_PREFIX != null) - Thread.currentThread().setName(IDLE_THREAD_NAME_PREFIX); - } - } - - public synchronized boolean contains(Runnable runnable) - { - //noinspection SimplifiableIfStatement - if (runnable == null) - return false; - - return (this.activeTasks.contains(runnable) || this.executor.getQueue().contains(runnable)); - } - - /** - * Enqueues a task to run. - * @param runnable the task to add - * @throws IllegalArgumentException if runnable is null - */ - public synchronized void addTask(Runnable runnable) - { - if (runnable == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RunnableIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - // Do not queue duplicates. - if (this.activeTasks.contains(runnable) || this.executor.getQueue().contains(runnable)) - return; - - this.executor.execute(runnable); - } - - public boolean isFull() - { - return this.executor.getQueue().remainingCapacity() == 0; - } -} diff --git a/gov/nasa/worldwind/Tile.java b/gov/nasa/worldwind/Tile.java deleted file mode 100644 index 73fec23..0000000 --- a/gov/nasa/worldwind/Tile.java +++ /dev/null @@ -1,407 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * @author tag - * @version $Id: Tile.java 2029 2007-06-14 02:44:20Z tgaskins $ - */ -public class Tile implements Comparable, Cacheable -{ - private final Sector sector; - private final gov.nasa.worldwind.Level level; - private final int row; - private final int column; - private final TileKey tileKey; - private double priority = Double.MAX_VALUE; // Default is minimum priority - // The following is late bound because it's only selectively needed and costly to create - private String path; - - public Tile(Sector sector, Level level, int row, int column) - { - if (sector == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (level == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.LevelIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (row < 0) - { - String msg = WorldWind.retrieveErrMsg("generic.rowIndexOutOfRange"); - msg += WorldWind.retrieveErrMsg("punctuation.space"); - msg += String.valueOf(row); - - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (column < 0) - { - String msg = WorldWind.retrieveErrMsg("generic.columnIndexOutOfRange"); - msg += WorldWind.retrieveErrMsg("punctuation.space"); - msg += String.valueOf(row); - - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.sector = sector; - this.level = level; - this.row = row; - this.column = column; - this.tileKey = new TileKey(this); - this.path = null; - } - - public Tile(Sector sector, gov.nasa.worldwind.Level level) - { - if (sector == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (level == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.LevelIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.sector = sector; - this.level = level; - this.row = Tile.computeRow(sector.getDeltaLat(), sector.getMinLatitude()); - this.column = Tile.computeColumn(sector.getDeltaLon(), sector.getMinLongitude()); - this.tileKey = new TileKey(this); - this.path = null; - } - - public Tile(Sector sector) - { - if (sector == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.sector = sector; - this.level = null; - this.row = 0; - this.column = 0; - this.tileKey = new TileKey(this); - this.path = null; - } - - public long getSizeInBytes() - { - // Return just an approximate size - long size = 0; - - if (this.sector != null) - size += this.sector.getSizeInBytes(); - - if (this.path != null) - size += this.getPath().length(); - - size += 32; // to account for the references and the TileKey size - - return size; - } - - public String getPath() - { - if (this.path == null) - { - this.path = this.level.getPath() + "/" + this.row + "/" + this.row + "_" + this.column; - if (!this.level.isEmpty()) - path += this.level.getFormatSuffix(); - } - - return this.path; - } - - public final Sector getSector() - { - return sector; - } - - public gov.nasa.worldwind.Level getLevel() - { - return level; - } - - public final int getLevelNumber() - { - return this.level != null ? this.level.getLevelNumber() : 0; - } - - public final String getLevelName() - { - return this.level != null ? this.level.getLevelName() : ""; - } - - public final int getRow() - { - return row; - } - - public final int getColumn() - { - return column; - } - - public final String getCacheName() - { - return this.level != null ? this.level.getCacheName() : null; - } - - public final String getFormatSuffix() - { - return this.level != null ? this.level.getFormatSuffix() : null; - } - - public final TileKey getTileKey() - { - return this.tileKey; - } - - public java.net.URL getResourceURL() throws java.net.MalformedURLException - { - return this.level != null ? this.level.getTileResourceURL(this) : null; - } - - public String getLabel() - { - StringBuilder sb = new StringBuilder(); - - sb.append(this.getLevelNumber()); - sb.append("("); - sb.append(this.getLevelName()); - sb.append(")"); - sb.append(", ").append(this.getRow()); - sb.append(", ").append(this.getColumn()); - - return sb.toString(); - } - - public int compareTo(Tile tile) - { - if (tile == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.TileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - // No need to compare Sectors or path because they are redundant with row and column - if (tile.getLevelNumber() == this.getLevelNumber() && tile.row == this.row && tile.column == this.column) - return 0; - - if (this.getLevelNumber() < tile.getLevelNumber()) // Lower-res levels compare lower than higher-res - return -1; - if (this.getLevelNumber() > tile.getLevelNumber()) - return 1; - - if (this.row < tile.row) - return -1; - if (this.row > tile.row) - return 1; - - if (this.column < tile.column) - return -1; - - return 1; // tile.column must be > this.column because equality was tested above - } - - @Override - public boolean equals(Object o) - { - // Equality based only on the tile key - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final Tile tile = (Tile) o; - - return !(tileKey != null ? !tileKey.equals(tile.tileKey) : tile.tileKey != null); - } - - @Override - public int hashCode() - { - return (tileKey != null ? tileKey.hashCode() : 0); - } - - @Override - public String toString() - { - return this.getPath(); - } - - /** - * Computes the row index of a latitude in the global tile grid corresponding to a specified grid interval. - * - * @param delta the grid interval - * @param latitude the latitude for which to compute the row index - * @return the row index of the row containing the specified latitude - * @throws IllegalArgumentException if delta is null or non-positive, or latitude is null, - * greater than positive 90 degrees, or less than negative 90 degrees - */ - public static int computeRow(Angle delta, Angle latitude) - { - if (delta == null || latitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (delta.degrees <= 0d) - { - String message = WorldWind.retrieveErrMsg("generic.deltaAngleOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (latitude.degrees < -90d || latitude.degrees > 90d) - { - String message = WorldWind.retrieveErrMsg("generic.angleOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (latitude.degrees == 90d) - return (int) (180d / delta.degrees) - 1; - else - return (int) ((latitude.degrees + 90d) / delta.degrees); - } - - /** - * Computes the column index of a longitude in the global tile grid corresponding to a specified grid interval. - * - * @param delta the grid interval - * @param longitude the longitude for which to compute the column index - * @return the column index of the column containing the specified latitude - * @throws IllegalArgumentException if delta is null or non-positive, or longitude is - * null, greater than positive 180 degrees, or less than negative 180 degrees - */ - public static int computeColumn(Angle delta, Angle longitude) - { - if (delta == null || longitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (delta.degrees <= 0d) - { - String message = WorldWind.retrieveErrMsg("generic.deltaAngleOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (longitude.degrees < -180d || longitude.degrees > 180d) - { - String message = WorldWind.retrieveErrMsg("generic.angleOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (longitude.degrees == 180d) - return (int) (360d / delta.degrees) - 1; - else - return (int) ((longitude.degrees + 180d) / delta.degrees); - } - - /** - * Determines the minimum latitude of a row in the global tile grid corresponding to a specified grid interval. - * - * @param row the row index of the row in question - * @param delta the grid interval - * @return the minimum latitude of the tile corresponding to the specified row - * @throws IllegalArgumentException if the grid interval (delta) is null or zero or the row index is - * negative. - */ - public static Angle computeRowLatitude(int row, Angle delta) - { - if (delta == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (row < 0) - { - String msg = WorldWind.retrieveErrMsg("generic.rowIndexOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (delta.degrees <= 0d) - { - String message = WorldWind.retrieveErrMsg("generic.deltaAngleOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return Angle.fromDegrees(-90d + delta.degrees * row); - } - - /** - * Determines the minimum longitude of a column in the global tile grid corresponding to a specified grid interval. - * - * @param column the row index of the row in question - * @param delta the grid interval - * @return the minimum longitude of the tile corresponding to the specified column - * @throws IllegalArgumentException if the grid interval (delta) is null or zero or the column index is - * negative. - */ - public static Angle computeColumnLongitude(int column, Angle delta) - { - if (delta == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (column < 0) - { - String msg = WorldWind.retrieveErrMsg("generic.columnIndexOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (delta.degrees <= 0d) - { - String message = WorldWind.retrieveErrMsg("generic.deltaAngleOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return Angle.fromDegrees(-180 + delta.degrees * column); - } - - public double getPriority() - { - return priority; - } - - public void setPriority(double priority) - { - this.priority = priority; - } -} diff --git a/gov/nasa/worldwind/TileKey.java b/gov/nasa/worldwind/TileKey.java deleted file mode 100644 index 6983c4f..0000000 --- a/gov/nasa/worldwind/TileKey.java +++ /dev/null @@ -1,205 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * @author tag - * @version $Id: TileKey.java 511 2007-01-17 07:26:02Z ericdalgliesh $ - */ -public class TileKey implements Comparable -{ - private final int level; - private final int row; - private final int col; - private final String cacheName; - private final int hash; - - /** - * @param level - * @param row - * @param col - * @param cacheName - * @throws IllegalArgumentException if level, row or column is negative or if - * cacheName is null or empty - */ - public TileKey(int level, int row, int col, String cacheName) - { - if (level < 0) - { - String msg = WorldWind.retrieveErrMsg("TileKey.levelIsLessThanZero"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (row < 0) - { - String msg = WorldWind.retrieveErrMsg("generic.rowIndexOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (col < 0) - { - String msg = WorldWind.retrieveErrMsg("generic.columnIndexOutOfRange"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (cacheName == null || cacheName.length() < 1) - { - String msg = WorldWind.retrieveErrMsg("TileKey.cacheNameIsNullOrEmpty"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.level = level; - this.row = row; - this.col = col; - this.cacheName = cacheName; - this.hash = this.computeHash(); - } - - /** - * @param latitude - * @param longitude - * @param level - * @throws IllegalArgumentException if any parameter is null - */ - public TileKey(Angle latitude, Angle longitude, Level level) - { - if (latitude == null || longitude == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - if (level == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.LevelIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.level = level.getLevelNumber(); - this.row = Tile.computeRow(level.getTileDelta().getLatitude(), latitude); - this.col = Tile.computeColumn(level.getTileDelta().getLongitude(), longitude); - this.cacheName = level.getCacheName(); - this.hash = this.computeHash(); - } - - /** - * @param tile - * @throws IllegalArgumentException if tile is null - */ - public TileKey(gov.nasa.worldwind.Tile tile) - { - if (tile == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.TileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - this.level = tile.getLevelNumber(); - this.row = tile.getRow(); - this.col = tile.getColumn(); - this.cacheName = tile.getCacheName(); - this.hash = this.computeHash(); - } - - public int getLevelNumber() - { - return level; - } - - public int getRow() - { - return row; - } - - public int getColumn() - { - return col; - } - - public String getCacheName() - { - return cacheName; - } - - private int computeHash() - { - int result; - result = this.level; - result = 29 * result + this.row; - result = 29 * result + this.col; - result = 29 * result + (this.cacheName != null ? this.cacheName.hashCode() : 0); - return result; - } - - /** - * @param key - * @return - * @throws IllegalArgumentException if key is null - */ - public final int compareTo(TileKey key) - { - if (key == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.KeyIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - // No need to compare Sectors because they are redundant with row and column - if (key.level == this.level && key.row == this.row && key.col == this.col) - return 0; - - if (this.level < key.level) // Lower-res levels compare lower than higher-res - return -1; - if (this.level > key.level) - return 1; - - if (this.row < key.row) - return -1; - if (this.row > key.row) - return 1; - - if (this.col < key.col) - return -1; - - return 1; // tile.col must be > this.col because equality was tested above - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final TileKey tileKey = (TileKey) o; - - if (this.col != tileKey.col) - return false; - if (this.level != tileKey.level) - return false; - if (this.row != tileKey.row) - return false; - - return !(this.cacheName != null ? !this.cacheName.equals(tileKey.cacheName) : tileKey.cacheName != null); - } - - @Override - public int hashCode() - { - return this.hash; - } - - @Override - public String toString() - { - return this.cacheName + "/" + this.level + "/" + this.row + "/" + col; - } -} diff --git a/gov/nasa/worldwind/ToolTipRenderer.java b/gov/nasa/worldwind/ToolTipRenderer.java deleted file mode 100644 index 866eae4..0000000 --- a/gov/nasa/worldwind/ToolTipRenderer.java +++ /dev/null @@ -1,275 +0,0 @@ -/* -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; - -import com.sun.opengl.util.j2d.*; - -import javax.media.opengl.*; -import javax.media.opengl.glu.*; -import javax.swing.*; -import javax.swing.border.*; -import java.awt.*; -import java.awt.geom.*; -import static java.util.logging.Level.*; - -/** - * @author dcollins - * @version $Id: ToolTipRenderer.java 1786 2007-05-08 14:05:34Z dcollins $ - */ -public class ToolTipRenderer -{ - private static final Font toolTipFont = UIManager.getFont("ToolTip.font"); - private static final Color toolTipFg = UIManager.getColor("ToolTip.foreground"); - private static final Color toolTipBg = UIManager.getColor("ToolTip.background"); - private static final Border toolTipBorder = UIManager.getBorder("ToolTip.border"); - - private Color foreground; - private Color background; - private float[] compArray; - private Insets insets; - private float borderWidth; - private boolean useSystemLookAndFeel = false; - - private TextRenderer textRenderer; - private int orthoWidth; - private int orthoHeight; - private GLU glu = new GLU(); - - public ToolTipRenderer() - { - this(new TextRenderer(toolTipFont, true, true), false); - } - - public ToolTipRenderer(TextRenderer textRenderer) - { - this(textRenderer, false); - } - - public ToolTipRenderer(TextRenderer textRenderer, boolean useSystemLookAndFeel) - { - if (textRenderer == null) - { - String message = WorldWind.retrieveErrMsg(""); // TODO - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - this.textRenderer = textRenderer; - this.useSystemLookAndFeel = useSystemLookAndFeel; - this.borderWidth = 1; - } - - public void beginRendering(int width, int height, boolean disableDepthTest) - { - GL gl = GLU.getCurrentGL(); - int attribBits = - GL.GL_ENABLE_BIT - | GL.GL_COLOR_BUFFER_BIT // for alpha test func and ref, and blend - | GL.GL_CURRENT_BIT // for current color - | GL.GL_TRANSFORM_BIT // for modelview and perspective - | GL.GL_POLYGON_BIT; // for polygon mode - gl.glPushAttrib(attribBits); - - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPushMatrix(); - gl.glLoadIdentity(); - glu.gluOrtho2D(0, width, 0, height); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPushMatrix(); - gl.glLoadIdentity(); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPushMatrix(); - gl.glLoadIdentity(); - - gl.glDisable(GL.GL_LIGHTING); - gl.glDisable(GL.GL_TEXTURE_2D); - if (disableDepthTest) - gl.glDisable(GL.GL_DEPTH_TEST); - gl.glDisable(GL.GL_CULL_FACE); - gl.glEnable(GL.GL_BLEND); - gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA); - // Suppress any fully transparent image pixels - final float ALPHA_EPSILON = 0.001f; - gl.glEnable(GL.GL_ALPHA_TEST); - gl.glAlphaFunc(GL.GL_GREATER, ALPHA_EPSILON); - - this.orthoWidth = width; - this.orthoHeight = height; - } - - public void endRendering() - { - GL gl = GLU.getCurrentGL(); - - gl.glMatrixMode(GL.GL_PROJECTION); - gl.glPopMatrix(); - gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glPopMatrix(); - gl.glMatrixMode(GL.GL_TEXTURE); - gl.glPopMatrix(); - - gl.glPopAttrib(); - } - - private static Rectangle2D ensureVisibleBounds(Rectangle2D bounds, int orthoWidth, int orthoHeight) - { - double newX; - if (bounds.getMinX() < 0) - newX = 1; - else if (bounds.getMaxX() > orthoWidth) - newX = orthoWidth - bounds.getWidth() - 1; - else - newX = bounds.getX(); - - double newY; - if (bounds.getMinX() < 0) - newY = 1; - else if (bounds.getMaxY() > orthoHeight) - newY = orthoHeight - bounds.getHeight() - 1; - else - newY = bounds.getY(); - - return new Rectangle2D.Double(newX, newY, bounds.getWidth(), bounds.getHeight()); - } - - public Color getBackground() - { - return this.background; - } - - public float getBorderWidth() - { - return this.borderWidth; - } - - public Color getForeground() - { - return this.foreground; - } - - public Insets getInsets() - { - return this.insets; - } - - public boolean getUseSystemLookAndFeel() - { - return this.useSystemLookAndFeel; - } - - public void draw(String str, int x, int y) - { - if (str == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - - Color fg; - Color bg; - Insets insets; - - GL gl = GLU.getCurrentGL(); - if (this.useSystemLookAndFeel) - { - insets = toolTipBorder.getBorderInsets(null); - fg = toolTipFg; - bg = toolTipBg; - } - else - { - if (this.foreground != null) - { - fg = this.foreground; - } - else - { - gl.glGetFloatv(GL.GL_CURRENT_COLOR, compArray, 0); - fg = new Color(compArray[0], compArray[1], compArray[2], compArray[3]); - } - - if (this.background != null) - { - bg = this.background; - } - else - { - if (compArray == null) - compArray = new float[4]; - Color.RGBtoHSB(fg.getRed(), fg.getGreen(), fg.getBlue(), compArray); - bg = Color.getHSBColor(0, 0, (compArray[2] + 0.5f) % 1f); - } - - if (this.insets != null) - insets = this.insets; - else - insets = new Insets(1, 1, 1, 1); - } - - Rectangle2D strBounds = this.textRenderer.getBounds(str); - Rectangle2D ttBounds = new Rectangle2D.Double( - x, y, - strBounds.getWidth() + insets.left + insets.right, - strBounds.getHeight() + insets.bottom + insets.top); - ttBounds = ensureVisibleBounds(ttBounds, this.orthoWidth, this.orthoHeight); - double strX = ttBounds.getX() + insets.left - strBounds.getX(); - double strY = ttBounds.getY() + insets.bottom + strBounds.getY() + strBounds.getHeight(); - - this.setDrawColor(bg); - gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); - gl.glRectd(ttBounds.getMinX(), ttBounds.getMinY(), ttBounds.getMaxX(), ttBounds.getMaxY()); - - this.setDrawColor(fg); - gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE); - gl.glLineWidth(this.borderWidth); - gl.glRectd(ttBounds.getMinX(), ttBounds.getMinY(), ttBounds.getMaxX(), ttBounds.getMaxY()); - - this.textRenderer.setColor(fg); - gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); - this.textRenderer.begin3DRendering(); - this.textRenderer.draw(str, (int) strX, (int) strY); - this.textRenderer.end3DRendering(); - } - - public void setBackground(Color color) - { - this.background = color; - } - - public void setBorderWidth(float borderWidth) - { - this.borderWidth = borderWidth; - } - - private void setDrawColor(float r, float g, float b, float a) - { - GL gl = GLU.getCurrentGL(); - gl.glColor4f(r * a, g * a, b * a, a); - } - - private void setDrawColor(Color color) - { - if (this.compArray == null) - this.compArray = new float[4]; - color.getRGBComponents(this.compArray); - this.setDrawColor(this.compArray[0], this.compArray[1], this.compArray[2], this.compArray[3]); - } - - public void setForeground(Color color) - { - this.foreground = color; - } - - public void setInsets(Insets insets) - { - this.insets = insets; - } - - public void setUseSystemLookAndFeel(boolean useSystemLookAndFeel) - { - this.useSystemLookAndFeel = useSystemLookAndFeel; - } -} diff --git a/gov/nasa/worldwind/Track.java b/gov/nasa/worldwind/Track.java deleted file mode 100644 index a3ae51a..0000000 --- a/gov/nasa/worldwind/Track.java +++ /dev/null @@ -1,20 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id: Track.java 1016 2007-02-25 11:24:47Z tgaskins $ - */ -public interface Track -{ - java.util.List getSegments(); - - String getName(); - - int getNumPoints(); -} diff --git a/gov/nasa/worldwind/TrackPoint.java b/gov/nasa/worldwind/TrackPoint.java deleted file mode 100644 index 8bcc915..0000000 --- a/gov/nasa/worldwind/TrackPoint.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id: TrackPoint.java 288 2006-12-07 12:21:49Z tgaskins $ - */ -public interface TrackPoint -{ - double getLatitude(); - - void setLatitude(double latitude); - - double getLongitude(); - - void setLongitude(double longitude); - - double getElevation(); - - void setElevation(double elevation); - - String getTime(); - - void setTime(String time); -} diff --git a/gov/nasa/worldwind/TrackPointIterator.java b/gov/nasa/worldwind/TrackPointIterator.java deleted file mode 100644 index f8c1a28..0000000 --- a/gov/nasa/worldwind/TrackPointIterator.java +++ /dev/null @@ -1,22 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id$ - */ -public interface TrackPointIterator extends java.util.Iterator -{ - boolean hasNext(); - - TrackPoint next(); - - void remove(); - - TrackPointIterator reset(); -} diff --git a/gov/nasa/worldwind/TrackPointIteratorImpl.java b/gov/nasa/worldwind/TrackPointIteratorImpl.java deleted file mode 100644 index fd1a254..0000000 --- a/gov/nasa/worldwind/TrackPointIteratorImpl.java +++ /dev/null @@ -1,99 +0,0 @@ -/* -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; - -import java.util.*; - -/** - * @author tag - * @version $Id$ - */ -public class TrackPointIteratorImpl implements TrackPointIterator -{ - private java.util.List tracksList; - private java.util.Iterator tracks; - private java.util.Iterator segments; - private java.util.Iterator positions; - - public TrackPointIteratorImpl(java.util.List tracksList) - { - this.tracksList = tracksList; - this.reset(); - } - - public TrackPointIteratorImpl reset() - { - if (this.tracksList == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.TracksIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.tracks = this.tracksList.iterator(); - this.segments = null; - this.positions = null; - this.loadNextPositions(); - - return this; - } - - public boolean hasNext() - { - if (this.positions != null && this.positions.hasNext()) - return true; - - this.loadNextPositions(); - - return (this.positions != null && this.positions.hasNext()); - } - - private void loadNextPositions() - { - if (this.segments != null && this.segments.hasNext()) - { - TrackSegment segment = this.segments.next(); - this.positions = segment.getPoints().iterator(); - return; - } - - if (this.tracks.hasNext()) - { - Track track = this.tracks.next(); - this.segments = track.getSegments().iterator(); - this.loadNextPositions(); - } - } - - public TrackPoint next() - { - if (!this.hasNext()) - { - String msg = WorldWind.retrieveErrMsg("iterator.NoMoreTrackPoints"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new NoSuchElementException(msg); - } - - return this.positions.next(); - } - - public void remove() - { - String msg = WorldWind.retrieveErrMsg("iterator.RemoveNotSupported"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new UnsupportedOperationException(msg); - } - - public int getNumPoints() - { - int numPoints; - for (numPoints = 0; this.hasNext(); this.next()) - ++numPoints; - - return numPoints; - } -} diff --git a/gov/nasa/worldwind/TrackRenderer.java b/gov/nasa/worldwind/TrackRenderer.java deleted file mode 100644 index 31b4f77..0000000 --- a/gov/nasa/worldwind/TrackRenderer.java +++ /dev/null @@ -1,409 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import javax.media.opengl.glu.*; - -/** - * @author tag - * @version $Id$ - */ -public class TrackRenderer implements Disposable -{ - private int lowerLimit = 0; - private int upperLimit = Integer.MAX_VALUE; - private double markerPixels = 10d; // TODO: these should all be configurable - private double minMarkerSize = 5d; - private double markerElevation = 10d; - private boolean overrideMarkerElevation = false; - private Material material = Material.WHITE; - private String iconFilePath; - private final TrackRenderer.Shape SPHERE = new TrackRenderer.Sphere(); - private final TrackRenderer.Shape CONE = new TrackRenderer.Cone(); - private final TrackRenderer.Shape CYLINDER = new TrackRenderer.Cylinder(); - private TrackRenderer.Shape shape = SPHERE; - - public TrackRenderer() - { - } - - public void dispose() - { - this.CONE.dispose(); - this.CYLINDER.dispose(); - this.SPHERE.dispose(); - } - - public double getMarkerPixels() - { - return markerPixels; - } - - public void setMarkerPixels(double markerPixels) - { - this.markerPixels = markerPixels; - } - - public double getMinMarkerSize() - { - return minMarkerSize; - } - - public void setMinMarkerSize(double minMarkerSize) - { - this.minMarkerSize = minMarkerSize; - } - - public double getMarkerElevation() - { - return markerElevation; - } - - public void setMarkerElevation(double markerElevation) - { - this.markerElevation = markerElevation; - } - - public boolean isOverrideMarkerElevation() - { - return overrideMarkerElevation; - } - - public void setOverrideMarkerElevation(boolean overrideMarkerElevation) - { - this.overrideMarkerElevation = overrideMarkerElevation; - } - - public Material getMaterial() - { - return material; - } - - public void setMaterial(Material material) - { - if (material == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.MaterialIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - // don't validate material's colors - material does that. - - this.material = material; - } - - public String getIconFilePath() - { - return iconFilePath; - } - - public void setIconFilePath(String iconFilePath) - { - //don't validate - a null iconFilePath cancels icon drawing - this.iconFilePath = iconFilePath; - } - - public int getLowerLimit() - { - return this.lowerLimit; - } - - public void setLowerLimit(int lowerLimit) - { - this.lowerLimit = lowerLimit; - } - - public int getUpperLimit() - { - return this.upperLimit; - } - - public void setUpperLimit(int upperLimit) - { - this.upperLimit = upperLimit; - } - - public void setShapeType(String shapeName) - { - if (shapeName.equalsIgnoreCase("Cone")) - this.shape = CONE; - else if (shapeName.equalsIgnoreCase("Cylinder")) - this.shape = CYLINDER; - else - this.shape = SPHERE; - } - - public void pick(DrawContext dc, java.util.Iterator trackPositions, java.awt.Point pickPoint, - Layer layer) - { - // TODO: picking - } - - public Vec4 render(DrawContext dc, java.util.Iterator trackPositions) - { - return this.draw(dc, trackPositions); - } - - private Vec4 draw(DrawContext dc, java.util.Iterator trackPositions) - { - if (dc.getVisibleSector() == null) - return null; - - SectorGeometryList geos = dc.getSurfaceGeometry(); - if (geos == null) - return null; - - if (!this.shape.isInitialized) - this.shape.initialize(dc); - - int index = 0; - java.util.List points = new java.util.ArrayList(); - while (trackPositions.hasNext()) - { - TrackPoint tp = trackPositions.next(); - if (index >= this.lowerLimit && index <= this.upperLimit) - { - Vec4 point = this.computeSurfacePoint(dc, tp); - if (point != null) - { - points.add(point); - } - } - if (++index >= this.upperLimit) - break; - } - - if (points.size() < 1) - return null; - - Vec4 firstPoint = points.get(0); - Vec4 lastPointDrawn = firstPoint; - this.begin(dc); - { - Vec4 previousDrawnPoint = null; - - double radius = this.computeMarkerRadius(dc, firstPoint); - this.shape.render(dc, firstPoint, radius); - for (Vec4 point : points) - { - if (previousDrawnPoint == null) - { - previousDrawnPoint = firstPoint; - continue; // skip over first point - } - - // TODO: More sophisticated separation algorithm to gain frame-to-frame consistency - radius = this.computeMarkerRadius(dc, point); - double separation = point.distanceTo3(previousDrawnPoint); - double minSeparation = 4d * radius; - if (separation > minSeparation) - { - if (!dc.isPickingMode()) - this.shape.render(dc, point, radius); - - previousDrawnPoint = point; - lastPointDrawn = point; - } - } - } - this.end(dc); - - Vec4 iconPoint = points.get(points.size() - 1); - return iconPoint != null ? iconPoint : lastPointDrawn; - } - - private Vec4 computeSurfacePoint(DrawContext dc, TrackPoint pos) - { - return dc.getSurfaceGeometry().getSurfacePoint(Angle.fromDegrees(pos.getLatitude()), - Angle.fromDegrees(pos.getLongitude()), - this.overrideMarkerElevation ? this.markerElevation : pos.getElevation()); - } - - private double computeMarkerRadius(DrawContext dc, Vec4 point) - { - double d = point.distanceTo3(dc.getView().getEyePoint()); - double radius = this.markerPixels * dc.getView().computePixelSizeAtDistance(d); - if (radius < this.minMarkerSize) - radius = this.minMarkerSize; - - return radius; - } - - private void begin(DrawContext dc) - { - GL gl = dc.getGL(); - Vec4 cameraPosition = dc.getView().getEyePoint(); - - gl.glPushAttrib( - GL.GL_TEXTURE_BIT | GL.GL_ENABLE_BIT | GL.GL_CURRENT_BIT | GL.GL_LIGHTING_BIT | GL.GL_TRANSFORM_BIT); - gl.glDisable(GL.GL_TEXTURE_2D); - - float[] lightPosition = - {(float) (cameraPosition.x * 2), (float) (cameraPosition.y / 2), (float) (cameraPosition.z), 0.0f}; - float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f}; - float[] lightAmbient = {1.0f, 1.0f, 1.0f, 1.0f}; - float[] lightSpecular = {1.0f, 1.0f, 1.0f, 1.0f}; - - this.material.apply(gl, GL.GL_FRONT); - - gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPosition, 0); - gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, lightDiffuse, 0); - gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightAmbient, 0); - gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, lightSpecular, 0); - - gl.glDisable(GL.GL_LIGHT0); - gl.glEnable(GL.GL_LIGHT1); - gl.glEnable(GL.GL_LIGHTING); - gl.glEnable(GL.GL_NORMALIZE); - - gl.glMatrixMode(javax.media.opengl.GL.GL_MODELVIEW); - gl.glPushMatrix(); - } - - private void end(DrawContext dc) - { - GL gl = dc.getGL(); - - gl.glMatrixMode(javax.media.opengl.GL.GL_MODELVIEW); - gl.glPopMatrix(); - - gl.glDisable(GL.GL_LIGHT1); - gl.glEnable(GL.GL_LIGHT0); - gl.glDisable(GL.GL_LIGHTING); - gl.glDisable(GL.GL_NORMALIZE); - gl.glPopAttrib(); - } - - private static abstract class Shape - { - protected int objectId; - protected GLUquadric quadric; - protected boolean isInitialized = false; - - abstract protected void doRender(DrawContext dc, Vec4 point, double radius); - - protected void initialize(DrawContext dc) - { - this.objectId = dc.getGL().glGenLists(1); - this.quadric = dc.getGLU().gluNewQuadric(); - dc.getGLU().gluQuadricDrawStyle(quadric, GLU.GLU_FILL); - dc.getGLU().gluQuadricNormals(quadric, GLU.GLU_SMOOTH); - dc.getGLU().gluQuadricOrientation(quadric, GLU.GLU_OUTSIDE); - dc.getGLU().gluQuadricTexture(quadric, false); - } - - private void dispose() - { - if (this.isInitialized) - { - GLU glu = new GLU(); - glu.gluDeleteQuadric(this.quadric); - // TODO: Determine how to release the opengl object ID. - } - } - - private void render(DrawContext dc, Vec4 point, double radius) - { - dc.getView().pushReferenceCenter(dc, point); - this.doRender(dc, point, radius); - dc.getView().popReferenceCenter(dc); - } - } - - private static class Sphere extends Shape - { - protected void initialize(DrawContext dc) - { - super.initialize(dc); - - double radius = 1; - int slices = 36; - int stacks = 18; - - dc.getGL().glNewList(this.objectId, GL.GL_COMPILE); - dc.getGLU().gluSphere(quadric, radius, slices, stacks); - dc.getGL().glEndList(); - - this.isInitialized = true; - } - - protected void doRender(DrawContext dc, Vec4 point, double radius) - { - dc.getGL().glScaled(radius, radius, radius); - dc.getGL().glCallList(this.objectId); - } - } - - private static class Cone extends Shape - { - protected void initialize(DrawContext dc) - { - super.initialize(dc); - - int slices = 30; - int stacks = 30; - int loops = 2; - - dc.getGL().glNewList(this.objectId, GL.GL_COMPILE); - dc.getGLU().gluCylinder(quadric, 1d, 0d, 2d, slices, (int) (2 * (Math.sqrt(stacks)) + 1)); - dc.getGLU().gluDisk(quadric, 0d, 1d, slices, loops); - dc.getGL().glEndList(); - - this.isInitialized = true; - } - - protected void doRender(DrawContext dc, Vec4 point, double size) - { - PolarPoint p = PolarPoint.fromCartesian(point); - - dc.getGL().glLoadIdentity(); - dc.getGL().glScaled(size, size, size); - dc.getGL().glRotated(p.getLongitude().getDegrees(), 0, 1, 0); - dc.getGL().glRotated(Math.abs(p.getLatitude().getDegrees()), Math.signum(p.getLatitude().getDegrees()) * -1, - 0, 0); - dc.getGL().glCallList(this.objectId); - } - } - - private static class Cylinder extends Shape - { - protected void initialize(DrawContext dc) - { - super.initialize(dc); - - int slices = 30; - int stacks = 30; - int loops = 2; - - dc.getGL().glNewList(this.objectId, GL.GL_COMPILE); - dc.getGLU().gluCylinder(quadric, 1d, 1d, 2d, slices, (int) (2 * (Math.sqrt(stacks)) + 1)); - dc.getGLU().gluDisk(quadric, 0d, 1d, slices, loops); - dc.getGL().glTranslated(0, 0, 2); - dc.getGLU().gluDisk(quadric, 0d, 1d, slices, loops); - dc.getGL().glTranslated(0, 0, -2); - dc.getGL().glEndList(); - - this.isInitialized = true; - } - - protected void doRender(DrawContext dc, Vec4 point, double size) - { - PolarPoint p = PolarPoint.fromCartesian(point); - - dc.getGL().glLoadIdentity(); - dc.getGL().glScaled(size, size, size); - dc.getGL().glRotated(p.getLongitude().getDegrees(), 0, 1, 0); - dc.getGL().glRotated(Math.abs(p.getLatitude().getDegrees()), Math.signum(p.getLatitude().getDegrees()) * -1, - 0, 0); - dc.getGL().glCallList(this.objectId); - } - } -} diff --git a/gov/nasa/worldwind/TrackSegment.java b/gov/nasa/worldwind/TrackSegment.java deleted file mode 100644 index 52276fa..0000000 --- a/gov/nasa/worldwind/TrackSegment.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id: TrackSegment.java 288 2006-12-07 12:21:49Z tgaskins $ - */ -public interface TrackSegment -{ - java.util.List getPoints(); -} diff --git a/gov/nasa/worldwind/URLRetriever.java b/gov/nasa/worldwind/URLRetriever.java deleted file mode 100644 index 2975e3e..0000000 --- a/gov/nasa/worldwind/URLRetriever.java +++ /dev/null @@ -1,487 +0,0 @@ -/* -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; - -import java.util.concurrent.atomic.*; -import java.util.zip.*; -import java.nio.*; -import java.nio.channels.*; -import java.net.*; -import java.io.*; - -/** - * @author Tom Gaskins - * @version $Id: URLRetriever.java 2228 2007-07-06 22:18:04Z tgaskins $ - */ -public abstract class URLRetriever extends WWObjectImpl implements Retriever -{ - private volatile String state = RETRIEVER_STATE_NOT_STARTED; - private volatile int contentLength = 0; - private AtomicInteger contentLengthRead = new AtomicInteger(0); - private volatile String contentType; - private volatile ByteBuffer byteBuffer; - private volatile URLConnection connection; - private final URL url; - private final RetrievalPostProcessor postProcessor; - private int connectTimeout = Configuration.getIntegerValue(AVKey.URL_CONNECT_TIMEOUT, 8000); - private int readTimeout = Configuration.getIntegerValue(AVKey.URL_READ_TIMEOUT, 5000); - private int staleRequestLimit = -1; - private long submitTime; - private long beginTime; - private long endTime; - - /** - * @param url - * @param postProcessor - * @throws IllegalArgumentException if url or postProcessor is null - */ - public URLRetriever(URL url, RetrievalPostProcessor postProcessor) - { - if (url == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.URLIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (postProcessor == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PostProcessorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.url = url; - this.postProcessor = postProcessor; - } - - public final URL getUrl() - { - return url; - } - - public final int getContentLength() - { - return this.contentLength; - } - - protected void setContentLengthRead(int length) - { - this.contentLengthRead.set(length); - } - - public final int getContentLengthRead() - { - return this.contentLengthRead.get(); - } - - public final String getContentType() - { - return this.contentType; - } - - public final ByteBuffer getBuffer() - { - return this.byteBuffer; - } - - public final String getName() - { - return this.url.toString(); - } - - public final String getState() - { - return this.state; - } - - protected final URLConnection getConnection() - { - return this.connection; - } - - public final RetrievalPostProcessor getPostProcessor() - { - return postProcessor; - } - - public final int getConnectTimeout() - { - return connectTimeout; - } - - public int getReadTimeout() - { - return readTimeout; - } - - public void setReadTimeout(int readTimeout) - { - this.readTimeout = readTimeout; - } - - public int getStaleRequestLimit() - { - return staleRequestLimit; - } - - public void setStaleRequestLimit(int staleRequestLimit) - { - this.staleRequestLimit = staleRequestLimit; - } - - public final void setConnectTimeout(int connectTimeout) - { - this.connectTimeout = connectTimeout; - } - - public long getSubmitTime() - { - return submitTime; - } - - public void setSubmitTime(long submitTime) - { - this.submitTime = submitTime; - } - - public long getBeginTime() - { - return beginTime; - } - - public void setBeginTime(long beginTime) - { - this.beginTime = beginTime; - } - - public long getEndTime() - { - return endTime; - } - - public void setEndTime(long endTime) - { - this.endTime = endTime; - } - - public final Retriever call() throws Exception - { - if (this.interrupted()) - return this; - - try - { - this.setState(RETRIEVER_STATE_STARTED); - - if (!this.interrupted()) - { - this.setState(RETRIEVER_STATE_CONNECTING); - this.connection = this.openConnection(); - } - - if (!this.interrupted()) - { - this.setState(RETRIEVER_STATE_READING); - this.byteBuffer = this.read(); - } - - if (!this.interrupted()) - this.setState(RETRIEVER_STATE_SUCCESSFUL); - } - catch (Exception e) - { - this.setState(RETRIEVER_STATE_ERROR); - if (!(e instanceof java.net.SocketTimeoutException)) - { - String message = WorldWind.retrieveErrMsg("URLRetriever.ErrorAttemptingToRetrieve") - + this.url.toString(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - } - throw e; - } - finally - { - this.end(); - } - - return this; - } - - private void setState(String state) - { - String oldState = this.state; - this.state = state; - this.firePropertyChange(AVKey.RETRIEVER_STATE, oldState, this.state); - } - - private boolean interrupted() - { - if (Thread.currentThread().isInterrupted()) - { - this.setState(RETRIEVER_STATE_INTERRUPTED); - String message = WorldWind.retrieveErrMsg("URLRetriever.RetrievalInterruptedFor") + this.url.toString(); - WorldWind.logger().log(java.util.logging.Level.FINER, message); - return true; - } - return false; - } - - private URLConnection openConnection() throws IOException - { - try - { - this.connection = this.url.openConnection(); - } - catch (java.io.IOException e) - { - String message = WorldWind.retrieveErrMsg("URLRetriever.ErrorOpeningConnection") + this.url.toString() - + " " + e.getLocalizedMessage(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - throw e; - } - - if (this.connection == null) // java.net.URL docs imply that this won't happen. We check anyway. - { - String message = WorldWind.retrieveErrMsg("URLRetriever.NullReturnedFromOpenConnection") + this.url; - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - this.connection.setConnectTimeout(this.connectTimeout); - this.connection.setReadTimeout(this.readTimeout); - - return connection; - } - - private void end() throws Exception - { - try - { - if (this.postProcessor != null) - { - this.byteBuffer = this.postProcessor.run(this); - } - } - catch (Exception e) - { - this.setState(RETRIEVER_STATE_ERROR); - String message = WorldWind.retrieveErrMsg("URLRetriever.ErrorPostProcessing") + this.url.toString(); - WorldWind.logger().log(java.util.logging.Level.FINE, message + " " + e.getLocalizedMessage()); - throw e; - } - } - - private ByteBuffer read() throws Exception - { - try - { - ByteBuffer buffer = this.doRead(this.connection); - if (buffer == null) - this.contentLength = 0; - return buffer; - } - catch (Exception e) - { - if (!(e instanceof java.net.SocketTimeoutException)) - { - String message = WorldWind.retrieveErrMsg("URLRetriever.ErrorReadingFromConnection") - + this.url.toString() + e.getLocalizedMessage(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - } - throw e; - } - } - - /** - * @param connection - * @return - * @throws Exception - * @throws IllegalArgumentException if connection is null - */ - protected ByteBuffer doRead(URLConnection connection) throws Exception - { - if (connection == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ConnectionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.contentLength = this.connection.getContentLength(); - - ByteBuffer buffer; - InputStream inputStream = null; - try - { - inputStream = this.connection.getInputStream(); - if (inputStream == null) - { - WorldWind.logger().log(java.util.logging.Level.FINE, WorldWind.retrieveErrMsg( - "URLRetriever.InputStreamFromConnectionNull") + connection.getURL()); - return null; - } - - // TODO: Make decompression of zip file configurable - // TODO: Make this more generally configurable based on content type - // todo: make a zip reader that handles streams of unknown length - // TODO: add a gzip reader - // TODO: this code is checking content type for compression when it should be checking content encoding, - // but the WW servers are sending application/zip as the content type, and null for the content encoding. - this.contentType = connection.getContentType(); - if (this.contentType != null && this.contentType.equalsIgnoreCase("application/zip")) - buffer = this.readZipStream(inputStream, connection); // assume single file in zip and decompress it - else - buffer = this.readNonSpecificStream(inputStream, connection); - - this.contentType = connection.getContentType(); - } - finally - { - if (inputStream != null) - try - { - inputStream.close(); - } - catch (IOException e) - { - WorldWind.logger().log(java.util.logging.Level.FINE, WorldWind.retrieveErrMsg( - "URLRetriever.ExceptionClosingInputStreamToConnection") + connection.getURL()); - } - } - - return buffer; - } - - private ByteBuffer readNonSpecificStream(InputStream inputStream, URLConnection connection) throws IOException - { - if (inputStream == null) - { - String message = WorldWind.retrieveErrMsg("URLRetriever.InputStreamNullFor") + connection.getURL(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.contentLength < 1) - { - return readNonSpecificStreamUnknownLength(inputStream); - } - - ReadableByteChannel channel = Channels.newChannel(inputStream); - ByteBuffer buffer = ByteBuffer.allocate(this.contentLength); - - int numBytesRead = 0; - while (!this.interrupted() && numBytesRead >= 0 && numBytesRead < buffer.limit()) - { - int count = channel.read(buffer); - if (count > 0) - this.contentLengthRead.getAndAdd(numBytesRead += count); - } - - if (buffer != null) - buffer.flip(); - - return buffer; - } - - private ByteBuffer readNonSpecificStreamUnknownLength(InputStream inputStream) throws IOException - { - final int PAGE_SIZE = 4096; - - ReadableByteChannel channel = Channels.newChannel(inputStream); - ByteBuffer buffer = ByteBuffer.allocate(PAGE_SIZE); - - int count = 0; - int numBytesRead = 0; - while (!this.interrupted() && count >= 0) - { - count = channel.read(buffer); - if (count > 0) - this.contentLengthRead.getAndAdd(numBytesRead += count); - - if (count > 0 && !buffer.hasRemaining()) - { - ByteBuffer biggerBuffer = ByteBuffer.allocate(buffer.limit() + PAGE_SIZE); - biggerBuffer.put((ByteBuffer) buffer.rewind()); - buffer = biggerBuffer; - } - } - - if (buffer != null) - buffer.flip(); - - return buffer; - } - - /** - * @param inputStream - * @param connection - * @return - * @throws java.io.IOException - * @throws IllegalArgumentException if inputStream is null - */ - private ByteBuffer readZipStream(InputStream inputStream, URLConnection connection) throws IOException - { - ZipInputStream zis = new ZipInputStream(inputStream); - ZipEntry ze = zis.getNextEntry(); - if (ze == null) - { - WorldWind.logger().log(java.util.logging.Level.FINE, WorldWind.retrieveErrMsg("URLRetriever.NoZipEntryFor") - + connection.getURL()); - return null; - } - - ByteBuffer buffer = null; - if (ze.getSize() > 0) - { - buffer = ByteBuffer.allocate((int) ze.getSize()); - - byte[] inputBuffer = new byte[8192]; - while (buffer.hasRemaining()) - { - int count = zis.read(inputBuffer); - if (count > 0) - { - buffer.put(inputBuffer, 0, count); - this.contentLengthRead.getAndAdd(buffer.position() + 1); - } - } - } - if (buffer != null) - buffer.flip(); - - return buffer; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final URLRetriever that = (URLRetriever) o; - - // Retrievers are considered identical if they are for the same URL. This convention is used by the - // retrieval service to filter out duplicate retreival requests. - return !(url != null ? !url.toString().contentEquals(that.url.toString()) : that.url != null); - } - - @Override - public int hashCode() - { - int result; - result = (url != null ? url.hashCode() : 0); - return result; - } - - @Override - public String toString() - { - return this.getName() != null ? this.getName() : super.toString(); - } -} diff --git a/gov/nasa/worldwind/UserFacingIcon.java b/gov/nasa/worldwind/UserFacingIcon.java deleted file mode 100644 index 03854cc..0000000 --- a/gov/nasa/worldwind/UserFacingIcon.java +++ /dev/null @@ -1,195 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.awt.*; - -/** - * @author tag - * @version $Id$ - */ -public class UserFacingIcon extends AVListImpl implements WWIcon, Movable -{ - // private final String iconPath; - private Position iconPosition; // may be null because placement may be relative - private Dimension iconSize; // may be null to indicate "use native image size" - private boolean isHighlighted = false; - private boolean isVisible = true; - private double highlightScale = 1.2; // TODO: make configurable - private String toolTipText; - private Font toolTipFont; - private boolean showToolTip = false; - private java.awt.Color textColor; - private Object imageSource; - - public UserFacingIcon(String iconPath, Position iconPosition) - { - if (iconPath == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.IconFilePath"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.imageSource = iconPath; - this.iconPosition = iconPosition; - } - - public UserFacingIcon(Object imageSource, Position iconPosition) - { - if (imageSource == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.IconFilePath"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.imageSource = imageSource; - this.iconPosition = iconPosition; - } - - public Object getImageSource() - { - return imageSource; - } - - public void setImageSource(Object imageSource) - { - this.imageSource = imageSource; - } - - public String getPath() - { - return this.imageSource instanceof String ? (String) this.imageSource : null; - } - - public Position getPosition() - { - return this.iconPosition; - } - - public void setPosition(Position iconPosition) - { - this.iconPosition = iconPosition; - } - - public boolean isHighlighted() - { - return isHighlighted; - } - - public void setHighlighted(boolean highlighted) - { - isHighlighted = highlighted; - } - - public double getHighlightScale() - { - return highlightScale; - } - - public void setHighlightScale(double highlightScale) - { - this.highlightScale = highlightScale; - } - - public Dimension getSize() - { - return this.iconSize; - } - - public void setSize(Dimension size) - { - this.iconSize = size; - } - - public boolean isVisible() - { - return isVisible; - } - - public void setVisible(boolean visible) - { - isVisible = visible; - } - - public String getToolTipText() - { - return toolTipText; - } - - public void setToolTipText(String toolTipText) - { - this.toolTipText = toolTipText; - } - - public Font getToolTipFont() - { - return toolTipFont; - } - - public void setToolTipFont(Font toolTipFont) - { - this.toolTipFont = toolTipFont; - } - - public boolean isShowToolTip() - { - return showToolTip; - } - - public void setShowToolTip(boolean showToolTip) - { - this.showToolTip = showToolTip; - } - - public Color getToolTipTextColor() - { - return textColor; - } - - public void setToolTipTextColor(Color textColor) - { - this.textColor = textColor; - } - - public void move(Position position) - { - if (position == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.iconPosition = this.iconPosition.add(position); - } - - public void moveTo(Position position) - { - if (position == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.iconPosition = position; - } - - public Position getReferencePosition() - { - return this.iconPosition; - } - - public String toString() - { - return this.imageSource != null ? this.imageSource.toString() : this.getClass().getName(); - } -} diff --git a/gov/nasa/worldwind/Version.java b/gov/nasa/worldwind/Version.java index 24b6e64..65e28bd 100644 --- a/gov/nasa/worldwind/Version.java +++ b/gov/nasa/worldwind/Version.java @@ -8,14 +8,14 @@ package gov.nasa.worldwind; /** * @author tag - * @version $Id: Version.java 2241 2007-07-09 23:13:33Z tgaskins $ + * @version $Id: Version.java 2981 2007-09-22 01:08:00Z tgaskins $ */ public class Version { private static final String MAJOR_VALUE = "0"; private static final String MINOR_VALUE = "2"; - private static final String DOT_VALUE = "2"; + private static final String DOT_VALUE = "5"; private static final String versionNumber = MAJOR_VALUE + "." + MINOR_VALUE + "." + DOT_VALUE; private static final String versionName = "NASA World Wind Early Access 2"; diff --git a/gov/nasa/worldwind/View.java b/gov/nasa/worldwind/View.java deleted file mode 100644 index 69b308b..0000000 --- a/gov/nasa/worldwind/View.java +++ /dev/null @@ -1,422 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -/** - * The View provides an interface for communicating current viewing state and viewing state chages. For - * example calling {@link #getLatitude} and {@link #setLatitude} will get and set the View latitude coordinate. - *

- * Views contain both fixed state and computed state. The computed state is typically updated during a call - * to the {@link #apply} method. Most accessor methods in this interface return the computed state that was set during - * the most recent call to apply(). - *

- * Implementations may impose constraints on any state variable. Following the above example, simple constraints on View - * latitude coordinates may be queried by calling {@link #normalizeLatitude}. However additional environmental factors - * may constrain View state variables in a manner that cannot be easliy predicted. For this reason, setting a state - * variable does not guarantee the specified state change will occur. When exact knowledge of viewing state is required, - * calling {@link #getLatitude}, immediately after a call to {@link #apply} will return the correct latitude - * coordiante. - *

- * View provides a coordinate transformation from Model coordinates to eye coordinates, - * following the OpenGL convention of a left-handed coordinate system with origin at the eye point and looking down the - * negative Z axis. View also provides a transformation from eye coordinates to screen coordinates, - * following the OpenGL convention of an origin in the lower left hand screen corner. - * - * @author Paul Collins - * @version $Id: View.java 2060 2007-06-14 22:41:20Z dcollins $ - * @see gov.nasa.worldwind.ViewStateIterator - * @see gov.nasa.worldwind.geom.Frustum - */ -public interface View extends WWObject -{ - /** - * Calculates and applies View's internal state to the graphics context in DrawContext. - * All subsequently rendered objects use this new state. Upon return, the OpenGL graphics context reflects the - * values of this view, as do any computed values of the view, such as the model-view matrix, projection matrix and - * Frustum. - * - * @param dc the current World Wind drawing context on which View's state will apply. - * @throws IllegalArgumentException if dc is null, or if the Globe or GL - * instances in dc are null. - */ - void apply(DrawContext dc); - - /** - * Gets the 'model-view' matrix computed in apply(), which transforms model coordinates to eye - * coordinates (where the eye is located at the origin, facing down the negative-z axis). This matrix is constructed - * using the model space translation and orientation specific to each implementation of View. - * - * @return the current model-view matrix. - */ - Matrix getModelViewMatrix(); - - /** - * Gets the 'projection' matrix computed in apply(), which transforms eye coordinates to screen - * coordinates. This matrix is constructed using the projection parameters specific to each implementation of - * View (e.g. field-of-view). The {@link #getFrustum} method returns the geometry corresponding to this - * matrix. - * - * @return the current projection matrix. - */ - Matrix getProjectionMatrix(); - - /** - * Gets a Rectangle representing the window bounds (x, y, width, height) of the viewport, computed in - * apply(). Implementations of View will configure themselves to render in this viewport. - * - * @return the current window bounds of the viewport. - */ - java.awt.Rectangle getViewport(); - - /** - * Gets the viewing Frustum in eye coordinates, computed in apply(). The - * Frustum is the portion of viewable space defined by three sets of parallel 'clipping' planes. The - * method {@link #getFrustumInModelCoordinates} maintains the shape of this Frustum, but it has been - * translated and aligned with the eye in model space. - * - * @return the current viewing frustum in eye coordinates. - */ - Frustum getFrustum(); - - /** - * Gets the viewing Frustum transformed to model coordinates. Model coordinate frustums are useful for - * performing visibility tests against world geometry. - * - * @return the current viewing frustum in model coordinates. - */ - Frustum getFrustumInModelCoordinates(); - - /** - * Gets the horizontal field-of-view angle (the angle of visibility) associated with this View, or null - * if the View implementation does not support a field-of-view. - * - * @return horizontal field-of-view angle, or null if none exists. - */ - Angle getFieldOfView(); - - /** - * Sets the horiziontal field-of-view angle (the angle of visibillity) associated with this View. This - * call may be ignored by implementations that do not support a field-of-view. - * - * @param newFov the new horizontal field-of-view angle. - * @throws IllegalArgumentException if newFov is null. - */ - void setFieldOfView(Angle newFov); - - /** - * Defines and applies a new model-view matrix in which the world origin is located at referenceCenter. - * Geometry rendered after a call to pushReferenceCenter should be transformed with respect to - * referenceCenter, rather than the canonical origin (0, 0, 0). Calls to - * pushReferenceCenter must be followed by {@link #popReferenceCenter} after rendering is complete. - * Note that calls to {@link #getModelViewMatrix} will not return reference-center model-view matrix, but the - * original matrix. - * - * @param dc the current World Wind drawing context on which new model-view state will be applied. - * @param referenceCenter the location to become the new world origin. - * @return a new model-view matrix with origin is at referenceCenter, or null if this method failed. - * @throws IllegalArgumentException if referenceCenter is null, if dc is null, or if the - * Globe or GL instances in dc are null. - */ - Matrix pushReferenceCenter(DrawContext dc, Vec4 referenceCenter); - - /** - * Removes the model-view matrix on top of the matrix stack, and restores the original matrix. - * - * @param dc the current World Wind drawing context on which the original matrix will be restored. - * @throws IllegalArgumentException if dc is null, or if the Globe or GL - * instances in dc are null. - */ - void popReferenceCenter(DrawContext dc); - - /** - * Gets the View eye position in model coordinates. - * - * @return the eye position in model coordinates. - */ - Vec4 getEyePoint(); - - /** - * Gets the View y-axis orientation in model coordinates. - * - * @return the y-axis vector in model coordinates. - */ - Vec4 getUpVector(); - - /** - * Gets the View z-axis orientation in model coordinates. - * - * @return the z-axis vector in model coordinates. - */ - Vec4 getForwardVector(); - - /** - * Gets the View latitude position. - * - * @return the current latitude positon. - */ - Angle getLatitude(); - - /** - * Sets the View eye point to the new latitude coordinate. - * - * @param newLatitude the new latitude position. - * @throws IllegalArgumentException if newLatitude is null. - */ - void setLatitude(Angle newLatitude); - - /** - * Gets the View longitude position. - * - * @return the current longitude positon. - */ - Angle getLongitude(); - - /** - * Sets the View eye point to the new longitude coordinate. - * - * @param newLongitude the new longitude position. - * @throws IllegalArgumentException if newLongitude is null. - */ - void setLongitude(Angle newLongitude); - - /** - * Gets the View eye altitude above the analytical globe radius. - * - * @return the View's altitude above the globe radius. - */ - double getAltitude(); - - /** - * Sets the View eye point to the new altitude above the analytical globe radius. - * - * @param newAltitude the new eye altitude above the globe radius. - */ - void setAltitude(double newAltitude); - - /** - * Sets the View eye point to the new (latitude, longitude) coordinate. This has the effect of calling - * {@link #setLatitude} and {@link #setLongitude}. - * - * @param newLatLon the latitude and longitude coordinate of the eye point. - */ - void setLatLon(LatLon newLatLon); - -// /** -// * Gets the geographic (latitude, longitude, elevation) coordinate of the View's eye point. -// * -// * @return the latitude and longitude coordinates of the eye point. -// */ -// Position getLatLonAltitude(); - - /** - * Sets the View eye point to the new (latitude, longitude, elevation) coordinate. This has the effect - * of calling {@link #setLatitude}, {@link #setLongitude} and {@link #setAltitude}. - * - * @param newPosition the latitude, longitude and elevation coordinate of the eye point. - */ - void setLatLonAltitude(Position newPosition); - - /** - * Gets the View's angle from true North. - * - * @return the angle from true North. - */ - Angle getHeading(); - - /** - * Sets the View's angle to true North. - * - * @param newHeading the new angle to true North. - * @throws IllegalArgumentException if newHeading is null. - */ - void setHeading(Angle newHeading); - - /** - * Gets the View's angle from the plane tangent to the surface. - * - * @return the angle from the surface tangent plane. - */ - Angle getPitch(); - - /** - * Sets the View's angle to the plane tangent to the surface. - * - * @param newPitch the new angle to the surface tangent plane. - * @throws IllegalArgumentException if newPitch is null. - */ - void setPitch(Angle newPitch); - - /** - * Gets the View's angle about its local z-axis. - * - * @return the angle about the local z-axis. - */ - Angle getRoll(); - - /** - * Sets the View's angle about its local z-axis. - * - * @param newRoll the new angle about the local z-axis. - * @throws IllegalArgumentException if newRoll is null. - */ - void setRoll(Angle newRoll); - - /** - * Gets the View's translation in its forward direction. - * - * @return translation along the forward direction. - */ - double getZoom(); - - /** - * Sets the View's translation in its forward direction. - * - * @param newZoom translation along the forward direction. - */ - void setZoom(double newZoom); - - /** - * Normalizes latitude coordinates to values acceptable to this View implementation. - * - * @param latitude the latitude to normalize. - * @return the (possibly) normalized latitude. - */ - Angle normalizeLatitude(Angle latitude); - - /** - * Normalizes longitude coordinates to values acceptable to this View implementation. - * - * @param longitude the longitude to normalize. - * @return the (possibly) normalized longitude. - */ - Angle normalizeLongitude(Angle longitude); - - /** - * Normalizes altitude coordinates to values acceptable to this View implementation. - * - * @param altitude the altitude to normalize. - * @return the (possibly) normalized altitude. - */ - double normalizeAltitude(double altitude); - - /** - * Normalizes heading coordinates to values acceptable to this View implementation. - * - * @param heading the altitude to normalize. - * @return the (possibly) normalized heading. - */ - Angle normalizeHeading(Angle heading); - - /** - * Normalizes pitch coordinates to values acceptable to this View implementation. - * - * @param pitch the altitude to normalize. - * @return the (possibly) normalized pitch. - */ - Angle normalizePitch(Angle pitch); - - /** - * Normalizes roll coordinates to values acceptable to this View implementation. - * - * @param roll the altitude to normalize. - * @return the (possibly) normalized roll. - */ - Angle normalizeRoll(Angle roll); - - /** - * Normalizes zoom coordinates to values acceptable to this View implementation. - * - * @param zoom the altitude to normalize. - * @return the (possibly) normalized zoom. - */ - double normalizeZoom(double zoom); - - /** - * Iterates over View state changes in ViewStateIterator and applies them to the - * View. The View will automatically refresh and request state from - * viewStateIterator until the iteration is complete, or View has been stopped by invoking - * {@link #stopIterating}. - * - * @param viewStateIterator the ViewStateIterator to iterate over. - */ - void iterateOver(ViewStateIterator viewStateIterator); - - /** - * Returns true when View is actively iterating over an instance of ViewStateIterator. - * - * @return true when iterating over ViewStateIterator; false otherwise. - */ - boolean isIterating(); - - /** - * Immediately stops all active iteration over ViewStateIterator. - */ - void stopIterating(); - - /** - * Computes a line, in model coordinates, originating from the eye point, and passing throught the point contained - * by (x, y) on the View's projection plane (or after projection into model space). - * - * @param x the horizontal coordinate originating from the left side of View's projection plane. - * @param y the vertical coordinate originating from the top of View's projection plane. - * @return a line beginning at the View's eye point and passing throught (x, y) transformed into model - * space. - */ - Line computeRayFromScreenPoint(double x, double y); - - /** - * Computes the intersection of a line originating from the eye point (passing throught (x, y)) with the last - * rendered SectorGeometry, or the last analytical Globe if no rendered geometry exists. - * - * @param x the horizontal coordinate originating from the left side of View's projection plane. - * @param y the vertical coordinate originating from the top of View's projection plane. - * @return the point on the surface in polar coordiantes. - */ - Position computePositionFromScreenPoint(double x, double y); - - /** - * Computes the screen-aligned dimension (in meters) that a screen pixel would cover at a given distance (also in - * meters). This computation assumes that pixels dimensions are square, and therefore returns a single dimension. - * - * @param distance the distance from the eye point, in eye coordinates, along the z-axis. This value must be - * positive but is otherwise unbounded. - * @return the dimension of a pixel (in meters) at the given distance. - * @throws IllegalArgumentException if distance is negative. - */ - double computePixelSizeAtDistance(double distance); - - /** - * Gets the distance from the View's eye point to the horizon point on the last rendered - * Globe. - * - * @return the distance from the eye point to the horizon (in meters). - */ - double computeHorizonDistance(); - - /** - * Maps a Point in model (cartesian) coordinates to a Point in screen coordinates. The - * returned x and y are relative to the lower left hand screen corner, while z is the screen depth-coordinate. If - * the model point cannot be sucessfully mapped, this will return null. - * - * @param modelPoint the model coordinate Point to project. - * @return the mapped screen coordinate Point. - * @throws IllegalArgumentException if modelPoint is null. - */ - Vec4 project(Vec4 modelPoint); - - /** - * Maps a Point in screen coordinates to a Point in model coordinates. The input x and y - * are relative to the lower left hand screen corner, while z is the screen depth-coordinate. If the screen point - * cannot be sucessfully mapped, this will return null. - * - * @param windowPoint the window coordinate Point to project. - * @return the mapped screen coordinate Point. - * @throws IllegalArgumentException if windowPoint is null. - */ - Vec4 unProject(Vec4 windowPoint); -} diff --git a/gov/nasa/worldwind/WWDuplicateRequestException.java b/gov/nasa/worldwind/WWDuplicateRequestException.java deleted file mode 100644 index 23dd840..0000000 --- a/gov/nasa/worldwind/WWDuplicateRequestException.java +++ /dev/null @@ -1,19 +0,0 @@ -/* -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; - -/** - * @author tag - * @version $Id: WWDuplicateRequestException.java 1718 2007-05-05 00:51:15Z tgaskins $ - */ -public class WWDuplicateRequestException extends WWRuntimeException -{ - public WWDuplicateRequestException(String s) - { - super(s); - } -} diff --git a/gov/nasa/worldwind/WWIO.java b/gov/nasa/worldwind/WWIO.java deleted file mode 100644 index 33bc6df..0000000 --- a/gov/nasa/worldwind/WWIO.java +++ /dev/null @@ -1,357 +0,0 @@ -/* -Copyright (C) 2001, 2006 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Tom Gaskins - * @version $Id: WWIO.java 1869 2007-05-23 22:18:47Z tgaskins $ - */ -package gov.nasa.worldwind; - -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import java.io.*; -import java.util.zip.*; - -public class WWIO -{ - public static boolean saveBuffer(ByteBuffer buffer, File file) throws IOException - { - if (buffer == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.BufferNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (file == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - FileOutputStream fos = null; - FileChannel channel = null; - FileLock lock; - int numBytesWritten = 0; - try - { - fos = new FileOutputStream(file); - channel = fos.getChannel(); - lock = channel.tryLock(); - if (lock == null) - { - // The file is being written to, or some other process is keeping it to itself. - // This is an okay condition, but worth noting. - String message = WorldWind.retrieveErrMsg("WWIO.UnableToAcquireLockFor") + file.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINER, message); - return false; - } - - for (buffer.rewind(); buffer.hasRemaining();) - { - numBytesWritten += channel.write(buffer); - } - - return true; - } - catch (IOException e) - { - String message = WorldWind.retrieveErrMsg("WWIO.ErrorSavingBufferTo") + file.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, message, e); - - if (numBytesWritten > 0) // don't leave behind incomplete files - file.delete(); - - throw e; - } - finally - { - try - { - if (channel != null) - channel.close(); // also releases the lock - else if (fos != null) - fos.close(); - } - catch (java.io.IOException e) - { - String message = WorldWind.retrieveErrMsg("WWIO.ErrorTryingToClose") + file.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - } - } - } - - public static MappedByteBuffer mapFile(File file) throws IOException - { - if (file == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - FileInputStream is = new FileInputStream(file); - try - { - return is.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()); - } - finally - { - is.close(); - } - } - - public static ByteBuffer readURLContentToBuffer(URL url) throws IOException - { - if (url == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.URLIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - InputStream is = url.openStream(); - return readStreamToBuffer(is); -// ByteBuffer buffer; -// try -// { -// URLConnection connection = url.openConnection(); -// int size = connection.getContentLength(); -// buffer = ByteBuffer.allocateDirect(size); -// byte inputBuffer[] = new byte[size]; -// int n; -// do -// { -// n = is.read(inputBuffer); -// if (n > 0) -// buffer.put(inputBuffer, 0, n); -// } while (buffer.hasRemaining() && n >= 0); -// buffer.flip(); -// buffer.rewind(); -// } -// finally -// { -// if (is != null) -// { -// is.close(); -// } -// } -// -// return buffer; - } - - public static ByteBuffer readFileToBuffer(File file) throws IOException - { - if (file == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - FileInputStream is = new FileInputStream(file); - try - { - FileChannel fc = is.getChannel(); - ByteBuffer buffer = ByteBuffer.allocate((int) fc.size()); - for (int count = 0; count >= 0 && buffer.hasRemaining();) - { - count = fc.read(buffer); - } - buffer.flip(); - return buffer; - } - finally - { - is.close(); - } - } - - public static ByteBuffer readZipEntryToBuffer(File zipFile, String entryName) throws IOException - { - if (zipFile == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - InputStream is = null; - ZipEntry ze; - try - { - ZipFile zf = new ZipFile(zipFile); - if (zf.size() < 1) - { - String message = WorldWind.retrieveErrMsg("WWIO.ZipFileIsEmpty") + zipFile.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new java.io.IOException(message); - } - - if (entryName != null) - { // Read the specified entry - ze = zf.getEntry(entryName); - if (ze == null) - { - String message = WorldWind.retrieveErrMsg("WWIO.ZipFileEntryNIF") + entryName - + WorldWind.retrieveErrMsg("punctuation.space") + zipFile.getPath(); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IOException(message); - } - } - else - { // Read the first entry - ze = zf.entries().nextElement(); // get the first entry - } - - is = zf.getInputStream(ze); - ByteBuffer buffer = null; - if (ze.getSize() > 0) - { - buffer = transferStreamToByteBuffer(is, (int) ze.getSize()); - buffer.flip(); - } - return buffer; - } - finally - { - if (is != null) - is.close(); - } - } - - private static ByteBuffer transferStreamToByteBuffer(InputStream stream, int numBytes) throws IOException - { - if (stream == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.InputStreamIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (numBytes < 1) - { - String message = WorldWind.retrieveErrMsg("WWIO.NumberBytesTransferLessThanOne"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - int bytesRead = 0; - int count = 0; - byte[] bytes = new byte[numBytes]; - while (count >= 0 && (numBytes - bytesRead) > 0) - { - count = stream.read(bytes, bytesRead, numBytes - bytesRead); - if (count > 0) - { - bytesRead += count; - } - } - return ByteBuffer.wrap(bytes); - } - - public static ByteBuffer readStreamToBuffer(InputStream inputStream) throws IOException - { - final int PAGE_SIZE = 8192; - - ReadableByteChannel channel = Channels.newChannel(inputStream); - ByteBuffer buffer = ByteBuffer.allocate(PAGE_SIZE); - - int count = 0; - while (count >= 0) - { - count = channel.read(buffer); - if (count > 0 && !buffer.hasRemaining()) - { - ByteBuffer biggerBuffer = ByteBuffer.allocate(buffer.limit() + PAGE_SIZE); - biggerBuffer.put((ByteBuffer) buffer.rewind()); - buffer = biggerBuffer; - } - } - - if (buffer != null) - buffer.flip(); - - return buffer; - } - - public static String replaceSuffix(String in, String newSuffix) - { - if (in == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.InputFileNameIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return in.substring(0, in.lastIndexOf(".")) + (newSuffix != null ? newSuffix : ""); - } - - public static File saveBufferToTempFile(ByteBuffer buffer, String suffix) throws IOException - { - if (buffer == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.ByteBufferIsNull"); - gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - File outputFile = java.io.File.createTempFile("WorldWind", suffix != null ? suffix : ""); - outputFile.deleteOnExit(); - buffer.rewind(); - WWIO.saveBuffer(buffer, outputFile); - - return outputFile; - } - - public static String getSuffixForMimeType(String mimeType) - { - if (mimeType == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.MimeTypeIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (mimeType.equalsIgnoreCase("image/jpeg") || mimeType.equalsIgnoreCase("image/jpg")) - return ".jpg"; - if (mimeType.equalsIgnoreCase("image/png")) - return ".png"; - - return null; - } - - public static boolean isFileOutOfDate(URL url, long expiryTime) - { - if (url == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.URLIsNull"); - gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - try - { - // Determine whether the file can be treated like a File, e.g., a jar entry. - URI uri = url.toURI(); - if (uri.isOpaque()) - return false; // TODO: Determine how to check the date of non-Files - - File file = new File(uri); - - return file.exists() && file.lastModified() < expiryTime; - } - catch (URISyntaxException e) - { - String message = WorldWind.retrieveErrMsg("WWIO.ExceptionValidatingFileExpiration"); - WorldWind.logger().log(java.util.logging.Level.FINE, message + url); - return false; - } - } -} diff --git a/gov/nasa/worldwind/WWIcon.java b/gov/nasa/worldwind/WWIcon.java deleted file mode 100644 index 7e50513..0000000 --- a/gov/nasa/worldwind/WWIcon.java +++ /dev/null @@ -1,59 +0,0 @@ -/* -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; - -import gov.nasa.worldwind.geom.*; - -import java.awt.*; -import java.awt.Color; - -/** - * @author tag - * @version $Id$ - */ -public interface WWIcon // extends gov.nasa.worldwind.AVList -{ - void setImageSource(Object imageSource); - - Object getImageSource(); - - Position getPosition(); - - void setPosition(Position iconPosition); - - boolean isHighlighted(); - - void setHighlighted(boolean highlighted); - - Dimension getSize(); - - void setSize(Dimension size); - - boolean isVisible(); - - void setVisible(boolean visible); - - double getHighlightScale(); - - void setHighlightScale(double highlightScale); - - String getToolTipText(); - - void setToolTipText(String toolTipText); - - Font getToolTipFont(); - - void setToolTipFont(Font toolTipFont); - - boolean isShowToolTip(); - - void setShowToolTip(boolean showToolTip); - - Color getToolTipTextColor(); - - void setToolTipTextColor(Color textColor); -} diff --git a/gov/nasa/worldwind/WWRuntimeException.java b/gov/nasa/worldwind/WWRuntimeException.java deleted file mode 100644 index 23da9e7..0000000 --- a/gov/nasa/worldwind/WWRuntimeException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* -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; - -/** - * @author Tom Gaskins - * @version $Id: WWRuntimeException.java 1718 2007-05-05 00:51:15Z tgaskins $ - */ -public class WWRuntimeException extends RuntimeException -{ - public WWRuntimeException() - { - } - - public WWRuntimeException(String s) - { - super(s); - } - - public WWRuntimeException(String s, Throwable throwable) - { - super(s, throwable); - } - - public WWRuntimeException(Throwable throwable) - { - super(throwable); - } -} diff --git a/gov/nasa/worldwind/WorldWindowGLAutoDrawable.java b/gov/nasa/worldwind/WorldWindowGLAutoDrawable.java index 6829f0a..87fc633 100644 --- a/gov/nasa/worldwind/WorldWindowGLAutoDrawable.java +++ b/gov/nasa/worldwind/WorldWindowGLAutoDrawable.java @@ -9,6 +9,7 @@ package gov.nasa.worldwind; import gov.nasa.worldwind.cache.TextureCache; import gov.nasa.worldwind.event.*; import gov.nasa.worldwind.geom.Position; +import gov.nasa.worldwind.layers.Layer; import gov.nasa.worldwind.pick.PickedObject; import gov.nasa.worldwind.util.*; @@ -21,7 +22,7 @@ import java.util.logging.Level; * provide the core functionality of World Wind. * * @author Tom Gaskins - * @version $Id: WorldWindowGLAutoDrawable.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: WorldWindowGLAutoDrawable.java 2980 2007-09-22 01:07:06Z tgaskins $ */ public class WorldWindowGLAutoDrawable extends WorldWindowImpl implements WorldWindowGLDrawable, GLEventListener { @@ -86,7 +87,18 @@ public class WorldWindowGLAutoDrawable extends WorldWindowImpl implements WorldW */ public void init(GLAutoDrawable glAutoDrawable) { - // This GLEventListener callback method is not used. + // Clear the texture cache if the window is reinitializing, most likely with a new gl hardware context. + if (this.getTextureCache() != null) + this.getTextureCache().clear(); + + if (this.getModel() != null && this.getModel().getLayers() != null) + { + for (Layer layer : this.getModel().getLayers()) + { + layer.dispose(); + } + } + // this.drawable.setGL(new DebugGL(this.drawable.getGL())); } @@ -212,5 +224,4 @@ public class WorldWindowGLAutoDrawable extends WorldWindowImpl implements WorldW if (this.drawable != null) this.drawable.display(); } - } diff --git a/gov/nasa/worldwind/avlist/AVKey.java b/gov/nasa/worldwind/avlist/AVKey.java index 981c62d..50ba938 100644 --- a/gov/nasa/worldwind/avlist/AVKey.java +++ b/gov/nasa/worldwind/avlist/AVKey.java @@ -8,10 +8,12 @@ package gov.nasa.worldwind.avlist; /** * @author Tom Gaskins - * @version $Id: AVKey.java 2593 2007-08-18 00:03:31Z tgaskins $ + * @version $Id: AVKey.java 2915 2007-09-19 06:01:49Z tgaskins $ */ public interface AVKey // TODO: Eliminate unused constants, if any { + final String BMNG_ONE_IMAGE_PATH = "gov.nasa.worldwind.avkey.BMNGOneImagePath"; + final String DATA_CACHE_NAME = "gov.nasa.worldwind.avkey.DataCacheNameKey"; final String DATA_FILE_CACHE_CLASS_NAME = "gov.nasa.worldwind.avkey.DataFileCacheClassName"; final String DATA_FILE_CACHE_CONFIGURATION_FILE_NAME = @@ -32,6 +34,7 @@ public interface AVKey // TODO: Eliminate unused constants, if any final String GLOBE_CLASS_NAME = "gov.nasa.worldwind.avkey.GlobeClassName"; final String IMAGE_FORMAT = "gov.nasa.worldwind.avkey.ImageFormat"; + final String INACTIVE_LEVELS = "gov.nasa.worldwind.avkey.InactiveLevels"; final String INITIAL_ALTITUDE = "gov.nasa.worldwind.avkey.InitialAltitude"; final String INITIAL_HEADING = "gov.nasa.worldwind.avkey.InitialHeading"; final String INITIAL_LATITUDE = "gov.nasa.worldwind.avkey.InitialLatitude"; @@ -86,9 +89,9 @@ public interface AVKey // TODO: Eliminate unused constants, if any final String TASK_SERVICE_CLASS_NAME = "gov.nasa.worldwind.avkey.TaskServiceClassName"; final String TILE_DELTA = "gov.nasa.worldwind.avkey.TileDeltaKey"; final String TILE_HEIGHT = "gov.nasa.worldwind.avkey.TileHeightKey"; + final String TILE_RETRIEVER = "gov.nasa.worldwind.avkey.TileRetriever"; final String TILE_URL_BUILDER = "gov.nasa.worldwind.avkey.TileURLBuilder"; final String TILE_WIDTH = "gov.nasa.worldwind.avkey.TileWidthKey"; - final String TILE_RETRIEVER = "gov.nasa.worldwind.avkey.TileRetriever"; final String URL_CONNECT_TIMEOUT = "gov.nasa.worldwind.avkey.URLConnectTimeout"; final String URL_READ_TIMEOUT = "gov.nasa.worldwind.avkey.URLReadTimeout"; diff --git a/gov/nasa/worldwind/awt/InterpolatorTimer.java b/gov/nasa/worldwind/awt/InterpolatorTimer.java deleted file mode 100644 index 4b4a546..0000000 --- a/gov/nasa/worldwind/awt/InterpolatorTimer.java +++ /dev/null @@ -1,303 +0,0 @@ -/* -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.awt; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.geom.*; - -/** - * @author dcollins - * @version $Id: InterpolatorTimer.java 1818 2007-05-10 15:59:46Z dcollins $ - */ -class InterpolatorTimer -{ - static class ViewProperties - { - public LatLon latLon; - public Angle heading; - public Angle pitch; - public Double zoom; - } - - private java.util.TimerTask timerTask; - private volatile boolean isRunning; - private java.beans.PropertyChangeListener listener; - private double stepCoefficient; - private double errorThreshold; - private Object begin; - private Object end; - - public InterpolatorTimer(final int period) - { - if (period < 0) - { - String message = WorldWind.retrieveErrMsg("awt.InterpolatorTimer.PeriodLessThanZero"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - java.util.Timer timer = new java.util.Timer(); - this.timerTask = new java.util.TimerTask() - { - public void run() - { - long time = System.currentTimeMillis(); - if (time - this.scheduledExecutionTime() >= 2 * period) - return; - if (InterpolatorTimer.this.listener == null) - return; - InterpolatorTimer.this.updateAndNotify(InterpolatorTimer.this.listener); - } - }; - timer.schedule(timerTask, 0, period); - } - - public synchronized boolean isRunning() - { - return this.isRunning; - } - - private static double error(Object x, Object end) - { - if (x instanceof Angle) - return error((Angle) x, (Angle) end); - else if (x instanceof Double) - return error((Double) x, (Double) end); - else if (x instanceof LatLon) - return error((LatLon) x, (LatLon) end); - else if (x instanceof Point) - return error((Point) x, (Point) end); - else if (x instanceof ViewProperties) - return error((ViewProperties) x, (ViewProperties) end); - else - return 0; - } - - private static double error(Double x, Double end) - { - return Math.abs(end - x); - } - - private static double error(Angle x, Angle end) - { - return Math.abs(end.getDegrees() - x.getDegrees()) % 360d; - } - - private static double error(LatLon x, LatLon end) - { - double latError = Math.abs(end.getLatitude().getRadians() - x.getLatitude().getRadians()) % (Math.PI / 2); - double lonError = Math.abs(end.getLongitude().getRadians() - x.getLongitude().getRadians()) % Math.PI; - return latError > lonError ? latError : lonError; - } - - private static double error(Point x, Point end) - { - double maxError = 0; - maxError = Math.max(maxError, error(x.x(), end.x())); - maxError = Math.max(maxError, error(x.y(), end.y())); - maxError = Math.max(maxError, error(x.z(), end.z())); - maxError = Math.max(maxError, error(x.w(), end.w())); - return maxError; - } - - private static double error(ViewProperties x, ViewProperties end) - { - double maxError = 0; - if (x.latLon != null && end.latLon != null) - maxError = Math.max(maxError, error(x.latLon, end.latLon)); - if (x.heading != null && end.heading != null) - maxError = Math.max(maxError, error(x.heading, end.heading)); - if (x.pitch != null && end.pitch != null) - maxError = Math.max(maxError, error(x.pitch, end.pitch)); - if (x.zoom != null && end.zoom != null) - maxError = Math.max(maxError, error(x.zoom, end.zoom)); - return maxError; - } - - private static Object mix(double t, Object begin, Object end) - { - if (begin instanceof Angle) - return mix(t, (Angle) begin, (Angle) end); - else if (begin instanceof Double) - return mix(t, (Double) begin, (Double) end); - else if (begin instanceof LatLon) - return mix(t, (LatLon) begin, (LatLon) end); - else if (begin instanceof Point) - return mix(t, (Point) begin, (Point) end); - else if (begin instanceof ViewProperties) - return mix(t, (ViewProperties) begin, (ViewProperties) end); - else - return null; - } - - private static Angle mix(double t, Angle begin, Angle end) - { - if (t < 0) - return begin; - else if (t > 1) - return end; - Quaternion beginQuat = Quaternion.EulerToQuaternion(begin.getRadians(), 0, 0); - Quaternion endQuat = Quaternion.EulerToQuaternion(end.getRadians(), 0, 0); - Quaternion q = Quaternion.Slerp(beginQuat, endQuat, t); - Point v = Quaternion.QuaternionToEuler(q); - - if (Double.isNaN(v.x())) - return null; - - return Angle.fromRadians(v.x()); - } - - private static Double mix(double t, Double begin, Double end) - { - if (t < 0) - return begin; - else if (t > 1) - return end; - return (1 - t) * begin + t * end; - } - - private static LatLon mix(double t, LatLon begin, LatLon end) - { - if (t < 0) - return begin; - else if (t > 1) - return end; - Quaternion beginQuat = Quaternion.EulerToQuaternion(begin.getLongitude().getRadians(), - begin.getLatitude().getRadians(), 0); - Quaternion endQuat = Quaternion.EulerToQuaternion(end.getLongitude().getRadians(), - end.getLatitude().getRadians(), 0); - Quaternion q = Quaternion.Slerp(beginQuat, endQuat, t); - Point v = Quaternion.QuaternionToEuler(q); - if (Double.isNaN(v.x()) || Double.isNaN(v.y())) - return null; - return LatLon.fromRadians(v.y(), v.x()); - } - - private static Point mix(double t, Point begin, Point end) - { - return new Point(mix(t, begin.x(), end.x()), mix(t, begin.y(), end.y()), - mix(t, begin.z(), end.z()), mix(t, begin.w(), end.w())); - } - - private static ViewProperties mix(double t, ViewProperties begin, ViewProperties end) - { - ViewProperties x = new ViewProperties(); - if (begin.latLon != null && end.latLon != null) - x.latLon = mix(t, begin.latLon, end.latLon); - if (begin.heading != null && end.heading != null) - { - if (begin.pitch != null && end.pitch != null) - { - // TODO: this doesn't pan heading & pitch equally - Quaternion beginQuat = Quaternion.EulerToQuaternion(begin.heading.getRadians(), - begin.pitch.getRadians(), 0); - Quaternion endQuat = Quaternion.EulerToQuaternion(end.heading.getRadians(), - end.pitch.getRadians(), 0); - Quaternion q = Quaternion.Slerp(beginQuat, endQuat, t); - Point v = Quaternion.QuaternionToEuler(q); - if (!Double.isNaN(v.x()) && !Double.isNaN(v.y())) - { - x.heading = Angle.fromRadians(v.x()); - x.pitch = Angle.fromRadians(v.y()); - } - else - { - x.heading = null; - x.pitch = null; - } - } - else - { - x.heading = mix(t, begin.heading, end.heading); - } - } - else if (begin.pitch != null && end.pitch != null) - x.pitch = mix(t, begin.pitch, end.pitch); - if (begin.zoom != null && end.zoom != null) - x.zoom = mix(t, begin.zoom, end.zoom); - return x; - } - - public synchronized void start(double stepCoefficient, double errorThreshold, Object begin, Object end, - java.beans.PropertyChangeListener listener) - { - if (stepCoefficient < 0) - { - String message = WorldWind.retrieveErrMsg("awt.InterpolatorTimer.StepCoefficientLessThanZero"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (errorThreshold < 0) - { - String message = WorldWind.retrieveErrMsg("awt.InterpolatorTimer.ErrorThresholdLessThanZero"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (begin == null || end == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.ObjectIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (!end.getClass().isInstance(begin)) - { - String message = WorldWind.retrieveErrMsg("awt.InterpolatorTimer.DifferentMixTypes"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (listener == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.ListenerIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.isRunning && this.listener != null && !this.listener.equals(listener)) - this.listener.propertyChange(new java.beans.PropertyChangeEvent(this, null, null, null)); - - this.listener = listener; - this.stepCoefficient = stepCoefficient; - this.errorThreshold = errorThreshold; - this.begin = begin; - this.end = end; - this.isRunning = true; - } - - public synchronized void stop() - { - if (this.isRunning) - { - if (this.listener != null) - listener.propertyChange(new java.beans.PropertyChangeEvent(this, null, null, null)); - this.listener = null; - this.stepCoefficient = errorThreshold = -1; - this.begin = end = null; - this.isRunning = false; - } - } - - private synchronized void updateAndNotify(java.beans.PropertyChangeListener listener) - { - if (!this.isRunning || this.begin == null || listener == null) - return; - - Object newValue = mix(this.stepCoefficient, this.begin, this.end); - if (newValue == null) - { - this.stop(); - return; - } - - double error = error(newValue, this.end); - if (error < this.errorThreshold) - { - this.stop(); - return; - } - - listener.propertyChange(new java.beans.PropertyChangeEvent(this, null, this.begin, newValue)); - this.begin = newValue; - } -} diff --git a/gov/nasa/worldwind/examples/ApplicationTemplate.java b/gov/nasa/worldwind/examples/ApplicationTemplate.java index c8ad41b..111c484 100644 --- a/gov/nasa/worldwind/examples/ApplicationTemplate.java +++ b/gov/nasa/worldwind/examples/ApplicationTemplate.java @@ -20,14 +20,41 @@ import java.awt.*; * Provides a base application framework for simple WorldWind examples. Although this class will run stand-alone, it is * not meant to be used that way. But it has a main method to show how a derived class would call it. * - * @version $Id: ApplicationTemplate.java 2532 2007-08-13 05:08:11Z tgaskins $ + * @version $Id: ApplicationTemplate.java 2979 2007-09-22 01:05:19Z tgaskins $ */ public class ApplicationTemplate { + public static class AppPanel extends JPanel + { + protected WorldWindowGLCanvas wwd; + protected StatusBar statusBar; + + public AppPanel(Dimension canvasSize, boolean includeStatusBar) + { + super(new BorderLayout()); + + this.wwd = new WorldWindowGLCanvas(); + this.wwd.setPreferredSize(canvasSize); + + // Create the default model as described in the current worldwind properties. + Model m = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME); + this.wwd.setModel(m); + + this.add(this.wwd, BorderLayout.CENTER); + if (includeStatusBar) + { + this.statusBar = new StatusBar(); + this.add(statusBar, BorderLayout.PAGE_END); + this.statusBar.setEventSource(wwd); + } + } + } + protected static class AppFrame extends JFrame { private Dimension canvasSize = new Dimension(800, 600); + protected AppPanel wwjPanel; protected WorldWindowGLCanvas wwd; protected StatusBar statusBar; protected LayerPanel layerPanel; @@ -46,24 +73,13 @@ public class ApplicationTemplate private void initialize(boolean includeStatusBar, boolean includeLayerPanel, boolean includeStatsPanel) { // Create the WorldWindow. - wwd = new WorldWindowGLCanvas(); - wwd.setPreferredSize(canvasSize); - - // Create the default model as described in the current worldwind properties. - Model m = (Model) WorldWind.createConfigurationComponent(AVKey.MODEL_CLASS_NAME); - wwd.setModel(m); - - // Create a container to hold the world window with the status bar centered below it. - JPanel mainPanel = new JPanel(new BorderLayout()); - mainPanel.add(wwd, BorderLayout.CENTER); - if (includeStatusBar) - { - this.statusBar = new StatusBar(); - mainPanel.add(statusBar, BorderLayout.PAGE_END); - } + this.wwjPanel = new AppPanel(this.canvasSize, includeStatusBar); + this.wwjPanel.setPreferredSize(canvasSize); + this.wwd = this.wwjPanel.wwd; + this.statusBar = this.wwjPanel.statusBar; // Put the pieces together. - this.getContentPane().add(mainPanel, BorderLayout.CENTER); + this.getContentPane().add(wwjPanel, BorderLayout.CENTER); if (includeLayerPanel) { this.layerPanel = new LayerPanel(wwd, new Dimension(250, canvasSize.height)); @@ -95,10 +111,10 @@ public class ApplicationTemplate int y = parentLocation.y + (parentSize.height - prefSize.height) / 2; this.setLocation(x, y); this.setResizable(true); - - // Forward events to the status bar to display the cursor position. - if (includeStatusBar) - this.statusBar.setEventSource(wwd); +// +// // Forward events to the status bar to display the cursor position. +// if (includeStatusBar) +// this.statusBar.setEventSource(wwd); } } @@ -128,6 +144,22 @@ public class ApplicationTemplate layers.add(compassPosition, layer); } + public static void insertBeforeLayerName(WorldWindow wwd, Layer layer, String targetName) + { + // Insert the layer into the layer list just before the target layer. + int targetPosition = 0; + LayerList layers = wwd.getModel().getLayers(); + for (Layer l : layers) + { + if (l.getName().indexOf(targetName) != -1) + { + targetPosition = layers.indexOf(l); + break; + } + } + layers.add(targetPosition, layer); + } + static { if (Configuration.isMacOS()) @@ -148,6 +180,7 @@ public class ApplicationTemplate try { AppFrame frame = (AppFrame) appFrameClass.newInstance(); + frame.setTitle(appName); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } diff --git a/gov/nasa/worldwind/examples/GlobalGridLayer.java b/gov/nasa/worldwind/examples/GlobalGridLayer.java deleted file mode 100644 index 87909b3..0000000 --- a/gov/nasa/worldwind/examples/GlobalGridLayer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* -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.examples; - -import gov.nasa.worldwind.layers.*; -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import java.util.*; - -/** - * @author tag - * @version $Id: GlobalGridLayer.java 2043 2007-06-14 06:58:16Z tgaskins $ - */ -public class GlobalGridLayer extends RenderableLayer -{ - private final Polyline ring; - - public GlobalGridLayer() - { - ArrayList positions = new ArrayList(); - positions.add(new Position(Angle.ZERO, Angle.NEG180, 10e3)); - positions.add(new Position(Angle.ZERO, Angle.ZERO, 10e3)); - positions.add(new Position(Angle.ZERO, Angle.POS180, 10e3)); - - ring = new Polyline(positions); - ring.setNumEdgeIntervals(360); - } - - @Override - protected void doRender(DrawContext dc) - { - GL gl = dc.getGL(); - - int attrBits = GL.GL_TRANSFORM_BIT; - gl.glPushAttrib(attrBits); - - try - { - gl.glMatrixMode(GL.GL_MODELVIEW); - for (double lon = 0; lon < 360; lon += 10) - { - gl.glPushMatrix(); - gl.glRotated(lon, 0, 0, 1); - this.ring.render(dc); - gl.glPopMatrix(); - } - } - finally - { - gl.glPopAttrib(); - } - } -} diff --git a/gov/nasa/worldwind/examples/WMSCapabilitiesParsing.java b/gov/nasa/worldwind/examples/WMSCapabilitiesParsing.java deleted file mode 100644 index 2c35bf5..0000000 --- a/gov/nasa/worldwind/examples/WMSCapabilitiesParsing.java +++ /dev/null @@ -1,360 +0,0 @@ -/* -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.examples; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.wms.*; -import org.w3c.dom.*; -import org.xml.sax.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.xml.parsers.*; -import java.awt.*; -import java.awt.event.*; -import java.io.*; -import java.net.*; - -/** - * @author tag - * @version $Id: WMSCapabilitiesParsing.java 2131 2007-06-22 22:45:35Z jason $ - */ -public class WMSCapabilitiesParsing -{ - private static final String TAB = "\t"; - - private static final String[] servers = new String[] - { - "http://neowms.sci.gsfc.nasa.gov/wms/wms" - }; - - private static class MainFrame extends JFrame - { - private static JComboBox serverList = new JComboBox(servers); - private static JTextArea outputArea = new JTextArea(40, 80); - - private static class RunAction extends AbstractAction - { - public RunAction() - { - super("Get Capabilities"); - } - - public void actionPerformed(ActionEvent actionEvent) - { - outputArea.setText(""); - - try - { - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - docBuilderFactory.setNamespaceAware(true); - DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); - Document doc; - - String s = (String) serverList.getSelectedItem(); - if (s.startsWith("file://")) - { - File f = new File(s.substring(7, s.length())); - if (!f.exists()) - { - System.out.println(f.getPath() + " does not exist."); - return; - } - doc = docBuilder.parse(f); - } - else - { - CapabilitiesRequest req = new CapabilitiesRequest(new URI(s)); - doc = docBuilder.parse(req.toString()); - } - - Capabilities caps = Capabilities.parse(doc); - - print("version", caps.getVersion()); - print("update sequence", caps.getUpdateSequence()); - print("abstract", caps.getAbstract()); - print("title", caps.getTitle()); - print("name", caps.getName()); - print("fees", caps.getFees()); - print("access constraints", caps.getAccessConstraints()); - print("layer limit", caps.getLayerLimit()); - print("max width", caps.getMaxWidth()); - print("max height", caps.getMaxHeight()); - print("exception formats", caps.getExceptionFormats()); - print("map get url", caps.getGetMapRequestGetURL()); - print("capabilities get url", caps.getGetCapabilitiesRequestGetURL()); - print("feature info get url", caps.getFeatureInfoRequestGetURL()); - print("map post url", caps.getGetMapRequestPostURL()); - print("capabilities post url", caps.getGetCapabilitiesRequestPostURL()); - print("feature info post url", caps.getFeatureInfoRequestPostURL()); - print("keywords", caps.getKeywordList()); - - Element[] elements = caps.getNamedLayers(); - if (elements == null || elements.length == 0) - print("named layers", "empty"); - else - for (Element e : elements) - { - print("named layer", caps.getLayerName(e)); - } - - Element layer = caps.getLayer(); - if (layer != null) - printLayer(caps, layer); - } - catch (URISyntaxException e) - { - e.printStackTrace(); - } - catch (MalformedURLException e) - { - e.printStackTrace(); - } - catch (IOException e) - { - e.printStackTrace(); - } - catch (ParserConfigurationException e) - { - e.printStackTrace(); - } - catch (SAXException e) - { - e.printStackTrace(); - } - } - } - - private static String indent = ""; - - private static void printLayer(Capabilities caps, Element layer) - { - print(indent, "===== LAYER ====="); - String lastIndent = indent; - indent += TAB; - - print("layer title", caps.getLayerTitle(layer)); - print("layer name", caps.getLayerName(layer)); - print("layer abstract", caps.getLayerAbstract(layer)); - print("layer srs", caps.getLayerSRS(layer)); - print("layer crs", caps.getLayerCRS(layer)); - - print("layer scale", "min " + caps.getLayerMinScaleDenominator(layer) + ", " - + ", max " + caps.getLayerMaxScaleDenominator(layer)); - print("layer queryable", caps.getLayerQueryable(layer)); - print("layer cascaded", caps.getLayerCascaded(layer)); - print("layer opaque", caps.getLayerOpaque(layer)); - print("layer nosubsets", caps.getLayerNoSubsets(layer)); - print("layer fixed width, height", caps.getLayerFixedWidth(layer) + ", " - + caps.getLayerFixedHeight(layer)); - BoundingBox bbox = caps.getLayerGeographicBoundingBox(layer); - print("layer geographic bounding box", bbox != null ? bbox.toString() : "empty"); - - print("layer keywords", caps.getLayerKeywordList(layer)); - - print("layer attribution url title", caps.getLayerAttributionTitle(layer)); - print("layer attribution url online resource", caps.getLayerAttributionURL(layer)); - print("layer attribution url logo format", caps.getLayerAttributionLogoFormat(layer)); - print("layer attribution url logo online resource", caps.getLayerAttributionLogoURL(layer)); - - print("layer data url format", caps.getLayerDataURLFormat(layer)); - print("layer data URL", caps.getLayerDataURL(layer)); - - print("layer feature list url format", caps.getLayerFeatureListFormat(layer)); - print("layer feature list URL", caps.getLayerFeatureListURL(layer)); - - Element[] elements; - - elements = caps.getLayerStyles(layer); - if (elements == null || elements.length == 0) - print("layer styles", "empty"); - else - for (Element e : elements) - { - print("layer style name", caps.getStyleName(e)); - print("layer style title", caps.getStyleTitle(e)); - print("layer style abstract", caps.getStyleAbstract(e)); - print("layer style legend URL", caps.getStyleLegendURL(e)); - print("layer style legend format", caps.getStyleLegendFormat(e)); - print("layer style legend width", caps.getStyleLegendWidth(e)); - print("layer style legend height", caps.getStyleLegendHeight(e)); - print("layer style sheet URL", caps.getStyleSheetURL(e)); - print("layer style sheet format", caps.getStyleSheetURLFormat(e)); - } - - elements = caps.getLayerAuthorityURLs(layer); - if (elements == null || elements.length == 0) - print("layer authority URL", "empty"); - else - for (Element e : elements) - { - print("layer authority URL", caps.getAuthorityName(e) + ": " + caps.getAuthorityURL(e)); - } - - elements = caps.getLayerMetadataURLs(layer); - if (elements == null || elements.length == 0) - print("layer metadata URL", "empty"); - else - for (Element e : elements) - { - print("metadata URL", caps.getMetadataType(e) + ": " + caps.getMetadataFormat(e) + ", " - + caps.getAuthorityURL(e)); - } - - elements = caps.getLayerIdentifiers(layer); - if (elements == null || elements.length == 0) - print("layer identifiers URL", "empty"); - else - for (Element e : elements) - { - print("layer identifiers authority ", caps.getIdentifierAuthority(e) - + ", identifier " + caps.getIdentifier(e)); - } - - elements = caps.getLayerDimensions(layer); - if (elements == null || elements.length == 0) - print("layer dimensions", "empty"); - else - for (Element e : elements) - { - print("layer dimension current", caps.getDimensionCurrent(e)); - print("layer dimension default", caps.getDimensionDefault(e)); - print("layer dimension extent", caps.getDimensionExtent(e)); - print("layer dimension multiple values", caps.getDimensionMultipleValues(e)); - print("layer dimension name", caps.getDimensionName(e)); - print("layer dimension nearest value", caps.getDimensionNearestValue(e)); - print("layer dimension units", caps.getDimensionUnits(e)); - print("layer dimension unit symbol", caps.getDimensionUnitSymbol(e)); - } - - elements = caps.getLayerExtents(layer); - if (elements == null || elements.length == 0) - print("layer extents", "empty"); - else - for (Element e : elements) - { - print("layer extent current", caps.getExtentCurrent(e)); - print("layer extent default", caps.getExtentDefault(e)); - print("layer extent multiple values", caps.getExtentMultipleValues(e)); - print("layer extent name", caps.getExtentName(e)); - print("layer extent nearest value", caps.getExtentNearestValue(e)); - print("layer extent extent", caps.getExtentText(e)); - } - - BoundingBox[] bboxes = caps.getLayerBoundingBoxes(layer); - if (bboxes == null || bboxes.length == 0) - print("layer bounding boxes", "empty"); - else - for (BoundingBox bb : bboxes) - { - print("bounding box", bb.toString()); - } - - Element[] children = caps.getLayerSubLayers(layer); - if (children == null || children.length == 0) - print("layer sublayers", "empty"); - else if (children != null) - { - for (Element l : children) - { - printLayer(caps, l); - } - } - - indent = lastIndent; - } - - private static void print(String name, String s) - { - outputArea.append(indent); - - if (name != null) - outputArea.append(name + ": "); - - outputArea.append(s == null ? "null" : s.equals("") ? "empty" : s.replaceAll("\n", " ").trim()); - outputArea.append("\n"); - } - - private static void print(String name, String[] ss) - { - outputArea.append(indent + name + "\n"); - - if (ss == null) - { - print(TAB, "null"); - return; - } - - for (String s : ss) - { - if (s != null) - print(TAB, s.trim()); - } - } - - public MainFrame() - { - try - { - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BorderLayout()); - mainPanel.setBorder(BorderFactory.createEmptyBorder(9, 9, 9, 9)); - - JPanel outputContainer = new JPanel(); - outputContainer.setBorder(new TitledBorder("Capabilities")); - outputArea.setLineWrap(true); - outputContainer.add(new JScrollPane(outputArea), BorderLayout.CENTER); - - JPanel controlContainer = new JPanel(new BorderLayout()); - controlContainer.setBorder(new TitledBorder("Server")); - JButton btn = new JButton(new RunAction()); - controlContainer.add(btn, BorderLayout.WEST); - serverList.setEditable(false); - controlContainer.add(serverList, BorderLayout.CENTER); - - mainPanel.add(controlContainer, BorderLayout.NORTH); - mainPanel.add(outputContainer, BorderLayout.CENTER); - this.getContentPane().add(mainPanel, BorderLayout.CENTER); - - this.pack(); - - java.awt.Dimension prefSize = this.getPreferredSize(); - prefSize.setSize(prefSize.getWidth(), 1.1 * prefSize.getHeight()); - this.setSize(prefSize); - - java.awt.Dimension parentSize; - java.awt.Point parentLocation = new java.awt.Point(0, 0); - parentSize = Toolkit.getDefaultToolkit().getScreenSize(); - int x = parentLocation.x + (parentSize.width - prefSize.width) / 2; - int y = parentLocation.y + (parentSize.height - prefSize.height) / 2; - this.setLocation(x, y); - this.setResizable(true); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - } - - static - { - if (Configuration.isMacOS()) - { - System.setProperty("apple.laf.useScreenMenuBar", "true"); - System.setProperty("com.apple.mrj.application.apple.menu.about.name", "World Wind wms Caps Parsing"); - System.setProperty("com.apple.mrj.application.growbox.intrudes", "false"); - } - } - - public static void main(String[] arg) - { - final MainFrame frame = new MainFrame(); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setVisible(true); - } -} diff --git a/gov/nasa/worldwind/examples/WMSLayers.java b/gov/nasa/worldwind/examples/WMSLayers.java deleted file mode 100644 index e590bcc..0000000 --- a/gov/nasa/worldwind/examples/WMSLayers.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -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.examples; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.layers.*; -import gov.nasa.worldwind.wms.*; -import org.w3c.dom.*; -import org.xml.sax.*; - -import javax.xml.parsers.*; -import java.io.*; -import java.net.*; - -/** - * Retrieves the capabilities doc from a wms server and adds the named layers described there to the ww model. - * - * @author tag - * @version $Id: WMSLayers.java 2131 2007-06-22 22:45:35Z jason $ - */ -public class WMSLayers extends ApplicationTemplate -{ - private static final String[] servers = new String[] - { - "http://neowms.sci.gsfc.nasa.gov/wms/wms" - }; - - private static class AppFrame extends ApplicationTemplate.AppFrame - { - public AppFrame() - { - try - { - // Retrieve the server's capabilities document and parse it into a DOM. - // Set up the DOM. - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - docBuilderFactory.setNamespaceAware(true); - DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); - Document doc; - - // Request the capabilities document from the server. - // The server id here is hardcoded. An interactive example would provide a choice. - String server = servers[0]; - CapabilitiesRequest req = new CapabilitiesRequest(new URI(server)); - doc = docBuilder.parse(req.toString()); - - // Parse the DOM as a capabilities document. - Capabilities caps = Capabilities.parse(doc); - System.out.println("wms server version: " + caps.getVersion()); - - // Get all the named layers in the capabilities document. - Element[] layerCaps = caps.getNamedLayers(); - if (layerCaps == null || layerCaps.length == 0) - { - System.out.println("No named layers found."); - return; - } - - // Just choose the first named layer for this example. - // An interactive example would present the available choices to the user. - AVListImpl params = new AVListImpl(); - params.setValue(AVKey.LAYER_NAMES, caps.getLayerName(layerCaps[0])); - - // For the chosen layer, determine the available styles and pick one. - // An interactive example would present the available choices to the user. - Element[] styles = caps.getLayerStyles(layerCaps[0]); - if (styles != null && styles.length > 0) - params.setValue(AVKey.STYLE_NAMES, caps.getStyleName(styles[0])); - - // Create a World Wind wms layer. - Layer layer = WMSLayerFactory.newLayer(caps, params); - - // The GeoBoost wms server is especially slow, so increase retrieval timeouts - // if that's the server. - if (server.contains("GeoBoost")) - { - layer.setValue(AVKey.URL_CONNECT_TIMEOUT, 30000); - layer.setValue(AVKey.URL_READ_TIMEOUT, 30000); - layer.setValue(AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT, 60000); - } - - // Insert the layer in front of the compass layer in the default layer list. - insertBeforePlacenames(this.wwd, layer); - - // The layer should start appearing on the globe once this constructor returns. - } - catch (ParserConfigurationException e) - { - e.printStackTrace(); - } - catch (SAXException e) - { - e.printStackTrace(); - } - catch (IOException e) - { - e.printStackTrace(); - } - catch (URISyntaxException e) - { - e.printStackTrace(); - } - } - } - - public static void main(String[] args) - { - ApplicationTemplate.start("World Wind Lines In Space", AppFrame.class); - } -} diff --git a/gov/nasa/worldwind/formats/gpx/GpxTrackPoint.java b/gov/nasa/worldwind/formats/gpx/GpxTrackPoint.java index 3131815..2bce81d 100644 --- a/gov/nasa/worldwind/formats/gpx/GpxTrackPoint.java +++ b/gov/nasa/worldwind/formats/gpx/GpxTrackPoint.java @@ -8,10 +8,11 @@ package gov.nasa.worldwind.formats.gpx; import gov.nasa.worldwind.tracks.TrackPoint; import gov.nasa.worldwind.util.Logging; +import gov.nasa.worldwind.geom.Position; /** * @author tag - * @version $Id: GpxTrackPoint.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: GpxTrackPoint.java 2814 2007-09-12 19:23:53Z tgaskins $ */ public class GpxTrackPoint extends gov.nasa.worldwind.formats.gpx.ElementParser implements TrackPoint { @@ -143,6 +144,25 @@ public class GpxTrackPoint extends gov.nasa.worldwind.formats.gpx.ElementParser this.elevation = elevation; } + public Position getPosition() + { + return Position.fromDegrees(this.latitude, this.longitude, this.elevation); + } + + public void setPosition(Position position) + { + if (position == null) + { + String msg = Logging.getMessage("nullValue.PositionIsNull"); + Logging.logger().severe(msg); + throw new IllegalArgumentException(msg); + } + + this.latitude = position.getLatitude().getDegrees(); + this.longitude = position.getLongitude().getDegrees(); + this.elevation = position.getElevation(); + } + public String getTime() { return time; diff --git a/gov/nasa/worldwind/formats/nitfs/AbstractRpf2DdsCompress.java b/gov/nasa/worldwind/formats/nitfs/AbstractRpf2DdsCompress.java deleted file mode 100644 index b3d965a..0000000 --- a/gov/nasa/worldwind/formats/nitfs/AbstractRpf2DdsCompress.java +++ /dev/null @@ -1,28 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: AbstractRpf2DdsCompress Apr 23, 2007 11:06:16 AM lado - */ -abstract class AbstractRpf2DdsCompress extends DDSConverter implements Rpf2DdsCompress -{ - private static DDSBlock4x4 Dxt1TransparentBlock4x4 = new DDSBlock4x4( (short)0, (short)0, 0xFFFFFFFF ); - - public DDSBlock4x4 getDxt1TransparentBlock4x4() - { - return Dxt1TransparentBlock4x4; - } - - public void writeDxt1Header(java.nio.ByteBuffer buffer, int width, int height) - { - DDSConverter.buildHeaderDxt1( buffer, width, height ); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/Cadrg2DdsCompress.java b/gov/nasa/worldwind/formats/nitfs/Cadrg2DdsCompress.java deleted file mode 100644 index 1145ffa..0000000 --- a/gov/nasa/worldwind/formats/nitfs/Cadrg2DdsCompress.java +++ /dev/null @@ -1,44 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; - -import java.nio.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: Cadrg2DdsCompress Apr 23, 2007 11:00:07 AM lado - */ -class Cadrg2DdsCompress extends AbstractRpf2DdsCompress -{ - public DDSBlock4x4 compressDxt1Block4x4(NitfsImageBand imageBand, byte[] pixelCodes, boolean hasTransparentPixels) - { - int[] pixels565 = new int[16]; - Color[] colors565 = new Color[16]; - for(int i = 0; i < pixelCodes.length; i++ ) - { - pixels565[i] = imageBand.lookupR5G6B5( 0x00FF & pixelCodes[i] ); - colors565[i] = DDSConverter.getColor565( pixels565[i] ); - } - - int[] extremaIndices = determineExtremeColors( colors565 ); - - if(pixels565[extremaIndices[0]] < pixels565[extremaIndices[1]]) - { - int t = extremaIndices[0]; - extremaIndices[0] = extremaIndices[1]; - extremaIndices[1] = t; - } - - return new DDSBlock4x4( - (short) pixels565[extremaIndices[0]], - (short) pixels565[extremaIndices[1]], - (int) DDSConverter.computeBitMask(colors565, extremaIndices) - ); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/Cib2DdsCompress.java b/gov/nasa/worldwind/formats/nitfs/Cib2DdsCompress.java deleted file mode 100644 index 4ef228b..0000000 --- a/gov/nasa/worldwind/formats/nitfs/Cib2DdsCompress.java +++ /dev/null @@ -1,59 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: Cib2DdsCompress Apr 23, 2007 10:59:01 AM lado - */ -class Cib2DdsCompress extends AbstractRpf2DdsCompress -{ - public DDSBlock4x4 compressDxt1Block4x4(NitfsImageBand imageBand, byte[] pixelCodes, boolean hasTransparentPixels) - { - int[] grayPixels = new int[16]; - int minColor = Integer.MAX_VALUE; - int maxColor = Integer.MIN_VALUE; - - for(int i = 0; i < pixelCodes.length; i++ ) - { - grayPixels[i] = imageBand.lookupGray( 0xFF & pixelCodes[i]); - if(grayPixels[i] < minColor) - minColor = grayPixels[i]; - if(grayPixels[i] > maxColor) - maxColor = grayPixels[i]; - } - - DDSBlock4x4 ddsBlock = new DDSBlock4x4( - (short) DDSConverter.getPixel565( new Color( maxColor, maxColor, maxColor ) ), - (short) DDSConverter.getPixel565( new Color( minColor, minColor, minColor ) ), - 0); - - if(maxColor != minColor) - { - int[] ext = new int[] { maxColor, minColor, (2 * maxColor + minColor)/3, (maxColor + 2 * minColor)/3 }; - ddsBlock.bitmask = 0; - for (int i = 0; i < grayPixels.length; i++) - { - int closest = Integer.MAX_VALUE; - int mask = 0; - for (int j = 0; j < ext.length; j++) - { - int d = ( ext[j] >= grayPixels[i] ) ? (ext[j] - grayPixels[i]) : (grayPixels[i] - ext[j]); - if (d < closest) - { - closest = d; - mask = j; - } - } - ddsBlock.bitmask |= mask << i * 2; - } - } - return ddsBlock; - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsDataExtensionSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsDataExtensionSegment.java deleted file mode 100644 index 95e11a2..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsDataExtensionSegment.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsDataExtensionSegment Mar 31, 2007 1:01:41 AM - */ -class NitfsDataExtensionSegment extends NitfsSegment -{ - public NitfsDataExtensionSegment(java.nio.ByteBuffer buffer, - int headerStartOffset, int headerLength, - int dataStartOffset, int dataLength) - { - super(NitfsSegmentType.DataExtensionSegment, buffer, headerStartOffset, headerLength, dataStartOffset, dataLength); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsExtendedHeaderSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsExtendedHeaderSegment.java deleted file mode 100644 index e050063..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsExtendedHeaderSegment.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsExtendedHeaderSegment Mar 31, 2007 1:06:23 AM - */ -class NitfsExtendedHeaderSegment extends NitfsSegment -{ - public NitfsExtendedHeaderSegment(java.nio.ByteBuffer buffer, int headerStartOffset, int headerLength, int dataStartOffset, int dataLength) - { - super(NitfsSegmentType.ExtendedHeaderSegment, buffer, headerStartOffset, headerLength, dataStartOffset, dataLength); - - this.restoreBufferPosition(); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsFileHeader.java b/gov/nasa/worldwind/formats/nitfs/NitfsFileHeader.java deleted file mode 100644 index 2d7ac3a..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsFileHeader.java +++ /dev/null @@ -1,275 +0,0 @@ -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; - -/** - * @author Lado Garakanidze - * @version $Id: NitfsFileHeader.java 525 2007-01-22 01:09:20Z garakl $ - */ -public class NitfsFileHeader -{ - private String headerID; - private String version; - private String specialType; - private int headerLength; - private int fileLength; - private boolean isVersion0210; - private short complexityLevel ; - private String originationStationId; - private String dateTime; - private String title ; - - private String FSCLAS ; - private String FSCLSY ; - private String FSCODE ; - private String FSCTLH ; - private String FSREL ; - private String FSDCTP ; - private String FSDCDT ; - private String FSDCXM ; - private String FSDG ; - private String FSDGDT ; - private String FSCLTX ; - private String FSCATP ; - private String FSCAUT ; - private String FSCRSN ; - private String FSSRDT ; - private String FSCTLN ; - private String FSDWNG ; - private String FSDEVT ; - private String FSCOP ; - private String FSCPYS ; - private String ENCRYP ; - private String FBKGC ; - private String ONAME ; - private String OPHONE ; - - public NitfsFileHeader(java.nio.ByteBuffer buffer) - { - parseFileHeaderInfo(buffer); - } - - private void parseFileHeaderInfo(java.nio.ByteBuffer buffer) - { - this.headerID = NitfsUtil.getString(buffer, 0, 4); - this.version = NitfsUtil.getString(buffer, 5); - this.isVersion0210 = StringUtil.Equals("02.10", version); - this.complexityLevel = NitfsUtil.getShortNumeric(buffer, 2); - this.specialType = NitfsUtil.getString(buffer, 4); // offset 11, size 4 - this.originationStationId = NitfsUtil.getString(buffer, 10); // offset 15, size 10 - this.dateTime = NitfsUtil.getString(buffer, 14); // offset 25, size 14 - this.title = NitfsUtil.getString(buffer, 80); // offset 39, size 80 - - this.FSCLAS = NitfsUtil.getString(buffer, 1); // offset 119, size 1 - this.FSCLSY = (isVersion0210 ? NitfsUtil.getString(buffer, 2) : StringUtil.EMPTY); // offset 120, size 2 - this.FSCODE = NitfsUtil.getString(buffer, isVersion0210 ? 11 : 40); - this.FSCTLH = NitfsUtil.getString(buffer, isVersion0210 ? 2 : 40); - this.FSREL = NitfsUtil.getString(buffer, isVersion0210 ? 20 : 40); - - this.FSDCTP = (isVersion0210 ? NitfsUtil.getString(buffer, 2) : StringUtil.EMPTY); - this.FSDCDT = (isVersion0210 ? NitfsUtil.getString(buffer, 8) : StringUtil.EMPTY); // offset 157/ - this.FSDCXM = (isVersion0210 ? NitfsUtil.getString(buffer, 4) : StringUtil.EMPTY); // offset 165/ - this.FSDG = (isVersion0210 ? NitfsUtil.getString(buffer, 1) : StringUtil.EMPTY); // offset 169/ - this.FSDGDT = (isVersion0210 ? NitfsUtil.getString(buffer, 8) : StringUtil.EMPTY); // oofset 170/ - this.FSCLTX = (isVersion0210 ? NitfsUtil.getString(buffer, 43) : StringUtil.EMPTY); // offset 178/ - this.FSCATP = (isVersion0210 ? NitfsUtil.getString(buffer, 1) : StringUtil.EMPTY); // offset 221/ - - this.FSCAUT = NitfsUtil.getString(buffer, isVersion0210 ? 40 : 20); // offset 222/240 - - this.FSCRSN = (isVersion0210 ? NitfsUtil.getString(buffer, 1) : StringUtil.EMPTY); // offset 262/ - this.FSSRDT = (isVersion0210 ? NitfsUtil.getString(buffer, 8) : StringUtil.EMPTY); // offset 263/ - this.FSCTLN = NitfsUtil.getString(buffer, isVersion0210 ? 15 : 20); // offset 271/260 - this.FSDWNG = (isVersion0210) ? StringUtil.EMPTY : NitfsUtil.getString(buffer, 6); // offset /280 - - this.FSDEVT = (!isVersion0210 && StringUtil.Equals("999998", FSDWNG)) // offset /286 - ? NitfsUtil.getString(buffer, 40) : StringUtil.EMPTY; - - this.FSCOP = NitfsUtil.getString(buffer, 5); // offset 286/+40 - this.FSCPYS = NitfsUtil.getString(buffer, 5); // offset 291/+40 - this.ENCRYP = NitfsUtil.getString(buffer, 1); // offset 296/+40 - - this.FBKGC = (isVersion0210 ? NitfsUtil.getString(buffer, 297, 3) : StringUtil.EMPTY); // offset 297/ - this.ONAME = NitfsUtil.getString(buffer, isVersion0210 ? 24 : 27); // offset 300/297(+40) - this.OPHONE = NitfsUtil.getString(buffer, 18); // offset 324(+40) - - this.fileLength = NitfsUtil.getNumeric(buffer, 12); // offset 342(+40) - this.headerLength = NitfsUtil.getNumeric(buffer, 6); // offset 352(+40) - } - - public String getHeaderID() - { - return this.headerID; - } - - public String getVersion() - { - return this.version; - } - - public boolean isVersion0210() - { - return this.isVersion0210; - } - - public short getComplexityLevel() - { - return this.complexityLevel; - } - - public String getSpecialType() - { - return this.specialType; - } - - public String getOriginationStationId() - { - return this.originationStationId; - } - - public String getDateTime() - { - return this.dateTime; - } - - public String getTitle() - { - return this.title; - } - - public int getHeaderLength() - { - return this.headerLength; - } - - public String getFSCLAS() - { - return this.FSCLAS; - } - - public String getFSCLSY() - { - return this.FSCLSY; - } - - public String getFSCODE() - { - return this.FSCODE; - } - - public String getFSCTLH() - { - return this.FSCTLH; - } - - public String getFSREL() - { - return this.FSREL; - } - - public String getFSDCTP() - { - return this.FSDCTP; - } - - public String getFSDCDT() - { - return this.FSDCDT; - } - - public String getFSDCXM() - { - return this.FSDCXM; - } - - public String getFSDG() - { - return this.FSDG; - } - - public String getFSDGDT() - { - return this.FSDGDT; - } - - public String getFSCLTX() - { - return this.FSCLTX; - } - - public String getFSCATP() - { - return this.FSCATP; - } - - public String getFSCAUT() - { - return this.FSCAUT; - } - - public String getFSCRSN() - { - return this.FSCRSN; - } - - public String getFSSRDT() - { - return this.FSSRDT; - } - - public String getFSCTLN() - { - return this.FSCTLN; - } - - public String getFSDWNG() - { - return this.FSDWNG; - } - - public String getFSDEVT() - { - return this.FSDEVT; - } - - public String getFSCOP() - { - return this.FSCOP; - } - - public String getFSCPYS() - { - return this.FSCPYS; - } - - public String getENCRYP() - { - return this.ENCRYP; - } - - public String getFBKGC() - { - return this.FBKGC; - } - - public String getONAME() - { - return this.ONAME; - } - - public String getOPHONE() - { - return this.OPHONE; - } - - public int getFileLength() - { - return this.fileLength; - } -} \ No newline at end of file diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsImageBand.java b/gov/nasa/worldwind/formats/nitfs/NitfsImageBand.java deleted file mode 100644 index a4f6583..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsImageBand.java +++ /dev/null @@ -1,126 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsImageBand Apr 17, 2007 3:22:33 PM lado - */ -class NitfsImageBand -{ - private String representation; - private String significanceForImageCategory; - private String imageFilterCondition; - private String stdImageFilterCode; - private short numOfLookupTables; - private short numOfLookupTableEntries; - // public int[] lookupTablesOffset; // one byte per entry per band - private byte[][] lut; - - private boolean isGrayImage; - private boolean hasTransparentEntry; - - public boolean isGrayImage() - { - return this.isGrayImage; - } - - public boolean isHasTransparentEntry() - { - return this.hasTransparentEntry; - } - - public String getRepresentation() - { - return this.representation; - } - - public short getNumOfLookupTables() - { - return this.numOfLookupTables; - } - - public short getNumOfLookupTableEntries() - { - return this.numOfLookupTableEntries; - } - - public NitfsImageBand(java.nio.ByteBuffer buffer) - { - this.representation = NitfsUtil.getString(buffer, 2); - this.significanceForImageCategory = NitfsUtil.getString(buffer, 6); - this.imageFilterCondition = NitfsUtil.getString(buffer, 1); - this.stdImageFilterCode = NitfsUtil.getString(buffer, 3); - this.numOfLookupTables = NitfsUtil.getShortNumeric(buffer, 1); - this.numOfLookupTableEntries = NitfsUtil.getShortNumeric(buffer, 5); - if (0 < this.numOfLookupTables && 0 < this.numOfLookupTableEntries) - { - this.lut = new byte[this.numOfLookupTables][this.numOfLookupTableEntries]; - for (int j = 0; j < this.numOfLookupTables; j++) - { - buffer.get(this.lut[j], 0, this.numOfLookupTableEntries); - } - } - - this.isGrayImage = (1 == this.numOfLookupTables); - this.hasTransparentEntry = (217 == this.numOfLookupTableEntries); - } - - public final int lookupR5G6B5(int colorIndex) - { - int r, g, b; - if (3 == this.numOfLookupTables) - { - r = (0x00FF & this.lut[0][colorIndex]) >> 3; - g = (0x00FF & this.lut[1][colorIndex]) >> 2; - b = (0x00FF & this.lut[2][colorIndex]) >> 3; - } - else - { - int gray = 0x00FF & this.lut[0][ colorIndex ]; - r = gray >> 3; - g = gray >> 2; - b = gray >> 3; - } - return 0x00FFFF & ((r << 11) | (g << 5) | b ); - } - - - public final int lookupRGB(int colorIndex) - { - int r, g, b; - if (3 == this.numOfLookupTables) - { - r = (0x00FF & this.lut[0][colorIndex]); - g = (0x00FF & this.lut[1][colorIndex]); - b = (0x00FF & this.lut[2][colorIndex]); - } - else - { - r = g = b = 0x00FF & this.lut[0][ colorIndex ]; - } - return (int) (0x00FFFFFFL & (long)((r << 16) | (g << 8) | b )); - } - - public final int lookupGray(int colorIndex) - { - - if (3 == this.numOfLookupTables) - { - int r = (0x00FF & this.lut[0][colorIndex]); - int g = (0x00FF & this.lut[1][colorIndex]); - int b = (0x00FF & this.lut[2][colorIndex]); - - return (30 * r + 59 * g + 11 * b)/100; - } - else - { - return (0x00FF & this.lut[0][colorIndex]); - } - } -} \ No newline at end of file diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsImageSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsImageSegment.java deleted file mode 100644 index 66cff1d..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsImageSegment.java +++ /dev/null @@ -1,654 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.formats.rpf.*; -import gov.nasa.worldwind.geom.*; - -import java.nio.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsImageSegment Mar 30, 2007 12:21:34 PM lado - */ -public class NitfsImageSegment extends NitfsSegment -{ - public static final String[] SupportedFormats = { "CIB", "CADRG", "ADRG" }; - // [ nitf identification , security, structure fields] - public String partType; - public String imageID; - public String dateTime; - public String targetID; - public String imageTitle; - public String securityClass; - public String codewords; - public String controlAndHandling; - public String releaseInstructions; - public String classAuthority; - public String securityCtrlNum; - public String ISDWNG; // image security downgrade - public String ISDEVT; // downgrading event - public short encryption; - public String imageSource; - public int numSignificantRows; - public int numSignificantCols; - public String pixelValueType; - public String imageRepresentation; - public String imageCategory; - public short bitsPerPixelPerBand; - public String pixelJustification; - public String imageCoordSystem; - // [ nitf image geographic location ] - public LatLon[] imageCoords; - // [ nitf comments ] - public String[] imageCommentRecords; - // [ nitf image compression structure ] - public String imageCompression; - public String compressionRateCode; - public short NBANDS; // number of bands { 1 for MONO and RGB/LUT, 3 for RGB; - // [ nitfs image bands ] - public NitfsImageBand[] imageBands; - // [ nitf image table structure fields ] - public short imageSyncCode; // ISYNC { 0 - No sync code, 1 - sync code } - public String imageMode; // IMODE { B, P, R, S } - public short numOfBlocksPerRow; // NBPR { 0001~9999 } - public short numOfBlocksPerCol; // NBPC { 0001~9999 } - public short numOfPixelsPerBlockH; // NPPBH { 0001~8192 } - public short numOfPixelsPerBlockV; // NPPBV { 0001~8192 } - public short numOfBitsPerPixelPerBand; // NBPP { 01~96 } - public short displayLevel; // IDLVL { 001~999 } - public short attachmentLevel; // IALVL { 001~998 } - // [ nitfs image location ] - public short imageRowOffset; // ILOC { -0001 ~ +9999 } - public short imageColOffset; // - - // [ nitf image magnification ] - public String imageMagnification; // IMAG - public short userDefinedSubheaderLength; - - // [ nitf user-defined image subheader ] - private UserDefinedImageSubheader userDefSubheader; - - // [ nitf-rpf image display parameter sub-header ] - private long numOfImageRows; - private long numOfImageCodesPerRow; - private short imageCodeBitLength; - - // [ nitf rpf compression section ] - // [ nitf-rpf compression section sub-header ] - private int compressionAlgorithmID; - private int numOfCompressionLookupOffsetRecords; - private int numOfCompressionParameterOffsetRecords; - - // [ nitf rpf compression lookup sub-section ] - private long compressionLookupOffsetTableOffset; - private int compressionLookupTableOffsetRecordLength; - - - // [ nitf-rpf mask subsection ] - private int subframeSequenceRecordLength; - private int transparencySequenceRecordLength; - private int transparentOutputPixelCodeLength; - private byte[] transparentOutputPixelCode; - private int[] subFrameOffsets = null; - - private boolean hasTransparentPixels = false; - private boolean hasMaskedSubframes = false; - - public static String[] getSupportedFormats() - { - return SupportedFormats; - } - - public boolean hasTransparentPixels() - { - return this.hasTransparentPixels; - } - - public boolean hasMaskedSubframes() - { - return this.hasMaskedSubframes; - } - - private CompressionLookupRecord[] compressionLUTS; - - public UserDefinedImageSubheader getUserDefinedImageSubheader() - { - return userDefSubheader; - } - - public RpfFrameFileComponents getRpfFrameFileComponents() - { - return (null != userDefSubheader) ? userDefSubheader.getRpfFrameFileComponents() : null; - } - - public NitfsImageSegment(java.nio.ByteBuffer buffer, int headerStartOffset, int headerLength,int dataStartOffset, int dataLength) - { - super(NitfsSegmentType.ImageSegment, buffer, headerStartOffset, headerLength, dataStartOffset, dataLength); - - int saveOffset = buffer.position(); - - buffer.position( headerStartOffset ); - // do not change order of parsing - this.parseIdentificationSecurityStructureFields(buffer); - this.parseImageGeographicLocation(buffer); - this.parseCommentRecords(buffer); - this.parseImageCompressionStructure(buffer); - this.parseImageBands(buffer); - this.parseImageTableStructure(buffer); - this.parseImageLocation(buffer); - this.parseImageSubheaders(buffer); - this.parseImageData(buffer); - this.validateImage(); - - buffer.position(saveOffset); // last line - restore buffer's position - } - - private void decompressBlock4x4(byte[][] block4x4, short code) - { - this.compressionLUTS[0].copyValues(block4x4[0], 0, code, 4); - this.compressionLUTS[1].copyValues(block4x4[1], 0, code, 4); - this.compressionLUTS[2].copyValues(block4x4[2], 0, code, 4); - this.compressionLUTS[3].copyValues(block4x4[3], 0, code, 4); - } - - private void decompressBlock16(byte[] block16, short code) - { - this.compressionLUTS[0].copyValues(block16, 0, code, 4); - this.compressionLUTS[1].copyValues(block16, 4, code, 4); - this.compressionLUTS[2].copyValues(block16, 8, code, 4); - this.compressionLUTS[3].copyValues(block16, 12, code, 4); - } - - - public ByteBuffer getImageAsDdsTexture() throws NitfsRuntimeException - { - RpfFrameFileComponents rpfComponents = this.getRpfFrameFileComponents(); - RpfLocationSection componentLocationTable = rpfComponents.componentLocationTable; - - int spatialDataSubsectionLocation = componentLocationTable.getSpatialDataSubsectionLocation(); - super.buffer.position( spatialDataSubsectionLocation ); - - short aa, ab, bb; - short[] codes = new short[(int) this.numOfImageCodesPerRow]; - byte[] block16 = new byte[16]; - int rowSize = (int) ((this.numOfImageCodesPerRow * this.imageCodeBitLength) / 8L); - byte[] rowBytes = new byte[rowSize]; - int subFrameOffset; - short subFrameIdx = 0; - - int band = 0; // for(int band = 0; band < rpfComponents.numOfSpectralBandTables; band++) - NitfsImageBand imageBand = this.imageBands[band]; - - Rpf2DdsCompress ddsCompress = (1 == imageBand.getNumOfLookupTables()) - ? new Cib2DdsCompress() : new Cadrg2DdsCompress(); - - boolean imageHasTransparentAreas = ( this.hasTransparentPixels || this.hasMaskedSubframes ); - if( imageHasTransparentAreas ) - { - - } - - // Allocate space for the DDS texture - int bufferSize = 128 + this.numSignificantCols * this.numSignificantRows / 2; - java.nio.ByteBuffer ddsBuffer = java.nio.ByteBuffer.allocateDirect(bufferSize); - ddsBuffer.order(java.nio.ByteOrder.LITTLE_ENDIAN); - ddsCompress.writeDxt1Header(ddsBuffer, this.numSignificantCols, this.numSignificantRows); - int ddsHeaderLength = ddsBuffer.position(); - - - for (int subFrameH = 0; subFrameH < this.numOfBlocksPerCol; subFrameH++) - { - for (int subFrameW = 0; subFrameW < this.numOfBlocksPerRow; subFrameW++, subFrameIdx++ ) - { - int blockY = (int) (subFrameH * rpfComponents.numOfOutputRowsPerSubframe); - int blockX = (int) (subFrameW * rpfComponents.numOfOutputColumnsPerSubframe); - - if(hasMaskedSubframes) - { - subFrameOffset = this.subFrameOffsets[subFrameIdx]; - if( -1 == subFrameOffset) - { // this is a masked / transparent(?) subframe - DDSBlock4x4 ddsBlock = ddsCompress.getDxt1TransparentBlock4x4(); - - for (int row = 0; row < this.numOfImageRows; row++) - { - int qy = blockY + row * 4; - for (int col = 0; col < this.numOfImageCodesPerRow; col++) - { - int qx = blockX + col * 4; - ddsBuffer.position(ddsHeaderLength + (qy * this.numSignificantCols) / 2 + 2 * qx); - ddsBlock.writeTo( ddsBuffer ); - } // end of column loop - } - continue; - } - else - { - super.buffer.position( spatialDataSubsectionLocation + subFrameOffset ); - } - } - - for (int row = 0; row < this.numOfImageRows; row++) - { - int qy = blockY + row * 4; - super.buffer.get(rowBytes, 0, rowSize); - - for (int i = 0, cidx = 0, bidx = 0; i < (int) this.numOfImageCodesPerRow / 2; i++) - { - aa = (short) ((0x00FF & (short) rowBytes[bidx++]) << 4); - ab = (short) (0x00FF & (short) rowBytes[bidx++]); - bb = (short) (0x00FF & (short) rowBytes[bidx++]); - - codes[cidx++] = (short) (aa | ((0x00F0 & ab) >> 4)); - codes[cidx++] = (short) (bb | ((0x000F & ab) << 8)); - } - - for (int col = 0; col < this.numOfImageCodesPerRow; col++) - { - int qx = blockX + col * 4; - this.decompressBlock16( block16, codes[col] ); - - DDSBlock4x4 ddsBlock = ddsCompress.compressDxt1Block4x4( imageBand, block16, false ); - - ddsBuffer.position( ddsHeaderLength + (qy * this.numSignificantCols)/2 + 2 * qx ); - ddsBlock.writeTo( ddsBuffer ); - } // end of column loop - } // end of row loop - } // end of subFrameW loop - } // end of subFrameH loop - - return ddsBuffer; - } - - public IntBuffer getImagePixelsAsArray(IntBuffer pixels, RpfImageType imageType) throws NitfsRuntimeException - { - RpfFrameFileComponents rpfComponents = this.getRpfFrameFileComponents(); - RpfLocationSection componentLocationTable = rpfComponents.componentLocationTable; - - int spatialDataSubsectionLocation = componentLocationTable.getSpatialDataSubsectionLocation(); - super.buffer.position( spatialDataSubsectionLocation ); - - int band = 0; // for(int band = 0; band < rpfComponents.numOfSpectralBandTables; band++) - NitfsImageBand imageBand = this.imageBands[band]; - - int rgbColor, colorCode; - short aa, ab, bb; - short[] codes = new short[(int) this.numOfImageCodesPerRow]; - byte[][] block4x4 = new byte[4][4]; - int rowSize = (short) ((this.numOfImageCodesPerRow * this.imageCodeBitLength) / 8L); - byte[] rowBytes = new byte[rowSize]; - int subFrameOffset; - short subFrameIdx = 0; - - for (int subFrameH = 0; subFrameH < this.numOfBlocksPerCol; subFrameH++) - { - for (int subFrameW = 0; subFrameW < this.numOfBlocksPerRow; subFrameW++, subFrameIdx++ ) - { - int blockY = (int) (subFrameH * rpfComponents.numOfOutputRowsPerSubframe); - int blockX = (int) (subFrameW * rpfComponents.numOfOutputColumnsPerSubframe); - - if(hasMaskedSubframes) - { - subFrameOffset = this.subFrameOffsets[subFrameIdx]; - if( -1 == subFrameOffset) - { // this is a masked / transparent(?) subframe - continue; - } - else - { - super.buffer.position( spatialDataSubsectionLocation + subFrameOffset ); - } - } - - for (int row = 0; row < this.numOfImageRows; row++) - { - int qy = blockY + row * 4; - - super.buffer.get(rowBytes, 0, rowSize); - - // short[] codes = new short[(int) this.numOfImageCodesPerRow]; - for (int i = 0, cidx = 0, bidx = 0; i < (int) this.numOfImageCodesPerRow / 2; i++) - { - aa = (short) ((0x00FF & (short) rowBytes[bidx++]) << 4); - ab = (short) (0x00FF & (short) rowBytes[bidx++]); - bb = (short) (0x00FF & (short) rowBytes[bidx++]); - - codes[cidx++] = (short) (aa | ((0x00F0 & ab) >> 4)); - codes[cidx++] = (short) (bb | ((0x000F & ab) << 8)); - } - - for (int col = 0; col < this.numOfImageCodesPerRow; col++) - { - this.decompressBlock4x4( block4x4, codes[col] ); - - int qx = blockX + col * 4; - - for (int h = 0; h < 4; h++) - { - for (int w = 0; w < 4; w++) - { - colorCode = 0x00FF & block4x4[h][w]; - rgbColor = imageBand.lookupRGB(colorCode); - switch (imageType) - { - case IMAGE_TYPE_ALPHA_RGB: - rgbColor = 0xFF000000 + rgbColor; - break; -// case IMAGE_TYPE_GRAY: -// break; -// case IMAGE_TYPE_RGB: -// break; - case IMAGE_TYPE_GRAY_ALPHA: - rgbColor = (rgbColor << 8) + 0xFF; - break; - case IMAGE_TYPE_RGB_ALPHA: - rgbColor = (rgbColor << 8) + 0xFF; - break; - } -// pixels[(qy + h) * this.numSignificantCols + (qx + w)] = rgbColor; - pixels.put((qy + h) * this.numSignificantCols + (qx + w), rgbColor); - } - } - } // end of column loop - } // end of row loop - } // end of subFrameW loop - } // end of subFrameH loop - - return pixels; - } - - private void validateImage() throws NitfsRuntimeException - { - RpfFrameFileComponents rpfComponents = this.getRpfFrameFileComponents(); - - if(1 != this.compressionAlgorithmID ) - throw new NitfsRuntimeException("NitfsReader.UnsupportedCompressionAlgorithm"); - if( !StringUtil.Equals( this.imageMode, "B")) - throw new NitfsRuntimeException("NitfsReader.UnsupportedImageMode"); - if( 1 != rpfComponents.numOfSpectralGroups ) - throw new NitfsRuntimeException("NitfsReader.UnsupportedNumberOfSpectralGroups."); - if( 12 != this.imageCodeBitLength ) - throw new NitfsRuntimeException("NitfsReader.UnsupportedImageCodeBitLength."); - - - - - } - - private void parseRpfMaskSubsection(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - // parse [ nitf-rpf mask subsection ] - this.subframeSequenceRecordLength = NitfsUtil.getUShort(buffer); - this.transparencySequenceRecordLength = NitfsUtil.getUShort(buffer); - this.transparentOutputPixelCodeLength = NitfsUtil.getUShort(buffer); - - if( 0 != this.transparentOutputPixelCodeLength ) - { - this.transparentOutputPixelCode = new byte[(int)this.transparentOutputPixelCodeLength]; - buffer.get(this.transparentOutputPixelCode, 0, (int)this.transparentOutputPixelCodeLength); - } - - if(0 < this.subframeSequenceRecordLength) - { - RpfFrameFileComponents rpfComponents = this.getRpfFrameFileComponents(); - subFrameOffsets = new int[ this.numOfBlocksPerCol * this.numOfBlocksPerRow ]; - // parse [ nitf-rpf subframe mask table ] - int idx = 0; - for(int group = 0 ; group < rpfComponents.numOfSpectralGroups; group++ ) - { - for(int row = 0 ; row < this.numOfBlocksPerCol; row++ ) - { - for(int col = 0 ; col < this.numOfBlocksPerRow; col++ ) - subFrameOffsets[idx++] = (int) NitfsUtil.getUInt(buffer); - } - } - - hasMaskedSubframes = (null != this.subFrameOffsets && 0 < this.subFrameOffsets.length); - } - else - { - this.subFrameOffsets = null; - } - this.hasMaskedSubframes = (null != this.subFrameOffsets && 0 < this.subFrameOffsets.length); - this.hasTransparentPixels = (0 < this.transparencySequenceRecordLength); - } - - - private void parseImageData(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - RpfLocationSection componentLocationTable = this.getRpfFrameFileComponents().componentLocationTable; - - buffer.position(this.dataStartOffset); - long spatialDataOffset = NitfsUtil.getUInt(buffer); - - if(0 < componentLocationTable.getMaskSubsectionLength()) - { - // parse nitf-rpf mask subsection - buffer.position( componentLocationTable.getMaskSubsectionLocation() ); - this.parseRpfMaskSubsection(buffer); - } - - if(0 < componentLocationTable.getImageDisplayParametersSubheaderLength()) - { // parse [ nitf-rpf image display parameter sub-header ] - buffer.position( componentLocationTable.getImageDisplayParametersSubheaderLocation() ); - this.parseImageDisplayParametersSubheader(buffer); - } - else - throw new NitfsRuntimeException("NitfsReader.ImageDisplayParametersSubheaderNotFound"); - - // [ nitf rpf compression section ] - if(0 < componentLocationTable.getCompressionSectionSubheaderLength()) - { // parse [ nitf-rpf compression section sub-header ] - buffer.position( componentLocationTable.getCompressionSectionSubheaderLocation() ); - this.parseRpfCompressionSectionSubheader(buffer); - } - else - throw new NitfsRuntimeException("NitfsReader.RpfCompressionSectionSubheaderNotFound"); - - // [ nitf rpf compression lookup sub-section ] - if(0 < componentLocationTable.getCompressionLookupSubsectionLength()) - { - buffer.position( componentLocationTable.getCompressionLookupSubsectionLocation() ); - this.parseRpfCompressionLookupSubsection(buffer); - } - else - throw new NitfsRuntimeException("NitfsReader.RpfCompressionLookupSubsectionNotFound"); - - // [ nitf rpf compression parameter subsection ] - if(0 < componentLocationTable.getCompressionParameterSubsectionLength()) - throw new NitfsRuntimeException("NitfsReader.RpfCompressionParameterSubsectionNotImplemented"); - - // [ nitf rpf spatial data subsection ] - if(0 < componentLocationTable.getSpatialDataSubsectionLength()) - { - - buffer.position( componentLocationTable.getSpatialDataSubsectionLocation() ); - this.parseRpfSpatialDataSubsection(buffer); - } - else - throw new NitfsRuntimeException("NitfsReader.RpfSpatialDataSubsectionNotFound"); - } - - private void parseRpfSpatialDataSubsection(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - - - } - - private void parseRpfCompressionLookupSubsection(java.nio.ByteBuffer buffer) - throws NitfsRuntimeException - { - int compressionLookupSubsectionLocation = buffer.position(); - // [ nitf rpf compression lookup sub-section ] - this.compressionLookupOffsetTableOffset = NitfsUtil.getUInt(buffer); - this.compressionLookupTableOffsetRecordLength = NitfsUtil.getUShort(buffer); - - this.compressionLUTS = new CompressionLookupRecord[this.numOfCompressionLookupOffsetRecords]; - for(int i = 0 ; i < this.numOfCompressionLookupOffsetRecords; i++) - { - this.compressionLUTS[i] = new CompressionLookupRecord( buffer, - compressionLookupSubsectionLocation, - this.getRpfFrameFileComponents().rpfColorMaps); - } - } - - private void parseRpfCompressionSectionSubheader(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - // parse [ nitf-rpf compression section sub-header ] - this.compressionAlgorithmID = NitfsUtil.getUShort(buffer); - this.numOfCompressionLookupOffsetRecords = NitfsUtil.getUShort(buffer); - this.numOfCompressionParameterOffsetRecords = NitfsUtil.getUShort(buffer); - } - - private void parseImageDisplayParametersSubheader(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - // parse [ nitf-rpf image display parameter sub-header ] - this.numOfImageRows = NitfsUtil.getUInt(buffer); - this.numOfImageCodesPerRow = NitfsUtil.getUInt(buffer); - this.imageCodeBitLength = NitfsUtil.getByteAsShort(buffer); - } - - private void parseImageSubheaders(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - this.userDefinedSubheaderLength = NitfsUtil.getShortNumeric(buffer, 5); - if (0 == this.userDefinedSubheaderLength) - { - this.userDefSubheader = null; - return; - } - - this.userDefSubheader = new UserDefinedImageSubheader(buffer); - } - private void parseImageLocation(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - this.imageRowOffset = NitfsUtil.getShortNumeric(buffer, 5); - this.imageColOffset = NitfsUtil.getShortNumeric(buffer, 5); - // [ nitf image magnification ] - this.imageMagnification = NitfsUtil.getString(buffer, 4); - } - - private void parseImageTableStructure(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - this.imageSyncCode = NitfsUtil.getShortNumeric(buffer, 1); - this.imageMode = NitfsUtil.getString(buffer, 1); - this.numOfBlocksPerRow = NitfsUtil.getShortNumeric(buffer, 4); - this.numOfBlocksPerCol = NitfsUtil.getShortNumeric(buffer, 4); - this.numOfPixelsPerBlockH = NitfsUtil.getShortNumeric(buffer, 4); - this.numOfPixelsPerBlockV = NitfsUtil.getShortNumeric(buffer, 4); - this.numOfBitsPerPixelPerBand = NitfsUtil.getShortNumeric(buffer, 2); - this.displayLevel = NitfsUtil.getShortNumeric(buffer, 3); - this.attachmentLevel = NitfsUtil.getShortNumeric(buffer, 3); - } - - private void parseImageBands(java.nio.ByteBuffer buffer) throws NitfsRuntimeException - { - if(0 == this.NBANDS) - throw new NitfsRuntimeException("NitfsReader.InvalidNumberOfImageBands"); - this.imageBands = new NitfsImageBand[this.NBANDS]; - for(int i = 0 ; i < this.NBANDS; i++) - this.imageBands[i] = new NitfsImageBand(buffer); - } - private void parseImageCompressionStructure(java.nio.ByteBuffer buffer) - { - this.imageCompression = NitfsUtil.getString(buffer, 2); - this.compressionRateCode = NitfsUtil.getString(buffer, 4); - this.NBANDS = NitfsUtil.getShortNumeric(buffer, 1); - } - - private void parseCommentRecords(java.nio.ByteBuffer buffer) - { - int numCommentRecords = NitfsUtil.getShortNumeric(buffer, 1); - if(0 < numCommentRecords) - { - this.imageCommentRecords = new String[numCommentRecords]; - for(int i = 0; i < numCommentRecords; i++) - this.imageCommentRecords[i] = NitfsUtil.getString(buffer, 80); - } - else - this.imageCommentRecords = null; - } - - private void parseImageGeographicLocation(java.nio.ByteBuffer buffer) - { - String hemisphere; - double deg, min, sec, lat, lon; - double sixty = (double) 60.0; - this.imageCoords = new LatLon[4]; - for (int i = 0; i < 4; i++) - { - deg = (double)NitfsUtil.getShortNumeric(buffer, 2); - min = (double)NitfsUtil.getShortNumeric(buffer, 2); - sec = (double)NitfsUtil.getShortNumeric(buffer, 2); - hemisphere = NitfsUtil.getString(buffer, 1); - lat = deg + (min + (sec / sixty)) / sixty; // deciaml latitude - if(StringUtil.Equals(hemisphere, "N")) - lat *= (double)-1.0; - - deg = (double)NitfsUtil.getShortNumeric(buffer, 3); - min = (double)NitfsUtil.getShortNumeric(buffer, 2); - sec = (double)NitfsUtil.getShortNumeric(buffer, 2); - hemisphere = NitfsUtil.getString(buffer, 1); - lon = deg + (min + (sec / sixty)) / sixty; // deciaml longitude - if(StringUtil.Equals(hemisphere, "W")) - lon *= (double)-1.0; - - // TODO Do not waste time on this calculations - the same info is repeated in the [ rpf coverage section ] - // TODO zz: garakl: convert to LatLon according to the CoordinateSystem - // if(0 == StringUtil.compare(imageCoordSystem, "G")) - this.imageCoords[i] = LatLon.fromDegrees(lat, lon); - } - } - - private void parseIdentificationSecurityStructureFields(java.nio.ByteBuffer buffer) - throws NitfsRuntimeException - { - // [ nitf identification , security, structure fields] - this.partType = NitfsUtil.getString(buffer, 2); - if(!StringUtil.Equals("IM", this.partType)) - throw new NitfsRuntimeException("NitfsReader.UnexpectedSegmentType", this.partType); - - this.imageID = NitfsUtil.getString(buffer, 10); - boolean isSupportedFormat = false; - for(String s : SupportedFormats) - { - if(0 == s.compareTo(this.imageID)) - { - isSupportedFormat = true; - break; - } - } - if(!isSupportedFormat) - throw new NitfsRuntimeException("NitfsReader.UnsupportedImageFormat", this.imageID); - - this.dateTime = NitfsUtil.getString(buffer, 14); - this.targetID = NitfsUtil.getString(buffer, 17); - this.imageTitle = NitfsUtil.getString(buffer, 80); - this.securityClass = NitfsUtil.getString(buffer, 1); - this.codewords = NitfsUtil.getString(buffer, 40); - this.controlAndHandling = NitfsUtil.getString(buffer, 40); - this.releaseInstructions = NitfsUtil.getString(buffer, 40); - this.classAuthority = NitfsUtil.getString(buffer, 20); // ISCAUT - this.securityCtrlNum = NitfsUtil.getString(buffer, 20); // ISCTLN - this.ISDWNG = NitfsUtil.getString(buffer, 6); - this.ISDEVT = StringUtil.Equals(this.ISDWNG, "999998") ? NitfsUtil.getString(buffer, 40) : StringUtil.EMPTY; - - this.encryption = NitfsUtil.getShortNumeric(buffer, 1); - this.imageSource = NitfsUtil.getString(buffer, 42); - this.numSignificantRows = NitfsUtil.getNumeric(buffer, 8); - this.numSignificantCols = NitfsUtil.getNumeric(buffer, 8); - this.pixelValueType = NitfsUtil.getString(buffer, 3); - this.imageRepresentation = NitfsUtil.getString(buffer, 8); - this.imageCategory = NitfsUtil.getString(buffer, 8); - this.bitsPerPixelPerBand = NitfsUtil.getShortNumeric(buffer, 2); - this.pixelJustification = NitfsUtil.getString(buffer, 1); - this.imageCoordSystem = NitfsUtil.getString(buffer, 1); - } - - -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsLabelSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsLabelSegment.java deleted file mode 100644 index 8af01ab..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsLabelSegment.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsLabelSegment Mar 31, 2007 12:57:41 AM - */ -class NitfsLabelSegment extends NitfsSegment -{ - public NitfsLabelSegment(java.nio.ByteBuffer buffer, int headerStartOffset, int headerLength, int dataStartOffset, int dataLength) - { - super(NitfsSegmentType.LabelSegment, buffer, headerStartOffset, headerLength, dataStartOffset, dataLength); - - this.restoreBufferPosition(); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsMessage.java b/gov/nasa/worldwind/formats/nitfs/NitfsMessage.java deleted file mode 100644 index 30be39c..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsMessage.java +++ /dev/null @@ -1,208 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.formats.rpf.*; - -import java.io.*; -import java.text.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsMessage Apr 4, 2007 4:11:55 PM lado - */ -public class NitfsMessage -{ - private java.nio.ByteBuffer buffer; - private NitfsFileHeader fileHeader; - private java.util.ArrayList segments = new java.util.ArrayList(); - - - public NitfsSegment getSegment( NitfsSegmentType segmentType ) - { - for(NitfsSegment seg : segments) - { - if(null != seg && seg.segmentType.equals(segmentType)) - return seg; - } - return null; - } - - public NitfsFileHeader getNitfsFileHeader() - { - return this.fileHeader; - } - - private NitfsMessage(java.nio.ByteBuffer buffer) - { - this.buffer = buffer; - this.fileHeader = new NitfsFileHeader(buffer); - - // read ALL description groups and segments - this.readSegments(); - } - - private void readSegments() - { - int saveOffset = this.buffer.position(); - int nextSegmentOffset = this.fileHeader.getHeaderLength(); - - // parse Image Description Group - nextSegmentOffset = parseSegment(NitfsSegmentType.ImageSegment, nextSegmentOffset); - // parse Graphic/Symbol Description Group - nextSegmentOffset = parseSegment(NitfsSegmentType.SymbolSegment, nextSegmentOffset); - // parse Label Description Group - nextSegmentOffset = parseSegment(NitfsSegmentType.LabelSegment, nextSegmentOffset); - // parse Text Description Group - nextSegmentOffset = parseSegment(NitfsSegmentType.TextSegment, nextSegmentOffset); - // parse Data Extension Description Group - nextSegmentOffset = parseSegment(NitfsSegmentType.DataExtensionSegment, nextSegmentOffset); - // parse Reserved Extension Description Group - nextSegmentOffset = parseSegment(NitfsSegmentType.ReservedExtensionSegment, nextSegmentOffset); - // parse User Defined Header Description (UDHD) Group - NitfsUserDefinedHeaderSegment userHeaderSeg = new RpfUserDefinedHeaderSegment(this.buffer); - this.segments.add( userHeaderSeg ); - nextSegmentOffset += userHeaderSeg.headerLength + userHeaderSeg.dataLength; - // parse Extended Header Description Group - nextSegmentOffset = parseSegment(NitfsSegmentType.ExtendedHeaderSegment, nextSegmentOffset); - - // let's read each header - for(NitfsSegment segment : segments) - { - -// -// String segId = NitfsUtil.getString(buffer, segment.headerStartOffset, 2); -// System.out.println("Segment type=" + segment.segmentType + ", id=" + segId); - } - } - - private int parseSegment(NitfsSegmentType segType, int nextSegmentOffset) - { - int headerLengthSize = segType.getHeaderLengthSize(); - int dataLengthSize = segType.getDataLengthSize(); - - int numOfSegments = Integer.parseInt(NitfsUtil.getString(this.buffer, 3)); - for (int i = 0; i < numOfSegments; i++) - { - int segHeaderLength = Integer.parseInt(NitfsUtil.getString(this.buffer, headerLengthSize)); - int seqDataLength = Integer.parseInt(NitfsUtil.getString(this.buffer, dataLengthSize)); - - int saveOffset = this.buffer.position(); // pass buffer to NitfsSegment to parse their headers' contents - NitfsSegment segment; - switch (segType) - { - case ImageSegment: - segment = new NitfsImageSegment(this.buffer, nextSegmentOffset, segHeaderLength, - nextSegmentOffset + segHeaderLength, seqDataLength); - break; - case SymbolSegment: - segment = new NitfsSymbolSegment(this.buffer, nextSegmentOffset, segHeaderLength, - nextSegmentOffset + segHeaderLength, seqDataLength); - break; - case LabelSegment: - segment = new NitfsLabelSegment(this.buffer, nextSegmentOffset, segHeaderLength, - nextSegmentOffset + segHeaderLength, seqDataLength); - break; - case TextSegment: - segment = new NitfsTextSegment(this.buffer, nextSegmentOffset, segHeaderLength, - nextSegmentOffset + segHeaderLength, seqDataLength); - break; - case DataExtensionSegment: - segment = new NitfsDataExtensionSegment(this.buffer, nextSegmentOffset, segHeaderLength, - nextSegmentOffset + segHeaderLength, seqDataLength); - break; - case ReservedExtensionSegment: - segment = new NitfsReservedExtensionSegment(this.buffer, nextSegmentOffset, segHeaderLength, - nextSegmentOffset + segHeaderLength, seqDataLength); - break; - case UserDefinedHeaderSegment: - segment = new RpfUserDefinedHeaderSegment(this.buffer); - break; - case ExtendedHeaderSegment: // // throw exception - wrong parser for ExtendedHeaderSegment - segment = new NitfsExtendedHeaderSegment(this.buffer, nextSegmentOffset, segHeaderLength, - nextSegmentOffset + segHeaderLength, seqDataLength); - break; - - default: - throw new NitfsRuntimeException("NitfsReader.UnknownOrUnsupportedSegment", segType.toString()); - - } - this.segments.add(segment); - - nextSegmentOffset += segHeaderLength + seqDataLength; - buffer.position(saveOffset); // restore offset - } - return nextSegmentOffset; - } - - public static NitfsMessage load(java.io.File file) throws java.io.IOException - { - validateImageFile(file); - - java.nio.ByteBuffer roBuffer = NitfsUtil.readEntireFile(file).asReadOnlyBuffer(); - - // check if it is a NITFS format file (NITF or NSIF - for NATO Secondary Imagery Format) - String fmtId = NitfsUtil.getString(roBuffer, 0, 4); - if( 0 != "NITF".compareTo(fmtId) && 0 != "NSIF".compareTo(fmtId)) - { - roBuffer = null; - throw new NitfsRuntimeException("NitfsReader.UnknownOrUnsupportedNitfsFormat", file.getCanonicalPath()); - } - - return new NitfsMessage(roBuffer); - } - - private static void validateImageFile(java.io.File file) - throws IOException, IllegalArgumentException, NitfsRuntimeException - { - if (null == file) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (!file.exists() || !file.canRead()) - throw new NitfsRuntimeException("NitfsReader.NoFileOrNoPermission", file.getCanonicalPath()); - } - - public static void main(String args[]) - { - String testImageFilename = "/depot/WorldWindJ/utils/gdal/020g222a.i42"; - - if(Configuration.isWindowsOS()) - testImageFilename = "C:\\depot\\WorldWindJ\\utils\\gdal\\020g222a.i42"; - - try - { - long startTime = System.currentTimeMillis(); - - NitfsMessage img = NitfsMessage.load(new File(testImageFilename)); - - System.out.println(MessageFormat.format("Image loaded in {0} mSec", (System.currentTimeMillis() - startTime))); - - System.out.println(img.fileHeader.getHeaderLength()); - System.out.println(img.fileHeader.getVersion()); - System.out.println(img.fileHeader.getComplexityLevel()); - System.out.println(img.fileHeader.getSpecialType()); - System.out.println(img.fileHeader.getOriginationStationId()); - System.out.println(img.fileHeader.getDateTime()); - System.out.println(img.fileHeader.getTitle()); - System.out.println(img.fileHeader.getFSCLAS()); - - System.out.println("HeaderLength=" + img.fileHeader.getHeaderLength()); - System.out.println("Total FileLength=" + img.fileHeader.getFileLength()); - - // System.out.println(); - } - catch (Exception e) - { - System.out.println(e.getMessage()); - e.printStackTrace(); - } - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsReservedExtensionSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsReservedExtensionSegment.java deleted file mode 100644 index c1e1605..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsReservedExtensionSegment.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsReservedExtensionSegment Mar 31, 2007 1:04:02 AM - */ -public class NitfsReservedExtensionSegment extends NitfsSegment -{ - public NitfsReservedExtensionSegment(java.nio.ByteBuffer buffer, int headerStartOffset, int headerLength, int dataStartOffset, int dataLength) - { - super(NitfsSegmentType.ReservedExtensionSegment, buffer, headerStartOffset, headerLength, dataStartOffset, dataLength); - - this.restoreBufferPosition(); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsRuntimeException.java b/gov/nasa/worldwind/formats/nitfs/NitfsRuntimeException.java deleted file mode 100644 index 0cf0454..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsRuntimeException.java +++ /dev/null @@ -1,56 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsRuntimeException Mar 31, 2007 7:41:31 AM - */ -public final class NitfsRuntimeException extends java.lang.RuntimeException -{ - public NitfsRuntimeException() - { - super(); - } - - public NitfsRuntimeException(String messageID) - { - super(WorldWind.retrieveErrMsg(messageID)); - log(this.getMessage()); - } - - public NitfsRuntimeException(String messageID, String params) - { - super(WorldWind.retrieveErrMsg(messageID) + params); - log(this.getMessage()); - } - - public NitfsRuntimeException(Throwable throwable) - { - super(throwable); - log(this.getMessage()); - } - - public NitfsRuntimeException(String messageID, Throwable throwable) - { - super(WorldWind.retrieveErrMsg(messageID), throwable); - log(this.getMessage()); - } - - public NitfsRuntimeException(String messageID, String params, Throwable throwable) - { - super(WorldWind.retrieveErrMsg(messageID) + params, throwable); - log(this.getMessage()); - } - - private void log(String s) - { - WorldWind.logger().log(java.util.logging.Level.FINE, s); - } -} \ No newline at end of file diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsSegment.java deleted file mode 100644 index 8b63253..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsSegment.java +++ /dev/null @@ -1,41 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsSegment.java Mar 21, 2007 5:44:57 PM lado - */ -public class NitfsSegment -{ - protected java.nio.ByteBuffer buffer; - protected NitfsSegmentType segmentType; - protected int savedBufferOffset; - - protected int headerStartOffset; - protected int headerLength; - protected int dataStartOffset; - protected int dataLength; - - public NitfsSegment(NitfsSegmentType segmentType, java.nio.ByteBuffer buffer, - int headerStartOffset, int headerLength, int dataStartOffset, int dataLength) - { - this.buffer = buffer; - this.segmentType = segmentType; - this.headerStartOffset = headerStartOffset; - this.headerLength = headerLength; - this.dataStartOffset = dataStartOffset; - this.dataLength = dataLength; - this.savedBufferOffset = buffer.position(); - } - - protected void restoreBufferPosition() - { - this.buffer.position(this.savedBufferOffset); - } -} - diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsSegmentType.java b/gov/nasa/worldwind/formats/nitfs/NitfsSegmentType.java deleted file mode 100644 index 3a6f028..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsSegmentType.java +++ /dev/null @@ -1,35 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsSegmentType Mar 29, 2007 6:33:57 PM lado - */ -public enum NitfsSegmentType -{ - ImageSegment (6, 10), - SymbolSegment (4, 6), - LabelSegment (4, 3), - TextSegment (4, 5), - DataExtensionSegment (4, 9), - ReservedExtensionSegment (4, 7), - UserDefinedHeaderSegment (0, 0), - ExtendedHeaderSegment (0, 0); - - private final int fieldHeaderLengthSize; - private final int fieldDataLengthSize; - - private NitfsSegmentType(int fieldHeaderLengthSize, int fieldDataLengthSize) - { - this.fieldHeaderLengthSize = fieldHeaderLengthSize; - this.fieldDataLengthSize = fieldDataLengthSize; - } - - public int getHeaderLengthSize() { return fieldHeaderLengthSize; } - public int getDataLengthSize() { return fieldDataLengthSize; } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsSymbolSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsSymbolSegment.java deleted file mode 100644 index 26fe331..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsSymbolSegment.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsSymbolSegment Mar 31, 2007 12:55:42 AM - */ -public class NitfsSymbolSegment extends NitfsSegment -{ - public NitfsSymbolSegment(java.nio.ByteBuffer buffer, int headerStartOffset, int headerLength, int dataStartOffset, int dataLength) - { - super(NitfsSegmentType.SymbolSegment, buffer, headerStartOffset, headerLength, dataStartOffset, dataLength); - - this.restoreBufferPosition(); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsTextSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsTextSegment.java deleted file mode 100644 index 5a5c8b8..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsTextSegment.java +++ /dev/null @@ -1,21 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsTextSegment Mar 31, 2007 12:59:42 AM - */ -class NitfsTextSegment extends NitfsSegment -{ - public NitfsTextSegment(java.nio.ByteBuffer buffer, int headerStartOffset, int headerLength, int dataStartOffset, int dataLength) - { - super(NitfsSegmentType.TextSegment, buffer, headerStartOffset, headerLength, dataStartOffset, dataLength); - - this.restoreBufferPosition(); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsUserDefinedHeaderSegment.java b/gov/nasa/worldwind/formats/nitfs/NitfsUserDefinedHeaderSegment.java deleted file mode 100644 index bdbf793..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsUserDefinedHeaderSegment.java +++ /dev/null @@ -1,30 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.formats.rpf.*; -import gov.nasa.worldwind.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsUserDefinedHeaderSegment Apr 4, 2007 6:07:10 PM lado - */ -public abstract class NitfsUserDefinedHeaderSegment extends NitfsSegment -{ - protected int overflow; - protected String dataTag; - - public NitfsUserDefinedHeaderSegment(java.nio.ByteBuffer buffer) - { - super(NitfsSegmentType.UserDefinedHeaderSegment, buffer, 0, 0, 0, 0); - - this.headerLength = Integer.parseInt(NitfsUtil.getString(buffer, 5)); - this.overflow = Integer.parseInt(NitfsUtil.getString(buffer, 3)); - this.dataTag = NitfsUtil.getString(buffer, 6); - this.dataLength = Integer.parseInt(NitfsUtil.getString(buffer, 5)); - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/NitfsUtil.java b/gov/nasa/worldwind/formats/nitfs/NitfsUtil.java deleted file mode 100644 index a89c087..0000000 --- a/gov/nasa/worldwind/formats/nitfs/NitfsUtil.java +++ /dev/null @@ -1,133 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; - -import gov.nasa.worldwind.*; - -import java.io.*; -import java.nio.channels.*; -import java.nio.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: NitfsUtil Mar 30, 2007 12:43:29 PM lado - */ -public class NitfsUtil -{ - public static String getString(java.nio.ByteBuffer buffer, int offset, int len) - { - String s = StringUtil.EMPTY; - if (null != buffer && buffer.capacity() >= offset + len) - { - byte[] dest = new byte[len]; - buffer.position(offset); - buffer.get(dest, 0, len); - s = new String(dest).trim(); - } - return s; - } - - public static String getString(java.nio.ByteBuffer buffer, int len) - { - String s = StringUtil.EMPTY; - if (null != buffer && buffer.remaining() >= len) - { - byte[] dest = new byte[len]; - buffer.get(dest, 0, len); - s = new String(dest).trim(); - } - return s; - } - - public static int getNumeric(java.nio.ByteBuffer buffer, int len) - { - String s = StringUtil.EMPTY; - if (null != buffer && buffer.remaining() >= len) - { - byte[] dest = new byte[len]; - buffer.get(dest, 0, len); - s = new String(dest); - } - return Integer.parseInt(s); - } - - public static short getShortNumeric(java.nio.ByteBuffer buffer, int len) - { - String s = StringUtil.EMPTY; - if (null != buffer && buffer.remaining() >= len) - { - byte[] dest = new byte[len]; - buffer.get(dest, 0, len); - s = new String(dest); - } - return (short) (0xFFFF & Integer.parseInt(s)); - } - - public static boolean getBoolean(java.nio.ByteBuffer buffer) - { - return !((byte) 0 == buffer.get()); // 0 = false, non-zero = true - } - - public static short getByteAsShort(java.nio.ByteBuffer buffer) - { - return (short) (0xFF & buffer.get()); - } - - public static int getUShort(java.nio.ByteBuffer buffer) - { - return 0xFFFF & buffer.getShort(); - } - - public static long getUInt(java.nio.ByteBuffer buffer) - { - return 0xFFFFFFFFL & (long) buffer.getInt(); - } - - private static final int PAGE_SIZE = 4096; - - - public static java.nio.ByteBuffer readEntireFile(java.io.File file) throws java.io.IOException - { - return NitfsUtil.memoryMapFile(file); - // return NitfsUtil.readFile(file); - } - - private static java.nio.ByteBuffer readFile(java.io.File file) throws java.io.IOException - { - java.io.FileInputStream fis = new java.io.FileInputStream(file); - java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(PAGE_SIZE); - java.nio.channels.ReadableByteChannel channel = java.nio.channels.Channels.newChannel(fis); - - int count = 0; - while (count >= 0) - { - count = channel.read(buffer); - if (count > 0 && !buffer.hasRemaining()) - { - java.nio.ByteBuffer biggerBuffer = java.nio.ByteBuffer.allocate(buffer.limit() + PAGE_SIZE); - biggerBuffer.put((java.nio.ByteBuffer) buffer.rewind()); - buffer = biggerBuffer; - } - } - - if (buffer != null) - buffer.flip(); - - return buffer; - } - - private static java.nio.ByteBuffer memoryMapFile(java.io.File file) throws IOException - { - FileChannel roChannel = new RandomAccessFile(file, "r").getChannel(); - long fileSize = roChannel.size(); - MappedByteBuffer mapFile = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize); - if (!mapFile.isLoaded()) - mapFile.load(); - roChannel.close(); - return mapFile; - } -} diff --git a/gov/nasa/worldwind/formats/nitfs/Rpf2DdsCompress.java b/gov/nasa/worldwind/formats/nitfs/Rpf2DdsCompress.java deleted file mode 100644 index 38498bf..0000000 --- a/gov/nasa/worldwind/formats/nitfs/Rpf2DdsCompress.java +++ /dev/null @@ -1,18 +0,0 @@ -package gov.nasa.worldwind.formats.nitfs; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: Rpf2DdsCompress Apr 23, 2007 10:56:39 AM lado - */ -interface Rpf2DdsCompress -{ - DDSBlock4x4 getDxt1TransparentBlock4x4 (); - void writeDxt1Header (java.nio.ByteBuffer buffer, int width, int height); - DDSBlock4x4 compressDxt1Block4x4 (NitfsImageBand imageBand, byte[] pixelCodes, boolean hasTransparentPixels ); -} diff --git a/gov/nasa/worldwind/formats/nmea/NmeaTrackPoint.java b/gov/nasa/worldwind/formats/nmea/NmeaTrackPoint.java index 61d3ec2..9b362d9 100644 --- a/gov/nasa/worldwind/formats/nmea/NmeaTrackPoint.java +++ b/gov/nasa/worldwind/formats/nmea/NmeaTrackPoint.java @@ -8,10 +8,11 @@ package gov.nasa.worldwind.formats.nmea; import gov.nasa.worldwind.tracks.TrackPoint; import gov.nasa.worldwind.util.Logging; +import gov.nasa.worldwind.geom.Position; /** * @author tag - * @version $Id: NmeaTrackPoint.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: NmeaTrackPoint.java 2815 2007-09-12 19:24:02Z tgaskins $ */ public class NmeaTrackPoint implements TrackPoint { @@ -161,6 +162,25 @@ public class NmeaTrackPoint implements TrackPoint this.longitude = longitude; } + public Position getPosition() + { + return Position.fromDegrees(this.latitude, this.longitude, this.altitude); + } + + public void setPosition(Position position) + { + if (position == null) + { + String msg = Logging.getMessage("nullValue.PositionIsNull"); + Logging.logger().severe(msg); + throw new IllegalArgumentException(msg); + } + + this.latitude = position.getLatitude().getDegrees(); + this.longitude = position.getLongitude().getDegrees(); + this.altitude = position.getElevation(); + } + public double getElevation() { return this.altitude + this.geoidHeight; diff --git a/gov/nasa/worldwind/formats/rpf/RpfColorMap.java b/gov/nasa/worldwind/formats/rpf/RpfColorMap.java deleted file mode 100644 index 675a447..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfColorMap.java +++ /dev/null @@ -1,111 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; -import java.nio.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author lado - * @version $Id: RpfColorMap Apr 2, 2007 9:43:32 PM - */ -public class RpfColorMap -{ - public int getTableID() - { - return tableID; - } - - public int getHistogramRecordLength() - { - return histogramRecordLength; - } - - public int getHistogramTableOffset() - { - return (int)(0xFFFFFFFFL & histogramTableOffset); - } - - public int getNumOfColorRecords() - { - return (int)(0xFFFFFFFFL & numOfColorRecords); - } - - public int getColorElementLength() - { - return (int)(0xFFFFFFFFL & colorElementLength); - } - - public byte getColor(int colorRec, int bytePosition) - { - long idx = colorRec * this.getNumOfColorRecords() * getColorElementLength() + bytePosition ; - return this.colorMap[(int)idx]; - } - - - - public byte[] getColorMap() - { - return this.colorMap; - } - - private byte[] colorMap; - // private byte[] histogramMap; - - private int tableID; - private long numOfColorRecords; - - private short colorElementLength; - private int histogramRecordLength; - private long colorTableOffset; - private long histogramTableOffset; - - public RpfColorMap(java.nio.ByteBuffer buffer, int colormapSubsectionOffset) - { - this.parseRpfColorOffsetRecord(buffer); - // now let's load color map and histogram - int saveOffset = buffer.position(); - this.loadColorMaps(buffer, colormapSubsectionOffset); - // ok, we can skip histogram for now - // this.loadHistogram(buffer, colormapSubsectionOffset); - buffer.position(saveOffset); - } - - private void parseRpfColorOffsetRecord(java.nio.ByteBuffer buffer) - { - this.tableID = NitfsUtil.getUShort(buffer); - this.numOfColorRecords = NitfsUtil.getUInt(buffer); - this.colorElementLength = NitfsUtil.getByteAsShort(buffer); - this.histogramRecordLength = NitfsUtil.getUShort(buffer); - this.colorTableOffset = NitfsUtil.getUInt(buffer); - this.histogramTableOffset = NitfsUtil.getUInt(buffer); - } - - private void loadColorMaps(java.nio.ByteBuffer buffer, int colormapSubsectionOffset) - { - if (0 == this.numOfColorRecords) - throw new NitfsRuntimeException("NitfsReader.InvalidNumberOfColorRecords"); - if (0 == this.colorElementLength) - throw new NitfsRuntimeException("NitfsReader.InvalidLengthOfColorRecordElement"); - - buffer.position((int) (colormapSubsectionOffset + this.colorTableOffset)); - int mapLength = (int)(this.numOfColorRecords * this.colorElementLength); - this.colorMap = new byte[mapLength]; - buffer.get(this.colorMap, 0, mapLength); - } - - private void loadHistogram(java.nio.ByteBuffer buffer, int colormapSubsectionOffset) - { - if (0 == this.numOfColorRecords) - throw new NitfsRuntimeException("NitfsReader.InvalidNumberOfColorRecords"); - if (0 == this.histogramRecordLength) - throw new NitfsRuntimeException("NitfsReader.InvalidLengthOfHistogramRecordElement"); - // skip the loading of the histogram table, just increment a position in the buffer - buffer.position((int) (colormapSubsectionOffset + this.histogramTableOffset - + (this.numOfColorRecords * this.histogramRecordLength))); - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfDataSeries.java b/gov/nasa/worldwind/formats/rpf/RpfDataSeries.java deleted file mode 100644 index 8c622ab..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfDataSeries.java +++ /dev/null @@ -1,198 +0,0 @@ -/* -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.formats.rpf; - -import gov.nasa.worldwind.*; - -import java.util.*; -import static java.util.logging.Level.*; - -/** - * @author dcollins - * @version $Id: RpfDataSeries.java 2127 2007-06-21 21:08:12Z dcollins $ - */ -public enum RpfDataSeries -{ - /* [Section 5.1.4, MIL-STD-2411-1] */ - DataSeriesGN("GN", "GNC", "1:5,000,000", "Global Navigation Chart", "CADRG", 5000000), - DataSeriesJN("JN", "JNC", "1:2,000,000", "Jet Navigation Chart", "CADRG", 2000000), - DataSeriesOH("OH", "VHRC", "1:1,000,000", "VFR Helicopter Route Chart", "CADRG", 1000000), - DataSeriesON("ON", "ONC", "1:1,000,000", "Operational Navigation Chart", "CADRG", 1000000), - DataSeriesOW("OW", "WAC", "1:1,000,000", "High Flying Chart - Host Nation", "CADRG", 1000000), - DataSeriesTP("TP", "TPC", "1:500,000", "Tactical Pilotage Chart", "CADRG", 500000), - DataSeriesLF("LF", "LFC-FR (Day)", "1:500,000", "Low Flying Chart (Day)- Host Nation", "CADRG", 500000), - DataSeriesL1("L1", "LFC-1", "1:500,000", "Low Flying Chart (TBD #1)", "CADRG", 500000), - DataSeriesL2("L2", "LFC-2", "1:500,000", "Low Flying Chart (TBD #2)", "CADRG", 500000), - DataSeriesL3("L3", "LFC-3", "1:500,000", "Low Flying Chart (TBD #3)", "CADRG", 500000), - DataSeriesL4("L4", "LFC-4", "1:500,000", "Low Flying Chart (TBD #4)", "CADRG", 500000), - DataSeriesL5("L5", "LFC-5", "1:500,000", "Low Flying Chart (TBD #5)", "CADRG", 500000), - DataSeriesLN("LN", "LFC (Night)", "1:500,000", "Low Flying Chart (Night) - Host Nation", "CADRG", 500000), - DataSeriesJG("JG", "JOG", "1:250,000", "Joint Operations Graphic", "CADRG", 250000), - DataSeriesJA("JA", "JOG-A", "1:250,000", "Joint Operations Graphic - Air", "CADRG", 250000), - DataSeriesJR("JR", "JOG-R", "1:250,000", "Joint Operations Graphic - Radar", "CADRG", 250000), - DataSeriesJO("JO", "OPG", "1:250,000", "Operational Planning Graphic", "CADRG", 250000), - DataSeriesVT("VT", "VTAC", "1:250,000", "VFR Terminal Area Chart", "CADRG", 250000), - DataSeriesF1("F1", "TFC-1", "1:250,000", "Transit Flying Chart (TBD #1)", "CADRG", 250000), - DataSeriesF2("F2", "TFC-2", "1:250,000", "Transit Flying Chart (TBD #2)", "CADRG", 250000), - DataSeriesF3("F3", "TFC-3", "1:250,000", "Transit Flying Chart (TBD #3)", "CADRG", 250000), - DataSeriesF4("F4", "TFC-4", "1:250,000", "Transit Flying Chart (TBD #4)", "CADRG", 250000), - DataSeriesF5("F5", "TFC-5", "1:250,000", "Transit Flying Chart (TBD #5)", "CADRG", 250000), - DataSeriesAT("AT", "ATC", "1:200,000", "Series 200 Air Target Chart", "CADRG", 200000), - DataSeriesVH("VH", "HRC", "1:125,000", "Helicopter Route Chart", "CADRG", 125000), - DataSeriesTN("TN", "TFC (Night)", "1:250,000", "Transit Flying Chart(Night)- Host nation", "CADRG", 250000), - DataSeriesTR("TR", "TLM200", "1:200,000", "Topographic Line Map 1:200,000 scale", "CADRG", 200000), - DataSeriesTC("TC", "TLM 100", "1:100,000", "Topographic Line Map 1:100,0000 scale", "CADRG", 100000), - DataSeriesRV("RV", "Riverine", "1:50,000", "Riverine Map 1:50,000 scale", "CADRG", 50000), - DataSeriesTL("TL", "TLM 50", "1:50,000", "Topographic Line Map", "CADRG", 50000), - DataSeriesUL("UL", "TLM50-Other", "1:50,000", "Topographic Line Map (other 1:50,000 scale)", "CADRG", 50000), - DataSeriesTT("TT", "TLM25", "1:25,000", "Topographic Line Map 1:25,000 scale", "CADRG", 25000), - DataSeriesTQ("TQ", "TLM24", "1:24,000", "Topographic Line Map 1:24,000 scale", "CADRG", 24000), -// DataSeriesHA("HA", "HA", "Various", "Harbor and Approach Charts", "CADRG", -1), -// DataSeriesCO("CO", "CO", "Various", "Coastal Charts", "CADRG", -1), -// DataSeriesOA("OA", "OPAREA", "Various", "Naval Range Operating Area Chart", "CADRG", -1), -// DataSeriesCG("CG", "CG", "Various", "City Graphics", "CADRG", -1), - DataSeriesC1("C1", "CG", "1:10,000", "City Graphics", "CADRG", 10000), - DataSeriesC2("C2", "CG", "1:10,560", "City Graphics", "CADRG", 10560), - DataSeriesC3("C3", "CG", "1:11,000", "City Graphics", "CADRG", 11000), - DataSeriesC4("C4", "CG", "1:11,800", "City Graphics", "CADRG", 11800), - DataSeriesC5("C5", "CG", "1:12,000", "City Graphics", "CADRG", 12000), - DataSeriesC6("C6", "CG", "1:12,500", "City Graphics", "CADRG", 12500), - DataSeriesC7("C7", "CG", "1:12,800", "City Graphics", "CADRG", 12800), - DataSeriesC8("C8", "CG", "1:14,000", "City Graphics", "CADRG", 14000), - DataSeriesC9("C9", "CG", "1:14,700", "City Graphics", "CADRG", 14700), - DataSeriesCA("CA", "CG", "1:15,000", "City Graphics", "CADRG", 15000), - DataSeriesCB("CB", "CG", "1:15,500", "City Graphics", "CADRG", 15500), - DataSeriesCC("CC", "CG", "1:16,000", "City Graphics", "CADRG", 16000), - DataSeriesCD("CD", "CG", "1:16,666", "City Graphics", "CADRG", 16666), - DataSeriesCE("CE", "CG", "1:17,000", "City Graphics", "CADRG", 17000), - DataSeriesCF("CF", "CG", "1:17,500", "City Graphics", "CADRG", 17500), - DataSeriesCH("CH", "CG", "1:18,000", "City Graphics", "CADRG", 18000), - DataSeriesCJ("CJ", "CG", "1:20,000", "City Graphics", "CADRG", 20000), - DataSeriesCK("CK", "CG", "1:21,000", "City Graphics", "CADRG", 21000), - DataSeriesCL("CL", "CG", "1:21,120", "City Graphics", "CADRG", 21120), - DataSeriesCN("CN", "CG", "1:22,000", "City Graphics", "CADRG", 22000), - DataSeriesCP("CP", "CG", "1:23,000", "City Graphics", "CADRG", 23000), - DataSeriesCQ("CQ", "CG", "1:25,000", "City Graphics", "CADRG", 25000), - DataSeriesCR("CR", "CG", "1:26,000", "City Graphics", "CADRG", 26000), - DataSeriesCS("CS", "CG", "1:35,000", "City Graphics", "CADRG", 35000), - DataSeriesCT("CT", "CG", "1:36,000", "City Graphics", "CADRG", 36000), -// DataSeriesCM("CM", "CM", "Various", "Combat Charts", "CADRG", -1), - DataSeriesA1("A1", "CM", "1:10,000", "Combat Charts, 1:10,000 scale", "CADRG", 10000), - DataSeriesA2("A2", "CM", "1:25,000", "Combat Charts, 1:25,000 scale", "CADRG", 25000), - DataSeriesA3("A3", "CM", "1:50,000", "Combat Charts, 1:50,000 scale", "CADRG", 50000), - DataSeriesA4("A4", "CM", "1:100,000", "Combat Charts, 1:100,000 scale", "CADRG", 100000), - DataSeriesMI("MI", "MIM", "1:50,000", "Military Installation Maps", "CADRG", 50000), -// DataSeriesM1("M1", "MIM", "Various", "Military Installation Map (TBD #1)", "CADRG", -1), -// DataSeriesM2("M2", "MIM", "Various", "Military Installation Map (TBD #2)", "CADRG", -1), - DataSeriesVN("VN", "VNC", "1:500,000", "Visual Navigation Charts", "CADRG", 500000), - DataSeriesMM("MM", "---", "Various", "(Miscellaneous Maps & Charts)", "CADRG", 12500), - DataSeriesI1("I1", "---", "10m", "Imagery, 10 meter resolution", "CIB", 10.0), - DataSeriesI2("I2", "---", "5m", "Imagery, 5 meter resolution", "CIB", 5.0), - DataSeriesI3("I3", "---", "2m", "Imagery, 2 meter resolution", "CIB", 2.0), - DataSeriesI4("I4", "---", "1m", "Imagery, 1 meter resolution", "CIB", 1.0), - DataSeriesI5("I5", "---", ".5m", "Imagery, .5 (half) meter resolution", "CIB", 0.5), -// DataSeriesIV("IV", "---", "Various>10m", "Imagery, greater than 10 meter resolution", "CIB", -1), - /* [Chart.php] */ - DataSeriesTF("TF", "---", "1:250000", "Transit Fly (UK)", "CADRG", 250000),; - - public final String seriesCode; - public final String seriesAbbreviation; - public final String scaleOrResolution; - public final String dataSeries; - public final String rpfDataType; - public final double scaleOrGSD; - - private RpfDataSeries(String seriesCode, String seriesAbbreviation, String scaleOrResolution, String dataSeries, - String rpfDataType, double scaleOrGSD) - { - if (rpfDataType == null) - { - String message = WorldWind.retrieveErrMsg("RpfDataSeries.InavlidRpfDataType") + rpfDataType; - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - if (scaleOrGSD <= 0) - { - String message = WorldWind.retrieveErrMsg("RpfDataSeries.InvalidScaleOrGSD") + scaleOrGSD; - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - - String validDataType = null; - for (String validType : validDataTypes()) - { - if (validType.equalsIgnoreCase(rpfDataType)) - validDataType = validType; - } - if (validDataType == null) - { - String message = WorldWind.retrieveErrMsg("RpfDataSeries.InavlidRpfDataType") + rpfDataType; - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - - this.rpfDataType = validDataType; - this.seriesCode = seriesCode; - this.seriesAbbreviation = seriesAbbreviation; - this.scaleOrResolution = scaleOrResolution; - this.dataSeries = dataSeries; - this.scaleOrGSD = scaleOrGSD; - } - - private static Map enumConstantDirectory = null; - - private static Map enumConstantDirectory() - { - if (enumConstantDirectory == null) - { - RpfDataSeries[] universe = RpfDataSeries.class.getEnumConstants(); - enumConstantDirectory = new HashMap(2 * universe.length); - for (RpfDataSeries dataSeries : universe) - { - enumConstantDirectory.put(dataSeries.seriesCode, dataSeries); - } - } - return enumConstantDirectory; - } - - public static RpfDataSeries dataSeriesFor(String seriesCode) - { - if (seriesCode == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - RpfDataSeries dataSeries = enumConstantDirectory().get(seriesCode); - if (dataSeries == null) - { - String message = WorldWind.retrieveErrMsg("generic.EnumNotFound") + seriesCode; - WorldWind.logger().log(FINE, message); - throw new EnumConstantNotPresentException(RpfDataSeries.class, message); - } - return dataSeries; - } - - public static boolean isDataSeriesCode(String seriesCode) - { - if (seriesCode == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - return enumConstantDirectory().get(seriesCode) != null; - } - - public static String[] validDataTypes = null; - - public static String[] validDataTypes() - { - if (validDataTypes == null) - validDataTypes = new String[] {"CADRG", "CIB"}; - return validDataTypes; - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFile.java b/gov/nasa/worldwind/formats/rpf/RpfFile.java deleted file mode 100644 index e00ad6b..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFile.java +++ /dev/null @@ -1,42 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; - -import java.io.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author lado - * @version $Id: RpfFile Apr 8, 2007 8:53:48 AM - */ -public class RpfFile -{ - private NitfsMessage nitfsMsg; - private java.io.File rpfFile; - - public File getFile() - { - return this.rpfFile; - } - - public NitfsFileHeader getNitfsFileHeader() - { - return (null != nitfsMsg) ? nitfsMsg.getNitfsFileHeader() : null; - } - - public NitfsSegment getNitfsSegment(NitfsSegmentType segmentType) - { - return (null != nitfsMsg) ? nitfsMsg.getSegment(segmentType) : null; - } - - protected RpfFile(java.io.File rpfFile) throws IOException - { - this.rpfFile = rpfFile; - this.nitfsMsg = NitfsMessage.load(rpfFile); - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFileComponents.java b/gov/nasa/worldwind/formats/rpf/RpfFileComponents.java deleted file mode 100644 index b35a935..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFileComponents.java +++ /dev/null @@ -1,44 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: RpfFileComponents Apr 4, 2007 5:53:04 PM lado - */ -public class RpfFileComponents -{ - private java.nio.ByteBuffer buffer; - - private RpfHeaderSection headerSection; - private RpfLocationSection locationSection; - - public RpfFileComponents(java.nio.ByteBuffer buffer) - { - this.buffer = buffer; - this.headerSection = new RpfHeaderSection(buffer); - - buffer.position(this.headerSection.locationSectionLocation); - this.locationSection = new RpfLocationSection(buffer); - - } - - public RpfHeaderSection getRpfHeaderSection() - { - return this.headerSection; - } - - public RpfFrameFileIndexSection getRpfFrameFileIndexSection() - { - if( 0 < locationSection.getFrameFileIndexSectionSubheaderLength()) - { - this.buffer.position(locationSection.getFrameFileIndexSectionSubheaderLocation()); - return new RpfFrameFileIndexSection(buffer); - } - return null; - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFrameFileComponents.java b/gov/nasa/worldwind/formats/rpf/RpfFrameFileComponents.java deleted file mode 100644 index c9df4bb..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFrameFileComponents.java +++ /dev/null @@ -1,166 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; -import gov.nasa.worldwind.geom.*; - -import java.nio.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author lado - * @version $Id: RpfFrameFileComponents Mar 31, 2007 10:06:22 PM - */ -public class RpfFrameFileComponents -{ - public static final String DATA_TAG = "RPFIMG"; - - // [ rpf location section ] - public RpfLocationSection componentLocationTable; - - // [ rpf coverage section ] - public LatLon nwUpperLeft, swLowerleft, neUpperRight, seLowerRight; - public double verticalResolutionNorthSouth; - public double horizontalResolutionEastWest; - public double verticalIntervalLatitude; - public double horizontalIntervalLongitude; - - // [ color / grayscale section ] - public RpfColorMap[] rpfColorMaps; - - // [ rpf color / grayscale section ] - public short numOfColorGrayscaleOffsetRecords; - public short numOfColorConverterOffsetRecords; - public String externalColorGrayscaleFilename; - // [ rpf colormap subsection ] - public long colormapOffsetTableOffset; - public int colormapGrayscaleOffsetRecordLength; - - // [ rpf color converter subsection ] - - // [ rpf image description subheader ] - public int numOfSpectralGroups; - public int numOfSubframeTables; - public int numOfSpectralBandTables; - public int numOfSpectralBandLinesPerImageRow; - public int numOfSubframesInEastWestDirection; - public int numOfSubframesInNorthSouthDirection; - public long numOfOutputColumnsPerSubframe; - public long numOfOutputRowsPerSubframe; - public long subframeMaskTableOffset; - public long transparencyMaskTableOffset; - - // [ rpf related images section ] - public RelatedImagesSection relatedImagesSection = null; - - public RpfFrameFileComponents(java.nio.ByteBuffer buffer) - { - this.componentLocationTable = new RpfLocationSection(buffer); - - if (0 < this.componentLocationTable.getCoverageSectionSubheaderLength()) - this.parseRpfCoverageSection(buffer); - - if (0 < this.componentLocationTable.getColorGrayscaleSectionSubheaderLength()) - this.parseColorGrayscaleSection(buffer); - - if (0 < this.componentLocationTable.getColormapSubsectionLength()) - this.parseColormapSubSection(buffer); - - if (0 < this.componentLocationTable.getColorConverterSubsectionLength()) - this.parseColorConverterSubsection(buffer); - - if (0 < this.componentLocationTable.getImageDescriptionSubheaderLength()) - { - buffer.position(this.componentLocationTable.getImageDescriptionSubheaderLocation()); - this.parseImageDescriptionSubheader(buffer); - } - if (0 < this.componentLocationTable.getRelatedImagesSectionSubheaderLength()) - { - buffer.position(this.componentLocationTable.getRelatedImagesSectionSubheaderLocation()); - this.relatedImagesSection = new RelatedImagesSection(buffer); - } - } - - private void parseImageDescriptionSubheader(java.nio.ByteBuffer buffer) - { - this.numOfSpectralGroups = NitfsUtil.getUShort(buffer); - this.numOfSubframeTables = NitfsUtil.getUShort(buffer); - this.numOfSpectralBandTables = NitfsUtil.getUShort(buffer); - this.numOfSpectralBandLinesPerImageRow = NitfsUtil.getUShort(buffer); - this.numOfSubframesInEastWestDirection = NitfsUtil.getUShort(buffer); - this.numOfSubframesInNorthSouthDirection = NitfsUtil.getUShort(buffer); - this.numOfOutputColumnsPerSubframe = NitfsUtil.getUInt(buffer); - this.numOfOutputRowsPerSubframe = NitfsUtil.getUInt(buffer); - this.subframeMaskTableOffset = NitfsUtil.getUInt(buffer); - this.transparencyMaskTableOffset = NitfsUtil.getUInt(buffer); - } - - private void parseColorConverterSubsection(java.nio.ByteBuffer buffer) - { - buffer.position(this.componentLocationTable.getColorConverterSubsectionLocation()); -// if (0 < this.numOfColorConverterOffsetRecords) -// throw new NitfsRuntimeException("NitfsReader.NotImplemented.ColorConvertorSubsectionReader"); - } - - private void parseColormapSubSection(java.nio.ByteBuffer buffer) - { - buffer.position(this.componentLocationTable.getColormapSubsectionLocation()); - - this.colormapOffsetTableOffset = NitfsUtil.getUInt(buffer); - this.colormapGrayscaleOffsetRecordLength = NitfsUtil.getUShort(buffer); - // read color / grayscale AND histogram records; builds a ColorMap (LUT) - if (0 < this.numOfColorGrayscaleOffsetRecords) - { - rpfColorMaps = new RpfColorMap[this.numOfColorGrayscaleOffsetRecords]; - for (int i = 0; i < this.numOfColorGrayscaleOffsetRecords; i++) - { - rpfColorMaps[i] = new RpfColorMap(buffer, this.componentLocationTable.getColormapSubsectionLocation()); - } - } - else - throw new NitfsRuntimeException("NitfsReader.InvalidNumberOfRpfColorGrayscaleRecords"); - } - - private void parseColorGrayscaleSection(java.nio.ByteBuffer buffer) - { - buffer.position(this.componentLocationTable.getColorGrayscaleSectionSubheaderLocation()); - - this.numOfColorGrayscaleOffsetRecords = NitfsUtil.getByteAsShort(buffer); - this.numOfColorConverterOffsetRecords = NitfsUtil.getByteAsShort(buffer); - this.externalColorGrayscaleFilename = NitfsUtil.getString(buffer, 12); - } - - private void parseRpfCoverageSection(java.nio.ByteBuffer buffer) - { - buffer.position(this.componentLocationTable.getCoverageSectionSubheaderLocation()); - - this.nwUpperLeft = LatLon.fromDegrees(buffer.getDouble(), buffer.getDouble()); - this.swLowerleft = LatLon.fromDegrees(buffer.getDouble(), buffer.getDouble()); - this.neUpperRight = LatLon.fromDegrees(buffer.getDouble(), buffer.getDouble()); - this.seLowerRight = LatLon.fromDegrees(buffer.getDouble(), buffer.getDouble()); - - this.verticalResolutionNorthSouth = buffer.getDouble(); - this.horizontalResolutionEastWest = buffer.getDouble(); - this.verticalIntervalLatitude = buffer.getDouble(); - this.horizontalIntervalLongitude = buffer.getDouble(); - } - - public class RelatedImagesSection - { - // [ rpf related images section subheader ] - public long relatedImageDescriptionTableOffset; - public int numOfRelatedImageDescriptionRecords; - public int relatedImageDescriptionRecordLength; - - public RelatedImagesSection(java.nio.ByteBuffer buffer) - { - this.relatedImageDescriptionTableOffset = NitfsUtil.getUInt(buffer); - this.numOfRelatedImageDescriptionRecords = NitfsUtil.getUShort(buffer); - this.relatedImageDescriptionRecordLength = NitfsUtil.getUShort(buffer); - } - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFrameFileIndexSection.java b/gov/nasa/worldwind/formats/rpf/RpfFrameFileIndexSection.java deleted file mode 100644 index 9724bcc..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFrameFileIndexSection.java +++ /dev/null @@ -1,193 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; -import gov.nasa.worldwind.*; - -import java.util.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: RpfFileIndexSection Apr 4, 2007 6:32:20 PM lado - */ -public class RpfFrameFileIndexSection -{ - // [ frame file index section subheader ] - private String highestSecurityClassification; - private long frameFileIndexTableOffset; - private long numOfFrameFileIndexRecords; - private int numOfPathnameRecords; - private int frameFileIndexRecordLength; - - // [ frame file index subsection ] - - // [ frame file index table ] - private ArrayList frameFileIndexTable = new ArrayList(); - // [ pathname table ] - // private ArrayList pathnameTable = new ArrayList(); - - - public String getHighestSecurityClassification() - { - return highestSecurityClassification; - } - - public long getFrameFileIndexTableOffset() - { - return frameFileIndexTableOffset; - } - - public long getNumOfFrameFileIndexRecords() - { - return numOfFrameFileIndexRecords; - } - - public int getNumOfPathnameRecords() - { - return numOfPathnameRecords; - } - - public int getFrameFileIndexRecordLength() - { - return frameFileIndexRecordLength; - } - - public ArrayList getFrameFileIndexTable() - { - return frameFileIndexTable; - } - -// public ArrayList getPathnameTable() -// { -// return pathnameTable; -// } - - public RpfFrameFileIndexSection(java.nio.ByteBuffer buffer) - { - // [ frame file index section subheader ] - this.highestSecurityClassification = NitfsUtil.getString(buffer, 1); - this.frameFileIndexTableOffset = NitfsUtil.getUInt(buffer); - this.numOfFrameFileIndexRecords = NitfsUtil.getUInt(buffer); - this.numOfPathnameRecords = NitfsUtil.getUShort(buffer); - this.frameFileIndexRecordLength = NitfsUtil.getUShort(buffer); - - this.parseFrameFileIndexAndPathnameTables( buffer ); - } - - private void parseFrameFileIndexAndPathnameTables(java.nio.ByteBuffer buffer) - { - int theSectionOffset = buffer.position(); - Hashtable pathnames = new Hashtable(); - - for(int i = 0 ; i < this.numOfFrameFileIndexRecords; i++) - this.frameFileIndexTable.add(new RpfFrameFileIndexRecord(buffer)); - - for(int i = 0 ; i < this.numOfPathnameRecords; i++) - { - int relOffset = buffer.position() - theSectionOffset; - int len = NitfsUtil.getUShort(buffer); - pathnames.put(relOffset, NitfsUtil.getString(buffer, len)); - } - - if(0 < this.frameFileIndexTable.size() && 0 < pathnames.size()) - { // update pathname field in every RpfFrameFileIndexRecord - for (RpfFrameFileIndexRecord rec : this.frameFileIndexTable) - { - int offset = (int) rec.getPathnameRecordOffset(); - if (pathnames.containsKey(offset)) - rec.setPathname(pathnames.get(offset)); - else - throw new NitfsRuntimeException("NitfsReader.CorrespondingPathnameWasNotFound"); - } - } - } - - public class RpfFrameFileIndexRecord - { - public int getBoundaryRectangleRecordNumber() - { - return boundaryRectangleRecordNumber; - } - - public int getFrameLocationRowNumber() - { - return frameLocationRowNumber; - } - - public int getFrameLocationColumnNumber() - { - return frameLocationColumnNumber; - } - - public String getFrameFileName() - { - return frameFileName; - } - - public String getGeoLocation() - { - return geoLocation; - } - - public String getSecurityClass() - { - return securityClass; - } - - public String getSecurityCountryCode() - { - return securityCountryCode; - } - - public String getSecurityReleaseMark() - { - return securityReleaseMark; - } - - public long getPathnameRecordOffset() - { - return pathnameRecordOffset; - } - - public String getPathname() - { - return pathname; - } - - public void setPathname(String pathname) - { - this.pathname = pathname; - } - - private int boundaryRectangleRecordNumber; - private int frameLocationRowNumber; - private int frameLocationColumnNumber; - private long pathnameRecordOffset; - private String frameFileName; - private String geoLocation; - private String securityClass; - private String securityCountryCode; - private String securityReleaseMark; - private String pathname; // this field is not part of the NITFS spec - - - public RpfFrameFileIndexRecord(java.nio.ByteBuffer buffer) - { - this.boundaryRectangleRecordNumber = NitfsUtil.getUShort(buffer); - this.frameLocationRowNumber = NitfsUtil.getUShort(buffer); - this.frameLocationColumnNumber = NitfsUtil.getUShort(buffer); - this.pathnameRecordOffset = NitfsUtil.getUInt(buffer); - this.frameFileName = NitfsUtil.getString(buffer, 12); - this.geoLocation = NitfsUtil.getString(buffer, 6); - this.securityClass = NitfsUtil.getString(buffer, 1); - this.securityCountryCode = NitfsUtil.getString(buffer, 2); - this.securityReleaseMark = NitfsUtil.getString(buffer, 2); - this.pathname = StringUtil.EMPTY; - } - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFrameFilenameFormatException.java b/gov/nasa/worldwind/formats/rpf/RpfFrameFilenameFormatException.java deleted file mode 100644 index e0cc117..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFrameFilenameFormatException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* -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.formats.rpf; - -/** - * @author dcollins - * @version $Id: RpfFrameFilenameFormatException.java 1762 2007-05-07 19:43:55Z dcollins $ - */ -public class RpfFrameFilenameFormatException extends IllegalArgumentException -{ - public RpfFrameFilenameFormatException() - { - } - - public RpfFrameFilenameFormatException(String message) - { - super(message); - } - - public RpfFrameFilenameFormatException(String message, Throwable cause) - { - super(message, cause); - } - - public RpfFrameFilenameFormatException(Throwable cause) - { - super(cause); - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFrameFilenameUtil.java b/gov/nasa/worldwind/formats/rpf/RpfFrameFilenameUtil.java deleted file mode 100644 index 346918f..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFrameFilenameUtil.java +++ /dev/null @@ -1,222 +0,0 @@ -/* -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.formats.rpf; - -import gov.nasa.worldwind.*; - -import static java.util.logging.Level.*; - -/** - * @author dcollins - * @version $Id: RpfFrameFilenameUtil.java 1894 2007-05-29 00:15:15Z dcollins $ - */ -public class RpfFrameFilenameUtil -{ - /* [Section 30.6, MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - private static final char[] BASE34_ALPHABET = - {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; - private static final char[] filenameArray = new char[12]; - - /* [Section 30.6, MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - private static char[] base34ValueOf(int i, char[] dest, int offset, int count) - { - if (dest == null || dest.length < count) - dest = new char[count]; - for (int digit = count + offset - 1; digit >= offset; digit--) - { - dest[digit] = BASE34_ALPHABET[i % 34]; - i /= 34; - } - return dest; - } - - public static String filenameFor(RpfFrameProperties frameProperties) - { - if (frameProperties == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfFramePropertiesIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - filenameFor(frameProperties, filenameArray); - return new String(filenameArray, 0, 12); - } - - /* [Section 30.6, MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - private static void filenameFor(RpfFrameProperties frameProperties, char[] dest) - { - int frameChars; - int versionChars; - if (frameProperties.dataSeries.rpfDataType.compareToIgnoreCase("CADRG") == 0) - { - frameChars = 5; - versionChars = 2; - } - else if (frameProperties.dataSeries.rpfDataType.compareToIgnoreCase("CIB") == 0) - { - frameChars = 6; - versionChars = 1; - } - else - { - String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.UnknownRpfDataType") - + frameProperties.dataSeries.rpfDataType; - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - base34ValueOf(frameProperties.frameNumber, dest, 0, frameChars); - base34ValueOf(frameProperties.version, dest, frameChars, versionChars); - dest[7] = frameProperties.producer.id; - dest[8] = '.'; - frameProperties.dataSeries.seriesCode.getChars(0, 2, dest, 9); - dest[11] = frameProperties.zone.zoneCode; - } - - private static boolean isBase34(char[] src, int offset, int count) - { - for (int digit = offset; digit < offset + count; digit++) - { - char charUpper = Character.toUpperCase(src[digit]); - if (!(charUpper >= '0' && charUpper <= '9') - && !(charUpper >= 'A' && charUpper <= 'H') - && !(charUpper >= 'J' && charUpper <= 'N') - && !(charUpper >= 'P' && charUpper <= 'Z')) - return false; - } - return true; - } - - /* [Section 30.6, MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - private static int parseBase34(char[] src, int offset, int count) - { - int i = 0; - for (int digit = offset; digit < offset + count; digit++) - { - int index; - char charUpper = Character.toUpperCase(src[digit]); - if (charUpper >= '0' && charUpper <= '9') - index = charUpper - '0'; - else if (charUpper >= 'A' && charUpper <= 'H') - index = 10 + charUpper - 'A'; - else if (charUpper >= 'J' && charUpper <= 'N') - index = 18 + charUpper - 'J'; - else if (charUpper >= 'P' && charUpper <= 'Z') - index = 23 + charUpper - 'P'; - else - { - String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.Base34Error"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - i = (i * 34) + index; - } - return i; - } - - public static boolean isRpfFilename(String filename) - { - if (filename == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - - if (filename.length() != 12) - return false; - filename.getChars(0, 12, filenameArray, 0); - - if (!isBase34(filenameArray, 0, 7)) - return false; - if (!RpfProducer.isProducerId(filenameArray[7])) - return false; - if ('.' != filenameArray[8]) - return false; - String seriesCode = filename.substring(9, 11); - if (!RpfDataSeries.isDataSeriesCode(seriesCode)) - return false; - if (!RpfZone.isZoneCode(filenameArray[11])) - return false; - - return true; - } - - /* [Section 30.6, MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - public static RpfFrameProperties parseFilename(String filename) - { - if (filename == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.StringIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - if (filename.length() != 12) - { - String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.BadFilenameLength") + filename; - WorldWind.logger().log(FINE, message); - throw new RpfFrameFilenameFormatException(message); - } - filename.getChars(0, 12, filenameArray, 0); - - RpfProducer producer; - RpfDataSeries dataSeries; - RpfZone zone; - try - { - producer = RpfProducer.producerFor(filenameArray[7]); - dataSeries = RpfDataSeries.dataSeriesFor(filename.substring(9, 11)); - zone = RpfZone.zoneFor(filenameArray[11]); - } - catch (EnumConstantNotPresentException e) - { - String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.EnumNotFound"); - WorldWind.logger().log(FINE, message); - throw new RpfFrameFilenameFormatException(message, e); - } - - int frameChars; - int versionChars; - if (dataSeries.rpfDataType.compareToIgnoreCase("CADRG") == 0) - { - frameChars = 5; - versionChars = 2; - } - else if (dataSeries.rpfDataType.compareToIgnoreCase("CIB") == 0) - { - frameChars = 6; - versionChars = 1; - } - else - { - String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.UnknownRpfDataType") - + dataSeries.rpfDataType; - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - - int frameNumber; - int version; - try - { - frameNumber = parseBase34(filenameArray, 0, frameChars); - version = parseBase34(filenameArray, frameChars, versionChars); - } - catch (IllegalArgumentException e) - { - String message = WorldWind.retrieveErrMsg("RpfFrameFilenameUtil.IntegerNotParsed"); - WorldWind.logger().log(FINE, message); - throw new RpfFrameFilenameFormatException(message, e); - } - - return new RpfFrameProperties(zone, frameNumber, dataSeries, producer, version); - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFrameProperties.java b/gov/nasa/worldwind/formats/rpf/RpfFrameProperties.java deleted file mode 100644 index 75100e4..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFrameProperties.java +++ /dev/null @@ -1,119 +0,0 @@ -/* -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.formats.rpf; - -import gov.nasa.worldwind.*; - -import java.util.logging.Level; - -/** - * @author dcollins - * @version $Id: RpfFrameProperties.java 1895 2007-05-29 00:15:40Z dcollins $ - */ -public class RpfFrameProperties -{ - public final RpfZone zone; - public final int frameNumber; - public final RpfDataSeries dataSeries; - public final RpfProducer producer; - public final int version; - - public RpfFrameProperties(RpfZone zone, int frameNumber, RpfDataSeries dataSeries, RpfProducer producer, - int version) - { - if (zone == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfZoneIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (frameNumber < 0) - { - String message = WorldWind.retrieveErrMsg("RpfFrameProperties.BadFrameNumber") - + frameNumber; - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (dataSeries == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfDataSeriesIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (producer == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfProducerIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - if (version < 0) - { - String message = WorldWind.retrieveErrMsg("RpfFrameProperties.BadVersion") - + version; - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.zone = zone; - this.frameNumber = frameNumber; - this.dataSeries = dataSeries; - this.producer = producer; - this.version = version; -// this.hashCode = this.computeHash(); - } - - private int computeHash() - { - int hash = 0; - if (this.zone != null) - hash = 29 * hash + this.zone.hashCode(); - if (this.dataSeries != null) - hash = 29 * hash + this.dataSeries.hashCode(); - if (this.producer != null) - hash = 29 * hash + producer.hashCode(); - hash = 29 * hash + version; - hash = 29 * hash + frameNumber; - return hash; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || o.getClass() != this.getClass()) - return false; - final RpfFrameProperties that = (RpfFrameProperties) o; - if (this.zone != that.zone) - return false; - if (this.frameNumber != that.frameNumber) - return false; - if (this.dataSeries != that.dataSeries) - return false; - if (this.producer != that.producer) - return false; - if (this.version != that.version) - return false; - return true; - } - - public int hashCode() - { - return this.computeHash(); - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(this.getClass().getName()); - sb.append('['); - sb.append("zone=").append(this.zone); - sb.append(", frameNumber=").append(this.frameNumber); - sb.append(", dataSeries=").append(this.dataSeries); - sb.append(", producer=").append(this.producer); - sb.append(", version=").append(this.version); - sb.append(']'); - return sb.toString(); - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfFramePropertyType.java b/gov/nasa/worldwind/formats/rpf/RpfFramePropertyType.java deleted file mode 100644 index a506a55..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfFramePropertyType.java +++ /dev/null @@ -1,68 +0,0 @@ -/* -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.formats.rpf; - -/** - * @author dcollins - * @version $Id: RpfFramePropertyType.java 1762 2007-05-07 19:43:55Z dcollins $ - */ -public enum RpfFramePropertyType -{ - DataSeries(RpfDataSeries.class) - { - public Object getInstance(RpfFrameProperties frameProperties) - { - if (frameProperties == null) - return null; - return frameProperties.dataSeries; - } - }, - FrameNumber(Integer.class) - { - public Object getInstance(RpfFrameProperties frameProperties) - { - if (frameProperties == null) - return null; - return frameProperties.frameNumber; - } - }, - Producer(RpfProducer.class) - { - public Object getInstance(RpfFrameProperties frameProperties) - { - if (frameProperties == null) - return null; - return frameProperties.producer; - } - }, - Version(Integer.class) - { - public Object getInstance(RpfFrameProperties frameProperties) - { - if (frameProperties == null) - return null; - return frameProperties.version; - } - }, - Zone(RpfZone.class) - { - public Object getInstance(RpfFrameProperties frameProperties) - { - if (frameProperties == null) - return null; - return frameProperties.zone; - } - }; - - public final Class classType; - - private RpfFramePropertyType(Class classType) - { - this.classType = classType; - } - - public abstract Object getInstance(RpfFrameProperties frameProperties); -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfHeaderSection.java b/gov/nasa/worldwind/formats/rpf/RpfHeaderSection.java deleted file mode 100644 index e18f21f..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfHeaderSection.java +++ /dev/null @@ -1,43 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: RpfHeaderSection Apr 4, 2007 4:37:01 PM lado - */ -class RpfHeaderSection -{ - public static final String DATA_TAG = "RPFHDR"; - - public boolean endianIndicator; - public short headerLength; - public String filename; - public short updateIndicator; // new | replacement | update - public String govSpecNumber; - public String govSpecDate; - public String securityClass; - public String securityCountryCode; - public String securityReleaseMark; - public int locationSectionLocation; - - public RpfHeaderSection(java.nio.ByteBuffer buffer) - { - this.endianIndicator = ((byte) 0 != buffer.get()); // reads 1 byte, 0 for big endian - this.headerLength = buffer.getShort(); // reads 2 bytes - this.filename = NitfsUtil.getString(buffer, 12); - this.updateIndicator = NitfsUtil.getByteAsShort(buffer); // reads 1 byte (short) - this.govSpecNumber = NitfsUtil.getString(buffer, 15); - this.govSpecDate = NitfsUtil.getString(buffer, 8); - this.securityClass = NitfsUtil.getString(buffer, 1); - this.securityCountryCode = NitfsUtil.getString(buffer, 2); - this.securityReleaseMark = NitfsUtil.getString(buffer, 2); - this.locationSectionLocation = buffer.getInt(); // read 4 bytes (int) - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfImageFile.java b/gov/nasa/worldwind/formats/rpf/RpfImageFile.java deleted file mode 100644 index d641127..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfImageFile.java +++ /dev/null @@ -1,188 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; -import gov.nasa.worldwind.*; - -import java.io.*; -import java.text.*; -import java.awt.image.*; - -import java.awt.*; -import java.awt.image.*; -import java.io.*; -import java.net.*; -import java.nio.*; -import javax.imageio.*; -import javax.swing.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author lado - * @version $Id: RpfImageFile Apr 8, 2007 8:51:57 AM - */ -public class RpfImageFile extends RpfFile -{ - private NitfsImageSegment imageSegment = null; - private UserDefinedImageSubheader imageSubheader = null; - private RpfFrameFileComponents rpfFrameFileComponents = null; - - public RpfFrameFileComponents getRpfFrameFileComponents() - { - return this.rpfFrameFileComponents; - } - - public UserDefinedImageSubheader getImageSubheader() - { - return this.imageSubheader; - } - - public NitfsImageSegment getImageSegment() - { - return this.imageSegment; - } - - - - private RpfImageFile(java.io.File rpfFile) throws java.io.IOException, NitfsRuntimeException - { - super(rpfFile); - - this.imageSegment = (NitfsImageSegment) this.getNitfsSegment(NitfsSegmentType.ImageSegment); - this.validateRpfImage(); - - this.imageSubheader = this.imageSegment.getUserDefinedImageSubheader(); - this.rpfFrameFileComponents = this.imageSubheader.getRpfFrameFileComponents(); - } - - private void validateRpfImage() throws NitfsRuntimeException - { - if ( null == this.imageSegment ) - throw new NitfsRuntimeException("NitfsReader.ImageSegmentWasNotFound"); - if( null == this.imageSegment.getUserDefinedImageSubheader()) - throw new NitfsRuntimeException("NitfsReader.UserDefinedImageSubheaderWasNotFound"); - if( null == this.imageSegment.getUserDefinedImageSubheader().getRpfFrameFileComponents()) - throw new NitfsRuntimeException("NitfsReader.RpfFrameFileComponentsWereNotFoundInUserDefinedImageSubheader"); - } - - public int[] getImagePixelsAsArray(int[] dest, RpfImageType imageType) - { - IntBuffer buffer = IntBuffer.wrap(dest); - this.getImagePixelsAsBuffer(buffer, imageType); - return dest; - } - - public ByteBuffer getImageAsDdsTexture() - { - if (null != this.imageSegment) - return this.imageSegment.getImageAsDdsTexture(); - return null; - } - - - public IntBuffer getImagePixelsAsBuffer(IntBuffer dest, RpfImageType imageType) - { - if (null != this.imageSegment) - this.imageSegment.getImagePixelsAsArray(dest, imageType); - return dest; - } - - public BufferedImage getBufferedImage() - { - if (null == this.imageSegment) - return null; - - BufferedImage bimage = new BufferedImage( - this.getImageSegment().numSignificantCols, - this.getImageSegment().numSignificantRows, - BufferedImage.TYPE_INT_ARGB); - - WritableRaster raster = bimage.getRaster(); - java.awt.image.DataBufferInt dataBuffer = (java.awt.image.DataBufferInt) raster.getDataBuffer(); - - IntBuffer buffer = IntBuffer.wrap(dataBuffer.getData()); - this.getImageSegment().getImagePixelsAsArray(buffer, RpfImageType.IMAGE_TYPE_ALPHA_RGB); - return bimage; - } - - public boolean hasTransparentAreas() - { - if(null != this.imageSegment) - return (this.imageSegment.hasTransparentPixels() || this.imageSegment.hasMaskedSubframes()); - return false; - } - - public static RpfImageFile load(java.io.File rpfFile) throws java.io.IOException, NitfsRuntimeException - { - return new RpfImageFile(rpfFile); - } - - public static void main(String args[]) throws IOException - { - String cibFilename = (Configuration.isWindowsOS()) - ? "C:\\depot\\WorldWindJ\\utils\\gdal\\020g222a.i42" : "/depot/WorldWindJ/utils/gdal/020g222a.i42"; - String cadrgFilename = (Configuration.isWindowsOS()) - ? "C:\\depot\\nitfs\\CADRG\\CTLM50\\CT50Z02\\02F7W053.TL2" : "/depot/nitfs/CADRG/CTLM50/CT50Z02/02F7W053.TL2"; - String transparentCadrgFilename = (Configuration.isWindowsOS()) - ? "C:\\depot\\nitfs\\CADRG\\CTLM50\\CT50Z02\\0D6MM013.TL1" : "/depot/nitfs/CADRG/CTLM50/CT50Z02/0D6MM013.TL1"; - - String rpfFilename = cibFilename; // cibFilename; // cadrgFilename; transparentCadrgFilename; - - try - { - long startTime = System.currentTimeMillis(); - - RpfImageFile rpfImageFile = RpfImageFile.load(new File(rpfFilename)); - -// ---------- getImageAsDdsTexture example ----------------------- - - ByteBuffer ddsBuffer = rpfImageFile.getImageAsDdsTexture(); - System.out.println(MessageFormat.format("RPF file loaded in {0} mSec", (System.currentTimeMillis() - startTime))); - WWIO.saveBuffer(ddsBuffer, new File( - (Configuration.isWindowsOS()) ? "c:\\depot\\nitfs\\DDS\\test.dds" : "/depot/nitfs/DDS/test.dds" - )); - -// ---------- getImageAsArray example ----------------------- -// -// int size = rpfImageFile.getImageSegment().numSignificantCols -// * rpfImageFile.getImageSegment().numSignificantRows; -// IntBuffer rgbaBuffer = IntBuffer.allocate(size); -// rpfImageFile.getImagePixelsAsArray(rgbaBuffer.array(), RpfImageType.IMAGE_TYPE_RGB_ALPHA); -// -// System.out.println(MessageFormat.format("RPF file loaded in {0} mSec", -// (System.currentTimeMillis() - startTime))); - -// ---------- getBufferedImage example ----------------------- -// BufferedImage bimage = rpfImageFile.getBufferedImage(); -// -// System.out.println(MessageFormat.format("RPF file loaded in {0} mSec", -// (System.currentTimeMillis() - startTime))); -// -// Icon icon = new ImageIcon(bimage); -// JLabel label = new JLabel(icon); -// -// final JFrame f = new JFrame("RPF Viewer"); -// f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); -// f.getContentPane().add(label); -// f.pack(); -// SwingUtilities.invokeLater(new Runnable() -// { -// public void run() -// { -// f.setLocationRelativeTo(null); -// f.setVisible(true); -// } -// }); - } - catch (Exception e) - { - System.out.println(e.getMessage()); - e.printStackTrace(); - } - } -} - diff --git a/gov/nasa/worldwind/formats/rpf/RpfImageType.java b/gov/nasa/worldwind/formats/rpf/RpfImageType.java deleted file mode 100644 index 74a1f61..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfImageType.java +++ /dev/null @@ -1,20 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author lado - * @version $Id: RpfImageType Apr 18, 2007 11:35:23 PM - */ -public enum RpfImageType -{ - IMAGE_TYPE_RGB, - IMAGE_TYPE_RGB_ALPHA, - IMAGE_TYPE_ALPHA_RGB, - IMAGE_TYPE_GRAY, - IMAGE_TYPE_GRAY_ALPHA -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfLocationSection.java b/gov/nasa/worldwind/formats/rpf/RpfLocationSection.java deleted file mode 100644 index 89837ec..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfLocationSection.java +++ /dev/null @@ -1,303 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: RpfLocationSection Apr 4, 2007 5:57:23 PM lado - */ -public class RpfLocationSection -{ - private java.util.Hashtable table = - new java.util.Hashtable(); - - public int getHeaderComponentLocation() - { - return this.getLocation(128); - } - public int getHeaderComponentLength() - { - return this.getLength(128); - } - public int getLocationComponentLocation() - { - return this.getLocation(129); - } - public int getLocationComponentLength() - { - return this.getLength(129); - } - public int getCoverageSectionSubheaderLocation() - { - return this.getLocation(130); - } - public int getCoverageSectionSubheaderLength() - { - return this.getLength(130); - } - public int getCompressionSectionSubheaderLocation() - { - return this.getLocation(131); - } - public int getCompressionSectionSubheaderLength() - { - return this.getLength(131); - } - public int getCompressionLookupSubsectionLocation() - { - return this.getLocation(132); - } - public int getCompressionLookupSubsectionLength() - { - return this.getLength(132); - } - public int getCompressionParameterSubsectionLocation() - { - return this.getLocation(133); - } - public int getCompressionParameterSubsectionLength() - { - return this.getLength(133); - } - public int getColorGrayscaleSectionSubheaderLocation() - { - return this.getLocation(134); - } - public int getColorGrayscaleSectionSubheaderLength() - { - return this.getLength(134); - } - public int getColormapSubsectionLocation() - { - return this.getLocation(135); - } - public int getColormapSubsectionLength() - { - return this.getLength(135); - } - public int getImageDescriptionSubheaderLocation() - { - return this.getLocation(136); - } - public int getImageDescriptionSubheaderLength() - { - return this.getLength(136); - } - public int getImageDisplayParametersSubheaderLocation() - { - return this.getLocation(137); - } - public int getImageDisplayParametersSubheaderLength() - { - return this.getLength(137); - } - public int getMaskSubsectionLocation() - { - return this.getLocation(138); - } - public int getMaskSubsectionLength() - { - return this.getLength(138); - } - public int getColorConverterSubsectionLocation() - { - return this.getLocation(139); - } - public int getColorConverterSubsectionLength() - { - return this.getLength(139); - } - - public int getSpatialDataSubsectionLocation() - { - return this.getLocation(140); - } - public int getSpatialDataSubsectionLength() - { - return this.getLength(140); - } - public int getAttributeSectionSubheaderLocation() - { - return this.getLocation(141); - } - public int getAttributeSectionSubheaderLength() - { - return this.getLength(141); - } - public int getAttributeSubsectionLocation() - { - return this.getLocation(142); - } - public int getAttributeSubsectionLength() - { - return this.getLength(142); - } - public int getExplicitArealCoverageTableLocation() - { - return this.getLocation(143); - } - public int getExplicitArealCoverageTableLength() - { - return this.getLength(143); - } - public int getRelatedImagesSectionSubheaderLocation() - { - return this.getLocation(144); - } - public int getRelatedImagesSectionSubheaderLength() - { - return this.getLength(144); - } - public int getRelatedImagesSubsectionLocation() - { - return this.getLocation(145); - } - public int getRelatedImagesSubsectionLength() - { - return this.getLength(145); - } - public int getReplaceUpdateSectionSubheaderLocation() - { - return this.getLocation(146); - } - public int getReplaceUpdateSectionSubheaderLength() - { - return this.getLength(146); - } - public int getReplaceUpdateTableLocation() - { - return this.getLocation(147); - } - public int getReplaceUpdateTableLength() - { - return this.getLength(147); - } - public int getBoundaryRectangleSectionSubheaderLocation() - { - return this.getLocation(148); - } - public int getBoundaryRectangleSectionSubheaderLength() - { - return this.getLength(148); - } - public int getBoundaryRectangleTableLocation() - { - return this.getLocation(149); - } - public int getBoundaryRectangleTableLength() - { - return this.getLength(149); - } - public int getFrameFileIndexSectionSubheaderLocation() - { - return this.getLocation(150); - } - public int getFrameFileIndexSectionSubheaderLength() - { - return this.getLength(150); - } - public int getFrameFileIndexSubsectionLocation() - { - return this.getLocation(151); - } - public int getFrameFileIndexSubsectionLength() - { - return this.getLength(151); - } - public int getColorTableIndexSectionSubheaderLocation() - { - return this.getLocation(152); - } - public int getColorTableIndexSectionSubheaderLength() - { - return this.getLength(152); - } - public int getColorTableIndexRecordLocation() - { - return this.getLocation(153); - } - public int getColorTableIndexRecordLength() - { - return this.getLength(153); - } - // because of lack of "unsigned" in java, we store UINT as int, and UINT as long - public int locationSectionLength; - public long componentLocationTableOffset; - public int numOfComponentLocationRecords; - public int componentLocationRecordLength; - public long componentAggregateLength; - - public RpfLocationSection(java.nio.ByteBuffer buffer) - { - this.locationSectionLength = NitfsUtil.getUShort(buffer); - this.componentLocationTableOffset = NitfsUtil.getUInt(buffer); - this.numOfComponentLocationRecords = NitfsUtil.getUShort(buffer); - this.componentLocationRecordLength = NitfsUtil.getUShort(buffer); - this.componentAggregateLength = NitfsUtil.getUInt(buffer); - - if (this.numOfComponentLocationRecords < 2) - throw new NitfsRuntimeException("NitfsReader:InvalidNumberOfComponentLocationRecords"); - - for (int i = 0; i < this.numOfComponentLocationRecords; i++) - { - int id = NitfsUtil.getUShort(buffer); - table.put(id, new ComponentLocationRecord(id, - NitfsUtil.getUInt(buffer), // read uint:4 as "length" - NitfsUtil.getUInt(buffer) // read uint:4 as "location" - )); - } - } - - private int getLocation(int componentID) - { - ComponentLocationRecord rec = this.getRecord(componentID); - return (int) ((null != rec) ? (0xFFFFFFFFL & rec.getLocation()) : 0); - } - private int getLength(int componentID) - { - ComponentLocationRecord rec = this.getRecord(componentID); - return (int) ((null != rec) ? (0xFFFFFFFFL & rec.getLength()) : 0); - } - private ComponentLocationRecord getRecord(int componentID) - { - if(table.containsKey(componentID)) - return table.get(componentID); - return null; - } - - public class ComponentLocationRecord - { - private int id; - private long length; - private long location; - - public int getId() - { - return id; - } - - public long getLength() - { - return length; - } - - public long getLocation() - { - return location; - } - - public ComponentLocationRecord(int id, long length, long location) - { - this.id = id; - this.length = length; - this.location = location; - } - } - -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfProducer.java b/gov/nasa/worldwind/formats/rpf/RpfProducer.java deleted file mode 100644 index d4fc827..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfProducer.java +++ /dev/null @@ -1,107 +0,0 @@ -/* -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.formats.rpf; - -import gov.nasa.worldwind.*; - -import static java.util.logging.Level.*; - -/** - * @author dcollins - * @version $Id: RpfProducer.java 1896 2007-05-29 00:16:25Z dcollins $ - */ -public enum RpfProducer -{ - /* [Section 5.2.1, MIL-STD-2411-1] */ - Producer1('1', "AFACC", "Air Force Air Combat Command"), - Producer2('2', "AFESC", "Air Force Electronic Systems Center"), - Producer3('3', "NIMA", "National Imagery and Mapping Agency, Primary"), - Producer4('4', "NIMA1", "NIMA, Alternate Site 1"), - Producer5('5', "NIMA2", "NIMA, Alternate Site 2"), - Producer6('6', "NIMA3", "NIMA, Alternate Site 3"), - Producer7('7', "SOCAF", "Air Force Special Operations Command"), - Producer8('8', "SOCOM", "United States Special Operations Command"), - Producer9('9', "PACAF", "Pacific Air Forces"), - ProducerA('A', "USAFE", "United States Air Force, Europe"), - ProducerB('B', "Non-DoD (NonDD)", "US producer outside the Department of Defense"), - ProducerC('C', "Non-US (NonUS)", "Non-US producer"), - ProducerD('D', "NIMA", "DCHUM (DCHUM) NIMA produced Digital CHUM file"), - ProducerE('E', "Non-NIMA DCHUM (DCHMD)", "DoD producer of Digital CHUM file otherthan NIMA "), - ProducerF('F', "Non-US DCHUM (DCHMF)", "Non-US (foreign)producer of Digital CHUMfiles"), - ProducerG('G', "Non-DoD DCHUM (DCHMG)", "US producer of Digital CHUM files outsideDoD"), - ProducerH('H', "IMG2RPF", "Non-specified, Imagery formatted to RPF"), -// Producer?('I'-'Z', "", "Reserved for future standardization"), - ; - - public final Character id; - public final String producerCode; - public final String producer; - - private RpfProducer(Character id, String producerCode, String producer) - { - this.id = id; - this.producer = producer; - this.producerCode = producerCode; - } - - private static RpfProducer[] enumConstantAlphabet = null; - - private static RpfProducer[] enumConstantAlphabet() - { - if (enumConstantAlphabet == null) - { - RpfProducer[] universe = RpfProducer.class.getEnumConstants(); - enumConstantAlphabet = new RpfProducer[36]; - for (RpfProducer producer : universe) - { - enumConstantAlphabet[indexFor(producer.id)] = producer; - } - } - return enumConstantAlphabet; - } - - private static int indexFor(Character id) - { - if (id >= '0' && id <= '9') - return id - '0'; - else if (id >= 'A' && id <= 'Z') - return 10 + id - 'A'; - return -1; - } - - public static boolean isProducerId(Character id) - { - if (id == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.CharacterIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - RpfProducer[] alphabet = enumConstantAlphabet(); - int index = indexFor(Character.toUpperCase(id)); - return (index >= 0) && (index < alphabet.length) && (alphabet[index] != null); - } - - public static RpfProducer producerFor(Character id) - { - if (id == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.CharacterIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - RpfProducer producer; - RpfProducer[] alphabet = enumConstantAlphabet(); - int index = indexFor(Character.toUpperCase(id)); - if (index < 0 || index >= alphabet.length || (producer = alphabet[index]) == null) - { - String message = WorldWind.retrieveErrMsg("generic.EnumNotFound") + id; - WorldWind.logger().log(FINE, message); - throw new EnumConstantNotPresentException(RpfZone.class, message); - } - return producer; - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfTocCrawler.java b/gov/nasa/worldwind/formats/rpf/RpfTocCrawler.java deleted file mode 100644 index bbba63d..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfTocCrawler.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - 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.formats.rpf; - -import gov.nasa.worldwind.*; - -import java.io.*; -import java.util.*; -import java.util.concurrent.locks.*; -import static java.util.logging.Level.*; - -/** - * @author dcollins - * @version $Id: RpfTocCrawler.java 1762 2007-05-07 19:43:55Z dcollins $ - */ -public class RpfTocCrawler -{ - public static final String RPF_DIRECTORY = "RPF"; - public static final String RPF_OVERVIEW_EXTENSION = ".OVR"; - public static final String RPF_TOC_EXTENSION = ".TOC"; - - public static interface RpfTocCrawlerListener - { - void fileFound(File tocFile); - - void finished(); - } - - public abstract static class RpfTocGrouper implements RpfTocCrawlerListener - { - private final RpfFramePropertyType groupType; - - public RpfTocGrouper(RpfFramePropertyType groupType) - { - if (groupType == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfFramePropertyTypeIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - this.groupType = groupType; - } - - public void fileFound(File tocFile) - { - RpfTocFile rpfTocFile = null; - try - { - rpfTocFile = RpfTocFile.load(tocFile); - } - catch (IOException e) - { - WorldWind.logger().log(FINE, e.getMessage()); - } - - if (rpfTocFile == null) - return; - - String firstFrameFilename = findFirstRpfFrameFilename(rpfTocFile); - if (firstFrameFilename == null) - return; - - RpfFrameProperties firstFrameProperties = null; - try - { - firstFrameProperties = RpfFrameFilenameUtil.parseFilename(firstFrameFilename); - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("RpfTocCrawler.ExceptionParsingFilename"); - WorldWind.logger().log(FINE, message, e); - } - - if (firstFrameProperties != null) - this.addToGroup(this.groupType.getInstance(firstFrameProperties), rpfTocFile); - } - - public void finished() - { - } - - public abstract void addToGroup(Object groupKey, RpfTocFile rpfTocFile); - } - - private static class RpfTocRunner implements Runnable - { - private final RpfTocCrawler context; - private final File directory; - private final RpfTocCrawlerListener listener; - - public RpfTocRunner(RpfTocCrawler context, File directory, RpfTocCrawlerListener listener) - { - this.context = context; - this.directory = directory; - this.listener = listener; - } - - public void run() - { - this.context.process(this.directory, listener, true); - this.context.threadLock.lock(); - try - { - if (this.context.thread != this.context.deadThread) - { - listener.finished(); - this.context.thread = this.context.deadThread; - } - } - finally - { - this.context.threadLock.unlock(); - } - } - } - - private final Thread deadThread = new Thread(); - private final Lock threadLock = new ReentrantLock(); - private volatile Thread thread = null; - - public RpfTocCrawler() - { - } - - public static String findFirstRpfFrameFilename(RpfTocFile tocFile) - { - if (tocFile != null - && tocFile.getFrameFileIndexSection() != null - && tocFile.getFrameFileIndexSection().getFrameFileIndexTable() != null - && tocFile.getFrameFileIndexSection().getFrameFileIndexTable().size() > 0) - { - for (RpfFrameFileIndexSection.RpfFrameFileIndexRecord frameFileIndexRecord - : tocFile.getFrameFileIndexSection().getFrameFileIndexTable()) - { - if (frameFileIndexRecord != null - && frameFileIndexRecord.getFrameFileName() != null - && !frameFileIndexRecord.getFrameFileName().toUpperCase().endsWith(RPF_OVERVIEW_EXTENSION)) - { - return frameFileIndexRecord.getFrameFileName(); - } - } - } - return null; - } - - private void process(File file, RpfTocCrawlerListener listener, boolean inOwnThread) - { - this.threadLock.lock(); - try - { - if (inOwnThread && this.thread == deadThread) - return; - } - finally - { - this.threadLock.unlock(); - } - - File[] children = file.listFiles(); - if (children == null) - return; - if (RPF_DIRECTORY.compareToIgnoreCase(file.getName()) == 0) - this.processRpfDirectory(children, listener, inOwnThread); - else - this.processUnknownDirectory(children, listener, inOwnThread); - } - - private void processRpfDirectory(File[] contents, RpfTocCrawlerListener listener, boolean inOwnThread) - { - for (File file : contents) - { - this.threadLock.lock(); - try - { - if (inOwnThread && this.thread == deadThread) - return; - } - finally - { - this.threadLock.unlock(); - } - - if (file.getName().toUpperCase().endsWith(RPF_TOC_EXTENSION)) - listener.fileFound(file); - } - } - - private void processUnknownDirectory(File[] contents, RpfTocCrawlerListener listener, boolean inOwnThread) - { - for (File file : contents) - { - this.threadLock.lock(); - try - { - if (inOwnThread && this.thread == deadThread) - return; - } - finally - { - this.threadLock.unlock(); - } - - if (file.isDirectory()) - this.process(file, listener, inOwnThread); - } - } - - public File[] invoke(File directory) - { - File validDir = this.validateDirectory(directory); - final Collection results = new ArrayList(); - this.process(validDir, new RpfTocCrawlerListener() - { - public void fileFound(File file) - { - if (file.exists()) - results.add(file); - } - - public void finished() - { - } - }, false); - File[] tocFileArray = new File[results.size()]; - results.toArray(tocFileArray); - return tocFileArray; - } - - public void invoke(File directory, RpfTocCrawlerListener listener) - { - File validDir = this.validateDirectory(directory); - this.process(validDir, listener, false); - } - - public void start(File directory, RpfTocCrawlerListener listener) - { - this.threadLock.lock(); - try - { - if (this.thread != null || this.thread == deadThread) - { - String message = WorldWind.retrieveErrMsg("RpfTocCrawler.BadStart"); - WorldWind.logger().log(FINE, message); - throw new IllegalStateException(message); - } - File validDir = this.validateDirectory(directory); - this.thread = new Thread(new RpfTocRunner(this, validDir, listener)); - this.thread.start(); - } - finally - { - this.threadLock.unlock(); - } - } - - public void stop() - { - this.threadLock.lock(); - try - { - this.thread = deadThread; - } - finally - { - this.threadLock.unlock(); - } - } - - private File validateDirectory(File directory) - { - if (directory == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - String path = directory.getAbsolutePath(); - if (!path.endsWith("/") && !path.endsWith("\\")) - { - path = path + File.separatorChar; - directory = new File(path); - } - if (!directory.exists()) - { - String message = WorldWind.retrieveErrMsg("generic.fileNotFound"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - return directory; - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfTocFile.java b/gov/nasa/worldwind/formats/rpf/RpfTocFile.java deleted file mode 100644 index f389d59..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfTocFile.java +++ /dev/null @@ -1,75 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.formats.nitfs.*; - -import java.io.*; -import java.text.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: RpfTocFile Apr 4, 2007 2:24:00 PM lado - */ -public class RpfTocFile extends RpfFile -{ - private RpfFileComponents rpfFileComponents; - - public RpfHeaderSection getHeaderSection() - { - return (null != this.rpfFileComponents) ? this.rpfFileComponents.getRpfHeaderSection() : null; - } - - public RpfFrameFileIndexSection getFrameFileIndexSection() - { - return (null != this.rpfFileComponents) ? this.rpfFileComponents.getRpfFrameFileIndexSection() : null; - } - - public RpfFileComponents getRpfFileComponents() - { - return this.rpfFileComponents; - } - - protected RpfTocFile(java.io.File rpfFile) throws IOException, NitfsRuntimeException - { - super(rpfFile); - - RpfUserDefinedHeaderSegment segment = - (RpfUserDefinedHeaderSegment)this.getNitfsSegment( NitfsSegmentType.UserDefinedHeaderSegment ); - - if(null == segment) - throw new NitfsRuntimeException("NitfsReader.UserDefinedHeaderSegmentWasNotFound"); - - this.rpfFileComponents = segment.getRpfFileComponents(); - if(null == this.rpfFileComponents) - throw new NitfsRuntimeException("NitfsReader.RpfFileComponents.Were.Not.Found.In.UserDefinedHeaderSegment"); - } - - public static RpfTocFile load(java.io.File tocFile) throws java.io.IOException - { - return new RpfTocFile(tocFile); - } - - public static void main(String args[]) - { - String testTocFilename = (Configuration.isWindowsOS()) ? "C:\\RPF\\A.TOC" : "/depot/WorldWindJ/utils/rpf/A.TOC"; - try - { - long startTime = System.currentTimeMillis(); - - RpfTocFile toc = RpfTocFile.load(new File(testTocFilename)); - - System.out.println(MessageFormat.format("TOC file loaded in {0} mSec", (System.currentTimeMillis() - startTime))); - } - catch (Exception e) - { - System.out.println(e.getMessage()); - e.printStackTrace(); - } - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfUserDefinedHeaderSegment.java b/gov/nasa/worldwind/formats/rpf/RpfUserDefinedHeaderSegment.java deleted file mode 100644 index c9a0d51..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfUserDefinedHeaderSegment.java +++ /dev/null @@ -1,37 +0,0 @@ -package gov.nasa.worldwind.formats.rpf; - -import gov.nasa.worldwind.formats.nitfs.*; -import gov.nasa.worldwind.*; -/* -Copyright (C) 2001, 2007 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ - -/** - * @author Lado Garakanidze - * @version $Id: RpfUserDefinedHeaderSegment Apr 17, 2007 6:55:38 PM lado - */ -public class RpfUserDefinedHeaderSegment extends NitfsUserDefinedHeaderSegment -{ - private RpfFileComponents components; - - public RpfUserDefinedHeaderSegment(java.nio.ByteBuffer buffer) - { - super(buffer); - - if(StringUtil.Equals(RpfHeaderSection.DATA_TAG, this.dataTag)) - { - this.components = new RpfFileComponents(buffer); - } - else - throw new NitfsRuntimeException("NitfsReader.RpfHeaderNotFoundInUserDefinedSegment", this.dataTag); - this.restoreBufferPosition(); - } - - public RpfFileComponents getRpfFileComponents() - { - return this.components; - } -} diff --git a/gov/nasa/worldwind/formats/rpf/RpfZone.java b/gov/nasa/worldwind/formats/rpf/RpfZone.java deleted file mode 100644 index f04c901..0000000 --- a/gov/nasa/worldwind/formats/rpf/RpfZone.java +++ /dev/null @@ -1,539 +0,0 @@ -/* -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.formats.rpf; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.geom.*; - -import java.util.*; -import static java.util.logging.Level.*; - -/** - * @author dcollins - * @version $Id: RpfZone.java 1896 2007-05-29 00:16:25Z dcollins $ - */ -public enum RpfZone -{ - /* [Table III, Section 70, MIL-A-89007] */ - Zone1('1', 369664, 400384, 0, 32), - Zone2('2', 302592, 400384, 32, 48), - Zone3('3', 245760, 400384, 48, 56), - Zone4('4', 199168, 400384, 56, 64), - Zone5('5', 163328, 400384, 64, 68), - Zone6('6', 137216, 400384, 68, 72), - Zone7('7', 110080, 400384, 72, 76), - Zone8('8', 82432, 400384, 76, 80), -// Zone9('9', 400384, 400384, 80, 90), - ZoneA('A', 369664, 400384, 0, -32), - ZoneB('B', 302592, 400384, -32, -48), - ZoneC('C', 245760, 400384, -48, -56), - ZoneD('D', 199168, 400384, -56, -64), - ZoneE('E', 163328, 400384, -64, -68), - ZoneF('F', 137216, 400384, -68, -72), - ZoneG('G', 110080, 400384, -72, -76), - ZoneH('H', 82432, 400384, -76, -80), -// ZoneJ('J', 400384, 400384, -80, -90), - ; - // TODO: computations for polar zones - - private static class ZoneKey - { - public final RpfZone zone; - public final RpfDataSeries dataSeries; - private int hashCode; - - public ZoneKey(RpfZone zone, RpfDataSeries dataSeries) - { - this.zone = zone; - this.dataSeries = dataSeries; - this.hashCode = this.computeHash(); - } - - private int computeHash() - { - int hash = 0; - if (this.zone != null) - hash = 29 * hash + this.zone.ordinal(); - if (this.dataSeries != null) - hash = 29 * hash + this.dataSeries.ordinal(); - return hash; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || !o.getClass().equals(this.getClass())) - return false; - final ZoneKey that = (ZoneKey) o; - return (this.zone == that.zone) && (this.dataSeries == that.dataSeries); - } - - public int hashCode() - { - return this.hashCode; - } - } - - public static class ZoneValues - { - public final RpfZone zone; - public final RpfDataSeries dataSeries; - public final int eastWestPixelConstant; - public final int northSouthPixelConstant; - public final Angle equatorwardExtent; - public final Angle polewardExtent; - public final Sector extent; - public final int latitudinalFrames; - public final int longitudinalFrames; - public final Angle latitudinalFrameExtent; - public final Angle longitudinalFrameExtent; - public final int maximumFrameNumber; - - private ZoneValues(RpfZone zone, RpfDataSeries dataSeries) - { - if (zone == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfZoneIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - if (dataSeries == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfDataSeriesIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - - this.zone = zone; - this.dataSeries = dataSeries; - this.northSouthPixelConstant = computeNorthSouthPixelConstant(zone.northSouthPixelSpacingConstant, - dataSeries); - this.eastWestPixelConstant = computeEastWestPixelConstant(zone.eastWestPixelSpacingConstant, dataSeries); - this.equatorwardExtent = computeEquatorwardExtent(zone.equatorwardNominalBoundary, - this.northSouthPixelConstant, PixelRowsPerFrame); - this.polewardExtent = computePolewardExtent(zone.polewardNominalBoundary, this.northSouthPixelConstant, - PixelRowsPerFrame); - this.extent = computeZoneExtent(this.equatorwardExtent.degrees, this.polewardExtent.degrees); - this.latitudinalFrames = computeLatitudinalFrames(this.polewardExtent.degrees, - this.equatorwardExtent.degrees, this.northSouthPixelConstant, PixelRowsPerFrame); - this.longitudinalFrames = computeLongitudinalFrames(this.eastWestPixelConstant, PixelRowsPerFrame); - this.latitudinalFrameExtent = computeLatitudinalFrameExtent(this.polewardExtent.degrees, - this.equatorwardExtent.degrees, this.latitudinalFrames); - this.longitudinalFrameExtent = computeLongitudinalFrameExtent(this.longitudinalFrames); - this.maximumFrameNumber = computeMaximumFrameNumber(this.latitudinalFrames, this.longitudinalFrames); - } - - private static double clamp(double x, double min, double max) - { - return (x < min) ? min : ((x > max) ? max : x); - } - - // ============== Constant Zone Computations ======================= // - // ============== Constant Zone Computations ======================= // - // ============== Constant Zone Computations ======================= // - - private static int computeEastWestPixelConstant(double eastWestPixelSpacingConstant, - RpfDataSeries dataSeries) - { - if (dataSeries.rpfDataType.equalsIgnoreCase("CADRG")) - return computeEastWestPixelConstantCADRG(eastWestPixelSpacingConstant, dataSeries.scaleOrGSD); - else if (dataSeries.rpfDataType.equalsIgnoreCase("CIB")) - return computeEastWestPixelConstantCIB(eastWestPixelSpacingConstant, dataSeries.scaleOrGSD); - else - { - String message = WorldWind.retrieveErrMsg("RpfZone.UnknownRpfDataType") + dataSeries.rpfDataType; - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - } - - /* [Section 60.1.2 MIL-C-89038] */ - private static int computeEastWestPixelConstantCADRG(double eastWestPixelSpacingConstant, double scale) - { - double S = 1000000d / scale; - double tmp = eastWestPixelSpacingConstant * S; - tmp = 512d * (int) Math.ceil(tmp / 512d); - tmp /= (150d / 100d); - return 256 * (int) Math.round(tmp / 256d); - } - - /* [Section A.5.1.1, MIL-PRF-89041A] */ - private static int computeEastWestPixelConstantCIB(double eastWestPixelSpacingConstant, - double groundSampleDistance) - { - double S = 100d / groundSampleDistance; - double tmp = eastWestPixelSpacingConstant * S; - return 512 * (int) Math.ceil(tmp / 512d); - } - - /* [Section 60.1.5.c MIL-C-89038] */ - /* [Section A.5.1.2.c MIL-PRF-89041A] */ - private static Angle computeEquatorwardExtent(double equatorwardNominalBoundary, - double northSouthPixelConstant, double pixelRowsPerFrame) - { - double nsPixelsPerDegree = northSouthPixelConstant / 90d; - double degrees = Math.signum(equatorwardNominalBoundary) - * clamp((int) (nsPixelsPerDegree * Math.abs(equatorwardNominalBoundary) / pixelRowsPerFrame) - * pixelRowsPerFrame / nsPixelsPerDegree, 0, 90); - return Angle.fromDegrees(degrees); - } - - private static Angle computeLatitudinalFrameExtent(double polewardExtent, double equatorwardExtent, - double latitudinalFrames) - { - double degrees = Math.abs(polewardExtent - equatorwardExtent) / latitudinalFrames; - return Angle.fromDegrees(degrees); - } - - /* [Section 60.1.6 MIL-C-89038] */ - /* [Section A.5.1.3 MIL-PRF-89041A] */ - private static int computeLatitudinalFrames(double polewardExtent, double equatorwardExtent, - double northSouthPixelConstant, double pixelRowsPerFrame) - { - double nsPixelsPerDegree = northSouthPixelConstant / 90d; - double extent = Math.abs(polewardExtent - equatorwardExtent); - return (int) Math.rint(extent * nsPixelsPerDegree / pixelRowsPerFrame); - } - - public static Angle computeLongitudinalFrameExtent(double longitudinalFrames) - { - double degrees = 360d / longitudinalFrames; - return Angle.fromDegrees(degrees); - } - - /* [Section 60.1.7 MIL-C-89038] */ - /* [Section A.5.1.4 MIL-PRF-89041A] */ - private static int computeLongitudinalFrames(double eastWestPixelConstant, double pixelRowsPerFrame) - { - return (int) Math.ceil(eastWestPixelConstant / pixelRowsPerFrame); - } - - /* [Section 30.6 MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - private static int computeMaximumFrameNumber(int latitudinalFrames, int longitudinalFrames) - { - return (latitudinalFrames * longitudinalFrames) - 1; - } - - private static int computeNorthSouthPixelConstant(double northSouthPixelSpacingConstant, - RpfDataSeries dataSeries) - { - if (dataSeries.rpfDataType.equalsIgnoreCase("CADRG")) - return computeNorthSouthPixelConstantCADRG(northSouthPixelSpacingConstant, dataSeries.scaleOrGSD); - else if (dataSeries.rpfDataType.equalsIgnoreCase("CIB")) - return computeNorthSouthPixelConstantCIB(northSouthPixelSpacingConstant, dataSeries.scaleOrGSD); - else - { - String message = WorldWind.retrieveErrMsg("RpfZone.UnknownRpfDataType") + dataSeries.rpfDataType; - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - } - - /* [Section 60.1.1 MIL-C-89038] */ - private static int computeNorthSouthPixelConstantCADRG(double northSouthPixelConstant, double scale) - { - double S = 1000000d / scale; - double tmp = northSouthPixelConstant * S; - tmp = 512d * (int) Math.ceil(tmp / 512d); - tmp /= 4d; - tmp /= (150d / 100d); - return 256 * (int) Math.round(tmp / 256d); - } - - /* [Section A.5.1.1, MIL-PRF-89041A] */ - private static int computeNorthSouthPixelConstantCIB(double northSouthPixelSpacingConstant, - double groundSampleDistance) - { - double S = 100d / groundSampleDistance; - double tmp = northSouthPixelSpacingConstant * S; - tmp = 512d * (int) Math.ceil(tmp / 512d); - tmp /= 4d; - return 256 * (int) Math.round(tmp / 256d); - } - - /* [Section 60.1.5.b MIL-C-89038] */ - /* [Section A.5.1.2.b MIL-PRF-89041A] */ - private static Angle computePolewardExtent(double polewardNominalBoundary, double northSouthPixelConstant, - double pixelRowsPerFrame) - { - double nsPixelsPerDegree = northSouthPixelConstant / 90d; - double degrees = Math.signum(polewardNominalBoundary) - * clamp(Math.ceil(nsPixelsPerDegree * Math.abs(polewardNominalBoundary) / pixelRowsPerFrame) - * pixelRowsPerFrame / nsPixelsPerDegree, 0, 90); - return Angle.fromDegrees(degrees); - } - - private static Sector computeZoneExtent(double equatorwardExtent, double polewardExtent) - { - double minLatitude, maxLatitude; - if (equatorwardExtent < polewardExtent) - { - minLatitude = equatorwardExtent; - maxLatitude = polewardExtent; - } - else - { - minLatitude = polewardExtent; - maxLatitude = equatorwardExtent; - } - return Sector.fromDegrees(minLatitude, maxLatitude, -180, 180); - } - - // ============== Varying Zone Computations ======================= // - // ============== Varying Zone Computations ======================= // - // ============== Varying Zone Computations ======================= // - - /* [Section 30.6 MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - - public int frameColumnFromFrameNumber(int frameNumber) - { - int row = this.frameRowFromFrameNumber(frameNumber); - return frameNumber - row * this.longitudinalFrames; - } - - /* [Section 30.3.2 MIL-C-89038] */ - /* [Section A.3.3.2, MIL-PRF-89041A] */ - public int frameColumnFromLongitude(Angle longitude) - { - if (longitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - return (int) (((longitude.degrees + 180d) / 360d) - * (this.eastWestPixelConstant / (double) PixelRowsPerFrame)); - } - - public Sector frameExtent(int frameNumber) - { - Angle latOrigin = latitudinalFrameOrigin(this.frameRowFromFrameNumber(frameNumber)); - Angle lonOrigin = longitudinalFrameOrigin(this.frameColumnFromFrameNumber(frameNumber)); - return new Sector( - latOrigin.subtract(this.latitudinalFrameExtent), latOrigin, - lonOrigin, lonOrigin.add(this.longitudinalFrameExtent)); - } - - /* [Section 30.6 MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - public int frameNumber(int row, int column) - { - return column + row * this.longitudinalFrames; - } - - /* [Section 30.6 MIL-C-89038] */ - /* [Section A.3.6, MIL-PRF-89041A] */ - public int frameRowFromFrameNumber(int frameNumber) - { - return (int) (frameNumber / (double) this.longitudinalFrames); - } - - /* [Section 30.3.1 MIL-C-89038] */ - /* [Section A.3.3.1, MIL-PRF-89041A] */ - public int frameRowFromLatitude(Angle latitude) - { - if (latitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - return (int) (((latitude.degrees - this.equatorwardExtent.degrees) / 90d) - * (this.northSouthPixelConstant / (double) PixelRowsPerFrame)); - } - - /* [Section 30.3.1 MIL-C-89038] */ - /* [Section A.3.3.1, MIL-PRF-89041A] */ - public Angle latitudinalFrameOrigin(int row) - { - double degrees = (90d / (double) this.northSouthPixelConstant) * ((double) PixelRowsPerFrame) * (row + 1) - + this.equatorwardExtent.degrees; - return Angle.fromDegrees(degrees); - } - - /* [Section 30.3.2 MIL-C-89038] */ - /* [Section A.3.3.2, MIL-PRF-89041A] */ - public Angle longitudinalFrameOrigin(int column) - { - double degrees = (360d / (double) this.eastWestPixelConstant) * ((double) PixelRowsPerFrame) - * column - 180d; - return Angle.fromDegrees(degrees); - } - } - - public static final int PixelRowsPerFrame = 1536; - public static final int SubframeRowsPerFrame = 6; - public final int eastWestPixelSpacingConstant; - public final int equatorwardNominalBoundary; - public final int northSouthPixelSpacingConstant; - public final int polewardNominalBoundary; - public final Character zoneCode; - - private RpfZone(Character zoneCode, int eastWestPixelSpacingConstant, int northSouthPixelSpacingConstant, - int equatorwardNominalBoundary, int polewardNominalBoundary) - { - this.zoneCode = zoneCode; - this.eastWestPixelSpacingConstant = eastWestPixelSpacingConstant; - this.northSouthPixelSpacingConstant = northSouthPixelSpacingConstant; - this.equatorwardNominalBoundary = equatorwardNominalBoundary; - this.polewardNominalBoundary = polewardNominalBoundary; - } - - private static RpfZone[] enumConstantAlphabet = null; - - private static RpfZone[] enumConstantAlphabet() - { - if (enumConstantAlphabet == null) - { - RpfZone[] universe = RpfZone.class.getEnumConstants(); - enumConstantAlphabet = new RpfZone[36]; - for (RpfZone zone : universe) - { - enumConstantAlphabet[indexFor(zone.zoneCode)] = zone; - } - } - return enumConstantAlphabet; - } - - private static int indexFor(Character zoneCode) - { - if (zoneCode >= '0' && zoneCode <= '9') - return zoneCode - '0'; - else if (zoneCode >= 'A' && zoneCode <= 'Z') - return 10 + zoneCode - 'A'; - return -1; - } - - public static boolean isZoneCode(Character zoneCode) - { - if (zoneCode == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.CharacterIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - RpfZone[] alphabet = enumConstantAlphabet(); - int index = indexFor(Character.toUpperCase(zoneCode)); - return (index >= 0) && (index < alphabet.length) && (alphabet[index] != null); - } - - private static RpfZone[] northernHemisphereZones = null; - - private static RpfZone[] northernHemisphereZones() - { - if (northernHemisphereZones == null) - { - RpfZone[] universe = RpfZone.class.getEnumConstants(); - northernHemisphereZones = new RpfZone[universe.length / 2]; - int index = 0; - for (RpfZone zone : universe) - { - if (zone.polewardNominalBoundary >= 0) - northernHemisphereZones[index++] = zone; - } - } - return northernHemisphereZones; - } - - private static RpfZone[] southernHemisphereZones = null; - - private static RpfZone[] southernHemisphereZones() - { - if (southernHemisphereZones == null) - { - RpfZone[] universe = RpfZone.class.getEnumConstants(); - southernHemisphereZones = new RpfZone[universe.length / 2]; - int index = 0; - for (RpfZone zone : universe) - { - if (zone.polewardNominalBoundary < 0) - southernHemisphereZones[index++] = zone; - } - } - return southernHemisphereZones; - } - - public static RpfZone zoneFor(Character zoneCode) - { - if (zoneCode == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.CharacterIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - RpfZone zone; - RpfZone[] alphabet = enumConstantAlphabet(); - int index = indexFor(Character.toUpperCase(zoneCode)); - if (index < 0 || index >= alphabet.length || (zone = alphabet[index]) == null) - { - String message = WorldWind.retrieveErrMsg("generic.EnumNotFound") + zoneCode; - WorldWind.logger().log(FINE, message); - throw new EnumConstantNotPresentException(RpfZone.class, message); - } - return zone; - } - - public static RpfZone zoneFor(RpfDataSeries dataSeries, Angle latitude) - { - if (latitude == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(FINE, message); - throw new IllegalArgumentException(message); - } - double latDegrees = latitude.degrees; - if (latDegrees < 0) - return zoneForSouthernHemisphere(dataSeries, latDegrees); - else - return zoneForNorthernHemisphere(dataSeries, latDegrees); - } - - private static RpfZone zoneForNorthernHemisphere(RpfDataSeries dataSeries, double latitude) - { - for (RpfZone zone : northernHemisphereZones()) - { - ZoneValues values = zone.zoneValues(dataSeries); - if (latitude >= values.equatorwardExtent.degrees && latitude <= values.polewardExtent.degrees) - return zone; - } - return null; - } - - private static RpfZone zoneForSouthernHemisphere(RpfDataSeries dataSeries, double latitude) - { - for (RpfZone zone : southernHemisphereZones()) - { - ZoneValues values = zone.zoneValues(dataSeries); - if (latitude <= values.equatorwardExtent.degrees && latitude >= values.polewardExtent.degrees) - return zone; - } - return null; - } - - public RpfZone.ZoneValues zoneValues(RpfDataSeries dataSeries) - { - RpfZone.ZoneKey key = new RpfZone.ZoneKey(this, dataSeries); - RpfZone.ZoneValues value = zoneValuesDirectory().get(key); - if (value == null) - { - value = new RpfZone.ZoneValues(this, dataSeries); - zoneValuesDirectory().put(key, value); - } - return value; - } - - private static Map zoneValuesDirectory = null; - - private static Map zoneValuesDirectory() - { - if (zoneValuesDirectory == null) - zoneValuesDirectory = new HashMap(); - return zoneValuesDirectory; - } -} diff --git a/gov/nasa/worldwind/geom/LatLon.java b/gov/nasa/worldwind/geom/LatLon.java index 41ce6ff..c6bb697 100644 --- a/gov/nasa/worldwind/geom/LatLon.java +++ b/gov/nasa/worldwind/geom/LatLon.java @@ -15,7 +15,7 @@ import gov.nasa.worldwind.util.Logging; * Instances of LatLon are immutable. * * @author Tom Gaskins - * @version $Id: LatLon.java 2567 2007-08-16 22:27:38Z tgaskins $ + * @version $Id: LatLon.java 2975 2007-09-21 17:05:19Z tgaskins $ */ public class LatLon { @@ -55,8 +55,8 @@ public class LatLon /** * Contructs a new LatLon from two angles. Neither angle may be null. * - * @param latitude - * @param longitude + * @param latitude latitude + * @param longitude longitude * @throws IllegalArgumentException if latitude or longitude is null */ public LatLon(Angle latitude, Angle longitude) @@ -119,28 +119,46 @@ public class LatLon } /** - * Computes the great circle angular distance between two locations + * Computes the great circle angular distance between two locations. The return value gives the distance as the + * angle between the two positions on the pi radius circle. In radians, this angle is also the arc length of the + * segment between the two positions on that circle. To compute a distance in meters from this value, multiply it by + * the radius of the globe. * - * @param begin LatLon of the first location - * @param end LatLon of the second location - * @return the angular distance between the two locations + * @param p1 LatLon of the first location + * @param p2 LatLon of the second location + * @return the angular distance between the two locations. In radians, this value is the arc length of the radius pi + * circle. */ - public static Angle sphericalDistance(LatLon begin, LatLon end) + public static Angle sphericalDistance(LatLon p1, LatLon p2) { + if ((p1 == null) || (p2 == null)) + { + String message = Logging.getMessage("nullValue.LatLonIsNull"); + Logging.logger().severe(message); + throw new IllegalArgumentException(message); + } + // TODO: Perhaps use more accurate formula described here: http://en.wikipedia.org/wiki/Great-circle_distance - double radLatA = begin.getLatitude().radians; - double radLatB = end.getLatitude().radians; - double radLonA = begin.getLongitude().radians; - double radLonB = end.getLongitude().radians; - return Angle.fromRadians( - Math.acos(Math.cos(radLatA) * Math.cos(radLatB) * Math.cos(radLonA - radLonB) - + Math.sin(radLatA) * Math.sin(radLatB))); + double radLatA = p1.getLatitude().radians; + double radLatB = p2.getLatitude().radians; + double radLonA = p1.getLongitude().radians; + double radLonB = p2.getLongitude().radians; + double a = + Math.cos(radLatA) * Math.cos(radLatB) * Math.cos(radLonA - radLonB) + Math.sin(radLatA) * Math.sin(radLatB); + return a > 1 ? Angle.ZERO : Angle.fromRadians(Math.acos(a)); } private static final double HALF_PI = Math.PI / 2d; public static Angle azimuth(LatLon p1, LatLon p2) { + if ((p1 == null) || (p2 == null)) + { + String message = Logging.getMessage("nullValue.LatLonIsNull"); + Logging.logger().severe(message); + throw new IllegalArgumentException(message); + } + double lat1 = p1.getLatitude().radians; double lon1 = p1.getLongitude().radians; double lat2 = p2.getLatitude().radians; @@ -165,6 +183,13 @@ public class LatLon public static LatLon endPosition(LatLon p, double azimuth, double pathLength) { + if (p == null) + { + String message = Logging.getMessage("nullValue.LatLonIsNull"); + Logging.logger().severe(message); + throw new IllegalArgumentException(message); + } + double a = Math.acos(Math.cos(pathLength) * Math.cos(HALF_PI - p.getLatitude().radians) + Math.sin(HALF_PI - p.getLatitude().radians) * Math.sin(pathLength) * Math.cos(azimuth)); @@ -252,7 +277,8 @@ public class LatLon // and are more than 180 degress longitude apart if (Math.signum(pos.getLongitude().degrees) != Math.signum(posNext.getLongitude().degrees)) { - if (Math.abs(pos.getLongitude().degrees - posNext.getLongitude().degrees) > 180) + double delta = Math.abs(pos.getLongitude().degrees - posNext.getLongitude().degrees); + if (delta > 180 && delta < 360) return true; } } @@ -266,7 +292,7 @@ public class LatLon { if (p1 == null || p2 == null) { - String msg = Logging.getMessage("nullValue.PositionsListIsNull"); + String msg = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } @@ -275,7 +301,8 @@ public class LatLon // and are more than 180 degress longitude apart if (Math.signum(p1.getLongitude().degrees) != Math.signum(p2.getLongitude().degrees)) { - if (Math.abs(p1.getLongitude().degrees - p2.getLongitude().degrees) > 180) + double delta = Math.abs(p1.getLongitude().degrees - p2.getLongitude().degrees); + if (delta > 180 && delta < 360) return true; } @@ -315,4 +342,162 @@ public class LatLon result = 29 * result + longitude.hashCode(); return result; } + + /** + * Compute the forward azimuth between two positions + * + * @param p1 first position + * @param p2 second position + * @param equatorialRadius the equatorial radius of the globe in meters + * @param polarRadius the polar radius of the globe in meters + * @return the azimuth + */ + public Angle ellipsoidalForwardAzimuth(LatLon p1, LatLon p2, double equatorialRadius, double polarRadius) + { + // TODO: What if polar radius is larger than equatorial radius? + final double F = (equatorialRadius - polarRadius) / equatorialRadius; // flattening = 1.0 / 298.257223563; + final double R = 1.0 - F; + + if (p1 == null || p2 == null) + { + String message = Logging.getMessage("nullValue.PositionIsNull"); + Logging.logger().severe(message); + throw new IllegalArgumentException(message); + } + + // See ellipsoidalDistance() below for algorithm info. + + double GLAT1 = p1.getLatitude().radians; + double GLAT2 = p2.getLatitude().radians; + double TU1 = R * Math.sin(GLAT1) / Math.cos(GLAT1); + double TU2 = R * Math.sin(GLAT2) / Math.cos(GLAT2); + double CU1 = 1. / Math.sqrt(TU1 * TU1 + 1.); + double CU2 = 1. / Math.sqrt(TU2 * TU2 + 1.); + double S = CU1 * CU2; + double BAZ = S * TU2; + double FAZ = BAZ * TU1; + + return Angle.fromRadians(FAZ); + } + + // TODO: Need method to compute end position from initial position, azimuth and distance. The companion to the + // spherical version, endPosition(), above. + + /** + * Computes the distance between two points on an ellipsoid iteratively. + *

+ * NOTE: This method was copied from the UniData NetCDF Java library. http://www.unidata.ucar.edu/software/netcdf-java/ + *

+ * Algorithm from U.S. National Geodetic Survey, FORTRAN program "inverse," subroutine "INVER1," by L. PFEIFER and + * JOHN G. GERGEN. See http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html + *

+ * Original documentation: SOLUTION OF THE GEODETIC INVERSE PROBLEM AFTER T.VINCENTY MODIFIED RAINSFORD'S METHOD + * WITH HELMERT'S ELLIPTICAL TERMS EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL + * STANDPOINT/FOREPOINT MUST NOT BE THE GEOGRAPHIC POLE + *

+ * Requires close to 1.4 E-5 seconds wall clock time per call on a 550 MHz Pentium with Linux 7.2. + * + * @param p1 first position + * @param p2 second position + * @param equatorialRadius the equatorial radius of the globe in meters + * @param polarRadius the polar radius of the globe in meters + * @return distance in meters between the two points + */ + public static double ellipsoidalDistance(LatLon p1, LatLon p2, double equatorialRadius, double polarRadius) + { + // TODO: I think there is a non-iterative way to calculate the distance. Find it and compare with this one. + // TODO: What if polar radius is larger than equatorial radius? + final double F = (equatorialRadius - polarRadius) / equatorialRadius; // flattening = 1.0 / 298.257223563; + final double R = 1.0 - F; + final double EPS = 0.5E-13; + + if (p1 == null || p2 == null) + { + String message = Logging.getMessage("nullValue.PositionIsNull"); + Logging.logger().severe(message); + throw new IllegalArgumentException(message); + } + + // Algorithm from National Geodetic Survey, FORTRAN program "inverse," + // subroutine "INVER1," by L. PFEIFER and JOHN G. GERGEN. + // http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html + // Conversion to JAVA from FORTRAN was made with as few changes as possible + // to avoid errors made while recasting form, and to facilitate any future + // comparisons between the original code and the altered version in Java. + // Original documentation: + // SOLUTION OF THE GEODETIC INVERSE PROBLEM AFTER T.VINCENTY + // MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS + // EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL + // STANDPOINT/FOREPOINT MUST NOT BE THE GEOGRAPHIC POLE + // A IS THE SEMI-MAJOR AXIS OF THE REFERENCE ELLIPSOID + // F IS THE FLATTENING (NOT RECIPROCAL) OF THE REFERNECE ELLIPSOID + // LATITUDES GLAT1 AND GLAT2 + // AND LONGITUDES GLON1 AND GLON2 ARE IN RADIANS POSITIVE NORTH AND EAST + // FORWARD AZIMUTHS AT BOTH POINTS RETURNED IN RADIANS FROM NORTH + // + // Reference ellipsoid is the WGS-84 ellipsoid. + // See http://www.colorado.edu/geography/gcraft/notes/datum/elist.html + // FAZ is forward azimuth in radians from pt1 to pt2; + // BAZ is backward azimuth from point 2 to 1; + // S is distance in meters. + // + // Conversion to JAVA from FORTRAN was made with as few changes as possible + // to avoid errors made while recasting form, and to facilitate any future + // comparisons between the original code and the altered version in Java. + // + //IMPLICIT REAL*8 (A-H,O-Z) + // COMMON/CONST/PI,RAD + + double GLAT1 = p1.getLatitude().radians; + double GLAT2 = p2.getLatitude().radians; + double TU1 = R * Math.sin(GLAT1) / Math.cos(GLAT1); + double TU2 = R * Math.sin(GLAT2) / Math.cos(GLAT2); + double CU1 = 1. / Math.sqrt(TU1 * TU1 + 1.); + double SU1 = CU1 * TU1; + double CU2 = 1. / Math.sqrt(TU2 * TU2 + 1.); + double S = CU1 * CU2; + double BAZ = S * TU2; + double FAZ = BAZ * TU1; + double GLON1 = p1.getLongitude().radians; + double GLON2 = p2.getLongitude().radians; + double X = GLON2 - GLON1; + double D, SX, CX, SY, CY, Y, SA, C2A, CZ, E, C; + do + { + SX = Math.sin(X); + CX = Math.cos(X); + TU1 = CU2 * SX; + TU2 = BAZ - SU1 * CU2 * CX; + SY = Math.sqrt(TU1 * TU1 + TU2 * TU2); + CY = S * CX + FAZ; + Y = Math.atan2(SY, CY); + SA = S * SX / SY; + C2A = -SA * SA + 1.; + CZ = FAZ + FAZ; + if (C2A > 0.) + { + CZ = -CZ / C2A + CY; + } + E = CZ * CZ * 2. - 1.; + C = ((-3. * C2A + 4.) * F + 4.) * C2A * F / 16.; + D = X; + X = ((E * CY * C + CZ) * SY * C + Y) * SA; + X = (1. - C) * X * F + GLON2 - GLON1; + //IF(DABS(D-X).GT.EPS) GO TO 100 + } while (Math.abs(D - X) > EPS); + + //FAZ = Math.atan2(TU1, TU2); + //BAZ = Math.atan2(CU1 * SX, BAZ * CX - SU1 * CU2) + Math.PI; + X = Math.sqrt((1. / R / R - 1.) * C2A + 1.) + 1.; + X = (X - 2.) / X; + C = 1. - X; + C = (X * X / 4. + 1.) / C; + D = (0.375 * X * X - 1.) * X; + X = E * CY; + S = 1. - E - E; + S = ((((SY * SY * 4. - 3.) * S * CZ * D / 6. - X) * D / 4. + CZ) * SY + * D + Y) * C * equatorialRadius * R; + + return S; + } } diff --git a/gov/nasa/worldwind/geom/Matrix4.java b/gov/nasa/worldwind/geom/Matrix4.java deleted file mode 100644 index 8ec21db..0000000 --- a/gov/nasa/worldwind/geom/Matrix4.java +++ /dev/null @@ -1,857 +0,0 @@ -/* -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.geom; - -import gov.nasa.worldwind.*; - -/** - * @author Tom Gaskins - * @version $Id: Matrix4.java 1749 2007-05-06 19:48:14Z tgaskins $ - */ -public class Matrix4 implements Matrix -{ - // TODO: scalar operations - private double m11 = 1, m12, m13, m14, m21, m22 = 1, m23, m24, m31, m32, m33 = 1, m34, m41, m42, m43, m44 = 1; - private boolean isOrthonormal = true; - - /** - * Creates a new Matrix4 as the identity matrix. - */ - public Matrix4() - { - } - - /** - * Creates a new Matrix4 from an array of double precision floating point values. The caller must - * provide at least sixteen values, and any values beyond the sixteenth are ignored. Values are assigned in the - * following order: (1, 1), (2, 1), (3, 1), (4, 1), (1, 2), (2, 2), (3, 2), (4, 2), (3, 3), (2, 3), (3, 3), (4, 3), - * (1, 4), (2, 4), (3, 4), (4, 4). - * - * @param entries the values, must contain at least 16 values and may not be null - * @throws IllegalArgumentException if entries is too short or null - */ - public Matrix4(double[] entries) - { - if (entries == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.EntriesIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (entries.length < 16) - { - String msg = WorldWind.retrieveErrMsg("geom.Matrix4.ArrayTooShort"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.m11 = entries[0]; - this.m21 = entries[1]; - this.m31 = entries[2]; - this.m41 = entries[3]; - - this.m12 = entries[4]; - this.m22 = entries[5]; - this.m32 = entries[6]; - this.m42 = entries[7]; - - this.m13 = entries[8]; - this.m23 = entries[9]; - this.m33 = entries[10]; - this.m43 = entries[11]; - - this.m14 = entries[12]; - this.m24 = entries[13]; - this.m34 = entries[14]; - this.m44 = entries[15]; - - // TODO: Determine this by checking key entries - this.isOrthonormal = false; - } - - /** - * Creates a new Matrix4 from an array of single precision floating point values. The caller must - * provide at least sixteen values, and any values beyond the sixteenth are ignored. Values are assigned in the - * following order: (1, 1), (2, 1), (3, 1), (4, 1), (1, 2), (2, 2), (3, 2), (4, 2), (3, 3), (2, 3), (3, 3), (4, 3), - * (1, 4), (2, 4), (3, 4), (4, 4). - * - * @param entries the values, must contain at least 16 values and may not be null - * @throws IllegalArgumentException if entries is too short or null - */ - public Matrix4(float[] entries) - { - if (entries == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.EntriesIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (entries.length < 16) - { - String msg = WorldWind.retrieveErrMsg("geom.Matrix4.ArrayTooShort"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.m11 = entries[0]; - this.m21 = entries[1]; - this.m31 = entries[2]; - this.m41 = entries[3]; - - this.m12 = entries[4]; - this.m22 = entries[5]; - this.m32 = entries[6]; - this.m42 = entries[7]; - - this.m13 = entries[8]; - this.m23 = entries[9]; - this.m33 = entries[10]; - this.m43 = entries[11]; - - this.m14 = entries[12]; - this.m24 = entries[13]; - this.m34 = entries[14]; - this.m44 = entries[15]; - - // TODO: Optimize this by checking key entries - this.isOrthonormal = false; - } - - /** - * Retrieves the entries comprising this Matrix. The returned array is always 16 entries long. Values - * are place in as in the aray as follows: (1, 1), (2, 1), (3, 1), (4, 1), (1, 2), (2, 2), (3, 2), (4, 2), (3, 3), - * (2, 3), (3, 3), (4, 3), (1, 4), (2, 4), (3, 4), (4, 4). - * - * @return an array, of length 16, containing this Matrices' entries. - */ - public final double[] getEntries() - { - double[] entries = new double[16]; - - entries[0] = this.m11; - entries[1] = this.m21; - entries[2] = this.m31; - entries[3] = this.m41; - - entries[4] = this.m12; - entries[5] = this.m22; - entries[6] = this.m32; - entries[7] = this.m42; - - entries[8] = this.m13; - entries[9] = this.m23; - entries[10] = this.m33; - entries[11] = this.m43; - - entries[12] = this.m14; - entries[13] = this.m24; - entries[14] = this.m34; - entries[15] = this.m44; - - return entries; - } - - /** - * Sets this Matrix to the identity matrix. This method causes internal changes to the - * Matrix it operates on. - * - * @return this, set to the identity - */ - public final Matrix setToIdentity() - { - this.m11 = 1; - this.m12 = 0; - this.m13 = 0; - this.m14 = 0; - this.m21 = 0; - this.m22 = 1; - this.m23 = 0; - this.m24 = 0; - this.m31 = 0; - this.m32 = 0; - this.m33 = 1; - this.m34 = 0; - this.m41 = 0; - this.m42 = 0; - this.m43 = 0; - this.m44 = 1; - - this.isOrthonormal = true; - - return this; - } - - /** - * Obtains whether or not this Matrix is orthonormal. Orthonormal matrices possess unique properties - * that can make algorithms more efficient. - * - * @return true if this is orthonormal, false otherwise - */ - public final boolean isOrthonormal() - { - return this.isOrthonormal; - } - - /** - * Rotate this matrix by some angle around an arbitrary axis. A positive Angle indicates an - * anti-clockwise direction. This method affects the internal state of this matrix. - * - * @param rotation the distance to rotate this matrix - * @param axisX the x component of the axis of rotation - * @param axisY the y component of the axis of rotation - * @param axisZ the z component of the axis of rotation - * @return this Matrix, with the rotation applied - * @throws IllegalArgumentException if rotation is null - */ - public final Matrix rotate(Angle rotation, double axisX, double axisY, double axisZ) - { - if (rotation == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RotationAngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double ll = axisX * axisX + axisY * axisY + axisZ * axisZ; - if (rotation.getDegrees() == 0 || ll == 0) - return this; - - if (ll != 1) // if axis not unit length, normalize it. - { - double l = Math.sqrt(ll); - axisX /= l; - axisY /= l; - axisZ /= l; - } - - double c = rotation.cos(); - double s = rotation.sin(); - double c1 = 1 - c; - Matrix4 o = new Matrix4(); - - o.m11 = c + axisX * axisX * c1; - o.m12 = axisX * axisY * c1 - axisZ * s; - o.m13 = axisX * axisZ * c1 + axisY * s; - o.m14 = 0; - o.m21 = axisX * axisY * c1 + axisZ * s; - o.m22 = c + axisY * axisY * c1; - o.m23 = axisY * axisZ * c1 - axisX * s; - o.m24 = 0; - o.m31 = axisX * axisZ * c1 - axisY * s; - o.m32 = axisY * axisZ * c1 + axisX * s; - o.m33 = c + axisZ * axisZ * c1; - o.m34 = 0; - o.m41 = 0; - o.m42 = 0; - o.m43 = 0; - o.m44 = 1; - - return this.multiply(o); - } - - /** - * Rotate this Matrix around the x-axis. A positive Angle indicates an anti-clockwise - * direction. Changes the internal state of this Matrix. - * - * @param rotation the distance to rotate - * @return this Matrix, rotated around the x-axis by rotation distance - * @throws IllegalArgumentException if rotation is null - */ - public final Matrix rotateX(Angle rotation) - { - if (rotation == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RotationAngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double c = rotation.cos(); - double s = rotation.sin(); - - double n12 = this.m12 * c + this.m13 * s; - double n13 = this.m12 * -s + this.m13 * c; - - double n22 = this.m22 * c + this.m23 * s; - double n23 = this.m22 * -s + this.m23 * c; - - double n32 = this.m32 * c + this.m33 * s; - double n33 = this.m32 * -s + this.m33 * c; - - double n42 = this.m42 * c + this.m43 * s; - double n43 = this.m42 * -s + this.m43 * c; - - this.m12 = n12; - this.m13 = n13; - this.m22 = n22; - this.m23 = n23; - this.m32 = n32; - this.m33 = n33; - this.m42 = n42; - this.m43 = n43; - - return this; - } - - /** - * Rotate this Matrix around the y-axis. A positive Angle indicates an anti-clockwise - * direction. Changes the internal state of this Matrix. - * - * @param rotation the distance to rotate - * @return this Matrix, rotated around the y-axis by rotation distance - * @throws IllegalArgumentException if rotation is null - */ - public final Matrix rotateY(Angle rotation) - { - if (rotation == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RotationAngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double c = rotation.cos(); - double s = rotation.sin(); - - double n11 = this.m11 * c + this.m13 * -s; - double n13 = this.m11 * s + this.m13 * c; - - double n21 = this.m21 * c + this.m23 * -s; - double n23 = this.m21 * s + this.m23 * c; - - double n31 = this.m31 * c + this.m33 * -s; - double n33 = this.m31 * s + this.m33 * c; - - double n41 = this.m41 * c + this.m43 * -s; - double n43 = this.m41 * s + this.m43 * c; - - this.m11 = n11; - this.m13 = n13; - this.m21 = n21; - this.m23 = n23; - this.m31 = n31; - this.m33 = n33; - this.m41 = n41; - this.m43 = n43; - - return this; - } - - /** - * Rotate this Matrix around the z-axis. A positive Angle indicates an anti-clockwise - * direction. Changes the internal state of this Matrix. - * - * @param rotation the distance to rotate - * @return this Matrix, rotated around the z-axis by rotation distance - * @throws IllegalArgumentException if rotation is null - */ - public final Matrix rotateZ(Angle rotation) - { - if (rotation == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RotationAngleIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double c = rotation.cos(); - double s = rotation.sin(); - - double n11 = this.m11 * c + this.m12 * s; - double n12 = this.m11 * -s + this.m12 * c; - - double n21 = this.m21 * c + this.m22 * s; - double n22 = this.m21 * -s + this.m22 * c; - - double n31 = this.m31 * c + this.m32 * s; - double n32 = this.m31 * -s + this.m32 * c; - - double n41 = this.m41 * c + this.m42 * s; - double n42 = this.m41 * -s + this.m42 * c; - - this.m11 = n11; - this.m12 = n12; - this.m21 = n21; - this.m22 = n22; - this.m31 = n31; - this.m32 = n32; - this.m41 = n41; - this.m42 = n42; - - return this; - } - - /** - * Translates this Matrix in three dimensional space. Changes the internal state of this - * Matrix. - * - * @param x the distance to translate along the x-axis - * @param y the distance to translate along the y-axis - * @param z the distance to translate along the z-axis - * @return this matrix, translated by (x, y, z) - */ - public Matrix translate(double x, double y, double z) - { - this.m14 = this.m11 * x + this.m12 * y + this.m13 * z + this.m14; - this.m24 = this.m21 * x + this.m22 * y + this.m23 * z + this.m24; - this.m34 = this.m31 * x + this.m32 * y + this.m33 * z + this.m34; - this.m44 = this.m41 * x + this.m42 * y + this.m43 * z + this.m44; - - return this; - } - - /** - * Translates this Matrix in three dimansional space. Changes the internal state of this - * Matrix. The x, y and z co-ordinates are used to translate along the x, y and z axes respectively. - * - * @param p the x, y and z distances to translate as a Point - * @return this Matrix, translated by the distances defined in p - * @throws IllegalArgumentException if p is null - */ - public final Matrix translate(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return this.translate(p.x(), p.y(), p.z()); - } - - /** - * Adds this another matrix to this one. - * - * @param m the Matrix to add to this one - * @return this Matrix, with the m added to it - * @throws IllegalArgumentException if m is null - */ - public final Matrix add(Matrix m) - { - if (m == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.MatrixIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - Matrix4 o = (Matrix4) m; - - this.m11 += o.m11; - this.m12 += o.m12; - this.m13 += o.m13; - this.m14 += o.m14; - this.m21 += o.m21; - this.m22 += o.m22; - this.m23 += o.m23; - this.m24 += o.m24; - this.m31 += o.m31; - this.m32 += o.m32; - this.m33 += o.m33; - this.m34 += o.m34; - this.m41 += o.m41; - this.m42 += o.m42; - this.m43 += o.m43; - this.m44 += o.m44; - - this.isOrthonormal = this.isOrthonormal || o.isOrthonormal; - - return this; - } - - /** - * Performs a cross multiplication with another Matrix. Alters the state of this Matrix. - * - * @param m another Matrix - * @return this, postmultiplied by m - * @throws IllegalArgumentException if m is null - */ - public final Matrix multiply(Matrix m) - { - if (m == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.MatrixIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - Matrix4 o = (Matrix4) m; - - double n11 = this.m11 * o.m11 + this.m12 * o.m21 + this.m13 * o.m31 + this.m14 * o.m41; - double n12 = this.m11 * o.m12 + this.m12 * o.m22 + this.m13 * o.m32 + this.m14 * o.m42; - double n13 = this.m11 * o.m13 + this.m12 * o.m23 + this.m13 * o.m33 + this.m14 * o.m43; - double n14 = this.m11 * o.m14 + this.m12 * o.m24 + this.m13 * o.m34 + this.m14 * o.m44; - - double n21 = this.m21 * o.m11 + this.m22 * o.m21 + this.m23 * o.m31 + this.m24 * o.m41; - double n22 = this.m21 * o.m12 + this.m22 * o.m22 + this.m23 * o.m32 + this.m24 * o.m42; - double n23 = this.m21 * o.m13 + this.m22 * o.m23 + this.m23 * o.m33 + this.m24 * o.m43; - double n24 = this.m21 * o.m14 + this.m22 * o.m24 + this.m23 * o.m34 + this.m24 * o.m44; - - double n31 = this.m31 * o.m11 + this.m32 * o.m21 + this.m33 * o.m31 + this.m34 * o.m41; - double n32 = this.m31 * o.m12 + this.m32 * o.m22 + this.m33 * o.m32 + this.m34 * o.m42; - double n33 = this.m31 * o.m13 + this.m32 * o.m23 + this.m33 * o.m33 + this.m34 * o.m43; - double n34 = this.m31 * o.m14 + this.m32 * o.m24 + this.m33 * o.m34 + this.m34 * o.m44; - - double n41 = this.m41 * o.m11 + this.m42 * o.m21 + this.m43 * o.m31 + this.m44 * o.m41; - double n42 = this.m41 * o.m12 + this.m42 * o.m22 + this.m43 * o.m32 + this.m44 * o.m42; - double n43 = this.m41 * o.m13 + this.m42 * o.m23 + this.m43 * o.m33 + this.m44 * o.m43; - double n44 = this.m41 * o.m14 + this.m42 * o.m24 + this.m43 * o.m34 + this.m44 * o.m44; - - this.m11 = n11; - this.m12 = n12; - this.m13 = n13; - this.m14 = n14; - this.m21 = n21; - this.m22 = n22; - this.m23 = n23; - this.m24 = n24; - this.m31 = n31; - this.m32 = n32; - this.m33 = n33; - this.m34 = n34; - this.m41 = n41; - this.m42 = n42; - this.m43 = n43; - this.m44 = n44; - - this.isOrthonormal = this.isOrthonormal || o.isOrthonormal; - - return this; - } - - /** - * Obtains the transpose of this Matrix. Does not alter the state of this Matrix. - * - * @return the transpoase of this Matrix - */ - public final Matrix getTranspose() - { - Matrix4 transpose = new Matrix4(); - - transpose.m11 = this.m11; - transpose.m12 = this.m21; - transpose.m13 = this.m31; - transpose.m14 = this.m41; - transpose.m21 = this.m12; - transpose.m22 = this.m22; - transpose.m23 = this.m32; - transpose.m24 = this.m42; - transpose.m31 = this.m13; - transpose.m32 = this.m23; - transpose.m33 = this.m33; - transpose.m34 = this.m43; - transpose.m41 = this.m14; - transpose.m42 = this.m24; - transpose.m43 = this.m34; - transpose.m44 = this.m44; - - transpose.isOrthonormal = this.isOrthonormal; - - return transpose; - } - - /** - * Obtain the inverse of this Matrix. - * - * @return the inverse of this Matrix. - */ - public final Matrix getInverse() - { - Matrix4 inverse; - - if (this.isOrthonormal) - { - inverse = this.orthonormalInverse(); - } - else - { - inverse = this.generalInverse(); - } - - inverse.isOrthonormal = this.isOrthonormal; - - return inverse; - } - - private Matrix4 orthonormalInverse() - { - Matrix4 inverse = new Matrix4(); - - // Transpose of upper 3x3. - inverse.m11 = this.m11; - inverse.m12 = this.m21; - inverse.m13 = this.m31; - - inverse.m21 = this.m12; - inverse.m22 = this.m22; - inverse.m23 = this.m32; - - inverse.m31 = this.m13; - inverse.m32 = this.m23; - inverse.m33 = this.m33; - - // Upper 3x3 inverse times current translation (4th column). - inverse.m14 = -(inverse.m11 * this.m14 + inverse.m12 * this.m24 + inverse.m13 * this.m34); - inverse.m24 = -(inverse.m21 * this.m14 + inverse.m22 * this.m24 + inverse.m23 * this.m34); - inverse.m34 = -(inverse.m31 * this.m14 + inverse.m32 * this.m24 + inverse.m33 * this.m34); - - return inverse; - } - - // TODO: Fix generalInverse. It's not producing correct inverses. - private Matrix4 generalInverse() - { - double d = this.determinant(); - if (d == 0) - { - return null; - } - - double id = 1 / d; - Matrix4 inverse = new Matrix4(); - - // Form the adjoint matrix. - double a1 = this.m33 * this.m44 - this.m34 * this.m43; - double a2 = this.m34 * this.m42 - this.m32 * this.m44; - double a3 = this.m32 * this.m43 - this.m33 * this.m42; - double a4 = this.m23 * this.m44 - this.m24 * this.m43; - double a5 = this.m24 * this.m42 - this.m22 * this.m44; - double a6 = this.m23 * this.m34 - this.m24 * this.m33; - double a7 = this.m22 * this.m33 - this.m23 * this.m32; - double a8 = this.m34 * this.m41 - this.m31 * this.m44; - double a9 = this.m31 * this.m43 - this.m33 * this.m41; - double a21 = this.m24 * this.m41 - this.m21 * this.m44; - double a22 = this.m24 * this.m31 - this.m21 * this.m34; - double a23 = this.m32 * this.m44 - this.m34 * this.m42; - double a24 = this.m31 * this.m42 - this.m32 * this.m41; - double a14 = this.m21 * this.m42 - this.m22 * this.m41; - double a15 = this.m21 * this.m32 - this.m22 * this.m31; - double a16 = this.m33 * this.m41 - this.m31 * this.m43; - - inverse.m11 = id - * this.m22 * a1 - + this.m23 * a2 - + this.m24 * a3; - inverse.m12 = -id - * this.m12 * a1 - + this.m13 * a2 - + this.m14 * a3; - inverse.m13 = id - * this.m12 * a4 - + this.m13 * (this.m24 * this.m42 - this.m22 * this.m44) - + this.m14 * a5; - inverse.m14 = -id - * this.m12 * a6 - + this.m13 * (this.m24 * this.m32 - this.m22 * this.m34) - + this.m14 * a7; - inverse.m21 = -id - * this.m21 * a1 - + this.m23 * a8 - + this.m24 * a9; - inverse.m22 = id - * this.m11 * a1 - + this.m13 * a8 - + this.m14 * a9; - inverse.m23 = -id - * this.m11 * a4 - + this.m13 * a21 - + this.m14 * (this.m21 * this.m43 - this.m23 * this.m41); - inverse.m24 = -id - * this.m11 * a6 - + this.m13 * a22 - + this.m14 * (this.m21 * this.m33 - this.m23 * this.m31); - inverse.m31 = id - * this.m21 * a23 - + this.m22 * a8 - + this.m24 * a24; - inverse.m32 = -id - * this.m11 * a23 - + this.m12 * a8 - + this.m14 * a24; - inverse.m33 = -id - * this.m11 * (this.m22 * this.m44 - this.m24 * this.m42) - + this.m12 * a21 - + this.m14 * a14; - inverse.m34 = id - * this.m11 * (this.m22 * this.m34 - this.m24 * this.m32) - + this.m12 * a22 - + this.m14 * a15; - inverse.m41 = -id - * this.m21 * a3 - + this.m22 * a16 - + this.m23 * a24; - inverse.m42 = -id - * this.m11 * a3 - + this.m12 * a16 - + this.m13 * a24; - inverse.m43 = id - * this.m11 * a5 - + this.m12 * (this.m23 * this.m41 - this.m21 * this.m43) - + this.m13 * a14; - inverse.m44 = -id - * this.m11 * a7 - + this.m12 * (this.m23 * this.m31 - this.m21 * this.m33) - + this.m13 * a15; - - return inverse; - } - - /** - * Obtains the determinant of this Matrix. - * - * @return the determinant - */ - public final double determinant() - { - return - this.m11 * ( - (this.m22 * this.m33 * this.m44 + this.m23 * this.m34 * this.m42 + this.m24 * this.m32 * this.m43) - - this.m24 * this.m33 * this.m42 - - this.m22 * this.m34 * this.m43 - - this.m23 * this.m32 * this.m44) - - this.m12 * ( - (this.m21 * this.m33 * this.m44 + this.m23 * this.m34 * this.m41 + this.m24 * this.m31 * this.m43) - - this.m24 * this.m33 * this.m41 - - this.m21 * this.m34 * this.m43 - - this.m23 * this.m31 * this.m44) - + this.m13 * ( - (this.m21 * this.m32 * this.m44 + this.m22 * this.m34 * this.m41 + this.m24 * this.m31 * this.m42) - - this.m24 * this.m32 * this.m41 - - this.m21 * this.m34 * this.m42 - - this.m22 * this.m31 * this.m44) - - this.m14 * ( - (this.m21 * this.m32 * this.m43 + this.m22 * this.m33 * this.m41 + this.m23 * this.m31 * this.m42) - - this.m23 * this.m32 * this.m41 - - this.m21 * this.m33 * this.m42 - - this.m22 * this.m31 * this.m43); - } - - /** - * Applies this Matrix to a Point. - * - * @param p the Point to transform - * @return p, trasformed by the current state of this Matrix - * @throws IllegalArgumentException if p is null - */ - public final Point transform(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double x = this.m11 * p.x() + this.m12 * p.y() + this.m13 * p.z() + this.m14 * p.w(); - double y = this.m21 * p.x() + this.m22 * p.y() + this.m23 * p.z() + this.m24 * p.w(); - double z = this.m31 * p.x() + this.m32 * p.y() + this.m33 * p.z() + this.m34 * p.w(); - double w = this.m41 * p.x() + this.m42 * p.y() + this.m43 * p.z() + this.m44 * p.w(); - - return new Point(x, y, z, w); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final gov.nasa.worldwind.geom.Matrix4 matrix4 = (gov.nasa.worldwind.geom.Matrix4) o; - - if (isOrthonormal != matrix4.isOrthonormal) - return false; - if (Double.compare(matrix4.m11, m11) != 0) - return false; - if (Double.compare(matrix4.m12, m12) != 0) - return false; - if (Double.compare(matrix4.m13, m13) != 0) - return false; - if (Double.compare(matrix4.m14, m14) != 0) - return false; - if (Double.compare(matrix4.m21, m21) != 0) - return false; - if (Double.compare(matrix4.m22, m22) != 0) - return false; - if (Double.compare(matrix4.m23, m23) != 0) - return false; - if (Double.compare(matrix4.m24, m24) != 0) - return false; - if (Double.compare(matrix4.m31, m31) != 0) - return false; - if (Double.compare(matrix4.m32, m32) != 0) - return false; - if (Double.compare(matrix4.m33, m33) != 0) - return false; - if (Double.compare(matrix4.m34, m34) != 0) - return false; - if (Double.compare(matrix4.m41, m41) != 0) - return false; - if (Double.compare(matrix4.m42, m42) != 0) - return false; - if (Double.compare(matrix4.m43, m43) != 0) - return false; - if (Double.compare(matrix4.m44, m44) != 0) - return false; - - return true; - } - - @Override - public int hashCode() - { - int result; - long temp; - temp = m11 != +0.0d ? Double.doubleToLongBits(m11) : 0L; - result = (int) (temp ^ (temp >>> 32)); - temp = m12 != +0.0d ? Double.doubleToLongBits(m12) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m13 != +0.0d ? Double.doubleToLongBits(m13) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m14 != +0.0d ? Double.doubleToLongBits(m14) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m21 != +0.0d ? Double.doubleToLongBits(m21) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m22 != +0.0d ? Double.doubleToLongBits(m22) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m23 != +0.0d ? Double.doubleToLongBits(m23) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m24 != +0.0d ? Double.doubleToLongBits(m24) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m31 != +0.0d ? Double.doubleToLongBits(m31) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m32 != +0.0d ? Double.doubleToLongBits(m32) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m33 != +0.0d ? Double.doubleToLongBits(m33) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m34 != +0.0d ? Double.doubleToLongBits(m34) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m41 != +0.0d ? Double.doubleToLongBits(m41) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m42 != +0.0d ? Double.doubleToLongBits(m42) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m43 != +0.0d ? Double.doubleToLongBits(m43) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = m44 != +0.0d ? Double.doubleToLongBits(m44) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - result = 29 * result + (isOrthonormal ? 1 : 0); - return result; - } - - @Override - public String toString() - { - return "Matrix4 :\n[ " + this.m11 + ", " + this.m12 + ", " + this.m13 + ", " + this.m14 + ",\n " - + this.m21 + ", " + this.m22 + ", " + this.m23 + ", " + this.m24 + ",\n " - + this.m31 + ", " + this.m32 + ", " + this.m33 + ", " + this.m34 + ",\n " - + this.m41 + ", " + this.m42 + ", " + this.m43 + ", " + this.m44 + " ]"; - } -} diff --git a/gov/nasa/worldwind/geom/Point.java b/gov/nasa/worldwind/geom/Point.java deleted file mode 100644 index 71fe6fe..0000000 --- a/gov/nasa/worldwind/geom/Point.java +++ /dev/null @@ -1,556 +0,0 @@ -/* -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.geom; - -import gov.nasa.worldwind.*; - -/** - * Point represents an homogeneous cartesian point in 3 dimensional space. - *

- * Instances of Point are immutable.

- * - * @author Tom Gaskins - * @version $Id: Point.java 1750 2007-05-06 19:53:06Z tgaskins $ - */ -public class Point implements gov.nasa.worldwind.Cacheable -{ - private final double x; - private final double y; - private final double z; - private final double w; - - /** - * Value of ZERO is (0,0,0) - */ - public static final Point ZERO = new Point(0, 0, 0); - /** - * Value of UNIT_X is (1,0,0) - */ - public static final Point UNIT_X = new Point(1, 0, 0); - /** - * Value of UNIT_Y is (0,1,0) - */ - public static final Point UNIT_Y = new Point(0, 1, 0); - /** - * Value of UNIT_Z is (0,0,1) - */ - public static final Point UNIT_Z = new Point(0, 0, 1); - - /** - * Constructs a new Point from four parameters. - * - * @param x the x position of the Point - * @param y the y position of the Point - * @param z the z position of the Point - * @param w the w position of the Point - */ - public Point(double x, double y, double z, double w) - { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - /** - * Constructs a new Point from three parameters. The w field is set to 1. - * - * @param x the x position of the Point - * @param y the y position of the Point - * @param z the z position of the Point - */ - public Point(double x, double y, double z) - { - this.x = x; - this.y = y; - this.z = z; - this.w = 1; - } - - /** - * Returns the w element of this Point. This method differs from w() in that subclasses may override - * it. - * - * @return the w element of this Point - * @see Point#w() - */ - public double getW() - { - return w; - } - - /** - * Returns the x element of this Point. This method differs from x() in that subclasses may override - * it. - * - * @return the x element of this Point - * @see Point#x() - */ - public double getX() - { - return x; - } - - /** - * Returns the y element of this Point. This method differs from y() in that subclasses may override - * it. - * - * @return the y element of this Point - * @see Point#y() - */ - public double getY() - { - return y; - } - - /** - * Returns the y element of this Point. This method differs from y() in that subclasses may override - * it. - * - * @return the y element of this Point - * @see Point#z() - */ - public double getZ() - { - return z; - } - - /** - * Returns the x element of this Point. - * - * @return the x element of this Point - */ - public final double x() - { - return this.x; - } - - /** - * Returns the y element of this Point. - * - * @return the y element of this Point - */ - public final double y() - { - return this.y; - } - - /** - * Returns the z element of this Point. - * - * @return the z element of this Point - */ - public final double z() - { - return this.z; - } - - /** - * Returns the w element of this Point. - * - * @return the w element of this Point - */ - public final double w() - { - return this.w; - } - - /** - * Calculates the sum of these two Points. The resulting Point has x value equivalent to - * this.x + p.x, the results for y,z and w are calculated in the same way. - * - * @param p the Point to be added to this Point - * @return a Point resulting from the algebraic operation this + p - * @throws IllegalArgumentException if p is null - */ - public final Point add(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return new Point(this.x + p.x, this.y + p.y, this.z + p.z, 1); - } - - /** - * Calculates the difference between these two Points. The resulting Point is equivalent - * to this.x - p.x, the results for y, z and w are calculated in the same way. - * - * @param p the Point to subtract from this Point - * @return a Point resulting from the algebraic operationthis - p - * @throws IllegalArgumentException if p is null - */ - public final Point subtract(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return new Point(this.x - p.x, this.y - p.y, this.z - p.z, 1); - } - - /** - * Multiplies this Point by a scalar quantity. This method simply returns a new Point - * whose values each equal the old Point's corresponding value multiplied by this scalar. - * - * @param s the scalar to be multiplied by - * @return a Point resulting from the scalar multiplication of this and s - */ - public final Point multiply(double s) - { - return new Point(this.x * s, this.y * s, this.z * s, 1); - } - - public final Point scale(double sx, double sy, double sz) - { - return new Point(this.x * sx, this.y * sy, this.z * sz, this.w); - } - - public final Point normalize() - { - double s = 1d / this.length(); - return this.scale(s, s, s); - } - - /** - * Performs a dot product of the x, y and z coorinates of this and p. - * - * @param p the Point to perform a dot product with - * @return the scalar product of this and p - * @throws IllegalArgumentException if p is null - */ - public final double dot(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return this.x * p.x + this.y * p.y + this.z * p.z; - } - - /** - * Performs a dot product of the x, y and z coorinates of this with itself. This method is equivalent - * to this.dot(this). - *

- *

- * A useful characteristic of this method is that the resulting value is the square of this Point's - * distance from ZERO. Finding the square of the distance from the origin in this manner is preferred - * over finding the square by first finding the length and then squaring it because this is faster and less prone to - * loss of precision.

- * - * @return this Point dotted with itself - * @see Point#ZERO - */ - public final double selfDot() - { - return this.x * this.x + this.y * this.y + this.z * this.z; - } - - /** - * Performs a dot product of all four components of this and p. - * - * @param p the Point to perform a dot product with - * @return the scalar product of this and p - * @throws IllegalArgumentException if p is null - */ - public final double dot4(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return this.x * p.x + this.y * p.y + this.z * p.z + this.w * this.w; - } - - /** - * Calculates the distance between this Point and the origin. - * - * @return the distance between this Point and ZERO - * @see Point#ZERO - */ - public final double length() - { - return Math.sqrt(this.selfDot()); - } - - /** - * Calculates the unsigned distance between this Point and p. - * - * @param p the Point to find the distance from - * @return the distance between these two Points - * @throws IllegalArgumentException if p is null - */ - public final double distanceTo(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double dx = this.x - p.x; - double dy = this.y - p.y; - double dz = this.z - p.z; - return Math.sqrt(dx * dx + dy * dy + dz * dz); - } - - /** - * Calculates the squared unsigned distance between this Point and p. This method is - * useful when actual distances are not required, but some measure is needed for comparison purposes. It avoids the - * square root required for computing actual distance. - * - * @param p the Point to find the square distance from - * @return the square of the distance between these two Points - * @throws IllegalArgumentException if p is null - */ - public final double distanceToSquared(Point p) - { - if (p == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - double dx = this.x - p.x; - double dy = this.y - p.y; - double dz = this.z - p.z; - return (dx * dx + dy * dy + dz * dz); - } - - /** - * Determines the midpoint of two Points. - * - * @param p1 the first Point - * @param p2 the second Point - * @return the midpoint of these two Points - * @throws IllegalArgumentException if either p1 or p2 is null - */ - public static Point midPoint(Point p1, Point p2) - { - if (p1 == null || p2 == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - return new Point(0.5 * (p1.x + p2.x), 0.5 * (p1.y + p2.y), 0.5 * (p1.z + p2.z)); - } - - /** - * Scales a Point along a vector. The resulting Point is affected by both the scale factor - * and the size of the vector direction. For example, a vector (2,2,2) and a vector (1,1,1) would produce a - * different result, if all other variables remain constant. For this reason, programmers may wish to normalize - * direction before calling this function. - * - * @param scale the factor to be scaled by - * @param direction the direction of scaling - * @param origin the original Point - * @return origin scaled by scale in the direction specified - * @throws IllegalArgumentException if direction or origin is null - */ - public static Point fromOriginAndDirection(double scale, Point direction, Point origin) - { - if (direction == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DirectionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (origin == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.OriginIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double x = scale * direction.x() + origin.x; - double y = scale * direction.y() + origin.y; - double z = scale * direction.z() + origin.z; - - return new Point(x, y, z); - } - - /** - * Calculate the extrema of a given array of Points. The resulting array is always of length 2, with - * the first element containing the minimum extremum, and the second containing the maximum. The minimum extremum is - * composed by taking the smallest x, y and z values from all the Points in the array. These values are - * not necessarily taken from the same Point. The maximum extrema is composed in the same fashion. - * - * @param points any array of Points - * @return a array with length of 2, comprising the most extreme values in the given array - * @throws IllegalArgumentException if points is null - */ - public static Point[] composeExtrema(Point points[]) - { - if (points == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PointsArrayIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (points.length == 0) - return new Point[] {Point.ZERO, Point.ZERO}; - - double xmin = points[0].x; - double ymin = points[0].y; - double zmin = points[0].z; - double xmax = xmin; - double ymax = ymin; - double zmax = zmin; - - for (int i = 1; i < points.length; i++) - { - double x = points[i].x; - if (x > xmax) - { - xmax = x; - } - else if (x < xmin) - { - xmin = x; - } - - double y = points[i].y; - if (y > ymax) - { - ymax = y; - } - else if (y < ymin) - { - ymin = y; - } - - double z = points[i].z; - if (z > zmax) - { - zmax = z; - } - else if (z < zmin) - { - zmin = z; - } - } - - return new Point[] {new Point(xmin, ymin, zmin), new Point(xmax, ymax, zmax)}; - } - - /** - * Determines the cross product of these two Points. This is post multiplied by that. - * - * @param that the second Point - * @return the cross product of two Points - * @throws IllegalArgumentException if that is null - */ - public Point cross(Point that) - { - if (that == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PointIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - return new Point(this.y * that.z - this.z * that.y, this.z * that.x - this.x * that.z, - this.x * that.y - this.y * that.x); - } - - /** - * Compares this Point to o for equality. - *

- * This method makes comparisons on private fields; overriding implementations should include a call to - * super.equals(). - * - * @param o the Object to be compared to for equality. - * @return true if the contents are equal, false otherwise - */ - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - final gov.nasa.worldwind.geom.Point point = (gov.nasa.worldwind.geom.Point) o; - - if (Double.compare(point.w, w) != 0) - return false; - if (Double.compare(point.x, x) != 0) - return false; - if (Double.compare(point.y, y) != 0) - return false; - //noinspection RedundantIfStatement - if (Double.compare(point.z, z) != 0) - return false; - - return true; - } - - /** - * Generates an integer that is always the same for identical objects, but usually different for different objects. - * This method overrides the one in Object. - *

- * This method makes comparisons on private fields; overriding implementations should include a call to - * super.hashCode(). - * - * @return the hashCode for this Point. - */ - @Override - public int hashCode() - { - int result; - long temp; - temp = x != +0.0d ? Double.doubleToLongBits(x) : 0L; - result = (int) (temp ^ (temp >>> 32)); - temp = y != +0.0d ? Double.doubleToLongBits(y) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = z != +0.0d ? Double.doubleToLongBits(z) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - temp = w != +0.0d ? Double.doubleToLongBits(w) : 0L; - result = 29 * result + (int) (temp ^ (temp >>> 32)); - return result; - } - - /** - * Generates a string representation of this object. The returned string has the format "(x, y, z, w)" where x, y, z - * and w correspond to their respective values in this Point. - * - * @return a string representation of this Point - */ - @Override - public final String toString() - { - return "(" + Double.toString(this.x) + ", " + Double.toString(this.y) + ", " + Double.toString(this.z) + ", " - + Double.toString(this.w) + ")"; - } - - /** - * Obtains the amount of memory this Point consumes. - * - * @return the memory footprint of this Point in bytes. - */ - public final long getSizeInBytes() - { - // we could consider using a constant value here - return Double.SIZE << 2; - } -} diff --git a/gov/nasa/worldwind/geom/Polyline.java b/gov/nasa/worldwind/geom/Polyline.java deleted file mode 100644 index 608c986..0000000 --- a/gov/nasa/worldwind/geom/Polyline.java +++ /dev/null @@ -1,349 +0,0 @@ -/* -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.geom; - -import com.sun.opengl.util.*; -import gov.nasa.worldwind.*; - -import javax.media.opengl.*; -import java.awt.*; -import java.nio.*; -import java.util.*; -import java.util.List; - -/** - * @author tag - * @version $Id: Polyline.java 2233 2007-07-06 23:56:34Z tgaskins $ - */ -public class Polyline implements Renderable -{ - private ArrayList positions; - private Vec4 referenceCenter; - private DoubleBuffer vertices; - private int antiAliasHint = GL.GL_FASTEST; - private Color color = Color.WHITE; - private boolean filled = false; // makes it a polygon - private boolean followGreatCircles = true; - private int numEdgeIntervals = 10; - - public Polyline(Iterable positions) - { - if (positions == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.setPositions(positions); - } - - public Polyline(Iterable positions, double elevation) - { - if (positions == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.setPositions(positions, elevation); - } - - public Color getColor() - { - return color; - } - - public void setColor(Color color) - { - if (color == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ColorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.color = color; - } - - public int getAntiAliasHint() - { - return antiAliasHint; - } - - public void setAntiAliasHint(int hint) - { - if (!(hint == GL.GL_DONT_CARE || hint == GL.GL_FASTEST || hint == GL.GL_NICEST)) - { - String msg = WorldWind.retrieveErrMsg("generic.InvalidHint"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.antiAliasHint = hint; - } - - public boolean isFilled() - { - return filled; - } - - public void setFilled(boolean filled) - { - this.filled = filled; - } - - public boolean isFollowGreatCircles() - { - return followGreatCircles; - } - - public void setFollowGreatCircles(boolean followGreatCircles) - { - this.followGreatCircles = followGreatCircles; - } - - public int getNumEdgeIntervals() - { - return numEdgeIntervals; - } - - public void setNumEdgeIntervals(int numEdgeIntervals) - { - this.numEdgeIntervals = numEdgeIntervals; - } - - public void setPositions(Iterable inPositions) - { - if (inPositions == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.positions = new ArrayList(); - for (Position position : inPositions) - { - this.positions.add(position); - } - - if ((this.filled && this.positions.size() < 3) || (!this.filled && this.positions.size() < 2)) - { - String msg = WorldWind.retrieveErrMsg("generic.InsufficientPositions"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.vertices = null; - } - - public void setPositions(Iterable inPositions, double elevation) - { - if (inPositions == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.positions = new ArrayList(); - for (LatLon position : inPositions) - { - this.positions.add(new Position(position, elevation)); - } - - if (this.positions.size() < 2 || (this.filled && this.positions.size() < 3)) - { - String msg = WorldWind.retrieveErrMsg("generic.InsufficientPositions"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.vertices = null; - } - - public Iterable getPositions() - { - return this.positions; - } - - private void intializeGeometry(DrawContext dc) - { - if (this.positions.size() < 2) - return; - - double[] refCenter = new double[3]; - if (this.followGreatCircles) - this.vertices = this.makeGreatCircleVertices(dc, this.positions, refCenter); - else - this.vertices = makeVertices(dc, this.positions, refCenter); - this.referenceCenter = new Vec4(refCenter[0], refCenter[1], refCenter[2]); - - double avgX = this.referenceCenter.x; - double avgY = this.referenceCenter.y; - double avgZ = this.referenceCenter.z; - - this.vertices.rewind(); - for (int i = 0; i < this.vertices.limit(); i += 3) - { - this.vertices.put(i, this.vertices.get(i) - avgX); - this.vertices.put(i + 1, this.vertices.get(i + 1) - avgY); - this.vertices.put(i + 2, this.vertices.get(i + 2) - avgZ); - } - } - - protected DoubleBuffer makeVertices(DrawContext dc, List posList, double[] refCenter) - { - DoubleBuffer verts = BufferUtil.newDoubleBuffer(posList.size() * 3); - - double avgX = 0; - double avgY = 0; - double avgZ = 0; - - int n = 0; - for (Position p : posList) - { - Vec4 pt = dc.getGlobe().computePointFromPosition(p.getLatitude(), p.getLongitude(), p.getElevation()); - verts.put(pt.x).put(pt.y).put(pt.z); - avgX += pt.x; - avgY += pt.y; - avgZ += pt.z; - ++n; - } - - refCenter[0] = avgX / (double) n; - refCenter[1] = avgY / (double) n; - refCenter[2] = avgZ / (double) n; - - return verts; - } - - protected DoubleBuffer makeGreatCircleVertices(DrawContext dc, List posList, double[] refCenter) - { - if (posList.size() < 1) - return null; - - int size = posList.size() + (this.numEdgeIntervals - 1) * (posList.size() - 1); - DoubleBuffer verts = BufferUtil.newDoubleBuffer(size * 3); - - double avgX = 0; - double avgY = 0; - double avgZ = 0; - int n = 0; - - Iterator iter = posList.iterator(); - Position pos = iter.next(); - Vec4 pt = dc.getGlobe().computePointFromPosition(pos.getLatitude(), pos.getLongitude(), pos.getElevation()); - verts.put(pt.x); - verts.put(pt.y); - verts.put(pt.z); - avgX += pt.x; - avgY += pt.y; - avgZ += pt.z; - ++n; - - double delta = 1d / this.numEdgeIntervals; - while (iter.hasNext()) - { - Position posNext = iter.next(); - for (int i = 1; i < numEdgeIntervals; i++) - { - LatLon ll = LatLon.interpolate(i * delta, new LatLon(pos.getLatitude(), pos.getLongitude()), - new LatLon(posNext.getLatitude(), posNext.getLongitude())); - double elevation = (i * delta) * pos.getElevation() + (1d - i * delta) * posNext.getElevation(); - pt = dc.getGlobe().computePointFromPosition(ll.getLatitude(), ll.getLongitude(), elevation); - verts.put(pt.x).put(pt.y).put(pt.z); - avgX += pt.x; - avgY += pt.y; - avgZ += pt.z; - ++n; - } - - pt = dc.getGlobe().computePointFromPosition(posNext.getLatitude(), posNext.getLongitude(), - pos.getElevation()); - verts.put(pt.x).put(pt.y).put(pt.z); - avgX += pt.x; - avgY += pt.y; - avgZ += pt.z; - ++n; - - pos = posNext; - } - - refCenter[0] = avgX / (double) n; - refCenter[1] = avgY / (double) n; - refCenter[2] = avgZ / (double) n; - - return verts; - } - - public void render(DrawContext dc) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - if (this.vertices == null) - { - this.intializeGeometry(dc); - - if (this.vertices == null) - return; // TODO: log a warning - } - - GL gl = dc.getGL(); - - int attrBits = GL.GL_HINT_BIT | GL.GL_CURRENT_BIT; - if (!dc.isPickingMode()) - { - if (this.color.getAlpha() != 255) - attrBits |= GL.GL_COLOR_BUFFER_BIT; - } - - gl.glPushAttrib(attrBits); - gl.glPushClientAttrib(GL.GL_CLIENT_VERTEX_ARRAY_BIT); - dc.getView().pushReferenceCenter(dc, this.referenceCenter); - - try - { - if (!dc.isPickingMode()) - { - if (this.color.getAlpha() != 255) - { - gl.glEnable(GL.GL_BLEND); - gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); - } - dc.getGL().glColor4ub((byte) this.color.getRed(), (byte) this.color.getGreen(), - (byte) this.color.getBlue(), (byte) this.color.getAlpha()); - } - - int hintAttr = GL.GL_LINE_SMOOTH_HINT; - if (this.filled) - hintAttr = GL.GL_POLYGON_SMOOTH_HINT; - gl.glHint(hintAttr, this.antiAliasHint); - - gl.glEnableClientState(GL.GL_VERTEX_ARRAY); - gl.glVertexPointer(3, GL.GL_DOUBLE, 0, this.vertices.rewind()); - - int primType = GL.GL_LINE_STRIP; - if (this.filled) - primType = GL.GL_POLYGON; - gl.glDrawArrays(primType, 0, this.vertices.capacity() / 3); - } - finally - { - gl.glPopClientAttrib(); - gl.glPopAttrib(); - dc.getView().popReferenceCenter(dc); - } - } -} diff --git a/gov/nasa/worldwind/geom/Quadrilateral.java b/gov/nasa/worldwind/geom/Quadrilateral.java deleted file mode 100644 index 38e990f..0000000 --- a/gov/nasa/worldwind/geom/Quadrilateral.java +++ /dev/null @@ -1,239 +0,0 @@ -/* -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.geom; - -import com.sun.opengl.util.*; -import gov.nasa.worldwind.*; - -import javax.media.opengl.*; -import java.awt.*; -import java.nio.*; - -/** - * @author tag - * @version $Id: Quadrilateral.java 2233 2007-07-06 23:56:34Z tgaskins $ - */ -public class Quadrilateral implements Renderable, Movable -{ - private LatLon southwestCorner; - private LatLon northeastCorner; - private double elevation; - private Vec4 referenceCenter; - private DoubleBuffer vertices; - private int antiAliasHint = GL.GL_FASTEST; - private Color color = Color.WHITE; - - public Quadrilateral(LatLon southwestCorner, LatLon northeastCorner, double elevation) - { - if (southwestCorner == null || northeastCorner == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.southwestCorner = southwestCorner; - this.northeastCorner = northeastCorner; - this.elevation = elevation; - } - - public Quadrilateral(Sector sector, double elevation) - { - if (sector == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.southwestCorner = new LatLon(sector.getMinLatitude(), sector.getMinLongitude()); - this.northeastCorner = new LatLon(sector.getMaxLatitude(), sector.getMaxLongitude()); - this.elevation = elevation; - } - - public Color getColor() - { - return color; - } - - public void setColor(Color color) - { - if (color == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.ColorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.color = color; - } - - public int getAntiAliasHint() - { - return antiAliasHint; - } - - public void setAntiAliasHint(int hint) - { - if (!(hint == GL.GL_DONT_CARE || hint == GL.GL_FASTEST || hint == GL.GL_NICEST)) - { - String msg = WorldWind.retrieveErrMsg("generic.InvalidHint"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.antiAliasHint = hint; - } - - public void setCorners(LatLon southWest, LatLon northEast) - { - this.southwestCorner = southWest; - this.northeastCorner = northEast; - this.vertices = null; - } - - public LatLon[] getCorners() - { - LatLon[] retVal = new LatLon[2]; - - retVal[0] = this.southwestCorner; - retVal[1] = this.northeastCorner; - - return retVal; - } - - public double getElevation() - { - return elevation; - } - - public void setElevation(double elevation) - { - this.elevation = elevation; - this.vertices = null; - } - - private void intializeGeometry(DrawContext dc) - { - DoubleBuffer verts = BufferUtil.newDoubleBuffer(12); - - Vec4[] p = new Vec4[4]; - - p[0] = dc.getGlobe().computePointFromPosition(this.southwestCorner.getLatitude(), - this.southwestCorner.getLongitude(), this.elevation); - p[1] = dc.getGlobe().computePointFromPosition(this.southwestCorner.getLatitude(), - this.northeastCorner.getLongitude(), this.elevation); - p[2] = dc.getGlobe().computePointFromPosition(this.northeastCorner.getLatitude(), - this.northeastCorner.getLongitude(), this.elevation); - p[3] = dc.getGlobe().computePointFromPosition(this.northeastCorner.getLatitude(), - this.southwestCorner.getLongitude(), this.elevation); - - Vec4 refcenter = new Vec4( - (p[0].x + p[2].x) / 2.0, - (p[0].y + p[2].y) / 2.0, - (p[0].z + p[2].z) / 2.0); - - for (int i = 0; i < 4; i++) - { - verts.put(p[i].x - refcenter.x); - verts.put(p[i].y - refcenter.y); - verts.put(p[i].z - refcenter.z); - } - - this.referenceCenter = refcenter; - this.vertices = verts; - } - - public void render(DrawContext dc) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalStateException(message); - } - - if (this.vertices == null) - { - this.intializeGeometry(dc); - - if (this.vertices == null) - return; // TODO: log a warning - } - - GL gl = dc.getGL(); - - int attrBits = GL.GL_HINT_BIT | GL.GL_CURRENT_BIT; - if (!dc.isPickingMode()) - { - if (this.color.getAlpha() != 255) - attrBits |= GL.GL_COLOR_BUFFER_BIT; - } - - gl.glPushAttrib(attrBits); - gl.glPushClientAttrib(GL.GL_CLIENT_VERTEX_ARRAY_BIT); - dc.getView().pushReferenceCenter(dc, this.referenceCenter); - - try - { - if (!dc.isPickingMode()) - { - if (this.color.getAlpha() != 255) - { - gl.glEnable(GL.GL_BLEND); - gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); - } - dc.getGL().glColor4ub((byte) this.color.getRed(), (byte) this.color.getGreen(), - (byte) this.color.getBlue(), (byte) this.color.getAlpha()); - } - - gl.glHint(GL.GL_POLYGON_SMOOTH_HINT, this.antiAliasHint); - gl.glEnableClientState(GL.GL_VERTEX_ARRAY); - gl.glVertexPointer(3, GL.GL_DOUBLE, 0, this.vertices.rewind()); - gl.glDrawArrays(GL.GL_QUADS, 0, 4); - } - finally - { - gl.glPopClientAttrib(); - gl.glPopAttrib(); - dc.getView().popReferenceCenter(dc); - } - } - - public Position getReferencePosition() - { - return new Position(this.southwestCorner, this.elevation); - } - - public void move(Position delta) - { - if (delta == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - this.northeastCorner = this.northeastCorner.add(delta); - this.southwestCorner = this.southwestCorner.add(delta); - this.elevation = this.elevation + delta.getElevation(); - this.vertices = null; - } - - public void moveTo(Position position) - { - if (position == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - Position delta = position.subtract(this.getReferencePosition()); - this.move(delta); - } -} diff --git a/gov/nasa/worldwind/geom/Sector.java b/gov/nasa/worldwind/geom/Sector.java index 54ac579..8470ffa 100644 --- a/gov/nasa/worldwind/geom/Sector.java +++ b/gov/nasa/worldwind/geom/Sector.java @@ -22,7 +22,7 @@ import gov.nasa.worldwind.util.Logging; * Sector instances are immutable.

* * @author Tom Gaskins - * @version $Id: Sector.java 2516 2007-08-07 01:40:17Z tgaskins $ + * @version $Id: Sector.java 2678 2007-08-25 06:42:09Z tgaskins $ * @see Angle */ public class Sector implements Cacheable, Comparable @@ -380,8 +380,8 @@ public class Sector implements Cacheable, Comparable } LatLon center = sector.getCentroid(); - double maxHeight = globe.getMaxElevation() * verticalExaggeration; - double minHeight = 0;//globe.getMinElevation() * verticalExaggeration; + double maxHeight = globe.getMaxElevation(sector) * verticalExaggeration; + double minHeight = globe.getMinElevation(sector) * verticalExaggeration; Vec4[] points = new Vec4[9]; points[0] = globe.computePointFromPosition(center.getLatitude(), center.getLongitude(), maxHeight); @@ -424,8 +424,8 @@ public class Sector implements Cacheable, Comparable // Compute the center points of the bounding cylinder's top and bottom planes. LatLon center = sector.getCentroid(); - double maxHeight = globe.getMaxElevation() * verticalExaggeration; - double minHeight = 0;//globe.getMinElevation() * verticalExaggeration; + double maxHeight = globe.getMaxElevation(sector) * verticalExaggeration; + double minHeight = 0;//globe.getMinElevation(sector) * verticalExaggeration; Vec4 centroidTop = globe.computePointFromPosition(center.getLatitude(), center.getLongitude(), maxHeight); Vec4 lowPoint = globe.computePointFromPosition(sector.getMinLatitude(), sector.getMinLongitude(), minHeight); Vec4 axis = centroidTop.normalize3(); diff --git a/gov/nasa/worldwind/geom/SurfacePolygon.java b/gov/nasa/worldwind/geom/SurfacePolygon.java deleted file mode 100644 index 524182c..0000000 --- a/gov/nasa/worldwind/geom/SurfacePolygon.java +++ /dev/null @@ -1,147 +0,0 @@ -/* -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.geom; - -import java.awt.*; -import java.awt.geom.*; -import java.awt.image.*; -import java.util.*; - -/** - * @author tag - * @version $Id: SurfacePolygon.java 2133 2007-06-23 02:08:28Z patrickmurris $ - */ -public class SurfacePolygon extends SurfaceShape -{ - - /** - * A Renderable polygon shape defined by a list of LatLon - * - * @param positions the list of LatLon positions that makes the polygon - * @param color the interior fill color - * @param borderColor the border color - */ - public SurfacePolygon(Iterable positions, Color color, Color borderColor) - { - super(positions, color, borderColor); - } - - /** - * A Renderable polygon shape defined by a list of LatLon - * - * @param positions the list of LatLon positions that makes the polygon - */ - public SurfacePolygon(Iterable positions) - { - super(positions, null, null); - } - - /** - * Draw all or part of the shape that intersects a given Sector into the given BufferedImage - */ - protected final BufferedImage drawShape(BufferedImage image, Sector sector) - { - double minLat = sector.getMinLatitude().getDegrees(); - double minLon = sector.getMinLongitude().getDegrees(); - double dLat = sector.getDeltaLatDegrees(); - double dLon = sector.getDeltaLonDegrees(); - - // Note : WWJ-36 negate latScale to define path upside-down - // (will be drawn with a mirror transform - this gets paint patterns right) - double latScale = dLat > 0 ? -image.getHeight() / dLat : 0; - double lonScale = dLon > 0 ? image.getWidth() / dLon : 0; - - // If we may cross +-180 degrees longitude, then offset - // all longitudes 180 degrees the other way - double lonOffset = 0; - if (sector.getMaxLongitude().getDegrees() == 180 && dLon < 180) - lonOffset = -180; - if (sector.getMinLongitude().getDegrees() == -180 && dLon < 180) - lonOffset = 180; - - GeneralPath path = new GeneralPath(); - - Iterator positions = this.getPositions().iterator(); - if (!positions.hasNext()) - return image; - - // Start position - LatLon pos = this.computeDrawLatLon(positions.next(), sector, lonOffset); - path.moveTo( - (float) (lonScale * (pos.getLongitude().getDegrees() - minLon - lonOffset)), - (float) (latScale * (pos.getLatitude().getDegrees() - minLat))); - - while (positions.hasNext()) - { - // Next position - LatLon posNext = this.computeDrawLatLon(positions.next(), sector, lonOffset); - // Compute number of necessary steps - int numIntervals = (int) Math.max(1d, - this.getNumEdgeIntervalsPerDegree() * - LatLon.sphericalDistance(pos, posNext).degrees); - double delta = 1d / numIntervals; - // Draw segments to next position - for (int i = 1; i < numIntervals; i++) - { - // In between steps - LatLon p = LatLon.interpolate(i * delta, pos, posNext); - path.lineTo( - (float) (lonScale * (p.getLongitude().getDegrees() - minLon - lonOffset)), - (float) (latScale * (p.getLatitude().getDegrees() - minLat))); - } - - // Set the last point directly to avoid any round-off error in the iteration above. - path.lineTo( - (float) (lonScale * (posNext.getLongitude().getDegrees() - minLon - lonOffset)), - (float) (latScale * (posNext.getLatitude().getDegrees() - minLat))); - // Next - - pos = posNext; - } - - Graphics2D g2 = image.createGraphics(); - // Set mirror Y transform - g2.setTransform(AffineTransform.getScaleInstance(1, -1)); - // Set antiliasing hint - if (this.isAntiAlias()) - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - // Draw interior - if (this.isDrawInterior()) - { - g2.setPaint(this.getPaint()); - g2.fill(path); - } - // Draw border - if (this.isDrawBorder()) - { - g2.setPaint(this.getBorderColor()); - g2.setStroke(this.getStroke()); - g2.draw(path); - } - - return image; - } - - /** - * Returns the drawing LatLon relative to a given Sector and a longitude offset Can go beyond +-180 degrees - * longitude if the offset is zero - * @param pos the real LatLon - * @param sector the drawing Sector - * @param lonOffset the current longitude offset in degrees - * @return the appropiate drawing LatLon - */ - private LatLon computeDrawLatLon(LatLon pos, Sector sector, double lonOffset) - { - int directionOffset; - directionOffset = sector.getMaxLongitude().degrees - pos.getLongitude().getDegrees() > 180 ? - 360 : 0; - directionOffset = pos.getLongitude().getDegrees() - sector.getMinLongitude().getDegrees() > 180 ? - -360 : directionOffset; - return LatLon.fromDegrees(pos.getLatitude().getDegrees(), - pos.getLongitude().getDegrees() + directionOffset + lonOffset); - } -} diff --git a/gov/nasa/worldwind/geom/SurfacePolyline.java b/gov/nasa/worldwind/geom/SurfacePolyline.java deleted file mode 100644 index cf91a17..0000000 --- a/gov/nasa/worldwind/geom/SurfacePolyline.java +++ /dev/null @@ -1,31 +0,0 @@ -/* -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.geom; - -import java.awt.*; - -/** - * @author tag - * @version $Id: SurfacePolyline.java 1448 2007-04-12 00:20:38Z tgaskins $ - */ -public class SurfacePolyline extends SurfacePolygon -{ - public SurfacePolyline(Iterable positions, Color color, Color borderColor) - { - super(positions, color, borderColor); - this.setDrawInterior(false); - this.setStroke(new BasicStroke(3f)); - } - - public SurfacePolyline(Iterable positions) - { - super(positions); - this.setDrawInterior(false); - this.setPaint(new Color(1f, 1f, 0f, .8f)); - this.setStroke(new BasicStroke(3f)); - } -} diff --git a/gov/nasa/worldwind/geom/SurfaceQuadrilateral.java b/gov/nasa/worldwind/geom/SurfaceQuadrilateral.java deleted file mode 100644 index 546ddea..0000000 --- a/gov/nasa/worldwind/geom/SurfaceQuadrilateral.java +++ /dev/null @@ -1,51 +0,0 @@ -/* -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.geom; - -import gov.nasa.worldwind.*; - -import java.awt.*; -import java.awt.image.*; -import java.util.*; - -/** - * @author tag - * @version $Id: SurfaceQuadrilateral.java 1680 2007-05-02 00:30:25Z tgaskins $ - */ -public class SurfaceQuadrilateral extends SurfacePolygon -{ - - public SurfaceQuadrilateral(Sector sector, Color color, Color borderColor) - { - super(makePositions(sector), color, borderColor); - } - - public SurfaceQuadrilateral(Sector sector) - { - super(makePositions(sector), null, null); - } - - private static Iterable makePositions(Sector sector) - { - if (sector == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.SectorIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - ArrayList positions = new ArrayList(5); - - positions.add(0, new LatLon(sector.getMinLatitude(), sector.getMinLongitude())); - positions.add(1, new LatLon(sector.getMinLatitude(), sector.getMaxLongitude())); - positions.add(2, new LatLon(sector.getMaxLatitude(), sector.getMaxLongitude())); - positions.add(3, new LatLon(sector.getMaxLatitude(), sector.getMinLongitude())); - positions.add(4, new LatLon(sector.getMinLatitude(), sector.getMinLongitude())); - - return positions; - } -} diff --git a/gov/nasa/worldwind/geom/SurfaceShape.java b/gov/nasa/worldwind/geom/SurfaceShape.java deleted file mode 100644 index 851cfd4..0000000 --- a/gov/nasa/worldwind/geom/SurfaceShape.java +++ /dev/null @@ -1,371 +0,0 @@ -/* -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.geom; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.layers.*; - -import javax.media.opengl.*; -import java.awt.*; -import java.awt.image.*; -import java.util.*; -import java.util.List; - -import com.sun.opengl.util.texture.*; - -/** - * @author tag - * @version $Id: SurfaceShape.java 2234 2007-07-07 00:10:08Z tgaskins $ - */ -public abstract class SurfaceShape implements Renderable, Disposable, Movable -{ - private static final Color DEFAULT_COLOR = new Color(1f, 1f, 0f, 0.4f); - private static final Color DEFAULT_BORDER_COLOR = new Color(1f, 1f, 0f, 0.7f); - private static final Dimension DEFAULT_TEXTURE_SIZE = new Dimension(512, 512); - private static final double DEFAULT_NUM_EDGE_INTERVALS_PER_DEGREE = 1; - - private ArrayList tiles = new ArrayList(); - private Dimension textureSize = DEFAULT_TEXTURE_SIZE; - private Paint paint; - private Color borderColor; - private Stroke stroke = new BasicStroke(); - private boolean drawBorder = true; - private boolean drawInterior = true; - private boolean antiAlias = true; - private double numEdgeIntervalsPerDegree = DEFAULT_NUM_EDGE_INTERVALS_PER_DEGREE; - private ArrayList positions = new ArrayList(); - - protected abstract BufferedImage drawShape(BufferedImage image, Sector sector); - - public SurfaceShape(Iterable positions, Color color, Color borderColor) - { - if (positions == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - // Copy positions list. - for (LatLon posNext : positions) - { - this.positions.add(posNext); - } - - // Make tile(s) - createTextureTiles(); - // Set draw attributes - this.paint = color != null ? color : DEFAULT_COLOR; - this.borderColor = borderColor != null ? borderColor : DEFAULT_BORDER_COLOR; - } - - private void createTextureTiles() - { - if (!LatLon.positionsCrossLongitudeBoundary(this.positions)) - { - this.tiles.add(new TextureTile(Sector.boundingSector(this.positions))); - } - else - { - Sector[] sectors = this.computeSplitSectors(this.positions); - this.tiles.add(new TextureTile(sectors[0])); - this.tiles.add(new TextureTile(sectors[1])); - } - } - - /** - * Returns two 'mirror' sectors each on one side of the longitude boundary - for boundary crossing shapes - * - * @param positions the shape positions - * @return an array of two sectors representing the shape - */ - private Sector[] computeSplitSectors(ArrayList positions) - { - Sector[] sectors = new Sector[2]; - // Find out longitude extremes for each sides - double maxWest = Angle.NEG180.getDegrees(); - double minEast = Angle.POS180.getDegrees(); - // Find out absolute latitude extremes - double minSouth = Angle.POS90.getDegrees(); - double maxNorth = Angle.NEG90.getDegrees(); - - LatLon lastPos = null; - for (LatLon pos : positions) - { - double lat = pos.getLatitude().getDegrees(); - if (lat > maxNorth) - maxNorth = lat; - if (lat < minSouth) - minSouth = lat; - - double lon = pos.getLongitude().getDegrees(); - if (lon <= 0 && lon > maxWest) - maxWest = lon; - if (lon >= 0 && lon < minEast) - minEast = lon; - - if (lastPos != null) - { - double lastLon = lastPos.getLongitude().getDegrees(); - if (Math.signum(lon) != Math.signum(lastLon)) - if (Math.abs(lon - lastLon) < 180) - { - // Crossing the zero longitude line too - maxWest = 0; - minEast = 0; - } - } - lastPos = pos; - } - // Mirror the two sectors - same longitude span - maxWest = minEast < -maxWest ? -minEast : maxWest; - minEast = minEast > -maxWest ? -maxWest : minEast; - - sectors[0] = Sector.fromDegrees(minSouth, maxNorth, minEast, 180d); // East side - sectors[1] = Sector.fromDegrees(minSouth, maxNorth, -180d, maxWest); // West side - - return sectors; - } - - public void dispose() - { - if (this.tiles.size() > 0) - for (TextureTile tile : this.tiles) - { - tile.dispose(); - } - tiles.clear(); - } - - public ArrayList getSectors() - { - ArrayList sectors = new ArrayList(); - for (TextureTile tile : this.tiles) - { - sectors.add(tile.getSector()); - } - return sectors; - } - - public List getPositions() - { - return positions; - } - - public Paint getPaint() - { - return paint; - } - - public void setPaint(Paint paint) - { - this.paint = paint; - this.clearTextureData(); - } - - public Color getBorderColor() - { - return borderColor; - } - - public void setBorderColor(Color borderColor) - { - this.borderColor = borderColor; - this.clearTextureData(); - } - - public Dimension getTextureSize() - { - return textureSize; - } - - public void setTextureSize(Dimension textureSize) - { - this.textureSize = textureSize; - this.clearTextureData(); - } - - public Stroke getStroke() - { - return stroke; - } - - public void setStroke(Stroke stroke) - { - this.stroke = stroke; - this.clearTextureData(); - } - - public boolean isDrawBorder() - { - return drawBorder; - } - - public void setDrawBorder(boolean drawBorder) - { - this.drawBorder = drawBorder; - this.clearTextureData(); - } - - public boolean isDrawInterior() - { - return drawInterior; - } - - public void setDrawInterior(boolean drawInterior) - { - this.drawInterior = drawInterior; - this.clearTextureData(); - } - - public boolean isAntiAlias() - { - return antiAlias; - } - - public void setAntiAlias(boolean antiAlias) - { - this.antiAlias = antiAlias; - this.clearTextureData(); - } - - public double getNumEdgeIntervalsPerDegree() - { - return numEdgeIntervalsPerDegree; - } - - public void setNumEdgeIntervalsPerDegree(double numEdgeIntervals) - { - this.numEdgeIntervalsPerDegree = numEdgeIntervals; - this.clearTextureData(); - } - - private boolean intersects(Sector sector) - { - for (TextureTile tile : this.tiles) - { - if (tile.getSector().intersects(sector)) - return true; - } - return false; - } - - public void render(DrawContext dc) - { - if (!this.intersects(dc.getVisibleSector())) - return; - - if (!this.tiles.get(0).holdsTexture()) - makeTextureData(this.textureSize); - - GL gl = dc.getGL(); - - gl.glPushAttrib(GL.GL_COLOR_BUFFER_BIT | GL.GL_POLYGON_BIT); - - try - { - if (!dc.isPickingMode()) - { - gl.glEnable(GL.GL_BLEND); - gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); - } - - gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL); - gl.glEnable(GL.GL_CULL_FACE); - gl.glCullFace(GL.GL_BACK); - - dc.getSurfaceTileRenderer().renderTiles(dc, this.tiles); - } - finally - { - gl.glPopAttrib(); - } - } - - private void makeTextureData(Dimension size) - { - for (TextureTile tile : this.tiles) - { - BufferedImage image = new BufferedImage((int) size.getWidth(), (int) size.getHeight(), - BufferedImage.TYPE_4BYTE_ABGR); - - TextureData td = new TextureData(GL.GL_RGBA, GL.GL_RGBA, false, - this.drawShape(image, tile.getSector())); - td.setMustFlipVertically(false); - tile.setTextureData(td); - } - } - - private void clearTextureData() - { - for (TextureTile tile : this.tiles) - { - if (tile.getTextureData() != null) - tile.setTextureData(null); - - if (tile.holdsTexture()) - tile.setTexture(null); - } - } - - public Position getReferencePosition() - { - LatLon centroid = this.tiles.get(0).getSector().getCentroid(); - return new Position(centroid, 0); - } - - public void move(Position position) - { - if (position == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - for (int i = 0; i < this.positions.size(); i++) - { - this.positions.set(i, this.positions.get(i).add(position)); - } - - ArrayList oldTiles = this.tiles; - this.tiles = new ArrayList(oldTiles.size()); - this.createTextureTiles(); - - // Re-use the existing texture if possible. - if (oldTiles.size() == 1 && this.tiles.size() == 1) - { - TextureTile oldTile = oldTiles.get(0); - TextureTile newTile = this.tiles.get(0); - if (oldTile.getTextureData() != null) - newTile.setTextureData(oldTile.getTextureData()); - if (oldTile.holdsTexture()) - newTile.setTexture(oldTile.getTexture()); - } - else - { - // Dispose of any current textures - for (TextureTile tile : oldTiles) - { - tile.dispose(); - } - } - } - - public void moveTo(Position position) - { - if (position == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - Position delta = position.subtract(this.getReferencePosition()); - this.move(delta); - } -} diff --git a/gov/nasa/worldwind/geom/ViewFrustum.java b/gov/nasa/worldwind/geom/ViewFrustum.java deleted file mode 100644 index 214f7d6..0000000 --- a/gov/nasa/worldwind/geom/ViewFrustum.java +++ /dev/null @@ -1,182 +0,0 @@ -/* -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.geom; - -import gov.nasa.worldwind.*; - -import java.util.logging.Level; - -/** - * @author Paul Collins - * @version $Id: ViewFrustum.java 1774 2007-05-08 01:03:37Z dcollins $ - */ -public class ViewFrustum -{ - private final Frustum frustum; - private final Matrix4 projection; -// private java.awt.geom.Rectangle2D nearRect; -// private java.awt.geom.Rectangle2D farRect; - - public ViewFrustum(Matrix4 projectionMatrix) - { - if (projectionMatrix == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.MatrixIsNull"); - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double[] m = projectionMatrix.getEntries(); - // Extract the near clipping plane from the projection-matrix. - double nearMag = Math.sqrt((m[3] + m[2]) * (m[3] + m[2]) + (m[7] + m[6]) * (m[7] + m[6]) - + (m[11] + m[10]) * (m[11] + m[10])); - Plane nearPlane = new Plane((m[3] + m[2]) / nearMag, (m[7] + m[6]) / nearMag, (m[11] + m[10]) / nearMag, - m[15] + m[14]); - // Extract the far clipping plane from the projection-matrix. - double farMag = Math.sqrt((m[3] - m[2]) * (m[3] - m[2]) + (m[7] - m[6]) * (m[7] - m[6]) - + (m[11] - m[10]) * (m[11] - m[10])); - Plane farPlane = new Plane((m[3] - m[2]) / farMag, (m[7] - m[6]) / farMag, (m[11] - m[10]) / farMag, - m[15] - m[14]); - // Extract the left clipping plane from the projection-matrix. - double leftMag = Math.sqrt((m[3] + m[0]) * (m[3] + m[0]) + (m[7] + m[4]) * (m[7] + m[4]) - + (m[11] + m[8]) * (m[11] + m[8])); - Plane leftPlane = new Plane((m[3] + m[0]) / leftMag, (m[7] + m[4]) / leftMag, (m[11] + m[8]) / leftMag, - m[15] + m[12]); - // Extract the right clipping plane from the projection-matrix. - double rightMag = Math.sqrt((m[3] - m[0]) * (m[3] - m[0]) + (m[7] - m[4]) * (m[7] - m[4]) - + (m[11] - m[8]) * (m[11] - m[8])); - Plane rightPlane = new Plane((m[3] - m[0]) / rightMag, (m[7] - m[4]) / rightMag, (m[11] - m[8]) / rightMag, - m[15] - m[12]); - // Extract the bottom clipping plane from the projection-matrix. - double bottomMag = Math.sqrt((m[3] + m[1]) * (m[3] + m[1]) + (m[7] + m[5]) * (m[7] + m[5]) - + (m[11] + m[9]) * (m[11] + m[9])); - Plane bottomPlane = new Plane((m[3] + m[1]) / bottomMag, (m[7] + m[5]) / bottomMag, (m[11] + m[9]) / bottomMag, - m[15] + m[13]); - // Extract the top clipping plane from the projection-matrix. - double topMag = Math.sqrt((m[3] - m[1]) * (m[3] - m[1]) + (m[7] - m[5]) * (m[7] - m[5]) - + (m[11] - m[9]) * (m[11] - m[9])); - Plane topPlane = new Plane((m[3] - m[1]) / topMag, (m[7] - m[5]) / topMag, (m[11] - m[9]) / topMag, - m[15] - m[13]); - this.frustum = new Frustum(nearPlane, farPlane, leftPlane, rightPlane, bottomPlane, topPlane); - this.projection = projectionMatrix; - } - - /** - * Creates a Frustum from a horizontal field-of-view, viewport aspect ratio and distance to near and - * far depth clipping planes. The near plane must be closer than the far plane, and both planes must be a positive - * distance away. - * - * @param fieldOfView horizontal field-of-view angle in the range (0, 180) - * @param viewportWidth the width of the viewport in screen pixels - * @param viewportHeight the height of the viewport in screen pixels - * @param near distance to the near depth clipping plane - * @param far distance to far depth clipping plane - * @throws IllegalArgumentException if fov is not in the range (0, 180), if either near or far are negative, or near - * is greater than or equal to far - */ - public ViewFrustum(Angle fieldOfView, int viewportWidth, int viewportHeight, double near, double far) - { - if (fieldOfView == null) - { - String message = WorldWind.retrieveErrMsg("geom.ViewFrustum.FieldOfViewIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - double fov = fieldOfView.getDegrees(); - double farMinusNear = far - near; - String message = null; - if (fov <= 0 || fov > 180) - message = WorldWind.retrieveErrMsg("geom.ViewFrustum.FieldOfViewOutOfRange"); - if (near <= 0 || farMinusNear <= 0) - message = WorldWind.retrieveErrMsg("geom.ViewFrusutm.ClippingDistanceOutOfRange"); - if (message != null) - { - WorldWind.logger().log(java.util.logging.Level.FINE, message); - throw new IllegalArgumentException(message); - } - - double focalLength = 1d / fieldOfView.tanHalfAngle(); - double aspect = viewportHeight / (double) viewportWidth; - double lrLen = Math.sqrt(focalLength * focalLength + 1); - double btLen = Math.sqrt(focalLength * focalLength + aspect * aspect); - Plane nearPlane = new Plane(0d, 0d, 0d - 1d, 0d - near); - Plane farPlane = new Plane(0d, 0d, 1d, far); - Plane leftPlane = new Plane(focalLength / lrLen, 0d, 0d - 1d / lrLen, 0); - Plane rightPlane = new Plane(0d - focalLength / lrLen, 0d, 0d - 1d / lrLen, 0d); - Plane bottomPlane = new Plane(0d, focalLength / btLen, 0d - aspect / btLen, 0d); - Plane topPlane = new Plane(0d, 0d - focalLength / btLen, 0d - aspect / btLen, 0d); - double[] projectionMatrix = new double[] { - focalLength, 0d, 0d, 0d, - 0d, focalLength / aspect, 0d, 0d, - 0d, 0d, 0d - (far + near) / farMinusNear, 0d - 1d, - 0d, 0d, 0d - (2d * far * near) / farMinusNear, 0d - }; - this.frustum = new Frustum(nearPlane, farPlane, leftPlane, rightPlane, bottomPlane, topPlane); - this.projection = new Matrix4(projectionMatrix); - } - - /** - * Creates a Frustum from three sets of parallel clipping planes (a parallel projection). In this case, - * the near and far depth clipping planes may be a negative distance away. - * - * @param left distance to the left vertical clipping plane - * @param right distance to the right vertical clipping plane - * @param bottom distance to the bottom horizontal clipping plane - * @param top distance to the top horizontal clipping plane - * @param near distance to the near depth clipping plane - * @param far distance to far depth clipping plane - * @throws IllegalArgumentException if the difference of any plane set (lright - left, top - bottom, far - near) is - * less than or equal to zero. - */ - public ViewFrustum(double near, double far, double left, double right, double bottom, - double top) - { - double farMinusNear = far - near; - double rightMinusLeft = right - left; - double topMinusBottom = top - bottom; - if (rightMinusLeft <= 0 || topMinusBottom <= 0 || farMinusNear <= 0) - { - String message = WorldWind.retrieveErrMsg("geom.ViewFrusutm.ClippingDistanceOutOfRange"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - - Plane nearPlane = new Plane(0d, 0d, 0d - 1d, near < 0d ? near : 0d - near); - Plane farPlane = new Plane(0d, 0d, 1d, far < 0d ? 0d - far : far); - Plane leftPlane = new Plane(1d, 0d, 0d, left < 0d ? left : 0d - left); - Plane rightPlane = new Plane(0d - 1d, 0d, 0d, right < 0d ? 0d - right : right); - Plane bottomPlane = new Plane(0d, 1d, 0d, bottom < 0d ? bottom : 0d - bottom); - Plane topPlane = new Plane(0d, 0d - 1d, 0d, top < 0d ? 0d - top : top); - double[] projectionMatrix = new double[] { - 2d / rightMinusLeft, 0d, 0d, 0d - (right + left) / rightMinusLeft, - 0d, 0d / topMinusBottom, 0d, 0d - (top + bottom) / topMinusBottom, - 0d, 0d, 0d - 2d / farMinusNear, 0d - (far + near) / farMinusNear, - 0d, 0d, 0d, 1d - }; - this.frustum = new Frustum(nearPlane, farPlane, leftPlane, rightPlane, bottomPlane, topPlane); - this.projection = new Matrix4(projectionMatrix); - } - - public final Frustum getFrustum() - { - return this.frustum; - } - - public final Matrix4 getProjectionMatrix() - { - return this.projection; - } - -// public final java.awt.geom.Rectangle2D getNearRectangle() -// { -// return this.nearRect; -// } - -// public final java.awt.geom.Rectangle2D getFarRectangle() -// { -// return this.farRect; -// } -} diff --git a/gov/nasa/worldwind/globes/Earth.java b/gov/nasa/worldwind/globes/Earth.java index afacc3a..c8def2f 100644 --- a/gov/nasa/worldwind/globes/Earth.java +++ b/gov/nasa/worldwind/globes/Earth.java @@ -8,14 +8,14 @@ package gov.nasa.worldwind.globes; /** * @author Tom Gaskins - * @version $Id: Earth.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: Earth.java 2830 2007-09-13 15:22:58Z dcollins $ */ public class Earth extends EllipsoidalGlobe { public static final double WGS84_EQUATORIAL_RADIUS = 6378137.0; // ellipsoid equatorial getRadius, in meters - public static final double WGS84_POLAR_RADIUS = 6378137.0; //6356752.3; // ellipsoid polar getRadius, in meters - public static final double WGS84_ES = 0;//0.00669437999013; // eccentricity squared, semi-major axis + public static final double WGS84_POLAR_RADIUS = 6356752.3; // ellipsoid polar getRadius, in meters + public static final double WGS84_ES = 0.00669437999013; // eccentricity squared, semi-major axis public Earth() { diff --git a/gov/nasa/worldwind/globes/EarthElevationModel.java b/gov/nasa/worldwind/globes/EarthElevationModel.java index c965a70..9c071cc 100644 --- a/gov/nasa/worldwind/globes/EarthElevationModel.java +++ b/gov/nasa/worldwind/globes/EarthElevationModel.java @@ -9,10 +9,11 @@ package gov.nasa.worldwind.globes; import gov.nasa.worldwind.avlist.*; import gov.nasa.worldwind.geom.*; import gov.nasa.worldwind.util.LevelSet; +import gov.nasa.worldwind.Configuration; /** * @author Tom Gaskins - * @version $Id: EarthElevationModel.java 2593 2007-08-18 00:03:31Z tgaskins $ + * @version $Id: EarthElevationModel.java 2664 2007-08-23 22:17:25Z tgaskins $ */ public class EarthElevationModel extends BasicElevationModel { @@ -23,6 +24,10 @@ public class EarthElevationModel extends BasicElevationModel { super(makeLevels(), DEPTH_OF_MARIANAS_TRENCH, HEIGHT_OF_MT_EVEREST); this.setNumExpectedValuesPerTile(22500); + String extremesFileName = + Configuration.getStringValue("gov.nasa.worldwind.avkey.ExtremeElevations.SRTM30Plus.FileName"); + if (extremesFileName != null) + this.loadExtremeElevations(extremesFileName); } private static LevelSet makeLevels() diff --git a/gov/nasa/worldwind/globes/EllipsoidalGlobe.java b/gov/nasa/worldwind/globes/EllipsoidalGlobe.java index 50af889..8d59e1b 100644 --- a/gov/nasa/worldwind/globes/EllipsoidalGlobe.java +++ b/gov/nasa/worldwind/globes/EllipsoidalGlobe.java @@ -12,7 +12,7 @@ import gov.nasa.worldwind.util.Logging; /** * @author Tom Gaskins - * @version $Id: EllipsoidalGlobe.java 2570 2007-08-16 22:31:33Z tgaskins $ + * @version $Id: EllipsoidalGlobe.java 2835 2007-09-13 19:29:22Z dcollins $ */ public class EllipsoidalGlobe extends WWObjectImpl implements Globe { @@ -100,12 +100,22 @@ public class EllipsoidalGlobe extends WWObjectImpl implements Globe public double getMaxElevation() { - return this.elevationModel.getMaximumElevation(); + return this.elevationModel.getMaxElevation(); } public double getMinElevation() { - return this.elevationModel.getMinimumElevation(); + return this.elevationModel.getMinElevation(); + } + + public double getMaxElevation(Sector sector) + { + return this.elevationModel.getMaxElevation(sector); + } + + public double getMinElevation(Sector sector) + { + return this.elevationModel.getMinElevation(sector); } public final Extent getExtent() @@ -145,10 +155,12 @@ public class EllipsoidalGlobe extends WWObjectImpl implements Globe } // Taken from Lengyel, 2Ed., Section 5.2.3, page 148. - double m = equRadius / polRadius; - double n = 1d; //this.equatorialRadius / this.equatorialRadius; + + double m = equRadius / polRadius; // "ratio of the x semi-axis length to the y semi-axis length" + double n = 1d; // "ratio of the x semi-axis length to the z semi-axis length" double m2 = m * m; double n2 = n * n; + double r2 = equRadius * equRadius; // nominal radius squared //equRadius * polRadius; double vx = line.getDirection().x; double vy = line.getDirection().y; @@ -159,7 +171,7 @@ public class EllipsoidalGlobe extends WWObjectImpl implements Globe double a = vx * vx + m2 * vy * vy + n2 * vz * vz; double b = 2d * (sx * vx + m2 * sy * vy + n2 * sz * vz); - double c = sx * sx + m2 * sy * sy + n2 * sz * sz - equRadius * polRadius; + double c = sx * sx + m2 * sy * sy + n2 * sz * sz - r2; double discriminant = discriminant(a, b, c); if (discriminant < 0) diff --git a/gov/nasa/worldwind/layers/CompassLayer.java b/gov/nasa/worldwind/layers/CompassLayer.java index ca162d4..f184425 100644 --- a/gov/nasa/worldwind/layers/CompassLayer.java +++ b/gov/nasa/worldwind/layers/CompassLayer.java @@ -48,9 +48,10 @@ public class CompassLayer extends AbstractLayer private int borderWidth = 20; // TODO: make configurable private String position = NORTHEAST; // TODO: make configurable private String resizeBehavior = RESIZE_SHRINK_ONLY; - private Texture iconTexture = null; + private int iconWidth; + private int iconHeight; private Vec4 locationCenter = null; - private boolean showTilt = false; + private boolean showTilt = true; // Draw it as ordered with an eye distance of 0 so that it shows up in front of most other things. private OrderedIcon orderedImage = new OrderedIcon(); @@ -275,8 +276,17 @@ public class CompassLayer extends AbstractLayer | GL.GL_CURRENT_BIT); attribsPushed = true; - if (this.iconTexture == null) + Texture iconTexture = dc.getTextureCache().get(this); + if (iconTexture == null) + { this.initializeTexture(dc); + iconTexture = dc.getTextureCache().get(this); + if (iconTexture == null) + { + // TODO: log warning + return; + } + } gl.glEnable(GL.GL_TEXTURE_2D); iconTexture.bind(); @@ -318,7 +328,7 @@ public class CompassLayer extends AbstractLayer gl.glRotated(heading, 0d, 0d, 1d); gl.glTranslated(-width / 2, -height / 2, 0); - TextureCoords texCoords = this.iconTexture.getImageTexCoords(); + TextureCoords texCoords = iconTexture.getImageTexCoords(); gl.glScaled(width, height, 1d); dc.drawUnitQuad(texCoords); } @@ -361,12 +371,12 @@ public class CompassLayer extends AbstractLayer private double getScaledIconWidth() { - return this.iconTexture.getWidth() * this.iconScale; + return this.iconWidth * this.iconScale; } private double getScaledIconHeight() { - return this.iconTexture.getHeight() * this.iconScale; + return this.iconHeight * this.iconScale; } private Vec4 computeLocation(java.awt.Rectangle viewport, double scale) @@ -440,7 +450,8 @@ public class CompassLayer extends AbstractLayer private void initializeTexture(DrawContext dc) { - if (this.iconTexture != null) + Texture iconTexture = dc.getTextureCache().get(this); + if (iconTexture != null) return; try @@ -455,8 +466,11 @@ public class CompassLayer extends AbstractLayer } } - this.iconTexture = TextureIO.newTexture(iconStream, true, null); - this.iconTexture.bind(); + iconTexture = TextureIO.newTexture(iconStream, true, null); + iconTexture.bind(); + this.iconWidth = iconTexture.getWidth(); + this.iconHeight = iconTexture.getHeight(); + dc.getTextureCache().put(this, iconTexture); } catch (IOException e) { diff --git a/gov/nasa/worldwind/layers/Earth/PoliticalBoundariesLayer.java b/gov/nasa/worldwind/layers/Earth/PoliticalBoundariesLayer.java deleted file mode 100644 index 5299367..0000000 --- a/gov/nasa/worldwind/layers/Earth/PoliticalBoundariesLayer.java +++ /dev/null @@ -1,86 +0,0 @@ -/* -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.Earth; - -import gov.nasa.worldwind.layers.*; -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.geom.*; - -import java.net.*; - -/** - * @author tag - * @version $Id: PoliticalBoundariesLayer.java 1731 2007-05-05 05:57:22Z tgaskins $ - */ -public class PoliticalBoundariesLayer extends TiledImageLayer -{ - public PoliticalBoundariesLayer() - { - super(makeLevels(new URLBuilder())); - this.setUseTransparentTextures(true); - } - - private static LevelSet makeLevels(URLBuilder urlBuilder) - { - AVList params = new AVListImpl(); - - params.setValue(Level.TILE_WIDTH, 512); - params.setValue(Level.TILE_HEIGHT, 512); - params.setValue(Level.CACHE_NAME, "Earth/PoliticalBoundaries"); - params.setValue(Level.SERVICE, "http://worldwind21.arc.nasa.gov/geoserver/wms"); - params.setValue(Level.DATASET_NAME, "topp:cia"); - params.setValue(Level.FORMAT_SUFFIX, ".png"); - params.setValue(Level.NUM_LEVELS, 13); - params.setValue(Level.NUM_EMPTY_LEVELS, 0); - params.setValue(Level.LEVEL_ZERO_TILE_DELTA, new LatLon(Angle.fromDegrees(36d), Angle.fromDegrees(36d))); - params.setValue(AVKey.SECTOR, Sector.FULL_SPHERE); - params.setValue(Level.TILE_URL_BUILDER, urlBuilder); - - return new LevelSet(params); - } - - private static class URLBuilder implements Level.TileURLBuilder - { - public URL getURL(Tile tile) throws MalformedURLException - { - StringBuffer sb = new StringBuffer(tile.getLevel().getService()); - if (sb.lastIndexOf("?") != sb.length() - 1) - sb.append("?"); - sb.append("request=GetMap"); - sb.append("&layers="); - sb.append(tile.getLevel().getDataset()); - sb.append("&srs=EPSG:4326"); - sb.append("&width="); - sb.append(tile.getLevel().getTileWidth()); - sb.append("&height="); - sb.append(tile.getLevel().getTileHeight()); - - Sector s = tile.getSector(); - sb.append("&bbox="); - sb.append(s.getMinLongitude().getDegrees()); - sb.append(","); - sb.append(s.getMinLatitude().getDegrees()); - sb.append(","); - sb.append(s.getMaxLongitude().getDegrees()); - sb.append(","); - sb.append(s.getMaxLatitude().getDegrees()); - - sb.append("&format=image/png"); - sb.append("&styles=countryboundaries"); -// sb.append("&bgcolor=0x000000"); - sb.append("&transparent=true"); - - return new java.net.URL(sb.toString()); - } - } - - @Override - public String toString() - { - return gov.nasa.worldwind.WorldWind.retrieveErrMsg("layers.Earth.PoliticalBoundaries.Name"); - } -} diff --git a/gov/nasa/worldwind/layers/Earth/USGSUrbanAreaOrtho.java b/gov/nasa/worldwind/layers/Earth/USGSUrbanAreaOrtho.java index 34b1519..b3461cb 100644 --- a/gov/nasa/worldwind/layers/Earth/USGSUrbanAreaOrtho.java +++ b/gov/nasa/worldwind/layers/Earth/USGSUrbanAreaOrtho.java @@ -13,14 +13,17 @@ import gov.nasa.worldwind.util.*; /** * @author tag - * @version $Id: USGSUrbanAreaOrtho.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: USGSUrbanAreaOrtho.java 2683 2007-08-25 06:45:31Z tgaskins $ */ public class USGSUrbanAreaOrtho extends BasicTiledImageLayer { public USGSUrbanAreaOrtho() { super(makeLevels()); - this.setMaxActiveAltitude(35e3d); + this.setMaxActiveAltitude(10e3d); + this.setSplitScale(0.8); +// this.setShowImageTileOutlines(true); +// this.setDrawBoundingVolumes(true); } private static LevelSet makeLevels() diff --git a/gov/nasa/worldwind/layers/PlaceNameLayer.java b/gov/nasa/worldwind/layers/PlaceNameLayer.java deleted file mode 100644 index c0a80af..0000000 --- a/gov/nasa/worldwind/layers/PlaceNameLayer.java +++ /dev/null @@ -1,871 +0,0 @@ -/* -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; - -import com.sun.opengl.util.*; -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.geom.*; - -import java.awt.*; -import java.util.*; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.*; -import java.util.logging.Level; - -/** - * @author Paul Collins - * @version $Id: PlaceNameLayer.java 2012 2007-06-13 06:19:51Z dcollins $ - */ -public class PlaceNameLayer extends AbstractLayer -{ - private final PlaceNameServiceSet placeNameServiceSet; - private final List tiles = new ArrayList(); - - /** - * @param placeNameServiceSet the set of PlaceNameService objects that PlaceNameLayer will render. - * @throws IllegalArgumentException if placeNameServiceSet is null - */ - public PlaceNameLayer(PlaceNameServiceSet placeNameServiceSet) - { - if (placeNameServiceSet == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.PlaceNameServiceSetIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - - this.placeNameServiceSet = placeNameServiceSet.deepCopy(); - for (int i = 0; i < this.placeNameServiceSet.getServiceCount(); i++) - { - tiles.add(i, buildTiles(this.placeNameServiceSet.getService(i))); - } - } - - public final PlaceNameServiceSet getPlaceNameServiceSet() - { - return this.placeNameServiceSet; - } - - // ============== Tile Assembly ======================= // - // ============== Tile Assembly ======================= // - // ============== Tile Assembly ======================= // - - private static class Tile - { - final PlaceNameService placeNameService; - final Sector sector; - final int row; - final int column; - final int hash; - // Computed data. - String fileCachePath = null; - Extent extent = null; - double extentVerticalExaggeration = Double.MIN_VALUE; - - static int computeRow(Angle delta, Angle latitude) - { - if (delta == null || latitude == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - return (int) ((latitude.getDegrees() + 90d) / delta.getDegrees()); - } - - static int computeColumn(Angle delta, Angle longitude) - { - if (delta == null || longitude == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - return (int) ((longitude.getDegrees() + 180d) / delta.getDegrees()); - } - - static Angle computeRowLatitude(int row, Angle delta) - { - if (delta == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - return Angle.fromDegrees(-90d + delta.getDegrees() * row); - } - - static Angle computeColumnLongitude(int column, Angle delta) - { - if (delta == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - return Angle.fromDegrees(-180 + delta.getDegrees() * column); - } - - Tile(PlaceNameService placeNameService, Sector sector, int row, int column) - { - this.placeNameService = placeNameService; - this.sector = sector; - this.row = row; - this.column = column; - this.hash = this.computeHash(); - } - - int computeHash() - { - return this.getFileCachePath() != null ? this.getFileCachePath().hashCode() : 0; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || this.getClass() != o.getClass()) - return false; - - final Tile other = (Tile) o; - - return this.getFileCachePath() != null ? !this.getFileCachePath().equals(other.getFileCachePath()) : - other.getFileCachePath() != null; - } - - Extent getExtent(DrawContext dc) - { - if (dc == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - - if (this.extent == null || this.extentVerticalExaggeration != dc.getVerticalExaggeration()) - { - this.extentVerticalExaggeration = dc.getVerticalExaggeration(); - this.extent = Sector.computeBoundingCylinder(dc.getGlobe(), this.extentVerticalExaggeration, - this.sector); - } - - return extent; - } - - String getFileCachePath() - { - if (this.fileCachePath == null) - this.fileCachePath = this.placeNameService.createFileCachePathFromTile(this.row, this.column); - - return this.fileCachePath; - } - - PlaceNameService getPlaceNameService() - { - return placeNameService; - } - - java.net.URL getRequestURL() throws java.net.MalformedURLException - { - return this.placeNameService.createServiceURLFromSector(this.sector); - } - - Sector getSector() - { - return sector; - } - - public int hashCode() - { - return this.hash; - } - } - - private Tile[] buildTiles(PlaceNameService placeNameService) - { - final Sector sector = placeNameService.getSector(); - 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, sector.getMinLatitude()); - int firstCol = Tile.computeColumn(dLon, sector.getMinLongitude()); - int lastRow = Tile.computeRow(dLat, sector.getMaxLatitude().subtract(dLat)); - int lastCol = Tile.computeColumn(dLon, sector.getMaxLongitude().subtract(dLon)); - - int nLatTiles = lastRow - firstRow + 1; - int nLonTiles = lastCol - firstCol + 1; - - Tile[] tiles = new Tile[nLatTiles * nLonTiles]; - - Angle p1 = Tile.computeRowLatitude(firstRow, dLat); - for (int row = firstRow; row <= lastRow; row++) - { - Angle p2; - p2 = p1.add(dLat); - - Angle t1 = Tile.computeColumnLongitude(firstCol, dLon); - for (int col = firstCol; col <= lastCol; col++) - { - Angle t2; - t2 = t1.add(dLon); - - tiles[col + row * nLonTiles] = new Tile(placeNameService, new Sector(p1, p2, t1, t2), row, col); - t1 = t2; - } - p1 = p2; - } - - return tiles; - } - - // ============== Place Name Data Structures ======================= // - // ============== Place Name Data Structures ======================= // - // ============== Place Name Data Structures ======================= // - - private static class PlaceNameChunk implements Cacheable - { - final PlaceNameService placeNameService; - final StringBuilder textArray; - final int[] textIndexArray; - final double[] latlonArray; - final int numEntries; - final long estimatedMemorySize; - - PlaceNameChunk(PlaceNameService service, StringBuilder text, int[] textIndices, - double[] positions, int numEntries) - { - this.placeNameService = service; - this.textArray = text; - this.textIndexArray = textIndices; - this.latlonArray = positions; - this.numEntries = numEntries; - this.estimatedMemorySize = this.computeEstimatedMemorySize(); - } - - long computeEstimatedMemorySize() - { - long result = 0; - result += BufferUtil.SIZEOF_SHORT * textArray.capacity(); - result += BufferUtil.SIZEOF_INT * textIndexArray.length; - result += BufferUtil.SIZEOF_DOUBLE * latlonArray.length; - return result; - } - - Position getPosition(int index) - { - int latlonIndex = 2 * index; - return Position.fromDegrees(latlonArray[latlonIndex], latlonArray[latlonIndex + 1], 0); - } - - PlaceNameService getPlaceNameService() - { - return this.placeNameService; - } - - String getText(int index) - { - int beginIndex = textIndexArray[index]; - int endIndex = (index + 1 < numEntries) ? textIndexArray[index + 1] : textArray.length(); - return this.textArray.substring(beginIndex, endIndex); - } - - public long getSizeInBytes() - { - return this.estimatedMemorySize; - } - - Iterator createRenderIterator(final DrawContext dc) - { - return new Iterator() - { - PlaceNameImpl placeNameProxy = new PlaceNameImpl(); - int index = -1; - - public boolean hasNext() - { - return index < (PlaceNameChunk.this.numEntries - 1); - } - - public PlaceName next() - { - if (!hasNext()) - throw new NoSuchElementException(); - this.updateProxy(placeNameProxy, ++index); - return placeNameProxy; - } - - public void remove() - { - throw new UnsupportedOperationException(); - } - - void updateProxy(PlaceNameImpl proxy, int index) - { - proxy.text = getText(index); - proxy.position = getPosition(index); - proxy.font = placeNameService.getFont(); - proxy.color = placeNameService.getColor(); - proxy.visible = isNameVisible(dc, placeNameService, proxy.position); - } - }; - } - } - - private static class PlaceNameImpl implements PlaceName - { - String text; - Position position; - Font font; - Color color; - boolean visible; - - PlaceNameImpl() - { - } - - public String getText() - { - return this.text; - } - - public void setText(String text) - { - throw new UnsupportedOperationException(); - } - - public Position getPosition() - { - return this.position; - } - - public void setPosition(Position position) - { - throw new UnsupportedOperationException(); - } - - public Font getFont() - { - return this.font; - } - - public void setFont(Font font) - { - throw new UnsupportedOperationException(); - } - - public Color getColor() - { - return this.color; - } - - public void setColor(Color color) - { - throw new UnsupportedOperationException(); - } - - public boolean isVisible() - { - return this.visible; - } - - public void setVisible(boolean visible) - { - throw new UnsupportedOperationException(); - } - - public WWIcon getIcon() - { - return null; - } - - public void setIcon(WWIcon icon) - { - throw new UnsupportedOperationException(); - } - } - - // ============== Rendering ======================= // - // ============== Rendering ======================= // - // ============== Rendering ======================= // - - private final PlaceNameRenderer placeNameRenderer = new PlaceNameRenderer(); - - @Override - protected void doRender(DrawContext dc) - { - final boolean enableDepthTest = dc.getView().getAltitude() - < (dc.getVerticalExaggeration() * dc.getGlobe().getMaxElevation()); - - int serviceCount = this.placeNameServiceSet.getServiceCount(); - for (int i = 0; i < serviceCount; i++) - { - PlaceNameService placeNameService = this.placeNameServiceSet.getService(i); - if (!isServiceVisible(dc, placeNameService)) - continue; - - double minDist = placeNameService.getMinDisplayDistance(); - double maxDist = placeNameService.getMaxDisplayDistance(); - double minDistSquared = minDist * minDist; - double maxDistSquared = maxDist * maxDist; - - Tile[] tiles = this.tiles.get(i); - for (Tile tile : tiles) - { - try - { - drawOrRequestTile(dc, tile, minDistSquared, maxDistSquared, enableDepthTest); - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionRenderingTile"); - WorldWind.logger().log(Level.FINE, message, e); - } - } - } - - this.sendRequests(); - } - - private void drawOrRequestTile(DrawContext dc, Tile tile, double minDisplayDistanceSquared, - double maxDisplayDistanceSquared, boolean enableDepthTest) - { - if (!isTileVisible(dc, tile, minDisplayDistanceSquared, maxDisplayDistanceSquared)) - return; - - Object cacheObj = WorldWind.memoryCache().getObject(tile); - if (cacheObj == null) - { - this.requestTile(this.readQueue, tile); - return; - } - - if (!(cacheObj instanceof PlaceNameChunk)) - return; - - PlaceNameChunk placeNameChunk = (PlaceNameChunk) cacheObj; - Iterator renderIter = placeNameChunk.createRenderIterator(dc); - placeNameRenderer.render(dc, renderIter, enableDepthTest); - } - - private static boolean isServiceVisible(DrawContext dc, PlaceNameService placeNameService) - { - if (!placeNameService.isEnabled()) - return false; - //noinspection SimplifiableIfStatement - if (dc.getVisibleSector() != null && !placeNameService.getSector().intersects(dc.getVisibleSector())) - return false; - - return placeNameService.getExtent(dc).intersects(dc.getView().getFrustumInModelCoordinates()); - } - - private static boolean isTileVisible(DrawContext dc, Tile tile, double minDistanceSquared, - double maxDistanceSquared) - { - if (!tile.getSector().intersects(dc.getVisibleSector())) - return false; - - View view = dc.getView(); - Angle lat = clampAngle(view.getLatitude(), tile.getSector().getMinLatitude(), - tile.getSector().getMaxLatitude()); - Angle lon = clampAngle(view.getLongitude(), tile.getSector().getMinLongitude(), - tile.getSector().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; - } - - private static boolean isNameVisible(DrawContext dc, PlaceNameService service, Position namePosition) - { - double elevation = dc.getVerticalExaggeration() * namePosition.getElevation(); - Vec4 namePoint = dc.getGlobe().computePointFromPosition(namePosition.getLatitude(), - namePosition.getLongitude(), elevation); - Vec4 eyeVec = dc.getView().getEyePoint(); - - double dist = eyeVec.distanceTo3(namePoint); - return dist >= service.getMinDisplayDistance() && dist <= service.getMaxDisplayDistance(); - } - - private static Angle clampAngle(Angle a, Angle min, Angle max) - { - return a.compareTo(min) < 0 ? min : (a.compareTo(max) > 0 ? max : a); - } - - // ============== Image Reading and Downloading ======================= // - // ============== Image Reading and Downloading ======================= // - // ============== Image Reading and Downloading ======================= // - - private static final int MAX_REQUESTS = 64; - private final Queue downloadQueue = new LinkedBlockingQueue(MAX_REQUESTS); - private final Queue readQueue = new LinkedBlockingQueue(MAX_REQUESTS); - - private static class RequestTask implements Runnable - { - final PlaceNameLayer layer; - final Tile tile; - - RequestTask(PlaceNameLayer layer, Tile tile) - { - this.layer = layer; - this.tile = tile; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || this.getClass() != o.getClass()) - return false; - - final RequestTask other = (RequestTask) o; - - // Don't include layer in comparison so that requests are shared among layers - return !(this.tile != null ? !this.tile.equals(other.tile) : other.tile != null); - } - - @Override - public int hashCode() - { - return (this.tile != null ? this.tile.hashCode() : 0); - } - - public void run() - { - synchronized (tile) - { - if (WorldWind.memoryCache().getObject(this.tile) != null) - return; - - final java.net.URL tileURL = WorldWind.dataFileCache().findFile(tile.getFileCachePath(), false); - if (tileURL != null) - { - if (this.layer.loadTile(this.tile, tileURL)) - { - tile.getPlaceNameService().unmarkResourceAbsent(tile.getPlaceNameService().getTileNumber( - tile.row, - tile.column)); - this.layer.firePropertyChange(AVKey.LAYER, null, this); - } - else - { - // Assume that something's wrong with the file and delete it. - WorldWind.dataFileCache().removeFile(tileURL); - tile.getPlaceNameService().markResourceAbsent(tile.getPlaceNameService().getTileNumber(tile.row, - tile.column)); - String message = WorldWind.retrieveErrMsg("generic.DeletedCorruptDataFile") + tileURL; - WorldWind.logger().log(Level.FINE, message); - } - return; - } - } - - this.layer.requestTile(this.layer.downloadQueue, this.tile); - } - - public String toString() - { - return this.tile.toString(); - } - } - - private static class DownloadPostProcessor implements RetrievalPostProcessor - { - final PlaceNameLayer layer; - final Tile tile; - - private DownloadPostProcessor(PlaceNameLayer layer, Tile tile) - { - this.layer = layer; - this.tile = tile; - } - - public java.nio.ByteBuffer run(Retriever retriever) - { - if (retriever == null) - { - String msg = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull"); - WorldWind.logger().log(Level.FINE, msg); - throw new IllegalArgumentException(msg); - } - - if (!retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL)) - return null; - - if (!(retriever instanceof URLRetriever)) - return null; - - try - { - if (retriever instanceof HTTPRetriever) - { - HTTPRetriever httpRetriever = (HTTPRetriever) retriever; - if (httpRetriever.getResponseCode() == java.net.HttpURLConnection.HTTP_NO_CONTENT) - { - // Mark tile as missing to avoid further attempts - tile.getPlaceNameService().markResourceAbsent(tile.getPlaceNameService().getTileNumber(tile.row, - tile.column)); - return null; - } - } - - URLRetriever urlRetriever = (URLRetriever) retriever; - java.nio.ByteBuffer buffer = urlRetriever.getBuffer(); - - synchronized (tile) - { - final java.io.File cacheFile = WorldWind.dataFileCache().newFile(this.tile.getFileCachePath()); - if (cacheFile == null) - { - String msg = WorldWind.retrieveErrMsg("generic.CantCreateCacheFile") - + this.tile.getFileCachePath(); - WorldWind.logger().log(Level.FINE, msg); - return null; - } - - if (cacheFile.exists()) - return buffer; // info is already here; don't need to do anything - - if (buffer != null) - { - WWIO.saveBuffer(buffer, cacheFile); - this.layer.firePropertyChange(AVKey.LAYER, null, this); - return buffer; - } - } - } - catch (java.io.IOException e) - { - String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionSavingRetrievedFile"); - WorldWind.logger().log(Level.FINE, message + this.tile.getFileCachePath(), e); - } - - return null; - } - } - - private static class GMLPlaceNameSAXHandler extends org.xml.sax.helpers.DefaultHandler - { - static final String GML_FEATURE_MEMBER = "gml:featureMember"; - static final String TOPP_FULL_NAME_ND = "topp:full_name_nd"; - static final String TOPP_LATITUDE = "topp:latitude"; - static final String TOPP_LONGITUDE = "topp:longitude"; - final LinkedList qNameStack = new LinkedList(); - boolean inBeginEndPair = false; - StringBuilder latBuffer = new StringBuilder(); - StringBuilder lonBuffer = new StringBuilder(); - - StringBuilder textArray = new StringBuilder(); - int[] textIndexArray = new int[16]; - double[] latlonArray = new double[16]; - int numEntries = 0; - - GMLPlaceNameSAXHandler() - { - } - - PlaceNameChunk createPlaceNameChunk(PlaceNameService service) - { - return new PlaceNameChunk(service, this.textArray, this.textIndexArray, this.latlonArray, this.numEntries); - } - - void beginEntry() - { - int textIndex = this.textArray.length(); - this.textIndexArray = append(this.textIndexArray, this.numEntries, textIndex); - this.inBeginEndPair = true; - } - - void endEntry() - { - double lat = this.parseDouble(this.latBuffer); - double lon = this.parseDouble(this.lonBuffer); - int numLatLon = 2 * this.numEntries; - this.latlonArray = this.append(this.latlonArray, numLatLon, lat); - numLatLon++; - this.latlonArray = this.append(this.latlonArray, numLatLon, lon); - - this.latBuffer.delete(0, this.latBuffer.length()); - this.lonBuffer.delete(0, this.lonBuffer.length()); - this.inBeginEndPair = false; - this.numEntries++; - } - - double parseDouble(StringBuilder sb) - { - double value = 0; - try - { - value = Double.parseDouble(sb.toString()); - } - catch (NumberFormatException e) - { - String msg = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToReadFile"); - WorldWind.logger().log(Level.FINE, msg, e); - } - return value; - } - - int[] append(int[] array, int index, int value) - { - if (index >= array.length) - array = this.resizeArray(array); - array[index] = value; - return array; - } - - int[] resizeArray(int[] oldArray) - { - int newSize = 2 * oldArray.length; - int[] newArray = new int[newSize]; - System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); - return newArray; - } - - double[] append(double[] array, int index, double value) - { - if (index >= array.length) - array = this.resizeArray(array); - array[index] = value; - return array; - } - - double[] resizeArray(double[] oldArray) - { - int newSize = 2 * oldArray.length; - double[] newArray = new double[newSize]; - System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); - return newArray; - } - - public void characters(char ch[], int start, int length) - { - if (!this.inBeginEndPair) - return; - - String top = this.qNameStack.getFirst(); - - StringBuilder sb = null; - if (TOPP_LATITUDE == top) - sb = this.latBuffer; - else if (TOPP_LONGITUDE == top) - sb = this.lonBuffer; - else if (TOPP_FULL_NAME_ND == top) - sb = this.textArray; - - if (sb != null) - sb.append(ch, start, length); - } - - public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attributes) - { - String internQName = qName.intern(); - // Don't validate uri, localName or attributes because they aren't used. - if (GML_FEATURE_MEMBER == internQName) - this.beginEntry(); - this.qNameStack.addFirst(qName); - } - - public void endElement(String uri, String localName, String qName) - { - String internQName = qName.intern(); - // Don't validate uri or localName because they aren't used. - if (GML_FEATURE_MEMBER == internQName) - this.endEntry(); - this.qNameStack.removeFirst(); - } - } - - private boolean loadTile(Tile tile, java.net.URL url) - { - PlaceNameChunk placeNameChunk = readTile(tile, url); - if (placeNameChunk == null) - return false; - - WorldWind.memoryCache().add(tile, placeNameChunk); - return true; - } - - private static PlaceNameChunk readTile(Tile tile, java.net.URL url) - { - java.io.InputStream is = null; - - try - { - String path = url.getFile(); - path = path.replaceAll("%20", " "); // TODO: find a better way to get a path usable by FileInputStream - - java.io.FileInputStream fis = new java.io.FileInputStream(path); - java.io.BufferedInputStream buf = new java.io.BufferedInputStream(fis); - is = new java.util.zip.GZIPInputStream(buf); - - GMLPlaceNameSAXHandler handler = new GMLPlaceNameSAXHandler(); - javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser().parse(is, handler); - return handler.createPlaceNameChunk(tile.getPlaceNameService()); - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToReadFile"); - WorldWind.logger().log(Level.FINE, message, e); - } - finally - { - try - { - if (is != null) - is.close(); - } - catch (java.io.IOException e) - { - String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToReadFile"); - WorldWind.logger().log(Level.FINE, message, e); - } - } - - return null; - } - - private void requestTile(Queue queue, Tile tile) - { - if (tile.getPlaceNameService().isResourceAbsent(tile.getPlaceNameService().getTileNumber( - tile.row, tile.column))) - return; - if (!queue.contains(tile)) - queue.offer(tile); - } - - private void sendRequests() - { - Tile tile; - // Send threaded read tasks. - while (!WorldWind.threadedTaskService().isFull() && (tile = this.readQueue.poll()) != null) - { - WorldWind.threadedTaskService().addTask(new RequestTask(this, tile)); - } - // Send retriever tasks. - while (!WorldWind.retrievalService().isFull() && (tile = this.downloadQueue.poll()) != null) - { - java.net.URL url; - try - { - url = tile.getRequestURL(); - } - catch (java.net.MalformedURLException e) - { - String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToDownloadFile"); - WorldWind.logger().log(Level.FINE, message + tile, e); - return; - } - WorldWind.retrievalService().runRetriever(new HTTPRetriever(url, new DownloadPostProcessor(this, tile))); - } - } -} diff --git a/gov/nasa/worldwind/layers/RpfLayer.java b/gov/nasa/worldwind/layers/RpfLayer.java deleted file mode 100644 index 28389bb..0000000 --- a/gov/nasa/worldwind/layers/RpfLayer.java +++ /dev/null @@ -1,1297 +0,0 @@ -/* -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; - -import com.sun.opengl.util.*; -import com.sun.opengl.util.texture.*; -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.formats.rpf.*; -import gov.nasa.worldwind.geom.*; - -import javax.media.opengl.*; -import java.awt.*; -import java.awt.geom.*; -import java.awt.image.*; -import java.io.*; -import java.net.*; -import java.nio.*; -import java.util.*; -import java.util.Queue; -import java.util.concurrent.*; -import java.util.concurrent.locks.*; -import java.util.logging.Level; - -/** - * @author dcollins - * @version $Id: RpfLayer.java 2233 2007-07-06 23:56:34Z tgaskins $ - */ -public class RpfLayer extends AbstractLayer -{ - public static final int DefaultWindow = 8; - public static final double DefaultDrawFrameThreshold = 0.75; - public static final double DefaultDrawIconThreshold = 0.25; - public static final long DefaultCacheLoWater = 192L * 1024L * 1024L; - public static final long DefaultCacheHiWater = 256L * 1024L * 1024L; - private static final long FrameExpiryTime = new GregorianCalendar(2007, 5, 31).getTimeInMillis(); - private final RpfDataSeries dataSeries; - private int latitudeWindow; - private int longitudeWindow; - private double drawFrameThreshold; - private double drawIconThreshold; - - private final MemoryCache memoryCache; - private final String cachePathBase = "Earth/RPF/"; - - public RpfLayer(RpfDataSeries dataSeries) - { - if (dataSeries == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.RpfDataSeriesIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.dataSeries = dataSeries; - this.latitudeWindow = DefaultWindow; - this.longitudeWindow = DefaultWindow; - this.drawFrameThreshold = DefaultDrawFrameThreshold; - this.drawIconThreshold = DefaultDrawIconThreshold; - // Initialize the MemoryCache. - this.memoryCache = new BasicMemoryCache(DefaultCacheLoWater, DefaultCacheHiWater); - this.memoryCache.addCacheListener(new MemoryCache.CacheListener() - { - public void entryRemoved(Object key, Object clientObject) - { - if (clientObject == null || !(clientObject instanceof RpfTextureTile)) - return; - RpfTextureTile rpfTextureTile = (RpfTextureTile) clientObject; - disposalQueue.offer(rpfTextureTile); - } - }); - } - - public int getLatitudeWindow() - { - return latitudeWindow; - } - - public void setLatitudeWindow(int latitudeWindow) - { - this.latitudeWindow = latitudeWindow; - } - - public int getLongitudeWindow() - { - return longitudeWindow; - } - - public void setLongitudeWindow(int longitudeWindow) - { - this.longitudeWindow = longitudeWindow; - } - - public double getDrawFrameThreshold() - { - return drawFrameThreshold; - } - - public void setDrawFrameThreshold(double drawFrameThreshold) - { - this.drawFrameThreshold = drawFrameThreshold; - } - - public double getDrawIconThreshold() - { - return drawIconThreshold; - } - - public void setDrawIconThreshold(double drawIconThreshold) - { - this.drawIconThreshold = drawIconThreshold; - } - - public String toString() - { - StringBuilder sb = new StringBuilder(); - sb.append(this.dataSeries.seriesCode); - sb.append(": "); - sb.append(this.dataSeries.dataSeries); - return sb.toString(); - } - - // ============== Frame Directory ======================= // - // ============== Frame Directory ======================= // - // ============== Frame Directory ======================= // - - private final Map frameDirectory = new HashMap(); - private Sector sector = Sector.EMPTY_SECTOR; - private int modCount = 0; - private int lastModCount = 0; - - private static class FrameKey - { - public final RpfZone zone; - public final int frameNumber; - private final int hashCode; - - public FrameKey(RpfZone zone, int frameNumber) - { - this.zone = zone; - this.frameNumber = frameNumber; - this.hashCode = this.computeHash(); - } - - private int computeHash() - { - int hash = 0; - if (this.zone != null) - hash = 29 * hash + this.zone.ordinal(); - hash = 29 * hash + this.frameNumber; - return hash; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || !o.getClass().equals(this.getClass())) - return false; - final FrameKey that = (FrameKey) o; - return (this.zone == that.zone) && (this.frameNumber == that.frameNumber); - } - - public int hashCode() - { - return this.hashCode; - } - } - - private static class FrameRecord - { - private final String filePath; - private RpfFrameProperties properties; - private Sector sector; - private String cacheFilePath; - final Lock fileLock = new ReentrantLock(); - - public FrameRecord(File file) - { - String fileName = file.getName().toUpperCase(); - this.filePath = file.getAbsolutePath(); - this.properties = RpfFrameFilenameUtil.parseFilename(fileName); - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || !o.getClass().equals(this.getClass())) - return false; - final FrameRecord that = (FrameRecord) o; - return this.filePath.equals(that.filePath); - } - - public String getCacheFilePath(RpfLayer layer) - { - if (this.cacheFilePath == null) - { - String fileName = RpfFrameFilenameUtil.filenameFor(this.properties); - this.cacheFilePath = cachePathFor(layer.cachePathBase, fileName, this.properties); - } - return this.cacheFilePath; - } - - public long getExpiryTime() - { - return FrameExpiryTime; - } - - public String getFilePath() - { - return this.filePath; - } - - public RpfFrameProperties getRpfFrameProperties() - { - return this.properties; - } - - public Sector getSector() - { - if (this.sector == null) - { - RpfFrameProperties rpfFrameProperties = this.getRpfFrameProperties(); - this.sector = sectorFor(rpfFrameProperties); - } - return this.sector; - } - } - - public int addFrame(File file) - { - if (file == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - - FrameRecord record = null; - try - { - record = new FrameRecord(file); - } - catch (Exception e) - { - String message = WorldWind.retrieveErrMsg("layers.RpfLayer.ExceptionParsingFileName") + file; - WorldWind.logger().log(Level.FINE, message, e); - } - - if (record != null && (this.dataSeries == record.getRpfFrameProperties().dataSeries)) - { - this.addRecord(record); - return 1; - } - return 0; - } - - private void addRecord(FrameRecord record) - { - FrameKey key = keyFor(record); - this.frameDirectory.put(key, record); - ++this.modCount; - } - - private static String cachePathFor(String cachePathBase, String filename, RpfFrameProperties properties) - { - StringBuilder sb = new StringBuilder(cachePathBase); - sb.append(properties.dataSeries.seriesCode).append(File.separatorChar); - sb.append(properties.zone.zoneCode).append(File.separatorChar); - sb.append(filename); - sb.append(".").append(TextureIO.DDS); - return sb.toString(); - } - - private static FrameKey keyFor(FrameRecord record) - { - return new FrameKey(record.getRpfFrameProperties().zone, record.getRpfFrameProperties().frameNumber); - } - - public int removeFrameFile(File file) - { - if (file == null) - return 0; - RpfFrameProperties properties = null; - try - { - properties = RpfFrameFilenameUtil.parseFilename(file.getName().toUpperCase()); - } - catch (IllegalArgumentException e) - { - String message = WorldWind.retrieveErrMsg("layers.RpfLayer.ExceptionParsingFileName") + file; - WorldWind.logger().log(Level.FINE, message, e); - } - return removeFrame(properties); - } - - private int removeFrame(RpfFrameProperties properties) - { - if (properties == null) - return 0; - if (this.dataSeries == properties.dataSeries) - { - this.removeKey(new FrameKey(properties.zone, properties.frameNumber)); - return 1; - } - return 0; - } - - private boolean removeKey(FrameKey key) - { - FrameRecord value = this.frameDirectory.remove(key); - --this.modCount; - return value != null; - } - - private static Sector sectorFor(RpfFrameProperties properties) - { - if (properties == null - || properties.zone == null - || properties.dataSeries == null) - return null; - RpfZone.ZoneValues zoneValues = properties.zone.zoneValues(properties.dataSeries); - if (properties.frameNumber < 0 || properties.frameNumber > (zoneValues.maximumFrameNumber - 1)) - return null; - return zoneValues.frameExtent(properties.frameNumber); - } - - private void updateSector() - { - Sector newSector = null; - for (FrameRecord record : this.frameDirectory.values()) - { - if (record.getSector() != null) - newSector = (newSector != null) ? newSector.union(record.getSector()) : record.getSector(); - } - this.sector = newSector; - } - - // ============== Tile Assembly ======================= // - // ============== Tile Assembly ======================= // - // ============== Tile Assembly ======================= // - - private void assembleTiles(DrawContext dc, Map cachedTiles, - Queue tilesToRender) - { - synchronized (cachedTiles) - { - for (RpfTextureTile rpfTextureTile : cachedTiles.values()) - { - if (this.isSectorVisible(dc, rpfTextureTile.getSector())) - tilesToRender.offer(rpfTextureTile); - } - } - } - - private void assembleRequests(DrawContext dc, RpfDataSeries dataSeries, Sector viewingSector, - Queue framesToRequest) - { - for (RpfZone zone : RpfZone.values()) - { - RpfZone.ZoneValues zoneValues = zone.zoneValues(dataSeries); - Sector sector = zoneValues.extent.intersection(viewingSector); - if (sector != null && this.isSectorVisible(dc, sector)) - this.assembleRequestsForZone(dc, zoneValues, sector, framesToRequest); - } - } - - private void assembleRequestsForZone(DrawContext dc, RpfZone.ZoneValues zoneValues, Sector sector, - Queue framesToRequest) - { - int startRow = zoneValues.frameRowFromLatitude(sector.getMinLatitude()); - int endRow = zoneValues.frameRowFromLatitude(sector.getMaxLatitude()); - int startCol = zoneValues.frameColumnFromLongitude(sector.getMinLongitude()); - int endCol = zoneValues.frameColumnFromLongitude(sector.getMaxLongitude()); - - for (int row = startRow; row <= endRow; row++) - { - for (int col = startCol; col <= endCol; col++) - { - int frameNum = zoneValues.frameNumber(row, col); - FrameKey key = new FrameKey(zoneValues.zone, frameNum); - RpfTextureTile tile = this.getTile(key); - if (tile == null) - { - FrameRecord record = this.frameDirectory.get(key); - if (record != null && this.isSectorVisible(dc, record.getSector())) - framesToRequest.offer(record); - } - } - } - } - - private static Sector[] normalizeSector(Sector sector) - { - Angle minLat = clampAngle(sector.getMinLatitude(), Angle.NEG90, Angle.POS90); - Angle maxLat = clampAngle(sector.getMaxLatitude(), Angle.NEG90, Angle.POS90); - if (maxLat.degrees < minLat.degrees) - { - Angle tmp = minLat; - minLat = maxLat; - maxLat = tmp; - } - - Angle minLon = normalizeAngle(sector.getMinLongitude(), Angle.NEG180, Angle.POS180); - Angle maxLon = normalizeAngle(sector.getMaxLongitude(), Angle.NEG180, Angle.POS180); - if (maxLon.degrees < minLon.degrees) - { - return new Sector[] { - new Sector(minLat, maxLat, minLon, Angle.POS180), - new Sector(minLat, maxLat, Angle.NEG180, maxLon), - }; - } - - return new Sector[] {new Sector(minLat, maxLat, minLon, maxLon)}; - } - - private static Sector createViewSector(RpfDataSeries dataSeries, - Angle centerLat, Angle centerLon, int latWindowFrames, int lonWindowFrames) - { - RpfZone.ZoneValues zoneValues = RpfZone.Zone1.zoneValues(dataSeries); - if (zoneValues == null) - return null; - Angle latWindow = zoneValues.latitudinalFrameExtent.multiply(latWindowFrames); - Angle lonWindow = zoneValues.longitudinalFrameExtent.multiply(lonWindowFrames); - Angle lat_over_2 = latWindow.divide(2.0); - Angle lon_over_2 = lonWindow.divide(2.0); - return new Sector( - centerLat.subtract(lat_over_2), centerLat.add(lat_over_2), - centerLon.subtract(lon_over_2), centerLon.add(lon_over_2)); - } - - private static Angle clampAngle(Angle angle, Angle min, Angle max) - { - return (angle.degrees < min.degrees) ? min : ((angle.degrees > max.degrees) ? max : angle); - } - - private static Angle normalizeAngle(Angle angle, Angle min, Angle max) - { - Angle range = max.subtract(min); - return (angle.degrees < min.degrees) ? - angle.add(range) : ((angle.degrees > max.degrees) ? angle.subtract(range) : angle); - } - - // ============== Rendering ======================= // - // ============== Rendering ======================= // - // ============== Rendering ======================= // - - // TODO: compute overview image, simple using j2D - // TODO: extrapolate based on small sample - - private static class RpfTextureTile extends TextureTile - { - final FrameKey frameKey; - final FrameRecord frameRecord; - - RpfTextureTile(FrameKey frameKey, FrameRecord frameRecord) - { - super(frameRecord.getSector()); - this.frameKey = frameKey; - this.frameRecord = frameRecord; - } - } - - private final BlockingQueue disposalQueue = new LinkedBlockingQueue(); - private final IconRenderer iconRenderer = new IconRenderer(); - private TextureTile coverageTile; - private WWIcon icon; - private boolean drawCoverage = true; - private boolean drawIcon = true; - private static Boolean haveARBNonPowerOfTwo = null; - - private static TextureData createCoverageTextureData(int width, int height, - Sector extent, Collection coverage) - { - IntBuffer buffer = BufferUtil.newIntBuffer(width * height); - Angle latWidth = extent.getMaxLatitude().subtract(extent.getMinLatitude()); - Angle lonWidth = extent.getMaxLongitude().subtract(extent.getMinLongitude()); - for (FrameRecord record : coverage) - { - int x0 = (int) Math.round((width - 1) - * record.sector.getMinLongitude().subtract(extent.getMinLongitude()).divide(lonWidth)); - int x1 = (int) Math.round((width - 1) - * record.sector.getMaxLongitude().subtract(extent.getMinLongitude()).divide(lonWidth)); - - int y0 = (int) Math.round((height - 1) - * record.sector.getMinLatitude().subtract(extent.getMinLatitude()).divide(latWidth)); - int y1 = (int) Math.round((height - 1) - * record.sector.getMaxLatitude().subtract(extent.getMinLatitude()).divide(latWidth)); - - for (int y = y0; y <= y1; y++) - { - for (int x = x0; x <= x1; x++) - { - buffer.put(x + y * width, 0x4040407F); - } - } - } - buffer.rewind(); - return new TextureData(GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_INT_8_8_8_8, - false, false, false, buffer, null); - } - -// private static TextureData createCoverageTextureData(int width, int height, -// Sector extent, Collection coverage) -// { -// BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); -// Graphics2D g2d = image.createGraphics(); -// Color fillColor = new Color(0.5f, 0.5f, 0.5f, 0.5f); -// for (FrameRecord record : coverage) -// drawFrame(g2d, width, height, fillColor, extent, record); -// -// TextureData textureData = new TextureData(GL.GL_RGBA, GL.GL_RGBA, false, image); -// textureData.setMustFlipVertically(false); -// return textureData; -// } - -// private static void drawFrame(Graphics2D g2d, int gWidth, int gHeight, Color fillColor, -// Sector graphicsExtent, FrameRecord record) -// { -// Angle xRange = graphicsExtent.getMaxLongitude().subtract(graphicsExtent.getMinLongitude()); -// int x0 = (int) Math.round((gWidth - 1) -// * record.getSector().getMinLongitude().subtract(graphicsExtent.getMinLongitude()).divide(xRange)); -// int x1 = (int) Math.round((gWidth - 1) -// * record.getSector().getMaxLongitude().subtract(graphicsExtent.getMinLongitude()).divide(xRange)); -// -// Angle yRange = graphicsExtent.getMaxLatitude().subtract(graphicsExtent.getMinLatitude()); -// int y0 = (int) Math.round((gHeight - 1) -// * record.getSector().getMinLatitude().subtract(graphicsExtent.getMinLatitude()).divide(yRange)); -// int y1 = (int) Math.round((gHeight - 1) -// * record.getSector().getMaxLatitude().subtract(graphicsExtent.getMinLatitude()).divide(yRange)); -// -// g2d.setColor(fillColor); -// g2d.fillRect(x0, y0, x1 - x0, y1 - y0); -// -//// BufferedImage img = null; -//// try -//// { -//// RpfImageFile rpfImageFile = RpfImageFile.load(new File(record.filePath)); -//// img = rpfImageFile.getBufferedImage(); -//// } -//// catch (Exception e) -//// { -//// WorldWind.logger().log(Level.FINE, "", e); -//// } -//// if (img == null) -//// return; -//// -//// -//// double sx = (x1 - x0) / (double) img.getWidth(); -//// double sy = (y1 - y0) / (double) img.getHeight(); -//// BufferedImageOp op = new AffineTransformOp( -//// AffineTransform.getScaleInstance(sx, sy), AffineTransformOp.TYPE_BICUBIC); -//// -//// g2d.drawImage(img, op, x0, y0); -// } - - public void dispose() - { - // Clear queues. - this.cachedTiles.clear(); - this.readQueue.clear(); - this.downloadQueue.clear(); - // Dispose objects that allocated GL memory. - if (this.iconRenderer != null) - disposalQueue.offer(this.iconRenderer); - if (this.coverageTile != null) - { - disposalQueue.offer(this.coverageTile); - this.coverageTile = null; - } - processDisposables(); - } - - protected void doRender(DrawContext dc) - { - // Gather GL extension info. - if (haveARBNonPowerOfTwo == null) - haveARBNonPowerOfTwo = dc.getGL().isExtensionAvailable("GL_ARB_texture_non_power_of_two"); - - // Process disposable queue. - this.processDisposables(); - - // Update sector and coverage renderables when frame contents change. - if (this.modCount != this.lastModCount) - { - this.updateSector(); - this.updateCoverage(); - this.lastModCount = this.modCount; - } - - if (!this.isSectorVisible(dc, this.sector)) - return; - - // Create viewing window. - View view = dc.getView(); - Sector viewingSector = createViewSector( - this.dataSeries, - view.getLatitude(), view.getLongitude(), - this.latitudeWindow, this.longitudeWindow); - - // Assemble frame requests. - Queue requestQueue = new LinkedList(); - for (Sector sector : normalizeSector(viewingSector)) - { - this.assembleRequests(dc, this.dataSeries, sector, requestQueue); - } - - // Assemble visible, in-memory tiles. - Queue renderQueue = new LinkedList(); - this.assembleTiles(dc, this.cachedTiles, renderQueue); - // Compute the union of rendred tile sectors. - Sector drawSector = null; - for (RpfTextureTile tile : renderQueue) - { - drawSector = (drawSector != null) ? drawSector.union(tile.getSector()) : tile.getSector(); - } - - // Render overview. - this.renderCoverage(dc); - - // Render frame tiles. - if (percentViewportOfSector(dc, viewingSector) > this.drawFrameThreshold) - { - this.renderFrames(dc, renderQueue); - this.requestAllFrames(requestQueue); - } - - // Render icon. - if (percentViewportOfSector(dc, this.sector) < this.drawIconThreshold) - { - this.renderIcon(dc, drawSector); - } - - this.sendRequests(); - } - - public WWIcon getIcon() - { - return this.icon; - } - - private static void initializeOverviewTexture(DrawContext dc, Texture texture) - { - texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); - texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); - texture.setTexParameteri(GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); - texture.setTexParameteri(GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); - int[] maxAnisotropy = new int[1]; - dc.getGL().glGetIntegerv(GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy, 0); - texture.setTexParameteri(GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy[0]); - } - - public boolean isDrawCoverage() - { - return this.drawCoverage; - } - - public boolean isDrawIcon() - { - return this.drawIcon; - } - - private boolean isSectorVisible(DrawContext dc, Sector sector) - { - if (dc.getVisibleSector() != null && !sector.intersects(dc.getVisibleSector())) - return false; - - Extent e = Sector.computeBoundingCylinder(dc.getGlobe(), dc.getVerticalExaggeration(), sector); - return e.intersects(dc.getView().getFrustumInModelCoordinates()); - } - - private static int pixelSizeOfSector(DrawContext dc, Sector sector) - { - LatLon centroid = sector.getCentroid(); - Globe globe = dc.getGlobe(); - Vec4 centroidPoint = globe.computePointFromPosition(centroid.getLatitude(), centroid.getLongitude(), 0); - Vec4 minPoint = globe.computePointFromPosition(sector.getMinLatitude(), sector.getMinLongitude(), 0); - Vec4 maxPoint = globe.computePointFromPosition(sector.getMaxLatitude(), sector.getMaxLongitude(), 0); - double distanceToEye = centroidPoint.distanceTo3(dc.getView().getEyePoint()); - double sectorSize = minPoint.distanceTo3(maxPoint); - double pixelSize = dc.getView().computePixelSizeAtDistance(distanceToEye); - return (int) Math.round(sectorSize / pixelSize); - } - - private static double percentViewportOfSector(DrawContext dc, Sector sector) - { - Rectangle viewport = dc.getView().getViewport(); - double pixelSize = pixelSizeOfSector(dc, sector); - double maxDimension = Math.min(viewport.width, viewport.height); - return pixelSize / maxDimension; - } - - private void processDisposables() - { - Disposable disposable; - while ((disposable = this.disposalQueue.poll()) != null) - { - if (disposable instanceof RpfTextureTile) - this.evictTile(((RpfTextureTile) disposable).frameKey); - disposable.dispose(); - } - } - - private void renderCoverage(DrawContext dc) - { - // Render coverage tile. - if (this.drawCoverage && this.coverageTile != null) - { - GL gl = dc.getGL(); - int attribBits = GL.GL_ENABLE_BIT | GL.GL_COLOR_BUFFER_BIT | GL.GL_POLYGON_BIT; - gl.glPushAttrib(attribBits); - try - { - gl.glEnable(GL.GL_BLEND); - gl.glEnable(GL.GL_CULL_FACE); - gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); - gl.glCullFace(GL.GL_BACK); - gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL); - dc.getSurfaceTileRenderer().renderTile(dc, this.coverageTile); - } - finally - { - gl.glPopAttrib(); - } - } - } - - private void renderIcon(DrawContext dc, Sector drawSector) - { - // Render coverage icon. - if (this.drawIcon && this.icon != null) - { - LatLon centroid = (drawSector != null) ? drawSector.getCentroid() : this.sector.getCentroid(); - this.icon.setPosition(new Position(centroid, 0)); - this.iconRenderer.render(dc, this.icon, null); - } - } - - private void renderFrames(DrawContext dc, Queue rpfTextureTiles) - { - GL gl = dc.getGL(); - int attribBits = GL.GL_ENABLE_BIT | GL.GL_POLYGON_BIT; - gl.glPushAttrib(attribBits); - try - { - gl.glEnable(GL.GL_CULL_FACE); - gl.glCullFace(GL.GL_BACK); - gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL); - dc.getSurfaceTileRenderer().renderTiles(dc, rpfTextureTiles); - } - finally - { - gl.glPopAttrib(); - } - } - - public void setIcon(WWIcon icon) - { - if (icon == null) - { - String message = WorldWind.retrieveErrMsg("nullValue.Icon"); - WorldWind.logger().log(Level.FINE, message); - throw new IllegalArgumentException(message); - } - this.icon = icon; - } - - public void setDrawCoverage(boolean drawCoverage) - { - this.drawCoverage = drawCoverage; - } - - public void setDrawIcon(boolean drawIcon) - { - this.drawIcon = drawIcon; - } - - private void updateCoverage() - { - if (this.coverageTile != null) - disposalQueue.offer(this.coverageTile); - TextureData textureData = createCoverageTextureData(1024, 1024, this.sector, this.frameDirectory.values()); - this.coverageTile = new TextureTile(this.sector) - { - public void initializeTexture(DrawContext dc) - { - if (this.getTexture() == null) - { - Texture tex = TextureIO.newTexture(this.getTextureData()); - initializeOverviewTexture(dc, tex); - this.setTexture(tex); - } - } - }; - this.coverageTile.setTextureData(textureData); - } - - // ============== Image Reading and Conversion ======================= // - // ============== Image Reading and Conversion ======================= // - // ============== Image Reading and Conversion ======================= // - - private final Map cachedTiles = new HashMap(); - private final LinkedList downloadQueue = new LinkedList(); - private final LinkedList readQueue = new LinkedList(); -// private final AbsentResourceList absentResourceList = new AbsentResourceList(); - - private static class FrameRequest - { - static final long STALE_REQUEST_LIMIT = 10000L; - final FrameRecord frameRecord; - long timestamp; - - public FrameRequest(FrameRecord frameRecord) - { - this.frameRecord = frameRecord; - this.timestamp = System.currentTimeMillis(); - } - - public void touch() - { - this.timestamp = System.currentTimeMillis(); - } - - public boolean isStale() - { - return (System.currentTimeMillis() - this.timestamp) > STALE_REQUEST_LIMIT; - } - } - - private static class RpfRetriever extends WWObjectImpl implements Retriever - { - private final RpfLayer layer; - private final FrameRecord record; - private volatile RpfImageFile rpfImageFile; - private volatile ByteBuffer buffer; - private volatile String state = RETRIEVER_STATE_NOT_STARTED; - private long submitTime; - private long beginTime; - private long endTime; - private int connectTimeout = -1; - private int readTimeout = -1; - private int staleRequestLimit = -1; - - public RpfRetriever(RpfLayer layer, FrameRecord record) - { - this.layer = layer; - this.record = record; - } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || !o.getClass().equals(this.getClass())) - return false; - final RpfRetriever that = (RpfRetriever) o; - return this.record.equals(that.record); - } - - public long getBeginTime() - { - return this.beginTime; - } - - public ByteBuffer getBuffer() - { - return this.buffer; - } - - public int getContentLength() - { - return 0; - } - - public int getContentLengthRead() - { - return 0; - } - - public String getContentType() - { - return null; - } - - public long getEndTime() - { - return this.endTime; - } - - public String getName() - { - return this.record.getFilePath(); - } - - public String getState() - { - return this.state; - } - - public long getSubmitTime() - { - return this.submitTime; - } - - public int getConnectTimeout() - { - return connectTimeout; - } - - public void setConnectTimeout(int connectTimeout) - { - this.connectTimeout = connectTimeout; - } - - public int getReadTimeout() - { - return readTimeout; - } - - public void setReadTimeout(int readTimeout) - { - this.readTimeout = readTimeout; - } - - public int getStaleRequestLimit() - { - return this.staleRequestLimit; - } - - public void setStaleRequestLimit(int staleRequestLimit) - { - this.staleRequestLimit = staleRequestLimit; - } - - private boolean interrupted() - { - if (Thread.currentThread().isInterrupted()) - { - this.setState(RETRIEVER_STATE_INTERRUPTED); - String message = WorldWind.retrieveErrMsg("layers.RpfLayer.DownloadInterrupted") - + this.record.getFilePath(); - WorldWind.logger().log(Level.FINER, message); - return true; - } - return false; - } - - public void setBeginTime(long beginTime) - { - this.beginTime = beginTime; - } - - public void setEndTime(long endTime) - { - this.endTime = endTime; - } - - private void setState(String state) - { - String oldState = this.state; - this.state = state; - this.firePropertyChange(AVKey.RETRIEVER_STATE, oldState, this.state); - } - - public void setSubmitTime(long submitTime) - { - this.submitTime = submitTime; - } - - public Retriever call() throws Exception - { - if (this.interrupted()) - return this; - - String cacheFilePath = this.record.getCacheFilePath(this.layer); - - if (!this.record.fileLock.tryLock()) - { - this.setState(RETRIEVER_STATE_SUCCESSFUL); - return this; - } - try - { - this.setState(RETRIEVER_STATE_STARTED); - - if (!this.interrupted()) - { - if (isFileResident(cacheFilePath)) - { - this.setState(RETRIEVER_STATE_SUCCESSFUL); - return this; - } - } - - if (!this.interrupted()) - { - this.setState(RETRIEVER_STATE_CONNECTING); - File file = new File(this.record.getFilePath()); - if (!file.exists()) - { - String message = WorldWind.retrieveErrMsg("generic.fileNotFound") + this.record.getFilePath(); - throw new IOException(message); - } - this.rpfImageFile = RpfImageFile.load(file); - } - - if (!this.interrupted()) - { - this.setState(RETRIEVER_STATE_READING); - File file = WorldWind.dataFileCache().newFile(cacheFilePath); - if (file == null) - { - String message = WorldWind.retrieveErrMsg("generic.CantCreateCacheFile") - + cacheFilePath; - throw new IOException(message); - } - if (haveARBNonPowerOfTwo) - { - this.buffer = this.rpfImageFile.getImageAsDdsTexture(); - } - else - { - BufferedImage src = this.rpfImageFile.getBufferedImage(); - int dstWidth = previousPowerOfTwo(src.getWidth()); - int dstHeight = previousPowerOfTwo(src.getHeight()); - double sx = dstWidth / (double) src.getWidth(); - double sy = dstHeight / (double) src.getHeight(); - AffineTransformOp op = new AffineTransformOp( - AffineTransform.getScaleInstance(sx, sy), AffineTransformOp.TYPE_BICUBIC); - BufferedImage dst = new BufferedImage(dstWidth, dstHeight, src.getType()); - op.filter(src, dst); - this.buffer = DDSConverter.convertToDxt1NoTransparency(dst); - } - WWIO.saveBuffer(this.buffer, file); - } - - if (!this.interrupted()) - { - this.setState(RETRIEVER_STATE_SUCCESSFUL); -// this.layer.absentResourceList.unmarkResourceAbsent(absentIdFor(this.record)); - this.layer.firePropertyChange(AVKey.LAYER, null, this.layer); - } - } - catch (Exception e) - { - this.setState(RETRIEVER_STATE_ERROR); -// this.layer.absentResourceList.markResourceAbsent(absentIdFor(this.record)); - throw e; - } - finally - { - this.record.fileLock.unlock(); - } - - return this; - } - } - - private static class ReadTask implements Runnable - { - public final RpfLayer layer; - public final FrameRecord record; - - public ReadTask(RpfLayer layer, FrameRecord record) - { - this.layer = layer; - this.record = record; - } - - private void deleteCorruptFile(URL fileURL) - { - WorldWind.dataFileCache().removeFile(fileURL); - String message = WorldWind.retrieveErrMsg("generic.DeletedCorruptDataFile") + fileURL; - WorldWind.logger().log(Level.FINER, message); - } - -// private void deleteOutOfDateFile(URL fileURL) -// { -// WorldWind.dataFileCache().removeFile(fileURL); -// String message = WorldWind.retrieveErrMsg("generic.DataFileExpired") + fileURL; -// WorldWind.logger().log(Level.FINER, message); -// } - - public boolean equals(Object o) - { - if (this == o) - return true; - if (o == null || !o.getClass().equals(this.getClass())) - return false; - final ReadTask that = (ReadTask) o; - return (this.record != null) ? this.record.equals(that.record) : (that.record == null); - } - - public void run() - { - FrameKey key = keyFor(this.record); - if (!this.layer.isTileResident(key)) - { - this.readFrame(key, this.record); - this.layer.firePropertyChange(AVKey.LAYER, null, this.layer); - } - } - - public void readFrame(FrameKey key, FrameRecord record) - { - String cacheFilePath = record.getCacheFilePath(this.layer); - URL dataFileURL = WorldWind.dataFileCache().findFile(cacheFilePath, false); - // The cached file does not exist. Issue a download and return. - if (dataFileURL == null) - { - this.layer.downloadFrame(this.record); - return; - } - - if (!record.fileLock.tryLock()) - return; - try - { -// // The file has expired. Delete it. -// if (WWIO.isFileOutOfDate(dataFileURL, record.getExpiryTime())) -// { -// this.deleteOutOfDateFile(dataFileURL); -// this.layer.firePropertyChange(AVKey.LAYER, null, this.layer); -// return; -// } - - if (this.layer.isTileResident(key)) - return; - - TextureData textureData = null; - try - { - textureData = TextureIO.newTextureData(dataFileURL, false, TextureIO.DDS); - } - catch (IOException e) - { - String message = WorldWind.retrieveErrMsg("generic.TextureIOException") + cacheFilePath; - WorldWind.logger().log(Level.FINE, message, e); - } - - // The file has expired. Delete it. - if (textureData == null) - { - this.deleteCorruptFile(dataFileURL); -// this.layer.absentResourceList.markResourceAbsent(absentIdFor(record)); - return; - } - else - { -// this.layer.absentResourceList.unmarkResourceAbsent(absentIdFor(record)); - } - - RpfTextureTile rpfTextureTile = new RpfTextureTile(key, record); - rpfTextureTile.setTextureData(textureData); - this.layer.makeTileResident(key, rpfTextureTile); - this.layer.firePropertyChange(AVKey.LAYER, null, this.layer); - } - finally - { - record.fileLock.unlock(); - } - } - } - - private void downloadFrame(FrameRecord record) - { -// if (this.absentResourceList.isResourceAbsent(absentIdFor(record))) -// return; - - synchronized (this.downloadQueue) - { - FrameRequest frameRequest = new FrameRequest(record); - int index = this.downloadQueue.indexOf(frameRequest); - // Frame has not been requested, add it. - if (index < 0) - this.downloadQueue.addFirst(frameRequest); - // Frame is already requested, update it's timestamp. - else - this.downloadQueue.get(index).touch(); - } - } - - private void evictTile(FrameKey key) - { - synchronized (this.cachedTiles) - { - // Value is assumed to be evicted from memory cache. - this.cachedTiles.remove(key); - } - } - - private RpfTextureTile getTile(FrameKey key) - { - synchronized (this.cachedTiles) - { - // Touch the value in memory cache. - this.memoryCache.getObject(key); - // Return the value in our local cache directory. - return this.cachedTiles.get(key); - } - } - -// private static long absentIdFor(FrameRecord record) -// { -// RpfFrameProperties properties = record.getRpfFrameProperties(); -// return properties.zone.ordinal() + (100 * properties.frameNumber); -// } - - private static boolean isFileResident(String fileName) - { - return WorldWind.dataFileCache().findFile(fileName, false) != null; - } - - private boolean isTileResident(FrameKey key) - { - synchronized (this.cachedTiles) - { - // Value may be evicted from memory cache, but still in local cache directory - // (not yet processsed for disposal). - return this.cachedTiles.get(key) != null; - } - } - - private void makeTileResident(FrameKey key, RpfTextureTile tile) - { - synchronized (this.memoryCache) - { - this.memoryCache.add(key, tile); - } - - synchronized (this.cachedTiles) - { - this.cachedTiles.put(key, tile); - } - } - - private static int previousPowerOfTwo(int value) - { - int result = 1; - while (result < value) - { - result <<= 1; - } - return (result >> 1); - } - - private void requestFrame(FrameRecord record) - { -// if (this.absentResourceList.isResourceAbsent(absentIdFor(record))) -// return; - - synchronized (this.readQueue) - { - FrameRequest frameRequest = new FrameRequest(record); - int index = this.readQueue.indexOf(frameRequest); - // Frame has not been requested, add it. - if (index < 0) - this.readQueue.addFirst(frameRequest); - // Frame is already requested, update it's timestamp. - else - this.readQueue.get(index).touch(); - } - } - - private void requestAllFrames(Collection frameRecords) - { - for (FrameRecord record : frameRecords) - { - this.requestFrame(record); - } - } - - private void sendRequests() - { - synchronized (this.readQueue) - { - FrameRequest request; - while (!WorldWind.threadedTaskService().isFull() && (request = this.readQueue.poll()) != null) - { - if (!request.isStale()) - WorldWind.threadedTaskService().addTask(new ReadTask(this, request.frameRecord)); - } - } - - synchronized (this.downloadQueue) - { - FrameRequest request; - while (!WorldWind.retrievalService().isFull() && (request = this.downloadQueue.poll()) != null) - { - if (!request.isStale()) - WorldWind.retrievalService().runRetriever(new RpfRetriever(this, request.frameRecord)); - } - } - } -} diff --git a/gov/nasa/worldwind/layers/TextureTile.java b/gov/nasa/worldwind/layers/TextureTile.java index c9c749e..bb837a2 100644 --- a/gov/nasa/worldwind/layers/TextureTile.java +++ b/gov/nasa/worldwind/layers/TextureTile.java @@ -18,21 +18,20 @@ import javax.media.opengl.*; /** * @author tag - * @version $Id: TextureTile.java 2533 2007-08-13 05:59:08Z tgaskins $ + * @version $Id: TextureTile.java 2812 2007-09-12 19:16:41Z tgaskins $ */ public class TextureTile extends Tile implements SurfaceTile { private volatile TextureData textureData; private TextureTile fallbackTile = null; // holds texture to use if own texture not available private Vec4 centroid; // Cartesian coordinate of lat/lon center - private Vec4[] corners; // Cartesian coordinate of lat/lon corners private Extent extent = null; // bounding volume private double extentVerticalExaggertion = Double.MIN_VALUE; // VE used to calculate the extent private double minDistanceToEye = Double.MAX_VALUE; - public TextureTile(Sector sector, TileKey tileKey) + public TextureTile(Sector sector) { - super(sector, tileKey); + super(sector); } public TextureTile(Sector sector, Level level, int row, int col) @@ -129,44 +128,6 @@ public class TextureTile extends Tile implements SurfaceTile return this.centroid; } - public Vec4[] getCornerPoints(Globe globe) - { - if (globe == null) - { - String msg = Logging.getMessage("nullValue.GlobeIsNull"); - Logging.logger().severe(msg); - throw new IllegalArgumentException(msg); - } - - if (this.corners == null) - { - Sector s = this.getSector(); - this.corners = new Vec4[4]; - this.corners[0] = globe.computePointFromPosition(s.getMinLatitude(), s.getMinLongitude(), 0); // sw - this.corners[1] = globe.computePointFromPosition(s.getMinLatitude(), s.getMaxLongitude(), 0); // se - this.corners[2] = globe.computePointFromPosition(s.getMaxLatitude(), s.getMaxLongitude(), 0); // nw - this.corners[3] = globe.computePointFromPosition(s.getMaxLatitude(), s.getMinLongitude(), 0); // ne - } - - return this.corners; - } - - public double getWidth() - { - double sLow = this.corners[0].distanceTo3(this.corners[1]); - double sHigh = this.corners[2].distanceTo3(this.corners[3]); - - return sLow > sHigh ? sLow : sHigh; - } - - public double getHeight() - { - double tLow = this.corners[0].distanceTo3(this.corners[2]); - double tHigh = this.corners[1].distanceTo3(this.corners[3]); - - return tLow > tHigh ? tLow : tHigh; - } - public double getMinDistanceToEye() { return this.minDistanceToEye; diff --git a/gov/nasa/worldwind/layers/TiledImageLayer.java b/gov/nasa/worldwind/layers/TiledImageLayer.java index 3c19229..990c252 100644 --- a/gov/nasa/worldwind/layers/TiledImageLayer.java +++ b/gov/nasa/worldwind/layers/TiledImageLayer.java @@ -26,7 +26,7 @@ import java.util.concurrent.PriorityBlockingQueue; /** * @author tag - * @version $Id: TiledImageLayer.java 2533 2007-08-13 05:59:08Z tgaskins $ + * @version $Id: TiledImageLayer.java 2790 2007-09-10 19:40:33Z tgaskins $ */ public abstract class TiledImageLayer extends AbstractLayer { @@ -38,6 +38,7 @@ public abstract class TiledImageLayer extends AbstractLayer private boolean levelZeroLoaded = false; private boolean retainLevelZeroTiles = false; private String tileCountName; + private double splitScale = 0.9; // TODO: Make configurable // Diagnostic flags private boolean showImageTileOutlines = false; @@ -156,6 +157,11 @@ public abstract class TiledImageLayer extends AbstractLayer return levels; } + protected void setSplitScale(double splitScale) + { + this.splitScale = splitScale; + } + protected PriorityBlockingQueue getRequestQ() { return requestQ; @@ -281,6 +287,8 @@ public abstract class TiledImageLayer extends AbstractLayer if (tile.isTextureInMemory(dc.getTextureCache())) { +// System.out.printf("Sector %s, min = %f, max = %f\n", tile.getSector(), +// dc.getGlobe().getMinElevation(tile.getSector()), dc.getGlobe().getMaxElevation(tile.getSector())); this.addTileToCurrent(tile); return; } @@ -327,16 +335,72 @@ public abstract class TiledImageLayer extends AbstractLayer private boolean isTileVisible(DrawContext dc, TextureTile tile) { +// if (!(tile.getExtent(dc).intersects(dc.getView().getFrustumInModelCoordinates()) +// && (dc.getVisibleSector() == null || dc.getVisibleSector().intersects(tile.getSector())))) +// return false; +// +// Position eyePos = dc.getView().getEyePosition(); +// LatLon centroid = tile.getSector().getCentroid(); +// Angle d = LatLon.sphericalDistance(eyePos.getLatLon(), centroid); +// if ((!tile.getLevelName().equals("0")) && d.compareTo(tile.getSector().getDeltaLat().multiply(2.5)) == 1) +// return false; +// +// return true; +// return tile.getExtent(dc).intersects(dc.getView().getFrustumInModelCoordinates()) && (dc.getVisibleSector() == null || dc.getVisibleSector().intersects(tile.getSector())); } +// +// private boolean meetsRenderCriteria2(DrawContext dc, TextureTile tile) +// { +// if (this.levels.isFinalLevel(tile.getLevelNumber())) +// return true; +// +// Sector sector = tile.getSector(); +// Vec4[] corners = sector.computeCornerPoints(dc.getGlobe()); +// Vec4 centerPoint = sector.computeCenterPoint(dc.getGlobe()); +// +// View view = dc.getView(); +// double d1 = view.getEyePoint().distanceTo3(corners[0]); +// double d2 = view.getEyePoint().distanceTo3(corners[1]); +// double d3 = view.getEyePoint().distanceTo3(corners[2]); +// double d4 = view.getEyePoint().distanceTo3(corners[3]); +// double d5 = view.getEyePoint().distanceTo3(centerPoint); +// +// double minDistance = d1; +// if (d2 < minDistance) +// minDistance = d2; +// if (d3 < minDistance) +// minDistance = d3; +// if (d4 < minDistance) +// minDistance = d4; +// if (d5 < minDistance) +// minDistance = d5; +// +// double r = 0; +// if (minDistance == d1) +// r = corners[0].getLength3(); +// if (minDistance == d2) +// r = corners[1].getLength3(); +// if (minDistance == d3) +// r = corners[2].getLength3(); +// if (minDistance == d4) +// r = corners[3].getLength3(); +// if (minDistance == d5) +// r = centerPoint.getLength3(); +// +// double texelSize = tile.getLevel().getTexelSize(r); +// double pixelSize = dc.getView().computePixelSizeAtDistance(minDistance); +// +// return 2 * pixelSize >= texelSize; +// } private boolean meetsRenderCriteria(DrawContext dc, TextureTile tile) { return this.levels.isFinalLevel(tile.getLevelNumber()) || !needToSplit(dc, tile.getSector(), 20); } - private static boolean needToSplit(DrawContext dc, Sector sector, int density) + private boolean needToSplit(DrawContext dc, Sector sector, int density) { Vec4[] corners = sector.computeCornerPoints(dc.getGlobe()); Vec4 centerPoint = sector.computeCenterPoint(dc.getGlobe()); @@ -360,7 +424,7 @@ public abstract class TiledImageLayer extends AbstractLayer double cellSize = (Math.PI * sector.getDeltaLatRadians() * dc.getGlobe().getRadius()) / density; - return !(Math.log10(cellSize) <= (Math.log10(minDistance) - 1)); + return !(Math.log10(cellSize) <= (Math.log10(minDistance) - this.splitScale)); } // ============== Rendering ======================= // @@ -406,7 +470,8 @@ public abstract class TiledImageLayer extends AbstractLayer gl.glEnable(GL.GL_CULL_FACE); gl.glCullFace(GL.GL_BACK); - dc.setPerFrameStatistic(PerformanceStatistic.IMAGE_TILE_COUNT, this.tileCountName, this.currentTiles.size()); + dc.setPerFrameStatistic(PerformanceStatistic.IMAGE_TILE_COUNT, this.tileCountName, + this.currentTiles.size()); dc.getGeographicSurfaceTileRenderer().renderTiles(dc, this.currentTiles); gl.glPopAttrib(); @@ -534,55 +599,35 @@ public abstract class TiledImageLayer extends AbstractLayer dc.getGL().glColor4fv(previousColor, 0); } - - // ============== Color Lookup ======================= // - // ============== Color Lookup ======================= // - // ============== Color Lookup ======================= // - - public Color getColor(Angle latitude, Angle longitude, int levelNumber) - { - // TODO: check args - - // Find the tile containing the position in the specified level. - TextureTile containingTile = null; - for (TextureTile tile : this.topLevels) - { - containingTile = this.getContainingTile(tile, latitude, longitude, levelNumber); - if (containingTile != null) - break; - } - if (containingTile == null) - return null; - - String pathBase = containingTile.getPath().substring(0, containingTile.getPath().lastIndexOf(".")); - String cacheKey = pathBase + ".BufferedImage"; - - // Look up the color if the image is in memory. - BufferedImage image = (BufferedImage) WorldWind.getMemoryCache("BatchTiles").getObject(cacheKey); - if (image != null) - return this.resolveColor(containingTile, image, latitude, longitude); - - // Read the image from disk since it's not in memory. - image = this.requestImage(containingTile, cacheKey); - if (image != null) - return this.resolveColor(containingTile, image, latitude, longitude); - - // Retrieve it from the net since it's not on disk. - this.downloadImage(containingTile); - - // Try to read from disk again after retrieving it from the net. - image = this.requestImage(containingTile, cacheKey); - if (image != null) - return this.resolveColor(containingTile, image, latitude, longitude); - - // All attempts to find the image have failed. - return null; - } - - private final static String[] formats = new String[]{"jpg", "jpeg", "png", "tiff"}; - private final static String[] suffixes = new String[]{".jpg", ".jpg", ".png", ".tiff"}; - - private BufferedImage requestImage(TextureTile tile, String cacheKey) +// +// private TextureTile getContainingTile(TextureTile tile, Angle latitude, Angle longitude, int levelNumber) +// { +// if (!tile.getSector().contains(latitude, longitude)) +// return null; +// +// if (tile.getLevelNumber() == levelNumber || this.levels.isFinalLevel(tile.getLevelNumber())) +// return tile; +// +// TextureTile containingTile; +// TextureTile[] subTiles = tile.createSubTiles(this.levels.getLevel(tile.getLevelNumber() + 1)); +// for (TextureTile child : subTiles) +// { +// containingTile = this.getContainingTile(child, latitude, longitude, levelNumber); +// if (containingTile != null) +// return containingTile; +// } +// +// return null; +// } + + // ============== Image Composition ======================= // + // ============== Image Composition ======================= // + // ============== Image Composition ======================= // + + private final static String[] formats = new String[] {"jpg", "jpeg", "png", "tiff"}; + private final static String[] suffixes = new String[] {".jpg", ".jpg", ".png", ".tiff"}; + + private BufferedImage requestImage(TextureTile tile) { URL url = null; String pathBase = tile.getPath().substring(0, tile.getPath().lastIndexOf(".")); @@ -600,7 +645,7 @@ public abstract class TiledImageLayer extends AbstractLayer if (WWIO.isFileOutOfDate(url, tile.getLevel().getExpiryTime())) { // The file has expired. Delete it then request download of newer. - gov.nasa.worldwind.WorldWind.getDataFileCache().removeFile(url); + WorldWind.getDataFileCache().removeFile(url); String message = Logging.getMessage("generic.DataFileExpired", url); Logging.logger().fine(message); } @@ -614,7 +659,6 @@ public abstract class TiledImageLayer extends AbstractLayer return null; // TODO: warn } - WorldWind.getMemoryCache("BatchTiles").add(cacheKey, image, image.getRaster().getDataBuffer().getSize()); this.levels.unmarkResourceAbsent(tile); return image; } @@ -665,70 +709,166 @@ public abstract class TiledImageLayer extends AbstractLayer } } - private TextureTile getContainingTile(TextureTile tile, Angle latitude, Angle longitude, int levelNumber) + private static class ImageSector { - if (!tile.getSector().contains(latitude, longitude)) + private final BufferedImage image; + private final Sector sector; + + public ImageSector(BufferedImage image, Sector sector) + { + this.image = image; + this.sector = sector; + } + } + + public BufferedImage composeImageForSector(Sector sector, int imageSize) + { + return this.composeImageForSector(sector, imageSize, -1); + } + + public BufferedImage composeImageForSector(Sector sector, int imageSize, int levelNumber) + { + TiledImageLayer.ImageSector[][] imageSectors = this.getImagesInSector(sector, levelNumber); + + if (imageSectors == null) + { + System.out.println("No images available."); // TODO return null; + } + + Sector actualSector = null; + for (TiledImageLayer.ImageSector[] isa : imageSectors) + { + for (TiledImageLayer.ImageSector is : isa) + { + actualSector = Sector.union(actualSector, is.sector); + } + } + + int ny = imageSectors.length; + int nx = imageSectors[0].length; - if (tile.getLevelNumber() == levelNumber || this.levels.isFinalLevel(tile.getLevelNumber())) - return tile; + int overallHeight = ny * imageSectors[0][0].image.getHeight(); + int overallWidth = nx * imageSectors[0][0].image.getWidth(); - TextureTile containingTile; - TextureTile[] subTiles = tile.createSubTiles(this.levels.getLevel(tile.getLevelNumber() + 1)); - for (TextureTile child : subTiles) + int tileWidth; + int tileHeight; + if (overallHeight >= overallWidth) { - containingTile = this.getContainingTile(child, latitude, longitude, levelNumber); - if (containingTile != null) - return containingTile; + tileHeight = imageSize / ny; + double aspect = (double) overallWidth / (double) overallHeight; + tileWidth = (int) (aspect * imageSize / nx); + } + else + { + tileWidth = imageSize / nx; + double aspect = (double) overallHeight / (double) overallWidth; + tileHeight = (int) (aspect * imageSize / ny); } - return null; + int imageHeight = tileHeight * imageSectors.length; + int imageWidth = tileWidth * imageSectors[0].length; + + //noinspection ConstantConditions + double sh = 1/sector.getDeltaLat().divide(actualSector.getDeltaLat()); + double sw = 1/sector.getDeltaLon().divide(actualSector.getDeltaLon()); + double dh = -(actualSector.getMaxLatitude().subtract(sector.getMaxLatitude()).divide(actualSector.getDeltaLat()) + * imageHeight); + double dw = -( + sector.getMinLongitude().subtract(actualSector.getMinLongitude()).divide(actualSector.getDeltaLon()) + * imageWidth); + + BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB); + Graphics2D g = image.createGraphics(); + g.scale(sw, sh); + g.translate(dw, dh); + + int y = 0; + for (TiledImageLayer.ImageSector[] row : imageSectors) + { + int x = 0; + for (TiledImageLayer.ImageSector is : row) + { + Image img = is.image.getScaledInstance(tileWidth, tileHeight, Image.SCALE_SMOOTH); + g.drawImage(img, x, y, null); + x += tileWidth; + } + y += tileHeight; + } + + return image; } - private Color resolveColor(TextureTile tile, BufferedImage image, Angle latitude, Angle longitude) + private ImageSector[][] getImagesInSector(Sector sector, int levelNumber) { - Sector sector = tile.getSector(); + if (sector == null) + { + String msg = Logging.getMessage("nullValue.SectorIsNull"); + Logging.logger().severe(msg); + throw new IllegalArgumentException(msg); + } - final double dLat = sector.getMaxLatitude().degrees - latitude.degrees; - final double dLon = longitude.degrees - sector.getMinLongitude().degrees; - final double sLat = dLat / sector.getDeltaLat().degrees; - final double sLon = dLon / sector.getDeltaLon().degrees; + // TODO: check level number arg - final int tileHeight = tile.getLevel().getTileHeight(); - final int tileWidth = tile.getLevel().getTileWidth(); - int x = (int) ((tileWidth - 1) * sLon); - int y = (int) ((tileHeight - 1) * sLat); - int w = x < (tileWidth - 1) ? 1 : 0; - int h = y < (tileHeight - 1) ? 1 : 0; + Level targetLevel = this.levels.getLastLevel(); + if (levelNumber >= 0) + { + for (int i = levelNumber; i < this.getLevels().getLastLevel().getLevelNumber(); i++) + { + if (this.levels.isLevelEmpty(i)) + continue; - double dh = sector.getDeltaLat().degrees / (tileHeight - 1); - double dw = sector.getDeltaLon().degrees / (tileWidth - 1); - double ssLat = (dLat - y * dh) / dh; - double ssLon = (dLon - x * dw) / dw; + targetLevel = this.levels.getLevel(i); + break; + } + } - int sw = image.getRGB(x, y); - int se = image.getRGB(x + w, y); - int ne = image.getRGB(x + w, y + h); - int nw = image.getRGB(x, y + h); + // Collect all the tiles intersecting the input sector. + LatLon delta = targetLevel.getTileDelta(); + final int nwRow = Tile.computeRow(delta.getLatitude(), sector.getMaxLatitude()); + final int nwCol = Tile.computeColumn(delta.getLongitude(), sector.getMinLongitude()); + final int seRow = Tile.computeRow(delta.getLatitude(), sector.getMinLatitude()); + final int seCol = Tile.computeColumn(delta.getLongitude(), sector.getMaxLongitude()); - Color csw = new Color(sw); - Color cse = new Color(se); - Color cne = new Color(ne); - Color cnw = new Color(nw); + int numRows = nwRow - seRow + 1; + int numCols = seCol - nwCol + 1; + ImageSector[][] imageSectors = new ImageSector[numRows][numCols]; - Color ctop = interpolateColors(cnw, cne, ssLon); - Color cbot = interpolateColors(csw, cse, ssLon); + for (int row = nwRow; row >= seRow; row--) + { + for (int col = nwCol; col <= seCol; col++) + { + TileKey key = new TileKey(targetLevel.getLevelNumber(), row, col, targetLevel.getCacheName()); + Sector tileSector = this.levels.computeSectorForKey(key); + TextureTile textureTile = new TextureTile(tileSector, targetLevel, row, col); + BufferedImage image = this.getImage(textureTile); + if (image != null) + imageSectors[nwRow - row][col - nwCol] = new ImageSector(image, textureTile.getSector()); + } + } - return interpolateColors(cbot, ctop, ssLat); + return imageSectors; } - private Color interpolateColors(Color ca, Color cb, double s) + private BufferedImage getImage(TextureTile tile) { - int r = (int) (s * ca.getRed() + (1 - s) * cb.getRed()); - int g = (int) (s * ca.getGreen() + (1 - s) * cb.getGreen()); - int b = (int) (s * ca.getBlue() + (1 - s) * cb.getBlue()); + // TODO: check args - return new Color(r, g, b); + // Read the image from disk. + BufferedImage image = this.requestImage(tile); + if (image != null) + return image; + + // Retrieve it from the net since it's not on disk. + this.downloadImage(tile); + + // Try to read from disk again after retrieving it from the net. + image = this.requestImage(tile); + if (image != null) + return image; + + // All attempts to find the image have failed. + return null; } private class HttpRetrievalPostProcessor implements RetrievalPostProcessor diff --git a/gov/nasa/worldwind/layers/TrackLayer.java b/gov/nasa/worldwind/layers/TrackLayer.java index ad08c0e..71223bf 100644 --- a/gov/nasa/worldwind/layers/TrackLayer.java +++ b/gov/nasa/worldwind/layers/TrackLayer.java @@ -6,25 +6,28 @@ All Rights Reserved. */ package gov.nasa.worldwind.layers; -import gov.nasa.worldwind.geom.*; -import gov.nasa.worldwind.globes.SectorGeometryList; -import gov.nasa.worldwind.render.*; import gov.nasa.worldwind.tracks.*; +import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.util.Logging; +import gov.nasa.worldwind.render.DrawContext; +import gov.nasa.worldwind.globes.SectorGeometryList; + +import java.util.List; /** * @author tag - * @version $Id: TrackLayer.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: TrackLayer.java 2817 2007-09-12 19:28:14Z tgaskins $ */ -public class TrackLayer extends AbstractLayer +public abstract class TrackLayer extends AbstractLayer { - private TrackRenderer trackRenderer = new TrackRenderer(); private java.util.List tracks = new java.util.ArrayList(); private Sector boundingSector; - private IconRenderer iconRenderer = new IconRenderer(); - private UserFacingIcon icon; + private int lowerLimit; + private int upperLimit; + private boolean overrideElevation = false; + private double elevation = 10d; - public TrackLayer(java.util.List tracks) + public TrackLayer(List tracks) { if (tracks == null) { @@ -37,89 +40,80 @@ public class TrackLayer extends AbstractLayer this.boundingSector = Sector.boundingSector(this.iterator()); } - private TrackPointIteratorImpl iterator() + public TrackPointIteratorImpl iterator() { return new TrackPointIteratorImpl(this.tracks); } - public void dispose() - { - this.trackRenderer.dispose(); - } - public int getNumPoints() { return this.iterator().getNumPoints(); } - public double getMarkerPixels() + public List getTracks() { - return this.trackRenderer.getMarkerPixels(); + return tracks; } - public void setMarkerPixels(double markerPixels) + public void setTracks(List tracks) { - this.trackRenderer.setMarkerPixels(markerPixels); + this.tracks = tracks; } - public double getMinMarkerSize() + public Sector getBoundingSector() { - return this.trackRenderer.getMinMarkerSize(); + return boundingSector; } - public void setMinMarkerSize(double minMarkerSize) + public void setBoundingSector(Sector boundingSector) { - this.trackRenderer.setMinMarkerSize(minMarkerSize); + this.boundingSector = boundingSector; } - public double getMarkerElevation() + public int getLowerLimit() { - return this.trackRenderer.getMarkerElevation(); + return lowerLimit; } - public void setMarkerElevation(double markerElevation) + public void setLowerLimit(int lowerLimit) { - this.trackRenderer.setMarkerElevation(markerElevation); + this.lowerLimit = lowerLimit; } - public Material getMaterial() + public int getUpperLimit() { - return this.trackRenderer.getMaterial(); + return upperLimit; } - public void setMaterial(Material material) + public void setUpperLimit(int upperLimit) { - this.trackRenderer.setMaterial(material); + this.upperLimit = upperLimit; } - public String getIconFilePath() + public double getElevation() { - return this.icon != null ? this.icon.getPath() : null; + return this.elevation; } - public void setIconFilePath(String iconFilePath) + public void setElevation(double markerElevation) { - this.icon = iconFilePath != null ? new UserFacingIcon(iconFilePath, null) : null; + this.elevation = markerElevation; } - public int getLowerLimit() + public boolean isOverrideElevation() { - return this.trackRenderer.getLowerLimit(); + return this.overrideElevation; } - public void setLowerLimit(int lowerLimit) + public void setOverrideElevation(boolean overrideElevation) { - this.trackRenderer.setLowerLimit(lowerLimit); + this.overrideElevation = overrideElevation; } - public int getUpperLimit() - { - return this.trackRenderer.getUpperLimit(); - } - - public void setUpperLimit(int upperLimit) + @Override + public String toString() { - this.trackRenderer.setUpperLimit(upperLimit); + return Logging.getMessage("layers.TrackLayer.Name"); } @Override @@ -146,23 +140,11 @@ public class TrackLayer extends AbstractLayer if (geos == null) return; - if (!dc.getVisibleSector().intersects(this.boundingSector)) + if (!dc.getVisibleSector().intersects(this.getBoundingSector())) return; - Vec4 iconPoint = this.trackRenderer.render(dc, trackPoints); - - if (iconPoint != null && this.icon != null) - { - if (dc.isPickingMode()) - this.iconRenderer.pick(dc, this.icon, iconPoint, pickPoint, this); - else - this.iconRenderer.render(dc, this.icon, iconPoint); - } + this.doDraw(dc, trackPoints, pickPoint); } - @Override - public String toString() - { - return Logging.getMessage("layers.TrackLayer.Name"); - } -} \ No newline at end of file + protected abstract void doDraw(DrawContext dc, TrackPointIterator trackPoints, java.awt.Point pickPoint); +} diff --git a/gov/nasa/worldwind/layers/placename/PlaceNameLayer.java b/gov/nasa/worldwind/layers/placename/PlaceNameLayer.java index 1e02c89..d963d16 100644 --- a/gov/nasa/worldwind/layers/placename/PlaceNameLayer.java +++ b/gov/nasa/worldwind/layers/placename/PlaceNameLayer.java @@ -26,7 +26,7 @@ import java.util.logging.Level; /** * @author Paul Collins - * @version $Id: PlaceNameLayer.java 2490 2007-08-02 18:24:12Z dcollins $ + * @version $Id: PlaceNameLayer.java 2980 2007-09-22 01:07:06Z tgaskins $ */ public class PlaceNameLayer extends AbstractLayer { @@ -419,6 +419,15 @@ public class PlaceNameLayer extends AbstractLayer private final PlaceNameRenderer placeNameRenderer = new PlaceNameRenderer(); @Override + public void dispose() // override if disposal is a supported operation + { + super.dispose(); + + if (this.placeNameRenderer != null) + this.placeNameRenderer.dispose(); + } + + @Override protected void doRender(DrawContext dc) { boolean enableDepthTest = this.isEnableDepthTest(dc); diff --git a/gov/nasa/worldwind/layers/placename/PlaceNameRenderer.java b/gov/nasa/worldwind/layers/placename/PlaceNameRenderer.java index 4aa7ec1..c3d3af5 100644 --- a/gov/nasa/worldwind/layers/placename/PlaceNameRenderer.java +++ b/gov/nasa/worldwind/layers/placename/PlaceNameRenderer.java @@ -21,7 +21,7 @@ import java.util.*; /** * @author dcollins - * @version $Id: PlaceNameRenderer.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: PlaceNameRenderer.java 2980 2007-09-22 01:07:06Z tgaskins $ */ public class PlaceNameRenderer implements Disposable { @@ -42,6 +42,8 @@ public class PlaceNameRenderer implements Disposable if (textRenderer != null) textRenderer.dispose(); } + + this.textRenderers.clear(); } public void render(DrawContext dc, Iterator placeNames, boolean enableDepthTest) diff --git a/gov/nasa/worldwind/render/Material.java b/gov/nasa/worldwind/render/Material.java index efae537..80e9d9e 100644 --- a/gov/nasa/worldwind/render/Material.java +++ b/gov/nasa/worldwind/render/Material.java @@ -12,7 +12,7 @@ import java.awt.*; /** * @author tag - * @version $Id: Material.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: Material.java 2677 2007-08-25 06:41:38Z tgaskins $ */ public class Material { @@ -25,7 +25,7 @@ public class Material 0.0f), new Color(0.2f, 0.2f, 0.2f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); public static final Material RED = new Material(new Color(0.75f, 0.0f, 0.0f, 0.0f), new Color(0.8f, 0.0f, 0.0f, - 0.0f), new Color(0.2f, 0.0f, 0.0f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); + 0.0f), new Color(0.2f, 0.0f, 0.0f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 80f); public static final Material GREEN = new Material(new Color(0.0f, 0.75f, 0.0f, 0.0f), new Color(0.0f, 0.8f, 0.0f, 0.0f), new Color(0.0f, 0.2f, 0.0f, 0.0f), new Color(0.0f, 0.0f, 0.0f, 0.0f), 20f); @@ -67,6 +67,22 @@ public class Material this.shininess = shininess; } + public Material(Color color) + { + if (color == null) + { + String msg = Logging.getMessage("nullValue.ColorIsNull"); + Logging.logger().severe(msg); + throw new IllegalArgumentException(msg); + } + + this.specular = new Color(0.75f, 0.75f, 0.55f, 0.0f); + this.diffuse = color; + this.ambient = new Color(0.2f, 0.2f, 0.01f, 0.0f); + this.emission = new Color(0.0f, 0.0f, 0.0f, 0.0f); + this.shininess = 20f; + } + public Color getSpecular() { return this.specular; diff --git a/gov/nasa/worldwind/render/Polyline.java b/gov/nasa/worldwind/render/Polyline.java index 59274ee..c2e4889 100644 --- a/gov/nasa/worldwind/render/Polyline.java +++ b/gov/nasa/worldwind/render/Polyline.java @@ -19,7 +19,7 @@ import java.util.List; /** * @author tag - * @version $Id: Polyline.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: Polyline.java 2932 2007-09-19 19:41:34Z patrickmurris $ */ public class Polyline implements Renderable, Movable { @@ -261,7 +261,7 @@ public class Polyline implements Renderable, Movable { LatLon ll = LatLon.interpolate(i * delta, new LatLon(pos.getLatitude(), pos.getLongitude()), new LatLon(posNext.getLatitude(), posNext.getLongitude())); - double elevation = (i * delta) * pos.getElevation() + (1d - i * delta) * posNext.getElevation(); + double elevation = (1d - i * delta) * pos.getElevation() + (i * delta) * posNext.getElevation(); pt = dc.getGlobe().computePointFromPosition(ll.getLatitude(), ll.getLongitude(), elevation); verts.put(pt.x).put(pt.y).put(pt.z); avgX += pt.x; @@ -271,7 +271,7 @@ public class Polyline implements Renderable, Movable } pt = dc.getGlobe().computePointFromPosition(posNext.getLatitude(), posNext.getLongitude(), - pos.getElevation()); + posNext.getElevation()); verts.put(pt.x).put(pt.y).put(pt.z); avgX += pt.x; avgY += pt.y; diff --git a/gov/nasa/worldwind/render/SurfaceShape.java b/gov/nasa/worldwind/render/SurfaceShape.java index bf86ec1..d42a2b9 100644 --- a/gov/nasa/worldwind/render/SurfaceShape.java +++ b/gov/nasa/worldwind/render/SurfaceShape.java @@ -20,7 +20,7 @@ import java.util.*; /** * @author tag - * @version $Id: SurfaceShape.java 2570 2007-08-16 22:31:33Z tgaskins $ + * @version $Id: SurfaceShape.java 2929 2007-09-19 13:38:34Z patrickmurris $ */ public abstract class SurfaceShape implements Renderable, Disposable, Movable { @@ -89,17 +89,94 @@ public abstract class SurfaceShape implements Renderable, Disposable, Movable this.tiles.clear(); if (!LatLon.positionsCrossDateLine(this.getPositions())) { - this.tiles.add(new TextureTile(Sector.boundingSector(this.getPositions()), null)); + this.tiles.add(new TextureTile(this.computeSquareSector(Sector.boundingSector(this.getPositions())))); } else { Sector[] sectors = this.computeSplitSectors(this.getPositions()); - this.tiles.add(new TextureTile(sectors[0], null)); - this.tiles.add(new TextureTile(sectors[1], null)); + this.tiles.add(new TextureTile(this.computeSquareSector(sectors[0]))); + this.tiles.add(new TextureTile(this.computeSquareSector(sectors[1]))); } } /** + * Returns a sector that will look square when projected on the globe + * and that contains a given sector + * + * @param sector the shape positions + * @return an array of two sectors representing the shape + */ + private Sector computeSquareSector(Sector sector) + { + //if(true) return sector; + // Make it look square - without going over the edges + // taking into account the sector centroid latitude distortion + Angle latSpan = sector.getDeltaLat(); + Angle lonSpan = sector.getDeltaLon(); + Angle midLat = sector.getCentroid().getLatitude(); + if(latSpan.degrees / midLat.cos() > lonSpan.degrees) + { + // Adjust longitude extent to match latitude's + Angle halfDelta = latSpan.divide(midLat.cos()).subtract(lonSpan).divide(2d); + if(halfDelta.degrees * 2 > 360 - lonSpan.degrees) + halfDelta = Angle.fromDegrees((360 - lonSpan.degrees) / 2); + if(sector.getMinLongitude().degrees - halfDelta.degrees < -180) + { + // -180 degrees longitude crossing + Angle westDelta = Angle.fromDegrees(sector.getMinLongitude().degrees + 180); + Angle eastDelta = halfDelta.add(halfDelta).subtract(westDelta); + sector = new Sector(sector.getMinLatitude(), sector.getMaxLatitude(), + sector.getMinLongitude().subtract(westDelta), sector.getMaxLongitude().add(eastDelta)); + } + else if(sector.getMaxLongitude().degrees + halfDelta.degrees > 180) + { + // +180 degrees longitude crossing + Angle eastDelta = Angle.fromDegrees(180 - sector.getMaxLongitude().degrees); + Angle westDelta = halfDelta.add(halfDelta).subtract(eastDelta); + sector = new Sector(sector.getMinLatitude(), sector.getMaxLatitude(), + sector.getMinLongitude().subtract(westDelta), sector.getMaxLongitude().add(eastDelta)); + } + else + { + // No edge crossing + sector = new Sector(sector.getMinLatitude(), sector.getMaxLatitude(), + sector.getMinLongitude().subtract(halfDelta), sector.getMaxLongitude().add(halfDelta)); + } + } + else if(lonSpan.degrees * midLat.cos() > latSpan.degrees) + { + // Adjust latitude extent to match longitude's + Angle halfDelta = lonSpan.multiply(midLat.cos()).subtract(latSpan).divide(2d); + if(halfDelta.degrees * 2 > 180 - latSpan.degrees) + halfDelta = Angle.fromDegrees((180 - latSpan.degrees) / 2); + if(sector.getMinLatitude().degrees - halfDelta.degrees < -90) + { + // -90 degrees latitude crossing + Angle southDelta = Angle.fromDegrees(sector.getMinLatitude().degrees + 90); + Angle northDelta = halfDelta.add(halfDelta).subtract(southDelta); + sector = new Sector(sector.getMinLatitude().subtract(southDelta), sector.getMaxLatitude().add(northDelta), + sector.getMinLongitude(), sector.getMaxLongitude()); + } + else if(sector.getMaxLatitude().degrees + halfDelta.degrees > 90) + { + // +90 degrees latitude crossing + Angle northDelta = Angle.fromDegrees(90 - sector.getMaxLatitude().degrees); + Angle southDelta = halfDelta.add(halfDelta).subtract(northDelta); + sector = new Sector(sector.getMinLatitude().subtract(southDelta), sector.getMaxLatitude().add(northDelta), + sector.getMinLongitude(), sector.getMaxLongitude()); + } + else + { + // No edge crossing + sector = new Sector(sector.getMinLatitude().subtract(halfDelta), sector.getMaxLatitude().add(halfDelta), + sector.getMinLongitude(), sector.getMaxLongitude()); + } + } + //System.out.println(sector.toString()); + return sector; + } + + /** * Returns two 'mirror' sectors each on one side of the longitude boundary - for boundary crossing shapes * * @param positions the shape positions @@ -176,7 +253,7 @@ public abstract class SurfaceShape implements Renderable, Disposable, Movable public void setPositions(Iterable positions) { this.replacePositions(positions); - this.clearTextureData(); + this.createTextureTiles(); } public Paint getPaint() @@ -320,7 +397,11 @@ public abstract class SurfaceShape implements Renderable, Disposable, Movable { BufferedImage image = new BufferedImage((int) size.getWidth(), (int) size.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); - + /*// Debug + Graphics2D g2 = image.createGraphics(); + g2.setPaint(this.getPaint()); + g2.fillRect(0, 0, (int) size.getWidth(), (int) size.getHeight()); + // end debug */ TextureData td = new TextureData(GL.GL_RGBA, GL.GL_RGBA, false, this.drawShape(dc.getGlobe(), tile.getSector(), image)); td.setMustFlipVertically(false); diff --git a/gov/nasa/worldwind/render/SurfaceTile.java b/gov/nasa/worldwind/render/SurfaceTile.java index ab3b6f5..17df808 100644 --- a/gov/nasa/worldwind/render/SurfaceTile.java +++ b/gov/nasa/worldwind/render/SurfaceTile.java @@ -10,7 +10,7 @@ import gov.nasa.worldwind.geom.*; /** * @author tag - * @version $Id: SurfaceTile.java 2533 2007-08-13 05:59:08Z tgaskins $ + * @version $Id: SurfaceTile.java 2812 2007-09-12 19:16:41Z tgaskins $ */ public interface SurfaceTile { @@ -18,6 +18,5 @@ public interface SurfaceTile void applyInternalTransform(DrawContext dc); Sector getSector(); Extent getExtent(DrawContext dc); - double getWidth(); - double getHeight(); + } diff --git a/gov/nasa/worldwind/render/SurfaceTileRenderer.java b/gov/nasa/worldwind/render/SurfaceTileRenderer.java index a28196a..1b30f5f 100644 --- a/gov/nasa/worldwind/render/SurfaceTileRenderer.java +++ b/gov/nasa/worldwind/render/SurfaceTileRenderer.java @@ -19,7 +19,7 @@ import java.util.logging.Level; /** * @author tag - * @version $Id: SurfaceTileRenderer.java 2533 2007-08-13 05:59:08Z tgaskins $ + * @version $Id: SurfaceTileRenderer.java 2980 2007-09-22 01:07:06Z tgaskins $ */ public abstract class SurfaceTileRenderer implements Disposable { @@ -98,8 +98,12 @@ public abstract class SurfaceTileRenderer implements Disposable try { + this.alphaTexture = dc.getTextureCache().get(this); if (this.alphaTexture == null) + { this.initAlphaTexture(DEFAULT_ALPHA_TEXTURE_SIZE); // TODO: choose size to match incoming tile sizes? + dc.getTextureCache().put(this, this.alphaTexture); + } boolean showOutlines = this.showImageTileOutlines && dc.getNumTextureUnits() > 2; if (showOutlines && this.outlineTexture == null) diff --git a/gov/nasa/worldwind/tracks/TrackPoint.java b/gov/nasa/worldwind/tracks/TrackPoint.java index 214bffd..7e8ceeb 100644 --- a/gov/nasa/worldwind/tracks/TrackPoint.java +++ b/gov/nasa/worldwind/tracks/TrackPoint.java @@ -6,9 +6,11 @@ All Rights Reserved. */ package gov.nasa.worldwind.tracks; +import gov.nasa.worldwind.geom.Position; + /** * @author tag - * @version $Id: TrackPoint.java 2422 2007-07-25 23:07:49Z tgaskins $ + * @version $Id: TrackPoint.java 2814 2007-09-12 19:23:53Z tgaskins $ */ public interface TrackPoint { @@ -27,4 +29,8 @@ public interface TrackPoint String getTime(); void setTime(String time); + + Position getPosition(); + + void setPosition(Position position); } diff --git a/gov/nasa/worldwind/tracks/TrackRenderer.java b/gov/nasa/worldwind/tracks/TrackRenderer.java deleted file mode 100644 index 6a475e2..0000000 --- a/gov/nasa/worldwind/tracks/TrackRenderer.java +++ /dev/null @@ -1,414 +0,0 @@ -/* -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.tracks; - -import gov.nasa.worldwind.Disposable; -import gov.nasa.worldwind.geom.*; -import gov.nasa.worldwind.globes.SectorGeometryList; -import gov.nasa.worldwind.layers.Layer; -import gov.nasa.worldwind.render.*; -import gov.nasa.worldwind.util.Logging; - -import javax.media.opengl.GL; -import javax.media.opengl.glu.*; - -/** - * @author tag - * @version $Id$ - */ -public class TrackRenderer implements Disposable -{ - private int lowerLimit = 0; - private int upperLimit = Integer.MAX_VALUE; - private double markerPixels = 10d; // TODO: these should all be configurable - private double minMarkerSize = 5d; - private double markerElevation = 10d; - private boolean overrideMarkerElevation = false; - private Material material = Material.WHITE; - private String iconFilePath; - private final TrackRenderer.Shape SPHERE = new TrackRenderer.Sphere(); - private final TrackRenderer.Shape CONE = new TrackRenderer.Cone(); - private final TrackRenderer.Shape CYLINDER = new TrackRenderer.Cylinder(); - private TrackRenderer.Shape shape = SPHERE; - - public TrackRenderer() - { - } - - public void dispose() - { - this.CONE.dispose(); - this.CYLINDER.dispose(); - this.SPHERE.dispose(); - } - - public double getMarkerPixels() - { - return markerPixels; - } - - public void setMarkerPixels(double markerPixels) - { - this.markerPixels = markerPixels; - } - - public double getMinMarkerSize() - { - return minMarkerSize; - } - - public void setMinMarkerSize(double minMarkerSize) - { - this.minMarkerSize = minMarkerSize; - } - - public double getMarkerElevation() - { - return markerElevation; - } - - public void setMarkerElevation(double markerElevation) - { - this.markerElevation = markerElevation; - } - - public boolean isOverrideMarkerElevation() - { - return overrideMarkerElevation; - } - - public void setOverrideMarkerElevation(boolean overrideMarkerElevation) - { - this.overrideMarkerElevation = overrideMarkerElevation; - } - - public Material getMaterial() - { - return material; - } - - public void setMaterial(Material material) - { - if (material == null) - { - String msg = Logging.getMessage("nullValue.MaterialIsNull"); - Logging.logger().severe(msg); - throw new IllegalArgumentException(msg); - } - - // don't validate material's colors - material does that. - - this.material = material; - } - - public String getIconFilePath() - { - return iconFilePath; - } - - public void setIconFilePath(String iconFilePath) - { - //don't validate - a null iconFilePath cancels icon drawing - this.iconFilePath = iconFilePath; - } - - public int getLowerLimit() - { - return this.lowerLimit; - } - - public void setLowerLimit(int lowerLimit) - { - this.lowerLimit = lowerLimit; - } - - public int getUpperLimit() - { - return this.upperLimit; - } - - public void setUpperLimit(int upperLimit) - { - this.upperLimit = upperLimit; - } - - public void setShapeType(String shapeName) - { - if (shapeName.equalsIgnoreCase("Cone")) - this.shape = CONE; - else if (shapeName.equalsIgnoreCase("Cylinder")) - this.shape = CYLINDER; - else - this.shape = SPHERE; - } - - public void pick(DrawContext dc, java.util.Iterator trackPositions, java.awt.Point pickPoint, - Layer layer) - { - // TODO: picking - } - - public Vec4 render(DrawContext dc, java.util.Iterator trackPositions) - { - return this.draw(dc, trackPositions); - } - - private Vec4 draw(DrawContext dc, java.util.Iterator trackPositions) - { - if (dc.getVisibleSector() == null) - return null; - - SectorGeometryList geos = dc.getSurfaceGeometry(); - if (geos == null) - return null; - - if (!this.shape.isInitialized) - this.shape.initialize(dc); - - int index = 0; - java.util.List points = new java.util.ArrayList(); - while (trackPositions.hasNext()) - { - TrackPoint tp = trackPositions.next(); - if (index >= this.lowerLimit && index <= this.upperLimit) - { - Vec4 point = this.computeSurfacePoint(dc, tp); - if (point != null) - { - points.add(point); - } - } - if (++index >= this.upperLimit) - break; - } - - if (points.size() < 1) - return null; - - Vec4 firstPoint = points.get(0); - Vec4 lastPointDrawn = firstPoint; - this.begin(dc); - { - Vec4 previousDrawnPoint = null; - - double radius = this.computeMarkerRadius(dc, firstPoint); - this.shape.render(dc, firstPoint, radius); - for (Vec4 point : points) - { - if (previousDrawnPoint == null) - { - previousDrawnPoint = firstPoint; - continue; // skip over first point - } - - // TODO: More sophisticated separation algorithm to gain frame-to-frame consistency - radius = this.computeMarkerRadius(dc, point); - double separation = point.distanceTo3(previousDrawnPoint); - double minSeparation = 4d * radius; - if (separation > minSeparation) - { - if (!dc.isPickingMode()) - this.shape.render(dc, point, radius); - - previousDrawnPoint = point; - lastPointDrawn = point; - } - } - } - this.end(dc); - - Vec4 iconPoint = points.get(points.size() - 1); - return iconPoint != null ? iconPoint : lastPointDrawn; - } - - private Vec4 computeSurfacePoint(DrawContext dc, TrackPoint pos) - { - return dc.getSurfaceGeometry().getSurfacePoint(Angle.fromDegrees(pos.getLatitude()), - Angle.fromDegrees(pos.getLongitude()), - this.overrideMarkerElevation ? this.markerElevation : pos.getElevation()); - } - - private double computeMarkerRadius(DrawContext dc, Vec4 point) - { - double d = point.distanceTo3(dc.getView().getEyePoint()); - double radius = this.markerPixels * dc.getView().computePixelSizeAtDistance(d); - if (radius < this.minMarkerSize) - radius = this.minMarkerSize; - - return radius; - } - - private void begin(DrawContext dc) - { - GL gl = dc.getGL(); - Vec4 cameraPosition = dc.getView().getEyePoint(); - - gl.glPushAttrib( - GL.GL_TEXTURE_BIT | GL.GL_ENABLE_BIT | GL.GL_CURRENT_BIT | GL.GL_LIGHTING_BIT | GL.GL_TRANSFORM_BIT); - gl.glDisable(GL.GL_TEXTURE_2D); - - float[] lightPosition = - {(float) (cameraPosition.x * 2), (float) (cameraPosition.y / 2), (float) (cameraPosition.z), 0.0f}; - float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f}; - float[] lightAmbient = {1.0f, 1.0f, 1.0f, 1.0f}; - float[] lightSpecular = {1.0f, 1.0f, 1.0f, 1.0f}; - - this.material.apply(gl, GL.GL_FRONT); - - gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPosition, 0); - gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, lightDiffuse, 0); - gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightAmbient, 0); - gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, lightSpecular, 0); - - gl.glDisable(GL.GL_LIGHT0); - gl.glEnable(GL.GL_LIGHT1); - gl.glEnable(GL.GL_LIGHTING); - gl.glEnable(GL.GL_NORMALIZE); - - gl.glMatrixMode(javax.media.opengl.GL.GL_MODELVIEW); - gl.glPushMatrix(); - } - - private void end(DrawContext dc) - { - GL gl = dc.getGL(); - - gl.glMatrixMode(javax.media.opengl.GL.GL_MODELVIEW); - gl.glPopMatrix(); - - gl.glDisable(GL.GL_LIGHT1); - gl.glEnable(GL.GL_LIGHT0); - gl.glDisable(GL.GL_LIGHTING); - gl.glDisable(GL.GL_NORMALIZE); - gl.glPopAttrib(); - } - - private static abstract class Shape - { - protected int objectId; - protected GLUquadric quadric; - protected boolean isInitialized = false; - - abstract protected void doRender(DrawContext dc, Vec4 point, double radius); - - protected void initialize(DrawContext dc) - { - this.objectId = dc.getGL().glGenLists(1); - this.quadric = dc.getGLU().gluNewQuadric(); - dc.getGLU().gluQuadricDrawStyle(quadric, GLU.GLU_FILL); - dc.getGLU().gluQuadricNormals(quadric, GLU.GLU_SMOOTH); - dc.getGLU().gluQuadricOrientation(quadric, GLU.GLU_OUTSIDE); - dc.getGLU().gluQuadricTexture(quadric, false); - } - - private void dispose() - { - if (this.isInitialized) - { - GLU glu = new GLU(); - glu.gluDeleteQuadric(this.quadric); - // TODO: Determine how to release the opengl object ID. - } - } - - private void render(DrawContext dc, Vec4 point, double radius) - { - dc.getView().pushReferenceCenter(dc, point); - this.doRender(dc, point, radius); - dc.getView().popReferenceCenter(dc); - } - } - - private static class Sphere extends Shape - { - protected void initialize(DrawContext dc) - { - super.initialize(dc); - - double radius = 1; - int slices = 36; - int stacks = 18; - - dc.getGL().glNewList(this.objectId, GL.GL_COMPILE); - dc.getGLU().gluSphere(quadric, radius, slices, stacks); - dc.getGL().glEndList(); - - this.isInitialized = true; - } - - protected void doRender(DrawContext dc, Vec4 point, double radius) - { - dc.getGL().glScaled(radius, radius, radius); - dc.getGL().glCallList(this.objectId); - } - } - - private static class Cone extends Shape - { - protected void initialize(DrawContext dc) - { - super.initialize(dc); - - int slices = 30; - int stacks = 30; - int loops = 2; - - dc.getGL().glNewList(this.objectId, GL.GL_COMPILE); - dc.getGLU().gluCylinder(quadric, 1d, 0d, 2d, slices, (int) (2 * (Math.sqrt(stacks)) + 1)); - dc.getGLU().gluDisk(quadric, 0d, 1d, slices, loops); - dc.getGL().glEndList(); - - this.isInitialized = true; - } - - protected void doRender(DrawContext dc, Vec4 point, double size) - { - PolarPoint p = PolarPoint.fromCartesian(point); - - dc.getGL().glLoadIdentity(); - dc.getGL().glScaled(size, size, size); - dc.getGL().glRotated(p.getLongitude().getDegrees(), 0, 1, 0); - dc.getGL().glRotated(Math.abs(p.getLatitude().getDegrees()), Math.signum(p.getLatitude().getDegrees()) * -1, - 0, 0); - dc.getGL().glCallList(this.objectId); - } - } - - private static class Cylinder extends Shape - { - protected void initialize(DrawContext dc) - { - super.initialize(dc); - - int slices = 30; - int stacks = 30; - int loops = 2; - - dc.getGL().glNewList(this.objectId, GL.GL_COMPILE); - dc.getGLU().gluCylinder(quadric, 1d, 1d, 2d, slices, (int) (2 * (Math.sqrt(stacks)) + 1)); - dc.getGLU().gluDisk(quadric, 0d, 1d, slices, loops); - dc.getGL().glTranslated(0, 0, 2); - dc.getGLU().gluDisk(quadric, 0d, 1d, slices, loops); - dc.getGL().glTranslated(0, 0, -2); - dc.getGL().glEndList(); - - this.isInitialized = true; - } - - protected void doRender(DrawContext dc, Vec4 point, double size) - { - PolarPoint p = PolarPoint.fromCartesian(point); - - dc.getGL().glLoadIdentity(); - dc.getGL().glScaled(size, size, size); - dc.getGL().glRotated(p.getLongitude().getDegrees(), 0, 1, 0); - dc.getGL().glRotated(Math.abs(p.getLatitude().getDegrees()), Math.signum(p.getLatitude().getDegrees()) * -1, - 0, 0); - dc.getGL().glCallList(this.objectId); - } - } -} diff --git a/gov/nasa/worldwind/util/Level.java b/gov/nasa/worldwind/util/Level.java index bb5fc08..73bc322 100644 --- a/gov/nasa/worldwind/util/Level.java +++ b/gov/nasa/worldwind/util/Level.java @@ -11,7 +11,7 @@ import gov.nasa.worldwind.geom.LatLon; /** * @author tag - * @version $Id: Level.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: Level.java 2675 2007-08-25 06:40:46Z tgaskins $ */ public class Level implements Comparable { @@ -29,6 +29,7 @@ public class Level implements Comparable private final String path; private final TileUrlBuilder urlBuilder; private long expiryTime = 0; + private boolean active = true; // Absent tiles: A tile is deemed absent if a specified maximum number of attempts have been made to retrieve it. // Retrieval attempts are governed by a minimum time interval between successive attempts. If an attempt is made @@ -210,7 +211,7 @@ public class Level implements Comparable public final boolean isEmpty() { - return this.levelName == null || this.levelName.equals(""); + return this.levelName == null || this.levelName.equals("") || !this.active; } public final void markResourceAbsent(long tileNumber) @@ -238,6 +239,16 @@ public class Level implements Comparable this.expiryTime = expiryTime; } + public boolean isActive() + { + return this.active; + } + + public void setActive(boolean active) + { + this.active = active; + } + // public interface TileURLBuilder // { // public URL getURL(Tile tile) throws java.net.MalformedURLException; diff --git a/gov/nasa/worldwind/util/LevelSet.java b/gov/nasa/worldwind/util/LevelSet.java index 74e42a4..fb789e8 100644 --- a/gov/nasa/worldwind/util/LevelSet.java +++ b/gov/nasa/worldwind/util/LevelSet.java @@ -15,7 +15,7 @@ import java.util.*; /** * @author tag - * @version $Id: LevelSet.java 2593 2007-08-18 00:03:31Z tgaskins $ + * @version $Id: LevelSet.java 2786 2007-09-10 17:41:00Z tgaskins $ */ public class LevelSet extends WWObjectImpl { @@ -59,6 +59,13 @@ public class LevelSet extends WWObjectImpl if (o == null || !(o instanceof Integer) || (numEmptyLevels = (Integer) o) < 0) sb.append(Logging.getMessage("term.numEMptyLevels")); + String[] inactiveLevels = null; + o = params.getValue(AVKey.INACTIVE_LEVELS); + if (o != null && !(o instanceof String)) + sb.append(Logging.getMessage("term.sector")); // TODO field name + else if (o != null) + inactiveLevels = ((String) o).split(","); + SectorResolution[] sectorLimits = null; o = params.getValue(AVKey.SECTOR_RESOLUTION_LIMITS); if (o != null && !(o instanceof SectorResolution[])) @@ -129,6 +136,15 @@ public class LevelSet extends WWObjectImpl this.levels.add(new Level(params)); } + if (inactiveLevels != null) + { + for (String s : inactiveLevels) + { + int i = Integer.parseInt(s); + this.getLevel(i).setActive(false); + } + } + if (this.sectorLevelLimits != null) { Arrays.sort(this.sectorLevelLimits, new Comparator() @@ -314,4 +330,50 @@ public class LevelSet extends WWObjectImpl tile.getLevel().unmarkResourceAbsent(this.getTileNumber(tile)); } + + // Create the tile corresponding to a specified key. + public Sector computeSectorForKey(TileKey key) + { + if (key == null) + { + String msg = Logging.getMessage("nullValue.KeyIsNull"); + Logging.logger().severe(msg); + throw new IllegalArgumentException(msg); + } + + Level level = this.getLevel(key.getLevelNumber()); + + // Compute the tile's SW lat/lon based on its row/col in the level's data set. + Angle dLat = level.getTileDelta().getLatitude(); + Angle dLon = level.getTileDelta().getLongitude(); + + Angle minLatitude = Tile.computeRowLatitude(key.getRow(), dLat); + Angle minLongitude = Tile.computeColumnLongitude(key.getColumn(), dLon); + + return new Sector(minLatitude, minLatitude.add(dLat), minLongitude, minLongitude.add(dLon)); + } + + // Create the tile corresponding to a specified key. + public Tile createTile(TileKey key) + { + if (key == null) + { + String msg = Logging.getMessage("nullValue.KeyIsNull"); + Logging.logger().severe(msg); + throw new IllegalArgumentException(msg); + } + + Level level = this.getLevel(key.getLevelNumber()); + + // Compute the tile's SW lat/lon based on its row/col in the level's data set. + Angle dLat = level.getTileDelta().getLatitude(); + Angle dLon = level.getTileDelta().getLongitude(); + + Angle minLatitude = Tile.computeRowLatitude(key.getRow(), dLat); + Angle minLongitude = Tile.computeColumnLongitude(key.getColumn(), dLon); + + Sector tileSector = new Sector(minLatitude, minLatitude.add(dLat), minLongitude, minLongitude.add(dLon)); + + return new Tile(tileSector, level, key.getRow(), key.getColumn()); + } } diff --git a/gov/nasa/worldwind/util/Tile.java b/gov/nasa/worldwind/util/Tile.java index 0d49013..2e0821e 100644 --- a/gov/nasa/worldwind/util/Tile.java +++ b/gov/nasa/worldwind/util/Tile.java @@ -13,7 +13,7 @@ import java.util.Random; /** * @author tag - * @version $Id: Tile.java 2471 2007-07-31 21:50:57Z tgaskins $ + * @version $Id: Tile.java 2786 2007-09-10 17:41:00Z tgaskins $ */ public class Tile implements Comparable, Cacheable { @@ -91,7 +91,7 @@ public class Tile implements Comparable, Cacheable this.path = null; } - public Tile(Sector sector, TileKey tileKey) + public Tile(Sector sector) { if (sector == null) { @@ -106,8 +106,8 @@ public class Tile implements Comparable, Cacheable this.level = null; this.row = random.nextInt(); this.column = random.nextInt(); - this.path = Long.toString(System.nanoTime()); - this.tileKey = tileKey != null ? tileKey : new TileKey(this); + this.path = null; + this.tileKey = new TileKey(this); } public long getSizeInBytes() diff --git a/gov/nasa/worldwind/view/AbstractView.java b/gov/nasa/worldwind/view/AbstractView.java index 59f91bf..bff8673 100644 --- a/gov/nasa/worldwind/view/AbstractView.java +++ b/gov/nasa/worldwind/view/AbstractView.java @@ -17,7 +17,7 @@ import javax.media.opengl.glu.GLU; /** * @author Paul Collins - * @version $Id: AbstractView.java 2491 2007-08-02 18:48:00Z dcollins $ + * @version $Id: AbstractView.java 2888 2007-09-18 00:23:29Z dcollins $ */ public abstract class AbstractView extends WWObjectImpl implements View { @@ -78,8 +78,10 @@ public abstract class AbstractView extends WWObjectImpl implements View this.viewportArray[3]); if (!this.isInitialized) + { this.initialize(dc); - this.isInitialized = true; + this.isInitialized = true; + } } private int getMatrixMode(GL gl) @@ -122,14 +124,28 @@ public abstract class AbstractView extends WWObjectImpl implements View final int matrixMode = this.getMatrixMode(gl); // Apply the model-view matrix to the current OpenGL context held by 'dc'. - this.modelView.toArray(this.matrixArray, 0, false); gl.glMatrixMode(GL.GL_MODELVIEW); - gl.glLoadMatrixd(this.matrixArray, 0); + if (this.modelView != null) + { + this.modelView.toArray(this.matrixArray, 0, false); + gl.glLoadMatrixd(this.matrixArray, 0); + } + else + { + gl.glLoadIdentity(); + } // Apply the projection matrix to the current OpenGL context held by 'dc'. - this.projection.toArray(this.matrixArray, 0, false); gl.glMatrixMode(GL.GL_PROJECTION); - gl.glLoadMatrixd(this.matrixArray, 0); + if (this.projection != null) + { + this.projection.toArray(this.matrixArray, 0, false); + gl.glLoadMatrixd(this.matrixArray, 0); + } + else + { + gl.glLoadIdentity(); + } // Restore matrix-mode state. gl.glMatrixMode(matrixMode); @@ -212,7 +228,7 @@ public abstract class AbstractView extends WWObjectImpl implements View if (referenceCenter == null) { String message = Logging.getMessage("nullValue.PointIsNull"); - Logging.logger().fine(message); + Logging.logger().severe(message); throw new IllegalArgumentException(message); } @@ -379,6 +395,7 @@ public abstract class AbstractView extends WWObjectImpl implements View Logging.logger().severe(message); throw new IllegalArgumentException(message); } + this.fieldOfView = newFov; } @@ -534,7 +551,7 @@ public abstract class AbstractView extends WWObjectImpl implements View protected double computeNearClipDistance(DrawContext dc, Vec4 eyeVec) { Angle fov = this.getFieldOfView(); - if (fov == null) + if (dc == null || eyeVec == null || fov == null) return MIN_NEAR_CLIP_DISTANCE; double heightAboveGlobe = this.computeHeightAboveGlobe(dc, eyeVec); @@ -549,6 +566,9 @@ public abstract class AbstractView extends WWObjectImpl implements View protected double computeFarClipDistance(DrawContext dc, Vec4 eyeVec) { + if (dc == null || eyeVec == null) + return MIN_FAR_CLIP_DISTANCE; + double heightAboveGlobe = this.computeHeightAboveGlobe(dc, eyeVec); double heightAboveSurface = this.computeHeightAboveSurface(dc, eyeVec); double farClipDist = Math.max( diff --git a/gov/nasa/worldwind/view/BasicOrbitView.java b/gov/nasa/worldwind/view/BasicOrbitView.java index 0aae0db..af61f08 100644 --- a/gov/nasa/worldwind/view/BasicOrbitView.java +++ b/gov/nasa/worldwind/view/BasicOrbitView.java @@ -13,7 +13,7 @@ import gov.nasa.worldwind.util.Logging; /** * @author dcollins - * @version $Id: BasicOrbitView.java 2506 2007-08-03 23:25:28Z dcollins $ + * @version $Id: BasicOrbitView.java 2890 2007-09-18 00:25:29Z dcollins $ */ public class BasicOrbitView extends AbstractView implements OrbitView { @@ -39,8 +39,14 @@ public class BasicOrbitView extends AbstractView implements OrbitView protected void doApply(DrawContext dc) { - // Compute current viewing attributes. + if (this.orbitViewModel == null) + return; + Vec4 eyeVec = this.orbitViewModel.getEyeVector(); + if (eyeVec == null) + return; + + // Compute current viewing attributes. double nearClipDist = this.computeNearClipDistance(dc, eyeVec); double farClipDist = this.computeFarClipDistance(dc, eyeVec); this.frustum = this.createFrustum(nearClipDist, farClipDist); @@ -58,13 +64,22 @@ public class BasicOrbitView extends AbstractView implements OrbitView private Matrix createModelViewMatrix(OrbitViewModel orbitViewModel) { + if (orbitViewModel == null) + return null; + return orbitViewModel.getTransformMatrix(); } private Matrix createProjectionMatrix(double nearClipDistance, double farClipDistance) { Angle fov = this.getFieldOfView(); + if (fov == null) + return null; + java.awt.Rectangle viewport = this.getViewport(); + if (viewport == null) + return null; + // Create a standard perspective projection. return Matrix.fromPerspective( fov, @@ -75,7 +90,13 @@ public class BasicOrbitView extends AbstractView implements OrbitView private Frustum createFrustum(double nearClipDistance, double farClipDistance) { Angle fov = this.getFieldOfView(); + if (fov == null) + return null; + java.awt.Rectangle viewport = this.getViewport(); + if (viewport == null) + return null; + // Create a standard perspective frustum. return Frustum.fromPerspective( fov, viewport.width, viewport.height, @@ -88,38 +109,38 @@ public class BasicOrbitView extends AbstractView implements OrbitView protected void doInitialize(DrawContext dc) { - Angle initialLatitude = getInitialLatitude(dc, this.latitude); - Angle initialLongitude = getInitialLongitude(dc, this.longitude); - Angle initialHeading = getInitialHeading(dc, this.heading); - Angle initialPitch = getInitialPitch(dc, this.pitch); - double initialAltitude = getInitialAltitude(dc, this.altitude); - // Save values not included in OrbitViewModel init. - // These may be set after OrbitViewModel init. - double initialZoom = this.zoom; - Angle initialLookAtLatitude = this.lookAtLatitude; - Angle initialLookAtLongitude = this.lookAtLongitude; - Quaternion initialRotation = this.rotation; + Angle initialLookAtLatitude = getInitialLatitude(this.lookAtLatitude); + Angle initialLookAtLongitude = getInitialLongitude(this.lookAtLongitude); + Angle initialHeading = getInitialHeading(this.heading); + Angle initialPitch = getInitialPitch(this.pitch); + double initialZoom = getInitialAltitude(dc, this.zoom); +// // Save values not included in OrbitViewModel init. +// // These may be set after OrbitViewModel init. +// double initialZoom = this.zoom; +// Angle initialLookAtLatitude = this.lookAtLatitude; +// Angle initialLookAtLongitude = this.lookAtLongitude; +// Quaternion initialRotation = this.rotation; this.orbitViewModel = new OrbitViewModel( dc, - initialLatitude, initialLongitude, + initialLookAtLatitude, initialLookAtLongitude, initialHeading, initialPitch, - initialAltitude); + initialZoom); this.updateAttributes(dc); - // Apply values set by client before initialization, - // but not included in OrbitViewModel init. - if (initialZoom >= 0) - this.setZoom(initialZoom); - if (initialLookAtLatitude != null) - this.setLookAtLatitude(initialLookAtLatitude); - if (initialLookAtLongitude != null) - this.setLookAtLongitude(initialLookAtLongitude); - if (initialRotation != null) - this.setRotation(initialRotation); +// // Apply values set by client before initialization, +// // but not included in OrbitViewModel init. +// if (initialZoom >= 0) +// this.setZoom(initialZoom); +// if (initialLookAtLatitude != null) +// this.setLookAtLatitude(initialLookAtLatitude); +// if (initialLookAtLongitude != null) +// this.setLookAtLongitude(initialLookAtLongitude); +// if (initialRotation != null) +// this.setRotation(initialRotation); } - protected static Angle getInitialLatitude(DrawContext dc, Angle clientValue) + protected static Angle getInitialLatitude(Angle clientValue) { // Use value specified by client. if (clientValue != null) @@ -134,7 +155,7 @@ public class BasicOrbitView extends AbstractView implements OrbitView return Angle.ZERO; } - protected static Angle getInitialLongitude(DrawContext dc, Angle clientValue) + protected static Angle getInitialLongitude(Angle clientValue) { // Use value specified by client. if (clientValue != null) @@ -155,7 +176,7 @@ public class BasicOrbitView extends AbstractView implements OrbitView return Angle.ZERO; } - protected static Angle getInitialHeading(DrawContext dc, Angle clientValue) + protected static Angle getInitialHeading(Angle clientValue) { // Use value specified by client. if (clientValue != null) @@ -170,7 +191,7 @@ public class BasicOrbitView extends AbstractView implements OrbitView return Angle.ZERO; } - protected static Angle getInitialPitch(DrawContext dc, Angle clientValue) + protected static Angle getInitialPitch(Angle clientValue) { // Use value specified by client. if (clientValue != null) @@ -261,6 +282,9 @@ public class BasicOrbitView extends AbstractView implements OrbitView private boolean onModelChange(DrawContext dc, OrbitViewModel orbitViewModel, boolean preserveCenter) { + if (dc == null || orbitViewModel == null) + return false; + // Moves the view when it collides with surface geometry. boolean isAboveSurface = this.ensureViewIsAboveSurface(orbitViewModel, preserveCenter); // Computes new values for orbital-viewing attributes. @@ -278,18 +302,42 @@ public class BasicOrbitView extends AbstractView implements OrbitView return; Position eyePos = this.orbitViewModel.getEyePosition(dc); - this.latitude = eyePos.getLatitude(); - this.longitude = eyePos.getLongitude(); - this.altitude = eyePos.getElevation(); + if (eyePos != null) + { + this.latitude = eyePos.getLatitude(); + this.longitude = eyePos.getLongitude(); + this.altitude = eyePos.getElevation(); + } + else + { + this.latitude = null; + this.longitude = null; + this.altitude = 0; + } Position centerPos = this.orbitViewModel.getLookAtPosition(dc); - this.lookAtLatitude = centerPos.getLatitude(); - this.lookAtLongitude = centerPos.getLongitude(); + if (centerPos != null) + { + this.lookAtLatitude = centerPos.getLatitude(); + this.lookAtLongitude = centerPos.getLongitude(); + } + else + { + this.lookAtLatitude = null; + this.lookAtLongitude = null; + } this.heading = this.orbitViewModel.getHeading(dc); this.pitch = this.orbitViewModel.getPitch(dc); - this.zoom = this.orbitViewModel.getZoom(dc); - + Double modelZoom = this.orbitViewModel.getZoom(dc); + if (modelZoom != null) + { + this.zoom = modelZoom; + } + else + { + this.zoom = 0; + } this.rotation = this.orbitViewModel.getRotation(); } @@ -423,6 +471,9 @@ public class BasicOrbitView extends AbstractView implements OrbitView private static Angle normalizedHeading(Angle unnormalizedAngle) { + if (unnormalizedAngle == null) + return null; + double degrees = unnormalizedAngle.degrees; double heading = degrees % 360; return Angle.fromDegrees(heading > 180 ? heading - 360 : (heading < -180 ? 360 + heading : heading)); @@ -458,12 +509,18 @@ public class BasicOrbitView extends AbstractView implements OrbitView private static boolean isPitchInRange(Angle angle) { + if (angle == null) + return false; + double pitch = angle.degrees % 360; return (pitch >= 0) && (pitch <= 90); } private static Angle clampedPitch(Angle unclampedAngle) { + if (unclampedAngle == null) + return null; + double degrees = unclampedAngle.degrees; double pitch = degrees % 360; return Angle.fromDegrees(pitch > 90 ? 90 : (pitch < 0 ? 0 : pitch)); @@ -530,12 +587,18 @@ public class BasicOrbitView extends AbstractView implements OrbitView private static boolean isLatitudeInRange(Angle angle) { + if (angle == null) + return false; + double latitude = angle.degrees; return (latitude >= -90) && (latitude <= 90); } private static Angle clampedLatitude(Angle unclampedAngle) { + if (unclampedAngle == null) + return null; + double unclampedDegrees = unclampedAngle.degrees; double degrees = unclampedDegrees < -90 ? -90 : (unclampedDegrees > 90 ? 90 : unclampedDegrees); return Angle.fromDegrees(degrees); @@ -669,6 +732,9 @@ public class BasicOrbitView extends AbstractView implements OrbitView private boolean ensureViewIsAboveSurface(OrbitViewModel orbitViewModel, boolean preserveCenter) { + if (orbitViewModel == null) + return false; + DrawContext dc = this.getDrawContext(); if (dc == null) return false; @@ -693,6 +759,9 @@ public class BasicOrbitView extends AbstractView implements OrbitView private void fixViewBelowSurfaceWithAltitude(DrawContext dc, OrbitViewModel orbitViewModel, double heightAboveSurface) { + if (dc == null || orbitViewModel == null) + return; + int i = 0; final int MAX_ITERATIONS = 2; while ((i < MAX_ITERATIONS) && (heightAboveSurface < 0)) @@ -706,6 +775,9 @@ public class BasicOrbitView extends AbstractView implements OrbitView private void fixViewBelowSurfaceWithPitch(DrawContext dc, OrbitViewModel orbitViewModel, double heightAboveSurface) { + if (dc == null || orbitViewModel == null) + return; + int i = 0; final int MAX_ITERATIONS = 4; while ((i < MAX_ITERATIONS) && (heightAboveSurface < 0)) @@ -721,10 +793,18 @@ public class BasicOrbitView extends AbstractView implements OrbitView private void transformPitchByHeight(DrawContext dc, OrbitViewModel orbitViewModel, double heightAboveSurface) { + if (dc == null || orbitViewModel == null) + return; + Vec4 eyeVec = orbitViewModel.getEyeVector(); + if (eyeVec == null) + return; + Vec4 centerVec = orbitViewModel.getLookAtVector(dc); - Vec4 normalVec = centerVec.normalize3(); + if (centerVec == null) + return; + Vec4 normalVec = centerVec.normalize3(); double dot1 = normalVec.dot3(eyeVec.subtract3(centerVec).normalize3()); if (dot1 >= 1) return; @@ -755,7 +835,12 @@ public class BasicOrbitView extends AbstractView implements OrbitView return 0; Vec4 eyeVec = orbitViewModel.getEyeVector(); + if (eyeVec == null) + return 0; + Matrix matrix = orbitViewModel.getTransformMatrix(); + if (matrix == null) + return 0; double nearClipDist = Math.abs(frustum.getNear().getDistance()); double tanHalfFov = fov.tanHalfAngle(); @@ -773,7 +858,8 @@ public class BasicOrbitView extends AbstractView implements OrbitView private double findLowestHeightAboveSurface(DrawContext dc, Vec4... points) { if (dc == null - || points == null) + || points == null + || points.length == 0) return 0; double minHeight = Double.MAX_VALUE; diff --git a/gov/nasa/worldwind/view/OrbitViewModel.java b/gov/nasa/worldwind/view/OrbitViewModel.java index ab0d414..34bb27e 100644 --- a/gov/nasa/worldwind/view/OrbitViewModel.java +++ b/gov/nasa/worldwind/view/OrbitViewModel.java @@ -12,7 +12,7 @@ import gov.nasa.worldwind.util.Logging; /** * @author dcollins - * @version $Id: OrbitViewModel.java 2503 2007-08-03 23:22:10Z dcollins $ + * @version $Id: OrbitViewModel.java 2889 2007-09-18 00:24:10Z dcollins $ */ class OrbitViewModel { @@ -24,15 +24,15 @@ class OrbitViewModel } public OrbitViewModel(DrawContext dc, - Angle latitude, Angle longitude, + Angle lookAtLatitude, Angle lookAtLongitude, Angle heading, Angle pitch, - double altitude) + double zoom) { this(dc, createInitTransform( dc, - latitude, longitude, + lookAtLatitude, lookAtLongitude, heading, pitch, - altitude)); + zoom)); } public OrbitViewModel(DrawContext dc, Matrix transformMatrix) @@ -132,7 +132,7 @@ class OrbitViewModel Position centerPos = dc.getGlobe().computePositionFromPoint(center); Position newCenterPos = dc.getGlobe().computePositionFromPoint(newCenter); // Abort the transform when it causes model errors. - final double EPSILON = 1e-10; + final double EPSILON = 1; if (Math.abs(newCenterPos.getLongitude().subtract(centerPos.getLongitude()).degrees) > EPSILON) return; @@ -307,14 +307,14 @@ class OrbitViewModel private static Matrix createInitTransform( DrawContext dc, - Angle latitude, Angle longitude, + Angle lookAtLatitude, Angle lookAtLongitude, Angle heading, Angle pitch, - double altitude) + double zoom) { if (dc == null || dc.getGlobe() == null - || latitude == null - || longitude == null + || lookAtLatitude == null + || lookAtLongitude == null || heading == null || pitch == null) return null; @@ -331,15 +331,15 @@ class OrbitViewModel initTransform = initTransform.multiply(Matrix.fromTranslation( 0.0, 0.0, - 0.0 - globe.getRadiusAt(latitude, longitude))); + 0.0 - globe.getRadiusAt(lookAtLatitude, lookAtLongitude))); initTransform = initTransform.multiply(Matrix.fromRotationX(heading.multiply(-1))); initTransform = initTransform.multiply(Matrix.fromRotationZ(pitch)); initTransform = initTransform.multiply(Matrix.fromTranslation( 0.0, 0.0, - 0.0 - altitude)); - initTransform = initTransform.multiply(Matrix.fromRotationX(latitude)); - initTransform = initTransform.multiply(Matrix.fromRotationY(longitude.multiply(-1))); + 0.0 - zoom)); + initTransform = initTransform.multiply(Matrix.fromRotationX(lookAtLatitude)); + initTransform = initTransform.multiply(Matrix.fromRotationY(lookAtLongitude.multiply(-1))); return initTransform; } @@ -700,13 +700,15 @@ class OrbitViewModel forwardVec = forwardVec.normalize3(); Position centerPos = globe.getIntersectionPosition(new Line(eyeVec, forwardVec)); - if (centerPos == null) - return computeHorizonPoint(globe, transformMatrix); + if (centerPos != null) + { + Angle centerLat = centerPos.getLatitude(); + Angle centerLon = centerPos.getLongitude(); + double centerElevation = dc.getVerticalExaggeration() * globe.getElevation(centerLat, centerLon); + return globe.computePointFromPosition(centerLat, centerLon, centerElevation); + } - Angle centerLat = centerPos.getLatitude(); - Angle centerLon = centerPos.getLongitude(); - double centerElevation = dc.getVerticalExaggeration() * globe.getElevation(centerLat, centerLon); - return globe.computePointFromPosition(centerLat, centerLon, centerElevation); + return computeHorizonPoint(globe, transformMatrix); } private static Vec4 computeHorizonPoint(Globe globe, Matrix transformMatrix) @@ -735,11 +737,13 @@ class OrbitViewModel || lookAtPoint == null) return null; - Vec4 heading = computeHeadingVector(transformMatrix, lookAtPoint); + Vec4 headingVec = computeHeadingVector(transformMatrix, lookAtPoint); + if (headingVec == null) + return null; - double dot = headingCoords.north.dot3(heading); + double dot = headingCoords.northVec.dot3(headingVec); // Compute the sum of magnitudes. - double length = headingCoords.north.getLength3() * heading.getLength3(); + double length = headingCoords.northVec.getLength3() * headingVec.getLength3(); // Normalize the dot product, if necessary. if ((length != 0) && (length != 1.0)) dot /= length; @@ -757,7 +761,7 @@ class OrbitViewModel if (Double.isNaN(degrees)) return null; - if (headingCoords.east.dot3(heading) < 0) + if (headingCoords.eastVec.dot3(headingVec) < 0) degrees = 360 - degrees; // Collapses duplicate values for North heading. @@ -769,13 +773,13 @@ class OrbitViewModel private static class HeadingCoordinates { - public final Vec4 north; - public final Vec4 east; + public final Vec4 northVec; + public final Vec4 eastVec; - public HeadingCoordinates(Vec4 north, Vec4 east) + public HeadingCoordinates(Vec4 northVec, Vec4 eastVec) { - this.north = north; - this.east = east; + this.northVec = northVec; + this.eastVec = eastVec; } } diff --git a/images/400x230-splash-wwr.png b/images/400x230-splash-wwr.png deleted file mode 100644 index 6f566d3a83c1a587b6da4aba37a9e73eb36cd2bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 155227 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 diff --git a/worldwinddemo/BasicDemo.java b/worldwinddemo/BasicDemo.java index cb5611d..13378fa 100644 --- a/worldwinddemo/BasicDemo.java +++ b/worldwinddemo/BasicDemo.java @@ -19,7 +19,7 @@ import java.awt.event.*; /** * @author tag - * @version $Id: WWPieceMaker.java 1764 2007-05-07 20:01:57Z tgaskins $ + * @version $Id: BasicDemo.java 2783 2007-09-10 17:12:44Z tgaskins $ */ public class BasicDemo { private BasicDemo.LayerAction[] layers = new BasicDemo.LayerAction[]{ diff --git a/worldwinddemo/StatusBar.java b/worldwinddemo/StatusBar.java deleted file mode 100644 index 1d90dc3..0000000 --- a/worldwinddemo/StatusBar.java +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright (C) 2001, 2006 United States Government -as represented by the Administrator of the -National Aeronautics and Space Administration. -All Rights Reserved. -*/ -package worldwinddemo; - -import gov.nasa.worldwind.*; -import gov.nasa.worldwind.geom.*; - -import javax.swing.*; -import java.awt.event.*; - -/** - * @author tag - * @version $Id: StatusBar.java 1764 2007-05-07 20:01:57Z tgaskins $ - */ -public class StatusBar extends JPanel implements PositionListener -{ - private WorldWindow eventSource; - private final JLabel latDisplay = new JLabel(""); - private final JLabel lonDisplay = new JLabel("Off globe"); - private final JLabel eleDisplay = new JLabel(""); - - public StatusBar() - { - super(new java.awt.GridLayout(1, 0)); - - final JLabel heartBeat = new JLabel("Downloading"); - - latDisplay.setHorizontalAlignment(SwingConstants.CENTER); - lonDisplay.setHorizontalAlignment(SwingConstants.CENTER); - eleDisplay.setHorizontalAlignment(SwingConstants.CENTER); - - this.add(new JLabel("")); // dummy label to visually balance with heartbeat - this.add(latDisplay); - this.add(lonDisplay); - this.add(eleDisplay); - this.add(heartBeat); - - heartBeat.setHorizontalAlignment(SwingConstants.CENTER); - heartBeat.setForeground(new java.awt.Color(255, 0, 0, 0)); - - Timer downloadTimer = new Timer(50, new ActionListener() - { - public void actionPerformed(java.awt.event.ActionEvent actionEvent) - { - - java.awt.Color color = heartBeat.getForeground(); - - int alpha = color.getAlpha(); - - if (WorldWind.retrievalService().hasActiveTasks()) - { - if (alpha == 255) - alpha = 255; - else - alpha = alpha < 16 ? 16 : Math.min(255, alpha + 20); - } - else - { - alpha = Math.max(0, alpha - 20); - } - heartBeat.setForeground(new java.awt.Color(255, 0, 0, alpha)); - } - }); - downloadTimer.start(); - } - - public void setEventSource(WorldWindow newEventSource) - { - if (this.eventSource != null) - this.eventSource.removePositionListener(this); - - if (newEventSource != null) - newEventSource.addPositionListener(this); - - this.eventSource = newEventSource; - } - - public void moved(PositionEvent event) - { - this.handleCursorPositionChange(event); - } - - public WorldWindow getEventSource() - { - return this.eventSource; - } - - private void handleCursorPositionChange(PositionEvent event) - { - Position newPos = (Position) event.getPosition(); - if (newPos != null) - { - String las = String.format("Latitude %7.3f\u00B0", - newPos.getLatitude().getDegrees()); - String los = String.format("Longitude %7.3f\u00B0", - newPos.getLongitude().getDegrees()); - String els = String.format("Elevation %7d meters", (int) newPos.getElevation()); - latDisplay.setText(las); - lonDisplay.setText(los); - eleDisplay.setText(els); - } - else - { - latDisplay.setText(""); - lonDisplay.setText("Off globe"); - eleDisplay.setText(""); - } - } -} -- 2.11.4.GIT