svn-gvsig-desktop / trunk / extensions / extGeoreferencing / src / com / iver / cit / gvsig / GeoOperations.java @ 4840
History | View | Annotate | Download (9.67 KB)
1 | 3192 | nacho | package com.iver.cit.gvsig; |
---|---|---|---|
2 | |||
3 | 4840 | nacho | import java.awt.geom.Point2D; |
4 | 4830 | nacho | import java.io.BufferedOutputStream; |
5 | import java.io.DataOutputStream; |
||
6 | import java.io.File; |
||
7 | import java.io.FileOutputStream; |
||
8 | import java.io.IOException; |
||
9 | import java.util.zip.DataFormatException; |
||
10 | |||
11 | 3192 | nacho | import com.iver.cit.gvsig.fmap.layers.FLyrPoints; |
12 | 4804 | nacho | import com.iver.cit.gvsig.utils.AffineT; |
13 | import com.iver.cit.gvsig.utils.MathUtils; |
||
14 | import com.iver.cit.gvsig.utils.PointT; |
||
15 | 3192 | nacho | |
16 | /**
|
||
17 | * @author Nacho Brodin (brodin_ign@gva.es)
|
||
18 | */
|
||
19 | public class GeoOperations{ |
||
20 | |||
21 | 4830 | nacho | private FLyrPoints lyrPoints = null; |
22 | 4840 | nacho | private int order = 1; |
23 | private PointT[] src = null; |
||
24 | private PointT[] dst = null; |
||
25 | private AffineT affine = null; |
||
26 | |||
27 | /**
|
||
28 | * Constructor
|
||
29 | */
|
||
30 | 4830 | nacho | public GeoOperations(){}
|
31 | 3192 | nacho | |
32 | 4830 | nacho | /**
|
33 | 4840 | nacho | * Constructor. Crea las estructuras de puntos y calcula la transformaci?n af?n.
|
34 | * @param lyr
|
||
35 | 4830 | nacho | */
|
36 | 4840 | nacho | public GeoOperations(FLyrPoints lyr){
|
37 | 4830 | nacho | this.lyrPoints = lyr;
|
38 | 4840 | nacho | src = new PointT[lyr.getCountPoints()];
|
39 | dst = new PointT[lyr.getCountPoints()];
|
||
40 | int nPoint = 0; |
||
41 | 4830 | nacho | for(int i = 0; i<lyr.getCountPoints(); i++){ |
42 | 4840 | nacho | if(lyr.getPoint(i).active == true){ |
43 | src[nPoint] = new PointT();
|
||
44 | dst[nPoint] = new PointT();
|
||
45 | src[nPoint].setX(lyr.getPoint(i).pixelPoint.getX()); |
||
46 | src[nPoint].setY(lyr.getPoint(i).pixelPoint.getY()); |
||
47 | src[nPoint].setI(lyr.getCountPoints()); |
||
48 | dst[nPoint].setX(lyr.getPoint(i).mapPoint.getX()); |
||
49 | dst[nPoint].setY(lyr.getPoint(i).mapPoint.getY()); |
||
50 | dst[nPoint].setI(lyr.getCountPoints()); |
||
51 | nPoint++; |
||
52 | } |
||
53 | 4830 | nacho | } |
54 | |||
55 | if(lyr.getCountPoints() >= 3 * 10) |
||
56 | order = 3;
|
||
57 | else if(lyr.getCountPoints() >= 3 * 6) |
||
58 | order = 2;
|
||
59 | else
|
||
60 | order = 1;
|
||
61 | |||
62 | |||
63 | 4840 | nacho | affine = new AffineT();
|
64 | 4830 | nacho | |
65 | //Calcular la transformaci?n afin por m?nimos cuadrados
|
||
66 | affine = computeLeastSquaresAffine(affine, src, dst, order); |
||
67 | 4840 | nacho | } |
68 | |||
69 | /**
|
||
70 | * A partir de la transformaci?n af?n creada en el construtor
|
||
71 | * genera un fichero de georreferenciaci?n para la imagen.
|
||
72 | * @param lyr Capa de puntos
|
||
73 | * @param order Orden del sistema de ecuaciones
|
||
74 | * @param widthPx Ancho en pixeles de la imagen a georreferenciar
|
||
75 | * @param heightPx Alto en pixeles de la imagen a georreferenciar
|
||
76 | * @param file Nombre del fichero raster a georreferenciar
|
||
77 | */
|
||
78 | public void createWorldFile(int widthPx, int heightPx, String file){ |
||
79 | 4830 | nacho | try{
|
80 | File f = new File(file); |
||
81 | String nameWorldFile = f.getPath().substring(0, f.getPath().lastIndexOf(".")) + getExtensionWorldFile(file); |
||
82 | createWorldFile(affine, widthPx, heightPx, nameWorldFile); |
||
83 | }catch(IOException ex){ |
||
84 | System.err.println("Can't create WorldFile"); |
||
85 | } |
||
86 | 3192 | nacho | } |
87 | |||
88 | 4804 | nacho | /**
|
89 | 4840 | nacho | * A partir de la transformaci?n af?n calculada en el contructor
|
90 | * transforma los puntos pasados como par?metros.
|
||
91 | * @param lyr Capa de puntos
|
||
92 | * @param list Lista de puntos a transformar
|
||
93 | * @return Lista de puntos transformados
|
||
94 | */
|
||
95 | public Point2D[] transformPoints(Point2D[] list){ |
||
96 | Point2D[] result = new Point2D[list.length]; |
||
97 | for(int i = 0; i < list.length;i++){ |
||
98 | double[] pto = transformPoint((int)list[i].getX(), (int)list[i].getY(), affine); |
||
99 | result[i] = new Point2D.Double(pto[0], pto[1]); |
||
100 | } |
||
101 | return result;
|
||
102 | } |
||
103 | |||
104 | /**
|
||
105 | 4830 | nacho | * Crea un fichero de georreferenciaci?n (worldfile) a partir de la transformaci?n af?n. Para
|
106 | * esto necesita obtener las coordenadas reales de la coordenada en pixels (0,0) y calcular
|
||
107 | * el tama?o de pixel.
|
||
108 | * @param affine Transformaci?n
|
||
109 | * @param widthPx Ancho en pixeles de la imagen a georreferenciar
|
||
110 | * @param heightPx Alto en pixeles de la imagen a georreferenciar
|
||
111 | * @param nameWordlFile Nombre del fichero de georreferenciaci?n
|
||
112 | * @throws IOException
|
||
113 | */
|
||
114 | private void createWorldFile(AffineT affine, int widthPx, int heightPx, String nameWordlFile) throws IOException { |
||
115 | StringBuffer data = new StringBuffer(); |
||
116 | double[] min = transformPoint(0, 0, affine); |
||
117 | double[] max = transformPoint(widthPx, heightPx, affine); |
||
118 | File f = new File(nameWordlFile); |
||
119 | DataOutputStream dos = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(f)) ); |
||
120 | |||
121 | data.append((max[0] - min[0])/(widthPx - 1)+"\n"); |
||
122 | data.append("0.0\n");
|
||
123 | data.append("0.0\n");
|
||
124 | data.append((max[1] - min[1])/(heightPx - 1)+"\n"); |
||
125 | data.append(""+min[0]+"\n"); |
||
126 | data.append(""+min[1]+"\n"); |
||
127 | |||
128 | dos.writeBytes(data.toString()); |
||
129 | dos.close(); |
||
130 | } |
||
131 | |||
132 | /**
|
||
133 | * Obtiene la extensi?n del fichero de georreferenciaci?n
|
||
134 | * @return String con la extensi?n del fichero de georreferenciaci?n dependiendo
|
||
135 | * del valor del formato obtenido del servidor. Por defecto asignaremos un .wld
|
||
136 | */
|
||
137 | private String getExtensionWorldFile(String file){ |
||
138 | String ext = file.substring(file.lastIndexOf(".") + 1); |
||
139 | String extWorldFile = ".wld"; |
||
140 | if(ext.equals("tif") || ext.equals("tiff")) |
||
141 | extWorldFile = ".tfw";
|
||
142 | if(ext.equals("jpeg") || ext.equals("jpg")) |
||
143 | extWorldFile = ".jpgw";
|
||
144 | return extWorldFile;
|
||
145 | } |
||
146 | |||
147 | /**
|
||
148 | 4804 | nacho | * Calcula la transformaci?n af?n a partir de los puntos introducidos por m?nimos cuadrados.
|
149 | * @param af Transformaci?n af?n
|
||
150 | * @param src Puntos de entrada en coordenadas pixel
|
||
151 | * @param dst Puntos de destino en coordenadas del mundo
|
||
152 | * @param order Orden del sistema de ecuaciones
|
||
153 | */
|
||
154 | 4830 | nacho | public AffineT computeLeastSquaresAffine(AffineT af, PointT[] src, PointT[] dst, int order){ |
155 | 4804 | nacho | double[] b = new double[dst.length]; |
156 | int i,cofs;
|
||
157 | |||
158 | af.setOrder(order); |
||
159 | cofs = order <= 2 ? order*3 : 10; |
||
160 | af.mallocCofs(cofs); |
||
161 | |||
162 | //First compute the X cofs
|
||
163 | for(i = 0; i < dst.length; i++) { |
||
164 | b[i] = dst[i].getX(); |
||
165 | } |
||
166 | |||
167 | 4830 | nacho | af.setCofX(singleLeastSquaresAffine(af.getXcofs(), src, b, order)); |
168 | 4804 | nacho | |
169 | //Now compute the Y cofs
|
||
170 | for(i = 0; i < dst.length; i++) { |
||
171 | b[i] = dst[i].getY(); |
||
172 | 4830 | nacho | } |
173 | |||
174 | af.setCofY(singleLeastSquaresAffine(af.getYcofs(), src, b, order)); |
||
175 | |||
176 | return af;
|
||
177 | 4804 | nacho | } |
178 | 3192 | nacho | |
179 | 4830 | nacho | private double[] singleLeastSquaresAffine(double[] a, PointT[] src, double[] dst, int order){ |
180 | 4804 | nacho | int i,j;
|
181 | int n = dst.length;
|
||
182 | |||
183 | 4830 | nacho | int points = order <= 2 ? order * 3 : 10; |
184 | double[][] combined = new double[points][points + 1]; |
||
185 | double[][] A = new double[n + 1][points]; |
||
186 | double[][] b = new double[n + 1][1]; |
||
187 | |||
188 | 4804 | nacho | for(i = 0; i < n; i++) { |
189 | A[i][0] = 1.0; |
||
190 | A[i][1] = src[i].getX();
|
||
191 | A[i][2] = src[i].getY();
|
||
192 | if(order > 1) { |
||
193 | A[i][3] = src[i].getX() * src[i].getX();
|
||
194 | A[i][4] = src[i].getX() * src[i].getY();
|
||
195 | A[i][5] = src[i].getY() * src[i].getY();
|
||
196 | } |
||
197 | if(order > 2) { |
||
198 | A[i][6] = src[i].getX() * src[i].getX() * src[i].getX();
|
||
199 | A[i][7] = src[i].getX() * src[i].getX() * src[i].getY();
|
||
200 | A[i][8] = src[i].getX() * src[i].getY() * src[i].getY();
|
||
201 | A[i][9] = src[i].getY() * src[i].getY() * src[i].getY();
|
||
202 | } |
||
203 | b[i][0] = dst[i];
|
||
204 | } |
||
205 | |||
206 | 4830 | nacho | double[][] Atrans = MathUtils.transpose(A, n, points); |
207 | double[][] left = MathUtils.multmatrix(Atrans,A,points,n,points); |
||
208 | double[][] right = MathUtils.multmatrix(Atrans,b,points,n,1); |
||
209 | |||
210 | 4804 | nacho | for(i = 0; i < points; i++) { |
211 | combined[i][0] = right[i][0]; |
||
212 | for(j = 0; j < points; j++) { |
||
213 | combined[i][j+1] = left[i][j];
|
||
214 | } |
||
215 | } |
||
216 | 4830 | nacho | |
217 | try{
|
||
218 | combined = solve(combined, points, points+1);
|
||
219 | }catch(DataFormatException ex){ |
||
220 | System.err.println("Can't solve matrix"); |
||
221 | } |
||
222 | 4804 | nacho | |
223 | 4830 | nacho | for(i = 0; i < points; i++) { |
224 | a[i] = combined[i][0];
|
||
225 | } |
||
226 | return a;
|
||
227 | } |
||
228 | |||
229 | |||
230 | private double[][] solve(double[][] mat,int rows,int cols)throws DataFormatException{ |
||
231 | int i,j,k;
|
||
232 | double d,tmp;
|
||
233 | int big;
|
||
234 | 4804 | nacho | |
235 | 4830 | nacho | for(i = 0; i < rows; i++) { |
236 | // Find largest row
|
||
237 | big = i; |
||
238 | for(j = i; j < rows; j++) {
|
||
239 | if(Math.abs(mat[j][i+1]) > Math.abs(mat[big][i+1])) { |
||
240 | big = j; |
||
241 | } |
||
242 | } |
||
243 | // swap row i and row big
|
||
244 | for(k = 0; k < cols ; k++) { |
||
245 | tmp = mat[i][k]; |
||
246 | mat[i][k] = mat[big][k]; |
||
247 | mat[big][k] = tmp; |
||
248 | } |
||
249 | if(mat[i][i+1] == 0) |
||
250 | throw new DataFormatException(); |
||
251 | |||
252 | d = 1.0 / mat[i][i+1]; |
||
253 | for(j = 0; j < cols ; j++) { |
||
254 | mat[i][j] *= d; |
||
255 | //assert(!isnan(mat[i][j]));
|
||
256 | } |
||
257 | for(k = 0; k < rows; k++) { |
||
258 | if(k == i)
|
||
259 | continue;
|
||
260 | if(mat[k][i+1] != 0.0) { |
||
261 | d = mat[k][i+1] / mat[i][i+1]; |
||
262 | for(j = 0; j < cols ; j++) { |
||
263 | mat[k][j] -= d*mat[i][j]; |
||
264 | //assert(!isnan(mat[k][j]));
|
||
265 | } |
||
266 | } |
||
267 | } |
||
268 | } |
||
269 | return mat;
|
||
270 | 4804 | nacho | } |
271 | |||
272 | 4830 | nacho | /**
|
273 | * Obtiene las coordenadas de un punto en coordenadas del mundo a partir de una transformaci?n
|
||
274 | * y el punto de entrada en coordenadas de la imagen.
|
||
275 | * @param sx Coordenada X del punto de entrada
|
||
276 | * @param syz Coordenada Y del punto de entrada
|
||
277 | * @param af Transformaci?n
|
||
278 | * @return Punto transformado
|
||
279 | */
|
||
280 | public double[] transformPoint(int sx, int sy, AffineT af){ |
||
281 | double[] p = new double[2]; |
||
282 | if(af.getOrder() == 1) { |
||
283 | p[0] = af.getCofX(0) + af.getCofX(1) * sx + af.getCofX(2) * sy; |
||
284 | p[1] = af.getCofY(0) + af.getCofY(1) * sx + af.getCofY(2) * sy; |
||
285 | } |
||
286 | else if(af.getOrder() == 2) { |
||
287 | p = quadTransformPoint(sx, sy, af); |
||
288 | } |
||
289 | else {
|
||
290 | p = cubicTransformPoint(sx, sy, af); |
||
291 | } |
||
292 | return p;
|
||
293 | } |
||
294 | 4804 | nacho | |
295 | 4830 | nacho | private static double[] quadTransformPoint(int sx, int sy, AffineT af){ |
296 | double[] p = new double[2]; |
||
297 | p[0] = af.getCofX(0) + af.getCofX(1) * sx + af.getCofX(2) * sy + |
||
298 | af.getCofX(3) * sx * sx + af.getCofX(4) * sx * sy + af.getCofX(5) * sy * sy; |
||
299 | p[1] = af.getCofY(0) + af.getCofY(1) * sx + af.getCofY(2) * sy + |
||
300 | af.getCofY(3) * sx * sx + af.getCofY(4) * sx * sy + af.getCofY(5) * sy * sy; |
||
301 | return p;
|
||
302 | } |
||
303 | |||
304 | private static double[] cubicTransformPoint(int sx, int sy, AffineT af){ |
||
305 | double[] p = new double[2]; |
||
306 | p[0] = af.getCofX(0) + af.getCofX(1) * sx + af.getCofX(2) * sy + |
||
307 | af.getCofX(3) * sx * sx + af.getCofX(4) * sx * sy + af.getCofX(5) * sy * sy + |
||
308 | af.getCofX(6) * sx * sx * sx + af.getCofX(7) * sx * sx * sy + |
||
309 | af.getCofX(8)*sx*sy*sy + af.getCofX(9)*sy*sy*sy; |
||
310 | p[1] = af.getCofY(0) + af.getCofY(1) * sx + af.getCofY(2) * sy + |
||
311 | af.getCofY(3) * sx * sx + af.getCofY(4) * sx * sy + af.getCofY(5) * sy * sy + |
||
312 | af.getCofY(6) * sx * sx * sx + af.getCofY(7) * sx * sx * sy + |
||
313 | af.getCofY(8) * sx * sy * sy + af.getCofY(9) * sy * sy * sy; |
||
314 | return p;
|
||
315 | } |
||
316 | 3192 | nacho | } |