// Path: ensemble-clustering/src/main/java/com/oculusinfo/ml/feature/spatial/GeoSpatialFeature.java
// public class GeoSpatialFeature extends Feature {
// 	private static final long serialVersionUID = 7917681828048658982L;
// 	private double latitude;
// 	private double longitude;
// 	
// 	@Override
// 	public String toString() {
// 		return (this.getName() + ":[" + latitude + ";" + longitude + "]");
// 	}
// 	
// 	public GeoSpatialFeature() {
// 		super();
// 	}
// 	
// 	public GeoSpatialFeature(String name) {
// 		super(name);
// 	}
// 
// 	public void setValue(double latitude, double longitude) {
// 		this.latitude = latitude;
// 		this.longitude = longitude;
// 	}
// 	
// 	public double getLatitude() {
// 		return latitude;
// 	}
// 	
// 	public void setLatitude(double latitude) {
// 		this.latitude = latitude;
// 	}
// 	
// 	public double getLongitude() {
// 		return longitude;
// 	}
// 	
// 	public void setLongitude(double longitude) {
// 		this.longitude = longitude;
// 	}
// }
// 
// Path: ensemble-clustering/src/main/java/com/oculusinfo/ml/feature/spatial/distance/SphericalCosineDistance.java
// public class SphericalCosineDistance extends DistanceFunction<GeoSpatialFeature> {
// 	private static final long serialVersionUID = -4202417997475962513L;
// 	private final static double EARTH_RADIUS = 6371.00; // Radius in Kilometers default
// 
// 	public SphericalCosineDistance(double weight) {
// 		super(weight);
// 	}
// 	
// 	@Override
// 	public double distance(GeoSpatialFeature x, GeoSpatialFeature y) {
// 		double lat1 = Math.toRadians(x.getLatitude());
// 		double lat2 = Math.toRadians(y.getLatitude());
// 		double lon1 = Math.toRadians(x.getLongitude());
// 		double lon2 = Math.toRadians(y.getLongitude());
// 		
// 		double d = Math.acos(Math.sin(lat1)*Math.sin(lat2) + 
//                 Math.cos(lat1)*Math.cos(lat2) *
//                 Math.cos(lon2-lon1));
// 		double normDist = d / Math.PI;
// 		return normDist;
// 	}
// 
// 	public double distanceInKM(GeoSpatialFeature x, GeoSpatialFeature y) {
//         return distance(x, y) * EARTH_RADIUS;
// 	}
// }


import com.oculusinfo.ml.feature.spatial.distance.SphericalCosineDistance;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import org.junit.Test;
import com.oculusinfo.ml.feature.spatial.GeoSpatialFeature;
		// Waterloo -80.5204096??W, 43.4642578??N
		GeoSpatialFeature t2 = new GeoSpatialFeature();
		t2.setValue(43.4642578, -80.5204096);
		
		SphericalCosineDistance d = new SphericalCosineDistance(1);
		
		double distance = d.distance(t1, t2);
		System.out.println(distance);
//		assertTrue(isEqual(distance, 0));
//		distance = d.aveMinDistance(Collections.singletonList(t1), Collections.singletonList(t2));
//		assertTrue(isEqual(distance, 0));
	}
	
	@Test
	public void testSymmetric3() {
		GeoSpatialFeature t1 = new GeoSpatialFeature();
		// Toronto -79.3831843??W, 43.6532260??N
		t1.setValue(43.6532260, -79.3831843);
		
		// Waterloo -80.5204096??W, 43.4642578??N
		GeoSpatialFeature t2 = new GeoSpatialFeature();
		t2.setValue(43.4642578, -80.5204096);
		
		SphericalCosineDistance d = new SphericalCosineDistance(1);
		
		double d1 = d.distance(t1, t2);
		double d2 = d.distance(t2, t1);
		
		assertTrue(isEqual(d1, d2));
		d1 = d.aveMinDistance(Collections.singletonList(t1), Collections.singletonList(t2));
// Path: ensemble-clustering/src/main/java/com/oculusinfo/ml/feature/spatial/GeoSpatialFeature.java
// public class GeoSpatialFeature extends Feature {
// 	private static final long serialVersionUID = 7917681828048658982L;
// 	private double latitude;
// 	private double longitude;
// 	
// 	@Override
// 	public String toString() {
// 		return (this.getName() + ":[" + latitude + ";" + longitude + "]");
// 	}
// 	
// 	public GeoSpatialFeature() {
// 		super();
// 	}
// 	
// 	public GeoSpatialFeature(String name) {
// 		super(name);
// 	}
// 
// 	public void setValue(double latitude, double longitude) {
// 		this.latitude = latitude;
// 		this.longitude = longitude;
// 	}
// 	
// 	public double getLatitude() {
// 		return latitude;
// 	}
// 	
// 	public void setLatitude(double latitude) {
// 		this.latitude = latitude;
// 	}
// 	
// 	public double getLongitude() {
// 		return longitude;
// 	}
// 	
// 	public void setLongitude(double longitude) {
// 		this.longitude = longitude;
// 	}
// }
// 
// Path: ensemble-clustering/src/main/java/com/oculusinfo/ml/feature/spatial/distance/SphericalCosineDistance.java
// public class SphericalCosineDistance extends DistanceFunction<GeoSpatialFeature> {
// 	private static final long serialVersionUID = -4202417997475962513L;
// 	private final static double EARTH_RADIUS = 6371.00; // Radius in Kilometers default
// 
// 	public SphericalCosineDistance(double weight) {
// 		super(weight);
// 	}
// 	
// 	@Override
// 	public double distance(GeoSpatialFeature x, GeoSpatialFeature y) {
// 		double lat1 = Math.toRadians(x.getLatitude());
// 		double lat2 = Math.toRadians(y.getLatitude());
// 		double lon1 = Math.toRadians(x.getLongitude());
// 		double lon2 = Math.toRadians(y.getLongitude());
// 		
// 		double d = Math.acos(Math.sin(lat1)*Math.sin(lat2) + 
//                 Math.cos(lat1)*Math.cos(lat2) *
//                 Math.cos(lon2-lon1));
// 		double normDist = d / Math.PI;
// 		return normDist;
// 	}
// 
// 	public double distanceInKM(GeoSpatialFeature x, GeoSpatialFeature y) {
//         return distance(x, y) * EARTH_RADIUS;
// 	}
// }


// Path: ensemble-clustering/src/test/java/com/oculusinfo/ml/distance/TestSphericalCosineDistance.java
import com.oculusinfo.ml.feature.spatial.distance.SphericalCosineDistance;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import org.junit.Test;
import com.oculusinfo.ml.feature.spatial.GeoSpatialFeature;

		// Waterloo -80.5204096??W, 43.4642578??N
		GeoSpatialFeature t2 = new GeoSpatialFeature();
		t2.setValue(43.4642578, -80.5204096);
		
		SphericalCosineDistance d = new SphericalCosineDistance(1);
		
		double distance = d.distance(t1, t2);
		System.out.println(distance);
//		assertTrue(isEqual(distance, 0));
//		distance = d.aveMinDistance(Collections.singletonList(t1), Collections.singletonList(t2));
//		assertTrue(isEqual(distance, 0));
	}
	
	@Test
	public void testSymmetric3() {
		GeoSpatialFeature t1 = new GeoSpatialFeature();
		// Toronto -79.3831843??W, 43.6532260??N
		t1.setValue(43.6532260, -79.3831843);
		
		// Waterloo -80.5204096??W, 43.4642578??N
		GeoSpatialFeature t2 = new GeoSpatialFeature();
		t2.setValue(43.4642578, -80.5204096);
		
		SphericalCosineDistance d = new SphericalCosineDistance(1);
		
		double d1 = d.distance(t1, t2);
		double d2 = d.distance(t2, t1);
		
		assertTrue(isEqual(d1, d2));
		d1 = d.aveMinDistance(Collections.singletonList(t1), Collections.singletonList(t2));
		d2 = d.aveMinDistance(Collections.singletonList(t2), Collections.singletonList(t1));