/*
 * Copyright 2014 JBoss Inc
 *
 * 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 org.optaplannerdelirium.sss.domain.location;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("SphereLocation")
public class SphereLocation extends Location {

    private static final double EARTH_R_IN_KM = 6371;

    public SphereLocation() {
    }

    public SphereLocation(long id, double latitude, double longitude) {
        super(id, latitude, longitude);
    }

    @Override
    public double getDistanceTo(Location other) {
        double latitudeDiff = Math.toRadians(other.getLatitude() - latitude);
        double longitudeDiff = Math.toRadians(other.getLongitude() - longitude);
        double a = Math.pow(Math.sin(latitudeDiff / 2), 2)
                + Math.pow(Math.sin(longitudeDiff / 2), 2)
                * Math.cos(Math.toRadians(latitude)) * Math.cos(Math.toRadians(other.getLatitude()));
        double c = 2 * Math.asin(Math.sqrt(a));
        return EARTH_R_IN_KM * c;
    }

}

@@ -701,16 +701,65 @@
 Alias;%0A%0A
+import java.util.HashMap;%0Aimport java.util.Map;%0A%0A
 @XStream
@@ -894,205 +894,67 @@
    p
-ublic SphereLocation() %7B%0A    %7D%0A%0A    public SphereLocation(long id, double latitude, double longitude) %7B%0A        super(id, latitude, longitude);%0A    %7D%0A%0A    @Override%0A    public double getDistanceTo(
+rivate static double getDistanceToUncached(Location first, 
 Loca
@@ -1034,24 +1034,35 @@
 ude() - 
-l
+first.getL
 atitude
+()
 );%0A     
@@ -1125,25 +1125,34 @@
 ude() - 
-l
+first.getL
 ongitude
 );%0A     
@@ -1143,16 +1143,18 @@
 ongitude
+()
 );%0A     
@@ -1308,24 +1308,35 @@
 Radians(
-l
+first.getL
 atitude
+()
 )) * Mat
@@ -1468,10 +1468,1315 @@
 %0A    %7D%0A%0A
+    private static Map%3CLong, Map%3CLong, Double%3E%3E locationCache = new HashMap%3CLong, Map%3CLong, Double%3E%3E();%0A%0A    public SphereLocation() %7B%0A    %7D%0A%0A    public SphereLocation(long id, double latitude, double longitude) %7B%0A        super(id, latitude, longitude);%0A    %7D%0A%0A    @Override%0A    public double getDistanceTo(Location other) %7B%0A        if (this == other) %7B%0A            return 0; // no need to cache this%0A        %7D%0A        // this should guarantee that no pair will be in the map twice%0A        final long firstId = Math.min(this.getId(), other.getId());%0A        final long secondId = Math.max(this.getId(), other.getId());%0A        synchronized (locationCache) %7B%0A            Map%3CLong, Double%3E cache = locationCache.get(firstId);%0A            if (cache == null) %7B // create mapping for the first key%0A                cache = new HashMap%3CLong, Double%3E();%0A                locationCache.put(firstId, cache);%0A            %7D else %7B%0A                final Double result = cache.get(secondId);%0A                if (result != null) %7B // the distance is cached already%0A                    return result;%0A                %7D%0A            %7D%0A            // cache the distance%0A            final double result = getDistanceToUncached(this, other);%0A            cache.put(secondId, result);%0A            return result;%0A        %7D%0A    %7D%0A%0A
 %7D%0A

Improve performance by caching the distances