1. 程式人生 > >GIS演算法基礎(四)平面座標變換(變換矩陣演算法實現)

GIS演算法基礎(四)平面座標變換(變換矩陣演算法實現)

目錄

一、平面直角座標系的建立

二、平面座標變換矩陣

三、平移變換

四、比例變換

五、對稱變換

六、旋轉變換

七、錯切變換

八、複合變換

(1)、複合平移

(2)複合比例變換

(3)複合旋轉

(4)相對某點的比例變換

(5)相對某點的選址變換


一、平面直角座標系的建立

平面座標系

在平面上選一點作為直角座標的原點,過該原點作相互垂直的兩軸,就建立起了平面直角座標系,如上圖所示。

在程式碼中,我們可以用一個類表示一個點實體,他由一串座標組成,但是,如果這些點如果位於不同的座標系中,該怎麼轉換呢?通過對X,Y的操作,比如平移就在相應的X,Y分量上加偏移量,我們就可以實現。那如果,我們既要平移,又要旋轉,或者一系列的對點實體的操作,該怎麼實現?這個時候就可以用到平面座標變換矩陣。

平面座標系

 

二、平面座標變換矩陣

  “變換矩陣是數學線性代數中的一個概念。線上性代數中,線性變換能夠用矩陣表示。如果T是一個把Rn對映到Rm的線性變換,且x是一個具有n個元素的列向量 ,那麼我們把m×n的矩陣A,稱為T的變換矩陣。”

                                                                                                                                     -------

百度百科-變換矩陣

 

其實沒有這麼複雜,就是我們通過對一個座標串構成的矩陣與某個矩陣相乘,得到的新矩陣包含了我們所要的座標的資訊。這個"某個矩陣"在這裡就是螢幕座標變換矩陣。

 

怎麼構建 矩陣吧,矩陣的構建可以用二維陣列實現。這個不是演算法的重點,所以我就不po程式碼了,想看程式碼可以到我的github上看

https://github.com/XiaoZhong233/GIS_ALG/blob/master/src/scau/gz/zhw/BasicTransform.java

平面座標變換矩陣可由下式表示:

    /**      
     *      |a d g|
     * T= |b e h|      |a d|                                                                                                             |g|
     *       |c f   i|      |b e| 負責對圖形的縮放,旋轉,對稱,錯切 。[c f] 負責對圖形進行平移變換    |h| 負責投影變換
     */    

構建程式碼:

public class SurfaceTransformationMatrix {
	
	private double a,b,c,d,e,f,g,h,i;
	private double[][]  data= {{a,d,g},{b,e,h},{c,f,i}};
	private Matrix matrix;
	
	public SurfaceTransformationMatrix() {
		this.matrix = new Matrix(data);
	}

	public SurfaceTransformationMatrix(double[][] data) {
		this.matrix = new Matrix(data);
	}
	
	public Matrix getMatrix() {
		return matrix;
	}
	
}

 

三、平移變換

公式如下:

平移變換矩陣

(m,n)是變換後的座標,(x,y)是變換前的座標,tx,ty分別對應x軸,y軸的偏移量

構建程式碼:

public class TransformMatrix extends SurfaceTransformationMatrix{
	
	private Matrix matrix;
	
	public TransformMatrix(double Tx,double Ty) {
		super(new double[][]{{1,0,0},{0,1,0},{Tx,Ty,1}});
		this.matrix = super.getMatrix();
	}
	
	public Matrix getTransformMatrix() {
		return matrix;
	}
	
	
}

 

平移演算法:

	/**
	 * 平移演算法
	 * @param point
	 * @param x	x正方向偏移量
	 * @param y	y正方向偏移量
	 * @return
	 */
	public static Point transform(Point point,double x,double y) {
		Matrix matrix = new TransformMatrix(x, y).getTransformMatrix();
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		//System.out.println("平移後的點 :"+new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]).toString());
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}
	
	public static Line transform(Line line,double x,double y) {
		Point start = line.getStart();
		Point end = line.getEnd();
		
		Point newStart = transform(start, x, y);
		Point newEnd = transform(end, x, y);
		return new Line(newStart,newEnd);
	}
	
	public static Polygon transform(Polygon polygon,double x,double y) {
		Point[] points = polygon.getPoints();
		Point[] result = new Point[points.length];
		for(int i=0;i<points.length;i++) {
			result[i]=transform(points[i], x, y);
			//System.out.println("result :"+result[i].toString());
		}
		return new Polygon(result, polygon.isClose());
	}

接下來的變換基本都和這個變換的例子差不多,無非是引數的變化

四、比例變換

變換公式:[x* y* 1] = [x y 1] x [{Sx,0,0},{0,Sy,0},{0,0,1}] = [Sx*x Sy*y 1]

因為公式沒找到圖,就用二維陣列來表示

x*,y*是x,y變換後的座標

變換關係如下

(1)當Sx = Sy = 1 時,為恆等比例變換,就是圖形不變

(2)當Sx = Sy > 1 時,圖形沿兩個座標軸方向等比例放大。

(3)當Sx = Sy < 1 時,圖形沿兩個座標軸方向等比例縮小。

(4)當Sx != Sy  時,圖形沿兩個座標軸方向做非均勻的比例變換。

 

構建程式碼:

public class ScaleMtrix extends SurfaceTransformationMatrix{
	private Matrix matrix;
	public ScaleMtrix(double Sx,double Sy) {
		// TODO Auto-generated constructor stub
		super(new double[][]{{Sx,0,0},{0,Sy,0},{0,0,1}});
		this.matrix = super.getMatrix();
	}
	
	public Matrix getScaleMatrix() {
		return matrix;
	}
}

演算法:

	/**
	 * 比例變換演算法
	 * x=y時,恆比例放大或縮小
	 * x!=y時,圖形沿兩個座標軸方向做非均勻比例變換
	 * @param point
	 * @param x 
	 * @param y
	 * @return
	 */
	public static Point scale(Point point,double x,double y) {
		Matrix matrix = new ScaleMtrix(x, y).getScaleMatrix();
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}
	
	public static Line scale(Line line,double x,double y) {
		Point start = line.getStart();
		Point end = line.getEnd();
		
		Point newStart = scale(start, x, y);
		Point newEnd = scale(end, x, y);
		return new Line(newStart,newEnd);
	}
	
	public static Polygon scale(Polygon polygon,double x,double y) {
		Point[] points = polygon.getPoints();
		Point[] result = new Point[points.length];
		for(int i=0;i<points.length;i++) {
			result[i]=scale(points[i], x, y);
			//System.out.println("result :"+result[i].toString());
		}
		return new Polygon(result, polygon.isClose());
	}

 

五、對稱變換

公式如下:

[x*,y*,1] = [x,y,1] x [{a,d,0},{b,e,0},{0,0,1}] = [ax+by dx+ey 1]

 

變換關係:

(1)當b=d=0,a=-1,e=1時,產生與y軸對稱的反射圖形

(2)當b=d=0,a=1,e=-1時,產生與x軸對稱的反射圖形

(3)當b=d=0,a=e=-1時,產生與原點對稱的反射圖形

(4)當b=d=1,a=e=0時,產生與直線y=x對稱的反射圖形

(5)當b=d=-1,a=e=0時,產生與直線y=-x對稱的反射圖形

 

構建程式碼:

/**
 * 對稱變換矩陣
 * @author Administrator
 *
 */
public class SymmetryMatrix extends SurfaceTransformationMatrix{
	private Matrix matrix;
	
	public SymmetryMatrix(double a,double b,double d,double e) {
		// TODO Auto-generated constructor stub
		super(new double[][] {{a,d,0},{b,e,0},{0,0,1}});
		this.matrix = super.getMatrix();
	}

	public Matrix getSymmetryMatrix() {
		return matrix;
	}
}

演算法:

	/**
	 * 對稱變換
	 * @param point
	 * @param symmetryType 列舉型別
	 * @return
	 */
	public static Point symmetry(Point point,SymmetryType symmetryType) {
		Matrix matrix;
		switch (symmetryType) {
		case xAxis:
			matrix = new SymmetryMatrix(1, 0, 0, -1).getSymmetryMatrix();
			break;
		case yAxis:
			matrix = new SymmetryMatrix(-1, 0, 0, 1).getSymmetryMatrix();
			break;
		case yx:
			matrix = new SymmetryMatrix(0, 1, 1, 0).getSymmetryMatrix();
			break;
		case anti_yx:
			matrix = new SymmetryMatrix(0, -1, -1, 0).getSymmetryMatrix();
			break;
		case origin:
			matrix = new SymmetryMatrix(-1, 0, 0, -1).getSymmetryMatrix();
		default:
			matrix = new SymmetryMatrix(-1, 0, 0, -1).getSymmetryMatrix();
			break;
		}
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}

 

六、旋轉變換

公式如下:

[x*,y*,1] =

[x,y,1] x [{cosa,sina,0},{-sina,cosa,0},{0,0,1}] = [xcosa-ysina xsina+ycosa 1]

a是二維圖形繞原點順時針旋轉a角。

構建程式碼:

public class RotateMatrix extends SurfaceTransformationMatrix{

	private Matrix matrix;
	
	public RotateMatrix(double angle) {
		// TODO Auto-generated constructor stub
		super(new double[][] {{Math.cos(Math.toRadians(angle)),Math.sin(Math.toRadians(angle)),0},
			{-Math.sin(Math.toRadians(angle)),Math.cos(Math.toRadians(angle)),0},
			{0,0,1}});
		this.matrix = super.getMatrix();
	}
	
	public Matrix getRotateMatrix() {
		return matrix;
	}
}

演算法:

	/**
	 * 旋轉變換
	 * @param point
	 * @param angle 角度制單位
	 * @return
	 */
	public static Point rotate(Point point,double angle) {
		Matrix matrix = new RotateMatrix(angle).getRotateMatrix();
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}

 

七、錯切變換

公式如下:

[x*,y*,1] = [x,y,1] * [{1,d,0},{b,1,0},{0,0,1}]  = [x+by,dx+y,1]

x*,y*為變換後的座標。

 

變換關係如下:

(1)當d=0時,x*=x+by,y*=y,此時圖形的y座標不變,x座標隨初值(x,y)及變換系數b而作線性變換;若b>0,則圖形沿+x方向做錯切位移;b<0圖形沿-x方向做錯切位移。

(2)當b=0時,x*=x,y*=dx+y,此時圖形的x座標不變,y座標隨初值(x,y)及變換系數d做線性變換;如d>0,則圖形沿+y方向作錯切變換;d<0時,圖形沿-y方向做錯切位移。

(3)當b!=0時,且d!=0時,x*=x+by,y*=dx+y,圖形沿x,y兩個方向錯切位移。

 

錯切變換圖

構建程式碼:

public class MiscutMatrix extends SurfaceTransformationMatrix{
	private Matrix matrix;
	
	public MiscutMatrix(double d,double b) {
		// TODO Auto-generated constructor stub
		super(new double[][] {{1,d,0},{b,1,0},{0,0,1}});
		this.matrix = super.getMatrix();
	}
	
	public Matrix getMiscutMatrix(){
		return matrix;
	}
}

演算法如下:

	/**
	 * 錯切變換
	 * @param point 
	 * @param b=0,y軸隨變換系數d變換  b>0,圖形沿+y方向做錯切變換,b<0,圖形沿-y方向做錯切變換 
	 * @param d=0,y軸隨變換系數b變換  b>0,圖形沿+x方向做錯切變換,b<0,圖形沿-x方向做錯切變換
	 * 		  b!=0 && d!=0時,x*=x+by y*=dx+y 圖形沿x,y兩個方向做錯切變換
	 * @return
	 */
	public static Point miscut(Point point,double b,double d) {
		Matrix matrix = new MiscutMatrix(b,d).getMiscutMatrix();
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}

 

八、複合變換

複合變換是指圖形做一次以上的幾何變換,變換結果是每次變換矩陣相乘。

 

(1)、複合平移

直接上程式碼吧,就直接幾個平移矩陣相乘

	/**
	 * 複合平移
	 * @param point
	 * @param matrixs
	 * @return
	 */
	public static Point complexTransform(Point point,TransformMatrix...matrixs) {
		int len = matrixs.length;
		Matrix matrix = matrixs[0].getTransformMatrix();
		
		for(int i=1;i<len;i++) {
			matrix = matrix.RightMultiMatrix(matrixs[i].getTransformMatrix());
		}
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}

 

(2)複合比例變換

	/**
	 * 複合比例變換
	 * @param point
	 * @param matrixs
	 * @return
	 */
	public static Point complexScale(Point point,ScaleMtrix...matrixs) {
		int len = matrixs.length;
		Matrix matrix = matrixs[0].getScaleMatrix();
		for(int i=1;i<len;i++) {
			matrix = matrix.RightMultiMatrix(matrixs[i].getScaleMatrix());
		}
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}

 

(3)複合旋轉

	/**
	 * 複合旋轉變換
	 * @param point
	 * @param matrixs
	 * @return
	 */
	public static Point complexRotate(Point point,RotateMatrix ...matrixs) {
		int len = matrixs.length;
		Matrix matrix = matrixs[0].getRotateMatrix();
		for(int i=1;i<len;i++) {
			matrix = matrix.RightMultiMatrix(matrixs[i].getRotateMatrix());
		}
		double [][] data= {{point.getX(),point.getY(),1}};
		Matrix pointMatrix = new Matrix(data);
		Matrix result = pointMatrix.RightMultiMatrix(matrix);
		return new Point(result.getMatrix()[0][0], result.getMatrix()[0][1]);
	}

 

比例,旋轉變換是與參考的有關的,上面的都是相對於原點的比例變換,如果要參考某個(m,n)點做比例 ,旋轉變換,其變換過程就是先把該座標系的原點移到(m,n)上來,然後做了旋轉或比例變換,然後再移回去。

(4)相對某點的比例變換

	/**
	 * 相對於某點的比例變換
	 * @param point 待變換的點
	 * @param center 相對點
	 * @param x
	 * @param y
	 * @return
	 */
	public static Point scaleAround(Point point,Point center,double x,double y) {
		TransformMatrix t1 = new TransformMatrix(-center.getX(), -center.getY());
		ScaleMtrix scaleMtrix = new ScaleMtrix(x, y);
		TransformMatrix t2 = new TransformMatrix(center.getX(), center.getY());
		return complexTransmit(point, t1,scaleMtrix,t2);
	}

(5)相對某點的選址變換

	/**
	 * 圍繞某點的旋轉變換
	 * @param point 待變換的點
	 * @param center 相對點
	 * @param angle
	 * @return
	 */
	public static Point rotateAround(Point point,Point center,double angle) {
		TransformMatrix t1 = new TransformMatrix(-center.getX(), -center.getY());
		RotateMatrix rotateMatrix = new RotateMatrix(angle);
		TransformMatrix t2 = new TransformMatrix(center.getX(), center.getY());
		return complexTransmit(point, t1,rotateMatrix,t2);
	}

 

最後 po上我github地址,有需要的同學可以看看

https://github.com/XiaoZhong233/GIS_ALG/blob/master/src/scau/gz/zhw/BasicTransform.java