1.四参数来历

1、平面坐标 - 平面坐标

在坐标转换的过程中,我们我们在小范围内,可以使用四参数就能达到坐标转换的目的,且精度也能达到预定的需求。,四参数计算公式如下

iOS 开发 将四个坐标进行连线 坐标四个数字_四参数求解


X1Y1代表原平面坐标下的坐标, X2Y2代表目标平面坐标下的坐标,二者转换需要四个参数,分别为x、y两个坐标的偏移,以及旋转角度和尺度因子等

2、四参数求解

四参数求解至少需要两个点对,分别知道其在目标投影坐标和原投影坐标下的坐标点对,我觉得**dibowei2069**写的求解过程就很详细,下面我将贴出其博客的链接,同时为了保持本文丰富性,将其内容进行拿来主义了:PS:这里的P矩阵写法有问题,自己在计算的过程中发现了致命的问题,P矩阵应该是一个单位矩阵,其维度应为2count✖2count (count为数据点对的个数),因此在公式中,我们可以忽略相应的单位矩阵,得到的结果也不影响最终的答案。

iOS 开发 将四个坐标进行连线 坐标四个数字_四参数求解_02

PS: 想知道更加具体的信息,可以去他博客去了解下,链接为: 再次表示感谢、感谢、感谢!!!!!

2、四参数求解

1、java写矩阵运算计算

一开始想着自己写矩阵运算,提高自己的码力,也写出来了,但是精度有点问题,我也不知道为啥,在计算的过程中,我都使用了BigDecimal去保留更多的精度,奈何就是精度不够,差距十多米,但是我坚信,自己写的没问题,下面我贴出自己的实现方式,希望大家多多提出意见,看看到底错在那里:同时在此我给出两组数组对,方便大家使用,在下面的代码中,需要的自取,最后,我还会给出一对方便大家验证:下面给出截图,同时为了方便复制,我也将其放在代码块里面

iOS 开发 将四个坐标进行连线 坐标四个数字_求解四参数_03

/*
    **点	   X1	      Y1	         X2	      Y2
    P1	4312820.897	513670.931	4312816.917	513553.7194
    P2	4314058.425	514231.984	4314054.44	514114.7771
    P3	4306670.108	511168.332	4306666.154 511051.098**
     */
 //利用两组坐标,求解四参数
    public static double [] solveFourParameters(){
        Point3D original = new Point3D(4312820.897,513670.931,402.992);
        Point3D origina2 = new Point3D(4314058.425,514231.984,432.447);
        Point3D target1 = new Point3D(4312816.917,513553.719,416.183);
        Point3D  target2 = new Point3D(4314054.440,514114.777,445.596);
        double [][] L = {{target1.getX()-original.getX()},
                {target1.getY()-original.getY()},
                {target2.getX()- origina2.getX()},
                {target2.getY()-origina2.getY()}
                };
        PrintMatrix(L);
        double [][] P = formUnitMatrix(4);
        PrintMatrix(P);
        double [][] B = {{1,0,original.getX(),-original.getY()},
                {0,1,original.getY(),original.getX()},
                {1,0,origina2.getX(),-origina2.getY()},
                {0,1,origina2.getY(),origina2.getX()}};
        PrintMatrix(B);
        double [][] firstPart = matrixInv(matrixMultiply(matrixMultiply(matrixTransposition(B),P),B));
        double [][] first = matrixMultiply(matrixTransposition(B),P);
        PrintMatrix(first);
        double [][] second = matrixMultiply(first,B);
        PrintMatrix(second);
        double [][] third = matrixInv(second);
        PrintMatrix(third);
        double [][] fourth = matrixMultiply(third,matrixTransposition(B));
        PrintMatrix(fourth);
        double [][] fifth = matrixMultiply(fourth,P);
        PrintMatrix(fifth);
        double [][] finalMatrix = matrixMultiply(fifth,L);
        PrintMatrix(finalMatrix);

       // double [][] finalMatrix = matrixMultiply(matrixMultiply(matrixMultiply(firstPart,matrixTransposition(B)),P),L);
        double m = Math.sqrt(Math.pow(finalMatrix[2][0]+1,2)+ Math.pow(finalMatrix[3][0],2));
        double angle = Math.atan(finalMatrix[3][0]/(finalMatrix[2][0]-1));

        double [] fourParameter = {finalMatrix[0][0],finalMatrix[1][0],angle,m};
        Log.e("anywhere", fourParameter[0]+ "\n"+ fourParameter[1]+"\n"+ fourParameter[2]+"\n"+fourParameter[3]);
        //得到的四参数进行结算
        double[] four_para = fourParameter;
        Point3D point3D = new Point3D(4306670.108,511168.332,309.157);
        BigDecimal oldx = BigDecimal.valueOf(point3D.getX());
        BigDecimal oldy = BigDecimal.valueOf(point3D.getY());
        BigDecimal cos = new BigDecimal(String.valueOf(Math.cos(four_para[2])));  //计算cos
        BigDecimal sin = new BigDecimal(String.valueOf(Math.sin(four_para[2])));   //计算sin
        BigDecimal part1= cos.multiply(oldx);
        BigDecimal part2= oldy.multiply(sin);
        BigDecimal part3= part1.subtract(part2);
        BigDecimal part4= BigDecimal.valueOf(four_para[3]).multiply(part3);
        BigDecimal x= BigDecimal.valueOf(four_para[0]).add(part4);
        BigDecimal newX =x.setScale(6,BigDecimal.ROUND_HALF_DOWN);
        BigDecimal y = BigDecimal.valueOf(four_para[1]).add(BigDecimal.valueOf(four_para[3]).multiply(oldx.multiply(sin).add(oldy.multiply(cos))));
        BigDecimal newY = y.setScale(6,BigDecimal.ROUND_HALF_DOWN);
        Log.e("anywhere","newx:"+ newX+"\n"+"newY:"+ newY);
        return fourParameter;
    }

    private static void PrintMatrix(double [][] matrix) {
        for(int i = 0 ; i< matrix.length;i++){
            StringBuilder builder = new StringBuilder();
            for(int j = 0; j<matrix[0].length;j++){
                builder.append(matrix[i][j]).append(" + ");
            }
            Log.e("matrix",builder.toString()+"\n");
        }
    }
    public static double[][] formUnitMatrix(int dimen) {
        double [][]temp = new double[dimen][dimen];
        for(int i = 0;i< dimen ;i++){
            for(int j= 0;j< dimen;j++){
                if(i==j)
                    temp[i][j]=1;
                else
                    temp[i][j]=0;
            }
        }
        return temp;
    }

    /*
    利用java实现矩阵的乘法和转置以及求逆矩阵
     */
    //转置,必须行列都一样
    public static double [][] matrixTransposition( double [][] changedMatrix){
        int colums = changedMatrix.length;
        double targetMatrix [][] = new double[colums][colums];
        for(int i = 0; i< colums ;i++){
            for(int j = 0; j< colums; j++){
                targetMatrix[i][j] = changedMatrix[j][i];
            }
        }
        return targetMatrix;
    }

    //矩阵的乘法,前一个列数与后一个行数相同
    public static  double[][] matrixMultiply(double[][] previousMatrix , double [][] laterMatrix){
        if(previousMatrix[0].length!= laterMatrix.length){
            return null;
        }
        int lines = previousMatrix.length;   //新的行数
        int colums = laterMatrix[0].length;  //列数
        int commonLines = laterMatrix.length;  //前一个的列数与后一个的行数
        double[][] targetMatrix = new double[lines][colums];
        for(int i = 0; i < lines ; i++){
            for(int j = 0; j< colums ;j++){
                BigDecimal sum = BigDecimal.valueOf(0.0);
                for(int k = 0 ;k < commonLines ;k++){
                    sum = sum.add(BigDecimal.valueOf(previousMatrix[i][k]).multiply(BigDecimal.valueOf(laterMatrix[k][j])));
                }
                targetMatrix[i][j] = sum.doubleValue();
            }
        }
        return targetMatrix;
    }

    //求矩阵的行列式,我们可以求解四次的
    public static double matrixValues(double [][] solvMatrix){
        if(solvMatrix.length!= solvMatrix[0].length)
            return 0.;
        if (solvMatrix.length==1)
            return solvMatrix[0][0];
        else if (solvMatrix.length==2)
            return matrix2Det(solvMatrix);
        else if (solvMatrix.length==3)
            return matrix3Det(solvMatrix);
        else {    //可以求解四次的
            double sum = 0.0;
            for (int i = 0; i < 4; i++) {
                sum += Math.pow(-1, i + 2) * solvMatrix[0][i] * matrix3Det(companionMatrix(solvMatrix, 0, i));
            }
            return sum;
        }
    }
    //  根据位置,求得伴随矩阵
    public static double [][] companionMatrix(double [][] matrix ,int line ,int column){
        int lines = matrix.length;
        int columns = matrix[0].length;
        double [][] targetMarix = new double[lines-1][columns-1];
        int dx=0;
        for(int i=0;i < lines ;++i){
            if(i!=line){
                int dy=0;
                for (int j=0;j < columns ;++j){
                    if (j!=column){
                        targetMarix[dx][dy++] = matrix[i][j];
                    }
                }
                ++dx;
            }
        }
        return targetMarix;
    }
    //求解三阶的行列式值
    public static double matrix3Det(double[][] solvMatrix) {
        if(solvMatrix.length!=solvMatrix[0].length){
            return 0.;
        }
        double [][] A0 = companionMatrix(solvMatrix,0,0);
        double [][] A1 = companionMatrix(solvMatrix,0,1);
        double [][] A2 = companionMatrix(solvMatrix,0,2);
        BigDecimal Part1 = BigDecimal.valueOf(solvMatrix[0][0]).multiply(BigDecimal.valueOf(matrix2Det(A0)));
        BigDecimal Part2 = BigDecimal.valueOf(solvMatrix[0][1]).multiply(BigDecimal.valueOf(matrix2Det(A1)));
        BigDecimal Part3 = BigDecimal.valueOf(solvMatrix[0][2]).multiply(BigDecimal.valueOf(matrix2Det(A2)));
        BigDecimal part1_2 = Part1.subtract(Part2);
        BigDecimal final_result = part1_2.add(Part3);
        return final_result.doubleValue();
    }
    //求解2阶的行列式值
    public static double matrix2Det(double[][] solvMatrix) {
        BigDecimal first = BigDecimal.valueOf(solvMatrix[0][0]).multiply(BigDecimal.valueOf(solvMatrix[1][1]));
        BigDecimal second = BigDecimal.valueOf(solvMatrix[0][1]).multiply(BigDecimal.valueOf(solvMatrix[1][0]));
        return first.subtract(second).doubleValue();
    }

    //求逆矩阵
    public static double[][] matrixInv(double[][] solveMatrix){
        //行数与列数必须相等
        if (solveMatrix.length!=solveMatrix[0].length)
            return null;
        int lines = solveMatrix.length;
        int columns = solveMatrix[0].length;
        double A = matrixValues(solveMatrix);
        double[][] targetMatrix =new double[lines][columns];
        for(int i=0;i < lines;++i){
            for (int j=0;j< columns ;++j){
                double[][] temp= companionMatrix(solveMatrix,i,j);
                targetMatrix[j][i]=BigDecimal.valueOf(matrixValues(temp)).divide(BigDecimal.valueOf(A),40,BigDecimal.ROUND_DOWN).doubleValue() * Math.pow(-1,i+j);
            }
        }
        return targetMatrix;
    }

2、jar包闪亮上场
既然自己写的精度存在问题,那么我就想到了jar的方法,去看看大佬们如何写的,然后就网上搜索,看到了一篇关于***commons-math3***的介绍,在此对***HFUT_qianyang***表示感谢、感谢、感谢!!大家也可以去他的博客去看看jar包math3关于矩阵的基本使用,链接位:,同时,我也将自己下载好的math3 jar包上传,希望能帮助到大家。

实现流程与上文自己写的类似,就是将矩阵运算替换位jar包中提供的方法,最后结果的截图位:

iOS 开发 将四个坐标进行连线 坐标四个数字_矩阵运算_04

newX、newY分别为根据计算出的四参数求得的新的转换坐标,本身应该为 X2= 4306666.154 Y2 = 511051.098,误差分别只有3mm与4mm,对于厘米级要求的工程,远远超出其标准。

import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.RealMatrix;

public class Hero {
    public static void main(String[] asgs){
        //checkRegerx();
        calculateFourParameters();

    }

    private static void calculateFourParameters() {
        Point3D original = new Point3D(4312820.897,513670.931,402.992);
        Point3D origina2 = new Point3D(4314058.425,514231.984,432.447);
        Point3D target1 = new Point3D(4312816.917,513553.719,416.183);
        Point3D  target2 = new Point3D(4314054.440,514114.777,445.596);
        double [][] L1 = {{target1.getX()-original.getX()},
                {target1.getY()-original.getY()},
                {target2.getX()- origina2.getX()},
                {target2.getY()-origina2.getY()}
        };
        double [][] P1 = formUnitMatrix(4);
        double [][] B1 = {{1,0,original.getX(),-original.getY()},
                {0,1,original.getY(),original.getX()},
                {1,0,origina2.getX(),-origina2.getY()},
                {0,1,origina2.getY(),origina2.getX()}};
        //转为我们需要的数组
        RealMatrix L = new Array2DRowRealMatrix(L1);
        RealMatrix P = new Array2DRowRealMatrix(P1);
        RealMatrix B = new Array2DRowRealMatrix(B1);

        RealMatrix first = P.multiply(B.transpose()); //Bt*P
        PrintMatrix(first,"BT*P");
        RealMatrix second = first.multiply(B);
        PrintMatrix(second,"BT*P*B");
        RealMatrix third = inverseMatrix(second);
        PrintMatrix(third,"(BT*B*P)-");
        RealMatrix fourth = third.multiply(B.transpose());
        PrintMatrix(fourth,"(BT*B*P)-*BT");
        RealMatrix fifth = fourth.multiply(P);
        PrintMatrix(fifth,"(BT*B*P)-BT*P");
        RealMatrix sixth = fifth.multiply(L);
        PrintMatrix(sixth,"(BT*B*P)-BT*P*L");

        double [][] finalMatrix = sixth.getData();
        double m = Math.sqrt(Math.pow(finalMatrix[2][0]+1,2)+ Math.pow(finalMatrix[3][0],2));
        double angle = Math.atan(finalMatrix[3][0]/(finalMatrix[2][0]-1));

        double [] fourParameter = {finalMatrix[0][0],finalMatrix[1][0],Math.abs(angle),m};
        System.out.print("final: "+ fourParameter[0]+ "\n"+ fourParameter[1]+"\n"+ fourParameter[2]+"\n"+fourParameter[3]);

        double[] four_para = fourParameter;
        Point3D point3D = new Point3D(4306670.108,511168.332,309.157);
        BigDecimal oldx = BigDecimal.valueOf(point3D.getX());
        BigDecimal oldy = BigDecimal.valueOf(point3D.getY());
        BigDecimal cos = new BigDecimal(String.valueOf(Math.cos(four_para[2])));  //计算cos
        BigDecimal sin = new BigDecimal(String.valueOf(Math.sin(four_para[2])));   //计算sin
        BigDecimal part1= cos.multiply(oldx);
        BigDecimal part2= oldy.multiply(sin);
        BigDecimal part3= part1.subtract(part2);
        BigDecimal part4= BigDecimal.valueOf(four_para[3]).multiply(part3);
        BigDecimal x= BigDecimal.valueOf(four_para[0]).add(part4);
        BigDecimal newX =x.setScale(6,BigDecimal.ROUND_HALF_DOWN);
        BigDecimal y = BigDecimal.valueOf(four_para[1]).add(BigDecimal.valueOf(four_para[3]).multiply(oldx.multiply(sin).add(oldy.multiply(cos))));
        BigDecimal newY = y.setScale(6,BigDecimal.ROUND_HALF_DOWN);
        System.out.print("newX:"+ newX+"\n"+"newY:"+ newY);
    }

    /*
    求逆函数
     */
    //求逆函数
    public static RealMatrix inverseMatrix(RealMatrix A) {
        RealMatrix result = new LUDecomposition(A).getSolver().getInverse();
        return result;
    }
    /*
    打印信息
     */
    private static void PrintMatrix(RealMatrix first,String part) {
        double [][] matrix = first.getData();
        for(int i = 0 ; i< matrix.length;i++){
            StringBuilder builder = new StringBuilder();
            for(int j = 0; j<matrix[0].length;j++){
                builder.append(matrix[i][j]).append(" + ");
            }
           System.out.print(part + builder.toString()+"\n");
        }
    }

    /*
    单位矩阵
     */
    private static double[][] formUnitMatrix(int dimen) {
        double [][]temp = new double[dimen][dimen];
        for(int i = 0;i< dimen ;i++){
            for(int j= 0;j< dimen;j++){
                if(i==j)
                    temp[i][j]=1;
                else
                    temp[i][j]=0;
            }
        }
        return temp;
    }

    private static void checkRegerx() {
        String test = "dz_2dc78";
        String regex = "(\\d+)";   //匹配数字
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(test);
        while (matcher.find()){
            int temp = Integer.valueOf(matcher.group(1))+1;
            System.out.println( temp);
            test = test.replace(matcher.group(),String.valueOf(temp));
            System.out.println( test);
        }
    }

}