net.sf.eBusx.geo.GeoObject Maven / Gradle / Ivy
The newest version!
//
// Copyright 2021 Charles W. Rapp
//
// 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.
//
package net.sf.eBusx.geo;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
import net.sf.eBus.messages.EField;
/**
* Base class for all GeoJSON elements. Contains GeoJSON element
* type (required) and bounding box (optional).
*
* @author Charles W. Rapp
*/
public abstract class GeoObject
extends EField
{
//---------------------------------------------------------------
// Member enums.
//
/**
* Enumerates GeoJSON geo-spatial data types.
*/
public enum GeoType
{
/**
* Single GeoJSON {@link Position position}.
*/
POINT ("Point", GeoPoint.class),
/**
* Multiple GeoJSON {@link Position positions}.
*/
MULTIPOINT ("MultiPoint", GeoMultiPoint.class),
/**
* Contains two or more GeoJSON positions.
*/
LINE_STRING ("LineString", GeoLineString.class),
/**
* Multiple GeoJSON {@link LineString line strings}.
*/
MULTI_LINE_STRING ("MultiLineString",
GeoMultiLineString.class),
/**
* GeoJSON polygon contain one or more linear rings.
*/
POLYGON ("Polygon", GeoPolygon.class);
//-----------------------------------------------------------
// Member data.
//
//-------------------------------------------------------
// Statics.
//
/**
* Maps the JSON value to the enum instance.
*/
private static final Map sTypes;
// Class static initialization.
static
{
final GeoType[] types = GeoType.values();
final int numTypes = types.length;
int i;
sTypes = new HashMap<>(numTypes);
for (i = 0; i < numTypes; ++i)
{
sTypes.put(types[i].mJsonName, types[i]);
}
} // end of class static initialization.
//-------------------------------------------------------
// Locals.
//
/**
* GeoJSON name.
*/
private final String mJsonName;
/**
* GeoJSON sub-class.
*/
private final Class extends GeoObject> mClass;
//-----------------------------------------------------------
// Member methods.
//
//-------------------------------------------------------
// Constructors.
//
private GeoType(final String name,
final Class extends GeoObject> clazz)
{
mJsonName = name;
mClass = clazz;
} // end of GeoType(String, Class)
//
// end of Constructors.
//-------------------------------------------------------
//-------------------------------------------------------
// Get Methods.
//
/**
* Returns GeoJSON type name.
* @return GeoJSON name.
*/
public String jsonName()
{
return (mJsonName);
} // end of jsonName()
/**
* Returns GeoJSON class.
* @return GeoJSON class.
*/
public Class extends GeoObject> jsonClass()
{
return (mClass);
} // end of jsonClass()
public static GeoType findType(final String s)
{
return (sTypes.get(s));
} // end of findType(String)
//
// end of Get Methods.
//-------------------------------------------------------
} // end of enum GeoType
//---------------------------------------------------------------
// Member data.
//
//-----------------------------------------------------------
// Constants.
//
/**
* Minimum allowed latitude is -90.
*/
public static final BigDecimal MIN_LATITUDE =
BigDecimal.valueOf(-90l);
/**
* Maximum allowed latitude is +90.
*/
public static final BigDecimal MAX_LATITUDE =
BigDecimal.valueOf(90l);
/**
* Minimum allowed longitude is -180.
*/
public static final BigDecimal MIN_LONGITUDE =
BigDecimal.valueOf(-180l);
/**
* Maximum allowed longitude is +180.
*/
public static final BigDecimal MAX_LONGITUDE =
BigDecimal.valueOf(180l);
/**
* Serialization version identifier.
*/
private static final long serialVersionUID = 0x000100L;
//-----------------------------------------------------------
// Locals.
//
/**
* Data represents this geometry type.
*/
public final GeoType type;
/**
* Optional bounding box associated with this GeoJSON type.
*/
@Nullable
public final BoundingBox boundingBox;
//---------------------------------------------------------------
// Member methods.
//
//-----------------------------------------------------------
// Constructors.
//
/**
* Creates a new OpenStreatMap element based on the given
* builder settings.
* @param builder contains common element settings.
*/
protected GeoObject(final GeoBuilder> builder)
{
super (builder);
this.type = builder.mType;
this.boundingBox = builder.mBoundingBox;
} // end of GeoObject(GeoBuilder)
//
// end of Constructors.
//-----------------------------------------------------------
//-----------------------------------------------------------
// Object Method Overrides.
//
/**
* Returns text specifying GeoJSON type.
* @return human-readable text containing GeoJSON type name.
*/
@Override
public String toString()
{
final StringBuilder retval = new StringBuilder();
retval.append("type=").append(type.jsonName());
if (boundingBox != null)
{
retval.append(", bbox=").append(boundingBox);
}
return (retval.toString());
} // end of toString()
//
// end of Object Method Overrides.
//-----------------------------------------------------------
/**
* Certifies that {@code latitude} is not {@code null} and
* is ≥ {@link #MIN_LATITUDE} and
* ≤ {@link #MAX_LATITUDE}. Throws the appropriate
* exception if not the case. Otherwise returns the validated
* latitude.
* @param latitude validate this latitude.
* @return validated {@code latitude}.
* @throws NullPointerException
* if {@code latitude} is {@code null}.
* @throws IllegalArgumentException
* if {@code latitude} < {@link #MIN_LATITUDE} or
* > {@link #MAX_LATITUDE}.
*/
public static BigDecimal validateLatitude(final BigDecimal latitude)
{
Objects.requireNonNull(latitude, "latitude is null");
if (latitude.compareTo(MIN_LATITUDE) < 0)
{
throw (
new IllegalArgumentException(
String.format(
"%s < min latitude %s",
latitude.toPlainString(),
MIN_LATITUDE.toPlainString())));
}
if (latitude.compareTo(MAX_LATITUDE) > 0)
{
throw (
new IllegalArgumentException(
String.format(
"%s > max latitude %s",
latitude.toPlainString(),
MAX_LATITUDE.toPlainString())));
}
return (latitude);
} // end of validateLatitude(BigDecimal)
/**
* Certifies that {@code longitude} is not {@code null} and
* is ≥ {@link #MIN_LONGITUDE} and
* ≤ {@link #MAX_LONGITUDE}. Throws the appropriate
* exception if not the case. Otherwise returns the validated
* longitude.
* @param longitude validate this longitude.
* @return validated {@code longitude}.
* @throws NullPointerException
* if {@code longitude} is {@code null}.
* @throws IllegalArgumentException
* if {@code longitude} < {@link #MIN_LONGITUDE} or
* > {@link #MAX_LONGITUDE}.
*/
public static BigDecimal validateLongitude(final BigDecimal longitude)
{
Objects.requireNonNull(longitude, "longitude is null");
if (longitude.compareTo(MIN_LONGITUDE) < 0)
{
throw (
new IllegalArgumentException(
String.format(
"%s < min longitude %s",
longitude.toPlainString(),
MIN_LONGITUDE.toPlainString())));
}
if (longitude.compareTo(MAX_LONGITUDE) > 0)
{
throw (
new IllegalArgumentException(
String.format(
"%s > max longitude %s",
longitude.toPlainString(),
MAX_LONGITUDE.toPlainString())));
}
return (longitude);
} // end of validateLongitude(BigDecimal)
//---------------------------------------------------------------
// Inner classes.
//
/**
* Base class for all GeoJSON object builders. Used to set
* the GeoJSON object type.
*
* @param target GeoJSON object type.
*/
public abstract static class GeoBuilder
extends EField.Builder
{
//-----------------------------------------------------------
// Member data.
//
//-------------------------------------------------------
// Locals.
//
/**
* Required GeoJSON object type.
*/
private GeoType mType;
/**
* Optional GeoJSON bounding box.
*/
private BoundingBox mBoundingBox;
//-----------------------------------------------------------
// Member methods.
//
//-------------------------------------------------------
// Constructors.
//
/**
* Constructor used to set the GeoJSON class and type.
* @param clazz target GeoJSON object class.
* @param type target GeoJSON object type.
*/
protected GeoBuilder(final Class clazz,
final GeoType type)
{
super (clazz);
mType = type;
} // end of className(Class, GeoType)
//
// end of Constructors.
//-------------------------------------------------------
//-------------------------------------------------------
// Set Methods.
//
/**
* Does nothing since GeoJSON type is set in the
* constructor. This method is required for eBus
* message de-serialization.
* @param type GeoJSON data type.
* @return {@code this Builder} instance.
*/
// Argument required by eBus.
@SuppressWarnings({"java:S1172"})
public final Builder type(final GeoType type)
{
return (this);
} // end of type(GeoType)
/**
* Sets optional bounding box.
* @param bbox bounding box. May be {@code null}.
* @return {@code this Builder} instance.
*/
public final Builder boundingBox(final BoundingBox bbox)
{
mBoundingBox = bbox;
return (this);
} // end of boundingBox(BoundingBox)
//
// end of Set Methods.
//-------------------------------------------------------
} // end of class GeoBuilder
} // end of class GeoObject