package org.etsi.geodesic; import java.util.ArrayList; import org.etsi.adapter.TERFactory; /** * @desc * @see To validate GPS location: http://www.gps-coordinates.net */ public class Positioning implements IPositioning { public static double TWOPI = 2 * Math.PI; /** * Unique reference to this object */ private static IPositioning Instance; /** * Singleton pattern implementation */ public static IPositioning getInstance() { if (Instance == null) { Instance = new Positioning(); } return Instance; } /** * Private constructor required for Singleton pattern implementation */ private Positioning() { } @Override public boolean isLocationInsideEllipticArea(final WGS84 p_location, final ArrayList p_ellipticArea) { // TERFactory.getInstance().logDebug(">>> Positioning.isLocationInsideEllipticArea: " + p_location); // TODO: implement it // Do not forget aboout passing throw 0 meridian return false; } @Override public boolean isLocationInsidePolygonalArea(final WGS84 p_location, final ArrayList p_polygonalArea) { // TERFactory.getInstance().logDebug(">>> Positioning.isLocationInsidePolygonalArea: " + p_location + ", " + p_polygonalArea); // TODO: Check passing throw 0 meridian and Equador double angle = 0; int poleNum = p_polygonalArea.size(); for (int index = 0; index < poleNum; index++) { WGS84 delta1 = new WGS84( p_polygonalArea.get(index).getLatitude() - p_location.getLatitude(), p_polygonalArea.get(index).getLongitude() - p_location.getLongitude(), 0 ); WGS84 delta2 = new WGS84( p_polygonalArea.get((index + 1) % poleNum).getLatitude() - p_location.getLatitude(), p_polygonalArea.get((index + 1) % poleNum).getLongitude() - p_location.getLongitude(), 0 ); angle += calcAngle(delta1, delta2); } // End of 'for' statement // TERFactory.getInstance().logDebug("<<< Positioning.isLocationInsidePolygonalArea: " + (boolean)((Math.abs(angle) < Math.PI) ? false : true)); return (boolean)((Math.abs(angle) < Math.PI) ? false : true); } @Override public boolean isLocationInsidePolygonalAreas(final WGS84 p_location, final ArrayList< ArrayList > p_polygonalAreas) { // TERFactory.getInstance().logDebug(">>> Positioning.isLocationInsidePolygonalAreas: " + p_location); for (int index = 0; index < p_polygonalAreas.size(); index++) { if (isLocationInsidePolygonalArea(p_location, p_polygonalAreas.get(index))) { return true; } } // End of 'for' statement return false; // Not found } @Override public boolean isLocationInsideCircularArea(final WGS84 p_location, final WGS84 p_center, final int p_radius) { // TERFactory.getInstance().logDebug(">>> Positioning.isLocationInsideCircularArea: " + p_location + ", " + p_center + ", " + p_radius); // TODO: Check passing throw 0 meridian and Equador double theta = p_center.getLongitude() - p_location.getLongitude(); double distance = Math.sin(dd2rad(p_center.getLatitude())) * Math.sin(dd2rad(p_location.getLatitude())) + Math.cos(dd2rad(p_center.getLatitude())) * Math.cos(dd2rad(p_location.getLatitude())) * Math.cos(dd2rad(theta)); distance = rad2dd(Math.acos(distance)); distance *= 60 * 1.1515 * 1.609344 /*Kilometers*/; // TERFactory.getInstance().logDebug("Positioning.isLocationInsideCircularArea: distance=" + distance); // TERFactory.getInstance().logDebug("<<< Positioning.isLocationInsideCircularArea: " + (boolean)(distance <= (p_radius / 1000.0))); return (boolean)(distance <= (p_radius / 1000.0)); } @Override public boolean isValidPolygonArea(final ArrayList p_polygonalArea) { // TERFactory.getInstance().logDebug(">>> Positioning.isValidPolygonArea"); // Check if polygon coordinates are valid for (int i = 0; i < p_polygonalArea.size(); i++) { if (!p_polygonalArea.get(i).isValidPosition()) { return false; } } return true; } @Override public boolean isLocationInsideIdentifiedRegion(final int p_regionDictionary, final int p_regionId, final long p_localRegion, final WGS84 p_location) { // TERFactory.getInstance().logDebug(">>> Positioning.isLocationInsideIdentifiedRegion: " + p_regionDictionary + ", " + p_regionId + ", " + p_localRegion + ", " + p_location); return CountriesAreas.getInstance().isLocationInsideIdentifiedRegion(p_regionDictionary, p_regionId, p_localRegion, p_location); } @Override public boolean isPolygonalRegionInside(final ArrayList p_parentArea, final ArrayList p_regionArea) { // TERFactory.getInstance().logDebug(">>> Positioning.isPolygonalRegionInside: " + p_parentArea + ", " + p_regionArea); for (int i = 0; i < p_regionArea.size(); i++) { if (!isLocationInsidePolygonalArea(p_regionArea.get(i), p_parentArea)) { return false; } } // End of 'for' statement return true; } private double calcAngle(final WGS84 p_origin, final WGS84 p_end) { // TERFactory.getInstance().logDebug(">>> calcAngle: " + p_origin.getLatitude() + " - " + p_origin.getLongitude() + " - " + p_end.getLatitude() + " - " + p_end.getLongitude()); double theta1 = Math.atan2(p_origin.getLatitude(), p_origin.getLongitude()); // TERFactory.getInstance().logDebug("Angle2D: theta1=" + theta1); double theta2 = Math.atan2(p_end.getLatitude(), p_end.getLongitude()); // TERFactory.getInstance().logDebug("Angle2D: theta2=" + theta2); double dtheta = theta2 - theta1; // TERFactory.getInstance().logDebug("calcAngle: dtheta" + dtheta); while (dtheta > Math.PI) { dtheta -= TWOPI; } // End of 'while' statement while (dtheta < -Math.PI) { dtheta += TWOPI; } // End of 'while' statement // TERFactory.getInstance().logDebug("<<< calcAngle: " + dtheta); return dtheta; } /** * @desc Convert a decimal degrees value into a decimal radian * @param p_decimalDegrees The value to convert * @return The converted value in radians */ private double dd2rad(final double p_decimalDegrees) { return p_decimalDegrees * Math.PI / 180; } /** * @desc Convert a decimal radians value into a decimal degrees * @param p_decimalRadians The value to convert * @return The converted value in degrees */ private double rad2dd(final double p_decimalRadians) { return p_decimalRadians * 180.0 / Math.PI; } } // End of class Positioning