Computes the mean coordinate of the vector. - Java java.lang

Java examples for java.lang:Math Matrix

Description

Computes the mean coordinate of the vector.

Demo Code

/*// ww w.java  2s .c o  m
 * Copyright (C) 2011 apurv
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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/>.
 */
//package com.java2s;

import java.util.Arrays;
import java.util.Vector;

public class Main {
    /**
     * Temporary variable for storing the immediate result of calculations.
     */
    private static Double angleZero = Double.NaN;
    /**
     * Temporary variable for storing the immediate result of calculations.
     */
    private static Double angleMax = Double.NaN;
    /**
     * The permissible error in equality comparisons.
     */
    private static double ERROR = 0.0000000000001;
    /**
     * All initializations are done to this value.
     * Also used as a minimum value for distances.
     */
    private static double UNDEFINED = -1.0;

    /**
     * Computes the mean coordinate of the vector posVector.
     * @param posVector
     * @return 
     */
    private static double computeMeanPosition(Vector<Double> posVector,
            Vector<Double> wVector) {
        double meanPos = 0.0;

        //Create 4 buckets, 1 for each quadrant of the circle.

        Vector bucket[] = new Vector[5];

        bucket[0] = null; //This is a dummy bucket,just to match the index with the exact quad. No.
        bucket[1] = new Vector<Double>(); //    0  <= x  <  90
        bucket[2] = new Vector<Double>(); //   90  <= x  < 180
        bucket[3] = new Vector<Double>(); // -180  <= x  < -90
        bucket[4] = new Vector<Double>(); //  -90  <= x  <   0

        //Iterate over the posVector and classify each of the positions in respective buckets.

        for (Double position : posVector) {

            //Change 180.0 to -180.0 so that there is no ambiguity.
            if (position == 180) {
                posVector.remove(position);
                posVector.add(-180.0);
            }

            int qNo = getQuadNumber(position);
            bucket[qNo].add(position);

        }

        //Create arrays out of the 4 buckets.

        Double[] quad1 = new Double[bucket[1].size()];
        Double[] quad2 = new Double[bucket[2].size()];
        Double[] quad3 = new Double[bucket[3].size()];
        Double[] quad4 = new Double[bucket[4].size()];

        bucket[1].toArray(quad1);
        bucket[2].toArray(quad2);
        bucket[3].toArray(quad3);
        bucket[4].toArray(quad4);

        // Sort the arrays.
        Arrays.sort(quad1);
        Arrays.sort(quad2);
        Arrays.sort(quad3);
        Arrays.sort(quad4);

        //Find the two points that are maximally separated.
        Double maxDistance = -1.0;
        Double angularDistance = -1.0;

        //The angle of two points that are maximally separated across all comparison.
        Double globalAngleZero = 0.0;
        Double globalAngleMax = 0.0;

        angularDistance = findMaxDistance12(quad1, quad2);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistance14(quad1, quad4);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistance23(quad2, quad3);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistance34(quad3, quad4);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistance13(quad1, quad3);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistance24(quad2, quad4);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistanceAA(quad1);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistanceAA(quad2);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistanceAA(quad3);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        angularDistance = findMaxDistanceAA(quad4);

        if (angularDistance > maxDistance) {
            maxDistance = angularDistance;
            globalAngleMax = angleMax;
            globalAngleZero = angleZero;

        }

        //TODO: Put additional check for maximum distance here. Exit if inconsistent value found.

        //Transform the coordinates such that globalAngleMax is transformed to 0 with positive direction
        //in the direction of least distance of globalAngleMax.        

        Vector<Double> tPosVector = null;

        if (maxDistance == 180.0) {
            tPosVector = transformPosVector(posVector, globalAngleZero,
                    globalAngleMax);

        } else {
            tPosVector = transformPosVector(posVector, globalAngleZero,
                    globalAngleMax, maxDistance);

        }

        double transMeanPos = 0.0;
        //Compute the mean in the transformed frame of reference.
        if (wVector == null) {
            transMeanPos = computeMean(tPosVector);

        } else {
            transMeanPos = computeWeightedMean(tPosVector, wVector);

        }

        //Transform back
        meanPos = unTransform(transMeanPos, globalAngleZero,
                globalAngleMax, maxDistance);

        //TODO: Remove; This is commented because its very handy in debugging.
        //out.println(Arrays.deepToString(posVector.toArray()));
        //out.println(Arrays.deepToString(tPosVector.toArray()));
        //out.println("mean position is "+meanPos);
        return meanPos;
    }

    /**
     * Finds the angle obtained by moving a distance of delta_x from x in a clockwise direction
     * if delta_x is positive and anticlockwise direction is delta_x is negative.
     * @param x
     * @param delta_x
     * @return the transformed angle obtained after clockwise addition.
     */
    private static Double add(Double x, Double delta_x) {
        Double y = null;
        if (delta_x > 0) {
            y = addClockwise(x, delta_x);

        } else if (delta_x < 0) {
            y = addAntiClockwise(x, Math.abs(delta_x));

        } else {
            y = x;
        }
        return y;
    }

    /**
     * Finds the quadrant in which this position belongs.
     * @param position
     * @return 
     */
    private static int getQuadNumber(Double position) {
        int qNo = -1;
        int[] constant = new int[] { 360, 0, 0 };
        int sgn = (int) Math.signum(position);
        double absPosition = position + constant[sgn + 1];
        qNo = (int) (absPosition / 90.0);

        return qNo + 1;
    }

    /**
     * Finds the maximum separation between two points that are in quadrant1 and quadrant2.
     * @param quad1
     * @param quad2
     * @param angleZero
     * @param angleMax
     * @return 
     */
    private static Double findMaxDistance12(Double[] quad1, Double[] quad2) {

        if (quad1.length == 0 || quad2.length == 0) {
            angleZero = Double.NaN;
            angleMax = Double.NaN;
            return UNDEFINED;
        }

        Double maxDistance = UNDEFINED;
        angleZero = quad1[0];
        angleMax = quad2[quad2.length - 1];

        maxDistance = findMinAngularDistance(angleZero, angleMax);

        return maxDistance;
    }

    /**
     * Finds the maximum separation between two points that are in quadrant1 and quadrant4.
     * @param quad1
     * @param quad4
     * @param angleZero
     * @param angleMax
     * @return 
     */
    private static Double findMaxDistance14(Double[] quad1, Double[] quad4) {

        if (quad1.length == 0 || quad4.length == 0) {
            angleZero = Double.NaN;
            angleMax = Double.NaN;
            return UNDEFINED;
        }

        Double maxDistance = UNDEFINED;
        angleZero = quad1[quad1.length - 1];
        angleMax = quad4[0];

        maxDistance = findMinAngularDistance(angleZero, angleMax);

        return maxDistance;
    }

    /**
     * Finds the maximum separation between two points that are in quadrant2 and quadrant3.
     * @param quad2
     * @param quad3
     * @param angleZero
     * @param angleMax
     * @return 
     */
    private static Double findMaxDistance23(Double[] quad2, Double[] quad3) {

        if (quad2.length == 0 || quad3.length == 0) {
            angleZero = Double.NaN;
            angleMax = Double.NaN;
            return UNDEFINED;
        }

        Double maxDistance = UNDEFINED;
        angleZero = quad2[0];
        angleMax = quad3[quad3.length - 1];

        maxDistance = findMinAngularDistance(angleZero, angleMax);

        return maxDistance;
    }

    /**
     * Finds the maximum separation between two points that are in quadrant3 and quadrant4.
     * @param quad3
     * @param quad4
     * @param angleZero
     * @param angleMax
     * @return 
     */
    private static Double findMaxDistance34(Double[] quad3, Double[] quad4) {

        if (quad3.length == 0 || quad4.length == 0) {
            angleZero = Double.NaN;
            angleMax = Double.NaN;
            return UNDEFINED;
        }

        Double maxDistance = UNDEFINED;
        angleZero = quad3[0];
        angleMax = quad4[quad4.length - 1];

        maxDistance = findMinAngularDistance(angleZero, angleMax);

        return maxDistance;
    }

    /**
     * Finds the maximum separation between two points that are in quadrant1 and quadrant3.
     * Employs a search method similar to binary search. O(n log n) algorithm.
     * @param quad1
     * @param quad3
     * @param angleZero
     * @param angleMax
     * @return 
     */
    private static Double findMaxDistance13(Double[] quad1, Double[] quad3) {

        if (quad1.length == 0 || quad3.length == 0) {
            angleZero = Double.NaN;
            angleMax = Double.NaN;
            return UNDEFINED;
        }

        Double maxDistance = UNDEFINED;
        angleZero = quad1[0];
        angleMax = quad3[0];

        for (Double x : quad1) {
            Double y = findDiametricallyOppositeAngle(x);
            Double z = findClosestAngle(y, quad3);
            Double angularDistance = findMinAngularDistance(z, x);

            if (angularDistance > maxDistance) {
                maxDistance = angularDistance;
                angleZero = x;
                angleMax = z;
            }
        }

        maxDistance = findMinAngularDistance(angleZero, angleMax);

        return maxDistance;
    }

    /**
     * Finds the maximum separation between two points that are in quadrant2 and quadrant4.
     * @param quad2
     * @param quad4
     * @param angleZero
     * @param angleMax
     * @return 
     */
    private static Double findMaxDistance24(Double[] quad2, Double[] quad4) {

        if (quad2.length == 0 || quad4.length == 0) {
            angleZero = Double.NaN;
            angleMax = Double.NaN;
            return UNDEFINED;
        }

        return findMaxDistance13(quad2, quad4);
    }

    /**
     * Finds the maximum separation between two points that are in the same quadrant.
     * @param quad1
     * @param angleZero
     * @param angleMax
     * @return 
     */
    private static Double findMaxDistanceAA(Double[] quadA) {

        if (quadA.length == 0) {
            angleZero = Double.NaN;
            angleMax = Double.NaN;
            return UNDEFINED;
        }

        Double maxDistance = UNDEFINED;
        angleZero = quadA[0].doubleValue();
        angleMax = quadA[quadA.length - 1].doubleValue();

        maxDistance = findMinAngularDistance(angleZero, angleMax);

        return maxDistance;
    }

    /**
     * Transforms the positions in posVector by placing the origin at gAngleZero with
     * positive direction towards gAngleMax.
     * @param posVector
     * @param gAngleZero
     * @param gAngleMax
     * @param maxDistance should be < 180.0
     * @return 
     */
    private static Vector<Double> transformPosVector(
            Vector<Double> posVector, Double gAngleZero, Double gAngleMax,
            Double maxDistance) {
        Vector<Double> tPosVector = new Vector<Double>();

        for (Double position : posVector) {
            double d1 = findMinAngularDistance(gAngleZero, position);
            double d2 = findMinAngularDistance(gAngleMax, position);

            if (((d1 + d2) - maxDistance) <= ERROR) {
                tPosVector.add(d1);

            } else {
                tPosVector.add(-1.0 * d1);
            }
        }

        return tPosVector;
    }

    /**
     * Transforms the positions in posVector by placing the origin at gAngleZero with
     * positive direction towards gAngleMax.
     * 
     * This assumes maxDistance = 180.0
     * 
     * @param posVector
     * @param gAngleZero
     * @param gAngleMax
     * @return 
     */
    private static Vector<Double> transformPosVector(
            Vector<Double> posVector, Double gAngleZero, Double gAngleMax) {

        Vector<Double> tPosVector = new Vector<Double>();

        posVector.remove(-10.0);

        int sgn = getSignOf180(posVector, gAngleZero, gAngleMax);

        for (Double position : posVector) {
            double d = findMinAngularDistance(gAngleZero, position);

            if (position.compareTo(gAngleMax) == 0) {
                tPosVector.add(sgn * Math.abs(d));
            } else if (position >= gAngleZero || position < gAngleMax) {
                tPosVector.add(d);

            } else if (position < gAngleZero || position > gAngleMax) {
                tPosVector.add(-1.0 * d);

            }
        }

        return tPosVector;
    }

    /**
     * Computes the normal mean.
     * @param tPosVector
     * @return 
     */
    private static double computeMean(Vector<Double> tPosVector) {
        double meanPos = 0.0;
        double sum = 0.0;
        int n = 0;
        for (Double position : tPosVector) {
            sum += position;
            n++;
        }
        meanPos = sum / n;
        return meanPos;
    }

    /**
     * Computes the weighted mean.
     * @param tPosVector
     * @param wVector
     * @return 
     */
    private static double computeWeightedMean(Vector<Double> tPosVector,
            Vector<Double> wVector) {
        double meanPos = 0.0;
        double sum = 0.0;
        double sumW = 0.0;

        for (int i = 0; i <= tPosVector.size() - 1; i++) {
            Double position = tPosVector.elementAt(i);
            Double weight = wVector.elementAt(i);
            sum += position * weight;
            sumW += weight;
        }
        meanPos = sum / sumW;
        return meanPos;
    }

    /**
     * Does the reverse transformation of an angle.
     * @param tMeanPos
     * @param gAngleZero
     * @param gAngleMax
     * @param maxDistance
     * @return 
     */
    private static double unTransform(Double tMeanPos, Double gAngleZero,
            Double gAngleMax, Double maxDistance) {
        double meanPos = 0.0;
        if (maxDistance == 180.0) {
            meanPos = add(gAngleZero, tMeanPos);

        } else {
            //Find the candidate mean postions.
            double cMean1 = addClockwise(gAngleZero, Math.abs(tMeanPos));
            double cMean2 = addAntiClockwise(gAngleZero, Math.abs(tMeanPos));

            //Find which one lies between gAngleZero and gAngleMax
            double d1 = findMinAngularDistance(gAngleZero, cMean1);
            double d2 = findMinAngularDistance(cMean1, gAngleMax);

            if (((d1 + d2) - maxDistance) <= ERROR) {
                meanPos = cMean1;

            }

            d1 = findMinAngularDistance(gAngleZero, cMean2);
            d2 = findMinAngularDistance(cMean2, gAngleMax);

            if (((d1 + d2) - maxDistance) <= ERROR) {
                meanPos = cMean2;

            }
        }

        return meanPos;
    }

    /**
     * Finds the angle obtained by moving a distance of delta_x from x in a clockwise direction.
     * @param x
     * @param delta_x magnitude of the clockwise shift.
     * @return the transformed angle obtained after clockwise addition.
     */
    private static Double addClockwise(Double x, Double delta_x) {
        Double y = null;
        delta_x = delta_x % 360;

        if (x + delta_x > 180.0) {
            y = (x + delta_x) - 360;

        } else {
            y = x + delta_x;

        }
        return y;
    }

    /**
     * Finds the angle obtained by moving a distance of delta_x from x in a anti-clockwise direction.
     * @param x
     * @param delta_x magnitude of the anti-clockwise shift.
     * @return the transformed angle obtained after anti-clockwise addition.
     */
    private static Double addAntiClockwise(Double x, Double delta_x) {
        Double y = null;
        delta_x = delta_x % 360;

        if (x - delta_x < -180.0) {
            y = (x - delta_x) + 360;

        } else {
            y = x - delta_x;

        }
        return y;
    }

    /**
     * Finds the minimum angular distance between two angles.
     * @param angle1
     * @param angle2
     * @return
     */
    private static double findMinAngularDistance(double angle1,
            double angle2) {
        double angDistance = 0.0;
        if (Math.signum(angle2) == Math.signum(angle1)) {
            angDistance = Math.abs(angle2 - angle1);
        } else {
            double sumAngle = Math.abs(angle1) + Math.abs(angle2);
            angDistance = Math.min(sumAngle, 360 - sumAngle);
        }
        return angDistance;
    }

    /**
     * Finds the diametrically opposite angle to this angle.<br>
     * The diametrically opposite angle to 2.5 is -177.5
     * @param angle
     * @return
     */
    private static double findDiametricallyOppositeAngle(double angle) {
        double oppAngle = 0.0;
        double sgn = Math.signum(angle);
        if (sgn == 0) {
            sgn += 1.0;
        }
        oppAngle = -1 * sgn * (180 - Math.abs(angle));
        return oppAngle;
    }

    /**
     * Finds the closest value in quad that is closest in distance to angle.
     * @param angle
     * @param quad
     * @return 
     */
    private static double findClosestAngle(double angle, Double[] quad) {
        double closestAngle = 0;
        int l = 0;
        int u = quad.length - 1;
        int mid = (l + u) / 2;
        while (l <= u) {

            mid = (l + u) / 2;
            if (angle > quad[mid]) {
                l = mid + 1;

            } else if (angle < quad[mid]) {
                u = mid - 1;

            } else {
                break;
            }
        }
        mid = (l + u) / 2;
        closestAngle = quad[mid];

        //IMP: The closestAngle obtained above is the angle just smaller than angle in the array quad.
        //     As an additional correction we need to check which among quad[mid] and quad[mid+1] is closer to angle.
        //     Also the case when size of quad is 1 is also handled.
        //Begin Correction
        if (mid + 1 < quad.length) {
            Double closestAngle1 = quad[mid];
            Double closestAngle2 = quad[mid + 1];
            Double distance1 = findMinAngularDistance(closestAngle1, angle);
            Double distance2 = findMinAngularDistance(closestAngle2, angle);
            if (distance1 < distance2) {
                closestAngle = closestAngle1;

            } else {
                closestAngle = closestAngle2;

            }
        }
        //End Correction

        return closestAngle;
    }

    /**
     * Finds the sign of gAngleMax in transformed coordinates when maxDistance = 180.0
     * @param posVector
     * @param gAngleZero
     * @param gAngleMax
     * @return 
     */
    private static int getSignOf180(Vector<Double> posVector,
            Double gAngleZero, Double gAngleMax) {
        int sgn = 1;
        int positives = 0;
        int negatives = 0;

        for (Double position : posVector) {
            if (position.compareTo(gAngleZero) == 0
                    || position.compareTo(gAngleMax) == 0) {
                continue;
            } else if (position > gAngleZero || position < gAngleMax) {
                positives++;

            } else if (position < gAngleZero || position > gAngleMax) {
                negatives++;
            }
        }

        if (positives > negatives) {
            sgn = 1;
        } else {
            sgn = -1;
        }
        return sgn;
    }
}

Related Tutorials