diff --git a/README.md b/README.md index 971132166e..fe13b4b70d 100755 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ # WorldWind Java -## New versions of WorldWind released -Web WorldWind 0.10.0 and WorldWind Java 2.2.0 are now available on GitHub. The new version of Web WorldWind addresses potential vulnerabilities in the code and underlying packages. The new version of WorldWind Java focuses on upgrading to Java 11 and JOGL 2.4 as well as a switch to Apache 2.0 license. WorldWind's API remains largely unchanged in this release and we are committed to maintaining a consistent API in future releases. -More information on the release can be found at these links: [Web WorldWind 0.10.0](https://github.com/NASAWorldWind/WebWorldWind/releases) and [WorldWind Java 2.2.0](https://github.com/NASAWorldWind/WorldWindJava/releases). +## New version of WorldWind Java released +WorldWind Java 2.2.1 is now available on GitHub. This version of WorldWind Java is a maintenance release that addresses small fixes (typos, bad references, etc.) to various areas of the code and removes references to services that are no longer supported by the WorldWind servers. + +WorldWind's API remains unchanged in this release and we are committed to maintaining a consistent API in future releases. +More information on the release can be found at this link: [WorldWind Java 2.2.1](https://github.com/NASAWorldWind/WorldWindJava/releases). Please direct questions to our new email address: arc-worldwind@mail.nasa.gov. @@ -25,10 +27,11 @@ Official WorldWind Java releases have the latest stable features, enhancements a ## Run a Demo -###### From a Web Browser +The following options are available to run a WorldWind Java demo: + +###### From the Apache NetBeans IDE -- [WorldWind Demo App](https://worldwind.arc.nasa.gov/java/latest/webstart/ApplicationTemplate.jnlp) shows WorldWind's basic capabilities -- [Java Demos](https://goworldwind.org/demos) has a complete list of example apps +Clone the SDK with git, open the WorldWind Java project with Apache Netbeans and run demos via the Netbeans interface. ###### From a Windows Development Environment diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt new file mode 100644 index 0000000000..c92a05cca0 --- /dev/null +++ b/RELEASE_NOTES.txt @@ -0,0 +1,26 @@ +################### WorldWindJava 2.2.1 + +This version of WorldWind Java is a maintenance release that addresses small fixes (updated formatting, typos, bad references, etc.) to various areas of the code and removes references to services that are no longer supported by the WorldWind servers. + +WorldWind's API remains unchanged in this release and we are committed to maintaining a consistent API in future releases. + +################### WorldWindJava 2.2.0 + +The primary goal of the WorldWind Java (WWJ) v2.2.0 release is to modernize the SDK after a period of inactivity. During this process some defects were addressed as well. Highlights of v2.2.0: + +- Upgrade to Java 11 +- Upgrade to the OpenGL layer (JOGL) 2.4 +- Switch to the Apache 2.0 license +- Deprecation of unsupported functionality such as Applets, WebStart and WebView. + +WorldWind's API remains largely unchanged in this release and we are committed to maintaining a consistent API in future releases. + +The prior release of WorldWind Java, v2.1.0, was compiled with Java 8. The decision was made to upgrade WWJ to Java 11 based on questionable support options for Java 8 at the time. This situation has evolved over time and we are evaluating whether a Java 8 version of WWJ is desirable. Your feedback is welcome. + +Migrating to Java 11 and JOGL 2.4 went relatively smoothly. Primary areas of work: + +- The package names for JOGL have changed although the API remains relatively consistent. +- Creating work alike code to replace the use of unpublished JRE APIs that now throw an access exception. For example, setting the java library path system property. Discussions around the types of changes that need to be made when moving from 8 to 11 are broadly available on the Web. +- Removing deprecated functionality like WebStart, Applets and WebView. + +This release positions WorldWind Java to begin adding new functionality in the near future, please watch this repository for further updates. diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index 4afb9b93a0..506f468c86 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -46,8 +46,8 @@ is divided into following sections: - - + + @@ -119,7 +119,43 @@ is divided into following sections: - + + + + + + + + + + + + + + + + + + + + + + + + + + Must set platform.home + Must set platform.bootcp + Must set platform.java + Must set platform.javac + + The J2SE Platform is not correctly set up. + Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files. + Either open the project in the IDE and setup the Platform with the same name or add it manually. + For example like this: + ant -Duser.properties.file=<path_to_property_file> jar (where you put the property "platforms.${platform.active}.home" in a .properties file) + or ant -Dplatforms.${platform.active}.home=<path_to_JDK_home> jar (where no properties file is used) + @@ -242,20 +278,6 @@ is divided into following sections: - - - - - - - - - - - - - - @@ -343,7 +365,7 @@ is divided into following sections: - + @@ -394,7 +416,7 @@ is divided into following sections: - + @@ -436,7 +458,7 @@ is divided into following sections: - + @@ -515,7 +537,7 @@ is divided into following sections: - + @@ -543,7 +565,7 @@ is divided into following sections: - + @@ -619,7 +641,7 @@ is divided into following sections: - + @@ -850,6 +872,9 @@ is divided into following sections: + + + @@ -899,7 +924,7 @@ is divided into following sections: - + @@ -933,7 +958,7 @@ is divided into following sections: - + @@ -965,7 +990,7 @@ is divided into following sections: - + @@ -1199,7 +1224,7 @@ is divided into following sections: To run this application from the command line without Ant, try: - java -jar "${dist.jar.resolved}" + ${platform.java} -jar "${dist.jar.resolved}" @@ -1301,8 +1326,8 @@ is divided into following sections: - - + + @@ -1495,16 +1520,19 @@ is divided into following sections: + + + - + - + - + @@ -1686,6 +1714,7 @@ is divided into following sections: + diff --git a/nbproject/configs/ColladaViewer.properties b/nbproject/configs/ColladaViewer.properties new file mode 100644 index 0000000000..db451073d7 --- /dev/null +++ b/nbproject/configs/ColladaViewer.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.ColladaViewer diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties index ec6652016b..6a15e776fa 100644 --- a/nbproject/genfiles.properties +++ b/nbproject/genfiles.properties @@ -1,8 +1,8 @@ -build.xml.data.CRC32=6106e3d1 +build.xml.data.CRC32=ed839dc9 build.xml.script.CRC32=b2ee8dee -build.xml.stylesheet.CRC32=f85dc8f2@1.95.0.48 +build.xml.stylesheet.CRC32=f85dc8f2@1.102.0.48 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=6106e3d1 -nbproject/build-impl.xml.script.CRC32=f2cfd8e0 -nbproject/build-impl.xml.stylesheet.CRC32=f89f7d21@1.95.0.48 +nbproject/build-impl.xml.data.CRC32=ed839dc9 +nbproject/build-impl.xml.script.CRC32=2e7bce4f +nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.102.0.48 diff --git a/nbproject/project.properties b/nbproject/project.properties index fab181db51..1adab5d73f 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -104,7 +104,7 @@ manifest.custom.permissions= manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF mkdist.disabled=false -platform.active=default_platform +platform.active=JDK_11 run.classpath=\ ${javac.classpath}:\ ${build.classes.dir} diff --git a/nbproject/project.xml b/nbproject/project.xml index e27d90a9ba..cba6c32199 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -4,6 +4,7 @@ WorldWindJava + diff --git a/release-build.xml b/release-build.xml index 8877973d0e..9810ad732d 100644 --- a/release-build.xml +++ b/release-build.xml @@ -381,24 +381,4 @@ - - - - - - - - - - - - - diff --git a/src/config/Earth/MSVirtualEarthAerialLayer.xml b/src/config/Earth/MSVirtualEarthAerialLayer.xml deleted file mode 100644 index 51d3ef162b..0000000000 --- a/src/config/Earth/MSVirtualEarthAerialLayer.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - MS Virtual Earth Aerial - - https://worldwind28.arc.nasa.gov/vewms/vewms.aspx - - - 19 09 2009 04:10:00 GMT - a - Earth/MS Virtual Earth a - image/jpg - - image/jpg - - .dds - - - - - - - - - - - - - - - - - - - - true - \ No newline at end of file diff --git a/src/config/Earth/MSVirtualEarthHybridLayer.xml b/src/config/Earth/MSVirtualEarthHybridLayer.xml deleted file mode 100644 index 356562fdcb..0000000000 --- a/src/config/Earth/MSVirtualEarthHybridLayer.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - MS Virtual Earth Hybrid - - https://worldwind28.arc.nasa.gov/vewms/vewms.aspx - - - 19 09 2009 04:10:00 GMT - h - Earth/MS Virtual Earth h - image/jpg - - image/jpg - - .dds - - - - - - - - - - - - - - - - - - - - true - \ No newline at end of file diff --git a/src/config/Earth/MSVirtualEarthRoadsLayer.xml b/src/config/Earth/MSVirtualEarthRoadsLayer.xml deleted file mode 100644 index 715e37ac55..0000000000 --- a/src/config/Earth/MSVirtualEarthRoadsLayer.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - MS Virtual Earth Roads - - https://worldwind28.arc.nasa.gov/vewms/vewms.aspx - - - 19 09 2009 04:10:00 GMT - r - Earth/MS Virtual Earth r - image/jpg - - image/jpg - - .dds - - - - - - - - - - - - - - - - - - - - true - \ No newline at end of file diff --git a/src/config/Earth/USDANAIPWMSImageLayer.xml b/src/config/Earth/USDANAIPWMSImageLayer.xml deleted file mode 100644 index 7d74784a7a..0000000000 --- a/src/config/Earth/USDANAIPWMSImageLayer.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - USDA NAIP - - https://worldwind47.arc.nasa.gov/wms - https://worldwind47.arc.nasa.gov/wms - NAIP - - 1240509300000 - - 23 04 2009 17:55:00 GMT - Earth/USDA NAIP - image/dds - - image/png - image/dds - - .dds - - - - - - - - - - - - - - - - - - - true - - images/usda_logo-32x32.png - http://www.fsa.usda.gov/FSA - - - - - - \ No newline at end of file diff --git a/src/config/Earth/USGSTopoHighResLayer.xml b/src/config/Earth/USGSTopoHighResLayer.xml deleted file mode 100644 index 3f626c65a2..0000000000 --- a/src/config/Earth/USGSTopoHighResLayer.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - USGS Topo Scanned Maps 1:24K - 25 06 2011 05:00:00 GMT - - 24e3 - - 0.3 - - https://worldwind47.arc.nasa.gov/topo - https://worldwind47.arc.nasa.gov/topo - US_TOPO_3 - - Earth/USGS Topographic Maps 24k Scale - true - - image/png - image/jpeg - image/dds - - image/png - .png - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/config/Earth/USGSTopoLowResLayer.xml b/src/config/Earth/USGSTopoLowResLayer.xml deleted file mode 100644 index 23387c5ad2..0000000000 --- a/src/config/Earth/USGSTopoLowResLayer.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - USGS Topo Scanned Maps 1:250K - 25 06 2011 05:00:00 GMT - - 250e3 - 0.3 - - - https://worldwind47.arc.nasa.gov/topo - https://worldwind47.arc.nasa.gov/topo - US_TOPO_1 - - Earth/USGS Topographic Maps 250k Scale - true - - image/png - image/jpeg - image/dds - - image/png - .png - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/config/Earth/USGSTopoMedResLayer.xml b/src/config/Earth/USGSTopoMedResLayer.xml deleted file mode 100644 index d108ed21ce..0000000000 --- a/src/config/Earth/USGSTopoMedResLayer.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - USGS Topo Scanned Maps 1:100K - 25 06 2011 05:00:00 GMT - - 100e3 - - 0.3 - - https://worldwind47.arc.nasa.gov/topo - https://worldwind47.arc.nasa.gov/topo - US_TOPO_2 - - Earth/USGS Topographic Maps 100k Scale - true - - image/png - image/jpeg - image/dds - - image/png - .png - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/config/worldwind.layers.xml b/src/config/worldwind.layers.xml index d39a047c7e..0cffc64e29 100644 --- a/src/config/worldwind.layers.xml +++ b/src/config/worldwind.layers.xml @@ -47,11 +47,11 @@ - + diff --git a/src/config/worldwind.xml b/src/config/worldwind.xml index ee08552899..8d59ea6a3b 100644 --- a/src/config/worldwind.xml +++ b/src/config/worldwind.xml @@ -1,31 +1,31 @@ +~ Copyright 2006-2009, 2017, 2020 United States Government, as represented by the +~ Administrator of the National Aeronautics and Space Administration. +~ All rights reserved. +~ +~ The NASA World Wind Java (WWJ) platform is licensed under the Apache License, +~ Version 2.0 (the "License"); you may not use this file except in compliance +~ with the License. You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ +~ Unless required by applicable law or agreed to in writing, software distributed +~ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +~ CONDITIONS OF ANY KIND, either express or implied. See the License for the +~ specific language governing permissions and limitations under the License. +~ +~ NASA World Wind Java (WWJ) also contains the following 3rd party Open Source +~ software: +~ +~ Jackson Parser – Licensed under Apache 2.0 +~ GDAL – Licensed under MIT +~ JOGL – Licensed under Berkeley Software Distribution (BSD) +~ Gluegen – Licensed under Berkeley Software Distribution (BSD) +~ +~ A complete listing of 3rd Party software notices and licenses included in +~ NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party +~ notices and licenses PDF found in code directory. +--> @@ -116,10 +116,10 @@ +See https://worldwind.arc.nasa.gov/java/tutorials/tactical-symbols/#offline-use for more information on how +to configure a local symbol repository. +Examples: http://myserver.com/milstd2525/ (web server) + jar:file:milstd2525-symbols.zip! (local zip archive) --> \ No newline at end of file diff --git a/src/gov/nasa/worldwind/Version.java b/src/gov/nasa/worldwind/Version.java index 9a1a4e7bd0..7fc7e9cb24 100644 --- a/src/gov/nasa/worldwind/Version.java +++ b/src/gov/nasa/worldwind/Version.java @@ -35,7 +35,7 @@ public class Version { private static final String MAJOR_VALUE = "2"; private static final String MINOR_VALUE = "2"; - private static final String DOT_VALUE = "0"; + private static final String DOT_VALUE = "1"; private static final String versionNumber = "v" + MAJOR_VALUE + "." + MINOR_VALUE + "." + DOT_VALUE; private static final String versionName = "NASA WorldWind Java"; diff --git a/src/gov/nasa/worldwind/data/package-info.java b/src/gov/nasa/worldwind/data/package-info.java index 700285cd03..dcf64cff4e 100644 --- a/src/gov/nasa/worldwind/data/package-info.java +++ b/src/gov/nasa/worldwind/data/package-info.java @@ -311,7 +311,7 @@ GDAL and PROJ4 have been incorporated for MacOSX (Snow Leopard, 64-bit), Windows

Deploying with Java Web Start

* Instructions for using the WorldWind GDAL libraries with a Java Web Start application are available at - * https://goworldwind.org/getting-started/. + * https://worldwind.arc.nasa.gov/java/get-started/. * * * diff --git a/src/gov/nasa/worldwind/formats/shapefile/Shapefile.java b/src/gov/nasa/worldwind/formats/shapefile/Shapefile.java index 3dca302b66..45bd27565b 100644 --- a/src/gov/nasa/worldwind/formats/shapefile/Shapefile.java +++ b/src/gov/nasa/worldwind/formats/shapefile/Shapefile.java @@ -25,7 +25,6 @@ * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. */ - package gov.nasa.worldwind.formats.shapefile; import com.jogamp.common.nio.Buffers; @@ -46,11 +45,14 @@ import java.util.logging.Level; /** - * Parses an ESRI Shapefile (.shp) and provides access to its contents. For details on the Shapefile format see the ESRI - * documentation at http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf. + * Parses an ESRI Shapefile (.shp) and provides access to its contents. For + * details on the Shapefile format see the ESRI documentation at + * http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf. *

- * The Shapefile provides a streaming interface for parsing a Shapefile's contents. The streaming interface enables - * applications to read Shapefiles that do not fit in memory. A typical usage pattern is as follows:


+ * The Shapefile provides a streaming interface for parsing a Shapefile's
+ * contents. The streaming interface enables applications to read Shapefiles
+ * that do not fit in memory. A typical usage pattern is as follows:
+ * 

  * Object source = "MyShapefile.shp";
  * Shapefile sf = new Shapefile(source);
  * try
@@ -67,49 +69,70 @@
  * }
  * 
*

- * The source Shapefile may be accompanied by an optional index file, attribute file, and projection file. Shapefile - * constructors that accept a generic source such as {@link #Shapefile(Object)} expect accompanying files to be in the - * same logical folder as the Shapefile, have the same filename as the Shapefile, and have suffixes ".shx", ".dbf", and - * ".prj" respectively. If any of these files do not exist, or cannot be read for any reason, the Shapefile opens - * without that information. Alternatively, the Shapefile can be constructed by providing a direct {@link - * java.io.InputStream} to any of the accompanying sources by using the InputStream based constructors, such as {@link + * The source Shapefile may be accompanied by an optional index file, attribute + * file, and projection file. Shapefile constructors that accept a generic + * source such as {@link #Shapefile(Object)} expect accompanying files to be in + * the same logical folder as the Shapefile, have the same filename as the + * Shapefile, and have suffixes ".shx", ".dbf", and ".prj" respectively. If any + * of these files do not exist, or cannot be read for any reason, the Shapefile + * opens without that information. Alternatively, the Shapefile can be + * constructed by providing a direct {@link + * java.io.InputStream} to any of the accompanying sources by using the + * InputStream based constructors, such as {@link * #Shapefile(java.io.InputStream, java.io.InputStream, java.io.InputStream, java.io.InputStream)}. *

Coordinate System

*

- * The Shapefile's coordinate system affects how the Shapefile's point coordinates are interpreted as follows:

    - *
  • Unspecified - coordinates are not changed.
  • Geographic - coordinates are validated during parsing. - * Coordinates outside the standard range of +90/-90 latitude and +180/-180 longitude cause the Shapefile to throw an - * exception during construction if the Shapefile's header contains an invalid coordinate, or in {@link - * #readNextRecord()} if any of the Shapefile's records contain an invalid coordinate.
  • Universal Transverse - * Mercator (UTM) - UTM coordinates are converted to geographic coordinates during parsing.
  • Unsupported - the - * Shapefile throws a {@link gov.nasa.worldwind.exception.WWRuntimeException} during construction.
+ * The Shapefile's coordinate system affects how the Shapefile's point + * coordinates are interpreted as follows:
    + *
  • Unspecified - coordinates are not changed.
  • Geographic - + * coordinates are validated during parsing. Coordinates outside the standard + * range of +90/-90 latitude and +180/-180 longitude cause the Shapefile to + * throw an exception during construction if the Shapefile's header contains an + * invalid coordinate, or in {@link + * #readNextRecord()} if any of the Shapefile's records contain an invalid + * coordinate.
  • Universal Transverse Mercator (UTM) - UTM coordinates + * are converted to geographic coordinates during parsing.
  • Unsupported + * - the Shapefile throws a + * {@link gov.nasa.worldwind.exception.WWRuntimeException} during + * construction.
*

- * The Shapefile's coordinate system can be specified in either an accompanying projection file, or by specifying the - * coordinate system parameters in an {@link gov.nasa.worldwind.avlist.AVList} during Shapefile's construction. The - * Shapefile gives priority to the AVList if an accompanying projection file is available and AVList projection - * parameters are specified. If an accompanying projection file is available, the Shapefile attempts to parse the - * projection file as an OGC coordinate system encoded in well-known text format. For details, see the OGC Coordinate - * Transform Service (CT) specification at http://www.opengeospatial.org/standards/ct. - * The Shapefile expects the AVList specifying its coordinate system parameters to contain the following properties: + * The Shapefile's coordinate system can be specified in either an accompanying + * projection file, or by specifying the coordinate system parameters in an + * {@link gov.nasa.worldwind.avlist.AVList} during Shapefile's construction. The + * Shapefile gives priority to the AVList if an accompanying projection file is + * available and AVList projection parameters are specified. If an accompanying + * projection file is available, the Shapefile attempts to parse the projection + * file as an OGC coordinate system encoded in well-known text format. For + * details, see the OGC Coordinate Transform Service (CT) specification at + * http://www.opengeospatial.org/standards/ct. + * The Shapefile expects the AVList specifying its coordinate system parameters + * to contain the following properties: *

  • {@link gov.nasa.worldwind.avlist.AVKey#COORDINATE_SYSTEM} - either {@link - * gov.nasa.worldwind.avlist.AVKey#COORDINATE_SYSTEM_GEOGRAPHIC} or {@link gov.nasa.worldwind.avlist.AVKey#COORDINATE_SYSTEM_PROJECTED}.
  • - *
  • {@link gov.nasa.worldwind.avlist.AVKey#PROJECTION_ZONE} - the UTM zone (if coordinate system projection is UTM); - * an integer in the range 1-60.
  • {@link gov.nasa.worldwind.avlist.AVKey#PROJECTION_HEMISPHERE} - the UTM - * hemisphere (if coordinate system is UTM); either {@link gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link + * gov.nasa.worldwind.avlist.AVKey#COORDINATE_SYSTEM_GEOGRAPHIC} or + * {@link gov.nasa.worldwind.avlist.AVKey#COORDINATE_SYSTEM_PROJECTED}.
  • + *
  • {@link gov.nasa.worldwind.avlist.AVKey#PROJECTION_ZONE} - the UTM zone + * (if coordinate system projection is UTM); an integer in the range 1-60.
  • + *
  • {@link gov.nasa.worldwind.avlist.AVKey#PROJECTION_HEMISPHERE} - the UTM + * hemisphere (if coordinate system is UTM); either + * {@link gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link * gov.nasa.worldwind.avlist.AVKey#SOUTH}.
*

- * Subclasses can override how the Shapefile reads and interprets its coordinate system. Override {@link - * #readCoordinateSystem()} and {@link #validateCoordinateSystem(gov.nasa.worldwind.avlist.AVList)} to change how the - * Shapefile parses an accompanying projection file and validates the coordinate system parameters. Override - * {@link #readBoundingRectangle(java.nio.ByteBuffer)} - * and {@link #readPoints(gov.nasa.worldwind.formats.shapefile.ShapefileRecord,java.nio.ByteBuffer)} to change how the - * Shapefile's point coordinates are interpreted according to its coordinate system. + * Subclasses can override how the Shapefile reads and interprets its coordinate + * system. Override {@link + * #readCoordinateSystem()} and + * {@link #validateCoordinateSystem(gov.nasa.worldwind.avlist.AVList)} to change + * how the Shapefile parses an accompanying projection file and validates the + * coordinate system parameters. Override + * {@link #readBoundingRectangle(java.nio.ByteBuffer)} and + * {@link #readPoints(gov.nasa.worldwind.formats.shapefile.ShapefileRecord,java.nio.ByteBuffer)} + * to change how the Shapefile's point coordinates are interpreted according to + * its coordinate system. * * @author Patrick Murris * @version $Id: Shapefile.java 3426 2015-09-30 23:19:16Z dcollins $ */ -public class Shapefile extends AVListImpl implements Closeable, Exportable -{ +public class Shapefile extends AVListImpl implements Closeable, Exportable { + protected static final int FILE_CODE = 0x0000270A; protected static final int HEADER_LENGTH = 100; @@ -118,22 +141,22 @@ public class Shapefile extends AVListImpl implements Closeable, Exportable protected static final String ATTRIBUTE_FILE_SUFFIX = ".dbf"; protected static final String PROJECTION_FILE_SUFFIX = ".prj"; - protected static final String[] SHAPE_CONTENT_TYPES = - { - "application/shp", - "application/octet-stream" - }; - protected static final String[] INDEX_CONTENT_TYPES = - { - "application/shx", - "application/octet-stream" - }; - protected static final String[] PROJECTION_CONTENT_TYPES = - { - "application/prj", - "application/octet-stream", - "text/plain" - }; + protected static final String[] SHAPE_CONTENT_TYPES + = { + "application/shp", + "application/octet-stream" + }; + protected static final String[] INDEX_CONTENT_TYPES + = { + "application/shx", + "application/octet-stream" + }; + protected static final String[] PROJECTION_CONTENT_TYPES + = { + "application/prj", + "application/octet-stream", + "text/plain" + }; public static final String SHAPE_NULL = "gov.nasa.worldwind.formats.shapefile.Shapefile.ShapeNull"; public static final String SHAPE_POINT = "gov.nasa.worldwind.formats.shapefile.Shapefile.ShapePoint"; @@ -154,21 +177,21 @@ public class Shapefile extends AVListImpl implements Closeable, Exportable public static final String SHAPE_MULTI_PATCH = "gov.nasa.worldwind.formats.shapefile.Shapefile.ShapeMultiPatch"; protected static List measureTypes = new ArrayList(Arrays.asList( - Shapefile.SHAPE_POINT_M, Shapefile.SHAPE_POINT_Z, - Shapefile.SHAPE_MULTI_POINT_M, Shapefile.SHAPE_MULTI_POINT_Z, - Shapefile.SHAPE_POLYLINE_M, Shapefile.SHAPE_POLYLINE_Z, - Shapefile.SHAPE_POLYGON_M, Shapefile.SHAPE_POLYGON_Z + Shapefile.SHAPE_POINT_M, Shapefile.SHAPE_POINT_Z, + Shapefile.SHAPE_MULTI_POINT_M, Shapefile.SHAPE_MULTI_POINT_Z, + Shapefile.SHAPE_POLYLINE_M, Shapefile.SHAPE_POLYLINE_Z, + Shapefile.SHAPE_POLYGON_M, Shapefile.SHAPE_POLYGON_Z )); protected static List zTypes = new ArrayList(Arrays.asList( - Shapefile.SHAPE_POINT_Z, - Shapefile.SHAPE_MULTI_POINT_Z, - Shapefile.SHAPE_POLYLINE_Z, - Shapefile.SHAPE_POLYGON_Z + Shapefile.SHAPE_POINT_Z, + Shapefile.SHAPE_MULTI_POINT_Z, + Shapefile.SHAPE_POLYLINE_Z, + Shapefile.SHAPE_POLYGON_Z )); - protected static class Header - { + protected static class Header { + public int fileCode = FILE_CODE; public int fileLength; public int version; @@ -188,9 +211,11 @@ protected static class Header protected DBaseFile attributeFile; protected boolean open; /** - * Indicates if the shapefile's point coordinates should be normalized. Defaults to false. This is used by Point - * records to determine if its points should be normalized. MultiPoint, Polyline, and Polygon records use their - * bounding rectangles to determine if they should be normalized, and therefore ignore this property. + * Indicates if the shapefile's point coordinates should be normalized. + * Defaults to false. This is used by Point records to determine if its + * points should be normalized. MultiPoint, Polyline, and Polygon records + * use their bounding rectangles to determine if they should be normalized, + * and therefore ignore this property. */ protected boolean normalizePoints; protected int numRecordsRead; @@ -200,121 +225,129 @@ protected static class Header protected MappedByteBuffer mappedShpBuffer; /** - * Opens an Shapefile from a general source. The source type may be one of the following:

  • {@link + * Opens an Shapefile from a general source. The source type may be one of + * the following:
    • {@link * java.io.InputStream}
    • {@link java.net.URL}
    • absolute {@link java.net.URI}
    • {@link - * File}
    • {@link String} containing a valid URL description or a file or resource name available on the - * classpath.
    + * File}
  • {@link String} containing a valid URL description or a + * file or resource name available on the classpath.
*

- * The source Shapefile may be accompanied by an optional index file, attribute file, and projection file. To be - * recognized by this Shapefile, accompanying files must be in the same logical folder as the Shapefile, have the - * same filename as the Shapefile, and have suffixes ".shx", ".dbf", and ".prj" respectively. If any of these files - * do not exist, or cannot be read for any reason, the Shapefile opens without that information. + * The source Shapefile may be accompanied by an optional index file, + * attribute file, and projection file. To be recognized by this Shapefile, + * accompanying files must be in the same logical folder as the Shapefile, + * have the same filename as the Shapefile, and have suffixes ".shx", + * ".dbf", and ".prj" respectively. If any of these files do not exist, or + * cannot be read for any reason, the Shapefile opens without that + * information. *

- * This throws an exception if the shapefile's coordinate system is unsupported. + * This throws an exception if the shapefile's coordinate system is + * unsupported. * * @param source the source of the shapefile. - * @param params parameter list describing metadata about the Shapefile, such as its map projection. + * @param params parameter list describing metadata about the Shapefile, + * such as its map projection. * - * @throws IllegalArgumentException if the source is null or an empty string. - * @throws WWRuntimeException if the shapefile cannot be opened for any reason, or if the shapefile's - * coordinate system is unsupported. + * @throws IllegalArgumentException if the source is null or an empty + * string. + * @throws WWRuntimeException if the shapefile cannot be opened for any + * reason, or if the shapefile's coordinate system is unsupported. */ - public Shapefile(Object source, AVList params) - { - if (source == null || WWUtil.isEmpty(source)) - { + public Shapefile(Object source, AVList params) { + if (source == null || WWUtil.isEmpty(source)) { String message = Logging.getMessage("nullValue.SourceIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - try - { + try { this.setValue(AVKey.DISPLAY_NAME, source.toString()); - if (source instanceof File) + if (source instanceof File) { this.initializeFromFile((File) source, params); - else if (source instanceof URL) + } else if (source instanceof URL) { this.initializeFromURL((URL) source, params); - else if (source instanceof InputStream) + } else if (source instanceof InputStream) { this.initializeFromStreams((InputStream) source, null, null, null, params); - else if (source instanceof String) + } else if (source instanceof String) { this.initializeFromPath((String) source, params); - else - { + } else { String message = Logging.getMessage("generic.UnrecognizedSourceType", source); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - } - catch (Exception e) - { + } catch (Exception e) { String message = Logging.getMessage("SHP.ExceptionAttemptingToReadShapefile", - this.getValue(AVKey.DISPLAY_NAME)); + this.getValue(AVKey.DISPLAY_NAME)); Logging.logger().log(Level.SEVERE, message, e); throw new WWRuntimeException(message, e); } } /** - * Opens an Shapefile from a general source. The source type may be one of the following:

  • {@link - * java.io.InputStream}
  • {@link java.net.URL}
  • {@link File}
  • {@link String} containing a - * valid URL description or a file or resource name available on the classpath.
+ * Opens an Shapefile from a general source. The source type may be one of + * the following:
  • {@link + * java.io.InputStream}
  • {@link java.net.URL}
  • + *
  • {@link File}
  • {@link String} containing a valid URL + * description or a file or resource name available on the classpath.
  • + *
*

- * The source Shapefile may be accompanied by an optional index file, attribute file, and projection file. To be - * recognized by this Shapefile, accompanying files must be in the same logical folder as the Shapefile, have the - * same filename as the Shapefile, and have suffixes ".shx", ".dbf", and ".prj" respectively. If any of these files - * do not exist, or cannot be read for any reason, the Shapefile opens without that information. + * The source Shapefile may be accompanied by an optional index file, + * attribute file, and projection file. To be recognized by this Shapefile, + * accompanying files must be in the same logical folder as the Shapefile, + * have the same filename as the Shapefile, and have suffixes ".shx", + * ".dbf", and ".prj" respectively. If any of these files do not exist, or + * cannot be read for any reason, the Shapefile opens without that + * information. *

- * This throws an exception if the shapefile's coordinate system is unsupported, or if the shapefile's coordinate - * system is unsupported. + * This throws an exception if the shapefile's coordinate system is + * unsupported, or if the shapefile's coordinate system is unsupported. * * @param source the source of the shapefile. * - * @throws IllegalArgumentException if the source is null or an empty string. - * @throws WWRuntimeException if the shapefile cannot be opened for any reason. + * @throws IllegalArgumentException if the source is null or an empty + * string. + * @throws WWRuntimeException if the shapefile cannot be opened for any + * reason. */ - public Shapefile(Object source) - { + public Shapefile(Object source) { this(source, null); } /** - * Opens a Shapefile from an InputStream, and InputStreams to its optional resources. + * Opens a Shapefile from an InputStream, and InputStreams to its optional + * resources. *

- * The source Shapefile may be accompanied optional streams to an index resource stream, an attribute resource - * stream, and a projection resource stream. If any of these streams are null or cannot be read for any reason, the - * Shapefile opens without that information. + * The source Shapefile may be accompanied optional streams to an index + * resource stream, an attribute resource stream, and a projection resource + * stream. If any of these streams are null or cannot be read for any + * reason, the Shapefile opens without that information. *

- * This throws an exception if the shapefile's coordinate system is unsupported. + * This throws an exception if the shapefile's coordinate system is + * unsupported. * * @param shpStream the shapefile geometry file stream. * @param shxStream the index file stream, can be null. * @param dbfStream the attribute file stream, can be null. * @param prjStream the projection file stream, can be null. - * @param params parameter list describing metadata about the Shapefile, such as its map projection. + * @param params parameter list describing metadata about the Shapefile, + * such as its map projection. * - * @throws IllegalArgumentException if the shapefile geometry stream shpStream is null. - * @throws WWRuntimeException if the shapefile cannot be opened for any reason, or if the shapefile's - * coordinate system is unsupported. + * @throws IllegalArgumentException if the shapefile geometry stream + * shpStream is null. + * @throws WWRuntimeException if the shapefile cannot be opened for any + * reason, or if the shapefile's coordinate system is unsupported. */ public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfStream, InputStream prjStream, - AVList params) - { - if (shpStream == null) - { + AVList params) { + if (shpStream == null) { String message = Logging.getMessage("nullValue.InputStreamIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - try - { + try { this.setValue(AVKey.DISPLAY_NAME, shpStream.toString()); this.initializeFromStreams(shpStream, shxStream, dbfStream, prjStream, params); - } - catch (Exception e) - { + } catch (Exception e) { String message = Logging.getMessage("SHP.ExceptionAttemptingToReadShapefile", shpStream); Logging.logger().log(Level.SEVERE, message, e); throw new WWRuntimeException(message, e); @@ -322,154 +355,173 @@ public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfSt } /** - * Opens a Shapefile from an InputStream, and InputStreams to its optional resources. + * Opens a Shapefile from an InputStream, and InputStreams to its optional + * resources. *

- * The source Shapefile may be accompanied optional streams to an index resource stream, an attribute resource - * stream, and a projection resource stream. If any of these streams are null or cannot be read for any reason, the - * Shapefile opens without that information. + * The source Shapefile may be accompanied optional streams to an index + * resource stream, an attribute resource stream, and a projection resource + * stream. If any of these streams are null or cannot be read for any + * reason, the Shapefile opens without that information. *

- * This throws an exception if the shapefile's coordinate system is unsupported. + * This throws an exception if the shapefile's coordinate system is + * unsupported. * * @param shpStream the shapefile geometry file stream. * @param shxStream the index file stream, can be null. * @param dbfStream the attribute file stream, can be null. * @param prjStream the projection file stream, can be null. * - * @throws IllegalArgumentException if the shapefile geometry stream shpStream is null. - * @throws WWRuntimeException if the shapefile cannot be opened for any reason, or if the shapefile's - * coordinate system is unsupported. + * @throws IllegalArgumentException if the shapefile geometry stream + * shpStream is null. + * @throws WWRuntimeException if the shapefile cannot be opened for any + * reason, or if the shapefile's coordinate system is unsupported. */ - public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfStream, InputStream prjStream) - { + public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfStream, InputStream prjStream) { this(shpStream, shxStream, dbfStream, prjStream, null); } /** - * Opens a Shapefile from an InputStream, and InputStreams to its optional resources. + * Opens a Shapefile from an InputStream, and InputStreams to its optional + * resources. *

- * The source Shapefile may be accompanied optional streams to an index resource stream, and an attribute resource - * stream. If any of these streams are null or cannot be read for any reason, the Shapefile opens without that - * information. + * The source Shapefile may be accompanied optional streams to an index + * resource stream, and an attribute resource stream. If any of these + * streams are null or cannot be read for any reason, the Shapefile opens + * without that information. *

- * This throws an exception if the shapefile's coordinate system is unsupported. + * This throws an exception if the shapefile's coordinate system is + * unsupported. * * @param shpStream the shapefile geometry file stream. * @param shxStream the index file stream, can be null. * @param dbfStream the attribute file stream, can be null. - * @param params parameter list describing metadata about the Shapefile, such as its map projection. + * @param params parameter list describing metadata about the Shapefile, + * such as its map projection. * - * @throws IllegalArgumentException if the shapefile geometry stream shpStream is null. - * @throws WWRuntimeException if the shapefile cannot be opened for any reason, or if the shapefile's - * coordinate system is unsupported. + * @throws IllegalArgumentException if the shapefile geometry stream + * shpStream is null. + * @throws WWRuntimeException if the shapefile cannot be opened for any + * reason, or if the shapefile's coordinate system is unsupported. */ - public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfStream, AVList params) - { + public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfStream, AVList params) { this(shpStream, shxStream, dbfStream, null, params); } /** - * Opens a Shapefile from an InputStream, and InputStreams to its optional resources. + * Opens a Shapefile from an InputStream, and InputStreams to its optional + * resources. *

- * The source Shapefile may be accompanied optional streams to an index resource stream, and an attribute resource - * stream. If any of these streams are null or cannot be read for any reason, the Shapefile opens without that - * information. + * The source Shapefile may be accompanied optional streams to an index + * resource stream, and an attribute resource stream. If any of these + * streams are null or cannot be read for any reason, the Shapefile opens + * without that information. * * @param shpStream the shapefile geometry file stream. * @param shxStream the index file stream, can be null. * @param dbfStream the attribute file stream, can be null. * - * @throws IllegalArgumentException if the shapefile geometry stream shpStream is null. - * @throws WWRuntimeException if the shapefile cannot be opened for any reason. + * @throws IllegalArgumentException if the shapefile geometry stream + * shpStream is null. + * @throws WWRuntimeException if the shapefile cannot be opened for any + * reason. */ - public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfStream) - { + public Shapefile(InputStream shpStream, InputStream shxStream, InputStream dbfStream) { this(shpStream, shxStream, dbfStream, null, null); } /** - * Returns the shapefile's version field, or -1 if the Shapefile failed to open. + * Returns the shapefile's version field, or -1 if the Shapefile failed to + * open. * - * @return the shapefile's version field, or -1 to denote the Shapefile failed to open. + * @return the shapefile's version field, or -1 to denote the Shapefile + * failed to open. */ - public int getVersion() - { + public int getVersion() { return this.header != null ? this.header.version : -1; } /** - * Returns the raw shapefile's length, or -1 if the Shapefile failed to open. + * Returns the raw shapefile's length, or -1 if the Shapefile failed to + * open. * - * @return the raw shapefile's length in bytes, or -1 to denote the Shapefile failed to open. + * @return the raw shapefile's length in bytes, or -1 to denote the + * Shapefile failed to open. */ - public int getLength() - { + public int getLength() { return this.header != null ? this.header.fileLength : -1; } /** - * Returns the shapefile's shape type: null if the Shapefile failed to open, otherwise one of the following symbolic - * constants:

  • {@link #SHAPE_NULL}
  • {@link #SHAPE_POINT}
  • {@link #SHAPE_MULTI_POINT}
  • - *
  • {@link #SHAPE_POLYLINE}
  • {@link #SHAPE_POLYGON}
  • {@link #SHAPE_POINT_M}
  • {@link - * #SHAPE_MULTI_POINT_M}
  • {@link #SHAPE_POLYLINE_M}
  • {@link #SHAPE_POLYGON_M}
  • {@link - * #SHAPE_POINT_Z}
  • {@link #SHAPE_MULTI_POINT_Z}
  • {@link #SHAPE_POLYLINE_Z}
  • {@link + * Returns the shapefile's shape type: null if the Shapefile failed to open, + * otherwise one of the following symbolic constants:
      + *
    • {@link #SHAPE_NULL}
    • {@link #SHAPE_POINT}
    • + *
    • {@link #SHAPE_MULTI_POINT}
    • + *
    • {@link #SHAPE_POLYLINE}
    • {@link #SHAPE_POLYGON}
    • + *
    • {@link #SHAPE_POINT_M}
    • {@link + * #SHAPE_MULTI_POINT_M}
    • {@link #SHAPE_POLYLINE_M}
    • + *
    • {@link #SHAPE_POLYGON_M}
    • {@link + * #SHAPE_POINT_Z}
    • {@link #SHAPE_MULTI_POINT_Z}
    • + *
    • {@link #SHAPE_POLYLINE_Z}
    • {@link * #SHAPE_POLYGON_Z}
    • {@link #SHAPE_MULTI_PATCH}
    * - * @return the shapefile's shape type: null if the Shapefile failed to open, othersise a symbolic constants denoting - * the type. + * @return the shapefile's shape type: null if the Shapefile failed to open, + * othersise a symbolic constants denoting the type. */ - public String getShapeType() - { + public String getShapeType() { return this.header != null ? this.header.shapeType : null; } /** - * Returns a four-element array containing the shapefile's bounding rectangle, or null if the Shapefile failed to - * open. The returned array is ordered as follows: minimum Y, maximum Y, minimum X, and maximum X. If the - * Shapefile's coordinate system is geographic, the elements can be interpreted as angular degrees in the order - * minimum latitude, maximum latitude, minimum longitude, and maximum longitude. - * - * @return the shapefile's bounding rectangle, or null to denote the Shapefile failed to open. + * Returns a four-element array containing the shapefile's bounding + * rectangle, or null if the Shapefile failed to open. The returned array is + * ordered as follows: minimum Y, maximum Y, minimum X, and maximum X. If + * the Shapefile's coordinate system is geographic, the elements can be + * interpreted as angular degrees in the order minimum latitude, maximum + * latitude, minimum longitude, and maximum longitude. + * + * @return the shapefile's bounding rectangle, or null to denote the + * Shapefile failed to open. */ - public double[] getBoundingRectangle() - { + public double[] getBoundingRectangle() { return this.header != null ? this.header.boundingRectangle : null; } /** - * Returns the number of records in the shapefile, or -1 if the number if records is unknown. + * Returns the number of records in the shapefile, or -1 if the number if + * records is unknown. * - * @return the number of records in the shapefile, or -1 to denote an unknown number of records. + * @return the number of records in the shapefile, or -1 to denote an + * unknown number of records. */ - public int getNumberOfRecords() - { + public int getNumberOfRecords() { return this.index != null ? this.index.length / 2 : -1; } /** - * Get the underlying {@link CompoundVecBuffer} describing the shapefile's points. + * Get the underlying {@link CompoundVecBuffer} describing the shapefile's + * points. * * @return the underlying {@link CompoundVecBuffer}. */ - public CompoundVecBuffer getPointBuffer() - { + public CompoundVecBuffer getPointBuffer() { return this.pointBuffer; } /** - * Returns a set of the unique attribute names associated with this shapefile's records, or null if this shapefile - * has no associated attributes. + * Returns a set of the unique attribute names associated with this + * shapefile's records, or null if this shapefile has no associated + * attributes. * - * @return a set containing the unique attribute names of this shapefile's records, or null if there are no - * attributes. + * @return a set containing the unique attribute names of this shapefile's + * records, or null if there are no attributes. */ - public Set getAttributeNames() - { - if (this.attributeFile == null) + public Set getAttributeNames() { + if (this.attributeFile == null) { return null; + } HashSet set = new HashSet(); - for (DBaseField field : this.attributeFile.getFields()) - { + for (DBaseField field : this.attributeFile.getFields()) { set.add(field.getName()); } @@ -477,43 +529,51 @@ public Set getAttributeNames() } /** - * Returns true if the Shapefile has a more records, and false if all records have been - * read. + * Returns true if the Shapefile has a more records, and + * false if all records have been read. * - * @return true if the Shapefile has a more records; false otherwise. + * @return true if the Shapefile has a more records; + * false otherwise. */ - public boolean hasNext() - { - if (!this.open || this.header == null) + public boolean hasNext() { + if (!this.open || this.header == null) { return false; + } int contentLength = this.header.fileLength - HEADER_LENGTH; return this.numBytesRead < contentLength; } /** - * Reads the Shapefile's next record and returns the result as a new {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. - * The record's type depends on the Shapefile's type, and is one of the following:
    • {@link + * Reads the Shapefile's next record and returns the result as a new + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. The + * record's type depends on the Shapefile's type, and is one of the + * following:
      • {@link * gov.nasa.worldwind.formats.shapefile.ShapefileRecordPoint} if type is {@link #SHAPE_POINT}, {@link - * #SHAPE_POINT_M} or {@link #SHAPE_POINT_Z}.
      • {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecordMultiPoint} - * if type is {@link #SHAPE_MULTI_POINT}, {@link #SHAPE_MULTI_POINT_M} or {@link #SHAPE_MULTI_POINT_Z}.
      • - *
      • {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecordPolyline} if type is {@link #SHAPE_POLYLINE}, - * {@link #SHAPE_POLYLINE_M} or {@link #SHAPE_POLYLINE_Z}.
      • {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecordPolygon} - * if type is {@link #SHAPE_POLYGON}, {@link #SHAPE_POLYGON_M} or {@link #SHAPE_POLYGON_Z}.
      + * #SHAPE_POINT_M} or {@link #SHAPE_POINT_Z}.
    • + *
    • {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecordMultiPoint} + * if type is {@link #SHAPE_MULTI_POINT}, {@link #SHAPE_MULTI_POINT_M} or + * {@link #SHAPE_MULTI_POINT_Z}.
    • + *
    • {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecordPolyline} + * if type is {@link #SHAPE_POLYLINE}, + * {@link #SHAPE_POLYLINE_M} or {@link #SHAPE_POLYLINE_Z}.
    • + *
    • {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecordPolygon} + * if type is {@link #SHAPE_POLYGON}, {@link #SHAPE_POLYGON_M} or + * {@link #SHAPE_POLYGON_Z}.
    *

    - * This throws an exception if the JVM cannot allocate enough memory to hold the buffer used to store the record's - * point coordinates. + * This throws an exception if the JVM cannot allocate enough memory to hold + * the buffer used to store the record's point coordinates. * * @return the Shapefile's next record. * - * @throws IllegalStateException if the Shapefile is closed or if the Shapefile has no more records. - * @throws WWRuntimeException if an exception occurs while reading the record. + * @throws IllegalStateException if the Shapefile is closed or if the + * Shapefile has no more records. + * @throws WWRuntimeException if an exception occurs while reading the + * record. * @see #getShapeType() */ - public ShapefileRecord nextRecord() - { - if (!this.open) - { + public ShapefileRecord nextRecord() { + if (!this.open) { String message = Logging.getMessage("SHP.ShapefileClosed", this.getStringValue(AVKey.DISPLAY_NAME)); Logging.logger().severe(message); throw new IllegalStateException(message); @@ -527,22 +587,18 @@ public ShapefileRecord nextRecord() } int contentLength = this.header.fileLength - HEADER_LENGTH; - if (contentLength <= 0 || this.numBytesRead >= contentLength) - { + if (contentLength <= 0 || this.numBytesRead >= contentLength) { String message = Logging.getMessage("SHP.NoRecords", this.getStringValue(AVKey.DISPLAY_NAME)); Logging.logger().severe(message); throw new IllegalStateException(message); } ShapefileRecord record; - try - { + try { record = this.readNextRecord(); - } - catch (Exception e) - { + } catch (Exception e) { String message = Logging.getMessage("SHP.ExceptionAttemptingToReadShapefileRecord", - this.getStringValue(AVKey.DISPLAY_NAME)); + this.getStringValue(AVKey.DISPLAY_NAME)); Logging.logger().log(Level.SEVERE, message, e); throw new WWRuntimeException(message, e); } @@ -552,37 +608,35 @@ record = this.readNextRecord(); } /** - * Closes the Shapefile, freeing any resources allocated during reading except the buffer containing the Shapefile's - * points. This closes any {@link java.io.InputStream} passed to the Shapefile during construction. Subsequent calls - * to {@link #nextRecord()} cause an IllegalStateException. + * Closes the Shapefile, freeing any resources allocated during reading + * except the buffer containing the Shapefile's points. This closes any + * {@link java.io.InputStream} passed to the Shapefile during construction. + * Subsequent calls to {@link #nextRecord()} cause an IllegalStateException. *

    - * After closing, the Shapefile's header information and point coordinates are still available. The following - * methods are safe to call:

    • {@link #getVersion()}
    • {@link #getLength()}
    • {@link - * #getShapeType()}
    • {@link #getBoundingRectangle()}
    • {@link #getNumberOfRecords()}
    • {@link + * After closing, the Shapefile's header information and point coordinates + * are still available. The following methods are safe to call:
        + *
      • {@link #getVersion()}
      • {@link #getLength()}
      • {@link + * #getShapeType()}
      • {@link #getBoundingRectangle()}
      • + *
      • {@link #getNumberOfRecords()}
      • {@link * #getPointBuffer()}
      */ - public void close() - { - if (this.shpChannel != null) - { + public void close() { + if (this.shpChannel != null) { WWIO.closeStream(this.shpChannel, null); this.shpChannel = null; } - if (this.shxChannel != null) - { + if (this.shxChannel != null) { WWIO.closeStream(this.shxChannel, null); this.shxChannel = null; } - if (this.prjChannel != null) - { + if (this.prjChannel != null) { WWIO.closeStream(this.prjChannel, null); this.prjChannel = null; } - if (this.attributeFile != null) - { + if (this.attributeFile != null) { this.attributeFile.close(); this.attributeFile = null; } @@ -596,32 +650,29 @@ public void close() /** * Returns whether the shapefile's point coordinates should be normalized. * - * @return true if the shapefile's points should be normalized; false otherwise. + * @return true if the shapefile's points should be normalized; + * false otherwise. */ - protected boolean isNormalizePoints() - { + protected boolean isNormalizePoints() { return this.normalizePoints; } /** - * Specifies if the shapefile's point coordinates should be normalized. Defaults to false. + * Specifies if the shapefile's point coordinates should be normalized. + * Defaults to false. * - * @param normalizePoints true if the shapefile's points should be normalized; false - * otherwise. + * @param normalizePoints true if the shapefile's points should + * be normalized; false otherwise. */ - protected void setNormalizePoints(boolean normalizePoints) - { + protected void setNormalizePoints(boolean normalizePoints) { this.normalizePoints = normalizePoints; } //**************************************************************// //******************** Initialization ************************// //**************************************************************// - - protected void initializeFromFile(File file, AVList params) throws IOException - { - if (!file.exists()) - { + protected void initializeFromFile(File file, AVList params) throws IOException { + if (!file.exists()) { String message = Logging.getMessage("generic.FileNotFound", file.getPath()); Logging.logger().severe(message); throw new FileNotFoundException(message); @@ -632,37 +683,36 @@ protected void initializeFromFile(File file, AVList params) throws IOException // file. Although we never change the file's bytes on disk, the file must be accessible for reading and writing // to use copy-on-write mode. Therefore files locked for writing and files stored on a read-only device // (e.g. CD, DVD) cannot be memory mapped. - if (file.canRead() && file.canWrite()) - { - try - { + if (file.canRead() && file.canWrite()) { + try { // Memory map the Shapefile in copy-on-write mode. this.mappedShpBuffer = WWIO.mapFile(file, FileChannel.MapMode.PRIVATE); Logging.logger().finer(Logging.getMessage("SHP.MemoryMappingEnabled", file.getPath())); - } - catch (IOException e) - { + } catch (IOException e) { Logging.logger().log(Level.WARNING, - Logging.getMessage("SHP.ExceptionAttemptingToMemoryMap", file.getPath()), e); + Logging.getMessage("SHP.ExceptionAttemptingToMemoryMap", file.getPath()), e); } } // If attempting to memory map the Shapefile failed, fall back on opening the file as a generic stream. Throw an // IOException if the file cannot be opened via stream. - if (this.mappedShpBuffer == null) + if (this.mappedShpBuffer == null) { this.shpChannel = Channels.newChannel(new BufferedInputStream(new FileInputStream(file))); + } // Attempt to open the optional index and projection files associated with the Shapefile. Ignore exceptions // thrown while attempting to open these optional resource streams. We wrap each source InputStream in a // BufferedInputStream because this increases read performance, even when the stream is wrapped in an NIO // Channel. InputStream shxStream = this.getFileStream(WWIO.replaceSuffix(file.getPath(), INDEX_FILE_SUFFIX)); - if (shxStream != null) + if (shxStream != null) { this.shxChannel = Channels.newChannel(WWIO.getBufferedInputStream(shxStream)); + } InputStream prjStream = this.getFileStream(WWIO.replaceSuffix(file.getPath(), PROJECTION_FILE_SUFFIX)); - if (prjStream != null) + if (prjStream != null) { this.prjChannel = Channels.newChannel(WWIO.getBufferedInputStream(prjStream)); + } // Initialize the Shapefile before opening its associated attributes file. This avoids opening the attributes // file if an exception is thrown while opening the Shapefile. @@ -671,28 +721,22 @@ protected void initializeFromFile(File file, AVList params) throws IOException // Open the shapefile attribute source as a DBaseFile. We let the DBaseFile determine how to handle source File. File dbfFile = new File(WWIO.replaceSuffix(file.getPath(), ATTRIBUTE_FILE_SUFFIX)); - if (dbfFile.exists()) - { - try - { + if (dbfFile.exists()) { + try { this.attributeFile = new DBaseFile(dbfFile); - } - catch (Exception e) - { + } catch (Exception e) { // Exception already logged by DBaseFile constructor. } } } - protected void initializeFromURL(URL url, AVList params) throws IOException - { + protected void initializeFromURL(URL url, AVList params) throws IOException { // Opening the Shapefile URL as a URL connection. Throw an IOException if the URL connection cannot be opened, // or if it's an invalid Shapefile connection. URLConnection connection = url.openConnection(); String message = this.validateURLConnection(connection, SHAPE_CONTENT_TYPES); - if (message != null) - { + if (message != null) { throw new IOException(message); } @@ -703,30 +747,28 @@ protected void initializeFromURL(URL url, AVList params) throws IOException // invalid. We wrap each source InputStream in a BufferedInputStream because this increases read performance, // even when the stream is wrapped in an NIO Channel. URLConnection shxConnection = this.getURLConnection(WWIO.replaceSuffix(url.toString(), INDEX_FILE_SUFFIX)); - if (shxConnection != null) - { + if (shxConnection != null) { message = this.validateURLConnection(shxConnection, INDEX_CONTENT_TYPES); - if (message != null) + if (message != null) { Logging.logger().warning(message); - else - { + } else { InputStream shxStream = this.getURLStream(shxConnection); - if (shxStream != null) + if (shxStream != null) { this.shxChannel = Channels.newChannel(WWIO.getBufferedInputStream(shxStream)); + } } } URLConnection prjConnection = this.getURLConnection(WWIO.replaceSuffix(url.toString(), PROJECTION_FILE_SUFFIX)); - if (prjConnection != null) - { + if (prjConnection != null) { message = this.validateURLConnection(prjConnection, PROJECTION_CONTENT_TYPES); - if (message != null) + if (message != null) { Logging.logger().warning(message); - else - { + } else { InputStream prjStream = this.getURLStream(prjConnection); - if (prjStream != null) + if (prjStream != null) { this.prjChannel = Channels.newChannel(WWIO.getBufferedInputStream(prjStream)); + } } } @@ -737,34 +779,32 @@ protected void initializeFromURL(URL url, AVList params) throws IOException // Open the shapefile attribute source as a DBaseFile. We let the DBaseFile determine how to handle source URL. URL dbfURL = WWIO.makeURL(WWIO.replaceSuffix(url.toString(), ATTRIBUTE_FILE_SUFFIX)); - if (dbfURL != null) - { - try - { + if (dbfURL != null) { + try { this.attributeFile = new DBaseFile(dbfURL); - } - catch (Exception e) - { + } catch (Exception e) { // Exception already logged by DBaseFile constructor. } } } protected void initializeFromStreams(InputStream shpStream, InputStream shxStream, InputStream dbfStream, - InputStream prjStream, AVList params) throws IOException - { + InputStream prjStream, AVList params) throws IOException { // Create Channels for the collection of resources used by the Shapefile reader. We wrap each source InputStream // in a BufferedInputStream because this increases read performance, even when the stream is wrapped in an NIO // Channel. - if (shpStream != null) + if (shpStream != null) { this.shpChannel = Channels.newChannel(WWIO.getBufferedInputStream(shpStream)); + } - if (shxStream != null) + if (shxStream != null) { this.shxChannel = Channels.newChannel(WWIO.getBufferedInputStream(shxStream)); + } - if (prjStream != null) + if (prjStream != null) { this.prjChannel = Channels.newChannel(WWIO.getBufferedInputStream(prjStream)); + } // Initialize the Shapefile before opening its associated attributes file. This avoids opening the attributes // file if an exception is thrown while opening the Shapefile. @@ -772,31 +812,24 @@ protected void initializeFromStreams(InputStream shpStream, InputStream shxStrea // Open the shapefile attribute source as a DBaseFile. We let the DBaseFile determine how to handle its source // InputStream. - if (dbfStream != null) - { - try - { + if (dbfStream != null) { + try { this.attributeFile = new DBaseFile(dbfStream); - } - catch (Exception e) - { + } catch (Exception e) { // Exception already logged by DBaseFile constructor. } } } - protected void initializeFromPath(String path, AVList params) throws IOException - { + protected void initializeFromPath(String path, AVList params) throws IOException { File file = new File(path); - if (file.exists()) - { + if (file.exists()) { this.initializeFromFile(file, params); return; } URL url = WWIO.makeURL(path); - if (url != null) - { + if (url != null) { this.initializeFromURL(url, params); return; } @@ -807,34 +840,32 @@ protected void initializeFromPath(String path, AVList params) throws IOException } /** - * Prepares the Shapefile for reading. This reads the Shapefile's accompanying index and projection (if they're - * available), validates the Shapefile's coordinate system, and reads the Shapefile's header. + * Prepares the Shapefile for reading. This reads the Shapefile's + * accompanying index and projection (if they're available), validates the + * Shapefile's coordinate system, and reads the Shapefile's header. * - * @param params arameter list describing metadata about the Shapefile, such as its map projection, or null to - * specify no additional parameters. + * @param params arameter list describing metadata about the Shapefile, such + * as its map projection, or null to specify no additional parameters. * - * @throws IOException if an error occurs while reading the Shapefile's header. + * @throws IOException if an error occurs while reading the Shapefile's + * header. */ - protected void initialize(AVList params) throws IOException - { + protected void initialize(AVList params) throws IOException { // Attempt to read this Shapefile's projection resource, and set any projection parameters parsed from that // resource. If reading the projection resource fails, log the exception and continue. - try - { + try { AVList csParams = this.readCoordinateSystem(); - if (csParams != null) + if (csParams != null) { this.setValues(csParams); - } - catch (IOException e) - { + } + } catch (IOException e) { Logging.logger().log(Level.WARNING, - Logging.getMessage("SHP.ExceptionAttemptingToReadProjection", this.getStringValue(AVKey.DISPLAY_NAME)), e); + Logging.getMessage("SHP.ExceptionAttemptingToReadProjection", this.getStringValue(AVKey.DISPLAY_NAME)), e); } // Set the Shapefile's caller specified parameters. We do this after reading the projection parameters to give // the caller's parameters priority over the projection parameters. - if (params != null) - { + if (params != null) { this.setValues(params); } @@ -843,8 +874,7 @@ protected void initialize(AVList params) throws IOException // about what the coordinates represent. Throw a WWRuntimeException if the projection is either invalid or // unsupported. Subsequent attempts to query the Shapefile's header data or read its records cause an exception. String message = this.validateCoordinateSystem(this); - if (message != null) - { + if (message != null) { throw new WWRuntimeException(message); } @@ -852,14 +882,11 @@ protected void initialize(AVList params) throws IOException // continue. We read the index after reading any projection information and assigning the caller specified // parameters. This ensures that any coordinates in the header are converted according to the Shapefile's // coordinate system. - try - { + try { this.index = this.readIndex(); - } - catch (IOException e) - { + } catch (IOException e) { Logging.logger().log(Level.WARNING, - Logging.getMessage("SHP.ExceptionAttemptingToReadIndex", this.getStringValue(AVKey.DISPLAY_NAME)), e); + Logging.getMessage("SHP.ExceptionAttemptingToReadIndex", this.getStringValue(AVKey.DISPLAY_NAME)), e); } // Read this Shapefile's header and flag the Shapefile as open. We read the header after reading any projection @@ -872,67 +899,51 @@ protected void initialize(AVList params) throws IOException this.setNormalizePoints(this.header.normalizePoints); } - protected InputStream getFileStream(String path) - { - try - { + protected InputStream getFileStream(String path) { + try { return new FileInputStream(path); - } - catch (Exception e) - { + } catch (Exception e) { return null; } } - protected URLConnection getURLConnection(String urlString) - { - try - { + protected URLConnection getURLConnection(String urlString) { + try { URL url = new URL(urlString); return url.openConnection(); - } - catch (Exception e) - { + } catch (Exception e) { return null; } } - protected InputStream getURLStream(URLConnection connection) - { - try - { + protected InputStream getURLStream(URLConnection connection) { + try { return connection.getInputStream(); - } - catch (Exception e) - { + } catch (Exception e) { return null; } } - protected String validateURLConnection(URLConnection connection, String[] acceptedContentTypes) - { - try - { - if (connection instanceof HttpURLConnection && - ((HttpURLConnection) connection).getResponseCode() != HttpURLConnection.HTTP_OK) - { + protected String validateURLConnection(URLConnection connection, String[] acceptedContentTypes) { + try { + if (connection instanceof HttpURLConnection + && ((HttpURLConnection) connection).getResponseCode() != HttpURLConnection.HTTP_OK) { return Logging.getMessage("HTTP.ResponseCode", ((HttpURLConnection) connection).getResponseCode(), - connection.getURL()); + connection.getURL()); } - } - catch (Exception e) - { + } catch (Exception e) { return Logging.getMessage("URLRetriever.ErrorOpeningConnection", connection.getURL()); } String contentType = connection.getContentType(); - if (WWUtil.isEmpty(contentType)) + if (WWUtil.isEmpty(contentType)) { return null; + } - for (String type : acceptedContentTypes) - { - if (contentType.trim().toLowerCase().startsWith(type)) + for (String type : acceptedContentTypes) { + if (contentType.trim().toLowerCase().startsWith(type)) { return null; + } } // Return an exception if the content type does not match the expected type. @@ -942,29 +953,24 @@ protected String validateURLConnection(URLConnection connection, String[] accept //**************************************************************// //******************** Header ********************************// //**************************************************************// - /** - * Reads the {@link Header} from this Shapefile. This file is assumed to have a header. + * Reads the {@link Header} from this Shapefile. This file is assumed to + * have a header. * * @return a {@link Header} instance. * * @throws IOException if the header cannot be read for any reason. */ - protected Header readHeader() throws IOException - { + protected Header readHeader() throws IOException { ByteBuffer buffer; - if (this.mappedShpBuffer != null) - { + if (this.mappedShpBuffer != null) { buffer = this.mappedShpBuffer; - } - else - { + } else { buffer = ByteBuffer.allocate(HEADER_LENGTH); WWIO.readChannelToBuffer(this.shpChannel, buffer); } - if (buffer.remaining() < HEADER_LENGTH) - { + if (buffer.remaining() < HEADER_LENGTH) { // Let the caller catch and log the message. throw new WWRuntimeException(Logging.getMessage("generic.InvalidFileLength", buffer.remaining())); } @@ -973,10 +979,12 @@ protected Header readHeader() throws IOException } /** - * Reads a {@link Header} instance from the given {@link java.nio.ByteBuffer}; + * Reads a {@link Header} instance from the given + * {@link java.nio.ByteBuffer}; *

      - * The buffer current position is assumed to be set at the start of the header and will be set to the end of the - * header after this method has completed. + * The buffer current position is assumed to be set at the start of the + * header and will be set to the end of the header after this method has + * completed. * * @param buffer the Header @link java.nio.ByteBuffer} to read from. * @@ -984,20 +992,17 @@ protected Header readHeader() throws IOException * * @throws IOException if the header cannot be read for any reason. */ - protected Header readHeaderFromBuffer(ByteBuffer buffer) throws IOException - { + protected Header readHeaderFromBuffer(ByteBuffer buffer) throws IOException { Header header = null; // Save the buffer's current position. int pos = buffer.position(); - try - { + try { // Read file code - first 4 bytes, big endian buffer.order(ByteOrder.BIG_ENDIAN); int fileCode = buffer.getInt(); - if (fileCode != FILE_CODE) - { + if (fileCode != FILE_CODE) { // Let the caller catch and log the message. throw new WWUnrecognizedException(Logging.getMessage("SHP.UnrecognizedShapefile", fileCode)); } @@ -1018,8 +1023,7 @@ protected Header readHeaderFromBuffer(ByteBuffer buffer) throws IOException // Check whether the shape type is supported String shapeType = getShapeType(type); - if (shapeType == null) - { + if (shapeType == null) { // Let the caller catch and log the message. throw new WWRuntimeException(Logging.getMessage("SHP.UnsupportedShapeType", type)); } @@ -1031,9 +1035,7 @@ protected Header readHeaderFromBuffer(ByteBuffer buffer) throws IOException header.shapeType = shapeType; header.boundingRectangle = rect.coords; header.normalizePoints = rect.isNormalized; - } - finally - { + } finally { // Move to the end of the header. buffer.position(pos + HEADER_LENGTH); } @@ -1044,30 +1046,33 @@ protected Header readHeaderFromBuffer(ByteBuffer buffer) throws IOException //**************************************************************// //******************** Index *********************************// //**************************************************************// - /** - * Reads the Shapefile's accompanying index file and return the indices as an array of integers. Each array element - * represents the byte offset of the i'th record from the start of the Shapefile. This returns null if - * this Shapefile has no accompanying index file, if the index file is empty, or if the JVM cannot allocate enough - * memory to hold the index. + * Reads the Shapefile's accompanying index file and return the indices as + * an array of integers. Each array element represents the byte offset of + * the i'th record from the start of the Shapefile. This returns + * null if this Shapefile has no accompanying index file, if + * the index file is empty, or if the JVM cannot allocate enough memory to + * hold the index. * - * @return the Shapefile's record offset index, or null if the Shapefile has no accompanying index - * file, if the index file is empty, or if the index cannot be allocated. + * @return the Shapefile's record offset index, or null if the + * Shapefile has no accompanying index file, if the index file is empty, or + * if the index cannot be allocated. * * @throws IOException if an exception occurs during reading. */ - protected int[] readIndex() throws IOException - { + protected int[] readIndex() throws IOException { // The Shapefile index resource is optional. Return null if we don't have a stream to an index resource. - if (this.shxChannel == null) + if (this.shxChannel == null) { return null; + } ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH); WWIO.readChannelToBuffer(this.shxChannel, buffer); // Return null if the index is empty or is smaller than the minimum required size. - if (buffer.remaining() < HEADER_LENGTH) + if (buffer.remaining() < HEADER_LENGTH) { return null; + } Header indexHeader = this.readHeaderFromBuffer(buffer); int numRecords = (indexHeader.fileLength - HEADER_LENGTH) / 8; @@ -1075,17 +1080,14 @@ protected int[] readIndex() throws IOException int indexLength = 8 * numRecords; // 8 bytes per record. int[] array; - try - { + try { buffer = ByteBuffer.allocate(indexLength); array = new int[numElements]; - } - catch (OutOfMemoryError e) - { + } catch (OutOfMemoryError e) { // Log a warning that we could not allocate enough memory to hold the Shapefile index. Shapefile parsing // can continue without the optional index, so we catch the exception and return immediately. Logging.logger().log(Level.WARNING, - Logging.getMessage("SHP.OutOfMemoryAllocatingIndex", this.getStringValue(AVKey.DISPLAY_NAME)), e); + Logging.getMessage("SHP.OutOfMemoryAllocatingIndex", this.getStringValue(AVKey.DISPLAY_NAME)), e); return null; } @@ -1094,8 +1096,7 @@ protected int[] readIndex() throws IOException buffer.asIntBuffer().get(array); - for (int i = 0; i < numElements; i++) - { + for (int i = 0; i < numElements; i++) { array[i] *= 2; // Convert indices from 16-bit words to byte indices. } @@ -1105,102 +1106,98 @@ protected int[] readIndex() throws IOException //**************************************************************// //******************** Coordinate System *********************// //**************************************************************// - /** - * Reads the Shapefile's accompanying projection file as an OGC coordinate system encoded in well-known text format, - * and returns the coordinate system parameters. This returns null if this Shapefile has no - * accompanying projection file or if the projection file is empty. For details, see the OGC Coordinate Transform - * Service (CT) specification at http://www.opengeospatial.org/standards/ct. + * Reads the Shapefile's accompanying projection file as an OGC coordinate + * system encoded in well-known text format, and returns the coordinate + * system parameters. This returns null if this Shapefile has + * no accompanying projection file or if the projection file is empty. For + * details, see the OGC Coordinate Transform Service (CT) specification at + * http://www.opengeospatial.org/standards/ct. * - * @return coordinate system parameters parsed from the projection file, or null if this Shapefile has - * no accompanying projection file or the projection file is empty. + * @return coordinate system parameters parsed from the projection file, or + * null if this Shapefile has no accompanying projection file + * or the projection file is empty. * * @throws IOException if an exception occurs during reading. */ - protected AVList readCoordinateSystem() throws IOException - { + protected AVList readCoordinateSystem() throws IOException { // The Shapefile projection resource is optional. Return the parameter list unchanged if we don't have a stream // to a projection resource. - if (this.prjChannel == null) + if (this.prjChannel == null) { return null; + } // Read the Shapefile's associated projection to a String, using the default character encoding. Decode the // projection text as an OGC coordinate system formatted as well-known text. String text = WWIO.readChannelToString(this.prjChannel, null); // Return null if the projection file is empty. - if (WWUtil.isEmpty(text)) + if (WWUtil.isEmpty(text)) { return null; + } return WorldFile.decodeOGCCoordinateSystemWKT(text, null); } /** - * Returns a string indicating an error with the Shapefile's coordinate system parameters, or null to indicate that - * the coordinate parameters are valid. + * Returns a string indicating an error with the Shapefile's coordinate + * system parameters, or null to indicate that the coordinate parameters are + * valid. * * @param params the Shapefile's coordinate system parameters. * - * @return a non-empty string if the coordinate system parameters are invalid; null otherwise. + * @return a non-empty string if the coordinate system parameters are + * invalid; null otherwise. */ - protected String validateCoordinateSystem(AVList params) - { + protected String validateCoordinateSystem(AVList params) { Object o = params.getValue(AVKey.COORDINATE_SYSTEM); - if (!this.hasKey(AVKey.COORDINATE_SYSTEM)) - { + if (!this.hasKey(AVKey.COORDINATE_SYSTEM)) { Logging.logger().warning( - Logging.getMessage("generic.UnspecifiedCoordinateSystem", this.getStringValue(AVKey.DISPLAY_NAME))); + Logging.getMessage("generic.UnspecifiedCoordinateSystem", this.getStringValue(AVKey.DISPLAY_NAME))); return null; - } - else if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(o)) - { + } else if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(o)) { return null; - } - else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) - { + } else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) { return this.validateProjection(params); - } - else - { + } else { return Logging.getMessage("generic.UnsupportedCoordinateSystem", o); } } /** - * Returns a string indicating an error with the Shapefile's projection parameters, or null to indicate that the - * projection parameters are valid. + * Returns a string indicating an error with the Shapefile's projection + * parameters, or null to indicate that the projection parameters are valid. * * @param params the Shapefile's projection parameters. * - * @return a non-empty string if the projection parameters are invalid; null otherwise. + * @return a non-empty string if the projection parameters are invalid; null + * otherwise. */ - protected String validateProjection(AVList params) - { + protected String validateProjection(AVList params) { Object proj = params.getValue(AVKey.PROJECTION_NAME); - if (AVKey.PROJECTION_UTM.equals(proj)) - { + if (AVKey.PROJECTION_UTM.equals(proj)) { StringBuilder sb = new StringBuilder(); // Validate the UTM zone. Object o = params.getValue(AVKey.PROJECTION_ZONE); - if (o == null) + if (o == null) { sb.append(Logging.getMessage("generic.ZoneIsMissing")); - else if (!(o instanceof Integer) || ((Integer) o) < 1 || ((Integer) o) > 60) + } else if (!(o instanceof Integer) || ((Integer) o) < 1 || ((Integer) o) > 60) { sb.append(Logging.getMessage("generic.ZoneIsInvalid", o)); + } // Validate the UTM hemisphere. o = params.getValue(AVKey.PROJECTION_HEMISPHERE); - if (o == null) + if (o == null) { sb.append(sb.length() > 0 ? ", " : "").append(Logging.getMessage("generic.HemisphereIsMissing")); - else if (!o.equals(AVKey.NORTH) && !o.equals(AVKey.SOUTH)) + } else if (!o.equals(AVKey.NORTH) && !o.equals(AVKey.SOUTH)) { sb.append(sb.length() > 0 ? ", " : "").append(Logging.getMessage("generic.HemisphereIsInvalid", o)); + } return sb.length() > 0 ? sb.toString() : null; - } - else - { + } else { return Logging.getMessage("generic.UnsupportedProjection", proj); } } @@ -1208,21 +1205,18 @@ else if (!o.equals(AVKey.NORTH) && !o.equals(AVKey.SOUTH)) //**************************************************************// //******************** Shape Records *************************// //**************************************************************// - /** - * Reads the next {@link ShapefileRecord} instance from this Shapefile. This file is assumed to have one or more - * remaining records available. + * Reads the next {@link ShapefileRecord} instance from this Shapefile. This + * file is assumed to have one or more remaining records available. * * @return a {@link ShapefileRecord} instance. * * @throws IOException if the record cannot be read for any reason. */ - protected ShapefileRecord readNextRecord() throws IOException - { + protected ShapefileRecord readNextRecord() throws IOException { ByteBuffer buffer; - if (this.mappedShpBuffer != null) - { + if (this.mappedShpBuffer != null) { // Save the mapped buffer's current position and limit. int pos = this.mappedShpBuffer.position(); @@ -1239,12 +1233,11 @@ protected ShapefileRecord readNextRecord() throws IOException this.numBytesRead += recordLength; buffer = this.mappedShpBuffer; - } - else - { + } else { // Allocate a buffer to hold the record header. - if (this.recordHeaderBuffer == null) + if (this.recordHeaderBuffer == null) { this.recordHeaderBuffer = ByteBuffer.allocate(ShapefileRecord.RECORD_HEADER_LENGTH); + } // Read the header bytes. this.recordHeaderBuffer.clear(); @@ -1257,8 +1250,9 @@ protected ShapefileRecord readNextRecord() throws IOException int recordLength = ShapefileRecord.RECORD_HEADER_LENGTH + contentLength; // Allocate a buffer to hold the record content. - if (this.recordContentBuffer == null || this.recordContentBuffer.capacity() < recordLength) + if (this.recordContentBuffer == null || this.recordContentBuffer.capacity() < recordLength) { this.recordContentBuffer = ByteBuffer.allocate(recordLength); + } this.recordContentBuffer.limit(recordLength); this.recordContentBuffer.rewind(); @@ -1271,40 +1265,38 @@ protected ShapefileRecord readNextRecord() throws IOException } ShapefileRecord record; - try - { + try { record = this.readRecordFromBuffer(buffer); - } - finally - { + } finally { // Restore the mapped buffer's limit to its capacity. - if (this.mappedShpBuffer != null) + if (this.mappedShpBuffer != null) { this.mappedShpBuffer.limit(this.mappedShpBuffer.capacity()); + } } return record; } /** - * Reads a {@link ShapefileRecord} instance from the given {@link java.nio.ByteBuffer}, or null if the buffer - * contains a null record. + * Reads a {@link ShapefileRecord} instance from the given + * {@link java.nio.ByteBuffer}, or null if the buffer contains a null + * record. *

      - * The buffer current position is assumed to be set at the start of the record and will be set to the start of the - * next record after this method has completed. + * The buffer current position is assumed to be set at the start of the + * record and will be set to the start of the next record after this method + * has completed. * - * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read from. + * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read + * from. * * @return a {@link ShapefileRecord} instance. */ - protected ShapefileRecord readRecordFromBuffer(ByteBuffer buffer) - { + protected ShapefileRecord readRecordFromBuffer(ByteBuffer buffer) { ShapefileRecord record = this.createRecord(buffer); - if (record != null) - { + if (record != null) { // Read the record's attribute data. - if (this.attributeFile != null && this.attributeFile.hasNext()) - { + if (this.attributeFile != null && this.attributeFile.hasNext()) { record.setAttributes(this.attributeFile.nextRecord()); } } @@ -1313,48 +1305,47 @@ protected ShapefileRecord readRecordFromBuffer(ByteBuffer buffer) } /** - * Returns a new {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the specified - * buffer. The buffer's current position is assumed to be set at the start of the record and will be set to the - * start of the next record after this method has completed. + * Returns a new + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} + * from the specified buffer. The buffer's current position is assumed to be + * set at the start of the record and will be set to the start of the next + * record after this method has completed. *

      - * This returns an instance of of ShapefileRecord appropriate for the record's shape type. For example, if the - * record's shape type is SHAPE_POINT, this returns a ShapefileRecordPoint, and if the - * record's shape type is SHAPE_NULL, this returns ShapefileRecordNull. + * This returns an instance of of ShapefileRecord appropriate for the + * record's shape type. For example, if the record's shape type is + * SHAPE_POINT, this returns a + * ShapefileRecordPoint, and if the record's shape type is + * SHAPE_NULL, this returns ShapefileRecordNull. *

      - * This returns null if the record's shape type is not one of the following types: - * SHAPE_POINT, SHAPE_POINT_M, SHAPE_POINT_Z, SHAPE_MULTI_POINT, - * SHAPE_MULTI_POINT_M, SHAPE_MULTI_POINT_Z, SHAPE_NULL, - * SHAPE_POLYGON, SHAPE_POLYGON_M, SHAPE_POLYGON_Z, - * SHAPE_POLYLINE, SHAPE_POLYLINE_M, SHAPE_POLYLINE_Z. + * This returns null if the record's shape type is not one of + * the following types: SHAPE_POINT, + * SHAPE_POINT_M, SHAPE_POINT_Z, + * SHAPE_MULTI_POINT, SHAPE_MULTI_POINT_M, + * SHAPE_MULTI_POINT_Z, SHAPE_NULL, + * SHAPE_POLYGON, SHAPE_POLYGON_M, + * SHAPE_POLYGON_Z, SHAPE_POLYLINE, + * SHAPE_POLYLINE_M, SHAPE_POLYLINE_Z. * * @param buffer the buffer containing the record's content. * - * @return a new {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} instance, null if the - * record's shape type is not one of the recognized types. + * @return a new + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} instance, + * null if the record's shape type is not one of the recognized + * types. */ - protected ShapefileRecord createRecord(ByteBuffer buffer) - { + protected ShapefileRecord createRecord(ByteBuffer buffer) { String shapeType = this.readRecordShapeType(buffer); // Select proper record class - if (isPointType(shapeType)) - { + if (isPointType(shapeType)) { return this.createPoint(buffer); - } - else if (isMultiPointType(shapeType)) - { + } else if (isMultiPointType(shapeType)) { return this.createMultiPoint(buffer); - } - else if (isPolylineType(shapeType)) - { + } else if (isPolylineType(shapeType)) { return this.createPolyline(buffer); - } - else if (isPolygonType(shapeType)) - { + } else if (isPolygonType(shapeType)) { return this.createPolygon(buffer); - } - else if (isNullType(shapeType)) - { + } else if (isNullType(shapeType)) { return this.createNull(buffer); } @@ -1362,78 +1353,92 @@ else if (isNullType(shapeType)) } /** - * Returns a new "null" {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the specified buffer. + * Returns a new "null" + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the + * specified buffer. *

      - * The buffer current position is assumed to be set at the start of the record and will be set to the start of the - * next record after this method has completed. + * The buffer current position is assumed to be set at the start of the + * record and will be set to the start of the next record after this method + * has completed. * * @param buffer the buffer containing the point record's content. * - * @return a new point {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. + * @return a new point + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. */ - protected ShapefileRecord createNull(ByteBuffer buffer) - { + protected ShapefileRecord createNull(ByteBuffer buffer) { return new ShapefileRecordNull(this, buffer); } /** - * Returns a new point {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the specified buffer. + * Returns a new point + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the + * specified buffer. *

      - * The buffer current position is assumed to be set at the start of the record and will be set to the start of the - * next record after this method has completed. + * The buffer current position is assumed to be set at the start of the + * record and will be set to the start of the next record after this method + * has completed. * * @param buffer the buffer containing the point record's content. * - * @return a new point {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. + * @return a new point + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. */ - protected ShapefileRecord createPoint(ByteBuffer buffer) - { + protected ShapefileRecord createPoint(ByteBuffer buffer) { return new ShapefileRecordPoint(this, buffer); } /** - * Returns a new multi-point {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the specified - * buffer. + * Returns a new multi-point + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the + * specified buffer. *

      - * The buffer current position is assumed to be set at the start of the record and will be set to the start of the - * next record after this method has completed. + * The buffer current position is assumed to be set at the start of the + * record and will be set to the start of the next record after this method + * has completed. * * @param buffer the buffer containing the multi-point record's content. * - * @return a new point {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. + * @return a new point + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. */ - protected ShapefileRecord createMultiPoint(ByteBuffer buffer) - { + protected ShapefileRecord createMultiPoint(ByteBuffer buffer) { return new ShapefileRecordMultiPoint(this, buffer); } /** - * Returns a new polyline {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the specified buffer. + * Returns a new polyline + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the + * specified buffer. *

      - * The buffer current position is assumed to be set at the start of the record and will be set to the start of the - * next record after this method has completed. + * The buffer current position is assumed to be set at the start of the + * record and will be set to the start of the next record after this method + * has completed. * * @param buffer the buffer containing the polyline record's content. * - * @return a new point {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. + * @return a new point + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. */ - protected ShapefileRecord createPolyline(ByteBuffer buffer) - { + protected ShapefileRecord createPolyline(ByteBuffer buffer) { return new ShapefileRecordPolyline(this, buffer); } /** - * Returns a new polygon {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the specified buffer. + * Returns a new polygon + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord} from the + * specified buffer. *

      - * The buffer current position is assumed to be set at the start of the record and will be set to the start of the - * next record after this method has completed. + * The buffer current position is assumed to be set at the start of the + * record and will be set to the start of the next record after this method + * has completed. * * @param buffer the buffer containing the polygon record's content. * - * @return a new point {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. + * @return a new point + * {@link gov.nasa.worldwind.formats.shapefile.ShapefileRecord}. */ - protected ShapefileRecord createPolygon(ByteBuffer buffer) - { + protected ShapefileRecord createPolygon(ByteBuffer buffer) { return new ShapefileRecordPolygon(this, buffer); } @@ -1444,16 +1449,14 @@ protected ShapefileRecord createPolygon(ByteBuffer buffer) * * @return the record's shape type. */ - protected String readRecordShapeType(ByteBuffer buffer) - { + protected String readRecordShapeType(ByteBuffer buffer) { // Read shape type - little endian buffer.order(ByteOrder.LITTLE_ENDIAN); int type = buffer.getInt(buffer.position() + 2 * 4); // skip record number and length as ints String shapeType = this.getShapeType(type); - if (shapeType == null) - { + if (shapeType == null) { // Let the caller catch and log the exception. throw new WWRuntimeException(Logging.getMessage("SHP.UnsupportedShapeType", type)); } @@ -1462,17 +1465,16 @@ protected String readRecordShapeType(ByteBuffer buffer) } /** - * Maps the integer shape type from the shapefile to the corresponding shape type defined above. + * Maps the integer shape type from the shapefile to the corresponding shape + * type defined above. * * @param type the integer shape type. * * @return the mapped shape type. */ - protected String getShapeType(int type) - { + protected String getShapeType(int type) { // Cases commented out indicate shape types not implemented - switch (type) - { + switch (type) { case 0: return SHAPE_NULL; case 1: @@ -1504,7 +1506,6 @@ protected String getShapeType(int type) // case 31: // return SHAPE_MULTI_PATCH; - default: return null; // unsupported shape type } @@ -1513,45 +1514,41 @@ protected String getShapeType(int type) //**************************************************************// //******************** Point Data ****************************// //**************************************************************// - /** - * Add point coordinates to the Shapefile starting at the buffer's positions and ending at the specified number of - * points, and returns an address to the point coordinates in the Shapefile's backing point buffer. Points are read - * as (X,Y) pairs of 64-bit floating point numbers. This throws an exception if the JVM cannot allocate enough - * memory to hold the Shapefile's backing point buffer. - * - * @param record the record associated with the point coordinates, may be null. - * @param buffer the buffer to read points from. + * Add point coordinates to the Shapefile starting at the buffer's positions + * and ending at the specified number of points, and returns an address to + * the point coordinates in the Shapefile's backing point buffer. Points are + * read as (X,Y) pairs of 64-bit floating point numbers. This throws an + * exception if the JVM cannot allocate enough memory to hold the + * Shapefile's backing point buffer. + * + * @param record the record associated with the point coordinates, may be + * null. + * @param buffer the buffer to read points from. * @param numPoints the number of (X,Y) pairs to read. * * @return the point's address in the Shapefile's backing point buffer. */ - protected int addPoints(ShapefileRecord record, ByteBuffer buffer, int numPoints) - { + protected int addPoints(ShapefileRecord record, ByteBuffer buffer, int numPoints) { DoubleBuffer pointBuffer; // Read the point data, keeping track of the start and end of the point data. int pos = buffer.position(); int limit = buffer.position() + 2 * WWBufferUtil.SIZEOF_DOUBLE * numPoints; - try - { + try { // Set the buffer's limit to include the number of bytes required to hold 2 double precision values for each // point, then read the point data between the buffer's current position and limit. buffer.limit(limit); pointBuffer = this.readPoints(record, buffer); - } - finally - { + } finally { // Restore the buffer's limit to its original value, and set its position at the end of the point data. buffer.clear(); buffer.position(limit); } // Add the point data to the Shapefile's internal point buffer. - if (this.mappedShpBuffer != null) - { - if (this.pointBuffer == null) - { + if (this.mappedShpBuffer != null) { + if (this.pointBuffer == null) { // Create a VecBufferBlocks to hold this Shapefile's point data. Shapefile points are 2-tuples stored in // IEEE 64-bit floating point format, in little endian byte order. ByteBuffer buf = this.mappedShpBuffer.duplicate(); @@ -1562,29 +1559,23 @@ protected int addPoints(ShapefileRecord record, ByteBuffer buffer, int numPoints // Add the point's byte range to the VecBufferBlocks. return ((VecBufferBlocks) this.pointBuffer).addBlock(pos, limit - 1); - } - else - { - if (this.pointBuffer == null) - { + } else { + if (this.pointBuffer == null) { // Create a CompoundVecBuffer to hold this Shapefile's point data. int totalPointsEstimate = this.computeNumberOfPointsEstimate(); DoubleBuffer doubleBuffer; - try - { + try { doubleBuffer = Buffers.newDirectDoubleBuffer(2 * totalPointsEstimate); - } - catch (OutOfMemoryError e) - { + } catch (OutOfMemoryError e) { // Let the caller catch and log the exception. If we cannot allocate enough memory to hold the // point buffer, we throw an exception indicating that the read operation should be terminated. throw new WWRuntimeException(Logging.getMessage("SHP.OutOfMemoryAllocatingPointBuffer", - this.getStringValue(AVKey.DISPLAY_NAME)), e); + this.getStringValue(AVKey.DISPLAY_NAME)), e); } this.pointBuffer = new VecBufferSequence( - new VecBuffer(2, new BufferWrapper.DoubleBufferWrapper(doubleBuffer))); + new VecBuffer(2, new BufferWrapper.DoubleBufferWrapper(doubleBuffer))); } // Append the point coordinates to the VecBufferSequence. @@ -1599,8 +1590,7 @@ protected int addPoints(ShapefileRecord record, ByteBuffer buffer, int numPoints * @return a liberal estimate of the number of points in the shapefile. */ @SuppressWarnings({"StringEquality"}) - protected int computeNumberOfPointsEstimate() - { + protected int computeNumberOfPointsEstimate() { // Compute the header overhead, subtract it from the file size, then divide by point size to get the estimate. // The Parts array is not included in the overhead, so the estimate will be slightly greater than the number of // points needed if the shape is a type with a Parts array. Measure values and ranges are also not included in @@ -1610,75 +1600,77 @@ protected int computeNumberOfPointsEstimate() final int numRecords = this.getNumberOfRecords(); // Return very liberal estimate based on file size if num records unknown. - if (numRecords < 0) + if (numRecords < 0) { return (this.getLength() - HEADER_LENGTH) / 16; // num X, Y tuples that can fit in the file length - + } int overhead = HEADER_LENGTH + numRecords * 12; //12 bytes per record for record header and record shape type String shapeType = this.getShapeType(); - if (shapeType == SHAPE_POINT || shapeType == SHAPE_POINT_M) + if (shapeType == SHAPE_POINT || shapeType == SHAPE_POINT_M) { return (this.getLength() - overhead) / 16; // 16 = two doubles, X and Y - - if (shapeType == SHAPE_MULTI_POINT || shapeType == SHAPE_MULTI_POINT_M) - // Add 32 bytes per record for bounding box + 4 bytes for one int per record + } + if (shapeType == SHAPE_MULTI_POINT || shapeType == SHAPE_MULTI_POINT_M) // Add 32 bytes per record for bounding box + 4 bytes for one int per record + { return (this.getLength() - (overhead + numRecords * (32 + 4))) / 16; // 16 = two doubles, X and Y - + } if (shapeType == SHAPE_POLYLINE || shapeType == SHAPE_POLYGON - || shapeType == SHAPE_POLYLINE_M || shapeType == SHAPE_POLYGON_M) - // Add 32 bytes per record for bounding box + 8 bytes for two ints per record + || shapeType == SHAPE_POLYLINE_M || shapeType == SHAPE_POLYGON_M) // Add 32 bytes per record for bounding box + 8 bytes for two ints per record + { return (this.getLength() - (overhead + numRecords * (32 + 8))) / 16; // 16 = two doubles, X and Y - - if (shapeType == SHAPE_POINT_Z) + } + if (shapeType == SHAPE_POINT_Z) { return (this.getLength() - overhead) / 24; // 24 = three doubles, X, Y, Z - - if (shapeType == SHAPE_MULTI_POINT_Z) - // Add 48 bytes per record for bounding box + 4 bytes for one int per record + } + if (shapeType == SHAPE_MULTI_POINT_Z) // Add 48 bytes per record for bounding box + 4 bytes for one int per record + { return (this.getLength() - (overhead + numRecords * (48 + 4))) / 24; // 24 = three doubles, X, Y, Z - - if (shapeType == SHAPE_POLYLINE_Z || shapeType == SHAPE_POLYGON_Z) - // Add 48 bytes per record for bounding box + 8 bytes for two ints per record + } + if (shapeType == SHAPE_POLYLINE_Z || shapeType == SHAPE_POLYGON_Z) // Add 48 bytes per record for bounding box + 8 bytes for two ints per record + { return (this.getLength() - (overhead + numRecords * (48 + 8))) / 24; // 24 = three doubles, X, Y and Z - + } // The shape type should have been checked before calling this method, so we shouldn't reach this code. // Let the caller catch and log the exception. throw new WWRuntimeException(Logging.getMessage("SHP.UnsupportedShapeType", shapeType)); } /** - * Returns a {@link java.nio.DoubleBuffer} containing the (X,Y) tuples between the buffer's position and its limit. - * This returns null if the buffer is null or if the buffer has no remaining elements. The returned coordinates are - * interpreted according to the Shapefile's coordinate system. This throws a {@link - * gov.nasa.worldwind.exception.WWRuntimeException} if the coordinate system is unsupported. + * Returns a {@link java.nio.DoubleBuffer} containing the (X,Y) tuples + * between the buffer's position and its limit. This returns null if the + * buffer is null or if the buffer has no remaining elements. The returned + * coordinates are interpreted according to the Shapefile's coordinate + * system. This throws a {@link + * gov.nasa.worldwind.exception.WWRuntimeException} if the coordinate system + * is unsupported. *

      - * The buffer current position is assumed to be set at the start of the point data and will be set to the end of the - * point data after this method has completed. + * The buffer current position is assumed to be set at the start of the + * point data and will be set to the end of the point data after this method + * has completed. * - * @param record the record associated with the point coordinates, may be null. + * @param record the record associated with the point coordinates, may be + * null. * @param buffer the buffer to read point coordinates from. * * @return a buffer containing the point coordinates. * - * @throws WWRuntimeException if the Shapefile's coordinate system is unsupported. + * @throws WWRuntimeException if the Shapefile's coordinate system is + * unsupported. */ - protected DoubleBuffer readPoints(ShapefileRecord record, ByteBuffer buffer) - { - if (buffer == null || !buffer.hasRemaining()) + protected DoubleBuffer readPoints(ShapefileRecord record, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) { return null; + } Object o = this.getValue(AVKey.COORDINATE_SYSTEM); - if (!this.hasKey(AVKey.COORDINATE_SYSTEM)) + if (!this.hasKey(AVKey.COORDINATE_SYSTEM)) { return this.readUnspecifiedPoints(record, buffer); - - else if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(o)) + } else if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(o)) { return this.readGeographicPoints(record, buffer); - - else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) + } else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) { return this.readProjectedPoints(record, buffer); - - else - { + } else { // The Shapefile's coordinate system is unsupported. This should never happen because the coordinate system // is validated during initialization, but we check anyway. Let the caller catch and log the message. throw new WWRuntimeException(Logging.getMessage("generic.UnsupportedCoordinateSystem", o)); @@ -1686,39 +1678,41 @@ else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) } /** - * Returns a {@link java.nio.DoubleBuffer} containing the (X,Y) tuples between the buffer's position and its limit. - * The coordinates are assumed to be in an unspecified coordinate system and are not changed. + * Returns a {@link java.nio.DoubleBuffer} containing the (X,Y) tuples + * between the buffer's position and its limit. The coordinates are assumed + * to be in an unspecified coordinate system and are not changed. * - * @param record the record associated with the point coordinates, may be null. + * @param record the record associated with the point coordinates, may be + * null. * @param buffer the buffer to read point coordinates from. * * @return a buffer containing the point coordinates. */ @SuppressWarnings({"UnusedDeclaration"}) - protected DoubleBuffer readUnspecifiedPoints(ShapefileRecord record, ByteBuffer buffer) - { + protected DoubleBuffer readUnspecifiedPoints(ShapefileRecord record, ByteBuffer buffer) { // Create a view of the buffer as a doubles. return buffer.asDoubleBuffer(); } /** - * Returns a {@link java.nio.DoubleBuffer} containing the geographic (longitude, latitude) tuples between the - * buffer's position and its limit. This normalizes the geographic coordinates to the range +-90 latitude and +-180 - * longitude if the record is non-null and {@link ShapefileRecord#isNormalizePoints()} returns true. - * - * @param record the record associated with the point coordinates, may be null. + * Returns a {@link java.nio.DoubleBuffer} containing the geographic + * (longitude, latitude) tuples between the buffer's position and its limit. + * This normalizes the geographic coordinates to the range +-90 latitude and + * +-180 longitude if the record is non-null and + * {@link ShapefileRecord#isNormalizePoints()} returns true. + * + * @param record the record associated with the point coordinates, may be + * null. * @param buffer the buffer to read point coordinates from. * * @return a buffer containing the geographic point coordinates. */ - protected DoubleBuffer readGeographicPoints(ShapefileRecord record, ByteBuffer buffer) - { + protected DoubleBuffer readGeographicPoints(ShapefileRecord record, ByteBuffer buffer) { // Create a view of the buffer as a doubles. DoubleBuffer doubleBuffer = buffer.asDoubleBuffer(); // Normalize the buffer of geographic point coordinates if the record is flagged as needing normalization. - if (record != null && record.isNormalizePoints()) - { + if (record != null && record.isNormalizePoints()) { WWUtil.normalizeGeographicCoordinates(doubleBuffer); doubleBuffer.rewind(); } @@ -1727,25 +1721,27 @@ protected DoubleBuffer readGeographicPoints(ShapefileRecord record, ByteBuffer b } /** - * Returns a {@link java.nio.DoubleBuffer} containing the projected (X,Y) tuples between the buffer's position and - * its limit, converted to geographic coordinates (latitude,longitude). The returned coordinates are interpreted - * according to the Shapefile's projection. This throws a {@link gov.nasa.worldwind.exception.WWRuntimeException} if - * the projection is unsupported. - * - * @param record the record associated with the point coordinates, may be null. + * Returns a {@link java.nio.DoubleBuffer} containing the projected (X,Y) + * tuples between the buffer's position and its limit, converted to + * geographic coordinates (latitude,longitude). The returned coordinates are + * interpreted according to the Shapefile's projection. This throws a + * {@link gov.nasa.worldwind.exception.WWRuntimeException} if the projection + * is unsupported. + * + * @param record the record associated with the point coordinates, may be + * null. * @param buffer the buffer to read point coordinates from. * - * @return a buffer containing geographic point coordinates converted form projected coordinates. + * @return a buffer containing geographic point coordinates converted form + * projected coordinates. * * @throws WWRuntimeException if the Shapefile's projection is unsupported. */ @SuppressWarnings({"UnusedDeclaration"}) - protected DoubleBuffer readProjectedPoints(ShapefileRecord record, ByteBuffer buffer) - { + protected DoubleBuffer readProjectedPoints(ShapefileRecord record, ByteBuffer buffer) { Object o = this.getValue(AVKey.PROJECTION_NAME); - if (AVKey.PROJECTION_UTM.equals(o)) - { + if (AVKey.PROJECTION_UTM.equals(o)) { // The Shapefile's coordinate system is UTM. Convert the UTM coordinates to geographic. The zone and hemisphere // parameters have already been validated in validateBounds. Integer zone = (Integer) this.getValue(AVKey.PROJECTION_ZONE); @@ -1757,9 +1753,7 @@ protected DoubleBuffer readProjectedPoints(ShapefileRecord record, ByteBuffer bu doubleBuffer.rewind(); return doubleBuffer; - } - else - { + } else { // The Shapefile's coordinate system projection is unsupported. This should never happen because the // projection is validated during initialization, but we check anyway. Let the caller catch and log the // message. @@ -1770,47 +1764,50 @@ protected DoubleBuffer readProjectedPoints(ShapefileRecord record, ByteBuffer bu //**************************************************************// //******************** Bounding Rectangle ********************// //**************************************************************// - /** - * Stores a bounding rectangle's coordinates, and if the coordinates are normalized. If isNormalized is - * true, this indicates that the original coordinate values are out of range and required - * normalization. The shapefile and shapefile records use this to determine which records must have their point - * coordinates normalized. Normalization is rarely needed, and this enables the shapefile to normalize only point - * coordinates associated with records that require it. + * Stores a bounding rectangle's coordinates, and if the coordinates are + * normalized. If isNormalized is true, this + * indicates that the original coordinate values are out of range and + * required normalization. The shapefile and shapefile records use this to + * determine which records must have their point coordinates normalized. + * Normalization is rarely needed, and this enables the shapefile to + * normalize only point coordinates associated with records that require it. */ - protected static class BoundingRectangle - { - /** Four-element array of the bounding rectangle's coordinates, ordered as follows: (minY, maxY, minX, maxX). */ + protected static class BoundingRectangle { + + /** + * Four-element array of the bounding rectangle's coordinates, ordered + * as follows: (minY, maxY, minX, maxX). + */ public double[] coords; - /** True if the coordinates are normalized, and false otherwise. */ + /** + * True if the coordinates are normalized, and false otherwise. + */ public boolean isNormalized; } /** - * Returns a bounding rectangle from the specified buffer. This reads four doubles and interprets them as a bounding - * rectangle in the following order: (minX, minY, maxX, maxY). The returned rectangle's coordinates are interpreted - * according to the Shapefile's coordinate system. This throws a {@link gov.nasa.worldwind.exception.WWRuntimeException} - * if the coordinate system is unsupported. + * Returns a bounding rectangle from the specified buffer. This reads four + * doubles and interprets them as a bounding rectangle in the following + * order: (minX, minY, maxX, maxY). The returned rectangle's coordinates are + * interpreted according to the Shapefile's coordinate system. This throws a + * {@link gov.nasa.worldwind.exception.WWRuntimeException} if the coordinate + * system is unsupported. * * @param buffer the buffer to read from. * * @return a bounding rectangle with coordinates from the specified buffer. */ - protected BoundingRectangle readBoundingRectangle(ByteBuffer buffer) - { + protected BoundingRectangle readBoundingRectangle(ByteBuffer buffer) { Object o = this.getValue(AVKey.COORDINATE_SYSTEM); - if (!this.hasKey(AVKey.COORDINATE_SYSTEM)) + if (!this.hasKey(AVKey.COORDINATE_SYSTEM)) { return this.readUnspecifiedBoundingRectangle(buffer); - - else if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(o)) + } else if (AVKey.COORDINATE_SYSTEM_GEOGRAPHIC.equals(o)) { return this.readGeographicBoundingRectangle(buffer); - - else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) + } else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) { return this.readProjectedBoundingRectangle(buffer); - - else - { + } else { // The Shapefile's coordinate system is unsupported. This should never happen because the coordinate system // is validated during initialization, but we check anyway. Let the caller catch and log the message. throw new WWRuntimeException(Logging.getMessage("generic.UnsupportedCoordinateSystem", o)); @@ -1818,17 +1815,18 @@ else if (AVKey.COORDINATE_SYSTEM_PROJECTED.equals(o)) } /** - * Returns a bounding rectangle from the specified buffer. This reads four doubles and interprets them as a bounding - * rectangle in the following order: (minX, minY, maxX, maxY). The coordinates are assumed to be in an unspecified - * coordinate system and are not changed. + * Returns a bounding rectangle from the specified buffer. This reads four + * doubles and interprets them as a bounding rectangle in the following + * order: (minX, minY, maxX, maxY). The coordinates are assumed to be in an + * unspecified coordinate system and are not changed. * * @param buffer the buffer to read bounding rectangle coordinates from. * - * @return a bounding rectangle with coordinates from the specified buffer. The rectangle's coordinates are ordered - * as follows: (minY, maxY, minX, maxX). + * @return a bounding rectangle with coordinates from the specified buffer. + * The rectangle's coordinates are ordered as follows: (minY, maxY, minX, + * maxX). */ - protected BoundingRectangle readUnspecifiedBoundingRectangle(ByteBuffer buffer) - { + protected BoundingRectangle readUnspecifiedBoundingRectangle(ByteBuffer buffer) { // Read the bounding rectangle coordinates in the following order: minY, maxY, minX, maxX. BoundingRectangle rect = new BoundingRectangle(); rect.coords = this.readBoundingRectangleCoordinates(buffer); @@ -1836,53 +1834,54 @@ protected BoundingRectangle readUnspecifiedBoundingRectangle(ByteBuffer buffer) } /** - * Returns a bounding rectangle from the specified buffer. This reads four doubles and interprets them as a - * Geographic bounding rectangle in the following order: (minLat, maxLat, minLon, maxLon). If any of the coordinates - * are out of the range -90/+90 latitude and -180/+180 longitude, this normalizes the coordinates and sets the - * rectangle's {@link gov.nasa.worldwind.formats.shapefile.Shapefile.BoundingRectangle#isNormalized} property to - * true. + * Returns a bounding rectangle from the specified buffer. This reads four + * doubles and interprets them as a Geographic bounding rectangle in the + * following order: (minLat, maxLat, minLon, maxLon). If any of the + * coordinates are out of the range -90/+90 latitude and -180/+180 + * longitude, this normalizes the coordinates and sets the rectangle's + * {@link gov.nasa.worldwind.formats.shapefile.Shapefile.BoundingRectangle#isNormalized} + * property to true. * * @param buffer the buffer to read bounding rectangle coordinates from. * - * @return a bounding rectangle with coordinates from the specified buffer. The rectangle's coordinates are ordered - * as follows: (minLat, maxLat, minLon, maxLon). + * @return a bounding rectangle with coordinates from the specified buffer. + * The rectangle's coordinates are ordered as follows: (minLat, maxLat, + * minLon, maxLon). */ - protected BoundingRectangle readGeographicBoundingRectangle(ByteBuffer buffer) - { + protected BoundingRectangle readGeographicBoundingRectangle(ByteBuffer buffer) { // Read the bounding rectangle coordinates in the following order: minLat, maxLat, minLon, maxLon. BoundingRectangle rect = new BoundingRectangle(); rect.coords = this.readBoundingRectangleCoordinates(buffer); // The bounding rectangle's min latitude exceeds -90. Set the min latitude to -90. Correct the max latitude if // the normalized min latitude is greater than the max latitude. - if (rect.coords[0] < -90) - { + if (rect.coords[0] < -90) { double normalizedLat = Angle.normalizedLatitude(Angle.fromDegrees(rect.coords[0])).degrees; rect.coords[0] = -90; rect.isNormalized = true; - if (rect.coords[1] < normalizedLat) + if (rect.coords[1] < normalizedLat) { rect.coords[1] = normalizedLat; + } } // The bounding rectangle's max latitude exceeds +90. Set the max latitude to +90. Correct the min latitude if // the normalized max latitude is less than the min latitude. - if (rect.coords[1] > 90) - { + if (rect.coords[1] > 90) { double normalizedLat = Angle.normalizedLatitude(Angle.fromDegrees(rect.coords[1])).degrees; rect.coords[1] = 90; rect.isNormalized = true; - if (rect.coords[0] > normalizedLat) + if (rect.coords[0] > normalizedLat) { rect.coords[0] = normalizedLat; + } } // The bounding rectangle's longitudes exceed +-180, therefore the rectangle spans the international // dateline. Set the longitude bound to (-180, 180) to contain the dateline spanning rectangle. - if (rect.coords[2] < -180 || rect.coords[3] > 180) - { + if (rect.coords[2] < -180 || rect.coords[3] > 180) { rect.coords[2] = -180; rect.coords[3] = 180; rect.isNormalized = true; @@ -1892,25 +1891,27 @@ protected BoundingRectangle readGeographicBoundingRectangle(ByteBuffer buffer) } /** - * Returns a bounding rectangle from the specified buffer. This reads four doubles and interprets them as a - * projected bounding rectangle in the following order: (minX, maxX, minY, maxY). The projected rectangle is - * converted to geographic coordinates before the rectangle is returned. The returned coordinates are interpreted - * according to the Shapefile's projection. This throws a {@link gov.nasa.worldwind.exception.WWRuntimeException} if - * the projection is unsupported. + * Returns a bounding rectangle from the specified buffer. This reads four + * doubles and interprets them as a projected bounding rectangle in the + * following order: (minX, maxX, minY, maxY). The projected rectangle is + * converted to geographic coordinates before the rectangle is returned. The + * returned coordinates are interpreted according to the Shapefile's + * projection. This throws a + * {@link gov.nasa.worldwind.exception.WWRuntimeException} if the projection + * is unsupported. * * @param buffer the buffer to read bounding rectangle coordinates from. * - * @return a bounding rectangle with coordinates from the specified buffer. The rectangle's coordinates are ordered - * as follows: (minLat, maxLat, minLon, maxLon). + * @return a bounding rectangle with coordinates from the specified buffer. + * The rectangle's coordinates are ordered as follows: (minLat, maxLat, + * minLon, maxLon). * * @throws WWRuntimeException if the Shapefile's projection is unsupported. */ - protected BoundingRectangle readProjectedBoundingRectangle(ByteBuffer buffer) - { + protected BoundingRectangle readProjectedBoundingRectangle(ByteBuffer buffer) { Object o = this.getValue(AVKey.PROJECTION_NAME); - if (AVKey.PROJECTION_UTM.equals(o)) - { + if (AVKey.PROJECTION_UTM.equals(o)) { // Read the bounding rectangle coordinates in the following order: minEast, minNorth, maxEast, maxNorth. double[] coords = ShapefileUtils.readDoubleArray(buffer, 4); // Convert the UTM bounding rectangle to a geographic bounding rectangle. The zone and hemisphere parameters @@ -1922,9 +1923,7 @@ protected BoundingRectangle readProjectedBoundingRectangle(ByteBuffer buffer) BoundingRectangle rect = new BoundingRectangle(); rect.coords = sector.toArrayDegrees(); return rect; - } - else - { + } else { // The Shapefile's coordinate system projection is unsupported. This should never happen because the // projection is validated during initialization, but we check anyway. Let the caller catch and log the // message. @@ -1933,16 +1932,18 @@ protected BoundingRectangle readProjectedBoundingRectangle(ByteBuffer buffer) } /** - * Reads a Shapefile bounding rectangle from the specified buffer. This reads four doubles and returns them as a - * four-element array in the following order: (minY, maxY, minX, maxX). This ordering is consistent with the - * ordering expected by {@link gov.nasa.worldwind.geom.Sector#fromDegrees(double[])}. + * Reads a Shapefile bounding rectangle from the specified buffer. This + * reads four doubles and returns them as a four-element array in the + * following order: (minY, maxY, minX, maxX). This ordering is consistent + * with the ordering expected by + * {@link gov.nasa.worldwind.geom.Sector#fromDegrees(double[])}. * * @param buffer the buffer to read from. * - * @return a four-element array ordered as follows: (minY, maxY, minX, maxX). + * @return a four-element array ordered as follows: (minY, maxY, minX, + * maxX). */ - protected double[] readBoundingRectangleCoordinates(ByteBuffer buffer) - { + protected double[] readBoundingRectangleCoordinates(ByteBuffer buffer) { // Read the bounding rectangle coordinates in the following order: minX, minY, maxX, maxY. double minx = buffer.getDouble(); double miny = buffer.getDouble(); @@ -1950,15 +1951,15 @@ protected double[] readBoundingRectangleCoordinates(ByteBuffer buffer) double maxy = buffer.getDouble(); // Return an array with bounding rectangle coordinates in the following order: minY, maxY, minX, maxX. - return new double[] {miny, maxy, minx, maxx}; + return new double[]{miny, maxy, minx, maxx}; } //**************************************************************// //******************** Static Utilities **********************// //**************************************************************// - /** - * Indicates whether a specified shape type may contain optional measure values. + * Indicates whether a specified shape type may contain optional measure + * values. * * @param shapeType the shape type to analyze. * @@ -1966,10 +1967,8 @@ protected double[] readBoundingRectangleCoordinates(ByteBuffer buffer) * * @throws IllegalArgumentException if shapeType is null. */ - public static boolean isMeasureType(String shapeType) - { - if (shapeType == null) - { + public static boolean isMeasureType(String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -1987,10 +1986,8 @@ public static boolean isMeasureType(String shapeType) * * @throws IllegalArgumentException if shapeType is null. */ - public static boolean isZType(String shapeType) - { - if (shapeType == null) - { + public static boolean isZType(String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -2008,10 +2005,8 @@ public static boolean isZType(String shapeType) * * @throws IllegalArgumentException if shapeType is null. */ - public static boolean isNullType(String shapeType) - { - if (shapeType == null) - { + public static boolean isNullType(String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -2021,7 +2016,8 @@ public static boolean isNullType(String shapeType) } /** - * Indicates whether a specified shape type is either {@link #SHAPE_POINT}, {@link #SHAPE_POINT_M} or {@link + * Indicates whether a specified shape type is either + * {@link #SHAPE_POINT}, {@link #SHAPE_POINT_M} or {@link * #SHAPE_POINT_Z}. * * @param shapeType the shape type to analyze. @@ -2030,21 +2026,20 @@ public static boolean isNullType(String shapeType) * * @throws IllegalArgumentException if shapeType is null. */ - public static boolean isPointType(String shapeType) - { - if (shapeType == null) - { + public static boolean isPointType(String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return shapeType.equals(Shapefile.SHAPE_POINT) || shapeType.equals(Shapefile.SHAPE_POINT_Z) - || shapeType.equals(Shapefile.SHAPE_POINT_M); + || shapeType.equals(Shapefile.SHAPE_POINT_M); } /** - * Indicates whether a specified shape type is either {@link #SHAPE_MULTI_POINT}, {@link #SHAPE_MULTI_POINT_M} or + * Indicates whether a specified shape type is either + * {@link #SHAPE_MULTI_POINT}, {@link #SHAPE_MULTI_POINT_M} or * {@link #SHAPE_MULTI_POINT_Z}. * * @param shapeType the shape type to analyze. @@ -2053,21 +2048,20 @@ public static boolean isPointType(String shapeType) * * @throws IllegalArgumentException if shapeType is null. */ - public static boolean isMultiPointType(String shapeType) - { - if (shapeType == null) - { + public static boolean isMultiPointType(String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return shapeType.equals(Shapefile.SHAPE_MULTI_POINT) || shapeType.equals(Shapefile.SHAPE_MULTI_POINT_Z) - || shapeType.equals(Shapefile.SHAPE_MULTI_POINT_M); + || shapeType.equals(Shapefile.SHAPE_MULTI_POINT_M); } /** - * Indicates whether a specified shape type is either {@link #SHAPE_POLYLINE}, {@link #SHAPE_POLYLINE_M} or {@link + * Indicates whether a specified shape type is either + * {@link #SHAPE_POLYLINE}, {@link #SHAPE_POLYLINE_M} or {@link * #SHAPE_POLYLINE_Z}. * * @param shapeType the shape type to analyze. @@ -2076,130 +2070,112 @@ public static boolean isMultiPointType(String shapeType) * * @throws IllegalArgumentException if shapeType is null. */ - public static boolean isPolylineType(String shapeType) - { - if (shapeType == null) - { + public static boolean isPolylineType(String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return shapeType.equals(Shapefile.SHAPE_POLYLINE) || shapeType.equals(Shapefile.SHAPE_POLYLINE_Z) - || shapeType.equals(Shapefile.SHAPE_POLYLINE_M); + || shapeType.equals(Shapefile.SHAPE_POLYLINE_M); } /** - * Indicates whether a specified shape type is either {@link #SHAPE_POLYGON}, {@link #SHAPE_POLYGON_M} or {@link + * Indicates whether a specified shape type is either + * {@link #SHAPE_POLYGON}, {@link #SHAPE_POLYGON_M} or {@link * #SHAPE_POLYGON_Z}. * * @param shapeType the shape type to analyze. * * @return true if the shape type is a polygon type. */ - public static boolean isPolygonType(String shapeType) - { - if (shapeType == null) - { + public static boolean isPolygonType(String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return shapeType.equals(Shapefile.SHAPE_POLYGON) || shapeType.equals(Shapefile.SHAPE_POLYGON_Z) - || shapeType.equals(Shapefile.SHAPE_POLYGON_M); + || shapeType.equals(Shapefile.SHAPE_POLYGON_M); } - public String isExportFormatSupported(String mimeType) - { - if (KMLConstants.KML_MIME_TYPE.equalsIgnoreCase(mimeType)) + public String isExportFormatSupported(String mimeType) { + if (KMLConstants.KML_MIME_TYPE.equalsIgnoreCase(mimeType)) { return FORMAT_SUPPORTED; + } return Arrays.binarySearch(SHAPE_CONTENT_TYPES, mimeType) >= 0 ? FORMAT_SUPPORTED : FORMAT_NOT_SUPPORTED; } - public void export(String mimeType, Object output) throws IOException, UnsupportedOperationException - { - if (mimeType == null) - { + public void export(String mimeType, Object output) throws IOException, UnsupportedOperationException { + if (mimeType == null) { String message = Logging.getMessage("nullValue.Format"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (output == null) - { + if (output == null) { String message = Logging.getMessage("nullValue.OutputBufferIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - try - { + try { this.doExport(mimeType, output); - } - catch (XMLStreamException e) - { + } catch (XMLStreamException e) { Logging.logger().throwing(getClass().getName(), "export", e); throw new IOException(e); } } - protected void doExport(String mimeType, Object output) throws IOException, XMLStreamException - { + protected void doExport(String mimeType, Object output) throws IOException, XMLStreamException { XMLStreamWriter xmlWriter = null; XMLOutputFactory factory = XMLOutputFactory.newInstance(); boolean closeWriterWhenFinished = true; - if (output instanceof XMLStreamWriter) - { + if (output instanceof XMLStreamWriter) { xmlWriter = (XMLStreamWriter) output; closeWriterWhenFinished = false; - } - else if (output instanceof Writer) - { + } else if (output instanceof Writer) { xmlWriter = factory.createXMLStreamWriter((Writer) output); - } - else if (output instanceof OutputStream) - { + } else if (output instanceof OutputStream) { xmlWriter = factory.createXMLStreamWriter((OutputStream) output); } - if (xmlWriter == null) - { + if (xmlWriter == null) { String message = Logging.getMessage("Export.UnsupportedOutputObject"); Logging.logger().warning(message); throw new IllegalArgumentException(message); } - if (KMLConstants.KML_MIME_TYPE.equals(mimeType)) + if (KMLConstants.KML_MIME_TYPE.equals(mimeType)) { exportAsKML(xmlWriter); - else + } else { exportAsXML(xmlWriter); + } xmlWriter.flush(); - if (closeWriterWhenFinished) + if (closeWriterWhenFinished) { xmlWriter.close(); + } } - protected void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException - { + protected void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException { xmlWriter.writeStartElement("Shapefile"); xmlWriter.writeCharacters("\n"); - while (this.hasNext()) - { - try - { + while (this.hasNext()) { + try { ShapefileRecord nr = this.nextRecord(); - if (nr == null) + if (nr == null) { continue; + } nr.exportAsXML(xmlWriter); xmlWriter.writeCharacters("\n"); - } - catch (Exception e) - { + } catch (Exception e) { String message = Logging.getMessage("Export.Exception.ShapefileRecord"); Logging.logger().log(Level.WARNING, message, e); @@ -2210,20 +2186,16 @@ protected void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStr xmlWriter.writeEndElement(); // Shapefile } - protected void exportAsKML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException - { - while (this.hasNext()) - { - try - { + protected void exportAsKML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException { + while (this.hasNext()) { + try { ShapefileRecord nr = this.nextRecord(); - if (nr == null) + if (nr == null) { continue; + } nr.exportAsKML(xmlWriter); - } - catch (Exception e) - { + } catch (Exception e) { String message = Logging.getMessage("Export.Exception.ShapefileRecord"); Logging.logger().log(Level.WARNING, message, e); @@ -2232,10 +2204,8 @@ protected void exportAsKML(XMLStreamWriter xmlWriter) throws IOException, XMLStr } } - public void printInfo(boolean printCoordinates) - { - while (this.hasNext()) - { + public void printInfo(boolean printCoordinates) { + while (this.hasNext()) { this.nextRecord().printInfo(printCoordinates); } } diff --git a/src/gov/nasa/worldwind/formats/shapefile/ShapefileLayerFactory.java b/src/gov/nasa/worldwind/formats/shapefile/ShapefileLayerFactory.java index 578a945938..303469d234 100644 --- a/src/gov/nasa/worldwind/formats/shapefile/ShapefileLayerFactory.java +++ b/src/gov/nasa/worldwind/formats/shapefile/ShapefileLayerFactory.java @@ -25,7 +25,6 @@ * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. */ - package gov.nasa.worldwind.formats.shapefile; import gov.nasa.worldwind.*; @@ -42,63 +41,78 @@ import java.util.Map; /** - * A factory that creates {@link gov.nasa.worldwind.layers.Layer} instances from a shapefile layer configuration source - * or a shapefile source. + * A factory that creates {@link gov.nasa.worldwind.layers.Layer} instances from + * a shapefile layer configuration source or a shapefile source. *

      Shapefile Geometry Conversion

      *

      - * Shapefile geometries are mapped to WorldWind objects as shown in the following table. - *
      WorldWind Shapefile Mapping
      Shapefile GeometryWorldWind Object
      Point{@link - * gov.nasa.worldwind.render.PointPlacemark}
      MultiPointList of {@link + * Shapefile geometries are mapped to WorldWind objects as shown in the + * following table. + * + *
      WorldWind Shapefile Mapping
      Shapefile + * GeometryWorldWind Object
      Point{@link + * gov.nasa.worldwind.render.PointPlacemark}
      MultiPointList of {@link * gov.nasa.worldwind.render.PointPlacemark}
      Polyline{@link * gov.nasa.worldwind.formats.shapefile.ShapefilePolylines}
      Polygon{@link * gov.nasa.worldwind.formats.shapefile.ShapefilePolygons}
      *

      - * In addition, if the DBase attributes file associated with the shapefile has an attribute named "height" or "hgt", the - * shapes in the shapefile are mapped to {@link gov.nasa.worldwind.formats.shapefile.ShapefileExtrudedPolygons}. + * In addition, if the DBase attributes file associated with the shapefile has + * an attribute named "height" or "hgt", the shapes in the shapefile are mapped + * to {@link gov.nasa.worldwind.formats.shapefile.ShapefileExtrudedPolygons}. *

      Shapefile Attributes

      *

      - * Shapefiles may have associated with them a DBase attributes file. This class provides a mechanism for mapping - * attribute names in the DBase file to keys assigned to the created shapes. The mapping is specified as key/value - * pairs, the key is the attribute name in the shapefile's DBase attributes file, the value is the key name to attach to - * the created shape to hold the value of the specified attribute. Thus, for example, the value of per-record "NAME" - * fields in the DBase attributes may be mapped to a {@link gov.nasa.worldwind.avlist.AVKey#DISPLAY_NAME} key in the - * av-list of the created shapes corresponding to each record. The mapping's key/value pairs are specified using {@link + * Shapefiles may have associated with them a DBase attributes file. This class + * provides a mechanism for mapping attribute names in the DBase file to keys + * assigned to the created shapes. The mapping is specified as key/value pairs, + * the key is the attribute name in the shapefile's DBase attributes file, the + * value is the key name to attach to the created shape to hold the value of the + * specified attribute. Thus, for example, the value of per-record "NAME" fields + * in the DBase attributes may be mapped to a + * {@link gov.nasa.worldwind.avlist.AVKey#DISPLAY_NAME} key in the av-list of + * the created shapes corresponding to each record. The mapping's key/value + * pairs are specified using {@link * #setDBaseMappings(gov.nasa.worldwind.avlist.AVList)}. *

      - * The rendering attributes applied to the created shapes may be specified to this class, either via the attribute - * accessors of this class or a configuration file passed to {@link #createFromConfigSource(Object, + * The rendering attributes applied to the created shapes may be specified to + * this class, either via the attribute accessors of this class or a + * configuration file passed to {@link #createFromConfigSource(Object, * gov.nasa.worldwind.avlist.AVList)}. *

      - * The key-value attributes and the rendering attributes of certain created shapes may be specified programmatically - * using a ShapefileRenderable.AttributeDelegate. The delegate is called for each shapefile record encountered during - * parsing, after this factory applies its DBase attribute mapping and its default rendering attributes. Currently, - * attribute delegates are called when parsing shapefiles containing polylines, polygons or extruded polygons. - * shapefiles containing points or multi-points ignore the attribute delegate. The delegate is specified using {@link + * The key-value attributes and the rendering attributes of certain created + * shapes may be specified programmatically using a + * ShapefileRenderable.AttributeDelegate. The delegate is called for each + * shapefile record encountered during parsing, after this factory applies its + * DBase attribute mapping and its default rendering attributes. Currently, + * attribute delegates are called when parsing shapefiles containing polylines, + * polygons or extruded polygons. shapefiles containing points or multi-points + * ignore the attribute delegate. The delegate is specified using {@link * #setAttributeDelegate(gov.nasa.worldwind.formats.shapefile.ShapefileRenderable.AttributeDelegate)}. * * @author tag * @version $Id: ShapefileLayerFactory.java 2348 2014-09-25 23:35:46Z dcollins $ */ -public class ShapefileLayerFactory implements Factory, ShapefileRenderable.AttributeDelegate -{ +public class ShapefileLayerFactory implements Factory, ShapefileRenderable.AttributeDelegate { + /** - * Defines an interface for receiving notifications when shapefile parsing completes or encounters an exception. - * This interface's methods are executed on a separate thread created by the factory. Implementations must - * synchronize access to objects that are not thread safe. + * Defines an interface for receiving notifications when shapefile parsing + * completes or encounters an exception. This interface's methods are + * executed on a separate thread created by the factory. Implementations + * must synchronize access to objects that are not thread safe. */ - public interface CompletionCallback - { + public interface CompletionCallback { + /** - * Called when shapefile parsing and geometry conversion completes. Always called before the factory's thread - * terminates. Executed on a separate thread created by the factory. + * Called when shapefile parsing and geometry conversion completes. + * Always called before the factory's thread terminates. Executed on a + * separate thread created by the factory. * * @param result The layer created by this factory. */ void completion(Object result); /** - * Called if exception occurs during shapefile parsing or shapefile geometry conversion. May be called multiple - * times during shapefile parsing. Executed on a separate thread created by the factory. + * Called if exception occurs during shapefile parsing or shapefile + * geometry conversion. May be called multiple times during shapefile + * parsing. Executed on a separate thread created by the factory. * * @param e The exception thrown. */ @@ -113,186 +127,203 @@ public interface CompletionCallback protected ShapefileRenderable.AttributeDelegate attributeDelegate; /** - * Indicates the mappings between shapefile attribute names and av-list keys attached to created shapes. + * Indicates the mappings between shapefile attribute names and av-list keys + * attached to created shapes. * * @return The mappings. */ - public AVList getDBaseMappings() - { + public AVList getDBaseMappings() { return dBaseMappings; } /** - * Specifies the mapping of shapefile attribute names to keys attached to created shapes. For each shapefile record, - * this class assigns the value of the named attribute for that record to the specified key on the shape created for - * that record. The key is associated only when the shapefile record's attributes contains the specified attribute - * name. + * Specifies the mapping of shapefile attribute names to keys attached to + * created shapes. For each shapefile record, this class assigns the value + * of the named attribute for that record to the specified key on the shape + * created for that record. The key is associated only when the shapefile + * record's attributes contains the specified attribute name. * - * @param dBaseMappings The mappings. May be null, in which case no mapping occurs. + * @param dBaseMappings The mappings. May be null, in which case no mapping + * occurs. */ - public void setDBaseMappings(AVList dBaseMappings) - { + public void setDBaseMappings(AVList dBaseMappings) { this.dBaseMappings = dBaseMappings; } /** - * Indicates the normal shape attributes assigned to non-point shapes created by this class. + * Indicates the normal shape attributes assigned to non-point shapes + * created by this class. * * @return The normal attributes assigned to non-point shapes. */ - public ShapeAttributes getNormalShapeAttributes() - { + public ShapeAttributes getNormalShapeAttributes() { return normalShapeAttributes; } /** - * Specifies the normal attributes assigned to non-point shapes created by this class. + * Specifies the normal attributes assigned to non-point shapes created by + * this class. * - * @param normalShapeAttributes The normal attributes assigned to non-point shapes. + * @param normalShapeAttributes The normal attributes assigned to non-point + * shapes. */ - public void setNormalShapeAttributes(ShapeAttributes normalShapeAttributes) - { + public void setNormalShapeAttributes(ShapeAttributes normalShapeAttributes) { this.normalShapeAttributes = normalShapeAttributes; } /** - * Indicates the highlight shape attributes assigned to non-point shapes created by this class. + * Indicates the highlight shape attributes assigned to non-point shapes + * created by this class. * * @return The highlight attributes assigned to non-point shapes. */ - public ShapeAttributes getHighlightShapeAttributes() - { + public ShapeAttributes getHighlightShapeAttributes() { return highlightShapeAttributes; } /** - * Specifies the highlight attributes assigned to non-point shapes created by this class. + * Specifies the highlight attributes assigned to non-point shapes created + * by this class. * - * @param highlightShapeAttributes The highlight attributes assigned to non-point shapes. + * @param highlightShapeAttributes The highlight attributes assigned to + * non-point shapes. */ - public void setHighlightShapeAttributes(ShapeAttributes highlightShapeAttributes) - { + public void setHighlightShapeAttributes(ShapeAttributes highlightShapeAttributes) { this.highlightShapeAttributes = highlightShapeAttributes; } /** - * Indicates the normal attributes assigned to point shapes created by this class. + * Indicates the normal attributes assigned to point shapes created by this + * class. * * @return The normal attributes assigned to point shapes. */ - public PointPlacemarkAttributes getNormalPointAttributes() - { + public PointPlacemarkAttributes getNormalPointAttributes() { return normalPointAttributes; } /** - * Specifies the normal attributes assigned to point shapes created by this class. + * Specifies the normal attributes assigned to point shapes created by this + * class. * - * @param normalPointAttributes The normal attributes assigned to point shapes. + * @param normalPointAttributes The normal attributes assigned to point + * shapes. */ - public void setNormalPointAttributes(PointPlacemarkAttributes normalPointAttributes) - { + public void setNormalPointAttributes(PointPlacemarkAttributes normalPointAttributes) { this.normalPointAttributes = normalPointAttributes; } /** - * Indicates the highlight attributes assigned to point shapes created by this class. + * Indicates the highlight attributes assigned to point shapes created by + * this class. * * @return The highlight attributes assigned to point shapes. */ - public PointPlacemarkAttributes getHighlightPointAttributes() - { + public PointPlacemarkAttributes getHighlightPointAttributes() { return highlightPointAttributes; } /** - * Specifies the highlight attributes assigned to point shapes created by this class. + * Specifies the highlight attributes assigned to point shapes created by + * this class. * - * @param highlightPointAttributes The highlight attributes assigned to point shapes. + * @param highlightPointAttributes The highlight attributes assigned to + * point shapes. */ - public void setHighlightPointAttributes(PointPlacemarkAttributes highlightPointAttributes) - { + public void setHighlightPointAttributes(PointPlacemarkAttributes highlightPointAttributes) { this.highlightPointAttributes = highlightPointAttributes; } /** - * Indicates the attribute delegate called for each shapefile record encountered during parsing. + * Indicates the attribute delegate called for each shapefile record + * encountered during parsing. * * @return The attribute delegate called for each shapefile record. */ - public ShapefileRenderable.AttributeDelegate getAttributeDelegate() - { + public ShapefileRenderable.AttributeDelegate getAttributeDelegate() { return this.attributeDelegate; } /** - * Specifies an attribute delegate to call for each shapefile record encountered during parsing. The delegate is - * called after this factory applies its DBase attribute mapping and its default rendering attributes. + * Specifies an attribute delegate to call for each shapefile record + * encountered during parsing. The delegate is called after this factory + * applies its DBase attribute mapping and its default rendering attributes. *

      - * Currently, attribute delegates are called when parsing shapefiles containing polylines, polygons or extruded - * polygons. shapefiles containing points or multi-points ignore the attribute delegate. + * Currently, attribute delegates are called when parsing shapefiles + * containing polylines, polygons or extruded polygons. shapefiles + * containing points or multi-points ignore the attribute delegate. * - * @param attributeDelegate The attribute delegate to call for each shapefile record. + * @param attributeDelegate The attribute delegate to call for each + * shapefile record. */ - public void setAttributeDelegate(ShapefileRenderable.AttributeDelegate attributeDelegate) - { + public void setAttributeDelegate(ShapefileRenderable.AttributeDelegate attributeDelegate) { this.attributeDelegate = attributeDelegate; } /** - * Applies this factory's DBase attribute mapping and default rendering attributes to the specified records. If an - * attribute delegate has been specified using {@link #setAttributeDelegate(gov.nasa.worldwind.formats.shapefile.ShapefileRenderable.AttributeDelegate)}, + * Applies this factory's DBase attribute mapping and default rendering + * attributes to the specified records. If an attribute delegate has been + * specified using + * {@link #setAttributeDelegate(gov.nasa.worldwind.formats.shapefile.ShapefileRenderable.AttributeDelegate)}, * this calls the attribute delegate before exiting. * - * @param shapefileRecord The shapefile record used to create the ShapefileRenderable.Record. - * @param renderableRecord The ShapefileRenderable.Record to assign attributes for. + * @param shapefileRecord The shapefile record used to create the + * ShapefileRenderable.Record. + * @param renderableRecord The ShapefileRenderable.Record to assign + * attributes for. */ @Override - public void assignAttributes(ShapefileRecord shapefileRecord, ShapefileRenderable.Record renderableRecord) - { - if (this.dBaseMappings != null) - { + public void assignAttributes(ShapefileRecord shapefileRecord, ShapefileRenderable.Record renderableRecord) { + if (this.dBaseMappings != null) { AVList mappings = this.applyMappings(shapefileRecord.getAttributes(), this.dBaseMappings); - if (mappings != null) + if (mappings != null) { renderableRecord.setValues(mappings); + } } - if (this.attributeDelegate != null) - { + if (this.attributeDelegate != null) { this.attributeDelegate.assignAttributes(shapefileRecord, renderableRecord); } } /** - * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general configuration source. The source can be one of - * the following:

      • a {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link - * java.io.InputStream}
      • {@link Element}
      • a {@link String} holding a file name, a name of a resource - * on the classpath, or a string representation of a URL
      + * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general + * configuration source. The source can be one of the following:
      • a + * {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link + * java.io.InputStream}
      • {@link Element}
      • a {@link String} + * holding a file name, a name of a resource on the classpath, or a string + * representation of a URL
      *

      - * The XML configuration file indicated by the source must contain the shapefile location, and may contain elements - * specifying shapefile attribute mappings, shape attributes to assign to created shapes, and layer properties. + * The XML configuration file indicated by the source must contain the + * shapefile location, and may contain elements specifying shapefile + * attribute mappings, shape attributes to assign to created shapes, and + * layer properties. *

      - * This returns with the new layer immediately, but executes shapefile parsing and shapefile geometry conversion on - * a separate thread. Shapefile geometry is added to the returned layer as it becomes available. In order to receive - * notifications when execution completes or if an exception occurs, use {@link #createFromConfigSource(Object, + * This returns with the new layer immediately, but executes shapefile + * parsing and shapefile geometry conversion on a separate thread. Shapefile + * geometry is added to the returned layer as it becomes available. In order + * to receive notifications when execution completes or if an exception + * occurs, use {@link #createFromConfigSource(Object, * gov.nasa.worldwind.avlist.AVList, gov.nasa.worldwind.formats.shapefile.ShapefileLayerFactory.CompletionCallback)} * and specify a completion callback. * - * @param configSource the configuration source. See above for supported types. - * @param params Key/value pairs to associate with the created layer. Values specified here override - * corresponding values specified within the configuration element. + * @param configSource the configuration source. See above for supported + * types. + * @param params Key/value pairs to associate with the created layer. Values + * specified here override corresponding values specified within the + * configuration element. * * @return a Layer, as described by the XML configuration file. * - * @throws IllegalArgumentException if the configuration file name is null or an empty string. - * @throws WWRuntimeException if object creation fails. The exception indicating the source of the failure is - * included as the {@link Exception#initCause(Throwable)}. + * @throws IllegalArgumentException if the configuration file name is null + * or an empty string. + * @throws WWRuntimeException if object creation fails. The exception + * indicating the source of the failure is included as the + * {@link Exception#initCause(Throwable)}. */ @Override - public Object createFromConfigSource(Object configSource, AVList params) - { - if (WWUtil.isEmpty(configSource)) - { + public Object createFromConfigSource(Object configSource, AVList params) { + if (WWUtil.isEmpty(configSource)) { String message = Logging.getMessage("generic.ConfigurationSourceIsInvalid", configSource); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -302,38 +333,47 @@ public Object createFromConfigSource(Object configSource, AVList params) } /** - * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general configuration source. The source can be one of - * the following:

      • a {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link - * java.io.InputStream}
      • {@link Element}
      • a {@link String} holding a file name, a name of a resource - * on the classpath, or a string representation of a URL
      + * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general + * configuration source. The source can be one of the following:
      • a + * {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link + * java.io.InputStream}
      • {@link Element}
      • a {@link String} + * holding a file name, a name of a resource on the classpath, or a string + * representation of a URL
      *

      - * The XML configuration file indicated by the source must contain the shapefile location, and may contain elements - * specifying shapefile attribute mappings, shape attributes to assign to created shapes, and layer properties. + * The XML configuration file indicated by the source must contain the + * shapefile location, and may contain elements specifying shapefile + * attribute mappings, shape attributes to assign to created shapes, and + * layer properties. *

      - * This returns with the new layer immediately, but executes shapefile parsing and shapefile geometry conversion on - * a separate thread. Shapefile geometry is added to the returned layer as it becomes available. Once parsing - * completes, this calls the callback's completion method with the completed layer as the sole argument. + * This returns with the new layer immediately, but executes shapefile + * parsing and shapefile geometry conversion on a separate thread. Shapefile + * geometry is added to the returned layer as it becomes available. Once + * parsing completes, this calls the callback's completion method with the + * completed layer as the sole argument. *

      - * If an exception occurs during execution, this catches the exception and forwards it to the callback's exception - * method. When an exception causes layer parsing or geometry conversion to fail, this calls the callback's + * If an exception occurs during execution, this catches the exception and + * forwards it to the callback's exception method. When an exception causes + * layer parsing or geometry conversion to fail, this calls the callback's * completion method before the separate thread terminates. * - * @param configSource the configuration source. See above for supported types. - * @param params Key/value pairs to associate with the created layer. Values specified here override - * corresponding values specified within the configuration element. - * @param callback a callback to notify when shapefile parsing completes or encounters an exception. May be - * null. + * @param configSource the configuration source. See above for supported + * types. + * @param params Key/value pairs to associate with the created layer. Values + * specified here override corresponding values specified within the + * configuration element. + * @param callback a callback to notify when shapefile parsing completes or + * encounters an exception. May be null. * * @return a Layer, as described by the XML configuration file. * - * @throws IllegalArgumentException if the configuration file name is null or an empty string. - * @throws WWRuntimeException if object creation fails. The exception indicating the source of the failure is - * included as the {@link Exception#initCause(Throwable)}. + * @throws IllegalArgumentException if the configuration file name is null + * or an empty string. + * @throws WWRuntimeException if object creation fails. The exception + * indicating the source of the failure is included as the + * {@link Exception#initCause(Throwable)}. */ - public Object createFromConfigSource(Object configSource, AVList params, CompletionCallback callback) - { - if (WWUtil.isEmpty(configSource)) - { + public Object createFromConfigSource(Object configSource, AVList params, CompletionCallback callback) { + if (WWUtil.isEmpty(configSource)) { String message = Logging.getMessage("generic.ConfigurationSourceIsInvalid", configSource); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -341,21 +381,16 @@ public Object createFromConfigSource(Object configSource, AVList params, Complet Object o = null; - try - { - if (configSource instanceof Element) - { + try { + if (configSource instanceof Element) { o = this.doCreateFromElement((Element) configSource, params, callback); - } - else - { + } else { Document doc = WWXML.openDocument(configSource); - if (doc != null) + if (doc != null) { o = this.doCreateFromElement(doc.getDocumentElement(), params, callback); + } } - } - catch (Exception e) - { + } catch (Exception e) { String msg = Logging.getMessage("generic.CreationFromConfigurationFileFailed", configSource); throw new WWRuntimeException(msg, e); } @@ -364,32 +399,37 @@ public Object createFromConfigSource(Object configSource, AVList params, Complet } /** - * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general shapefile source. The source can be one of the - * following:

      • a {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link - * java.io.InputStream}
      • {@link Shapefile}
      • a {@link String} holding a file name, a name of a - * resource on the classpath, or a string representation of a URL
      + * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general + * shapefile source. The source can be one of the following:
      • a + * {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link + * java.io.InputStream}
      • {@link Shapefile}
      • a {@link String} + * holding a file name, a name of a resource on the classpath, or a string + * representation of a URL
      *

      - * This returns with the new layer immediately, but executes shapefile parsing and shapefile geometry conversion on - * a separate thread. Shapefile geometry is added to the returned layer as it becomes available. In order to receive - * notifications when execution completes or if an exception occurs, use {@link #createFromConfigSource(Object, + * This returns with the new layer immediately, but executes shapefile + * parsing and shapefile geometry conversion on a separate thread. Shapefile + * geometry is added to the returned layer as it becomes available. In order + * to receive notifications when execution completes or if an exception + * occurs, use {@link #createFromConfigSource(Object, * gov.nasa.worldwind.avlist.AVList, gov.nasa.worldwind.formats.shapefile.ShapefileLayerFactory.CompletionCallback)} * and specify a completion callback. *

      - * If the source is a Shapefile instance, it is the responsibility of the caller to close the shapefile after this - * factory completes execution. + * If the source is a Shapefile instance, it is the responsibility of the + * caller to close the shapefile after this factory completes execution. * - * @param shapefileSource the shapefile source. See above for supported types. + * @param shapefileSource the shapefile source. See above for supported + * types. * * @return a Layer that renders the shapefile's contents. * - * @throws IllegalArgumentException if the shapefile file name is null or an empty string. - * @throws WWRuntimeException if object creation fails. The exception indicating the source of the failure is - * included as the {@link Exception#initCause(Throwable)}. + * @throws IllegalArgumentException if the shapefile file name is null or an + * empty string. + * @throws WWRuntimeException if object creation fails. The exception + * indicating the source of the failure is included as the + * {@link Exception#initCause(Throwable)}. */ - public Object createFromShapefileSource(Object shapefileSource) - { - if (WWUtil.isEmpty(shapefileSource)) - { + public Object createFromShapefileSource(Object shapefileSource) { + if (WWUtil.isEmpty(shapefileSource)) { String message = Logging.getMessage("generic.ShapefileSourceIsInvalid", shapefileSource); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -399,36 +439,42 @@ public Object createFromShapefileSource(Object shapefileSource) } /** - * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general shapefile source. The source can be one of the - * following:

      • a {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link - * java.io.InputStream}
      • {@link Shapefile}
      • a {@link String} holding a file name, a name of a - * resource on the classpath, or a string representation of a URL
      + * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general + * shapefile source. The source can be one of the following:
      • a + * {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link + * java.io.InputStream}
      • {@link Shapefile}
      • a {@link String} + * holding a file name, a name of a resource on the classpath, or a string + * representation of a URL
      *

      - * This returns with the new layer immediately, but executes shapefile parsing and shapefile geometry conversion on - * a separate thread. Shapefile geometry is added to the returned layer as it becomes available. Once parsing - * completes, this calls the callback's completion method with the completed layer as the sole argument. + * This returns with the new layer immediately, but executes shapefile + * parsing and shapefile geometry conversion on a separate thread. Shapefile + * geometry is added to the returned layer as it becomes available. Once + * parsing completes, this calls the callback's completion method with the + * completed layer as the sole argument. *

      - * If an exception occurs during execution, this catches the exception and forwards it to the callback's exception - * method. When an exception causes layer parsing or geometry conversion to fail, this calls the callback's + * If an exception occurs during execution, this catches the exception and + * forwards it to the callback's exception method. When an exception causes + * layer parsing or geometry conversion to fail, this calls the callback's * completion method before the separate thread terminates. *

      - * If the source is a Shapefile instance, it is the responsibility of the caller to close the shapefile after this - * factory completes execution. + * If the source is a Shapefile instance, it is the responsibility of the + * caller to close the shapefile after this factory completes execution. * - * @param shapefileSource the shapefile source. See above for supported types. - * @param callback a callback to notify when shapefile parsing completes or encounters an exception. May be - * null. + * @param shapefileSource the shapefile source. See above for supported + * types. + * @param callback a callback to notify when shapefile parsing completes or + * encounters an exception. May be null. * * @return a Layer that renders the shapefile's contents. * - * @throws IllegalArgumentException if the shapefile file name is null or an empty string. - * @throws WWRuntimeException if object creation fails. The exception indicating the source of the failure is - * included as the {@link Exception#initCause(Throwable)}. + * @throws IllegalArgumentException if the shapefile file name is null or an + * empty string. + * @throws WWRuntimeException if object creation fails. The exception + * indicating the source of the failure is included as the + * {@link Exception#initCause(Throwable)}. */ - public Object createFromShapefileSource(Object shapefileSource, CompletionCallback callback) - { - if (WWUtil.isEmpty(shapefileSource)) - { + public Object createFromShapefileSource(Object shapefileSource, CompletionCallback callback) { + if (WWUtil.isEmpty(shapefileSource)) { String message = Logging.getMessage("generic.ShapefileSourceIsInvalid", shapefileSource); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -436,12 +482,9 @@ public Object createFromShapefileSource(Object shapefileSource, CompletionCallba Object o; - try - { + try { o = this.doCreateFromShapefile(shapefileSource, callback); - } - catch (Exception e) - { + } catch (Exception e) { String msg = Logging.getMessage("generic.CreationFromShapefileSourceFailed", shapefileSource); throw new WWRuntimeException(msg, e); } @@ -450,32 +493,34 @@ public Object createFromShapefileSource(Object shapefileSource, CompletionCallba } /** - * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general shapefile layer configuration element. The - * element must contain the shapefile location, and may contain elements specifying shapefile attribute mappings, - * shape attributes to assign to created shapes, and layer properties. + * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general + * shapefile layer configuration element. The element must contain the + * shapefile location, and may contain elements specifying shapefile + * attribute mappings, shape attributes to assign to created shapes, and + * layer properties. * * @param domElement an XML element describing the layer. - * @param params any properties to apply when creating the layer. - * @param callback A callback to notify when shapefile parsing completes or encounters an exception. May be null. + * @param params any properties to apply when creating the layer. + * @param callback A callback to notify when shapefile parsing completes or + * encounters an exception. May be null. * * @return a Layer, as described by the specified description. * * @throws Exception if an exception occurs during creation. */ protected Object doCreateFromElement(Element domElement, AVList params, CompletionCallback callback) - throws Exception - { + throws Exception { String shapefileLocation = WWXML.getText(domElement, "ShapefileLocation"); - if (WWUtil.isEmpty(shapefileLocation)) - { + if (WWUtil.isEmpty(shapefileLocation)) { String msg = Logging.getMessage("SHP.ShapefileLocationUnspecified"); throw new WWRuntimeException(msg); } RenderableLayer layer = new RenderableLayer(); - if (params == null) + if (params == null) { params = new AVListImpl(); + } // Common layer properties. AbstractLayer.getLayerConfigParams(domElement, params); @@ -499,20 +544,24 @@ protected Object doCreateFromElement(Element domElement, AVList params, Completi this.setHighlightPointAttributes(element != null ? this.collectPointAttributes(element) : null); Double d = (Double) params.getValue(AVKey.OPACITY); - if (d != null) + if (d != null) { layer.setOpacity(d); + } d = (Double) params.getValue(AVKey.MAX_ACTIVE_ALTITUDE); - if (d != null) + if (d != null) { layer.setMaxActiveAltitude(d); + } d = (Double) params.getValue(AVKey.MIN_ACTIVE_ALTITUDE); - if (d != null) + if (d != null) { layer.setMinActiveAltitude(d); + } Boolean b = (Boolean) params.getValue(AVKey.PICK_ENABLED); - if (b != null) + if (b != null) { layer.setPickEnabled(b); + } this.createShapefileLayer(shapefileLocation, layer, callback); @@ -520,21 +569,23 @@ protected Object doCreateFromElement(Element domElement, AVList params, Completi } /** - * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general shapefile source. The source can be one of the - * following:

      • a {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link - * java.io.InputStream}
      • {@link Shapefile}
      • a {@link String} holding a file name, a name of a - * resource on the classpath, or a string representation of a URL
      + * Creates a {@link gov.nasa.worldwind.layers.Layer} from a general + * shapefile source. The source can be one of the following:
      • a + * {@link java.net.URL}
      • a {@link java.io.File}
      • a {@link + * java.io.InputStream}
      • {@link Shapefile}
      • a {@link String} + * holding a file name, a name of a resource on the classpath, or a string + * representation of a URL
      * - * @param shapefileSource the shapefile source. See above for supported types. - * @param callback A callback to notify when shapefile parsing completes or encounters an exception. May be - * null. + * @param shapefileSource the shapefile source. See above for supported + * types. + * @param callback A callback to notify when shapefile parsing completes or + * encounters an exception. May be null. * * @return a Layer that renders the shapefile's contents. * * @throws Exception if an exception occurs during creation. */ - protected Object doCreateFromShapefile(Object shapefileSource, CompletionCallback callback) throws Exception - { + protected Object doCreateFromShapefile(Object shapefileSource, CompletionCallback callback) throws Exception { RenderableLayer layer = new RenderableLayer(); this.createShapefileLayer(shapefileSource, layer, callback); @@ -543,69 +594,61 @@ protected Object doCreateFromShapefile(Object shapefileSource, CompletionCallbac } protected void createShapefileLayer(final Object shapefileSource, final RenderableLayer layer, - final CompletionCallback callback) - { - WorldWind.getScheduledTaskService().addTask(new Runnable() - { + final CompletionCallback callback) { + WorldWind.getScheduledTaskService().addTask(new Runnable() { @Override - public void run() - { + public void run() { Shapefile shp = null; - try - { + try { shp = loadShapefile(shapefileSource); assembleShapefileLayer(shp, layer); - } - catch (Exception e) - { - if (callback != null) + } catch (Exception e) { + if (callback != null) { callback.exception(e); - } - finally - { - if (callback != null) + } + } finally { + if (callback != null) { callback.completion(layer); + } if (shapefileSource != shp) // close the shapefile if we created it + { WWIO.closeStream(shp, shapefileSource.toString()); + } } } }); } - protected Shapefile loadShapefile(Object shapefileSource) - { + protected Shapefile loadShapefile(Object shapefileSource) { return (shapefileSource instanceof Shapefile) ? (Shapefile) shapefileSource : new Shapefile(shapefileSource); } - protected void assembleShapefileLayer(Shapefile shp, RenderableLayer layer) - { + protected void assembleShapefileLayer(Shapefile shp, RenderableLayer layer) { this.addRenderablesForShapefile(shp, layer); this.addPropertiesForShapefile(shp, layer); } - protected AVList collectDBaseMappings(Element domElement, XPath xpath) - { - try - { + protected AVList collectDBaseMappings(Element domElement, XPath xpath) { + try { Element[] elements = WWXML.getElements(domElement, "AttributeMapping", xpath); - if (elements == null || elements.length == 0) + if (elements == null || elements.length == 0) { return null; + } AVList attrMappings = new AVListImpl(); - for (Element el : elements) - { + for (Element el : elements) { String prop = xpath.evaluate("@attributeName", el); String value = xpath.evaluate("@mapToKey", el); - if (WWUtil.isEmpty(prop) || WWUtil.isEmpty(value)) + if (WWUtil.isEmpty(prop) || WWUtil.isEmpty(value)) { continue; + } attrMappings.setValue(prop, value); } return attrMappings; - } - catch (XPathExpressionException e) // should not occur, but log just if it does + } catch (XPathExpressionException e) // should not occur, but log just if it does { String message = Logging.getMessage("XML.InvalidXPathExpression", "internal expression"); Logging.logger().log(java.util.logging.Level.WARNING, message, e); @@ -613,119 +656,121 @@ protected AVList collectDBaseMappings(Element domElement, XPath xpath) } } - protected PointPlacemarkAttributes collectPointAttributes(Element attrElement) - { + protected PointPlacemarkAttributes collectPointAttributes(Element attrElement) { XPathFactory xpFactory = XPathFactory.newInstance(); XPath xpath = xpFactory.newXPath(); PointPlacemarkAttributes attributes = new PointPlacemarkAttributes(); String imageAddress = WWXML.getText(attrElement, "ImageAddress", xpath); - if (!WWUtil.isEmpty(imageAddress)) + if (!WWUtil.isEmpty(imageAddress)) { attributes.setImageAddress(imageAddress); + } Double scale = WWXML.getDouble(attrElement, "Scale", xpath); - if (scale != null) + if (scale != null) { attributes.setScale(scale); + } Color imageColor = WWXML.getColor(attrElement, "ImageColor", xpath); - if (imageColor != null) + if (imageColor != null) { attributes.setImageColor(imageColor); + } Double width = WWXML.getDouble(attrElement, "LineWidth", xpath); - if (width != null) + if (width != null) { attributes.setLineWidth(width); + } Double labelScale = WWXML.getDouble(attrElement, "LabelScale", xpath); - if (labelScale != null) + if (labelScale != null) { attributes.setLabelScale(labelScale); + } Color labelColor = WWXML.getColor(attrElement, "LabelColor", xpath); - if (labelColor != null) + if (labelColor != null) { attributes.setLabelMaterial(new Material(labelColor)); + } Color lineColor = WWXML.getColor(attrElement, "LineColor", xpath); - if (lineColor != null) + if (lineColor != null) { attributes.setLabelMaterial(new Material(lineColor)); + } Boolean tf = WWXML.getBoolean(attrElement, "UsePointAsDefaultImage", xpath); - if (tf != null) + if (tf != null) { attributes.setUsePointAsDefaultImage(tf); + } return attributes; } - protected ShapeAttributes collectShapeAttributes(Element attrElement) - { + protected ShapeAttributes collectShapeAttributes(Element attrElement) { XPathFactory xpFactory = XPathFactory.newInstance(); XPath xpath = xpFactory.newXPath(); ShapeAttributes shapeAttributes = new BasicShapeAttributes(); Boolean tf = WWXML.getBoolean(attrElement, "DrawInterior", xpath); - if (tf != null) + if (tf != null) { shapeAttributes.setDrawInterior(tf); + } tf = WWXML.getBoolean(attrElement, "DrawOutline", xpath); - if (tf != null) + if (tf != null) { shapeAttributes.setDrawOutline(tf); + } Double opacity = WWXML.getDouble(attrElement, "InteriorOpacity", xpath); - if (opacity != null) + if (opacity != null) { shapeAttributes.setInteriorOpacity(opacity); + } opacity = WWXML.getDouble(attrElement, "OutlineOpacity", xpath); - if (opacity != null) + if (opacity != null) { shapeAttributes.setOutlineOpacity(opacity); + } Double width = WWXML.getDouble(attrElement, "OutlineWidth", xpath); - if (opacity != null) + if (opacity != null) { shapeAttributes.setOutlineWidth(width); + } Color color = WWXML.getColor(attrElement, "InteriorColor", xpath); - if (color != null) + if (color != null) { shapeAttributes.setInteriorMaterial(new Material(color)); + } color = WWXML.getColor(attrElement, "OutlineColor", xpath); - if (color != null) + if (color != null) { shapeAttributes.setOutlineMaterial(new Material(color)); + } return shapeAttributes; } - protected void addRenderablesForShapefile(Shapefile shp, RenderableLayer layer) - { - if (Shapefile.isPointType(shp.getShapeType())) - { + protected void addRenderablesForShapefile(Shapefile shp, RenderableLayer layer) { + if (Shapefile.isPointType(shp.getShapeType())) { this.addRenderablesForPoints(shp, layer); - } - else if (Shapefile.isMultiPointType(shp.getShapeType())) - { + } else if (Shapefile.isMultiPointType(shp.getShapeType())) { this.addRenderablesForMultiPoints(shp, layer); - } - else if (Shapefile.isPolylineType(shp.getShapeType())) - { + } else if (Shapefile.isPolylineType(shp.getShapeType())) { this.addRenderablesForPolylines(shp, layer); - } - else if (Shapefile.isPolygonType(shp.getShapeType())) - { + } else if (Shapefile.isPolygonType(shp.getShapeType())) { this.addRenderablesForPolygons(shp, layer); - } - else - { + } else { String msg = Logging.getMessage("generic.UnrecognizedShapeType", shp.getShapeType()); throw new WWRuntimeException(msg); } } - protected void addRenderablesForPoints(Shapefile shp, RenderableLayer layer) - { - while (shp.hasNext()) - { + protected void addRenderablesForPoints(Shapefile shp, RenderableLayer layer) { + while (shp.hasNext()) { ShapefileRecord record = shp.nextRecord(); - if (!Shapefile.isPointType(record.getShapeType())) + if (!Shapefile.isPointType(record.getShapeType())) { continue; + } AVList mappings = this.applyMappings(record.getAttributes(), this.dBaseMappings); @@ -734,102 +779,93 @@ protected void addRenderablesForPoints(Shapefile shp, RenderableLayer layer) } } - protected void addRenderablesForMultiPoints(Shapefile shp, RenderableLayer layer) - { - while (shp.hasNext()) - { + protected void addRenderablesForMultiPoints(Shapefile shp, RenderableLayer layer) { + while (shp.hasNext()) { ShapefileRecord record = shp.nextRecord(); - if (!Shapefile.isMultiPointType(record.getShapeType())) + if (!Shapefile.isMultiPointType(record.getShapeType())) { continue; + } AVList mappings = this.applyMappings(record.getAttributes(), this.dBaseMappings); Iterable iterable = ((ShapefileRecordMultiPoint) record).getPoints(0); - for (double[] point : iterable) - { + for (double[] point : iterable) { layer.addRenderable( - this.createPoint(record, point[1], point[0], mappings)); + this.createPoint(record, point[1], point[0], mappings)); } } } @SuppressWarnings({"UnusedDeclaration"}) - protected Renderable createPoint(ShapefileRecord record, double latDegrees, double lonDegrees, AVList mappings) - { + protected Renderable createPoint(ShapefileRecord record, double latDegrees, double lonDegrees, AVList mappings) { PointPlacemark placemark = new PointPlacemark(Position.fromDegrees(latDegrees, lonDegrees, 0)); placemark.setAltitudeMode(WorldWind.CLAMP_TO_GROUND); - if (this.normalPointAttributes != null) + if (this.normalPointAttributes != null) { placemark.setAttributes(this.normalPointAttributes); - if (this.highlightPointAttributes != null) + } + if (this.highlightPointAttributes != null) { placemark.setHighlightAttributes(this.highlightPointAttributes); + } - if (mappings != null) + if (mappings != null) { placemark.setValues(mappings); + } return placemark; } - protected void addRenderablesForPolylines(Shapefile shp, RenderableLayer layer) - { + protected void addRenderablesForPolylines(Shapefile shp, RenderableLayer layer) { ShapefilePolylines shape = new ShapefilePolylines(shp, this.normalShapeAttributes, - this.highlightShapeAttributes, this); + this.highlightShapeAttributes, this); layer.addRenderable(shape); } - protected void addRenderablesForPolygons(Shapefile shp, RenderableLayer layer) - { - if (ShapefileUtils.hasHeightAttribute(shp)) - { + protected void addRenderablesForPolygons(Shapefile shp, RenderableLayer layer) { + if (ShapefileUtils.hasHeightAttribute(shp)) { this.addRenderablesForExtrudedPolygons(shp, layer); - } - else - { + } else { this.addRenderablesForSurfacePolygons(shp, layer); } } - protected void addRenderablesForSurfacePolygons(Shapefile shp, RenderableLayer layer) - { + protected void addRenderablesForSurfacePolygons(Shapefile shp, RenderableLayer layer) { ShapefilePolygons shape = new ShapefilePolygons(shp, this.normalShapeAttributes, - this.highlightShapeAttributes, this); + this.highlightShapeAttributes, this); layer.addRenderable(shape); } - protected void addRenderablesForExtrudedPolygons(Shapefile shp, RenderableLayer layer) - { + protected void addRenderablesForExtrudedPolygons(Shapefile shp, RenderableLayer layer) { ShapefileExtrudedPolygons shape = new ShapefileExtrudedPolygons(shp, this.normalShapeAttributes, - this.highlightShapeAttributes, this); + this.highlightShapeAttributes, this); layer.addRenderable(shape); } - protected AVList applyMappings(DBaseRecord attrRecord, AVList attrMappings) - { - if (attrRecord == null || attrMappings == null) + protected AVList applyMappings(DBaseRecord attrRecord, AVList attrMappings) { + if (attrRecord == null || attrMappings == null) { return null; + } AVList mappings = new AVListImpl(); - for (Map.Entry mapping : attrMappings.getEntries()) - { + for (Map.Entry mapping : attrMappings.getEntries()) { Object attrValue = attrRecord.getValue(mapping.getKey()); - if (attrValue != null) + if (attrValue != null) { mappings.setValue((String) mapping.getValue(), attrValue); + } } return mappings.getEntries().size() > 0 ? mappings : null; } - protected void addPropertiesForShapefile(Shapefile shp, RenderableLayer layer) - { + protected void addPropertiesForShapefile(Shapefile shp, RenderableLayer layer) { if (layer.getValue(AVKey.DISPLAY_NAME) == null) // use the shapefile's display name when the layer is unnamed { layer.setValue(AVKey.DISPLAY_NAME, shp.getValue(AVKey.DISPLAY_NAME)); } - if (shp.getBoundingRectangle() != null) - { + if (shp.getBoundingRectangle() != null) { layer.setValue(AVKey.SECTOR, Sector.fromDegrees(shp.getBoundingRectangle())); } } diff --git a/src/gov/nasa/worldwind/formats/shapefile/ShapefileRecord.java b/src/gov/nasa/worldwind/formats/shapefile/ShapefileRecord.java index 1b1e443dff..9553c1ba2c 100644 --- a/src/gov/nasa/worldwind/formats/shapefile/ShapefileRecord.java +++ b/src/gov/nasa/worldwind/formats/shapefile/ShapefileRecord.java @@ -42,8 +42,8 @@ * @author Patrick Murris * @version $Id: ShapefileRecord.java 2303 2014-09-14 22:33:36Z dcollins $ */ -public abstract class ShapefileRecord -{ +public abstract class ShapefileRecord { + protected Shapefile shapeFile; protected int recordNumber; protected int contentLengthInBytes; @@ -52,39 +52,42 @@ public abstract class ShapefileRecord protected int numberOfParts; protected int numberOfPoints; protected int firstPartNumber; - /** Indicates if the record's point coordinates should be normalized. Defaults to false. */ + /** + * Indicates if the record's point coordinates should be normalized. + * Defaults to false. + */ protected boolean normalizePoints; protected static final int RECORD_HEADER_LENGTH = 8; protected static List measureTypes = new ArrayList(Arrays.asList( - Shapefile.SHAPE_POINT_M, Shapefile.SHAPE_POINT_Z, - Shapefile.SHAPE_MULTI_POINT_M, Shapefile.SHAPE_MULTI_POINT_Z, - Shapefile.SHAPE_POLYLINE_M, Shapefile.SHAPE_POLYLINE_Z, - Shapefile.SHAPE_POLYGON_M, Shapefile.SHAPE_POLYGON_Z + Shapefile.SHAPE_POINT_M, Shapefile.SHAPE_POINT_Z, + Shapefile.SHAPE_MULTI_POINT_M, Shapefile.SHAPE_MULTI_POINT_Z, + Shapefile.SHAPE_POLYLINE_M, Shapefile.SHAPE_POLYLINE_Z, + Shapefile.SHAPE_POLYGON_M, Shapefile.SHAPE_POLYGON_Z )); /** - * Constructs a record instance from the given {@link java.nio.ByteBuffer}. The buffer's current position must be - * the start of the record, and will be the start of the next record when the constructor returns. + * Constructs a record instance from the given {@link java.nio.ByteBuffer}. + * The buffer's current position must be the start of the record, and will + * be the start of the next record when the constructor returns. * * @param shapeFile the parent {@link Shapefile}. - * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read from. + * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read + * from. * - * @throws IllegalArgumentException if any argument is null or otherwise invalid. - * @throws gov.nasa.worldwind.exception.WWRuntimeException - * if the record's shape type does not match that of the shapefile. + * @throws IllegalArgumentException if any argument is null or otherwise + * invalid. + * @throws gov.nasa.worldwind.exception.WWRuntimeException if the record's + * shape type does not match that of the shapefile. */ - public ShapefileRecord(Shapefile shapeFile, ByteBuffer buffer) - { - if (shapeFile == null) - { + public ShapefileRecord(Shapefile shapeFile, ByteBuffer buffer) { + if (shapeFile == null) { String message = Logging.getMessage("nullValue.ShapefileIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (buffer == null) - { + if (buffer == null) { String message = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -92,12 +95,9 @@ public ShapefileRecord(Shapefile shapeFile, ByteBuffer buffer) // Save the buffer's current position. int pos = buffer.position(); - try - { + try { this.readFromBuffer(shapeFile, buffer); - } - finally - { + } finally { // Move to the end of the record. buffer.position(pos + this.contentLengthInBytes + RECORD_HEADER_LENGTH); } @@ -108,8 +108,7 @@ public ShapefileRecord(Shapefile shapeFile, ByteBuffer buffer) * * @return the shapefile containing this record. */ - public Shapefile getShapeFile() - { + public Shapefile getShapeFile() { return this.shapeFile; } @@ -118,18 +117,17 @@ public Shapefile getShapeFile() * * @return the record's ordinal position in the shapefile. */ - public int getRecordNumber() - { + public int getRecordNumber() { return this.recordNumber; } /** * Returns the record's shape type. * - * @return the record' shape type. See {@link Shapefile} for a list of the defined shape types. + * @return the record' shape type. See {@link Shapefile} for a list of the + * defined shape types. */ - public String getShapeType() - { + public String getShapeType() { return this.shapeType; } @@ -138,8 +136,7 @@ public String getShapeType() * * @return the record's attributes. */ - public DBaseRecord getAttributes() - { + public DBaseRecord getAttributes() { return this.attributes; } @@ -148,8 +145,7 @@ public DBaseRecord getAttributes() * * @param attributes the shapefile's attributes. May be null. */ - public void setAttributes(DBaseRecord attributes) - { + public void setAttributes(DBaseRecord attributes) { this.attributes = attributes; } @@ -158,8 +154,7 @@ public void setAttributes(DBaseRecord attributes) * * @return the number of parts in the record. */ - public int getNumberOfParts() - { + public int getNumberOfParts() { return this.numberOfParts; } @@ -168,8 +163,7 @@ public int getNumberOfParts() * * @return the first part number in the record. */ - public int getFirstPartNumber() - { + public int getFirstPartNumber() { return this.firstPartNumber; } @@ -178,8 +172,7 @@ public int getFirstPartNumber() * * @return the last part number in the record. */ - public int getLastPartNumber() - { + public int getLastPartNumber() { return this.firstPartNumber + this.numberOfParts - 1; } @@ -188,22 +181,20 @@ public int getLastPartNumber() * * @return the number of points in the record. */ - public int getNumberOfPoints() - { + public int getNumberOfPoints() { return this.numberOfPoints; } /** * Returns the number of points in a specified part of the record. * - * @param partNumber the part number for which to return the number of points. + * @param partNumber the part number for which to return the number of + * points. * * @return the number of points in the specified part. */ - public int getNumberOfPoints(int partNumber) - { - if (partNumber < 0 || partNumber >= this.getNumberOfParts()) - { + public int getNumberOfPoints(int partNumber) { + if (partNumber < 0 || partNumber >= this.getNumberOfParts()) { String message = Logging.getMessage("generic.indexOutOfRange", partNumber); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -214,17 +205,16 @@ public int getNumberOfPoints(int partNumber) } /** - * Returns the {@link gov.nasa.worldwind.util.VecBuffer} holding the X and Y points of a specified part. + * Returns the {@link gov.nasa.worldwind.util.VecBuffer} holding the X and Y + * points of a specified part. * * @param partNumber the part for which to return the point buffer. * - * @return the buffer holding the part's points. The points are ordered X0,Y0,X1,Y1,...Xn-1,Yn-1, where "n" is the - * number of points in the part. + * @return the buffer holding the part's points. The points are ordered + * X0,Y0,X1,Y1,...Xn-1,Yn-1, where "n" is the number of points in the part. */ - public VecBuffer getPointBuffer(int partNumber) - { - if (partNumber < 0 || partNumber >= this.getNumberOfParts()) - { + public VecBuffer getPointBuffer(int partNumber) { + if (partNumber < 0 || partNumber >= this.getNumberOfParts()) { String message = Logging.getMessage("generic.indexOutOfRange", partNumber); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -235,51 +225,56 @@ public VecBuffer getPointBuffer(int partNumber) } /** - * Returns the {@link gov.nasa.worldwind.util.CompoundVecBuffer} holding all the X and Y points for this record. The - * returned buffer contains one sub-buffer for each of this record's parts. The coordinates for each part are - * referenced by invoking {@link gov.nasa.worldwind.util.CompoundVecBuffer#subBuffer(int)}, where the index is one - * of this record's part IDs, starting with 0 and ending with {@link #getNumberOfParts()} - 1 - * (inclusive). + * Returns the {@link gov.nasa.worldwind.util.CompoundVecBuffer} holding all + * the X and Y points for this record. The returned buffer contains one + * sub-buffer for each of this record's parts. The coordinates for each part + * are referenced by invoking + * {@link gov.nasa.worldwind.util.CompoundVecBuffer#subBuffer(int)}, where + * the index is one of this record's part IDs, starting with 0 and ending + * with {@link #getNumberOfParts()} - 1 (inclusive). * * @return a CompoundVecBuffer that holds this record's coordinate data. */ - public CompoundVecBuffer getCompoundPointBuffer() - { + public CompoundVecBuffer getCompoundPointBuffer() { return this.getShapeFile().getPointBuffer().slice(this.getFirstPartNumber(), this.getLastPartNumber()); } /** - * Returns a four-element array containing this record's bounding rectangle, or null if this record has no bounding - * rectangle. + * Returns a four-element array containing this record's bounding rectangle, + * or null if this record has no bounding rectangle. *

      - * The returned array is ordered as follows: minimum Y, maximum Y, minimum X, and maximum X. If the Shapefile's - * coordinate system is geographic, the elements can be interpreted as angular degrees in the order minimum + * The returned array is ordered as follows: minimum Y, maximum Y, minimum + * X, and maximum X. If the Shapefile's coordinate system is geographic, the + * elements can be interpreted as angular degrees in the order minimum * latitude, maximum latitude, minimum longitude, and maximum longitude. * - * @return the record's bounding rectangle, or null to indicate that this record does not have a bounding - * rectangle. + * @return the record's bounding rectangle, or null to indicate that this + * record does not have a bounding rectangle. */ public abstract double[] getBoundingRectangle(); /** - * Reads and parses subclass-specific contents of a shapefile record from a specified buffer. The buffer's current - * position must be the start of the subclass' unique contents and will be the start of the next record when the - * constructor returns. + * Reads and parses subclass-specific contents of a shapefile record from a + * specified buffer. The buffer's current position must be the start of the + * subclass' unique contents and will be the start of the next record when + * the constructor returns. * * @param shapefile the containing {@link Shapefile}. - * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read from. + * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read + * from. */ protected abstract void doReadFromBuffer(Shapefile shapefile, ByteBuffer buffer); /** - * Reads and parses the contents of a shapefile record from a specified buffer. The buffer's current position must - * be the start of the record and will be the start of the next record when the constructor returns. + * Reads and parses the contents of a shapefile record from a specified + * buffer. The buffer's current position must be the start of the record and + * will be the start of the next record when the constructor returns. * * @param shapefile the containing {@link Shapefile}. - * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read from. + * @param buffer the shapefile record {@link java.nio.ByteBuffer} to read + * from. */ - protected void readFromBuffer(Shapefile shapefile, ByteBuffer buffer) - { + protected void readFromBuffer(Shapefile shapefile, ByteBuffer buffer) { // Read record number and record length - big endian. buffer.order(ByteOrder.BIG_ENDIAN); this.recordNumber = buffer.getInt(); @@ -298,31 +293,31 @@ protected void readFromBuffer(Shapefile shapefile, ByteBuffer buffer) } /** - * Verifies that the record's shape type matches the expected one, typically that of the shapefile. All non-null - * records in a Shapefile must be of the same type. Throws an exception if the types do not match and the shape type - * is not {@link Shapefile#SHAPE_NULL}. Records of type SHAPE_NULL are always valid, and - * may appear in any Shapefile. + * Verifies that the record's shape type matches the expected one, typically + * that of the shapefile. All non-null records in a Shapefile must be of the + * same type. Throws an exception if the types do not match and the shape + * type is not {@link Shapefile#SHAPE_NULL}. Records of type + * SHAPE_NULL are always valid, and may appear in any + * Shapefile. *

      - * For details, see the ESRI Shapefile specification at , + * For details, see the ESRI Shapefile specification at + * , * pages 4 and 5. * * @param shapefile the shapefile. * @param shapeType the record's shape type. * - * @throws WWRuntimeException if the shape types do not match. + * @throws WWRuntimeException if the shape types do not match. * @throws IllegalArgumentException if the specified shape type is null. */ - protected void validateShapeType(Shapefile shapefile, String shapeType) - { - if (shapeType == null) - { + protected void validateShapeType(Shapefile shapefile, String shapeType) { + if (shapeType == null) { String message = Logging.getMessage("nullValue.ShapeType"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (!shapeType.equals(shapefile.getShapeType()) && !shapeType.equals(Shapefile.SHAPE_NULL)) - { + if (!shapeType.equals(shapefile.getShapeType()) && !shapeType.equals(Shapefile.SHAPE_NULL)) { String message = Logging.getMessage("SHP.UnsupportedShapeType", shapeType); Logging.logger().severe(message); throw new WWRuntimeException(message); @@ -330,13 +325,13 @@ protected void validateShapeType(Shapefile shapefile, String shapeType) } /** - * Indicates whether the record is a shape type capable of containing optional measure values. Does not indicate - * whether the record actually contains measure values. + * Indicates whether the record is a shape type capable of containing + * optional measure values. Does not indicate whether the record actually + * contains measure values. * * @return true if the record may contain measure values. */ - protected boolean isMeasureType() - { + protected boolean isMeasureType() { return Shapefile.isMeasureType(this.getShapeType()); } @@ -345,146 +340,141 @@ protected boolean isMeasureType() * * @return true if the record is a type containing Z values. */ - protected boolean isZType() - { + protected boolean isZType() { return Shapefile.isZType(this.getShapeType()); } /** - * Indicates whether this is a null record. When true, this record may be cast to a ShapefileRecordNull by calling - * {@link #asNullRecord()}. + * Indicates whether this is a null record. When true, this record may be + * cast to a ShapefileRecordNull by calling {@link #asNullRecord()}. * * @return true if this is a null record, otherwise false. */ - public boolean isNullRecord() - { + public boolean isNullRecord() { return false; } /** - * Indicates whether this is a point record. When true, this record may be cast to a ShapefileRecordPoint by calling - * {@link #asPointRecord()}. + * Indicates whether this is a point record. When true, this record may be + * cast to a ShapefileRecordPoint by calling {@link #asPointRecord()}. * * @return true if this is a point record, otherwise false. */ - public boolean isPointRecord() - { + public boolean isPointRecord() { return false; } /** - * Indicates whether this is a multi point record. When true, this record may be cast to a ShapefileRecordMultiPoint - * by calling {@link #asPointRecord()}. + * Indicates whether this is a multi point record. When true, this record + * may be cast to a ShapefileRecordMultiPoint by calling + * {@link #asPointRecord()}. * * @return true if this is a multi point record, otherwise false. */ - public boolean isMultiPointRecord() - { + public boolean isMultiPointRecord() { return false; } /** - * Indicates whether this is a polyline record. When true, this record may be cast to a ShapefileRecordPolyline by - * calling {@link #asPolylineRecord()}. + * Indicates whether this is a polyline record. When true, this record may + * be cast to a ShapefileRecordPolyline by calling + * {@link #asPolylineRecord()}. * * @return true if this is a polyline record, otherwise false. */ - public boolean isPolylineRecord() - { + public boolean isPolylineRecord() { return false; } /** - * Indicates whether this is a polygon record. When true, this record may be cast to a ShapefileRecordPolygon by - * calling {@link #asPolygonRecord()}. + * Indicates whether this is a polygon record. When true, this record may be + * cast to a ShapefileRecordPolygon by calling {@link #asPolygonRecord()}. * * @return true if this is a polygon record, otherwise false. */ - public boolean isPolygonRecord() - { + public boolean isPolygonRecord() { return false; } /** - * Returns this record as a ShapefileRecordNull. This results in a class cast exception if this is not a null - * record. Check this record's type using {@link #isNullRecord()} prior to calling this method. + * Returns this record as a ShapefileRecordNull. This results in a class + * cast exception if this is not a null record. Check this record's type + * using {@link #isNullRecord()} prior to calling this method. * * @return this record cast as a ShapefileRecordNull. */ - public ShapefileRecordNull asNullRecord() - { + public ShapefileRecordNull asNullRecord() { return (ShapefileRecordNull) this; } /** - * Returns this record as a ShapefileRecordPoint. This results in a class cast exception if this is not a point - * record. Check this record's type using {@link #isPointRecord()} prior to calling this method. + * Returns this record as a ShapefileRecordPoint. This results in a class + * cast exception if this is not a point record. Check this record's type + * using {@link #isPointRecord()} prior to calling this method. * * @return this record cast as a ShapefileRecordPoint. */ - public ShapefileRecordPoint asPointRecord() - { + public ShapefileRecordPoint asPointRecord() { return (ShapefileRecordPoint) this; } /** - * Returns this record as a ShapefileRecordMultiPoint. This results in a class cast exception if this is not a multi - * point record. Check this record's type using {@link #isMultiPointRecord()} prior to calling this method. + * Returns this record as a ShapefileRecordMultiPoint. This results in a + * class cast exception if this is not a multi point record. Check this + * record's type using {@link #isMultiPointRecord()} prior to calling this + * method. * * @return this record cast as a ShapefileRecordMultiPoint. */ - public ShapefileRecordMultiPoint asMultiPointRecord() - { + public ShapefileRecordMultiPoint asMultiPointRecord() { return (ShapefileRecordMultiPoint) this; } /** - * Returns this record as a ShapefileRecordPolyline. This results in a class cast exception if this is not a - * polyline record. Check this record's type using {@link #isPolylineRecord()} prior to calling this method. + * Returns this record as a ShapefileRecordPolyline. This results in a class + * cast exception if this is not a polyline record. Check this record's type + * using {@link #isPolylineRecord()} prior to calling this method. * * @return this record cast as a ShapefileRecordPolyline. */ - public ShapefileRecordPolyline asPolylineRecord() - { + public ShapefileRecordPolyline asPolylineRecord() { return (ShapefileRecordPolyline) this; } /** - * Returns this record as a ShapefileRecordPolygon. This results in a class cast exception if this is not a polygon - * record. Check this record's type using {@link #isPolygonRecord()} prior to calling this method. + * Returns this record as a ShapefileRecordPolygon. This results in a class + * cast exception if this is not a polygon record. Check this record's type + * using {@link #isPolygonRecord()} prior to calling this method. * * @return this record cast as a ShapefileRecordPolygon. */ - public ShapefileRecordPolygon asPolygonRecord() - { + public ShapefileRecordPolygon asPolygonRecord() { return (ShapefileRecordPolygon) this; } /** * Returns whether the record's point coordinates should be normalized. * - * @return true if the record's points should be normalized; false otherwise. + * @return true if the record's points should be normalized; + * false otherwise. */ - public boolean isNormalizePoints() - { + public boolean isNormalizePoints() { return this.normalizePoints; } /** - * Specifies if the record's point coordinates should be normalized. Defaults to false. + * Specifies if the record's point coordinates should be normalized. + * Defaults to false. * - * @param normalizePoints true if the record's points should be normalized; false - * otherwise. + * @param normalizePoints true if the record's points should be + * normalized; false otherwise. */ - public void setNormalizePoints(boolean normalizePoints) - { + public void setNormalizePoints(boolean normalizePoints) { this.normalizePoints = normalizePoints; } - public void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException - { - if (xmlWriter == null) - { + public void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException { + if (xmlWriter == null) { String message = Logging.getMessage("Export.UnsupportedOutputObject"); Logging.logger().warning(message); throw new IllegalArgumentException(message); @@ -498,8 +488,7 @@ public void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStream xmlWriter.writeAttribute("points", Integer.toString(this.getNumberOfPoints())); xmlWriter.writeCharacters("\n"); - for (Map.Entry a : this.getAttributes().getEntries()) - { + for (Map.Entry a : this.getAttributes().getEntries()) { xmlWriter.writeStartElement("Attribute"); xmlWriter.writeAttribute("name", a.getKey() != null ? a.getKey().toString() : ""); @@ -509,11 +498,9 @@ public void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStream xmlWriter.writeCharacters("\n"); } - if (this.getNumberOfParts() > 0) - { + if (this.getNumberOfParts() > 0) { VecBuffer vb = this.getPointBuffer(0); - for (LatLon ll : vb.getLocations()) - { + for (LatLon ll : vb.getLocations()) { xmlWriter.writeStartElement("Point"); xmlWriter.writeAttribute("x", Double.toString(ll.getLatitude().degrees)); xmlWriter.writeAttribute("y", Double.toString(ll.getLongitude().degrees)); @@ -523,49 +510,47 @@ public void exportAsXML(XMLStreamWriter xmlWriter) throws IOException, XMLStream } // TODO: export record-type specific fields - xmlWriter.writeEndElement(); // Record } /** - * Export the record as KML. This implementation does nothing; subclasses may override this method to provide KML - * export. + * Export the record as KML. This implementation does nothing; subclasses + * may override this method to provide KML export. * * @param xmlWriter Writer to receive KML. * - * @throws IOException If an exception occurs while writing the KML - * @throws XMLStreamException If an exception occurs while exporting the data. + * @throws IOException If an exception occurs while writing the KML + * @throws XMLStreamException If an exception occurs while exporting the + * data. */ - public void exportAsKML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException - { + public void exportAsKML(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException { } - public void printInfo(boolean printCoordinates) - { + public void printInfo(boolean printCoordinates) { System.out.printf("%d, %s: %d parts, %d points", this.getRecordNumber(), this.getShapeType(), - this.getNumberOfParts(), this.getNumberOfPoints()); - for (Map.Entry a : this.getAttributes().getEntries()) - { - if (a.getKey() != null) + this.getNumberOfParts(), this.getNumberOfPoints()); + for (Map.Entry a : this.getAttributes().getEntries()) { + if (a.getKey() != null) { System.out.printf(", %s", a.getKey()); - if (a.getValue() != null) + } + if (a.getValue() != null) { System.out.printf(", %s", a.getValue()); + } } System.out.println(); System.out.print("\tAttributes: "); - for (Map.Entry entry : this.getAttributes().getEntries()) - { + for (Map.Entry entry : this.getAttributes().getEntries()) { System.out.printf("%s = %s, ", entry.getKey(), entry.getValue()); } System.out.println(); - if (!printCoordinates) + if (!printCoordinates) { return; + } VecBuffer vb = this.getPointBuffer(0); - for (LatLon ll : vb.getLocations()) - { + for (LatLon ll : vb.getLocations()) { System.out.printf("\t%f, %f\n", ll.getLatitude().degrees, ll.getLongitude().degrees); } } diff --git a/src/gov/nasa/worldwind/geom/Sector.java b/src/gov/nasa/worldwind/geom/Sector.java index 6a5d1fd584..5b1e73092c 100644 --- a/src/gov/nasa/worldwind/geom/Sector.java +++ b/src/gov/nasa/worldwind/geom/Sector.java @@ -39,20 +39,28 @@ import java.util.*; /** - * Sector represents a rectangular region of latitude and longitude. The region is defined by four angles: - * its minimum and maximum latitude, its minimum and maximum longitude. The angles are assumed to be normalized to +/- - * 90 degrees latitude and +/- 180 degrees longitude. The minimums and maximums are relative to these ranges, e.g., -80 - * is less than 20. Behavior of the class is undefined for angles outside these ranges. Normalization is not performed - * on the angles by this class, nor is it verified by the class' methods. See {@link Angle} for a description of - * specifying angles.

      Sector instances are immutable.

      + * Sector represents a rectangular region of latitude and + * longitude. The region is defined by four angles: its minimum and maximum + * latitude, its minimum and maximum longitude. The angles are assumed to be + * normalized to +/- 90 degrees latitude and +/- 180 degrees longitude. The + * minimums and maximums are relative to these ranges, e.g., -80 is less than + * 20. Behavior of the class is undefined for angles outside these ranges. + * Normalization is not performed on the angles by this class, nor is it + * verified by the class' methods. See {@link Angle} for a description of + * specifying angles. + *

      + * Sector instances are immutable.

      * * @author Tom Gaskins * @version $Id: Sector.java 2397 2014-10-28 17:13:04Z dcollins $ * @see Angle */ -public class Sector implements Cacheable, Comparable, Iterable -{ - /** A Sector of latitude [-90 degrees, + 90 degrees] and longitude [-180 degrees, + 180 degrees]. */ +public class Sector implements Cacheable, Comparable, Iterable { + + /** + * A Sector of latitude [-90 degrees, + 90 degrees] and + * longitude [-180 degrees, + 180 degrees]. + */ public static final Sector FULL_SPHERE = new Sector(Angle.NEG90, Angle.POS90, Angle.NEG180, Angle.POS180); public static final Sector EMPTY_SECTOR = new Sector(Angle.ZERO, Angle.ZERO, Angle.ZERO, Angle.ZERO); @@ -64,73 +72,79 @@ public class Sector implements Cacheable, Comparable, Iterable private final Angle deltaLon; /** - * Creates a new Sector and initializes it to the specified angles. The angles are assumed to be - * normalized to +/- 90 degrees latitude and +/- 180 degrees longitude, but this method does not verify that. + * Creates a new Sector and initializes it to the specified + * angles. The angles are assumed to be normalized to +/- 90 degrees + * latitude and +/- 180 degrees longitude, but this method does not verify + * that. * - * @param minLatitude the sector's minimum latitude in degrees. - * @param maxLatitude the sector's maximum latitude in degrees. + * @param minLatitude the sector's minimum latitude in degrees. + * @param maxLatitude the sector's maximum latitude in degrees. * @param minLongitude the sector's minimum longitude in degrees. * @param maxLongitude the sector's maximum longitude in degrees. * * @return the new Sector */ public static Sector fromDegrees(double minLatitude, double maxLatitude, double minLongitude, - double maxLongitude) - { + double maxLongitude) { return new Sector(Angle.fromDegrees(minLatitude), Angle.fromDegrees(maxLatitude), Angle.fromDegrees( - minLongitude), Angle.fromDegrees(maxLongitude)); + minLongitude), Angle.fromDegrees(maxLongitude)); } /** - * Creates a new Sector and initializes it to the specified angles. The angles are assumed to be - * normalized to +/- 90 degrees latitude and +/- 180 degrees longitude, but this method does not verify that. + * Creates a new Sector and initializes it to the specified + * angles. The angles are assumed to be normalized to +/- 90 degrees + * latitude and +/- 180 degrees longitude, but this method does not verify + * that. * - * @param minLatitude the sector's minimum latitude in degrees. - * @param maxLatitude the sector's maximum latitude in degrees. + * @param minLatitude the sector's minimum latitude in degrees. + * @param maxLatitude the sector's maximum latitude in degrees. * @param minLongitude the sector's minimum longitude in degrees. * @param maxLongitude the sector's maximum longitude in degrees. * * @return the new Sector */ public static Sector fromDegreesAndClamp(double minLatitude, double maxLatitude, double minLongitude, - double maxLongitude) - { - if (minLatitude < -90) + double maxLongitude) { + if (minLatitude < -90) { minLatitude = -90; - if (maxLatitude > 90) + } + if (maxLatitude > 90) { maxLatitude = 90; - if (minLongitude < -180) + } + if (minLongitude < -180) { minLongitude = -180; - if (maxLongitude > 180) + } + if (maxLongitude > 180) { maxLongitude = 180; + } return new Sector(Angle.fromDegrees(minLatitude), Angle.fromDegrees(maxLatitude), Angle.fromDegrees( - minLongitude), Angle.fromDegrees(maxLongitude)); + minLongitude), Angle.fromDegrees(maxLongitude)); } /** - * Creates a new Sector and initializes it to angles in the specified array. The array is assumed to - * hold four elements containing the Sector's angles, and must be ordered as follows: minimum latitude, maximum - * latitude, minimum longitude, and maximum longitude. Additionally, the angles are assumed to be normalized to +/- - * 90 degrees latitude and +/- 180 degrees longitude, but this method does not verify that. + * Creates a new Sector and initializes it to angles in the + * specified array. The array is assumed to hold four elements containing + * the Sector's angles, and must be ordered as follows: minimum latitude, + * maximum latitude, minimum longitude, and maximum longitude. Additionally, + * the angles are assumed to be normalized to +/- 90 degrees latitude and + * +/- 180 degrees longitude, but this method does not verify that. * * @param array the array of angles in degrees. * * @return he new Sector * - * @throws IllegalArgumentException if array is null or if its length is less than 4. + * @throws IllegalArgumentException if array is null or if its + * length is less than 4. */ - public static Sector fromDegrees(double[] array) - { - if (array == null) - { + public static Sector fromDegrees(double[] array) { + if (array == null) { String message = Logging.getMessage("nullValue.ArrayIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (array.length < 4) - { + if (array.length < 4) { String message = Logging.getMessage("generic.ArrayInvalidLength", array.length); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -140,69 +154,70 @@ public static Sector fromDegrees(double[] array) } /** - * Creates a new Sector and initializes it to the angles resulting from the given {@link - * java.awt.geom.Rectangle2D} in degrees lat-lon coordinates where x corresponds to longitude and y to latitude. The - * resulting geographic angles are assumed to be normalized to +/- 90 degrees latitude and +/- 180 degrees - * longitude, but this method does not verify that. + * Creates a new Sector and initializes it to the angles + * resulting from the given {@link + * java.awt.geom.Rectangle2D} in degrees lat-lon coordinates where x + * corresponds to longitude and y to latitude. The resulting geographic + * angles are assumed to be normalized to +/- 90 degrees latitude and +/- + * 180 degrees longitude, but this method does not verify that. * * @param rectangle the sector's rectangle in degrees lat-lon coordinates. * * @return the new Sector */ - public static Sector fromDegrees(java.awt.geom.Rectangle2D rectangle) - { + public static Sector fromDegrees(java.awt.geom.Rectangle2D rectangle) { return fromDegrees(rectangle.getY(), rectangle.getMaxY(), rectangle.getX(), rectangle.getMaxX()); } /** - * Creates a new Sector and initializes it to the specified angles. The angles are assumed to be - * normalized to +/- \u03c0/2 radians latitude and +/- \u03c0 radians longitude, but this method does not verify - * that. + * Creates a new Sector and initializes it to the specified + * angles. The angles are assumed to be normalized to +/- \u03c0/2 radians + * latitude and +/- \u03c0 radians longitude, but this method does not + * verify that. * - * @param minLatitude the sector's minimum latitude in radians. - * @param maxLatitude the sector's maximum latitude in radians. + * @param minLatitude the sector's minimum latitude in radians. + * @param maxLatitude the sector's maximum latitude in radians. * @param minLongitude the sector's minimum longitude in radians. * @param maxLongitude the sector's maximum longitude in radians. * * @return the new Sector */ public static Sector fromRadians(double minLatitude, double maxLatitude, double minLongitude, - double maxLongitude) - { + double maxLongitude) { return new Sector(Angle.fromRadians(minLatitude), Angle.fromRadians(maxLatitude), Angle.fromRadians( - minLongitude), Angle.fromRadians(maxLongitude)); + minLongitude), Angle.fromRadians(maxLongitude)); } /** - * Returns a geographic Sector which bounds the specified UTM rectangle. The UTM rectangle is located in specified - * UTM zone and hemisphere. + * Returns a geographic Sector which bounds the specified UTM rectangle. The + * UTM rectangle is located in specified UTM zone and hemisphere. * - * @param zone the UTM zone. - * @param hemisphere the UTM hemisphere, either {@link gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link + * @param zone the UTM zone. + * @param hemisphere the UTM hemisphere, either + * {@link gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link * gov.nasa.worldwind.avlist.AVKey#SOUTH}. - * @param minEasting the minimum UTM easting, in meters. - * @param maxEasting the maximum UTM easting, in meters. + * @param minEasting the minimum UTM easting, in meters. + * @param maxEasting the maximum UTM easting, in meters. * @param minNorthing the minimum UTM northing, in meters. * @param maxNorthing the maximum UTM northing, in meters. * * @return a Sector that bounds the specified UTM rectangle. * - * @throws IllegalArgumentException if zone is outside the range 1-60, if hemisphere is - * null, or if hemisphere is not one of {@link - * gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link gov.nasa.worldwind.avlist.AVKey#SOUTH}. + * @throws IllegalArgumentException if zone is outside the + * range 1-60, if hemisphere is null, or if + * hemisphere is not one of {@link + * gov.nasa.worldwind.avlist.AVKey#NORTH} or + * {@link gov.nasa.worldwind.avlist.AVKey#SOUTH}. */ public static Sector fromUTMRectangle(int zone, String hemisphere, double minEasting, double maxEasting, - double minNorthing, double maxNorthing) - { - if (zone < 1 || zone > 60) - { + double minNorthing, double maxNorthing) { + if (zone < 1 || zone > 60) { String message = Logging.getMessage("generic.ZoneIsInvalid", zone); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (!AVKey.NORTH.equals(hemisphere) && !AVKey.SOUTH.equals(hemisphere)) - { + if (!AVKey.NORTH.equals(hemisphere) && !AVKey.SOUTH.equals(hemisphere)) { String message = Logging.getMessage("generic.HemisphereIsInvalid", hemisphere); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -216,17 +231,16 @@ public static Sector fromUTMRectangle(int zone, String hemisphere, double minEas return boundingSector(Arrays.asList(ll, lr, ur, ul)); } - public static Sector boundingSector(java.util.Iterator positions) - { - if (positions == null) - { + public static Sector boundingSector(java.util.Iterator positions) { + if (positions == null) { String message = Logging.getMessage("nullValue.TracksPointsIteratorNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (!positions.hasNext()) + if (!positions.hasNext()) { return EMPTY_SECTOR; + } TrackPoint position = positions.next(); double minLat = position.getLatitude(); @@ -234,71 +248,72 @@ public static Sector boundingSector(java.util.Iterator positions) double maxLat = minLat; double maxLon = minLon; - while (positions.hasNext()) - { + while (positions.hasNext()) { TrackPoint p = positions.next(); double lat = p.getLatitude(); - if (lat < minLat) + if (lat < minLat) { minLat = lat; - else if (lat > maxLat) + } else if (lat > maxLat) { maxLat = lat; + } double lon = p.getLongitude(); - if (lon < minLon) + if (lon < minLon) { minLon = lon; - else if (lon > maxLon) + } else if (lon > maxLon) { maxLon = lon; + } } return Sector.fromDegrees(minLat, maxLat, minLon, maxLon); } - public static Sector boundingSector(Iterable locations) - { - if (locations == null) - { + public static Sector boundingSector(Iterable locations) { + if (locations == null) { String message = Logging.getMessage("nullValue.PositionsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (!locations.iterator().hasNext()) + if (!locations.iterator().hasNext()) { return EMPTY_SECTOR; // TODO: should be returning null - + } double minLat = Angle.POS90.getDegrees(); double minLon = Angle.POS180.getDegrees(); double maxLat = Angle.NEG90.getDegrees(); double maxLon = Angle.NEG180.getDegrees(); - for (LatLon p : locations) - { + for (LatLon p : locations) { double lat = p.getLatitude().getDegrees(); - if (lat < minLat) + if (lat < minLat) { minLat = lat; - if (lat > maxLat) + } + if (lat > maxLat) { maxLat = lat; + } double lon = p.getLongitude().getDegrees(); - if (lon < minLon) + if (lon < minLon) { minLon = lon; - if (lon > maxLon) + } + if (lon > maxLon) { maxLon = lon; + } } return Sector.fromDegrees(minLat, maxLat, minLon, maxLon); } - public static Sector[] splitBoundingSectors(Iterable locations) - { - if (locations == null) - { + public static Sector[] splitBoundingSectors(Iterable locations) { + if (locations == null) { String message = Logging.getMessage("nullValue.LocationInListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (!locations.iterator().hasNext()) + if (!locations.iterator().hasNext()) { return null; + } double minLat = Angle.POS90.getDegrees(); double minLon = Angle.POS180.getDegrees(); @@ -307,27 +322,27 @@ public static Sector[] splitBoundingSectors(Iterable locations LatLon lastLocation = null; - for (LatLon ll : locations) - { + for (LatLon ll : locations) { double lat = ll.getLatitude().getDegrees(); - if (lat < minLat) + if (lat < minLat) { minLat = lat; - if (lat > maxLat) + } + if (lat > maxLat) { maxLat = lat; + } double lon = ll.getLongitude().getDegrees(); - if (lon >= 0 && lon < minLon) + if (lon >= 0 && lon < minLon) { minLon = lon; - if (lon <= 0 && lon > maxLon) + } + if (lon <= 0 && lon > maxLon) { maxLon = lon; + } - if (lastLocation != null) - { + if (lastLocation != null) { double lastLon = lastLocation.getLongitude().getDegrees(); - if (Math.signum(lon) != Math.signum(lastLon)) - { - if (Math.abs(lon - lastLon) < 180) - { + if (Math.signum(lon) != Math.signum(lastLon)) { + if (Math.abs(lon - lastLon) < 180) { // Crossing the zero longitude line too maxLon = 0; minLon = 0; @@ -337,20 +352,18 @@ public static Sector[] splitBoundingSectors(Iterable locations lastLocation = ll; } - if (minLat == maxLat && minLon == maxLon) + if (minLat == maxLat && minLon == maxLon) { return null; + } - return new Sector[] - { - Sector.fromDegrees(minLat, maxLat, minLon, 180), // Sector on eastern hemisphere. - Sector.fromDegrees(minLat, maxLat, -180, maxLon) // Sector on western hemisphere. - }; + return new Sector[]{ + Sector.fromDegrees(minLat, maxLat, minLon, 180), // Sector on eastern hemisphere. + Sector.fromDegrees(minLat, maxLat, -180, maxLon) // Sector on western hemisphere. + }; } - public static Sector boundingSector(LatLon pA, LatLon pB) - { - if (pA == null || pB == null) - { + public static Sector boundingSector(LatLon pA, LatLon pB) { + if (pA == null || pB == null) { String message = Logging.getMessage("nullValue.PositionsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -361,75 +374,75 @@ public static Sector boundingSector(LatLon pA, LatLon pB) double maxLat = pA.getLatitude().degrees; double maxLon = pA.getLongitude().degrees; - if (pB.getLatitude().degrees < minLat) + if (pB.getLatitude().degrees < minLat) { minLat = pB.getLatitude().degrees; - else if (pB.getLatitude().degrees > maxLat) + } else if (pB.getLatitude().degrees > maxLat) { maxLat = pB.getLatitude().degrees; + } - if (pB.getLongitude().degrees < minLon) + if (pB.getLongitude().degrees < minLon) { minLon = pB.getLongitude().degrees; - else if (pB.getLongitude().degrees > maxLon) + } else if (pB.getLongitude().degrees > maxLon) { maxLon = pB.getLongitude().degrees; + } return Sector.fromDegrees(minLat, maxLat, minLon, maxLon); } /** - * Returns a new Sector encompassing a circle centered at a given position, with a given radius in - * meter. + * Returns a new Sector encompassing a circle centered at a + * given position, with a given radius in meter. * - * @param globe a Globe instance. + * @param globe a Globe instance. * @param center the circle center position. * @param radius the circle radius in meter. * * @return the circle bounding sector. */ - public static Sector boundingSector(Globe globe, LatLon center, double radius) - { + public static Sector boundingSector(Globe globe, LatLon center, double radius) { double halfDeltaLatRadians = radius / globe.getRadiusAt(center); double halfDeltaLonRadians = Math.PI * 2; - if (center.getLatitude().cos() > 0) + if (center.getLatitude().cos() > 0) { halfDeltaLonRadians = halfDeltaLatRadians / center.getLatitude().cos(); + } return new Sector( - Angle.fromRadiansLatitude(center.getLatitude().radians - halfDeltaLatRadians), - Angle.fromRadiansLatitude(center.getLatitude().radians + halfDeltaLatRadians), - Angle.fromRadiansLongitude(center.getLongitude().radians - halfDeltaLonRadians), - Angle.fromRadiansLongitude(center.getLongitude().radians + halfDeltaLonRadians)); + Angle.fromRadiansLatitude(center.getLatitude().radians - halfDeltaLatRadians), + Angle.fromRadiansLatitude(center.getLatitude().radians + halfDeltaLatRadians), + Angle.fromRadiansLongitude(center.getLongitude().radians - halfDeltaLonRadians), + Angle.fromRadiansLongitude(center.getLongitude().radians + halfDeltaLonRadians)); } /** - * Returns an array of Sectors encompassing a circle centered at a given position, with a given radius in meters. If - * the geometry defined by the circle and radius spans the international dateline, this will return two sectors, one - * for each side of the dateline. Otherwise, this will return a single bounding sector. This returns null if the - * radius is zero. + * Returns an array of Sectors encompassing a circle centered at a given + * position, with a given radius in meters. If the geometry defined by the + * circle and radius spans the international dateline, this will return two + * sectors, one for each side of the dateline. Otherwise, this will return a + * single bounding sector. This returns null if the radius is zero. * - * @param globe a Globe instance. + * @param globe a Globe instance. * @param center the circle center location. * @param radius the circle radius in meters. * * @return the circle's bounding sectors, or null if the radius is zero. * - * @throws IllegalArgumentException if either the globe or center is null, or if the radius is less than zero. + * @throws IllegalArgumentException if either the globe or center is null, + * or if the radius is less than zero. */ - public static Sector[] splitBoundingSectors(Globe globe, LatLon center, double radius) - { - if (globe == null) - { + public static Sector[] splitBoundingSectors(Globe globe, LatLon center, double radius) { + if (globe == null) { String message = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (center == null) - { + if (center == null) { String message = Logging.getMessage("nullValue.CenterIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (radius < 0) - { + if (radius < 0) { String message = Logging.getMessage("generic.ArgumentOutOfRange", "radius < 0"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -444,8 +457,7 @@ public static Sector[] splitBoundingSectors(Globe globe, LatLon center, double r double maxLon; // If the circle does not cross a pole, then compute the max and min longitude. - if (minLat >= Angle.NEG90.radians && maxLat <= Angle.POS90.radians) - { + if (minLat >= Angle.NEG90.radians && maxLat <= Angle.POS90.radians) { // We want to find the maximum and minimum longitude values on the circle. We will start with equation 5-6 // from "Map Projections - A Working Manual", page 31, and solve for the value of Az that will maximize // lon - lon0. @@ -477,59 +489,56 @@ public static Sector[] splitBoundingSectors(Globe globe, LatLon center, double r // circle would cover a pole. double az; if (Math.abs(Angle.POS90.radians - halfDeltaLatRadians) - > 0.001) // Consider within 1/1000th of a radian to be equal + > 0.001) // Consider within 1/1000th of a radian to be equal + { az = Math.acos(Math.tan(halfDeltaLatRadians) * Math.tan(center.latitude.radians)); - else + } else { az = Angle.POS90.radians; + } LatLon east = LatLon.greatCircleEndPosition(center, az, halfDeltaLatRadians); LatLon west = LatLon.greatCircleEndPosition(center, -az, halfDeltaLatRadians); minLon = Math.min(east.longitude.radians, west.longitude.radians); maxLon = Math.max(east.longitude.radians, west.longitude.radians); - } - else - { + } else { // If the circle crosses the pole then it spans the full circle of longitude minLon = Angle.NEG180.radians; maxLon = Angle.POS180.radians; } LatLon ll = new LatLon( - Angle.fromRadiansLatitude(minLat), - Angle.normalizedLongitude(Angle.fromRadians(minLon))); + Angle.fromRadiansLatitude(minLat), + Angle.normalizedLongitude(Angle.fromRadians(minLon))); LatLon ur = new LatLon( - Angle.fromRadiansLatitude(maxLat), - Angle.normalizedLongitude(Angle.fromRadians(maxLon))); + Angle.fromRadiansLatitude(maxLat), + Angle.normalizedLongitude(Angle.fromRadians(maxLon))); Iterable locations = java.util.Arrays.asList(ll, ur); - if (LatLon.locationsCrossDateLine(locations)) - { + if (LatLon.locationsCrossDateLine(locations)) { return splitBoundingSectors(locations); - } - else - { + } else { Sector s = boundingSector(locations); - return (s != null && !s.equals(Sector.EMPTY_SECTOR)) ? new Sector[] {s} : null; + return (s != null && !s.equals(Sector.EMPTY_SECTOR)) ? new Sector[]{s} : null; } } /** - * Creates a new Sector and initializes it to the specified angles. The angles are assumed to be - * normalized to +/- 90 degrees latitude and +/- 180 degrees longitude, but this method does not verify that. + * Creates a new Sector and initializes it to the specified + * angles. The angles are assumed to be normalized to +/- 90 degrees + * latitude and +/- 180 degrees longitude, but this method does not verify + * that. * - * @param minLatitude the sector's minimum latitude. - * @param maxLatitude the sector's maximum latitude. + * @param minLatitude the sector's minimum latitude. + * @param maxLatitude the sector's maximum latitude. * @param minLongitude the sector's minimum longitude. * @param maxLongitude the sector's maximum longitude. * * @throws IllegalArgumentException if any of the angles are null */ - public Sector(Angle minLatitude, Angle maxLatitude, Angle minLongitude, Angle maxLongitude) - { - if (minLatitude == null || maxLatitude == null || minLongitude == null || maxLongitude == null) - { + public Sector(Angle minLatitude, Angle maxLatitude, Angle minLongitude, Angle maxLongitude) { + if (minLatitude == null || maxLatitude == null || minLongitude == null || maxLongitude == null) { String message = Logging.getMessage("nullValue.InputAnglesNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -543,10 +552,8 @@ public Sector(Angle minLatitude, Angle maxLatitude, Angle minLongitude, Angle ma this.deltaLon = Angle.fromDegrees(this.maxLongitude.degrees - this.minLongitude.degrees); } - public Sector(Sector sector) - { - if (sector == null) - { + public Sector(Sector sector) { + if (sector == null) { String message = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -565,8 +572,7 @@ public Sector(Sector sector) * * @return The sector's minimum latitude. */ - public final Angle getMinLatitude() - { + public final Angle getMinLatitude() { return minLatitude; } @@ -575,8 +581,7 @@ public final Angle getMinLatitude() * * @return The sector's minimum longitude. */ - public final Angle getMinLongitude() - { + public final Angle getMinLongitude() { return minLongitude; } @@ -585,8 +590,7 @@ public final Angle getMinLongitude() * * @return The sector's maximum latitude. */ - public final Angle getMaxLatitude() - { + public final Angle getMaxLatitude() { return maxLatitude; } @@ -595,68 +599,63 @@ public final Angle getMaxLatitude() * * @return The sector's maximum longitude. */ - public final Angle getMaxLongitude() - { + public final Angle getMaxLongitude() { return maxLongitude; } /** - * Returns the angular difference between the sector's minimum and maximum latitudes: max - min + * Returns the angular difference between the sector's minimum and maximum + * latitudes: max - min * - * @return The angular difference between the sector's minimum and maximum latitudes. + * @return The angular difference between the sector's minimum and maximum + * latitudes. */ - public final Angle getDeltaLat() - { + public final Angle getDeltaLat() { return this.deltaLat;//Angle.fromDegrees(this.maxLatitude.degrees - this.minLatitude.degrees); } - public final double getDeltaLatDegrees() - { + public final double getDeltaLatDegrees() { return this.deltaLat.degrees;//this.maxLatitude.degrees - this.minLatitude.degrees; } - public final double getDeltaLatRadians() - { + public final double getDeltaLatRadians() { return this.deltaLat.radians;//this.maxLatitude.radians - this.minLatitude.radians; } /** - * Returns the angular difference between the sector's minimum and maximum longitudes: max - min. + * Returns the angular difference between the sector's minimum and maximum + * longitudes: max - min. * - * @return The angular difference between the sector's minimum and maximum longitudes + * @return The angular difference between the sector's minimum and maximum + * longitudes */ - public final Angle getDeltaLon() - { + public final Angle getDeltaLon() { return this.deltaLon;//Angle.fromDegrees(this.maxLongitude.degrees - this.minLongitude.degrees); } - public final double getDeltaLonDegrees() - { + public final double getDeltaLonDegrees() { return this.deltaLon.degrees;//this.maxLongitude.degrees - this.minLongitude.degrees; } - public final double getDeltaLonRadians() - { + public final double getDeltaLonRadians() { return this.deltaLon.radians;//this.maxLongitude.radians - this.minLongitude.radians; } - public boolean isWithinLatLonLimits() - { + public boolean isWithinLatLonLimits() { return this.minLatitude.degrees >= -90 && this.maxLatitude.degrees <= 90 - && this.minLongitude.degrees >= -180 && this.maxLongitude.degrees <= 180; + && this.minLongitude.degrees >= -180 && this.maxLongitude.degrees <= 180; } - public boolean isSameSector(Iterable corners) - { - if (corners == null) - { + public boolean isSameSector(Iterable corners) { + if (corners == null) { String message = Logging.getMessage("nullValue.LocationsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (!isSector(corners)) + if (!isSector(corners)) { return false; + } Sector s = Sector.boundingSector(corners); @@ -664,10 +663,8 @@ public boolean isSameSector(Iterable corners) } @SuppressWarnings({"RedundantIfStatement"}) - public static boolean isSector(Iterable corners) - { - if (corners == null) - { + public static boolean isSector(Iterable corners) { + if (corners == null) { String message = Logging.getMessage("nullValue.LocationsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -676,37 +673,42 @@ public static boolean isSector(Iterable corners) LatLon[] latlons = new LatLon[5]; int i = 0; - for (LatLon ll : corners) - { - if (i > 4 || ll == null) + for (LatLon ll : corners) { + if (i > 4 || ll == null) { return false; + } latlons[i++] = ll; } - if (!latlons[0].getLatitude().equals(latlons[1].getLatitude())) + if (!latlons[0].getLatitude().equals(latlons[1].getLatitude())) { return false; - if (!latlons[2].getLatitude().equals(latlons[3].getLatitude())) + } + if (!latlons[2].getLatitude().equals(latlons[3].getLatitude())) { return false; - if (!latlons[0].getLongitude().equals(latlons[3].getLongitude())) + } + if (!latlons[0].getLongitude().equals(latlons[3].getLongitude())) { return false; - if (!latlons[1].getLongitude().equals(latlons[2].getLongitude())) + } + if (!latlons[1].getLongitude().equals(latlons[2].getLongitude())) { return false; + } - if (i == 5 && !latlons[4].equals(latlons[0])) + if (i == 5 && !latlons[4].equals(latlons[0])) { return false; + } return true; } /** - * Returns the latitude and longitude of the sector's angular center: (minimum latitude + maximum latitude) / 2, - * (minimum longitude + maximum longitude) / 2. + * Returns the latitude and longitude of the sector's angular center: + * (minimum latitude + maximum latitude) / 2, (minimum longitude + maximum + * longitude) / 2. * * @return The latitude and longitude of the sector's angular center */ - public LatLon getCentroid() - { + public LatLon getCentroid() { Angle la = Angle.fromDegrees(0.5 * (this.getMaxLatitude().degrees + this.getMinLatitude().degrees)); Angle lo = Angle.fromDegrees(0.5 * (this.getMaxLongitude().degrees + this.getMinLongitude().degrees)); return new LatLon(la, lo); @@ -715,17 +717,15 @@ public LatLon getCentroid() /** * Computes the Cartesian coordinates of a Sector's center. * - * @param globe The globe associated with the sector. + * @param globe The globe associated with the sector. * @param exaggeration The vertical exaggeration to apply. * * @return the Cartesian coordinates of the sector's center. * * @throws IllegalArgumentException if globe is null. */ - public Vec4 computeCenterPoint(Globe globe, double exaggeration) - { - if (globe == null) - { + public Vec4 computeCenterPoint(Globe globe, double exaggeration) { + if (globe == null) { String msg = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -742,17 +742,15 @@ public Vec4 computeCenterPoint(Globe globe, double exaggeration) /** * Computes the Cartesian coordinates of a Sector's corners. * - * @param globe The globe associated with the sector. + * @param globe The globe associated with the sector. * @param exaggeration The vertical exaggeration to apply. * * @return an array of four Cartesian points. * * @throws IllegalArgumentException if globe is null. */ - public Vec4[] computeCornerPoints(Globe globe, double exaggeration) - { - if (globe == null) - { + public Vec4[] computeCornerPoints(Globe globe, double exaggeration) { + if (globe == null) { String msg = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -773,27 +771,26 @@ public Vec4[] computeCornerPoints(Globe globe, double exaggeration) } /** - * Returns a sphere that minimally surrounds the sector at a specified vertical exaggeration. + * Returns a sphere that minimally surrounds the sector at a specified + * vertical exaggeration. * - * @param globe the globe the sector is associated with - * @param verticalExaggeration the vertical exaggeration to apply to the globe's elevations when computing the - * sphere. - * @param sector the sector to return the bounding sphere for. + * @param globe the globe the sector is associated with + * @param verticalExaggeration the vertical exaggeration to apply to the + * globe's elevations when computing the sphere. + * @param sector the sector to return the bounding sphere for. * * @return The minimal bounding sphere in Cartesian coordinates. * - * @throws IllegalArgumentException if globe or sector is null + * @throws IllegalArgumentException if globe or + * sector is null */ - static public Sphere computeBoundingSphere(Globe globe, double verticalExaggeration, Sector sector) - { - if (globe == null) - { + static public Sphere computeBoundingSphere(Globe globe, double verticalExaggeration, Sector sector) { + if (globe == null) { String msg = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (sector == null) - { + if (sector == null) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -819,31 +816,33 @@ static public Sphere computeBoundingSphere(Globe globe, double verticalExaggerat } /** - * Returns a {@link gov.nasa.worldwind.geom.Box} that bounds the specified sector on the surface of the specified - * {@link gov.nasa.worldwind.globes.Globe}. The returned box encloses the globe's surface terrain in the sector, - * according to the specified vertical exaggeration and the globe's minimum and maximum elevations in the sector. If - * the minimum and maximum elevation are equal, this assumes a maximum elevation of 10 + the minimum. If this fails - * to compute a box enclosing the sector, this returns a unit box enclosing one of the boxes corners. - * - * @param globe the globe the extent relates to. + * Returns a {@link gov.nasa.worldwind.geom.Box} that bounds the specified + * sector on the surface of the specified + * {@link gov.nasa.worldwind.globes.Globe}. The returned box encloses the + * globe's surface terrain in the sector, according to the specified + * vertical exaggeration and the globe's minimum and maximum elevations in + * the sector. If the minimum and maximum elevation are equal, this assumes + * a maximum elevation of 10 + the minimum. If this fails to compute a box + * enclosing the sector, this returns a unit box enclosing one of the boxes + * corners. + * + * @param globe the globe the extent relates to. * @param verticalExaggeration the globe's vertical surface exaggeration. - * @param sector a sector on the globe's surface to compute a bounding box for. + * @param sector a sector on the globe's surface to compute a bounding box + * for. * * @return a box enclosing the globe's surface on the specified sector. * * @throws IllegalArgumentException if either the globe or sector is null. */ - public static Box computeBoundingBox(Globe globe, double verticalExaggeration, Sector sector) - { - if (globe == null) - { + public static Box computeBoundingBox(Globe globe, double verticalExaggeration, Sector sector) { + if (globe == null) { String msg = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (sector == null) - { + if (sector == null) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -854,34 +853,35 @@ public static Box computeBoundingBox(Globe globe, double verticalExaggeration, S } /** - * Returns a {@link gov.nasa.worldwind.geom.Box} that bounds the specified sector on the surface of the specified - * {@link gov.nasa.worldwind.globes.Globe}. The returned box encloses the globe's surface terrain in the sector, - * according to the specified vertical exaggeration, minimum elevation, and maximum elevation. If the minimum and - * maximum elevation are equal, this assumes a maximum elevation of 10 + the minimum. If this fails to compute a box - * enclosing the sector, this returns a unit box enclosing one of the boxes corners. - * - * @param globe the globe the extent relates to. + * Returns a {@link gov.nasa.worldwind.geom.Box} that bounds the specified + * sector on the surface of the specified + * {@link gov.nasa.worldwind.globes.Globe}. The returned box encloses the + * globe's surface terrain in the sector, according to the specified + * vertical exaggeration, minimum elevation, and maximum elevation. If the + * minimum and maximum elevation are equal, this assumes a maximum elevation + * of 10 + the minimum. If this fails to compute a box enclosing the sector, + * this returns a unit box enclosing one of the boxes corners. + * + * @param globe the globe the extent relates to. * @param verticalExaggeration the globe's vertical surface exaggeration. - * @param sector a sector on the globe's surface to compute a bounding box for. - * @param minElevation the globe's minimum elevation in the sector. - * @param maxElevation the globe's maximum elevation in the sector. + * @param sector a sector on the globe's surface to compute a bounding box + * for. + * @param minElevation the globe's minimum elevation in the sector. + * @param maxElevation the globe's maximum elevation in the sector. * * @return a box enclosing the globe's surface on the specified sector. * * @throws IllegalArgumentException if either the globe or sector is null. */ public static Box computeBoundingBox(Globe globe, double verticalExaggeration, Sector sector, - double minElevation, double maxElevation) - { - if (globe == null) - { + double minElevation, double maxElevation) { + if (globe == null) { String msg = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (sector == null) - { + if (sector == null) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -892,8 +892,7 @@ public static Box computeBoundingBox(Globe globe, double verticalExaggeration, S double max = maxElevation * verticalExaggeration; // Ensure the top and bottom heights are not equal. - if (min == max) - { + if (min == max) { max = min + 10; } @@ -907,39 +906,34 @@ public static Box computeBoundingBox(Globe globe, double verticalExaggeration, S Vec4[] points = new Vec4[15]; globe.computePointsFromPositions(sector, 3, 5, elevations, points); - try - { + try { return Box.computeBoundingBox(Arrays.asList(points)); - } - catch (Exception e) - { + } catch (Exception e) { return new Box(points[0]); // unit box around point } } /** - * Returns a cylinder that minimally surrounds the specified sector at a specified vertical exaggeration. + * Returns a cylinder that minimally surrounds the specified sector at a + * specified vertical exaggeration. * - * @param globe The globe associated with the sector. - * @param verticalExaggeration the vertical exaggeration to apply to the minimum and maximum elevations when - * computing the cylinder. - * @param sector the sector to return the bounding cylinder for. + * @param globe The globe associated with the sector. + * @param verticalExaggeration the vertical exaggeration to apply to the + * minimum and maximum elevations when computing the cylinder. + * @param sector the sector to return the bounding cylinder for. * * @return The minimal bounding cylinder in Cartesian coordinates. * * @throws IllegalArgumentException if sector is null */ - static public Cylinder computeBoundingCylinder(Globe globe, double verticalExaggeration, Sector sector) - { - if (globe == null) - { + static public Cylinder computeBoundingCylinder(Globe globe, double verticalExaggeration, Sector sector) { + if (globe == null) { String msg = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (sector == null) - { + if (sector == null) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -947,36 +941,34 @@ static public Cylinder computeBoundingCylinder(Globe globe, double verticalExagg double[] minAndMaxElevations = globe.getMinAndMaxElevations(sector); return computeBoundingCylinder(globe, verticalExaggeration, sector, - minAndMaxElevations[0], minAndMaxElevations[1]); + minAndMaxElevations[0], minAndMaxElevations[1]); } /** - * Returns a cylinder that minimally surrounds the specified sector at a specified vertical exaggeration and minimum - * and maximum elevations for the sector. + * Returns a cylinder that minimally surrounds the specified sector at a + * specified vertical exaggeration and minimum and maximum elevations for + * the sector. * - * @param globe The globe associated with the sector. - * @param verticalExaggeration the vertical exaggeration to apply to the minimum and maximum elevations when - * computing the cylinder. - * @param sector the sector to return the bounding cylinder for. - * @param minElevation the minimum elevation of the bounding cylinder. - * @param maxElevation the maximum elevation of the bounding cylinder. + * @param globe The globe associated with the sector. + * @param verticalExaggeration the vertical exaggeration to apply to the + * minimum and maximum elevations when computing the cylinder. + * @param sector the sector to return the bounding cylinder for. + * @param minElevation the minimum elevation of the bounding cylinder. + * @param maxElevation the maximum elevation of the bounding cylinder. * * @return The minimal bounding cylinder in Cartesian coordinates. * * @throws IllegalArgumentException if sector is null */ public static Cylinder computeBoundingCylinder(Globe globe, double verticalExaggeration, Sector sector, - double minElevation, double maxElevation) - { - if (globe == null) - { + double minElevation, double maxElevation) { + if (globe == null) { String msg = Logging.getMessage("nullValue.GlobeIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (sector == null) - { + if (sector == null) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -986,19 +978,17 @@ public static Cylinder computeBoundingCylinder(Globe globe, double verticalExagg double minHeight = minElevation * verticalExaggeration; double maxHeight = maxElevation * verticalExaggeration; - if (minHeight == maxHeight) + if (minHeight == maxHeight) { maxHeight = minHeight + 1; // ensure the top and bottom of the cylinder won't be coincident - + } List points = new ArrayList(); - for (LatLon ll : sector) - { + for (LatLon ll : sector) { points.add(globe.computePointFromPosition(ll, minHeight)); points.add(globe.computePointFromPosition(ll, maxHeight)); } points.add(globe.computePointFromPosition(sector.getCentroid(), maxHeight)); - if (sector.getDeltaLonDegrees() > 180) - { + if (sector.getDeltaLonDegrees() > 180) { // Need to compute more points to ensure the box encompasses the full sector. Angle cLon = sector.getCentroid().getLongitude(); Angle cLat = sector.getCentroid().getLatitude(); @@ -1016,47 +1006,40 @@ public static Cylinder computeBoundingCylinder(Globe globe, double verticalExagg points.add(globe.computePointFromPosition(cLat, sector.getMaxLongitude(), maxHeight)); } - try - { + try { return Cylinder.computeBoundingCylinder(points); - } - catch (Exception e) - { + } catch (Exception e) { return new Cylinder(points.get(0), points.get(0).add3(Vec4.UNIT_Y), 1); } } - static public Cylinder computeBoundingCylinderOrig(Globe globe, double verticalExaggeration, Sector sector) - { + static public Cylinder computeBoundingCylinderOrig(Globe globe, double verticalExaggeration, Sector sector) { return Cylinder.computeVerticalBoundingCylinder(globe, verticalExaggeration, sector); } /** - * Returns a cylinder that minimally surrounds the specified minimum and maximum elevations in the sector at a - * specified vertical exaggeration. + * Returns a cylinder that minimally surrounds the specified minimum and + * maximum elevations in the sector at a specified vertical exaggeration. * - * @param globe The globe associated with the sector. - * @param verticalExaggeration the vertical exaggeration to apply to the minimum and maximum elevations when - * computing the cylinder. - * @param sector the sector to return the bounding cylinder for. - * @param minElevation the minimum elevation of the bounding cylinder. - * @param maxElevation the maximum elevation of the bounding cylinder. + * @param globe The globe associated with the sector. + * @param verticalExaggeration the vertical exaggeration to apply to the + * minimum and maximum elevations when computing the cylinder. + * @param sector the sector to return the bounding cylinder for. + * @param minElevation the minimum elevation of the bounding cylinder. + * @param maxElevation the maximum elevation of the bounding cylinder. * * @return The minimal bounding cylinder in Cartesian coordinates. * * @throws IllegalArgumentException if sector is null */ public static Cylinder computeBoundingCylinderOrig(Globe globe, double verticalExaggeration, Sector sector, - double minElevation, double maxElevation) - { + double minElevation, double maxElevation) { return Cylinder.computeVerticalBoundingCylinder(globe, verticalExaggeration, sector, minElevation, - maxElevation); + maxElevation); } - public final boolean contains(Angle latitude, Angle longitude) - { - if (latitude == null || longitude == null) - { + public final boolean contains(Angle latitude, Angle longitude) { + if (latitude == null || longitude == null) { String message = Logging.getMessage("nullValue.LatLonIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -1066,20 +1049,21 @@ public final boolean contains(Angle latitude, Angle longitude) } /** - * Determines whether a latitude/longitude position is within the sector. The sector's angles are assumed to be - * normalized to +/- 90 degrees latitude and +/- 180 degrees longitude. The result of the operation is undefined if - * they are not. + * Determines whether a latitude/longitude position is within the sector. + * The sector's angles are assumed to be normalized to +/- 90 degrees + * latitude and +/- 180 degrees longitude. The result of the operation is + * undefined if they are not. * - * @param latLon the position to test, with angles normalized to +/- π latitude and +/- 2π longitude. + * @param latLon the position to test, with angles normalized to +/- π + * latitude and +/- 2π longitude. * - * @return true if the position is within the sector, false otherwise. + * @return true if the position is within the sector, + * false otherwise. * * @throws IllegalArgumentException if latlon is null. */ - public final boolean contains(LatLon latLon) - { - if (latLon == null) - { + public final boolean contains(LatLon latLon) { + if (latLon == null) { String message = Logging.getMessage("nullValue.LatLonIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -1089,137 +1073,157 @@ public final boolean contains(LatLon latLon) } /** - * Determines whether a latitude/longitude postion expressed in radians is within the sector. The sector's angles - * are assumed to be normalized to +/- 90 degrees latitude and +/- 180 degrees longitude. The result of the + * Determines whether a latitude/longitude postion expressed in radians is + * within the sector. The sector's angles are assumed to be normalized to + * +/- 90 degrees latitude and +/- 180 degrees longitude. The result of the * operation is undefined if they are not. * - * @param radiansLatitude the latitude in radians of the position to test, normalized +/- π. - * @param radiansLongitude the longitude in radians of the position to test, normalized +/- 2π. + * @param radiansLatitude the latitude in radians of the position to test, + * normalized +/- π. + * @param radiansLongitude the longitude in radians of the position to test, + * normalized +/- 2π. * - * @return true if the position is within the sector, false otherwise. + * @return true if the position is within the sector, + * false otherwise. */ - public boolean containsRadians(double radiansLatitude, double radiansLongitude) - { + public boolean containsRadians(double radiansLatitude, double radiansLongitude) { return radiansLatitude >= this.minLatitude.radians && radiansLatitude <= this.maxLatitude.radians - && radiansLongitude >= this.minLongitude.radians && radiansLongitude <= this.maxLongitude.radians; + && radiansLongitude >= this.minLongitude.radians && radiansLongitude <= this.maxLongitude.radians; } - public boolean containsDegrees(double degreesLatitude, double degreesLongitude) - { + public boolean containsDegrees(double degreesLatitude, double degreesLongitude) { return degreesLatitude >= this.minLatitude.degrees && degreesLatitude <= this.maxLatitude.degrees - && degreesLongitude >= this.minLongitude.degrees && degreesLongitude <= this.maxLongitude.degrees; + && degreesLongitude >= this.minLongitude.degrees && degreesLongitude <= this.maxLongitude.degrees; } /** - * Determines whether another sector is fully contained within this one. The sector's angles are assumed to be - * normalized to +/- 90 degrees latitude and +/- 180 degrees longitude. The result of the operation is undefined if - * they are not. + * Determines whether another sector is fully contained within this one. The + * sector's angles are assumed to be normalized to +/- 90 degrees latitude + * and +/- 180 degrees longitude. The result of the operation is undefined + * if they are not. * * @param that the sector to test for containment. * - * @return true if this sector fully contains the input sector, otherwise false. + * @return true if this sector fully contains the input sector, + * otherwise false. */ - public boolean contains(Sector that) - { - if (that == null) + public boolean contains(Sector that) { + if (that == null) { return false; + } // Assumes normalized angles -- [-180, 180], [-90, 90] - if (that.minLongitude.degrees < this.minLongitude.degrees) + if (that.minLongitude.degrees < this.minLongitude.degrees) { return false; - if (that.maxLongitude.degrees > this.maxLongitude.degrees) + } + if (that.maxLongitude.degrees > this.maxLongitude.degrees) { return false; - if (that.minLatitude.degrees < this.minLatitude.degrees) + } + if (that.minLatitude.degrees < this.minLatitude.degrees) { return false; + } //noinspection RedundantIfStatement - if (that.maxLatitude.degrees > this.maxLatitude.degrees) + if (that.maxLatitude.degrees > this.maxLatitude.degrees) { return false; + } return true; } /** - * Determines whether this sector intersects another sector's range of latitude and longitude. The sector's angles - * are assumed to be normalized to +/- 90 degrees latitude and +/- 180 degrees longitude. The result of the - * operation is undefined if they are not. + * Determines whether this sector intersects another sector's range of + * latitude and longitude. The sector's angles are assumed to be normalized + * to +/- 90 degrees latitude and +/- 180 degrees longitude. The result of + * the operation is undefined if they are not. * * @param that the sector to test for intersection. * - * @return true if the sectors intersect, otherwise false. + * @return true if the sectors intersect, otherwise + * false. */ - public boolean intersects(Sector that) - { - if (that == null) + public boolean intersects(Sector that) { + if (that == null) { return false; + } // Assumes normalized angles -- [-180, 180], [-90, 90] - if (that.maxLongitude.degrees < this.minLongitude.degrees) + if (that.maxLongitude.degrees < this.minLongitude.degrees) { return false; - if (that.minLongitude.degrees > this.maxLongitude.degrees) + } + if (that.minLongitude.degrees > this.maxLongitude.degrees) { return false; - if (that.maxLatitude.degrees < this.minLatitude.degrees) + } + if (that.maxLatitude.degrees < this.minLatitude.degrees) { return false; + } //noinspection RedundantIfStatement - if (that.minLatitude.degrees > this.maxLatitude.degrees) + if (that.minLatitude.degrees > this.maxLatitude.degrees) { return false; + } return true; } /** - * Determines whether the interiors of this sector and another sector intersect. The sector's angles are assumed to - * be normalized to +/- 90 degrees latitude and +/- 180 degrees longitude. The result of the operation is undefined - * if they are not. + * Determines whether the interiors of this sector and another sector + * intersect. The sector's angles are assumed to be normalized to +/- 90 + * degrees latitude and +/- 180 degrees longitude. The result of the + * operation is undefined if they are not. * * @param that the sector to test for intersection. * - * @return true if the sectors' interiors intersect, otherwise false. + * @return true if the sectors' interiors intersect, otherwise + * false. * * @see #intersects(Sector) */ - public boolean intersectsInterior(Sector that) - { - if (that == null) + public boolean intersectsInterior(Sector that) { + if (that == null) { return false; + } // Assumes normalized angles -- [-180, 180], [-90, 90] - if (that.maxLongitude.degrees <= this.minLongitude.degrees) + if (that.maxLongitude.degrees <= this.minLongitude.degrees) { return false; - if (that.minLongitude.degrees >= this.maxLongitude.degrees) + } + if (that.minLongitude.degrees >= this.maxLongitude.degrees) { return false; - if (that.maxLatitude.degrees <= this.minLatitude.degrees) + } + if (that.maxLatitude.degrees <= this.minLatitude.degrees) { return false; + } //noinspection RedundantIfStatement - if (that.minLatitude.degrees >= this.maxLatitude.degrees) + if (that.minLatitude.degrees >= this.maxLatitude.degrees) { return false; + } return true; } /** - * Determines whether this sector intersects the specified geographic line segment. The line segment is specified by - * a begin location and an end location. The locations are are assumed to be connected by a linear path in - * geographic space. This returns true if any location along that linear path intersects this sector, including the - * begin and end locations. + * Determines whether this sector intersects the specified geographic line + * segment. The line segment is specified by a begin location and an end + * location. The locations are are assumed to be connected by a linear path + * in geographic space. This returns true if any location along that linear + * path intersects this sector, including the begin and end locations. * * @param begin the line segment begin location. - * @param end the line segment end location. + * @param end the line segment end location. * - * @return true true if this sector intersects the line segment, otherwise false. + * @return true true if this sector intersects the line + * segment, otherwise false. * - * @throws IllegalArgumentException if either the begin location or the end location is null. + * @throws IllegalArgumentException if either the begin location or the end + * location is null. */ - public boolean intersectsSegment(LatLon begin, LatLon end) - { - if (begin == null) - { + public boolean intersectsSegment(LatLon begin, LatLon end) { + if (begin == null) { String message = Logging.getMessage("nullValue.BeginIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (end == null) - { + if (end == null) { String message = Logging.getMessage("nullValue.EndIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -1239,112 +1243,119 @@ public boolean intersectsSegment(LatLon begin, LatLon end) Vec4 diff = segmentCenter.subtract3(boxCenter); - if (Math.abs(diff.x) > (boxExtentX + segmentExtent * Math.abs(segmentDirection.x))) - { + if (Math.abs(diff.x) > (boxExtentX + segmentExtent * Math.abs(segmentDirection.x))) { return false; } - if (Math.abs(diff.y) > (boxExtentY + segmentExtent * Math.abs(segmentDirection.y))) - { + if (Math.abs(diff.y) > (boxExtentY + segmentExtent * Math.abs(segmentDirection.y))) { return false; } //noinspection SuspiciousNameCombination Vec4 segmentPerp = new Vec4(segmentDirection.y, -segmentDirection.x, 0); - return Math.abs(segmentPerp.dot3(diff)) <= - (boxExtentX * Math.abs(segmentPerp.x) + boxExtentY * Math.abs(segmentPerp.y)); + return Math.abs(segmentPerp.dot3(diff)) + <= (boxExtentX * Math.abs(segmentPerp.x) + boxExtentY * Math.abs(segmentPerp.y)); } /** - * Determines whether this sector intersects any one of the sectors in the specified iterable. This returns true if - * at least one of the sectors is non-null and intersects this sector. + * Determines whether this sector intersects any one of the sectors in the + * specified iterable. This returns true if at least one of the sectors is + * non-null and intersects this sector. * * @param sectors the sectors to test for intersection. * - * @return true if at least one of the sectors is non-null and intersects this sector, otherwise false. + * @return true if at least one of the sectors is non-null and intersects + * this sector, otherwise false. * * @throws java.lang.IllegalArgumentException if the iterable is null. */ - public boolean intersectsAny(Iterable sectors) - { - if (sectors == null) - { + public boolean intersectsAny(Iterable sectors) { + if (sectors == null) { String msg = Logging.getMessage("nullValue.SectorListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - for (Sector s : sectors) - { - if (s != null && s.intersects(this)) + for (Sector s : sectors) { + if (s != null && s.intersects(this)) { return true; + } } return false; } /** - * Returns a new sector whose angles are the extremes of the this sector and another. The new sector's minimum - * latitude and longitude will be the minimum of the two sectors. The new sector's maximum latitude and longitude - * will be the maximum of the two sectors. The sectors are assumed to be normalized to +/- 90 degrees latitude and - * +/- 180 degrees longitude. The result of the operation is undefined if they are not. + * Returns a new sector whose angles are the extremes of the this sector and + * another. The new sector's minimum latitude and longitude will be the + * minimum of the two sectors. The new sector's maximum latitude and + * longitude will be the maximum of the two sectors. The sectors are assumed + * to be normalized to +/- 90 degrees latitude and +/- 180 degrees + * longitude. The result of the operation is undefined if they are not. * * @param that the sector to join with this. * - * @return A new sector formed from the extremes of the two sectors, or this if the incoming sector is - * null. + * @return A new sector formed from the extremes of the two sectors, or + * this if the incoming sector is null. */ - public final Sector union(Sector that) - { - if (that == null) + public final Sector union(Sector that) { + if (that == null) { return this; + } Angle minLat = this.minLatitude; Angle maxLat = this.maxLatitude; Angle minLon = this.minLongitude; Angle maxLon = this.maxLongitude; - if (that.minLatitude.degrees < this.minLatitude.degrees) + if (that.minLatitude.degrees < this.minLatitude.degrees) { minLat = that.minLatitude; - if (that.maxLatitude.degrees > this.maxLatitude.degrees) + } + if (that.maxLatitude.degrees > this.maxLatitude.degrees) { maxLat = that.maxLatitude; - if (that.minLongitude.degrees < this.minLongitude.degrees) + } + if (that.minLongitude.degrees < this.minLongitude.degrees) { minLon = that.minLongitude; - if (that.maxLongitude.degrees > this.maxLongitude.degrees) + } + if (that.maxLongitude.degrees > this.maxLongitude.degrees) { maxLon = that.maxLongitude; + } return new Sector(minLat, maxLat, minLon, maxLon); } - public final Sector union(Angle latitude, Angle longitude) - { - if (latitude == null || longitude == null) + public final Sector union(Angle latitude, Angle longitude) { + if (latitude == null || longitude == null) { return this; + } Angle minLat = this.minLatitude; Angle maxLat = this.maxLatitude; Angle minLon = this.minLongitude; Angle maxLon = this.maxLongitude; - if (latitude.degrees < this.minLatitude.degrees) + if (latitude.degrees < this.minLatitude.degrees) { minLat = latitude; - if (latitude.degrees > this.maxLatitude.degrees) + } + if (latitude.degrees > this.maxLatitude.degrees) { maxLat = latitude; - if (longitude.degrees < this.minLongitude.degrees) + } + if (longitude.degrees < this.minLongitude.degrees) { minLon = longitude; - if (longitude.degrees > this.maxLongitude.degrees) + } + if (longitude.degrees > this.maxLongitude.degrees) { maxLon = longitude; + } return new Sector(minLat, maxLat, minLon, maxLon); } - public static Sector union(Sector sectorA, Sector sectorB) - { - if (sectorA == null || sectorB == null) - { - if (sectorA == sectorB) + public static Sector union(Sector sectorA, Sector sectorB) { + if (sectorA == null || sectorB == null) { + if (sectorA == sectorB) { return sectorA; + } return sectorB == null ? sectorA : sectorB; } @@ -1352,10 +1363,8 @@ public static Sector union(Sector sectorA, Sector sectorB) return sectorA.union(sectorB); } - public static Sector union(Iterable sectors) - { - if (sectors == null) - { + public static Sector union(Iterable sectors) { + if (sectors == null) { String msg = Logging.getMessage("nullValue.SectorListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -1366,74 +1375,79 @@ public static Sector union(Iterable sectors) Angle minLon = Angle.POS180; Angle maxLon = Angle.NEG180; - for (Sector s : sectors) - { - if (s == null) + for (Sector s : sectors) { + if (s == null) { continue; + } - for (LatLon p : s) - { - if (p.getLatitude().degrees < minLat.degrees) + for (LatLon p : s) { + if (p.getLatitude().degrees < minLat.degrees) { minLat = p.getLatitude(); - if (p.getLatitude().degrees > maxLat.degrees) + } + if (p.getLatitude().degrees > maxLat.degrees) { maxLat = p.getLatitude(); - if (p.getLongitude().degrees < minLon.degrees) + } + if (p.getLongitude().degrees < minLon.degrees) { minLon = p.getLongitude(); - if (p.getLongitude().degrees > maxLon.degrees) + } + if (p.getLongitude().degrees > maxLon.degrees) { maxLon = p.getLongitude(); + } } } return new Sector(minLat, maxLat, minLon, maxLon); } - public final Sector intersection(Sector that) - { - if (that == null) + public final Sector intersection(Sector that) { + if (that == null) { return this; + } Angle minLat, maxLat; minLat = (this.minLatitude.degrees > that.minLatitude.degrees) ? this.minLatitude : that.minLatitude; maxLat = (this.maxLatitude.degrees < that.maxLatitude.degrees) ? this.maxLatitude : that.maxLatitude; - if (minLat.degrees > maxLat.degrees) + if (minLat.degrees > maxLat.degrees) { return null; + } Angle minLon, maxLon; minLon = (this.minLongitude.degrees > that.minLongitude.degrees) ? this.minLongitude : that.minLongitude; maxLon = (this.maxLongitude.degrees < that.maxLongitude.degrees) ? this.maxLongitude : that.maxLongitude; - if (minLon.degrees > maxLon.degrees) + if (minLon.degrees > maxLon.degrees) { return null; + } return new Sector(minLat, maxLat, minLon, maxLon); } - public final Sector intersection(Angle latitude, Angle longitude) - { - if (latitude == null || longitude == null) + public final Sector intersection(Angle latitude, Angle longitude) { + if (latitude == null || longitude == null) { return this; + } - if (!this.contains(latitude, longitude)) + if (!this.contains(latitude, longitude)) { return null; + } return new Sector(latitude, latitude, longitude, longitude); } /** - * Returns the intersection of all sectors in the specified iterable. This returns a non-null sector if the iterable - * contains at least one non-null entry and all non-null entries intersect. The returned sector represents the - * geographic region in which all sectors intersect. This returns null if at least one of the sectors does not - * intersect the others. + * Returns the intersection of all sectors in the specified iterable. This + * returns a non-null sector if the iterable contains at least one non-null + * entry and all non-null entries intersect. The returned sector represents + * the geographic region in which all sectors intersect. This returns null + * if at least one of the sectors does not intersect the others. * * @param sectors the sectors to intersect. * - * @return the intersection of all sectors in the specified iterable, or null if at least one of the sectors does - * not intersect the others. + * @return the intersection of all sectors in the specified iterable, or + * null if at least one of the sectors does not intersect the others. * * @throws java.lang.IllegalArgumentException if the iterable is null. */ - public static Sector intersection(Iterable sectors) - { - if (sectors == null) - { + public static Sector intersection(Iterable sectors) { + if (sectors == null) { String msg = Logging.getMessage("nullValue.SectorListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -1441,22 +1455,21 @@ public static Sector intersection(Iterable sectors) Sector result = null; - for (Sector s : sectors) - { - if (s == null) + for (Sector s : sectors) { + if (s == null) { continue; // ignore null sectors - - if (result == null) + } + if (result == null) { result = s; // start with the first non-null sector - else if ((result = result.intersection(s)) == null) + } else if ((result = result.intersection(s)) == null) { break; // at least one of the sectors does not intersect the others + } } return result; } - public Sector[] subdivide() - { + public Sector[] subdivide() { Angle midLat = Angle.average(this.minLatitude, this.maxLatitude); Angle midLon = Angle.average(this.minLongitude, this.maxLongitude); @@ -1469,22 +1482,19 @@ public Sector[] subdivide() return sectors; } - public Sector[] subdivide(int div) - { + public Sector[] subdivide(int div) { double dLat = this.deltaLat.degrees / div; double dLon = this.deltaLon.degrees / div; Sector[] sectors = new Sector[div * div]; int idx = 0; - for (int row = 0; row < div; row++) - { - for (int col = 0; col < div; col++) - { + for (int row = 0; row < div; row++) { + for (int col = 0; col < div; col++) { sectors[idx++] = Sector.fromDegrees( - this.minLatitude.degrees + dLat * row, - this.minLatitude.degrees + dLat * row + dLat, - this.minLongitude.degrees + dLon * col, - this.minLongitude.degrees + dLon * col + dLon); + this.minLatitude.degrees + dLat * row, + this.minLatitude.degrees + dLat * row + dLat, + this.minLongitude.degrees + dLon * col, + this.minLongitude.degrees + dLon * col + dLon); } } @@ -1492,29 +1502,29 @@ public Sector[] subdivide(int div) } /** - * Returns an approximation of the distance in model coordinates between the surface geometry defined by this sector - * and the specified model coordinate point. The returned value represents the shortest distance between the - * specified point and this sector's corner points or its center point. The draw context defines the globe and the - * elevations that are used to compute the corner points and the center point. - * - * @param dc The draw context defining the surface geometry. + * Returns an approximation of the distance in model coordinates between the + * surface geometry defined by this sector and the specified model + * coordinate point. The returned value represents the shortest distance + * between the specified point and this sector's corner points or its center + * point. The draw context defines the globe and the elevations that are + * used to compute the corner points and the center point. + * + * @param dc The draw context defining the surface geometry. * @param point The model coordinate point to compute a distance to. * - * @return The distance between this sector's surface geometry and the specified point, in model coordinates. + * @return The distance between this sector's surface geometry and the + * specified point, in model coordinates. * * @throws IllegalArgumentException if any argument is null. */ - public double distanceTo(DrawContext dc, Vec4 point) - { - if (dc == null) - { + public double distanceTo(DrawContext dc, Vec4 point) { + if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (point == null) - { + if (point == null) { String message = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -1532,43 +1542,47 @@ public double distanceTo(DrawContext dc, Vec4 point) // Find the minimum distance. double minDistance = d1; - if (minDistance > d2) + if (minDistance > d2) { minDistance = d2; - if (minDistance > d3) + } + if (minDistance > d3) { minDistance = d3; - if (minDistance > d4) + } + if (minDistance > d4) { minDistance = d4; - if (minDistance > d5) + } + if (minDistance > d5) { minDistance = d5; + } return minDistance; } /** - * Returns a four element array containing the Sector's angles in degrees. The returned array is ordered as follows: - * minimum latitude, maximum latitude, minimum longitude, and maximum longitude. + * Returns a four element array containing the Sector's angles in degrees. + * The returned array is ordered as follows: minimum latitude, maximum + * latitude, minimum longitude, and maximum longitude. * * @return four-element array containing the Sector's angles. */ - public double[] toArrayDegrees() - { - return new double[] - { - this.minLatitude.degrees, this.maxLatitude.degrees, - this.minLongitude.degrees, this.maxLongitude.degrees - }; + public double[] toArrayDegrees() { + return new double[]{ + this.minLatitude.degrees, this.maxLatitude.degrees, + this.minLongitude.degrees, this.maxLongitude.degrees + }; } /** - * Returns a {@link java.awt.geom.Rectangle2D} corresponding to this Sector in degrees lat-lon coordinates where x - * corresponds to longitude and y to latitude. + * Returns a {@link java.awt.geom.Rectangle2D} corresponding to this Sector + * in degrees lat-lon coordinates where x corresponds to longitude and y to + * latitude. * - * @return a {@link java.awt.geom.Rectangle2D} corresponding to this Sector in degrees lat-lon coordinates. + * @return a {@link java.awt.geom.Rectangle2D} corresponding to this Sector + * in degrees lat-lon coordinates. */ - public Rectangle2D toRectangleDegrees() - { + public Rectangle2D toRectangleDegrees() { return new Rectangle2D.Double(this.getMinLongitude().degrees, this.getMinLatitude().degrees, - this.getDeltaLonDegrees(), this.getDeltaLatDegrees()); + this.getDeltaLonDegrees(), this.getDeltaLatDegrees()); } /** @@ -1577,8 +1591,7 @@ public Rectangle2D toRectangleDegrees() * @return A string indicating the sector's angles. */ @Override - public String toString() - { + public String toString() { StringBuilder sb = new StringBuilder(); sb.append("("); sb.append(this.minLatitude.toString()); @@ -1598,86 +1611,90 @@ public String toString() } /** - * Retrieve the size of this object in bytes. This implementation returns an exact value of the object's size. + * Retrieve the size of this object in bytes. This implementation returns an + * exact value of the object's size. * * @return the size of this object in bytes */ - public long getSizeInBytes() - { + public long getSizeInBytes() { return 4 * minLatitude.getSizeInBytes(); // 4 angles } /** - * Compares this sector to a specified sector according to their minimum latitude, minimum longitude, maximum - * latitude, and maximum longitude, respectively. + * Compares this sector to a specified sector according to their minimum + * latitude, minimum longitude, maximum latitude, and maximum longitude, + * respectively. * * @param that the Sector to compareTo with this. * - * @return -1 if this sector compares less than that specified, 0 if they're equal, and 1 if it compares greater. + * @return -1 if this sector compares less than that specified, 0 if they're + * equal, and 1 if it compares greater. * * @throws IllegalArgumentException if that is null */ - public int compareTo(Sector that) - { - if (that == null) - { + public int compareTo(Sector that) { + if (that == null) { String msg = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (this.getMinLatitude().compareTo(that.getMinLatitude()) < 0) + if (this.getMinLatitude().compareTo(that.getMinLatitude()) < 0) { return -1; + } - if (this.getMinLatitude().compareTo(that.getMinLatitude()) > 0) + if (this.getMinLatitude().compareTo(that.getMinLatitude()) > 0) { return 1; + } - if (this.getMinLongitude().compareTo(that.getMinLongitude()) < 0) + if (this.getMinLongitude().compareTo(that.getMinLongitude()) < 0) { return -1; + } - if (this.getMinLongitude().compareTo(that.getMinLongitude()) > 0) + if (this.getMinLongitude().compareTo(that.getMinLongitude()) > 0) { return 1; + } - if (this.getMaxLatitude().compareTo(that.getMaxLatitude()) < 0) + if (this.getMaxLatitude().compareTo(that.getMaxLatitude()) < 0) { return -1; + } - if (this.getMaxLatitude().compareTo(that.getMaxLatitude()) > 0) + if (this.getMaxLatitude().compareTo(that.getMaxLatitude()) > 0) { return 1; + } - if (this.getMaxLongitude().compareTo(that.getMaxLongitude()) < 0) + if (this.getMaxLongitude().compareTo(that.getMaxLongitude()) < 0) { return -1; + } - if (this.getMaxLongitude().compareTo(that.getMaxLongitude()) > 0) + if (this.getMaxLongitude().compareTo(that.getMaxLongitude()) > 0) { return 1; + } return 0; } /** - * Creates an iterator over the four corners of the sector, starting with the southwest position and continuing - * counter-clockwise. + * Creates an iterator over the four corners of the sector, starting with + * the southwest position and continuing counter-clockwise. * * @return an iterator for the sector. */ - public Iterator iterator() - { - return new Iterator() - { + public Iterator iterator() { + return new Iterator() { private int position = 0; - public boolean hasNext() - { + public boolean hasNext() { return this.position < 4; } - public LatLon next() - { - if (this.position > 3) + public LatLon next() { + if (this.position > 3) { throw new NoSuchElementException(); + } LatLon p; - switch (this.position) - { + switch (this.position) { case 0: p = new LatLon(Sector.this.getMinLatitude(), Sector.this.getMinLongitude()); break; @@ -1696,24 +1713,22 @@ public LatLon next() return p; } - public void remove() - { + public void remove() { throw new UnsupportedOperationException(); } }; } /** - * Returns the coordinates of the sector as a list, in the order minLat, maxLat, minLon, maxLon. + * Returns the coordinates of the sector as a list, in the order minLat, + * maxLat, minLon, maxLon. * * @return the list of sector coordinates. */ - public List asList() - { + public List asList() { ArrayList list = new ArrayList(4); - for (LatLon ll : this) - { + for (LatLon ll : this) { list.add(ll); } @@ -1721,42 +1736,38 @@ public List asList() } /** - * Returns the coordinates of the sector as an array of values in degrees, in the order minLat, maxLat, minLon, - * maxLon. + * Returns the coordinates of the sector as an array of values in degrees, + * in the order minLat, maxLat, minLon, maxLon. * * @return the array of sector coordinates. */ - public double[] asDegreesArray() - { - return new double[] - { - this.getMinLatitude().degrees, this.getMaxLatitude().degrees, - this.getMinLongitude().degrees, this.getMaxLongitude().degrees - }; + public double[] asDegreesArray() { + return new double[]{ + this.getMinLatitude().degrees, this.getMaxLatitude().degrees, + this.getMinLongitude().degrees, this.getMaxLongitude().degrees + }; } /** - * Returns the coordinates of the sector as an array of values in radians, in the order minLat, maxLat, minLon, - * maxLon. + * Returns the coordinates of the sector as an array of values in radians, + * in the order minLat, maxLat, minLon, maxLon. * * @return the array of sector coordinates. */ - public double[] asRadiansArray() - { - return new double[] - { - this.getMinLatitude().radians, this.getMaxLatitude().radians, - this.getMinLongitude().radians, this.getMaxLongitude().radians - }; + public double[] asRadiansArray() { + return new double[]{ + this.getMinLatitude().radians, this.getMaxLatitude().radians, + this.getMinLongitude().radians, this.getMaxLongitude().radians + }; } /** * Returns a list of the Lat/Lon coordinates of a Sector's corners. * - * @return an array of the four corner locations, in the order SW, SE, NE, NW + * @return an array of the four corner locations, in the order SW, SE, NE, + * NW */ - public LatLon[] getCorners() - { + public LatLon[] getCorners() { LatLon[] corners = new LatLon[4]; corners[0] = new LatLon(this.minLatitude, this.minLongitude); @@ -1768,32 +1779,38 @@ public LatLon[] getCorners() } /** - * Tests the equality of the sectors' angles. Sectors are equal if all of their corresponding angles are equal. + * Tests the equality of the sectors' angles. Sectors are equal if all of + * their corresponding angles are equal. * * @param o the sector to compareTo with this. * - * @return true if the four corresponding angles of each sector are equal, false - * otherwise. + * @return true if the four corresponding angles of each sector + * are equal, false otherwise. */ @Override - public boolean equals(Object o) - { - if (this == o) + public boolean equals(Object o) { + if (this == o) { return true; - if (o == null || getClass() != o.getClass()) + } + if (o == null || getClass() != o.getClass()) { return false; + } final gov.nasa.worldwind.geom.Sector sector = (gov.nasa.worldwind.geom.Sector) o; - if (!maxLatitude.equals(sector.maxLatitude)) + if (!maxLatitude.equals(sector.maxLatitude)) { return false; - if (!maxLongitude.equals(sector.maxLongitude)) + } + if (!maxLongitude.equals(sector.maxLongitude)) { return false; - if (!minLatitude.equals(sector.minLatitude)) + } + if (!minLatitude.equals(sector.minLatitude)) { return false; + } //noinspection RedundantIfStatement - if (!minLongitude.equals(sector.minLongitude)) + if (!minLongitude.equals(sector.minLongitude)) { return false; + } return true; } @@ -1804,8 +1821,7 @@ public boolean equals(Object o) * @return a hash code incorporating the sector's four angles. */ @Override - public int hashCode() - { + public int hashCode() { int result; result = minLatitude.hashCode(); result = 29 * result + maxLatitude.hashCode(); @@ -1813,4 +1829,4 @@ public int hashCode() result = 29 * result + maxLongitude.hashCode(); return result; } -} \ No newline at end of file +} diff --git a/src/gov/nasa/worldwind/geom/Triangle.java b/src/gov/nasa/worldwind/geom/Triangle.java index e43cc850f1..16da4df598 100644 --- a/src/gov/nasa/worldwind/geom/Triangle.java +++ b/src/gov/nasa/worldwind/geom/Triangle.java @@ -39,8 +39,8 @@ * @author Eric Dalgliesh 30/11/2006 * @version $Id: Triangle.java 1171 2013-02-11 21:45:02Z dcollins $ */ -public class Triangle -{ +public class Triangle { + private static final double EPSILON = 0.0000001; // used in intersects method private final Vec4 a; @@ -48,8 +48,8 @@ public class Triangle private final Vec4 c; /** - * Construct a triangle from three counter-clockwise ordered vertices. The front face of the triangle is determined - * by the right-hand rule. + * Construct a triangle from three counter-clockwise ordered vertices. The + * front face of the triangle is determined by the right-hand rule. * * @param a the first vertex. * @param b the second vertex. @@ -57,10 +57,8 @@ public class Triangle * * @throws IllegalArgumentException if any vertex is null. */ - public Triangle(Vec4 a, Vec4 b, Vec4 c) - { - if (a == null || b == null || c == null) - { + public Triangle(Vec4 a, Vec4 b, Vec4 c) { + if (a == null || b == null || c == null) { String msg = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -76,8 +74,7 @@ public Triangle(Vec4 a, Vec4 b, Vec4 c) * * @return the first vertex. */ - public Vec4 getA() - { + public Vec4 getA() { return this.a; } @@ -86,8 +83,7 @@ public Vec4 getA() * * @return the second vertex. */ - public Vec4 getB() - { + public Vec4 getB() { return this.b; } @@ -96,8 +92,7 @@ public Vec4 getB() * * @return the third vertex. */ - public Vec4 getC() - { + public Vec4 getC() { return this.c; } @@ -111,7 +106,6 @@ public Vec4 getC() // // return new gov.nasa.worldwind.geom.Plane(n); // } - // private Point temporaryIntersectPlaneAndLine(Line line, Plane plane) // { // Vector n = line.getDirection(); @@ -130,7 +124,6 @@ public Vec4 getC() // d = 1/d; // return new Triangle(this.a.multiply(d), this.b.multiply(d), this.c.multiply(d)); // } - /** * Indicates whether a specified point is on the triangle. * @@ -138,10 +131,10 @@ public Vec4 getC() * * @return true if the point is on the triangle, otherwise false. */ - public boolean contains(Vec4 p) - { - if (p == null) + public boolean contains(Vec4 p) { + if (p == null) { return false; + } // Compute vectors Vec4 v0 = this.c.subtract3(this.a); @@ -174,56 +167,59 @@ public boolean contains(Vec4 p) * * @param line the line to test. * - * @return the point of intersection if the line intersects the triangle, otherwise null. + * @return the point of intersection if the line intersects the triangle, + * otherwise null. * * @throws IllegalArgumentException if the line is null. */ - public Vec4 intersect(Line line) - { + public Vec4 intersect(Line line) { Intersection intersection = intersect(line, this.a, this.b, this.c); return intersection != null ? intersection.getIntersectionPoint() : null; } /** - * Determines the intersection of a specified line with a specified triangle. The triangle is specified by three - * points ordered counterclockwise. The triangle's front face is determined by the right-hand rule. + * Determines the intersection of a specified line with a specified + * triangle. The triangle is specified by three points ordered + * counterclockwise. The triangle's front face is determined by the + * right-hand rule. * * @param line the line to test. - * @param a the first vertex of the triangle. - * @param b the second vertex of the triangle. - * @param c the third vertex of the triangle. + * @param a the first vertex of the triangle. + * @param b the second vertex of the triangle. + * @param c the third vertex of the triangle. * - * @return the point of intersection if the line intersects the triangle, otherwise null. + * @return the point of intersection if the line intersects the triangle, + * otherwise null. * - * @throws IllegalArgumentException if the line or any of the triangle vertices is null. + * @throws IllegalArgumentException if the line or any of the triangle + * vertices is null. */ - public static Intersection intersect(Line line, Vec4 a, Vec4 b, Vec4 c) - { + public static Intersection intersect(Line line, Vec4 a, Vec4 b, Vec4 c) { return intersect(line, a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z); } /** - * Determines the intersection of a specified line with a triangle specified by individual coordinates. + * Determines the intersection of a specified line with a triangle specified + * by individual coordinates. * * @param line the line to test. - * @param vax the X coordinate of the first vertex of the triangle. - * @param vay the Y coordinate of the first vertex of the triangle. - * @param vaz the Z coordinate of the first vertex of the triangle. - * @param vbx the X coordinate of the second vertex of the triangle. - * @param vby the Y coordinate of the second vertex of the triangle. - * @param vbz the Z coordinate of the second vertex of the triangle. - * @param vcx the X coordinate of the third vertex of the triangle. - * @param vcy the Y coordinate of the third vertex of the triangle. - * @param vcz the Z coordinate of the third vertex of the triangle. + * @param vax the X coordinate of the first vertex of the triangle. + * @param vay the Y coordinate of the first vertex of the triangle. + * @param vaz the Z coordinate of the first vertex of the triangle. + * @param vbx the X coordinate of the second vertex of the triangle. + * @param vby the Y coordinate of the second vertex of the triangle. + * @param vbz the Z coordinate of the second vertex of the triangle. + * @param vcx the X coordinate of the third vertex of the triangle. + * @param vcy the Y coordinate of the third vertex of the triangle. + * @param vcz the Z coordinate of the third vertex of the triangle. * - * @return the point of intersection if the line intersects the triangle, otherwise null. + * @return the point of intersection if the line intersects the triangle, + * otherwise null. */ public static Intersection intersect(Line line, - double vax, double vay, double vaz, double vbx, double vby, double vbz, double vcx, double vcy, double vcz) - { - if (line == null) - { + double vax, double vay, double vaz, double vbx, double vby, double vbz, double vcx, double vcy, double vcz) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -232,7 +228,6 @@ public static Intersection intersect(Line line, // taken from Moller and Trumbore // http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/ // Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf - Vec4 origin = line.getOrigin(); Vec4 dir = line.getDirection(); @@ -254,7 +249,9 @@ public static Intersection intersect(Line line, double det = edge1x * pvecx + edge1y * pvecy + edge1z * pvecz; // edge1 dot pvec if (det > -EPSILON && det < EPSILON) // If det is near zero, then ray lies on plane of triangle + { return null; + } double detInv = 1d / det; @@ -265,8 +262,9 @@ public static Intersection intersect(Line line, // Calculate u parameter and test bounds: 1/det * tvec dot pvec double u = detInv * (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz); - if (u < 0 || u > 1) + if (u < 0 || u > 1) { return null; + } // Prepare to test v parameter: tvec cross edge1 double qvecx = (tvecy * edge1z) - (tvecz * edge1y); @@ -275,13 +273,15 @@ public static Intersection intersect(Line line, // Calculate v parameter and test bounds: 1/det * dir dot qvec double v = detInv * (dir.x * qvecx + dir.y * qvecy + dir.z * qvecz); - if (v < 0 || u + v > 1) + if (v < 0 || u + v > 1) { return null; + } // Calculate the point of intersection on the line: t = 1/det * edge2 dot qvec; double t = detInv * (edge2x * qvecx + edge2y * qvecy + edge2z * qvecz); - if (t < 0) + if (t < 0) { return null; + } return new Intersection(line.getPointAt(t), t, false); } @@ -289,25 +289,24 @@ public static Intersection intersect(Line line, /** * Compute the intersections of a line with a triangle strip. * - * @param line the line to intersect. + * @param line the line to intersect. * @param vertices the tri-strip vertices. - * @param indices the indices forming the tri-strip. + * @param indices the indices forming the tri-strip. * - * @return the list of intersections with the line and the tri-strip, or null if there are no intersections. + * @return the list of intersections with the line and the tri-strip, or + * null if there are no intersections. * - * @throws IllegalArgumentException if the line, vertex buffer or index buffer is null. + * @throws IllegalArgumentException if the line, vertex buffer or index + * buffer is null. */ - public static List intersectTriStrip(final Line line, FloatBuffer vertices, IntBuffer indices) - { - if (line == null) - { + public static List intersectTriStrip(final Line line, FloatBuffer vertices, IntBuffer indices) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (vertices == null || indices == null) - { + if (vertices == null || indices == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -315,8 +314,7 @@ public static List intersectTriStrip(final Line line, FloatBuffer List intersections = null; - for (int n = indices.position(); n < indices.limit() - 2; n++) - { + for (int n = indices.position(); n < indices.limit() - 2; n++) { Intersection intersection; int i = indices.get(n) * 3; @@ -326,14 +324,14 @@ public static List intersectTriStrip(final Line line, FloatBuffer // The triangle intersect method detects front and back face intersections so there's no reason to // order the vertices. intersection = intersect(line, - vertices.get(i), vertices.get(i + 1), vertices.get(i + 2), - vertices.get(j), vertices.get(j + 1), vertices.get(j + 2), - vertices.get(k), vertices.get(k + 1), vertices.get(k + 2)); + vertices.get(i), vertices.get(i + 1), vertices.get(i + 2), + vertices.get(j), vertices.get(j + 1), vertices.get(j + 2), + vertices.get(k), vertices.get(k + 1), vertices.get(k + 2)); - if (intersection != null) - { - if (intersections == null) + if (intersection != null) { + if (intersections == null) { intersections = new ArrayList(); + } intersections.add(intersection); } } @@ -344,32 +342,30 @@ public static List intersectTriStrip(final Line line, FloatBuffer /** * Compute the intersections of a line with a triangle strip. * - * @param line the line to intersect. + * @param line the line to intersect. * @param vertices the tri-strip vertices. - * @param indices the indices forming the tri-strip. + * @param indices the indices forming the tri-strip. * - * @return the list of intersections with the line and the triangle strip, or null if there are no intersections. + * @return the list of intersections with the line and the triangle strip, + * or null if there are no intersections. * - * @throws IllegalArgumentException if the line, vertex array or index buffer is null. + * @throws IllegalArgumentException if the line, vertex array or index + * buffer is null. */ - public static List intersectTriStrip(final Line line, Vec4[] vertices, IntBuffer indices) - { - if (line == null) - { + public static List intersectTriStrip(final Line line, Vec4[] vertices, IntBuffer indices) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (vertices == null) - { + if (vertices == null) { String msg = Logging.getMessage("nullValue.ArrayIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (indices == null) - { + if (indices == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -377,8 +373,7 @@ public static List intersectTriStrip(final Line line, Vec4[] verti List intersections = null; - for (int n = indices.position(); n < indices.limit() - 1; n++) - { + for (int n = indices.position(); n < indices.limit() - 1; n++) { Intersection intersection; int i = indices.get(n) * 3; @@ -389,10 +384,10 @@ public static List intersectTriStrip(final Line line, Vec4[] verti // order the vertices. intersection = intersect(line, vertices[i], vertices[j], vertices[k]); - if (intersection != null) - { - if (intersections == null) + if (intersection != null) { + if (intersections == null) { intersections = new ArrayList(); + } intersections.add(intersection); } } @@ -403,25 +398,24 @@ public static List intersectTriStrip(final Line line, Vec4[] verti /** * Compute the intersections of a line with a triangle fan. * - * @param line the line to intersect. + * @param line the line to intersect. * @param vertices the tri-fan vertices. - * @param indices the indices forming the tri-fan. + * @param indices the indices forming the tri-fan. * - * @return the list of intersections with the line and the triangle fan, or null if there are no intersections. + * @return the list of intersections with the line and the triangle fan, or + * null if there are no intersections. * - * @throws IllegalArgumentException if the line, vertex buffer or index buffer is null. + * @throws IllegalArgumentException if the line, vertex buffer or index + * buffer is null. */ - public static List intersectTriFan(final Line line, FloatBuffer vertices, IntBuffer indices) - { - if (line == null) - { + public static List intersectTriFan(final Line line, FloatBuffer vertices, IntBuffer indices) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (vertices == null || indices == null) - { + if (vertices == null || indices == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -437,8 +431,7 @@ public static List intersectTriFan(final Line line, FloatBuffer ve float v0z = vertices.get(k * 3 + 2); // Starting with the second position in the index buffer, get subsequent indices and vertices. - for (int n = indices.position(); n < indices.limit() - 1; n++) - { + for (int n = indices.position(); n < indices.limit() - 1; n++) { Intersection intersection; int i = indices.get(n) * 3; @@ -447,14 +440,14 @@ public static List intersectTriFan(final Line line, FloatBuffer ve // The triangle intersect method detects front and back face intersections so there's no reason to // order the vertices. intersection = intersect(line, - v0x, v0y, v0z, - vertices.get(i), vertices.get(i + 1), vertices.get(i + 2), - vertices.get(j), vertices.get(j + 1), vertices.get(j + 2)); + v0x, v0y, v0z, + vertices.get(i), vertices.get(i + 1), vertices.get(i + 2), + vertices.get(j), vertices.get(j + 1), vertices.get(j + 2)); - if (intersection != null) - { - if (intersections == null) + if (intersection != null) { + if (intersections == null) { intersections = new ArrayList(); + } intersections.add(intersection); } } @@ -465,32 +458,30 @@ public static List intersectTriFan(final Line line, FloatBuffer ve /** * Compute the intersections of a line with a triangle fan. * - * @param line the line to intersect. + * @param line the line to intersect. * @param vertices the tri-fan vertices. - * @param indices the indices forming the tri-fan. + * @param indices the indices forming the tri-fan. * - * @return the list of intersections with the line and the triangle fan, or null if there are no intersections. + * @return the list of intersections with the line and the triangle fan, or + * null if there are no intersections. * - * @throws IllegalArgumentException if the line, vertex array or index buffer is null. + * @throws IllegalArgumentException if the line, vertex array or index + * buffer is null. */ - public static List intersectTriFan(final Line line, Vec4[] vertices, IntBuffer indices) - { - if (line == null) - { + public static List intersectTriFan(final Line line, Vec4[] vertices, IntBuffer indices) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (vertices == null) - { + if (vertices == null) { String msg = Logging.getMessage("nullValue.ArrayIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (indices == null) - { + if (indices == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -500,8 +491,7 @@ public static List intersectTriFan(final Line line, Vec4[] vertice Vec4 v0 = vertices[0]; - for (int n = indices.position() + 1; n < indices.limit() - 1; n++) - { + for (int n = indices.position() + 1; n < indices.limit() - 1; n++) { Intersection intersection; Vec4 v1 = vertices[indices.get(n)]; @@ -510,10 +500,10 @@ public static List intersectTriFan(final Line line, Vec4[] vertice // The triangle intersect method detects front and back face intersections so there's no reason to // order the vertices. intersection = intersect(line, v0, v1, v2); - if (intersection != null) - { - if (intersections == null) + if (intersection != null) { + if (intersections == null) { intersections = new ArrayList(); + } intersections.add(intersection); } } @@ -524,24 +514,23 @@ public static List intersectTriFan(final Line line, Vec4[] vertice /** * Compute the intersections of a line with a collection of triangles. * - * @param line the line to intersect. - * @param vertices the triangles, arranged in a buffer as GL_TRIANGLES (9 floats per triangle). + * @param line the line to intersect. + * @param vertices the triangles, arranged in a buffer as GL_TRIANGLES (9 + * floats per triangle). * - * @return the list of intersections with the line and the triangles, or null if there are no intersections. + * @return the list of intersections with the line and the triangles, or + * null if there are no intersections. * * @throws IllegalArgumentException if the line or vertex buffer is null. */ - public static List intersectTriangles(final Line line, FloatBuffer vertices) - { - if (line == null) - { + public static List intersectTriangles(final Line line, FloatBuffer vertices) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (vertices == null) - { + if (vertices == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -551,17 +540,16 @@ public static List intersectTriangles(final Line line, FloatBuffer vertices.rewind(); - while (vertices.limit() - vertices.position() >= 9) - { + while (vertices.limit() - vertices.position() >= 9) { Intersection intersection = intersect(line, - vertices.get(), vertices.get(), vertices.get(), - vertices.get(), vertices.get(), vertices.get(), - vertices.get(), vertices.get(), vertices.get()); + vertices.get(), vertices.get(), vertices.get(), + vertices.get(), vertices.get(), vertices.get(), + vertices.get(), vertices.get(), vertices.get()); - if (intersection != null) - { - if (intersections == null) + if (intersection != null) { + if (intersections == null) { intersections = new ArrayList(); + } intersections.add(intersection); } } @@ -572,25 +560,25 @@ public static List intersectTriangles(final Line line, FloatBuffer /** * Compute the intersections of a line with a collection of triangles. * - * @param line the line to intersect. - * @param vertices the triangles, arranged in a buffer as GL_TRIANGLES (9 floats per triangle). - * @param indices the indices forming the triangles. + * @param line the line to intersect. + * @param vertices the triangles, arranged in a buffer as GL_TRIANGLES (9 + * floats per triangle). + * @param indices the indices forming the triangles. * - * @return the list of intersections with the line and the triangle fan, or null if there are no intersections. + * @return the list of intersections with the line and the triangle fan, or + * null if there are no intersections. * - * @throws IllegalArgumentException if the line, vertex buffer or index buffer is null. + * @throws IllegalArgumentException if the line, vertex buffer or index + * buffer is null. */ - public static List intersectTriangles(final Line line, FloatBuffer vertices, IntBuffer indices) - { - if (line == null) - { + public static List intersectTriangles(final Line line, FloatBuffer vertices, IntBuffer indices) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (vertices == null || indices == null) - { + if (vertices == null || indices == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -598,8 +586,7 @@ public static List intersectTriangles(final Line line, FloatBuffer List intersections = null; - for (int n = indices.position(); n < indices.limit(); n += 3) - { + for (int n = indices.position(); n < indices.limit(); n += 3) { Intersection intersection; int i = indices.get(n) * 3; @@ -607,14 +594,14 @@ public static List intersectTriangles(final Line line, FloatBuffer int k = indices.get(n + 2) * 3; intersection = intersect(line, - vertices.get(i), vertices.get(i + 1), vertices.get(i + 2), - vertices.get(j), vertices.get(j + 1), vertices.get(j + 2), - vertices.get(k), vertices.get(k + 1), vertices.get(k + 2)); + vertices.get(i), vertices.get(i + 1), vertices.get(i + 2), + vertices.get(j), vertices.get(j + 1), vertices.get(j + 2), + vertices.get(k), vertices.get(k + 1), vertices.get(k + 2)); - if (intersection != null) - { - if (intersections == null) + if (intersection != null) { + if (intersections == null) { intersections = new ArrayList(); + } intersections.add(intersection); } } @@ -625,63 +612,63 @@ public static List intersectTriangles(final Line line, FloatBuffer /** * Compute the intersections of a line with a triangle collection. * - * @param line the line to intersect. - * @param vertices the tri-fan vertices, in the order x, y, z, x, y, z, ... - * @param indices the indices forming the tri-fan. - * @param triangleType the type of triangle collection, either GL.GL_TRIANGLE_STRIP or GL.GL_TRIANGLE_FAN. + * @param line the line to intersect. + * @param vertices the tri-fan vertices, in the order x, y, z, x, y, z, ... + * @param indices the indices forming the tri-fan. + * @param triangleType the type of triangle collection, either + * GL.GL_TRIANGLE_STRIP or GL.GL_TRIANGLE_FAN. * - * @return the list of intersections with the line and the triangle fan, or null if there are no intersections. + * @return the list of intersections with the line and the triangle fan, or + * null if there are no intersections. */ public static List intersectTriangleTypes(final Line line, FloatBuffer vertices, IntBuffer indices, - int triangleType) - { - if (triangleType == GL.GL_TRIANGLES) + int triangleType) { + if (triangleType == GL.GL_TRIANGLES) { return Triangle.intersectTriangles(line, vertices, indices); - else if (triangleType == GL.GL_TRIANGLE_STRIP) + } else if (triangleType == GL.GL_TRIANGLE_STRIP) { return Triangle.intersectTriStrip(line, vertices, indices); - else if (triangleType == GL.GL_TRIANGLE_FAN) + } else if (triangleType == GL.GL_TRIANGLE_FAN) { return Triangle.intersectTriFan(line, vertices, indices); + } return null; } /** - * Expands a buffer of indexed triangle vertices to a buffer of non-indexed triangle vertices. + * Expands a buffer of indexed triangle vertices to a buffer of non-indexed + * triangle vertices. * * @param indices the triangle indices. - * @param inBuf the vertex buffer the indices refer to, in the order x, y, z, x, y, z, ... - * @param outBuf the buffer in which to place the expanded triangle vertices. The buffer must have a limit - * sufficient to hold the output vertices. + * @param inBuf the vertex buffer the indices refer to, in the order x, y, + * z, x, y, z, ... + * @param outBuf the buffer in which to place the expanded triangle + * vertices. The buffer must have a limit sufficient to hold the output + * vertices. * - * @throws IllegalArgumentException if the index list or the input or output buffer is null, or if the output buffer - * size is insufficient. + * @throws IllegalArgumentException if the index list or the input or output + * buffer is null, or if the output buffer size is insufficient. */ - public static void expandTriangles(List indices, FloatBuffer inBuf, FloatBuffer outBuf) - { - if (indices == null) - { + public static void expandTriangles(List indices, FloatBuffer inBuf, FloatBuffer outBuf) { + if (indices == null) { String msg = Logging.getMessage("nullValue.ListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (inBuf == null || outBuf == null) - { + if (inBuf == null || outBuf == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int nunTriangles = indices.size() / 3; - if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position()) - { + if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position()) { String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - for (int i = 0; i < indices.size(); i += 3) - { + for (int i = 0; i < indices.size(); i += 3) { int k = indices.get(i) * 3; outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2)); @@ -694,35 +681,34 @@ public static void expandTriangles(List indices, FloatBuffer inBuf, Flo } /** - * Expands a buffer of indexed triangle fan vertices to a buffer of non-indexed general-triangle vertices. + * Expands a buffer of indexed triangle fan vertices to a buffer of + * non-indexed general-triangle vertices. * * @param indices the triangle indices. - * @param inBuf the vertex buffer the indices refer to, in the order x, y, z, x, y, z, ... - * @param outBuf the buffer in which to place the expanded triangle vertices. The buffer must have a limit - * sufficient to hold the output vertices. + * @param inBuf the vertex buffer the indices refer to, in the order x, y, + * z, x, y, z, ... + * @param outBuf the buffer in which to place the expanded triangle + * vertices. The buffer must have a limit sufficient to hold the output + * vertices. * - * @throws IllegalArgumentException if the index list or the input or output buffer is null, or if the output buffer - * size is insufficient. + * @throws IllegalArgumentException if the index list or the input or output + * buffer is null, or if the output buffer size is insufficient. */ - public static void expandTriangleFan(List indices, FloatBuffer inBuf, FloatBuffer outBuf) - { - if (indices == null) - { + public static void expandTriangleFan(List indices, FloatBuffer inBuf, FloatBuffer outBuf) { + if (indices == null) { String msg = Logging.getMessage("nullValue.ListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (inBuf == null || outBuf == null) - { + if (inBuf == null || outBuf == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int nunTriangles = indices.size() - 2; - if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position()) - { + if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position()) { String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -733,8 +719,7 @@ public static void expandTriangleFan(List indices, FloatBuffer inBuf, F float v0y = inBuf.get(k + 1); float v0z = inBuf.get(k + 2); - for (int i = 1; i < indices.size() - 1; i++) - { + for (int i = 1; i < indices.size() - 1; i++) { outBuf.put(v0x).put(v0y).put(v0z); k = indices.get(i) * 3; @@ -746,42 +731,40 @@ public static void expandTriangleFan(List indices, FloatBuffer inBuf, F } /** - * Expands a buffer of indexed triangle strip vertices to a buffer of non-indexed general-triangle vertices. + * Expands a buffer of indexed triangle strip vertices to a buffer of + * non-indexed general-triangle vertices. * * @param indices the triangle indices. - * @param inBuf the vertex buffer the indices refer to, in the order x, y, z, x, y, z, ... - * @param outBuf the buffer in which to place the expanded triangle vertices. The buffer must have a limit - * sufficient to hold the output vertices. + * @param inBuf the vertex buffer the indices refer to, in the order x, y, + * z, x, y, z, ... + * @param outBuf the buffer in which to place the expanded triangle + * vertices. The buffer must have a limit sufficient to hold the output + * vertices. * - * @throws IllegalArgumentException if the index list or the input or output buffer is null, or if the output buffer - * size is insufficient. + * @throws IllegalArgumentException if the index list or the input or output + * buffer is null, or if the output buffer size is insufficient. */ - public static void expandTriangleStrip(List indices, FloatBuffer inBuf, FloatBuffer outBuf) - { - if (indices == null) - { + public static void expandTriangleStrip(List indices, FloatBuffer inBuf, FloatBuffer outBuf) { + if (indices == null) { String msg = Logging.getMessage("nullValue.ListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (inBuf == null || outBuf == null) - { + if (inBuf == null || outBuf == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int nunTriangles = indices.size() - 2; - if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position()) - { + if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position()) { String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - for (int i = 2; i < indices.size(); i++) - { + for (int i = 2; i < indices.size(); i++) { int k = indices.get(i - 2) * 3; outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2)); @@ -793,55 +776,46 @@ public static void expandTriangleStrip(List indices, FloatBuffer inBuf, } } - public static void expandTriangles(List indices, IntBuffer outBuf) - { - if (indices == null) - { + public static void expandTriangles(List indices, IntBuffer outBuf) { + if (indices == null) { String msg = Logging.getMessage("nullValue.ListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (outBuf == null) - { + if (outBuf == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int numTriangles = indices.size() / 3; - if (numTriangles * 3 > outBuf.limit() - outBuf.position()) - { + if (numTriangles * 3 > outBuf.limit() - outBuf.position()) { String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - for (int i = 0; i < indices.size(); i++) - { + for (int i = 0; i < indices.size(); i++) { outBuf.put(indices.get(i)); } } - public static void expandTriangleFan(List indices, IntBuffer outBuf) - { - if (indices == null) - { + public static void expandTriangleFan(List indices, IntBuffer outBuf) { + if (indices == null) { String msg = Logging.getMessage("nullValue.ListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (outBuf == null) - { + if (outBuf == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int nunTriangles = indices.size() - 2; - if (nunTriangles * 3 > outBuf.limit() - outBuf.position()) - { + if (nunTriangles * 3 > outBuf.limit() - outBuf.position()) { String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -849,40 +823,34 @@ public static void expandTriangleFan(List indices, IntBuffer outBuf) int k0 = indices.get(0); - for (int i = 1; i < indices.size() - 1; i++) - { + for (int i = 1; i < indices.size() - 1; i++) { outBuf.put(k0); outBuf.put(indices.get(i)); outBuf.put(indices.get(i + 1)); } } - public static void expandTriangleStrip(List indices, IntBuffer outBuf) - { - if (indices == null) - { + public static void expandTriangleStrip(List indices, IntBuffer outBuf) { + if (indices == null) { String msg = Logging.getMessage("nullValue.ListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - if (outBuf == null) - { + if (outBuf == null) { String msg = Logging.getMessage("nullValue.BufferIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } int nunTriangles = indices.size() - 2; - if (nunTriangles * 3 > outBuf.limit() - outBuf.position()) - { + if (nunTriangles * 3 > outBuf.limit() - outBuf.position()) { String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position()); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - for (int i = 2; i < indices.size(); i++) - { + for (int i = 2; i < indices.size(); i++) { outBuf.put(indices.get(i - 2)); outBuf.put(indices.get(i % 2 == 0 ? i - 1 : i)); outBuf.put(indices.get(i % 2 == 0 ? i : i - 1)); @@ -890,11 +858,11 @@ public static void expandTriangleStrip(List indices, IntBuffer outBuf) } /** - * Defines a line segment representing the intersection of a line with and in the plane of a triangle. Used only - * within {@link #intersectTriangles}. + * Defines a line segment representing the intersection of a line with and + * in the plane of a triangle. Used only within {@link #intersectTriangles}. */ - protected static class TriangleIntersection - { + protected static class TriangleIntersection { + public Vec4 p0; // the first point of the line public Vec4 p1; // the second point of the line public double s0; // the distance along the line to the first intersection with the triangle @@ -904,15 +872,15 @@ protected static class TriangleIntersection /** * Intersects two triangles and returns their intersection vertices. * - * @param v the Cartesian coordinates of the first triangle. - * @param u the Cartesian coordinates of the second triangle. - * @param intersectionVertices a pre-allocated two-element array in which the intersection vertices, if any, are - * returned. + * @param v the Cartesian coordinates of the first triangle. + * @param u the Cartesian coordinates of the second triangle. + * @param intersectionVertices a pre-allocated two-element array in which + * the intersection vertices, if any, are returned. * - * @return -1 if there is no intersection, 1 if there is an intersection, or 0 if the triangles are co-planar. + * @return -1 if there is no intersection, 1 if there is an intersection, or + * 0 if the triangles are co-planar. */ - public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVertices) - { + public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVertices) { // Taken from http://jgt.akpeters.com/papers/Moller97/tritri.html#ISECTLINE // Compute plane equation of first triangle: n1 * x + d1 = 0. @@ -931,18 +899,23 @@ public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVert double du2 = n1.dot3(u[2]) + d1; // Coplanarity robustness check. - if (Math.abs(du0) < EPSILON) + if (Math.abs(du0) < EPSILON) { du0 = 0; - if (Math.abs(du1) < EPSILON) + } + if (Math.abs(du1) < EPSILON) { du1 = 0; - if (Math.abs(du2) < EPSILON) + } + if (Math.abs(du2) < EPSILON) { du2 = 0; + } double du0du1 = du0 * du1; double du0du2 = du0 * du2; if (du0du1 > 0 && du0du2 > 0) // same sign on all of them + != 0 ==> no intersection + { return -1; + } // Compute plane equation of second triangle: n2 * x + d2 = 0 e1x = u[1].x - u[0].x; @@ -960,18 +933,23 @@ public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVert double dv2 = n2.dot3(v[2]) + d2; // Coplanarity robustness check. - if (Math.abs(dv0) < EPSILON) + if (Math.abs(dv0) < EPSILON) { dv0 = 0; - if (Math.abs(dv1) < EPSILON) + } + if (Math.abs(dv1) < EPSILON) { dv1 = 0; - if (Math.abs(dv2) < EPSILON) + } + if (Math.abs(dv2) < EPSILON) { dv2 = 0; + } double dv0dv1 = dv0 * dv1; double dv0dv2 = dv0 * dv2; if (dv0dv1 > 0 && dv0dv2 > 0) // same sign on all of them + != 0 ==> no intersection + { return -1; + } // Compute direction of intersection line. Vec4 ld = n1.cross3(n2); @@ -981,13 +959,11 @@ public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVert int index = 0; double b = Math.abs(ld.y); double c = Math.abs(ld.z); - if (b > max) - { + if (b > max) { max = b; index = 1; } - if (c > max) - { + if (c > max) { index = 2; } @@ -999,8 +975,7 @@ public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVert double up0 = u[0].x; double up1 = u[1].x; double up2 = u[2].x; - if (index == 1) - { + if (index == 1) { vp0 = v[0].y; vp1 = v[1].y; vp2 = v[2].y; @@ -1008,9 +983,7 @@ public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVert up0 = u[0].y; up1 = u[1].y; up2 = u[2].y; - } - else if (index == 2) - { + } else if (index == 2) { vp0 = v[0].z; vp1 = v[1].z; vp2 = v[2].z; @@ -1023,12 +996,12 @@ else if (index == 2) // Compute interval for triangle 1. TriangleIntersection isectA = compute_intervals_isectline(v, vp0, vp1, vp2, dv0, dv1, dv2, dv0dv1, dv0dv2); - if (isectA == null) + if (isectA == null) { return coplanarTriangles(n1, v, u) ? 0 : -1; + } int smallest1 = 0; - if (isectA.s0 > isectA.s1) - { + if (isectA.s0 > isectA.s1) { double cc = isectA.s0; isectA.s0 = isectA.s1; isectA.s1 = cc; @@ -1039,62 +1012,58 @@ else if (index == 2) TriangleIntersection isectB = compute_intervals_isectline(u, up0, up1, up2, du0, du1, du2, du0du1, du0du2); int smallest2 = 0; - if (isectB.s0 > isectB.s1) - { + if (isectB.s0 > isectB.s1) { double cc = isectB.s0; isectB.s0 = isectB.s1; isectB.s1 = cc; smallest2 = 1; } - if (isectA.s1 < isectB.s0 || isectB.s1 < isectA.s0) + if (isectA.s1 < isectB.s0 || isectB.s1 < isectA.s0) { return -1; + } // At this point we know that the triangles intersect: there's an intersection line, the triangles are not // coplanar, and they overlap. - - if (isectB.s0 < isectA.s0) - { - if (smallest1 == 0) + if (isectB.s0 < isectA.s0) { + if (smallest1 == 0) { intersectionVertices[0] = isectA.p0; - else + } else { intersectionVertices[0] = isectA.p1; + } - if (isectB.s1 < isectA.s1) - { - if (smallest2 == 0) + if (isectB.s1 < isectA.s1) { + if (smallest2 == 0) { intersectionVertices[1] = isectB.p1; - else + } else { intersectionVertices[1] = isectB.p0; - } - else - { - if (smallest1 == 0) + } + } else { + if (smallest1 == 0) { intersectionVertices[1] = isectA.p1; - else + } else { intersectionVertices[1] = isectA.p0; + } } - } - else - { - if (smallest2 == 0) + } else { + if (smallest2 == 0) { intersectionVertices[0] = isectB.p0; - else + } else { intersectionVertices[0] = isectB.p1; + } - if (isectB.s1 > isectA.s1) - { - if (smallest1 == 0) + if (isectB.s1 > isectA.s1) { + if (smallest1 == 0) { intersectionVertices[1] = isectA.p1; - else + } else { intersectionVertices[1] = isectA.p0; - } - else - { - if (smallest2 == 0) + } + } else { + if (smallest2 == 0) { intersectionVertices[1] = isectB.p1; - else + } else { intersectionVertices[1] = isectB.p0; + } } } @@ -1102,26 +1071,26 @@ else if (index == 2) } protected static TriangleIntersection compute_intervals_isectline(Vec4[] v, double vv0, double vv1, double vv2, - double d0, double d1, double d2, - double d0d1, double d0d2) - { + double d0, double d1, double d2, + double d0d1, double d0d2) { if (d0d1 > 0) // D0, D1 are on the same side, D2 on the other or on the plane + { return intersect(v[2], v[0], v[1], vv2, vv0, vv1, d2, d0, d1); - else if (d0d2 > 0) + } else if (d0d2 > 0) { return intersect(v[1], v[0], v[2], vv1, vv0, vv2, d1, d0, d2); - else if (d1 * d2 > 0 || d0 != 0) + } else if (d1 * d2 > 0 || d0 != 0) { return intersect(v[0], v[1], v[2], vv0, vv1, vv2, d0, d1, d2); - else if (d1 != 0) + } else if (d1 != 0) { return intersect(v[1], v[0], v[2], vv1, vv0, vv2, d1, d0, d2); - else if (d2 != 0) + } else if (d2 != 0) { return intersect(v[2], v[0], v[1], vv2, vv0, vv1, d2, d0, d1); - else + } else { return null; // triangles are coplanar + } } protected static TriangleIntersection intersect(Vec4 v0, Vec4 v1, Vec4 v2, double vv0, double vv1, double vv2, - double d0, double d1, double d2) - { + double d0, double d1, double d2) { TriangleIntersection intersection = new TriangleIntersection(); double tmp = d0 / (d0 - d1); @@ -1139,91 +1108,87 @@ protected static TriangleIntersection intersect(Vec4 v0, Vec4 v1, Vec4 v2, doubl return intersection; } - protected static boolean coplanarTriangles(Vec4 n, Vec4[] v, Vec4[] u) - { + protected static boolean coplanarTriangles(Vec4 n, Vec4[] v, Vec4[] u) { // First project onto an axis-aligned plane that maximizes the are of the triangles. int i0; int i1; - double[] a = new double[] {Math.abs(n.x), Math.abs(n.y), Math.abs(n.z)}; + double[] a = new double[]{Math.abs(n.x), Math.abs(n.y), Math.abs(n.z)}; if (a[0] > a[1]) // X > Y { - if (a[0] > a[2]) - { // X is greatest + if (a[0] > a[2]) { // X is greatest i0 = 1; i1 = 2; - } - else - { // Z is greatest + } else { // Z is greatest i0 = 0; i1 = 1; } - } - else // X < Y + } else // X < Y { - if (a[2] > a[1]) - { // Z is greatest + if (a[2] > a[1]) { // Z is greatest i0 = 0; i1 = 1; - } - else - { // Y is greatest + } else { // Y is greatest i0 = 0; i1 = 2; } } // Test all edges of triangle 1 against the edges of triangle 2. - double[] v0 = new double[] {v[0].x, v[0].y, v[0].z}; - double[] v1 = new double[] {v[1].x, v[1].y, v[1].z}; - double[] v2 = new double[] {v[2].x, v[2].y, v[2].z}; + double[] v0 = new double[]{v[0].x, v[0].y, v[0].z}; + double[] v1 = new double[]{v[1].x, v[1].y, v[1].z}; + double[] v2 = new double[]{v[2].x, v[2].y, v[2].z}; - double[] u0 = new double[] {u[0].x, u[0].y, u[0].z}; - double[] u1 = new double[] {u[1].x, u[1].y, u[1].z}; - double[] u2 = new double[] {u[2].x, u[2].y, u[2].z}; + double[] u0 = new double[]{u[0].x, u[0].y, u[0].z}; + double[] u1 = new double[]{u[1].x, u[1].y, u[1].z}; + double[] u2 = new double[]{u[2].x, u[2].y, u[2].z}; boolean tf = triangleEdgeTest(v0, v1, u0, u1, u2, i0, i1); - if (tf) + if (tf) { return true; + } tf = triangleEdgeTest(v1, v2, u0, u1, u2, i0, i1); - if (tf) + if (tf) { return true; + } tf = triangleEdgeTest(v2, v0, u0, u1, u2, i0, i1); - if (tf) + if (tf) { return true; + } // Finally, test whether one triangle is contained in the other one. tf = pointInTri(v0, u0, u1, u2, i0, i1); - if (tf) + if (tf) { return true; + } return pointInTri(u0, v0, v1, v2, i0, i1); } protected static boolean triangleEdgeTest(double[] v0, double[] v1, double[] u0, double[] u1, double[] u2, int i0, - int i1) - { + int i1) { double ax = v1[i0] - v0[i0]; double ay = v1[i1] - v0[i1]; // Test edge u0:u1 against v0:v1 boolean tf = edgeEdgeTest(v0, u0, u1, i0, i1, ax, ay); - if (tf) + if (tf) { return true; + } // Test edge u1:u2 against v0:v1 tf = edgeEdgeTest(v0, u1, u2, i0, i1, ax, ay); - if (tf) + if (tf) { return true; + } // Test edge u2:u0 against v0:v1 return edgeEdgeTest(v0, u2, u0, i0, i1, ax, ay); } - protected static boolean edgeEdgeTest(double[] v0, double[] u0, double[] u1, int i0, int i1, double ax, double ay) - { + protected static boolean edgeEdgeTest(double[] v0, double[] u0, double[] u1, int i0, int i1, double ax, double ay) { double bx = u0[i0] - u1[i0]; double by = u0[i1] - u1[i1]; double cx = v0[i0] - u0[i0]; @@ -1232,26 +1197,23 @@ protected static boolean edgeEdgeTest(double[] v0, double[] u0, double[] u1, int double f = ay * bx - ax * by; double d = by * cx - bx * cy; - if ((f > 0 && d >= 0 && d <= f) || (f < 0 && d <= 0 && d >= f)) - { + if ((f > 0 && d >= 0 && d <= f) || (f < 0 && d <= 0 && d >= f)) { double e = ax * cy - ay * cx; - if (f > 0) - { - if (e >= 0 && e <= f) + if (f > 0) { + if (e >= 0 && e <= f) { return true; - } - else - { - if (e <= 0 && e >= f) + } + } else { + if (e <= 0 && e >= f) { return true; + } } } return false; } - protected static boolean pointInTri(double[] v0, double[] u0, double[] u1, double[] u2, int i0, int i1) - { + protected static boolean pointInTri(double[] v0, double[] u0, double[] u1, double[] u2, int i0, int i1) { double a = u1[i1] - u0[i1]; double b = -(u1[i0] - u0[i0]); double c = -a * u0[i0] - b * u0[i1]; @@ -1270,8 +1232,7 @@ protected static boolean pointInTri(double[] v0, double[] u0, double[] u1, doubl return d0 * d1 > 0 && d0 * d2 > 0; } - public String toString() - { + public String toString() { return "Triangle (" + a + ", " + b + ", " + c + ")"; } } diff --git a/src/gov/nasa/worldwind/terrain/SectorGeometryList.java b/src/gov/nasa/worldwind/terrain/SectorGeometryList.java index 65fb268c26..e23cd94d6f 100644 --- a/src/gov/nasa/worldwind/terrain/SectorGeometryList.java +++ b/src/gov/nasa/worldwind/terrain/SectorGeometryList.java @@ -43,35 +43,38 @@ * @author tag * @version $Id: SectorGeometryList.java 1537 2013-08-07 19:58:01Z dcollins $ */ -public class SectorGeometryList extends ArrayList -{ - /** The spanning sector of all sector geometries contained in this list. */ +public class SectorGeometryList extends ArrayList { + + /** + * The spanning sector of all sector geometries contained in this list. + */ protected Sector sector; protected PickSupport pickSupport = new PickSupport(); protected HashMap> pickSectors = new HashMap>(); - /** Constructs an empty sector geometry list. */ - public SectorGeometryList() - { + /** + * Constructs an empty sector geometry list. + */ + public SectorGeometryList() { } /** - * Constructs a sector geometry list that contains a specified list of sector geometries. + * Constructs a sector geometry list that contains a specified list of + * sector geometries. * * @param list the secter geometries to place in the list. */ - public SectorGeometryList(SectorGeometryList list) - { + public SectorGeometryList(SectorGeometryList list) { super(list); } /** * Indicates the spanning sector of all sector geometries in this list. * - * @return a sector that is the union of all sectors of entries in this list. + * @return a sector that is the union of all sectors of entries in this + * list. */ - public Sector getSector() - { + public Sector getSector() { return sector; } @@ -80,69 +83,69 @@ public Sector getSector() * * @param sector the sector spanned by this list. */ - public void setSector(Sector sector) - { + public void setSector(Sector sector) { this.sector = sector; } /** - * Indicates that this list's sectors are about to be rendered. When rendering is complete, the {@link + * Indicates that this list's sectors are about to be rendered. When + * rendering is complete, the {@link * #endRendering(gov.nasa.worldwind.render.DrawContext)} must be called. * - * @param dc the current draw context. + * @param dc the current draw context. */ - public void beginRendering(DrawContext dc) - { - if (dc == null) - { + public void beginRendering(DrawContext dc) { + if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } // TODO: add the beginRendering interface to Tessellator in order to eliminate this type test - if (dc.getGlobe().getTessellator() instanceof RectangularTessellator) + if (dc.getGlobe().getTessellator() instanceof RectangularTessellator) { ((RectangularTessellator) dc.getGlobe().getTessellator()).beginRendering(dc); + } } /** - * Restores state established by {@link #beginRendering(gov.nasa.worldwind.render.DrawContext)}. + * Restores state established by + * {@link #beginRendering(gov.nasa.worldwind.render.DrawContext)}. * * @param dc the current draw context. */ - public void endRendering(DrawContext dc) - { - if (dc == null) - { + public void endRendering(DrawContext dc) { + if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } - if (dc.getGlobe().getTessellator() instanceof RectangularTessellator) + if (dc.getGlobe().getTessellator() instanceof RectangularTessellator) { ((RectangularTessellator) dc.getGlobe().getTessellator()).endRendering(dc); + } } /** - * Detects the locations of the sector geometries in this list that intersect a specified screen point. + * Detects the locations of the sector geometries in this list that + * intersect a specified screen point. *

      - * Note: Prior to calling this method, {@link #beginRendering(gov.nasa.worldwind.render.DrawContext)} must be + * Note: Prior to calling this method, + * {@link #beginRendering(gov.nasa.worldwind.render.DrawContext)} must be * called. * - * @param dc the current draw context. + * @param dc the current draw context. * @param pickPoint the screen point to test. */ - public void pick(DrawContext dc, java.awt.Point pickPoint) - { - if (dc == null) - { + public void pick(DrawContext dc, java.awt.Point pickPoint) { + if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } - if (pickPoint == null) + if (pickPoint == null) { return; + } this.pickSupport.clearPickList(); this.pickSupport.beginPicking(dc); @@ -150,12 +153,10 @@ public void pick(DrawContext dc, java.awt.Point pickPoint) GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. gl.glShadeModel(GL2.GL_FLAT); - try - { + try { // render each sector in unique color this.beginRendering(dc); - for (SectorGeometry sector : this) - { + for (SectorGeometry sector : this) { Color color = dc.getUniquePickColor(); gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); sector.render(dc); @@ -164,15 +165,13 @@ public void pick(DrawContext dc, java.awt.Point pickPoint) } PickedObject pickedSector = this.pickSupport.getTopObject(dc, pickPoint); - if (pickedSector == null || pickedSector.getObject() == null) + if (pickedSector == null || pickedSector.getObject() == null) { return; // no sector picked - + } this.beginSectorGeometryPicking(dc); SectorGeometry sector = (SectorGeometry) pickedSector.getObject(); sector.pick(dc, pickPoint); - } - finally - { + } finally { this.endSectorGeometryPicking(dc); this.endRendering(dc); gl.glShadeModel(GL2.GL_SMOOTH); // restore to default explicitly to avoid more expensive pushAttrib @@ -183,28 +182,29 @@ public void pick(DrawContext dc, java.awt.Point pickPoint) } /** - * Detects the locations of the sector geometries in this list that intersect any of the points in a specified list - * of screen points. + * Detects the locations of the sector geometries in this list that + * intersect any of the points in a specified list of screen points. *

      - * Note: Prior to calling this method, {@link #beginRendering(gov.nasa.worldwind.render.DrawContext)} must be + * Note: Prior to calling this method, + * {@link #beginRendering(gov.nasa.worldwind.render.DrawContext)} must be * called. * - * @param dc the current draw context. + * @param dc the current draw context. * @param pickPoints the points to test. * - * @return an array of picked objects that intersect one or more of the specified screen points. + * @return an array of picked objects that intersect one or more of the + * specified screen points. */ - public List pick(DrawContext dc, List pickPoints) - { - if (dc == null) - { + public List pick(DrawContext dc, List pickPoints) { + if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } - if (pickPoints == null || pickPoints.size() < 1) + if (pickPoints == null || pickPoints.size() < 1) { return null; + } this.pickSupport.clearPickList(); this.pickSupport.beginPicking(dc); @@ -212,12 +212,10 @@ public List pick(DrawContext dc, List pickPoints) GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. gl.glShadeModel(GL2.GL_FLAT); - try - { + try { // render each sector in a unique color this.beginRendering(dc); - for (SectorGeometry sector : this) - { + for (SectorGeometry sector : this) { Color color = dc.getUniquePickColor(); gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); sector.render(dc); @@ -228,50 +226,46 @@ public List pick(DrawContext dc, List pickPoints) // Determine the sectors underneath the pick points. Assemble a pick-points per sector map. // Several pick points might intersect the same sector. this.pickSectors.clear(); - for (Point pickPoint : pickPoints) - { + for (Point pickPoint : pickPoints) { PickedObject pickedSector = this.pickSupport.getTopObject(dc, pickPoint); - if (pickedSector == null || pickedSector.getObject() == null) + if (pickedSector == null || pickedSector.getObject() == null) { continue; + } SectorGeometry sector = (SectorGeometry) pickedSector.getObject(); ArrayList sectorPickPoints; - if (!this.pickSectors.containsKey(sector)) - { + if (!this.pickSectors.containsKey(sector)) { sectorPickPoints = new ArrayList(); this.pickSectors.put(sector, sectorPickPoints); - } - else - { + } else { sectorPickPoints = this.pickSectors.get(sector); } sectorPickPoints.add(pickPoint); } - if (this.pickSectors.size() < 1) + if (this.pickSectors.size() < 1) { return null; + } // Now have each sector determine the pick position for each intersecting pick point. this.beginSectorGeometryPicking(dc); ArrayList pickedObjects = new ArrayList(); - for (Map.Entry> sector : this.pickSectors.entrySet()) - { + for (Map.Entry> sector : this.pickSectors.entrySet()) { ArrayList sectorPickPoints = sector.getValue(); PickedObject[] pos = sector.getKey().pick(dc, sectorPickPoints); - if (pos == null) + if (pos == null) { continue; + } - for (PickedObject po : pos) - { - if (po != null) + for (PickedObject po : pos) { + if (po != null) { pickedObjects.add(po); + } } } return pickedObjects; - } - finally - { + } finally { this.endSectorGeometryPicking(dc); this.endRendering(dc); gl.glShadeModel(GL2.GL_SMOOTH); // restore to default explicitly to avoid more expensive pushAttrib @@ -282,14 +276,15 @@ public List pick(DrawContext dc, List pickPoints) } /** - * Indicates that sector geometry picking is about to be performed. Configures the state necessary to correctly draw - * sector geometry in a second pass using unique per-triangle colors. When picking is complete, {@link - * #endSectorGeometryPicking(gov.nasa.worldwind.render.DrawContext)} must be called. + * Indicates that sector geometry picking is about to be performed. + * Configures the state necessary to correctly draw sector geometry in a + * second pass using unique per-triangle colors. When picking is complete, {@link + * #endSectorGeometryPicking(gov.nasa.worldwind.render.DrawContext)} must be + * called. * * @param dc the current draw context. */ - protected void beginSectorGeometryPicking(DrawContext dc) - { + protected void beginSectorGeometryPicking(DrawContext dc) { GL gl = dc.getGL(); gl.glDepthFunc(GL.GL_LEQUAL); @@ -298,8 +293,7 @@ protected void beginSectorGeometryPicking(DrawContext dc) // color geometry's depth values toward the eye and disable depth buffer writes. This works around an issue // where the VMware driver breaks OpenGL's invariance requirement when per-vertex colors are enabled. // See WWJ-425. - if (dc.getGLRuntimeCapabilities().isVMwareSVGA3D()) - { + if (dc.getGLRuntimeCapabilities().isVMwareSVGA3D()) { gl.glDepthMask(false); gl.glEnable(GL.GL_POLYGON_OFFSET_FILL); gl.glPolygonOffset(-1f, -1f); @@ -307,18 +301,17 @@ protected void beginSectorGeometryPicking(DrawContext dc) } /** - * Restores state established by {@link #beginSectorGeometryPicking(gov.nasa.worldwind.render.DrawContext)}. + * Restores state established by + * {@link #beginSectorGeometryPicking(gov.nasa.worldwind.render.DrawContext)}. * * @param dc the current draw context. */ - protected void endSectorGeometryPicking(DrawContext dc) - { + protected void endSectorGeometryPicking(DrawContext dc) { GL gl = dc.getGL(); gl.glDepthFunc(GL.GL_LESS); // restore to default explicitly to avoid more expensive pushAttrib - if (dc.getGLRuntimeCapabilities().isVMwareSVGA3D()) - { + if (dc.getGLRuntimeCapabilities().isVMwareSVGA3D()) { gl.glDepthMask(true); gl.glDisable(GL.GL_POLYGON_OFFSET_FILL); gl.glPolygonOffset(0f, 0f); @@ -326,16 +319,18 @@ protected void endSectorGeometryPicking(DrawContext dc) } /** - * Computes a Cartesian point at a specified latitude, longitude and altitude above the terrain. + * Computes a Cartesian point at a specified latitude, longitude and + * altitude above the terrain. * - * @param position the position to compute the Cartesian point for. The altitude element of the position is - * considered to be distance above the terrain at the position's latitude and longitude. + * @param position the position to compute the Cartesian point for. The + * altitude element of the position is considered to be distance above the + * terrain at the position's latitude and longitude. * - * @return the Cartesian point, in meters, relative to an origin of (0, 0, 0). Will be null if there is no sector - * geometry in this list for the specifed latitude and longitude. + * @return the Cartesian point, in meters, relative to an origin of (0, 0, + * 0). Will be null if there is no sector geometry in this list for the + * specifed latitude and longitude. */ - public Vec4 getSurfacePoint(Position position) - { + public Vec4 getSurfacePoint(Position position) { return this.getSurfacePoint(position.getLatitude(), position.getLongitude(), position.getElevation()); } @@ -344,55 +339,55 @@ public Vec4 getSurfacePoint(Position position) * * @param latLon the location of the point to compute. * - * @return the Cartesian point, in meters, relative to an origin of (0, 0, 0). Will be null if there is no sector - * geometry in this list for the specifed latitude and longitude. + * @return the Cartesian point, in meters, relative to an origin of (0, 0, + * 0). Will be null if there is no sector geometry in this list for the + * specifed latitude and longitude. */ - public Vec4 getSurfacePoint(LatLon latLon) - { + public Vec4 getSurfacePoint(LatLon latLon) { return this.getSurfacePoint(latLon.getLatitude(), latLon.getLongitude(), 0d); } /** * Computes a Cartesian point at a specified location on the terrain. * - * @param latitude the latitude of the point to compute. + * @param latitude the latitude of the point to compute. * @param longitude the longitude of the point to compute. * - * @return the Cartesian point, in meters, relative to an origin of (0, 0, 0). Will be null if there is no sector - * geometry in this list for the specifed latitude and longitude. + * @return the Cartesian point, in meters, relative to an origin of (0, 0, + * 0). Will be null if there is no sector geometry in this list for the + * specifed latitude and longitude. */ - public Vec4 getSurfacePoint(Angle latitude, Angle longitude) - { + public Vec4 getSurfacePoint(Angle latitude, Angle longitude) { return this.getSurfacePoint(latitude, longitude, 0d); } /** - * Computes a Cartesian point at a specified latitude, longitude and altitude above the terrain. + * Computes a Cartesian point at a specified latitude, longitude and + * altitude above the terrain. * - * @param latitude the latitude of the point to compute. - * @param longitude the longitude of the point to compute. - * @param metersOffset the distance above the terrain of the point to compute. + * @param latitude the latitude of the point to compute. + * @param longitude the longitude of the point to compute. + * @param metersOffset the distance above the terrain of the point to + * compute. * - * @return the Cartesian point, in meters, relative to an origin of (0, 0, 0). Will be null if there is no sector - * geometry in this list for the specifed latitude and longitude. + * @return the Cartesian point, in meters, relative to an origin of (0, 0, + * 0). Will be null if there is no sector geometry in this list for the + * specifed latitude and longitude. */ - public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset) - { - if (latitude == null || longitude == null) - { + public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset) { + if (latitude == null || longitude == null) { String msg = Logging.getMessage("nullValue.LatLonIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } - for (int i = 0; i < this.size(); i++) - { + for (int i = 0; i < this.size(); i++) { SectorGeometry sg = this.get(i); - if (sg.getSector().contains(latitude, longitude)) - { + if (sg.getSector().contains(latitude, longitude)) { Vec4 point = sg.getSurfacePoint(latitude, longitude, metersOffset); - if (point != null) + if (point != null) { return point; + } } } @@ -402,15 +397,14 @@ public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset /** * Determines if and where a ray intersects the geometry. * - * @param line the Line for which an intersection is to be found. + * @param line the Line for which an intersection is to be + * found. * - * @return the <Vec4> point closest to the ray origin where an intersection has been found or null if no - * intersection was found. + * @return the <Vec4> point closest to the ray origin where an + * intersection has been found or null if no intersection was found. */ - public Intersection[] intersect(Line line) - { - if (line == null) - { + public Intersection[] intersect(Line line) { + if (line == null) { String msg = Logging.getMessage("nullValue.LineIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); @@ -420,31 +414,34 @@ public Intersection[] intersect(Line line) Intersection[] hits; ArrayList list = new ArrayList(); - for (SectorGeometry sg : sglist) - { - if (sg.getExtent().intersects(line)) - if ((hits = sg.intersect(line)) != null) + for (SectorGeometry sg : sglist) { + if (sg.getExtent().intersects(line)) { + if ((hits = sg.intersect(line)) != null) { list.addAll(Arrays.asList(hits)); + } + } } int numHits = list.size(); - if (numHits == 0) + if (numHits == 0) { return null; + } hits = new Intersection[numHits]; list.toArray(hits); final Vec4 origin = line.getOrigin(); - Arrays.sort(hits, new Comparator() - { - public int compare(Intersection i1, Intersection i2) - { - if (i1 == null && i2 == null) + Arrays.sort(hits, new Comparator() { + public int compare(Intersection i1, Intersection i2) { + if (i1 == null && i2 == null) { return 0; - if (i2 == null) + } + if (i2 == null) { return -1; - if (i1 == null) + } + if (i1 == null) { return 1; + } Vec4 v1 = i1.getIntersectionPoint(); Vec4 v2 = i2.getIntersectionPoint(); @@ -457,23 +454,26 @@ public int compare(Intersection i1, Intersection i2) } /** - * Determines if and where the geometry intersects the ellipsoid at a given elevation. + * Determines if and where the geometry intersects the ellipsoid at a given + * elevation. *

      - * The returned array of Intersection describes a list of individual segments - two - * Intersection for each, corresponding to each geometry triangle that intersects the given elevation. + * The returned array of Intersection describes a list of + * individual segments - two Intersection for each, + * corresponding to each geometry triangle that intersects the given + * elevation. *

      - * Note that the provided bounding Sector only serves as a 'hint' to avoid processing unnecessary - * geometry tiles. The returned intersection list may contain segments outside that sector. + * Note that the provided bounding Sector only serves as a + * 'hint' to avoid processing unnecessary geometry tiles. The returned + * intersection list may contain segments outside that sector. * * @param elevation the elevation for which intersections are to be found. - * @param sector the sector inside which intersections are to be found. + * @param sector the sector inside which intersections are to be found. * - * @return a list of Intersection pairs/segments describing a contour line at the given elevation. + * @return a list of Intersection pairs/segments describing a + * contour line at the given elevation. */ - public Intersection[] intersect(double elevation, Sector sector) - { - if (sector == null) - { + public Intersection[] intersect(double elevation, Sector sector) { + if (sector == null) { String message = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); @@ -483,16 +483,18 @@ public Intersection[] intersect(double elevation, Sector sector) Intersection[] hits; ArrayList list = new ArrayList(); - for (SectorGeometry sg : sglist) - { - if (sector.intersects(sg.getSector())) - if ((hits = sg.intersect(elevation)) != null) + for (SectorGeometry sg : sglist) { + if (sector.intersects(sg.getSector())) { + if ((hits = sg.intersect(elevation)) != null) { list.addAll(Arrays.asList(hits)); + } + } } int numHits = list.size(); - if (numHits == 0) + if (numHits == 0) { return null; + } hits = new Intersection[numHits]; list.toArray(hits); diff --git a/src/gov/nasa/worldwindx/examples/ColladaViewer.java b/src/gov/nasa/worldwindx/examples/ColladaViewer.java new file mode 100644 index 0000000000..1347481433 --- /dev/null +++ b/src/gov/nasa/worldwindx/examples/ColladaViewer.java @@ -0,0 +1,152 @@ +/* + * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source + * software: + * + * Jackson Parser – Licensed under Apache 2.0 + * GDAL – Licensed under MIT + * JOGL – Licensed under Berkeley Software Distribution (BSD) + * Gluegen – Licensed under Berkeley Software Distribution (BSD) + * + * A complete listing of 3rd Party software notices and licenses included in + * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party + * notices and licenses PDF found in code directory. + */ +package gov.nasa.worldwindx.examples; + +import gov.nasa.worldwind.*; +import gov.nasa.worldwind.avlist.AVKey; +import gov.nasa.worldwind.geom.Position; +import gov.nasa.worldwind.layers.Layer; +import gov.nasa.worldwind.layers.LayerList; +import gov.nasa.worldwind.layers.RenderableLayer; +import gov.nasa.worldwind.ogc.collada.ColladaRoot; +import gov.nasa.worldwind.ogc.collada.impl.ColladaController; +import gov.nasa.worldwind.util.WWUtil; + +import javax.swing.*; +import java.awt.*; +import java.io.File; + +/** + * Shows how to load COLLADA 3D models. + */ +public class ColladaViewer extends ApplicationTemplate { + + public static class AppFrame extends ApplicationTemplate.AppFrame { + + public AppFrame() { + super(true, true, false); // Don't include the layer panel; we're using the on-screen layer tree. + + // Size the WorldWindow to take up the space typically used by the layer panel. + Dimension size = new Dimension(1400, 800); + this.setPreferredSize(size); + this.pack(); + WWUtil.alignComponent(null, this, AVKey.CENTER); + LayerList layers = getWwd().getModel().getLayers(); + for (Layer layer : layers) { + String layerName = layer.getName(); + if (layerName != null && layerName.toLowerCase().startsWith("bing")) { + layer.setEnabled(true); + break; + } + } + } + + /** + * Adds the specified colladaRoot to this app frame's WorldWindow as a new + * Layer. + * + * @param colladaRoot the ColladaRoot to add a new layer for. + */ + protected void addColladaLayer(ColladaRoot colladaRoot) { + // Create a ColladaController to adapt the ColladaRoot to the WorldWind renderable interface. + ColladaController colladaController = new ColladaController(colladaRoot); + + // Adds a new layer containing the ColladaRoot to the end of the WorldWindow's layer list. + RenderableLayer layer = new RenderableLayer(); + layer.addRenderable(colladaController); + this.getWwd().getModel().getLayers().add(layer); + } + } + + // A Thread that loads a COLLADA file and displays it in an AppFrame. + public static class WorkerThread extends Thread { + + // Indicates the source of the COLLADA file loaded by this thread. Initialized during construction. + protected Object colladaSource; + + // Geographic position of the COLLADA model. + protected Position position; + + // Indicates the AppFrame the COLLADA file content is displayed in. Initialized during + // construction. + protected AppFrame appFrame; + + /** + * Creates a new worker thread from a specified colladaSource and appFrame. + * + * @param colladaSource the source of the COLLADA file to load. May be a {@link java.io.File}, a {@link + * java.net.URL}, or an {@link java.io.InputStream}, or a {@link String} identifying a file path or URL. + * @param position the geographic position of the COLLADA model. + * @param appFrame the AppFrame in which to display the COLLADA source. + */ + public WorkerThread(Object colladaSource, Position position, AppFrame appFrame) { + this.colladaSource = colladaSource; + this.position = position; + this.appFrame = appFrame; + } + + /** + * Loads this worker thread's COLLADA source into a new + * {@link gov.nasa.worldwind.ogc.collada.ColladaRoot}, then adds the new ColladaRoot + * to this worker thread's AppFrame. + */ + @Override + public void run() { + try { + final ColladaRoot colladaRoot = ColladaRoot.createAndParse(this.colladaSource); + colladaRoot.setPosition(this.position); + colladaRoot.setAltitudeMode(WorldWind.RELATIVE_TO_GROUND); + + // Schedule a task on the EDT to add the parsed document to a layer + SwingUtilities.invokeLater(() -> { + appFrame.addColladaLayer(colladaRoot); + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static void main(String[] args) { + + // Set camera position and pitch angle. + Configuration.setValue(AVKey.INITIAL_LATITUDE, 40.028); + Configuration.setValue(AVKey.INITIAL_LONGITUDE, -105.27284091410579); + Configuration.setValue(AVKey.INITIAL_ALTITUDE, 4000); + Configuration.setValue(AVKey.INITIAL_PITCH, 50); + + // Set the application frame to update, a position for the model, and a path to the COLLADA file. + final AppFrame af = (AppFrame) start("WorldWind COLLADA Viewer", AppFrame.class); + final Position MackyAuditoriumPosition = Position.fromDegrees(40.009993372683, -105.272774533734); + final File ColladaFile = new File("testData/collada/cu_macky/CU Macky.dae"); + + // Invoke the Thread to load the COLLADA model asynchronously. + new WorkerThread(ColladaFile, MackyAuditoriumPosition, af).start(); + + } +}