
org.numenta.nupic.encoders.GeospatialCoordinateEncoder Maven / Gradle / Ivy
/* ---------------------------------------------------------------------
* Numenta Platform for Intelligent Computing (NuPIC)
* Copyright (C) 2014, Numenta, Inc. Unless you have an agreement
* with Numenta, Inc., for a separate license for this software code, the
* following terms and conditions apply:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses.
*
* http://numenta.org/licenses/
* ---------------------------------------------------------------------
*/
package org.numenta.nupic.encoders;
import org.numenta.nupic.util.Tuple;
public class GeospatialCoordinateEncoder extends CoordinateEncoder {
private int scale;
private int timestep;
public GeospatialCoordinateEncoder() {
Tuple desc = new Tuple("longitude", 0);
Tuple desc2 = new Tuple("lattitude", 1);
Tuple desc3 = new Tuple("speed", 2);
description.add(desc);
description.add(desc2);
description.add(desc3);
}
/**
* Returns a builder for building ScalarEncoders.
* This builder may be reused to produce multiple builders
*
* @return a {@code CoordinateEncoder.Builder}
*/
public static GeospatialCoordinateEncoder.Builder geobuilder() {
return new GeospatialCoordinateEncoder.Builder();
}
/**
* {@inheritDoc}
*/
@Override
public void encodeIntoArray(Tuple inputData, int[] output) {
double longitude = (double)inputData.get(0);
double lattitude = (double)inputData.get(1);
double speed = (double)inputData.get(2);
int[] coordinate = coordinateForPosition(longitude, lattitude);
double radius = radiusForSpeed(speed);
super.encodeIntoArray(new Tuple(coordinate, radius), output);
}
public int[] coordinateForPosition(double longitude, double lattitude) {
double[] coordinate = toMercator(longitude, lattitude);
coordinate[0] /= scale;
coordinate[1] /= scale;
return new int[] { (int)coordinate[0], (int)coordinate[1] };
}
/**
* Returns coordinates converted to Mercator Spherical projection
*
* @param lon the longitude
* @param lat the lattitude
* @return
*/
protected double[] toMercator(double lon, double lat) {
double x = lon * 20037508.34d / 180;
double y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
y = y * 20037508.34d / 180;
return new double[] { x, y};
}
/**
* Returns coordinates converted to Long/Lat from Mercator Spherical projection
*
* @param lon the longitude
* @param lat the lattitude
* @return
*/
protected double[] inverseMercator(double x, double y) {
double lon = (x / 20037508.34d) * 180;
double lat = (y / 20037508.34d) * 180;
lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
return new double[] { lon, lat };
}
/**
* Tries to get the encodings of consecutive readings to be
* adjacent with some overlap.
*
* @param speed Speed (in meters per second)
* @return Radius for given speed
*/
public double radiusForSpeed(double speed) {
double overlap = 1.5;
double coordinatesPerTimestep = speed * timestep / scale;
int radius = (int)Math.round(coordinatesPerTimestep / 2D * overlap);
int minRadius = (int)Math.ceil((Math.sqrt(w) - 1) / 2);
return Math.max(radius, minRadius);
}
/**
* Returns a {@link EncoderBuilder} for constructing {@link GeospatialCoordinateEncoder}s
*
* The base class architecture is put together in such a way where boilerplate
* initialization can be kept to a minimum for implementing subclasses, while avoiding
* the mistake-proneness of extremely long argument lists.
*
* @see ScalarEncoder.Builder#setStuff(int)
*/
public static class Builder extends Encoder.Builder {
private int scale;
private int timestep;
private Builder() {}
@Override
public GeospatialCoordinateEncoder build() {
//Must be instantiated so that super class can initialize
//boilerplate variables.
encoder = new GeospatialCoordinateEncoder();
//Call super class here
super.build();
////////////////////////////////////////////////////////
// Implementing classes would do setting of specific //
// vars here together with any sanity checking //
////////////////////////////////////////////////////////
if(scale == 0 || timestep == 0) {
throw new IllegalStateException("Scale or Timestep not set");
}
((GeospatialCoordinateEncoder)encoder).scale = scale;
((GeospatialCoordinateEncoder)encoder).timestep = timestep;
if(w <= 0 || w % 2 == 0) {
throw new IllegalArgumentException("w must be odd, and must be a positive integer");
}
if(n <= 6 * w) {
throw new IllegalArgumentException(
"n must be an int strictly greater than 6*w. For " +
"good results we recommend n be strictly greater than 11*w");
}
if(name == null || name.equals("None")) {
name = new StringBuilder("[").append(n).append(":").append(w).append("]").toString();
}
return (GeospatialCoordinateEncoder)encoder;
}
/**
* Scale of the map, as measured by
* distance between two coordinates
* (in meters per dimensional unit)
* @param scale
* @return
*/
public Builder scale(int scale) {
this.scale = scale;
return this;
}
/**
* Time between readings
* @param timestep
* @return
*/
public Builder timestep(int timestep) {
this.timestep = timestep;
return this;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy