Package org.geotools.referencing.operation.builder

Source Code of org.geotools.referencing.operation.builder.BursaWolfTransformBuilder

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library 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
*    Lesser General Public License for more details.
*/
package org.geotools.referencing.operation.builder;

import org.opengis.referencing.FactoryException;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.geometry.DirectPosition;

import org.geotools.referencing.datum.BursaWolfParameters;
import org.geotools.referencing.operation.matrix.GeneralMatrix;
import org.geotools.referencing.operation.transform.GeocentricTranslation;

import java.util.List;
import javax.vecmath.GMatrix;


/**
* Builds {@linkplain org.opengis.referencing.operation.MathTransform
* MathTransform} setup as BursaWolf transformation from a list of {@linkplain
* org.geotools.referencing.operation.builder.MappedPosition MappedPosition}.
* The calculation uses least square method.  Calculated parameters can be
* used for following operations:<p></p>
<p>The equations:<pre> X = q * R * x  +  T ,             </pre>Where X
* is the Matrix of destination points, q is the scale,  R is the rotation
* Matrix, x is the Matrix of source points  and T is matrix of translation.
* Expressing the errors, we get this:<pre>        Err =  A * Dx + l </pre>where
* Err is the Error Matrix, A is Matrix of derivations, Dx is Matrix  of
* difference changes of 7 parameters, and l is value of DX, DY, DZ for
* calculated from approximate values. Using the least square method to
* minimalize the errors we get this result:<pre>
*  Dx = (A<sup>T</sup>A)<sup>-1</sup> A<sup>T</sup></pre></p>
*
* @since 2.4
*
*
* @source $URL$
* @version $Id$
* @author Jan Jezek
*
*/
public class BursaWolfTransformBuilder extends MathTransformBuilder {
    /** The Geodetic Datum of target reference system */
    private GeodeticDatum targetDatum;

    /** Matrix of source points */
    GeneralMatrix x;

    /** Matrix of destination points. */
    GeneralMatrix X;

    /** Bursa Wolf rotation in arc radians. */
    private double alfa = 0;

    /** Bursa Wolf rotation in arc radians. */
    private double beta = 0;

    /** Bursa Wolf rotation in arc radians. */
    private double gamma = 0;

    /** Bursa Wolf shift in meters. */
    private double dx = 0;

    /** Bursa Wolf shift in meters. */
    private double dy = 0;

    /** Bursa Wolf shift in meters. */
    private double dz = 0;

    /** Bursa Wolf scaling. */
    private double q = 1;

    /**
     * Creates a BursaWolfTransformBuilder.
     *
     * @param vectors list of {@linkplain MappedPosition mapped positions}.
     */
    public BursaWolfTransformBuilder(final List<MappedPosition> vectors) {
        super.setMappedPositions(vectors);

        x = new GeneralMatrix(vectors.size(), 3);
        X = new GeneralMatrix(vectors.size(), 3);
        x = getx();
        X = getX();
        this.getDxMatrix();
    }

    /**
     * Returns the minimum number of points required by this builder,
     * which is 3.
     *
     * @return the minimum number of points required by this builder which is
     *         3.
     */
    public int getMinimumPointCount() {
        return 3;
    }

    /**
     * Returns the dimension for {@link #getSourceCRS source} and
     * {@link #getTargetCRS target} CRS, which is 2.
     *
     * @return dimension for {@linkplain #getSourceCRS source} and {@link
     *         #getTargetCRS target} CRS, which is 2.
     */
    @Override
    public int getDimension() {
        return 3;
    }

    /**
     * Returns the required coordinate system type, which is
     * {@linkplain CartesianCS cartesian CS}.
     *
     * @return coordinate system type
     */
    @Override
    public Class <? extends CartesianCS> getCoordinateSystemType() {
        return CartesianCS.class;
    }

    /**
     * Fills the x matrix by coordinates of source points.
     *
     * @return x matrix.
     */
    protected GeneralMatrix getx() {
        final DirectPosition[] sourcePoints = getSourcePoints();
        GeneralMatrix x = new GeneralMatrix(3 * sourcePoints.length, 1);

        for (int j = 0; j < (x.getNumRow()); j = j + 3) {
            x.setElement(j, 0, sourcePoints[j / 3].getCoordinate()[0]);
            x.setElement(j + 1, 0, sourcePoints[j / 3].getCoordinate()[1]);
            x.setElement(j + 2, 0, sourcePoints[j / 3].getCoordinate()[2]);
        }

        return x;
    }

    /**
     * Fills the x matrix by  coordinates of destination points.
     *
     * @return the X matrix
     */
    protected GeneralMatrix getX() {
        final DirectPosition[] sourcePoints = getSourcePoints();
        final DirectPosition[] targetPoints = getTargetPoints();
        GeneralMatrix X = new GeneralMatrix(3 * sourcePoints.length, 1);

        for (int j = 0; j < (X.getNumRow()); j = j + 3) {
            X.setElement(j, 0, targetPoints[j / 3].getCoordinate()[0]);
            X.setElement(j + 1, 0, targetPoints[j / 3].getCoordinate()[1]);
            X.setElement(j + 2, 0, targetPoints[j / 3].getCoordinate()[2]);
        }

        return X;
    }

    /**
     * Generates rotation matrix around X axis.
     *
     * @return rotation Matrix
     */
    protected GeneralMatrix getRalfa() {
        GeneralMatrix Ralfa = new GeneralMatrix(3, 3);
        double[] m0 = { 1, 0, 0 };
        double[] m1 = { 0, Math.cos(alfa), Math.sin(alfa) };
        double[] m2 = { 0, -Math.sin(alfa), Math.cos(alfa) };
        Ralfa.setRow(0, m0);
        Ralfa.setRow(1, m1);
        Ralfa.setRow(2, m2);

        return Ralfa;
    }

    /**
     * Generates rotation matrix around Y axis.
     *
     * @return rotation Matrix.
     */
    protected GeneralMatrix getRbeta() {
        GeneralMatrix Rbeta = new GeneralMatrix(3, 3);
        double[] m0 = { Math.cos(beta), 0, -Math.sin(beta) };
        double[] m1 = { 0, 1, 0 };
        double[] m2 = { Math.sin(beta), 0, Math.cos(beta) };
        Rbeta.setRow(0, m0);
        Rbeta.setRow(1, m1);
        Rbeta.setRow(2, m2);

        return Rbeta;
    }

    /**
     * Generates rotation matrix around Z axis.
     *
     * @return rotation Matrix.
     */
    protected GeneralMatrix getRgamma() {
        GeneralMatrix Rgamma = new GeneralMatrix(3, 3);
        double[] m0 = { Math.cos(gamma), Math.sin(gamma), 0 };
        double[] m1 = { -Math.sin(gamma), Math.cos(gamma), 0 };
        double[] m2 = { 0, 0, 1 };
        Rgamma.setRow(0, m0);
        Rgamma.setRow(1, m1);
        Rgamma.setRow(2, m2);

        return Rgamma;
    }

    /**
     * Generates partial derivative with respect to alfa.
     *
     * @return Matrix, that represents partial derivation of rotation Matrix
     *         with respect to  alfa.
     */
    protected GeneralMatrix getDRalfa() {
        GeneralMatrix dRa = new GeneralMatrix(3, 3);

        double[] m0 = { 0, 0, 0 };
        double[] m1 = { 0, -Math.sin(alfa), Math.cos(alfa) };
        double[] m2 = { 0, -Math.cos(alfa), -Math.sin(alfa) };

        dRa.setRow(0, m0);
        dRa.setRow(1, m1);
        dRa.setRow(2, m2);

        dRa.mul(dRa, getRbeta());
        dRa.mul(dRa, getRgamma());

        return specialMul(dRa, x);
    }

    /**
     * Generates partial derivative with respect to beta.
     *
     * @return Matrix, that represents partial derivation of rotation Matrix
     *         with respect to  beta.
     */
    protected GeneralMatrix getDRbeta() {
        //GeneralMatrix dRbeta = new GeneralMatrix(3 * sourcePoints.size(), 1);
        GeneralMatrix dRb = new GeneralMatrix(3, 3);
        double[] m0 = { -Math.sin(beta), 0, -Math.cos(beta) };
        double[] m1 = { 0, 0, 0 };
        double[] m2 = { Math.cos(beta), 0, -Math.sin(beta) };
        dRb.setRow(0, m0);
        dRb.setRow(1, m1);
        dRb.setRow(2, m2);

        dRb.mul(getRalfa(), dRb);
        dRb.mul(dRb, getRgamma());

        return specialMul(dRb, x);
    }

    /**
     * Generates partial derivative with respect to gamma.
     *
     * @return Matrix, that represents partial derivation of rotation Matrix
     *         with respect to  gamma.
     */
    protected GeneralMatrix getDRgamma() {
        //  GeneralMatrix dRgamma = new GeneralMatrix(3 * sourcePoints.size(), 1);
        GeneralMatrix dRg = new GeneralMatrix(3, 3);
        GeneralMatrix pom = new GeneralMatrix(3, 3);
        double[] m0 = { -Math.sin(gamma), Math.cos(gamma), 0 };
        double[] m1 = { -Math.cos(gamma), -Math.sin(gamma), 0 };
        double[] m2 = { 0, 0, 0 };
        dRg.setRow(0, m0);
        dRg.setRow(1, m1);
        dRg.setRow(2, m2);

        pom.mul(getRalfa(), getRbeta());
        dRg.mul(pom, dRg);

        return specialMul(dRg, x);
    }

    /**
     * Generates partial derivative in q (scale factor).
     *
     * @return rotation Matrix.
     */
    protected GeneralMatrix getDq() {
        //  GeneralMatrix Dq = new GeneralMatrix(3 * sourcePoints.size(), 1);
        GeneralMatrix R = new GeneralMatrix(3, 3);
        R.mul(getRalfa(), getRbeta());
        R.mul(R, getRgamma());

        return specialMul(R, x);
    }

    /**
     * Calculates the matrix of errors from aproximate values of
     * prameters.
     *
     * @return the l matrix.
     */
    protected GeneralMatrix getl() {
        GeneralMatrix l = new GeneralMatrix(3 * getMappedPositions().size(), 1);
        GeneralMatrix R = new GeneralMatrix(3, 3);
        GeneralMatrix T = new GeneralMatrix(3, 1, new double[] { -dx, -dy, -dz });
        GeneralMatrix qMatrix = new GeneralMatrix(1, 1, new double[] { q });
        GeneralMatrix qx = new GeneralMatrix(X.getNumRow(), X.getNumCol());
        qx.mul(x, qMatrix);
        R.mul(getRalfa(), getRbeta());
        R.mul(getRgamma());

        l.sub(specialMul(R, qx), X);
        l = specialSub(T, l);

        return l;
    }

    /**
     * Method for multiplying  matrix (3,3) by matrix of  coordintes (3
     * number of coordinates,1)
     *
     * @param R ratrix
     * @param x matrix
     *
     * @return matrix
     */
    protected GeneralMatrix specialMul(GeneralMatrix R, GeneralMatrix x) {
        GeneralMatrix dRx = new GeneralMatrix(3 * getMappedPositions().size(), 1);

        for (int i = 0; i < x.getNumRow(); i = i + 3) {
            GeneralMatrix subMatrix = new GeneralMatrix(3, 1);
            x.copySubMatrix(i, 0, 3, 1, 0, 0, subMatrix);
            subMatrix.mul(R, subMatrix);
            subMatrix.copySubMatrix(0, 0, 3, 1, i, 0, dRx);
        }

        return dRx;
    }

    /**
     * Method for addition matrix (3,3) with matrix of coordintes (3
     * number of coordinates,1)
     *
     * @param R ratrix
     * @param x matrix
     *
     * @return matrix
     */
    private GeneralMatrix specialSub(GeneralMatrix R, GeneralMatrix x) {
        GeneralMatrix dRx = new GeneralMatrix(3 * getMappedPositions().size(), 1);

        for (int i = 0; i < x.getNumRow(); i = i + 3) {
            GeneralMatrix subMatrix = new GeneralMatrix(3, 1);
            x.copySubMatrix(i, 0, 3, 1, 0, 0, subMatrix);
            subMatrix.sub(R, subMatrix);
            subMatrix.copySubMatrix(0, 0, 3, 1, i, 0, dRx);
        }

        return dRx;
    }

    /**
     * Glues the submatrix of derivations into the A matrix.
     *
     * @return A mtarix
     */
    protected GeneralMatrix getA() {
        final int size = getMappedPositions().size();
        GeneralMatrix A = new GeneralMatrix(3 * size, 7);
        GeneralMatrix DT = new GeneralMatrix(3, 3);

        // the partial derivative with respect to dx,dy,dz.
        double[] m0 = { 1, 0, 0 };
        double[] m1 = { 0, 1, 0 };
        double[] m2 = { 0, 0, 1 };
        DT.setRow(0, m0);
        DT.setRow(1, m1);
        DT.setRow(2, m2);

        for (int i = 0; i < A.getNumRow(); i = i + 3) {
            DT.copySubMatrix(0, 0, 3, 3, i, 0, A);
        }

        getDRalfa().copySubMatrix(0, 0, 3 * size, 1, 0, 3, A);
        getDRbeta().copySubMatrix(0, 0, 3 * size, 1, 0, 4, A);
        getDRgamma().copySubMatrix(0, 0, 3 * size, 1, 0, 5, A);
        getDq().copySubMatrix(0, 0, 3 * size, 1, 0, 6, A);

        return A;
    }

    /**
     * Returns array of doubles of transformation parameters (dx, dy,
     * dz, ex, ey, ez, scale).
     *
     * @return array of doubles of transformation parameters (dx, dy, dz, ex,
     *         ey, ez, scale).
     */
    protected double[] getParameters() {
        return getDxMatrix().getElements()[0];
    }

    /**
     * Method that claculates the parameters by iteration. The
     * tolarance is set to 1  10<sub>-8</sub>  and max �number of steps is set
     * to 20.
     *
     * @return Matrix of parameters (dx, dy, dz, ex, ey, ez, scale).
     */
    public GeneralMatrix getDxMatrix() {
        return getDxMatrix(0.00000001, 20);
    }

    /**
     * Iterates the parameters..
     *
     * @param tolerance for iteration steps (the max difference between last
     *        two steps)
     * @param maxSteps highest number of iteations.
     *
     * @return GeneralMatrix of calculated parameters.
     */
    private GeneralMatrix getDxMatrix(double tolerance, int maxSteps) {
        // Matriix of new calculated coefficeients
        GeneralMatrix xNew = new GeneralMatrix(7, 1);

        // Matrix of coefficients claculated in previous iteration
        GeneralMatrix xOld = new GeneralMatrix(7, 1);

        // diference between each steps of old iteration
        GeneralMatrix dxMatrix = new GeneralMatrix(7, 1);

        GeneralMatrix zero = new GeneralMatrix(7, 1);
        zero.setZero();

        // i is a number of iterations
        int i = 0;

        // cicle for iteration
        do {
            xOld.set(new double[] { dx, dy, dz, alfa, beta, gamma, q });

            GeneralMatrix A = getA();
            GeneralMatrix l = getl();

            GeneralMatrix AT = A.clone();
            AT.transpose();

            GeneralMatrix ATA = new GeneralMatrix(7, 7);
            GeneralMatrix ATl = new GeneralMatrix(7, 1);

            // dx = A^T * A  * A^T * l
            ATA.mul(AT, A);
            ATA.invert();
            ATl.mul(AT, l);

            dxMatrix.mul(ATA, ATl);

            // New values of x = dx + previous values
            xOld.negate();
            xNew.sub(dxMatrix, xOld);

            // New values are setup for another iteration
            dx = xNew.getElement(0, 0);
            dy = xNew.getElement(1, 0);
            dz = xNew.getElement(2, 0);
            alfa = xNew.getElement(3, 0);
            beta = xNew.getElement(4, 0);
            gamma = xNew.getElement(5, 0);
            q = xNew.getElement(6, 0);

            i++;
        } while ((!dxMatrix.equals(zero, tolerance) & (i < maxSteps)));

        xNew.transpose();

        return xNew;
    }

    /**
     * Coverts radians to seconds.
     *
     * @param rad Angle in radians
     *
     * @return Angle is seconds
     */
    private static double radiansToSeconds(double rad) {
        return (rad * (180 / Math.PI) * (3600));
    }

    /**
     * Returns Bursa Wolf Transformation parameters.
     *
     * @param Datum The target datum for this parameters.
     *
     * @return parameters the BursaWolfParameters
     */
    public BursaWolfParameters getBursaWolfParameters(GeodeticDatum Datum) {
        BursaWolfParameters parameters = new BursaWolfParameters(Datum);
        parameters.dx = dx;
        parameters.dy = dy;
        parameters.dz = dz;
        parameters.ex = -radiansToSeconds(alfa);
        parameters.ey = -radiansToSeconds(beta);
        parameters.ez = -radiansToSeconds(gamma);
        parameters.ppm = (q - 1) * 1000000;

        return parameters;
    }

    public void setTargetGeodeticDatum(GeodeticDatum gd) {
        this.targetDatum = gd;
    }

    /**
     * Returns MathtTransform setup as BursaWolf transformation.
     *
     * @return calculated MathTransform
     *
     * @throws FactoryException when the size of source and destination point
     *         is not the same or if the number of points is too small to
     *         define such transformation.
     */
    protected MathTransform computeMathTransform() throws FactoryException {
        return new GeocentricTranslation(getBursaWolfParameters(targetDatum));
    }
}
TOP

Related Classes of org.geotools.referencing.operation.builder.BursaWolfTransformBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.