comparison gnv-artifacts/src/main/java/de/intevation/gnv/utils/WKTUtils.java @ 657:af3f56758f59

merged gnv-artifacts/0.5
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:13:53 +0200
parents 4e347624ee7c
children 0563389138bb
comparison
equal deleted inserted replaced
590:5f5f273c8566 657:af3f56758f59
1 package de.intevation.gnv.utils;
2
3 import com.vividsolutions.jts.geom.Coordinate;
4 import com.vividsolutions.jts.geom.LineString;
5 import com.vividsolutions.jts.geom.Point;
6 import com.vividsolutions.jts.geom.Polygon;
7
8 import com.vividsolutions.jts.io.ParseException;
9 import com.vividsolutions.jts.io.WKTReader;
10
11 import de.intevation.gnv.artifacts.ressource.RessourceFactory;
12
13 import de.intevation.gnv.geobackend.base.Result;
14
15 import de.intevation.gnv.geobackend.base.query.QueryExecutor;
16 import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
17
18 import de.intevation.gnv.geobackend.base.query.exception.QueryException;
19
20 import de.intevation.gnv.math.LinearFunction;
21
22 import java.text.MessageFormat;
23 import java.text.NumberFormat;
24
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.Locale;
29
30 import org.apache.commons.math.FunctionEvaluationException;
31
32 import org.apache.commons.math.optimization.OptimizationException;
33
34 import org.apache.commons.math.optimization.fitting.CurveFitter;
35
36 import org.apache.commons.math.optimization.general.GaussNewtonOptimizer;
37
38 import org.apache.log4j.Logger;
39
40 public abstract class WKTUtils {
41
42 private static Logger log = Logger.getLogger(WKTUtils.class);
43
44 public static final double NAUTICAL_MILE = 1852.216d;
45 public static final double KILOMETER = 1000d;
46
47 public static final String I_NAME = "MEDIAN.MESHPOINT.IPOSITION";
48 public static final String J_NAME = "MEDIAN.MESHPOINT.JPOSITION";
49
50 public static final String TRUE_EXPRESSION = "FEATUREID=FEATUREID";
51
52 public static final String[] COORDINATE_OUT_FORMAT = {
53 "coordinate.template.northeast",
54 "coordinate.template.southeast",
55 "coordinate.template.northwest",
56 "coordinate.template.southwest"
57 };
58
59 public static final String DEFAULT_COORDINATE_TEMPLATE =
60 "{0}\u00b0N {1}'' {2}\u00b0E {3}''";
61
62 public static boolean different(Result a, Result b, int [] indices) {
63 for (int i = 0; i < indices.length; ++i) {
64 String oa = a.getString(indices[i]);
65 String ob = b.getString(indices[i]);
66
67 if (oa == null && ob == null) {
68 continue;
69 }
70
71 if (oa == null || ob == null) {
72 return true;
73 }
74
75 if (!oa.equals(ob)) {
76 return true;
77 }
78 }
79 return false;
80 }
81
82 public static Coordinate toCoordinate(String shape) {
83 try {
84 return shape != null
85 ? ((Point)(new WKTReader().read(shape))).getCoordinate()
86 : null;
87 }
88 catch (ParseException pe) {
89 log.error(pe);
90 }
91 catch (ClassCastException cce) {
92 log.error("cannot read WKT point", cce);
93 }
94 return null;
95 }
96
97 public static Polygon toPolygon(String shape) {
98 try {
99 return (Polygon)new WKTReader().read(shape);
100 }
101 catch (ParseException pe) {
102 log.error(pe);
103 }
104 catch (ClassCastException cce) {
105 log.error("cannot read WKT polygon", cce);
106 }
107 return null;
108 }
109
110 public static final double toKM(double distance) {
111 return (distance * NAUTICAL_MILE) / KILOMETER;
112 }
113
114
115 public static String toWKT(Coordinate coordinate) {
116 StringBuilder sb = new StringBuilder("POINT(");
117 sb.append(coordinate.x)
118 .append(' ')
119 .append(coordinate.y)
120 .append(')');
121 return sb.toString();
122 }
123
124 public static final String indexBox(
125 java.awt.Point a,
126 java.awt.Point b,
127 String iName,
128 String jName
129 ) {
130 int minI = Math.min(a.x, b.x) - 1;
131 int maxI = Math.max(a.x, b.x) + 1;
132 int minJ = Math.min(a.y, b.y) - 1;
133 int maxJ = Math.max(a.y, b.y) + 1;
134 StringBuilder sb = new StringBuilder("(")
135 .append(iName).append(" >= ").append(minI)
136 .append(" AND ").append(iName).append(" <= ").append(maxI)
137 .append(" AND ").append(jName).append(" >= ").append(minJ)
138 .append(" AND ").append(jName).append(" <= ").append(maxJ)
139 .append(')');
140 return sb.toString();
141 }
142
143 public static final String diagonalBox(List<java.awt.Point> points) {
144
145 if (points.get(0) != null && points.get(2) != null) {
146 return indexBox(
147 points.get(0), points.get(2),
148 I_NAME,
149 J_NAME);
150 }
151
152 if (points.get(1) != null && points.get(3) != null) {
153 return indexBox(
154 points.get(1), points.get(3),
155 I_NAME,
156 J_NAME);
157 }
158
159 return null;
160 }
161
162 public static String worldEnvelopeCoordinatesToIndex(
163 Coordinate [] coords,
164 String meshid,
165 String ijkQueryID
166 )
167 throws QueryException
168 {
169 List<java.awt.Point> points =
170 new ArrayList<java.awt.Point>(coords.length);
171
172 ArrayList<Object []> missingPoints =
173 new ArrayList<Object []>();
174
175 createIJKPoints(coords, meshid, ijkQueryID, points, missingPoints);
176
177 String additionWhere = null;
178
179 if (missingPoints.size() == coords.length) {
180 log.debug("cannot create index buffer");
181 }
182 else {
183 additionWhere = diagonalBox(points);
184
185 if (additionWhere == null) {
186 // 3 Points are missing or are on one side of the envelope
187 boolean remainsMissingPoints = calculateIJ4MissingPoints(
188 coords, points, missingPoints);
189
190 if (!remainsMissingPoints) {
191 additionWhere = diagonalBox(points);
192 }
193 }
194 }
195
196 return additionWhere != null
197 ? additionWhere
198 : TRUE_EXPRESSION;
199 }
200
201 public static String worldCoordinatesToIndex(
202 Coordinate [] coords,
203 Collection<Result> result,
204 String meshid,
205 String ijkQueryID
206 )
207 throws QueryException
208 {
209 List<java.awt.Point> points = new ArrayList<java.awt.Point>(coords.length);
210
211 ArrayList<Object []> missingPoints = new ArrayList<Object []>();
212
213 createIJKPoints(coords, meshid, ijkQueryID, points, missingPoints);
214
215 String additionWhere = TRUE_EXPRESSION;
216
217 if (missingPoints.size() == coords.length) {
218 log.debug("cannot create index buffer");
219 }
220 else { // generate index filter
221 boolean remainsMissingPoints = calculateIJ4MissingPoints(
222 coords, points, missingPoints);
223
224 if (!remainsMissingPoints) {
225 // TODO: Make Tablenames and Columns Configurable
226 IndexBuffer ib = new IndexBuffer(
227 points,
228 I_NAME,
229 J_NAME );
230 additionWhere = ib.toWhereClause();
231 log.debug("Additional Where Clause = "+additionWhere);
232 }
233 } // if generate index filter
234
235 return additionWhere;
236 }
237
238
239 /**
240 * @param coords
241 * @param points
242 * @param missingPoints
243 * @return
244 */
245 private static boolean calculateIJ4MissingPoints(
246 Coordinate [] coords,
247 List<java.awt.Point> points,
248 ArrayList<Object[]> missingPoints
249 ) {
250 boolean remainsMissingPoints = !missingPoints.isEmpty();
251
252 if (remainsMissingPoints) {
253 // try to guess the missing (i, j)
254 CurveFitter iFitter = new CurveFitter(new GaussNewtonOptimizer(true));
255 CurveFitter jFitter = new CurveFitter(new GaussNewtonOptimizer(true));
256
257 for (int i = 0, N = points.size(); i < N; ++i) {
258 java.awt.Point p = (java.awt.Point)points.get(i);
259 if (p != null) {
260 Coordinate coord = coords[i];
261 iFitter.addObservedPoint(coord.x, p.x);
262 jFitter.addObservedPoint(coord.y, p.y);
263 }
264 }
265 try {
266 // XXX: Assumption: (i, j) are created by componentwise linear function.
267 // This is surely not correct because (x, y) are in a ellipsoid projection.
268 // TODO: use ellipsoid functions and fit with Levenberg Marquardt.
269 double [] iParams = iFitter.fit(
270 LinearFunction.INSTANCE, new double [] { 1d, 1d });
271
272 double [] jParams = jFitter.fit(
273 LinearFunction.INSTANCE, new double [] { 1d, 1d });
274
275 for (int i = missingPoints.size()-1; i >= 0; --i) {
276 Object [] a = (Object [])missingPoints.get(i);
277 Coordinate coord = (Coordinate)a[1];
278 int pi = (int)Math.round(iParams[0]*coord.x + iParams[1]);
279 int pj = (int)Math.round(jParams[0]*coord.y + jParams[1]);
280 points.set(
281 ((Integer)a[0]).intValue(),
282 new java.awt.Point(pi, pj));
283 }
284
285 remainsMissingPoints = false; // we filled the gaps
286 }
287 catch (FunctionEvaluationException fee) {
288 log.error(fee);
289 }
290 catch (OptimizationException oe) {
291 log.error(oe);
292 }
293 }
294 return remainsMissingPoints;
295 }
296
297
298 /**
299 * @param coords
300 * @param meshid
301 * @param ijkQueryID
302 * @param points
303 * @param missingPoints
304 * @throws QueryException
305 */
306 private static void createIJKPoints(
307 Coordinate[] coords,
308 String meshid,
309 String ijkQueryID,
310 List<java.awt.Point> points,
311 ArrayList<Object []> missingPoints
312 )
313 throws QueryException
314 {
315 boolean debug = log.isDebugEnabled();
316
317 QueryExecutor queryExecutor = QueryExecutorFactory
318 .getInstance()
319 .getQueryExecutor();
320
321 for (int i = 0; i < coords.length; i++) {
322
323 String wkt = toWKT(coords[i]);
324
325 Collection<Result> result = queryExecutor.executeQuery(
326 ijkQueryID,
327 new String [] {meshid, wkt});
328
329 if (!result.isEmpty()) {
330 Result resultValue = result.iterator().next();
331 int iPos = resultValue.getInteger(1);
332 int jPos = resultValue.getInteger(0);
333 if (debug) {
334 log.debug("Found Pos "+iPos+"/"+jPos +" for "+wkt);
335 }
336 points.add(i, new java.awt.Point(iPos,jPos));
337 }
338 else {
339 if (debug) {
340 log.debug("No i/j Pos found for "+wkt);
341 }
342 missingPoints.add(new Object [] { Integer.valueOf(i), coords[i] });
343 points.add(i, null);
344 // Special Case no i,j found for Coordinate
345 }
346 }
347 }
348
349 public static Coordinate [] toCoordinates(String wkt) {
350 try {
351 LineString ls = (LineString)new WKTReader().read(wkt);
352 return ls.getCoordinates();
353 }
354 catch (ParseException pe) {
355 log.error("cannot read WKT line string", pe);
356 }
357 catch (ClassCastException cce) {
358 log.error("cannot read WKT line string", cce);
359 }
360 return null;
361 }
362
363 public static String toText(String wkt) {
364 return toText(Locale.getDefault(), wkt);
365 }
366
367 public static String toText(Locale locale, String wkt) {
368 String formattedCoordinate = null;
369 try {
370 Point p = (Point)new WKTReader().read(wkt);
371 double lat = p.getY();
372 double lon =p.getX();
373
374 int choice = 0;
375
376 if (lat <0 ) {
377 choice += 1;
378 lat=-lat;
379 }
380
381 if (lon <0 ) {
382 choice += 2;
383 lon=-lon;
384 }
385
386 RessourceFactory factory = RessourceFactory.getInstance();
387 String template = factory.getRessource(
388 locale,
389 COORDINATE_OUT_FORMAT[choice],
390 DEFAULT_COORDINATE_TEMPLATE
391 );
392
393 NumberFormat minFormatter = NumberFormat.getInstance(locale);
394 minFormatter.setMaximumFractionDigits(3);
395 minFormatter.setMinimumFractionDigits(3);
396
397 String minLat = minFormatter.format(60.*(lat-((int)lat)));
398 String minLon = minFormatter.format(60.*(lon-((int)lon)));
399
400 NumberFormat degFormatter = NumberFormat.getInstance(locale);
401 degFormatter.setMinimumIntegerDigits(2);
402
403 String formLat = degFormatter.format((int)lat);
404 String formLon = degFormatter.format((int)lon);
405
406 MessageFormat formatter = new MessageFormat(template);
407
408 Object[] args = {
409 formLat, minLat,
410 formLon, minLon
411 };
412
413 return formatter.format(args);
414
415 }
416 catch (ParseException e) {
417 log.warn(e,e);
418 }
419
420 return null;
421 }
422 }

http://dive4elements.wald.intevation.org