// Path: ensemble-clustering/src/main/java/com/oculusinfo/math/linearalgebra/ListUtilities.java
// public class ListUtilities {
//     private static boolean equal (double a, double b, double epsilon) {
//         return Math.abs(a-b) < epsilon;
//     }
// 
//     /**
//      * Join together 2 ordered lists of doubles into a single, ordered list
//      * 
//      * @param lists
//      *            The lists to be joined
//      * 
//      * @param A
//      *            The first list
//      * @param B
//      *            The second list
//      * @param epsilon
//      *            The difference within which two doubles are considered equal
//      * @return The conjoined list
//      */
//     public static List<Double> joinLists (List<Double> A, List<Double> B,
//                                           double epsilon) {
//         List<Double> C = new ArrayList<Double>();
//         int nA = 0;
//         int NA = A.size();
//         double a = A.get(nA);
// 
//         int nB = 0;
//         int NB = B.size();
//         double b = B.get(nB);
// 
//         while (nA < NA || nB < NB) {
//             if (equal(a, b, epsilon)) {
//                 // A bit silly, since they are already shown equal, but just in
//                 // case of large epsilon, it'd be nice to be sure
//                 C.add((a + b) / 2);
//                 while (nA < NA && equal(a, A.get(nA), epsilon)) ++nA;
//                 a = (nA < NA ? A.get(nA) : Double.MAX_VALUE);
//                 while (nB < NB && equal(b, B.get(nB), epsilon)) ++nB;
//                 b = (nB < NB ? B.get(nB) : Double.MAX_VALUE);
//             } else if (a < b) {
//                 C.add(a);
//                 ++nA;
//                 a = (nA < NA ? A.get(nA) : Double.MAX_VALUE);
//             } else {
//                 C.add(b);
//                 ++nB;
//                 b = (nB < NB ? B.get(nB) : Double.MAX_VALUE);
//             }
//         }
// 
//         return C;
//     }
// 
//     /**
//      * Join together N orderd lists of doubles into a single, ordered list
//      * 
//      * @param lists
//      *            The lists to be joined
//      * @param epsilon
//      *            The difference within which two doubles are considered equal
//      */
//     public static List<Double> joinNLists (List<List<Double>> lists,
//                                            double epsilon) {
//         if (null == lists)
//             return null;
//         if (0 == lists.size())
//             return null;
//         if (1 == lists.size())
//             return lists.get(0);
// 
//         while (lists.size() > 1) {
//             // This looks like it's looping over every member, but each time,
//             // it's really replacing the current and next list with a single,
//             // new, joined list. So, in actuallity, it's looping over pairs,
//             // because replacement happens durring the loop.
//             for (int i = 0; i < lists.size() - 1; ++i) {
//                 List<Double> A = lists.remove(i);
//                 List<Double> B = lists.remove(i);
//                 lists.add(i, joinLists(A, B, epsilon));
//             }
//         }
//         return lists.get(0);
//     }
// }


import com.oculusinfo.math.linearalgebra.ListUtilities;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

        Position ourStart = _points.get(0);
        Position ourEnd = _points.get(_points.size()-1);

        List<Position> theirPoints = them.getPoints();
        Position theirStart = theirPoints.get(0);
        Position theirEnd = theirPoints.get(theirPoints.size()-1);

        double dss = getSegmentDistance(ourStart, theirStart);
        double dse = getSegmentDistance(ourStart, theirEnd);
        double des = getSegmentDistance(ourEnd, theirStart);
        double dee = getSegmentDistance(ourEnd, theirEnd);

        double requiredConfidence = 0.5;
        return (dse/dee < requiredConfidence && des / dss < requiredConfidence);
    }

    public double getDistance (Track them) {
        if (_parameters.ignoreDirection()) {
            if (closerToReverse(them))
                return getDistanceWithDirection(them.reverse());
            else
                return getDistanceWithDirection(them);
        } else {
            return getDistanceWithDirection(them);
        }
    }

    private double getDistanceWithDirection (Track them) {
        List<Double> ourParameterization = getParameterization();
        List<Double> theirParameterization = them.getParameterization();

// Path: ensemble-clustering/src/main/java/com/oculusinfo/math/linearalgebra/ListUtilities.java
// public class ListUtilities {
//     private static boolean equal (double a, double b, double epsilon) {
//         return Math.abs(a-b) < epsilon;
//     }
// 
//     /**
//      * Join together 2 ordered lists of doubles into a single, ordered list
//      * 
//      * @param lists
//      *            The lists to be joined
//      * 
//      * @param A
//      *            The first list
//      * @param B
//      *            The second list
//      * @param epsilon
//      *            The difference within which two doubles are considered equal
//      * @return The conjoined list
//      */
//     public static List<Double> joinLists (List<Double> A, List<Double> B,
//                                           double epsilon) {
//         List<Double> C = new ArrayList<Double>();
//         int nA = 0;
//         int NA = A.size();
//         double a = A.get(nA);
// 
//         int nB = 0;
//         int NB = B.size();
//         double b = B.get(nB);
// 
//         while (nA < NA || nB < NB) {
//             if (equal(a, b, epsilon)) {
//                 // A bit silly, since they are already shown equal, but just in
//                 // case of large epsilon, it'd be nice to be sure
//                 C.add((a + b) / 2);
//                 while (nA < NA && equal(a, A.get(nA), epsilon)) ++nA;
//                 a = (nA < NA ? A.get(nA) : Double.MAX_VALUE);
//                 while (nB < NB && equal(b, B.get(nB), epsilon)) ++nB;
//                 b = (nB < NB ? B.get(nB) : Double.MAX_VALUE);
//             } else if (a < b) {
//                 C.add(a);
//                 ++nA;
//                 a = (nA < NA ? A.get(nA) : Double.MAX_VALUE);
//             } else {
//                 C.add(b);
//                 ++nB;
//                 b = (nB < NB ? B.get(nB) : Double.MAX_VALUE);
//             }
//         }
// 
//         return C;
//     }
// 
//     /**
//      * Join together N orderd lists of doubles into a single, ordered list
//      * 
//      * @param lists
//      *            The lists to be joined
//      * @param epsilon
//      *            The difference within which two doubles are considered equal
//      */
//     public static List<Double> joinNLists (List<List<Double>> lists,
//                                            double epsilon) {
//         if (null == lists)
//             return null;
//         if (0 == lists.size())
//             return null;
//         if (1 == lists.size())
//             return lists.get(0);
// 
//         while (lists.size() > 1) {
//             // This looks like it's looping over every member, but each time,
//             // it's really replacing the current and next list with a single,
//             // new, joined list. So, in actuallity, it's looping over pairs,
//             // because replacement happens durring the loop.
//             for (int i = 0; i < lists.size() - 1; ++i) {
//                 List<Double> A = lists.remove(i);
//                 List<Double> B = lists.remove(i);
//                 lists.add(i, joinLists(A, B, epsilon));
//             }
//         }
//         return lists.get(0);
//     }
// }


// Path: ensemble-clustering/src/main/java/com/oculusinfo/geometry/geodesic/Track.java
import com.oculusinfo.math.linearalgebra.ListUtilities;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

        Position ourStart = _points.get(0);
        Position ourEnd = _points.get(_points.size()-1);

        List<Position> theirPoints = them.getPoints();
        Position theirStart = theirPoints.get(0);
        Position theirEnd = theirPoints.get(theirPoints.size()-1);

        double dss = getSegmentDistance(ourStart, theirStart);
        double dse = getSegmentDistance(ourStart, theirEnd);
        double des = getSegmentDistance(ourEnd, theirStart);
        double dee = getSegmentDistance(ourEnd, theirEnd);

        double requiredConfidence = 0.5;
        return (dse/dee < requiredConfidence && des / dss < requiredConfidence);
    }

    public double getDistance (Track them) {
        if (_parameters.ignoreDirection()) {
            if (closerToReverse(them))
                return getDistanceWithDirection(them.reverse());
            else
                return getDistanceWithDirection(them);
        } else {
            return getDistanceWithDirection(them);
        }
    }

    private double getDistanceWithDirection (Track them) {
        List<Double> ourParameterization = getParameterization();
        List<Double> theirParameterization = them.getParameterization();

        List<Double> joinedParameterization = ListUtilities.joinLists(ourParameterization,
