gov.nasa.worldwind.util.WWUtil Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.util;
import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.geom.coords.UTMCoord;
import java.awt.*;
import java.lang.reflect.*;
import java.nio.*;
import java.text.*;
import java.util.regex.Pattern;
/**
* @author tag
* @version $Id: WWUtil.java 2396 2014-10-27 23:46:42Z tgaskins $
*/
public class WWUtil
{
/**
* Converts a specified string to an integer value. Returns null if the string cannot be converted.
*
* @param s the string to convert.
*
* @return integer value of the string, or null if the string cannot be converted.
*
* @throws IllegalArgumentException if the string is null.
*/
public static Integer convertStringToInteger(String s)
{
if (s == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
try
{
if (s.length() == 0)
{
return null;
}
return Integer.valueOf(s);
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", s);
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
return null;
}
}
/**
* Converts a specified string to a floating point value. Returns null if the string cannot be converted.
*
* @param s the string to convert.
*
* @return floating point value of the string, or null if the string cannot be converted.
*
* @throws IllegalArgumentException if the string is null.
*/
public static Double convertStringToDouble(String s)
{
if (s == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
try
{
if (s.length() == 0)
{
return null;
}
return Double.valueOf(s);
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", s);
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
return null;
}
}
/**
* Converts a specified string to a long integer value. Returns null if the string cannot be converted.
*
* @param s the string to convert.
*
* @return long integer value of the string, or null if the string cannot be converted.
*
* @throws IllegalArgumentException if the string is null.
*/
public static Long convertStringToLong(String s)
{
if (s == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
try
{
if (s.length() == 0)
{
return null;
}
return Long.valueOf(s);
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", s);
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
return null;
}
}
/**
* Converts a specified string to a boolean value. Returns null if the string cannot be converted.
*
* @param s the string to convert.
*
* @return boolean value of the string, or null if the string cannot be converted.
*
* @throws IllegalArgumentException if the string is null.
*/
public static Boolean convertStringToBoolean(String s)
{
if (s == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
try
{
s = s.trim();
if (s.length() == 0)
return null;
if (s.length() == 1)
return convertNumericStringToBoolean(s);
return Boolean.valueOf(s);
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", s);
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
return null;
}
}
/**
* Converts a specified string to a boolean value. Returns null if the string cannot be converted.
*
* @param s the string to convert.
*
* @return boolean value of the string, or null if the string cannot be converted.
*
* @throws IllegalArgumentException if the string is null.
*/
public static Boolean convertNumericStringToBoolean(String s)
{
if (s == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
try
{
if (s.length() == 0)
{
return null;
}
Integer i = makeInteger(s);
return i != null && i != 0;
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", s);
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
return null;
}
}
/**
* Parses a string to an integer value if the string can be parsed as a integer. Does not log a message if the
* string can not be parsed as an integer.
*
* @param s the string to parse.
*
* @return the integer value parsed from the string, or null if the string cannot be parsed as an integer.
*/
public static Integer makeInteger(String s)
{
if (WWUtil.isEmpty(s))
{
return null;
}
try
{
return Integer.valueOf(s);
}
catch (NumberFormatException e)
{
return null;
}
}
/**
* Parses a string to a long value if the string can be parsed as a long. Does not log a message if the string can
* not be parsed as a long.
*
* @param s the string to parse.
*
* @return the long value parsed from the string, or null if the string cannot be parsed as a long.
*/
public static Long makeLong(String s)
{
if (WWUtil.isEmpty(s))
{
return null;
}
try
{
return Long.valueOf(s);
}
catch (NumberFormatException e)
{
return null;
}
}
/**
* Parses a string to a double value using the current locale if the string can be parsed as a double. Does not log
* a message if the string can not be parsed as a double.
*
* @param s the string to parse.
*
* @return the double value parsed from the string, or null if the string cannot be parsed as a double.
*/
public static Double makeDoubleForLocale(String s)
{
if (WWUtil.isEmpty(s))
{
return null;
}
try
{
return NumberFormat.getInstance().parse(s.trim()).doubleValue();
}
catch (ParseException e)
{
return null;
}
}
/**
* Parses a string to a double value if the string can be parsed as a double. Does not log a message if the string
* can not be parsed as a double.
*
* @param s the string to parse.
*
* @return the double value parsed from the string, or null if the string cannot be parsed as a double.
*/
public static Double makeDouble(String s)
{
if (WWUtil.isEmpty(s))
{
return null;
}
try
{
return Double.valueOf(s);
}
catch (NumberFormatException e)
{
return null;
}
}
/**
* Returns a sub sequence of the specified {@link CharSequence}, with leading and trailing whitespace omitted. If
* the CharSequence has length zero, this returns a reference to the CharSequence. If the CharSequence represents
* and empty character sequence, this returns an empty CharSequence.
*
* @param charSequence the CharSequence to trim.
*
* @return a sub sequence with leading and trailing whitespace omitted.
*
* @throws IllegalArgumentException if the charSequence is null.
*/
public static CharSequence trimCharSequence(CharSequence charSequence)
{
if (charSequence == null)
{
String message = Logging.getMessage("nullValue.CharSequenceIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
int len = charSequence.length();
if (len == 0)
{
return charSequence;
}
int start, end;
for (start = 0; (start < len) && charSequence.charAt(start) == ' '; start++)
{
}
for (end = charSequence.length() - 1; (end > start) && charSequence.charAt(end) == ' '; end--)
{
}
return charSequence.subSequence(start, end + 1);
}
public static void alignComponent(Component parent, Component child, String alignment)
{
Dimension prefSize = child.getPreferredSize();
java.awt.Point parentLocation = parent != null ? parent.getLocation() : new java.awt.Point(0, 0);
Dimension parentSize = parent != null ? parent.getSize() : Toolkit.getDefaultToolkit().getScreenSize();
int x = parentLocation.x;
int y = parentLocation.y;
if (alignment != null && alignment.equals(AVKey.RIGHT))
{
x += parentSize.width - 50;
y += parentSize.height - prefSize.height;
}
else if (alignment != null && alignment.equals(AVKey.CENTER))
{
x += (parentSize.width - prefSize.width) / 2;
y += (parentSize.height - prefSize.height) / 2;
}
else if (alignment != null && alignment.equals(AVKey.LEFT_OF_CENTER))
{
x += parentSize.width / 2 - 1.05 * prefSize.width;
y += (parentSize.height - prefSize.height) / 2;
}
else if (alignment != null && alignment.equals(AVKey.RIGHT_OF_CENTER))
{
x += parentSize.width / 2 + 0.05 * prefSize.width;
y += (parentSize.height - prefSize.height) / 2;
}
// else it's left aligned by default
child.setLocation(x, y);
}
/**
* Generates a random {@link Color} by scaling each of the red, green and blue components of a specified color with
* independent random numbers. The alpha component is not scaled and is copied to the new color. The returned color
* can be any value between white (0x000000aa) and black (0xffffffaa).
*
* Unless there's a reason to use a specific input color, the best color to use is white.
*
* @param color the color to generate a random color from. If null, the color white (0x000000aa) is used.
*
* @return a new color with random red, green and blue components.
*/
public static Color makeRandomColor(Color color)
{
if (color == null)
{
color = Color.WHITE;
}
float[] cc = color.getRGBComponents(null);
return new Color(cc[0] * (float) Math.random(), cc[1] * (float) Math.random(), cc[2] * (float) Math.random(),
cc[3]);
}
/**
* Generates a random {@link Color} by scaling each of the red, green and blue components of a specified color with
* independent random numbers. The alpha component is not scaled and is copied to the new color. The returned color
* can be any value between white (0x000000aa) and a specified darkest color.
*
* Unless there's a reason to use a specific input color, the best color to use is white.
*
* @param color the color to generate a random color from. If null, the color white (0x000000aa) is used.
* @param darkestColor the darkest color allowed. If any of the generated color's components are less than the
* corresponding component in this color, new colors are generated until one satisfies this
* requirement, up to the specified maximum number of attempts.
* @param maxAttempts the maximum number of attempts to create a color lighter than the specified darkestColor. If
* this limit is reached, the last color generated is returned.
*
* @return a new color with random red, green and blue components.
*/
public static Color makeRandomColor(Color color, Color darkestColor, int maxAttempts)
{
Color randomColor = makeRandomColor(color);
if (darkestColor == null)
{
return randomColor;
}
float[] dc = darkestColor.getRGBComponents(null);
float[] rc = randomColor.getRGBComponents(null);
for (int i = 0; i < (maxAttempts - 1) && (rc[0] < dc[0] || rc[1] < dc[1] || rc[2] < dc[2]); i++)
{
rc = randomColor.getRGBComponents(null);
}
return randomColor;
}
public static Color makeColorBrighter(Color color)
{
if (color == null)
{
String message = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
float[] hsbComponents = new float[3];
Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsbComponents);
float hue = hsbComponents[0];
float saturation = hsbComponents[1];
float brightness = hsbComponents[2];
saturation /= 3f;
brightness *= 3f;
if (saturation < 0f)
{
saturation = 0f;
}
if (brightness > 1f)
{
brightness = 1f;
}
int rgbInt = Color.HSBtoRGB(hue, saturation, brightness);
return new Color(rgbInt);
}
public static Color makeColorDarker(Color color)
{
if (color == null)
{
String message = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
float[] hsbComponents = new float[3];
Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsbComponents);
float hue = hsbComponents[0];
float saturation = hsbComponents[1];
float brightness = hsbComponents[2];
saturation *= 3f;
brightness /= 3f;
if (saturation > 1f)
{
saturation = 1f;
}
if (brightness < 0f)
{
brightness = 0f;
}
int rgbInt = Color.HSBtoRGB(hue, saturation, brightness);
return new Color(rgbInt);
}
public static Color computeContrastingColor(Color color)
{
if (color == null)
{
String message = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
float[] compArray = new float[4];
Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), compArray);
int colorValue = compArray[2] < 0.5f ? 255 : 0;
int alphaValue = color.getAlpha();
return new Color(colorValue, colorValue, colorValue, alphaValue);
}
/**
* Returns the component-wise linear interpolation of color1
and color2
. Each of the RGBA
* components in the colors are interpolated according to the function: (1 - amount) * c1 + amount *
* c2
, where c1 and c2 are components of color1
and color2
, respectively. The
* interpolation factor amount
defines the weight given to each value, and is clamped to the range [0,
* 1].
*
* @param amount the interpolation factor.
* @param color1 the first color.
* @param color2 the second color.
*
* @return this returns the linear interpolation of color1
and color2
if is
* between 0 and 1, a color equivalent to color1 if amount
is 0 or less, or a color equivalent
* to color2
if amount
is 1 or more.
*
* @throws IllegalArgumentException if either color1
or color2
are null
.
*/
public static Color interpolateColor(double amount, Color color1, Color color2)
{
if (color1 == null || color2 == null)
{
String message = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
float t = (amount < 0 ? 0 : (amount > 1 ? 1 : (float) amount));
float r = color1.getRed() + t * (color2.getRed() - color1.getRed());
float g = color1.getGreen() + t * (color2.getGreen() - color1.getGreen());
float b = color1.getBlue() + t * (color2.getBlue() - color1.getBlue());
float a = color1.getAlpha() + t * (color2.getAlpha() - color1.getAlpha());
return new Color(r / 255f, g / 255f, b / 255f, a / 255f);
}
/**
* Creates a hexadecimal string representation of a {@link Color} in the form 0xrrggbbaa.
*
* @param color Color to encode.
*
* @return String encoding of the specified color.
*
* @throws IllegalArgumentException If the specified color is null.
* @see #decodeColorRGBA(String)
* @see #encodeColorABGR(java.awt.Color)
*/
public static String encodeColorRGBA(java.awt.Color color)
{
if (color == null)
{
String message = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// Encode the red, green, blue, and alpha components
int rgba = (color.getRed() & 0xFF) << 24
| (color.getGreen() & 0xFF) << 16
| (color.getBlue() & 0xFF) << 8
| (color.getAlpha() & 0xFF);
return String.format("%#08X", rgba);
}
/**
* Creates a hexadecimal string representation of a {@link Color} in the form 0xaabbggrr.
*
* @param color Color to encode.
*
* @return String encoding of the specified color.
*
* @throws IllegalArgumentException If the specified color is null.
* @see #decodeColorABGR(String)
* @see #encodeColorRGBA(java.awt.Color)
*/
public static String encodeColorABGR(java.awt.Color color)
{
if (color == null)
{
String message = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// Encode the red, green, blue, and alpha components
int rgba = (color.getRed() & 0xFF)
| (color.getGreen() & 0xFF) << 8
| (color.getBlue() & 0xFF) << 16
| (color.getAlpha() & 0xFF) << 24;
return String.format("%#08X", rgba);
}
/**
* Decodes a hexadecimal string in the form rrggbbaa, rrggbbaa or #rrggbbaa to a color.
*
* @param encodedString String to decode.
*
* @return the decoded color, or null if the string cannot be decoded.
*
* @throws IllegalArgumentException If the specified string is null.
* @see #decodeColorABGR(String) (String)
* @see #encodeColorRGBA(java.awt.Color)
*/
public static java.awt.Color decodeColorRGBA(String encodedString)
{
if (encodedString == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (encodedString.startsWith("#"))
{
encodedString = encodedString.replaceFirst("#", "0x");
}
else if (!encodedString.startsWith("0x") && !encodedString.startsWith("0X"))
{
encodedString = "0x" + encodedString;
}
// The hexadecimal representation for an RGBA color can result in a value larger than
// Integer.MAX_VALUE (for example, 0XFFFF). Therefore we decode the string as a long,
// then keep only the lower four bytes.
Long longValue;
try
{
longValue = Long.parseLong(encodedString.substring(2), 16);
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", encodedString);
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
return null;
}
int i = (int) (longValue & 0xFFFFFFFFL);
return new java.awt.Color(
(i >> 24) & 0xFF,
(i >> 16) & 0xFF,
(i >> 8) & 0xFF,
i & 0xFF);
}
/**
* Decodes a hexadecimal string in the form aabbggrr, 0xaabbggrr or #aabbggrr to a color.
*
* @param encodedString String to decode.
*
* @return the decoded color, or null if the string cannot be decoded.
*
* @throws IllegalArgumentException If the specified string is null.
* @see #decodeColorRGBA(String)
* @see #encodeColorABGR(java.awt.Color)
*/
public static java.awt.Color decodeColorABGR(String encodedString)
{
if (encodedString == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (encodedString.startsWith("#"))
{
encodedString = encodedString.replaceFirst("#", "0x");
}
else if (!encodedString.startsWith("0x") && !encodedString.startsWith("0X"))
{
encodedString = "0x" + encodedString;
}
// The hexadecimal representation for an RGBA color can result in a value larger than
// Integer.MAX_VALUE (for example, 0XFFFF). Therefore we decode the string as a long,
// then keep only the lower four bytes.
Long longValue;
try
{
longValue = Long.parseLong(encodedString.substring(2), 16);
}
catch (NumberFormatException e)
{
String message = Logging.getMessage("generic.ConversionError", encodedString);
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
return null;
}
int i = (int) (longValue & 0xFFFFFFFFL);
return new java.awt.Color(
i & 0xFF,
(i >> 8) & 0xFF,
(i >> 16) & 0xFF,
(i >> 24) & 0xFF);
}
/**
* Determine whether an object reference is null or a reference to an empty string.
*
* @param s the reference to examine.
*
* @return true if the reference is null or is a zero-length {@link String}.
*/
public static boolean isEmpty(Object s)
{
return s == null || (s instanceof String && ((String) s).length() == 0);
}
/**
* Determine whether an {@link List} is null or empty.
*
* @param list the list to examine.
*
* @return true if the list is null or zero-length.
*/
public static boolean isEmpty(java.util.List> list)
{
return list == null || list.size() == 0;
}
/**
* Creates a two-element array of default min and max values, typically used to initialize extreme values searches.
*
* @return a two-element array of extreme values. Entry 0 is the maximum double value; entry 1 is the negative of
* the maximum double value;
*/
public static double[] defaultMinMix()
{
return new double[] {Double.MAX_VALUE, -Double.MAX_VALUE};
}
/**
* Converts the specified buffer of UTM tuples to geographic coordinates, according to the specified UTM zone and
* hemisphere. The buffer must be organized as pairs of tightly packed UTM tuples in the order (easting,
* northing)
. Each UTM tuple is replaced with its corresponding geographic location in the order
* (longitude, latitude)
. Geographic locations are expressed in degrees. Tuples are replaced starting
* at the buffer's position and ending at its limit.
*
* @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 buffer the buffer of UTM tuples to convert.
*
* @throws IllegalArgumentException if zone
is outside the range 1-60, if hemisphere
is
* null, if hemisphere
is not one of {@link gov.nasa.worldwind.avlist.AVKey#NORTH}
* or {@link gov.nasa.worldwind.avlist.AVKey#SOUTH}, if buffer
is
* null, or if the number of remaining elements in buffer
is not a
* multiple of two.
*/
public static void convertUTMCoordinatesToGeographic(int zone, String hemisphere, DoubleBuffer buffer)
{
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))
{
String message = Logging.getMessage("generic.HemisphereIsInvalid", hemisphere);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (buffer == null)
{
String message = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if ((buffer.remaining() % 2) != 0)
{
String message = Logging.getMessage("generic.BufferSize", buffer.remaining());
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
while (buffer.hasRemaining())
{
buffer.mark();
double easting = buffer.get();
double northing = buffer.get();
LatLon location = UTMCoord.locationFromUTMCoord(zone, hemisphere, easting, northing, null);
buffer.reset();
buffer.put(location.getLongitude().degrees);
buffer.put(location.getLatitude().degrees);
}
}
/**
* Normalizes the specified buffer of geographic tuples. The buffer must be organized as pairs of tightly packed
* geographic tuples in the order (longitude, latitude)
. Each geographic tuple is normalized to the
* range +-90 latitude and +-180 longitude and replaced with its normalized values. Geographic locations are
* expressed in degrees. Tuples are replaced starting at the buffer's position and ending at its limit.
*
* @param buffer the buffer of geographic tuples to convert.
*
* @throws IllegalArgumentException if buffer
is null, or if the number of remaining elements in
* buffer
is not a multiple of two.
*/
public static void normalizeGeographicCoordinates(DoubleBuffer buffer)
{
if (buffer == null)
{
String message = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if ((buffer.remaining() % 2) != 0)
{
String message = Logging.getMessage("generic.BufferSize", buffer.remaining());
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
while (buffer.hasRemaining())
{
buffer.mark();
Angle lon = Angle.fromDegrees(buffer.get());
Angle lat = Angle.fromDegrees(buffer.get());
buffer.reset();
buffer.put(Angle.normalizedLongitude(lon).degrees);
buffer.put(Angle.normalizedLatitude(lat).degrees);
}
}
/**
* Uses reflection to invoke a set method for a specified property. The specified class must have a method
* named "set" + propertyName, with either a single String
argument, a single double
* argument, a single int
argument or a single long
argument. If it does, the method is
* called with the specified property value argument.
*
* @param parent the object on which to set the property.
* @param propertyName the name of the property.
* @param propertyValue the value to give the property. Specify double, int and long values in a
* String
.
*
* @return the return value of the set method, or null if the method has no return value.
*
* @throws IllegalArgumentException if the parent object or the property name is null.
* @throws NoSuchMethodException if no set method exists for the property name.
* @throws InvocationTargetException if the set method throws an exception.
* @throws IllegalAccessException if the set method is inaccessible due to access control.
*/
public static Object invokePropertyMethod(Object parent, String propertyName, String propertyValue)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
if (parent == null)
{
String message = Logging.getMessage("nullValue.nullValue.ParentIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (propertyName == null)
{
String message = Logging.getMessage("nullValue.PropertyNameIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
String methodName = "set" + propertyName;
try // String arg
{
Method method = parent.getClass().getMethod(methodName, new Class[] {String.class});
return method != null ? method.invoke(parent, propertyValue) : null;
}
catch (NoSuchMethodException e)
{
// skip to next arg type
}
try // double arg
{
Double d = WWUtil.makeDouble(propertyValue);
if (d != null)
{
Method method = parent.getClass().getMethod(methodName, new Class[] {double.class});
return method != null ? method.invoke(parent, d) : null;
}
}
catch (NoSuchMethodException e)
{
// skip to next arg type
}
try // int arg
{
Integer i = WWUtil.makeInteger(propertyValue);
if (i != null)
{
Method method = parent.getClass().getMethod(methodName, new Class[] {int.class});
return method != null ? method.invoke(parent, i) : null;
}
}
catch (NoSuchMethodException e)
{
// skip to next arg type
}
try // boolean arg
{
Boolean b = WWUtil.convertStringToBoolean(propertyValue);
if (b != null)
{
Method method = parent.getClass().getMethod(methodName, new Class[] {boolean.class});
return method != null ? method.invoke(parent, b) : null;
}
}
catch (NoSuchMethodException e)
{
// skip to next arg type
}
try // long arg
{
Long l = WWUtil.makeLong(propertyValue);
if (l != null)
{
Method method = parent.getClass().getMethod(methodName, new Class[] {long.class});
return method != null ? method.invoke(parent, l) : null;
}
}
catch (NoSuchMethodException e)
{
// skip to next arg type
}
throw new NoSuchMethodException();
}
/**
* Copies only values of the specified keys
from srcList
to another destList
.
* The forceOverwrite
controls what to do if the destination list already contains values for specified
* keys
. If forceOverwrite
is set to true, the existing value wills be overwritten.
*
* @param srcList The source list. May not be null
.
* @param destList The destination list. May not be null
.
* @param forceOverwrite Allow overwrite existing values in the destination list
* @param keys Array of keys
*/
public static void copyValues(AVList srcList, AVList destList, String[] keys, boolean forceOverwrite)
{
if (WWUtil.isEmpty(srcList) || WWUtil.isEmpty(destList) || WWUtil.isEmpty(keys) || keys.length == 0)
{
return;
}
for (String key : keys)
{
if (WWUtil.isEmpty(key) || !srcList.hasKey(key))
{
continue;
}
Object o = srcList.getValue(key);
if (!destList.hasKey(key) || forceOverwrite)
{
destList.setValue(key, o);
}
}
}
/**
* Eliminates all white space in a specified string. (Applies the regular expression "\\s+".)
*
* @param inputString the string to remove white space from.
*
* @return the string with white space eliminated, or null if the input string is null.
*/
public static String removeWhiteSpace(String inputString)
{
if (WWUtil.isEmpty(inputString))
{
return inputString;
}
return inputString.replaceAll("\\s+", "");
}
/**
* Extracts an error message from the exception object
*
* @param t Exception instance
*
* @return A string that contains an error message
*/
public static String extractExceptionReason(Throwable t)
{
if (t == null)
{
return Logging.getMessage("generic.Unknown");
}
StringBuilder sb = new StringBuilder();
String message = t.getMessage();
if (!WWUtil.isEmpty(message))
sb.append(message);
String messageClass = t.getClass().getName();
Throwable cause = t.getCause();
if (null != cause && cause != t)
{
String causeMessage = cause.getMessage();
String causeClass = cause.getClass().getName();
if (!WWUtil.isEmpty(messageClass) && !WWUtil.isEmpty(causeClass) && !messageClass.equals(causeClass))
{
if (sb.length() != 0)
{
sb.append(" : ");
}
sb.append(causeClass).append(" (").append(causeMessage).append(")");
}
}
if (sb.length() == 0)
{
sb.append(messageClass);
}
return sb.toString();
}
/**
* Strips leading period from a string (Example: input -> ".ext", output -> "ext")
*
* @param s String to test, must not be null
*
* @return String without leading period
*/
public static String stripLeadingPeriod(String s)
{
if (null != s && s.startsWith("."))
return s.substring(Math.min(1, s.length()), s.length());
return s;
}
protected static boolean isKMLTimeShift(String timeString)
{
return Pattern.matches(".*[+-]+\\d\\d:\\d\\d$", timeString.trim());
}
/**
* Parse a date/time string and return its equivalent in milliseconds (using same time coordinate system as
* System.currentTimeMillis()). The following formats are recognized and conform to those defined in KML version
* 2.2: "1997", "1997-07", "1997-07-16", "1997-07-16T07:30:15Z", "1997-07-16T07:30:15+03:00" and
* "1997-07-16T07:30:15+0300".
*
* @param timeString the date/time string to parse.
*
* @return the number of milliseconds since 00:00:00 1970 indicated by the date/time string, or null if the input
* string is null or the string is not a recognizable format.
*/
public static Long parseTimeString(String timeString)
{
if (timeString == null)
return null;
// KML allows a hybrid time zone offset that does not contain the leading "GMT", e.g. 1997-05-10T09:30:00+03:00.
// If the time string has this pattern, we convert it to an RFC 822 time zone so that SimpleDateFormat can
// parse it.
if (isKMLTimeShift(timeString))
{
// Remove the colon from the GMT offset portion of the time string.
timeString = timeString.trim();
int colonPosition = timeString.length() - 3;
String newTimeString = timeString.substring(0, colonPosition);
timeString = newTimeString + timeString.substring(colonPosition + 1, timeString.length());
}
try
{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:sszzzzz");
return df.parse(timeString).getTime();
}
catch (ParseException ignored)
{
}
try
{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
return df.parse(timeString).getTime();
}
catch (ParseException ignored)
{
}
try
{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
return df.parse(timeString).getTime();
}
catch (ParseException ignored)
{
}
try
{
DateFormat df = new SimpleDateFormat("yyyy-MM");
return df.parse(timeString).getTime();
}
catch (ParseException ignored)
{
}
try
{
DateFormat df = new SimpleDateFormat("yyyy");
return df.parse(timeString).getTime();
}
catch (ParseException ignored)
{
}
return null;
}
/**
* Compares two version strings, e.g., 1.3.0, and returns 0 if they match, -1 if the first string is less than the
* second, and 1 if the first string is greater than the second. The strings can be arbitrary length but the
* components must be separated by ".". A missing component maps to 0, e.g. 1.3 will match 1.3.0.
*
* @param va the first version string
* @param vb the second version string
*
* @return -1 if the first string is less than the second, 0 if the strings match, 1 if the first string is greater
* than the second string.
*/
public static int compareVersion(String va, String vb)
{
if (va == null || vb == null)
{
throw new IllegalArgumentException(Logging.getMessage("nullValue.StringIsNull"));
}
if (va.equals(vb))
return 0;
String[] vas = va.split("\\.");
String[] vbs = vb.split("\\.");
for (int i = 0; i < Math.max(vas.length, vbs.length); i++)
{
String sa = vas.length > i ? vas[i] : "0";
String sb = vbs.length > i ? vbs[i] : "0";
if (sa.compareTo(sb) < 0)
return -1;
if (sa.compareTo(sb) > 0)
return 1;
}
return 0; // the versions match
}
/**
* Generates average normal vectors for the vertices of a triangle strip.
*
* @param vertices the triangle strip vertices.
* @param indices the indices identifying the triangle strip from the specified vertices.
* @param normals a buffer to accept the output normals. The buffer must be allocated and all its values must be
* initialized to 0. The buffer's size limit must be at least as large as that of the specified
* vertex buffer.
*
* @throws IllegalArgumentException if any of the specified buffers are null or the limit of the normal
* buffer is less than that of the vertex buffer.
*/
public static void generateTriStripNormals(FloatBuffer vertices, IntBuffer indices, FloatBuffer normals)
{
if (vertices == null || indices == null || normals == null)
{
String message = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (normals.limit() < vertices.limit())
{
String message = Logging.getMessage("generic.BufferSize", normals.limit());
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
for (int i = 0; i < indices.limit() - 2; i++)
{
int i1 = 3 * indices.get(i);
int i2 = 3 * indices.get(i + 1);
int i3 = 3 * indices.get(i + 2);
Vec4 t0 = new Vec4(vertices.get(i1), vertices.get(i1 + 1), vertices.get(i1 + 2));
Vec4 t1 = new Vec4(vertices.get(i2), vertices.get(i2 + 1), vertices.get(i2 + 2));
Vec4 t2 = new Vec4(vertices.get(i3), vertices.get(i3 + 1), vertices.get(i3 + 2));
Vec4 va = new Vec4(t1.x - t0.x, t1.y - t0.y, t1.z - t0.z);
Vec4 vb = new Vec4(t2.x - t0.x, t2.y - t0.y, t2.z - t0.z);
Vec4 facetNormal;
if (i % 2 == 0)
{
facetNormal = va.cross3(vb).normalize3();
}
else
{
facetNormal = vb.cross3(va).normalize3();
}
normals.put(i1, normals.get(i1) + (float) facetNormal.x);
normals.put(i1 + 1, normals.get(i1 + 1) + (float) facetNormal.y);
normals.put(i1 + 2, normals.get(i1 + 2) + (float) facetNormal.z);
normals.put(i2, normals.get(i2) + (float) facetNormal.x);
normals.put(i2 + 1, normals.get(i2 + 1) + (float) facetNormal.y);
normals.put(i2 + 2, normals.get(i2 + 2) + (float) facetNormal.z);
normals.put(i3, normals.get(i3) + (float) facetNormal.x);
normals.put(i3 + 1, normals.get(i3 + 1) + (float) facetNormal.y);
normals.put(i3 + 2, normals.get(i3 + 2) + (float) facetNormal.z);
}
// Normalize all the computed normals.
for (int i = 0; i < indices.limit() - 2; i++)
{
int i1 = 3 * indices.get(i);
int i2 = 3 * indices.get(i + 1);
int i3 = 3 * indices.get(i + 2);
Vec4 n1 = new Vec4(normals.get(i1), normals.get(i1 + 1), normals.get(i1 + 2)).normalize3();
Vec4 n2 = new Vec4(normals.get(i2), normals.get(i2 + 1), normals.get(i2 + 2)).normalize3();
Vec4 n3 = new Vec4(normals.get(i3), normals.get(i3 + 1), normals.get(i3 + 2)).normalize3();
normals.put(i1, (float) n1.x);
normals.put(i1 + 1, (float) n1.y);
normals.put(i1 + 2, (float) n1.z);
normals.put(i2, (float) n2.x);
normals.put(i2 + 1, (float) n2.y);
normals.put(i2 + 2, (float) n2.z);
normals.put(i3, (float) n3.x);
normals.put(i3 + 1, (float) n3.y);
normals.put(i3 + 2, (float) n3.z);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy