comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/FloodMapState.java @ 3814:8083f6384023

merged flys-artifacts/pre2.6-2012-01-04
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:56 +0200
parents 368040e5c400
children cbeeaaad1056
comparison
equal deleted inserted replaced
1491:2a00f4849738 3814:8083f6384023
1 package de.intevation.flys.artifacts.states;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import com.vividsolutions.jts.geom.Coordinate;
11 import com.vividsolutions.jts.geom.Geometry;
12 import com.vividsolutions.jts.geom.LineString;
13 import com.vividsolutions.jts.geom.Polygon;
14
15 import org.apache.log4j.Logger;
16
17 import org.opengis.feature.simple.SimpleFeature;
18 import org.opengis.feature.simple.SimpleFeatureType;
19
20 import org.geotools.feature.FeatureCollection;
21 import org.geotools.feature.FeatureCollections;
22 import org.geotools.feature.simple.SimpleFeatureBuilder;
23
24 import de.intevation.artifacts.Artifact;
25 import de.intevation.artifacts.CallContext;
26 import de.intevation.artifacts.GlobalContext;
27
28 import de.intevation.artifacts.common.utils.FileTools;
29
30 import de.intevation.artifactdatabase.state.Facet;
31
32 import de.intevation.flys.model.CrossSectionTrack;
33 import de.intevation.flys.model.DGM;
34 import de.intevation.flys.model.Floodplain;
35 import de.intevation.flys.model.RiverAxis;
36
37 import de.intevation.flys.artifacts.FLYSArtifact;
38 import de.intevation.flys.artifacts.context.FLYSContext;
39 import de.intevation.flys.artifacts.model.CalculationMessage;
40 import de.intevation.flys.artifacts.model.CalculationResult;
41 import de.intevation.flys.artifacts.model.FacetTypes;
42 import de.intevation.flys.artifacts.model.WQKms;
43 import de.intevation.flys.artifacts.model.WSPLGENCalculation;
44 import de.intevation.flys.artifacts.model.WSPLGENJob;
45 import de.intevation.flys.artifacts.model.WSPLGENReportFacet;
46 import de.intevation.flys.artifacts.resources.Resources;
47 import de.intevation.flys.artifacts.states.DefaultState.ComputeType;
48 import de.intevation.flys.exports.WstWriter;
49 import de.intevation.flys.utils.FLYSUtils;
50 import de.intevation.flys.utils.MapfileGenerator;
51 import de.intevation.flys.utils.GeometryUtils;
52 import de.intevation.flys.wsplgen.FacetCreator;
53 import de.intevation.flys.wsplgen.JobObserver;
54 import de.intevation.flys.wsplgen.Scheduler;
55
56
57 public class FloodMapState
58 extends DefaultState
59 implements FacetTypes
60 {
61 /** The logger that is used in this state. */
62 private static Logger logger = Logger.getLogger(FloodMapState.class);
63
64
65 public static final String KEEP_ARTIFACT_DIR =
66 System.getProperty("flys.uesk.keep.artifactsdir", "false");
67
68
69 public static final String WSP_ARTIFACT = "wsp";
70
71 public static final String WINFO_WSP_STATE_ID = "state.winfo.waterlevel";
72
73 public static final String WSPLGEN_PARAMETER_FILE = "wsplgen.par";
74 public static final String WSPLGEN_BARRIERS_LINES = "barrier_lines.shp";
75 public static final String WSPLGEN_BARRIERS_POLY = "barrier_polygons.shp";
76 public static final String WSPLGEN_AXIS = "axis.shp";
77 public static final String WSPLGEN_QPS = "qps.shp";
78 public static final String WSPLGEN_FLOODPLAIN = "talaue.shp";
79 public static final String WSPLGEN_WSP_FILE = "waterlevel.wst";
80 public static final String WSPLGEN_OUTPUT_FILE = "wsplgen.shp";
81
82 public static final int WSPLGEN_DEFAULT_OUTPUT = 0;
83
84
85
86 @Override
87 public Object computeAdvance(
88 FLYSArtifact artifact,
89 String hash,
90 CallContext context,
91 List<Facet> facets,
92 Object old
93 ) {
94 logger.debug("FloodMapState.computeAdvance");
95
96 File artifactDir = getDirectory(artifact);
97
98 if (artifactDir == null) {
99 logger.error("Could not create directory for WSPLGEN results!");
100 return null;
101 }
102
103 WSPLGENCalculation calculation = new WSPLGENCalculation();
104
105 FacetCreator facetCreator = new FacetCreator(
106 artifact, context, hash, getID(), facets);
107
108 WSPLGENJob job = prepareWSPLGENJob(
109 artifact,
110 facetCreator,
111 artifactDir,
112 context,
113 calculation);
114
115 CalculationResult res = new CalculationResult(null, calculation);
116 WSPLGENReportFacet report= new WSPLGENReportFacet(
117 ComputeType.ADVANCE, hash, getID(), res);
118
119 facets.add(report);
120
121 if (job == null) {
122 if (KEEP_ARTIFACT_DIR.equals("false")) {
123 removeDirectory(artifact);
124 }
125
126 calculation.addError(-1, Resources.getMsg(
127 context.getMeta(),
128 "wsplgen.job.error",
129 "wsplgen.job.error"));
130
131 logger.error("No WSPLGEN processing has been started!");
132
133 return null;
134 }
135
136 context.afterCall(CallContext.BACKGROUND);
137 context.addBackgroundMessage(new CalculationMessage(
138 JobObserver.STEPS.length,
139 0,
140 Resources.getMsg(
141 context.getMeta(),
142 "wsplgen.job.queued",
143 "wsplgen.job.queued")
144 ));
145
146 GlobalContext gc = (GlobalContext) context.globalContext();
147 Scheduler scheduler = (Scheduler) gc.get(FLYSContext.SCHEDULER);
148 scheduler.addJob(job);
149
150 return null;
151 }
152
153
154 /**
155 * Returns (and creates if not existing) the directory for storing WSPLEN
156 * data for the owner artifact.
157 *
158 * @param artifact The owner Artifact.
159 *
160 * @return the directory for WSPLEN data.
161 */
162 protected File getDirectory(FLYSArtifact artifact) {
163 String shapePath = FLYSUtils.getXPathString(
164 FLYSUtils.XPATH_SHAPEFILE_DIR);
165
166 File artifactDir = FileTools.getDirectory(
167 shapePath, artifact.identifier());
168
169 return artifactDir;
170 }
171
172
173 /**
174 * Removes the directory and all its content where the required data and the
175 * results of WSPLGEN are stored. Should be called in endOfLife().
176 */
177 protected void removeDirectory(FLYSArtifact artifact) {
178 String shapePath = FLYSUtils.getXPathString(
179 FLYSUtils.XPATH_SHAPEFILE_DIR);
180
181 File artifactDir = new File(shapePath, artifact.identifier());
182
183 if (artifactDir.exists()) {
184 logger.info("Delete directory: " + artifactDir.getAbsolutePath());
185 boolean success = FileTools.deleteRecursive(artifactDir);
186 }
187 else {
188 logger.debug("There is no directory to remove.");
189 }
190 }
191
192
193 @Override
194 public void endOfLife(Artifact artifact, Object callContext) {
195 logger.info("FloodMapState.endOfLife: " + artifact.identifier());
196
197 FLYSArtifact flys = (FLYSArtifact) artifact;
198 removeDirectory(flys);
199
200 Scheduler scheduler = Scheduler.getInstance();
201 scheduler.cancelJob(flys.identifier());
202
203 MapfileGenerator.getInstance().update();
204 }
205
206
207 protected WSPLGENJob prepareWSPLGENJob(
208 FLYSArtifact artifact,
209 FacetCreator facetCreator,
210 File artifactDir,
211 CallContext context,
212 WSPLGENCalculation calculation
213 ) {
214 logger.debug("FloodMapState.prepareWSPLGENJob");
215
216 WSPLGENJob job = new WSPLGENJob(
217 artifact,
218 artifactDir,
219 facetCreator,
220 context,
221 calculation);
222
223 File paraFile = new File(artifactDir, WSPLGEN_PARAMETER_FILE);
224
225 setOut(artifact, job);
226 setRange(artifact, job);
227 setDelta(artifact, job);
228 setGel(artifact, job);
229 setDist(artifact, job);
230 setLine(artifact, facetCreator, artifactDir, job);
231 setAxis(artifact, artifactDir, job);
232 setPro(artifact, artifactDir, job);
233 setDgm(artifact, job);
234 setArea(artifact, artifactDir, job);
235 setOutFile(artifact, job);
236 setWsp(artifact, context, artifactDir, job); // WSP
237
238 // TODO
239 // setWspTag(artifact, job);
240
241 try {
242 job.toFile(paraFile);
243
244 return job;
245 }
246 catch (IOException ioe) {
247 logger.warn("Cannot write PAR file: " + ioe.getMessage());
248 }
249 catch (IllegalArgumentException iae) {
250 logger.warn("Cannot write PAR file: " + iae.getMessage());
251 }
252
253 return null;
254 }
255
256
257 protected void setOut(FLYSArtifact artifact, WSPLGENJob job) {
258 job.setOut(WSPLGEN_DEFAULT_OUTPUT);
259 }
260
261
262 protected void setRange(FLYSArtifact artifact, WSPLGENJob job) {
263 double[] range = FLYSUtils.getKmRange(artifact);
264
265 job.setStart(range[0]);
266 job.setEnd(range[1]);
267 }
268
269
270 protected void setDelta(FLYSArtifact artifact, WSPLGENJob job) {
271 String from = artifact.getDataAsString("diff_from");
272 String to = artifact.getDataAsString("diff_to");
273 String diff = artifact.getDataAsString("diff_diff");
274
275 try {
276 job.setFrom(Double.parseDouble(from));
277 }
278 catch (NumberFormatException nfe) {
279 }
280
281 try {
282 job.setTo(Double.parseDouble(to));
283 }
284 catch (NumberFormatException nfe) {
285 }
286
287 try {
288 job.setDiff(Double.parseDouble(diff));
289 }
290 catch (NumberFormatException nfe) {
291 }
292 }
293
294
295 protected void setGel(FLYSArtifact artifact, WSPLGENJob job) {
296 String gel = artifact.getDataAsString("scenario");
297
298 logger.debug("Selected gel = '" + gel + "'");
299
300 if (gel == null || gel.length() == 0) {
301 job.setGel(WSPLGENJob.GEL_NOSPERRE);
302 }
303 else if (gel.equals("scenario.current")) {
304 job.setGel(WSPLGENJob.GEL_SPERRE);
305 }
306 else if (gel.equals("scenario.scenario")) {
307 job.setGel(WSPLGENJob.GEL_SPERRE);
308 }
309 else {
310 job.setGel(WSPLGENJob.GEL_NOSPERRE);
311 }
312 }
313
314
315 protected void setDist(FLYSArtifact artifact, WSPLGENJob job) {
316 String dist = artifact.getDataAsString("profile_distance");
317
318 try {
319 job.setDist(Double.parseDouble(dist));
320 }
321 catch (NumberFormatException nfe) {
322 // nothing to do here
323 }
324 }
325
326
327 protected void setLine(
328 FLYSArtifact artifact,
329 FacetCreator facetCreator,
330 File dir,
331 WSPLGENJob job
332 ) {
333 String geoJSON = artifact.getDataAsString("uesk.barriers");
334 String srid = FLYSUtils.getRiverSrid(artifact);
335 String srs = "EPSG:" + srid;
336
337 if (geoJSON == null || geoJSON.length() == 0) {
338 logger.debug("No barrier features in parameterization existing.");
339 return;
340 }
341
342 SimpleFeatureType ft = getBarriersFeatureType(
343 "barriers", srs, Geometry.class);
344
345 List<SimpleFeature> features = GeometryUtils.parseGeoJSON(geoJSON, ft);
346 if (features == null || features.size() == 0) {
347 logger.debug("No barrier features extracted.");
348 return;
349 }
350
351 FeatureCollection[] fcs = splitLinesAndPolygons(features);
352
353 File shapeLines = new File(dir, WSPLGEN_BARRIERS_LINES);
354 File shapePolys = new File(dir, WSPLGEN_BARRIERS_POLY);
355
356 Object[][] obj = new Object[][] {
357 new Object[] { "typ", String.class }
358 };
359
360 String scenario = job.getGel();
361
362 boolean l = GeometryUtils.writeShapefile(
363 shapeLines,
364 GeometryUtils.buildFeatureType("lines", srs, LineString.class, obj),
365 fcs[0]);
366
367 if (l) {
368 logger.debug(
369 "Successfully created barrier line shapefile. " +
370 "Write shapefile path into WSPLGEN job.");
371
372 if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) {
373 logger.debug("WSPLGEN will not use barrier features.");
374 }
375 else {
376 job.addLin(shapeLines.getAbsolutePath());
377 }
378 }
379
380 boolean p = GeometryUtils.writeShapefile(
381 shapePolys,
382 GeometryUtils.buildFeatureType("polygons", srs, Polygon.class, obj),
383 fcs[1]);
384
385 if (p) {
386 logger.debug(
387 "Successfully created barrier polygon shapefile. " +
388 "Write shapefile path into WSPLGEN job.");
389
390 if (scenario.equals(WSPLGENJob.GEL_NOSPERRE)) {
391 logger.debug("WSPLGEN will not use barrier features.");
392 }
393 else {
394 job.addLin(shapePolys.getAbsolutePath());
395 }
396 }
397
398 if (p || l) {
399 facetCreator.createBarrierFacet();
400 }
401 }
402
403
404 protected SimpleFeatureType getBarriersFeatureType(
405 String name,
406 String srs,
407 Class type
408 ) {
409 Object[][] attrs = new Object[3][];
410 attrs[0] = new Object[] { "typ", String.class };
411 attrs[1] = new Object[] { "elevation", Double.class };
412 attrs[2] = new Object[] { "mark.selected", Integer.class };
413
414 return GeometryUtils.buildFeatureType(name, srs, type, attrs);
415 }
416
417
418 protected FeatureCollection[] splitLinesAndPolygons(List<SimpleFeature> f) {
419 FeatureCollection lines = FeatureCollections.newCollection();
420 FeatureCollection polygons = FeatureCollections.newCollection();
421
422 for (SimpleFeature feature: f) {
423 Geometry geom = (Geometry) feature.getDefaultGeometry();
424
425
426 if (geom instanceof LineString) {
427 geom = applyElevationAttribute(feature, (LineString) geom);
428 lines.add(feature);
429 }
430 else if (geom instanceof Polygon) {
431 geom = applyElevationAttribute(feature, (Polygon) geom);
432 polygons.add(feature);
433 }
434 else {
435 logger.warn("Feature not supported: " + geom.getClass());
436 }
437 }
438
439 logger.debug("Found " + lines.size() + " barrier lines.");
440 logger.debug("Found " + polygons.size() + " barrier polygons.");
441
442 return new FeatureCollection[] { lines, polygons };
443 }
444
445
446 protected static Geometry applyElevationAttribute(
447 SimpleFeature feature,
448 Geometry geom
449 ) {
450 logger.debug("Apply elevations for: " + geom.getClass());
451
452 List<Double> elevations = extractElevations(feature);
453 int numPoints = geom.getNumPoints();
454 int numElevation = elevations.size();
455
456 String typ = (String) feature.getAttribute("typ");
457
458 if (numPoints > numElevation) {
459 logger.warn("More vertices in Geometry than elevations given.");
460 }
461
462 Coordinate[] c = geom.getCoordinates();
463 for (int i = 0; i < numPoints; i++) {
464 if (i < numElevation) {
465 c[i].z = elevations.get(i);
466 }
467 else if (typ != null && typ.equals("Graben")) {
468 c[i].z = -9999d;
469 }
470 else {
471 c[i].z = 9999d;
472 }
473 }
474
475 return geom;
476 }
477
478
479 protected static List<Double> extractElevations(SimpleFeature feature) {
480 String tmp = (String) feature.getAttribute("elevation");
481 String typ = (String) feature.getAttribute("typ");
482
483 String[] elevations = tmp == null ? null : tmp.split(" ");
484
485 int num = elevations != null ? elevations.length : 0;
486
487 List<Double> list = new ArrayList<Double>(num);
488
489 for (int i = 0; i < num; i++) {
490 try {
491 list.add(Double.parseDouble(elevations[i]));
492 }
493 catch (NumberFormatException nfe) {
494 logger.warn("Error while parsing elevation at pos: " + i);
495 if (typ != null && typ.equals("Graben")) {
496 list.add(new Double(-9999.0));
497 }
498 else {
499 list.add(new Double(9999.0));
500 }
501 }
502 }
503
504 return list;
505 }
506
507
508 protected void setAxis(FLYSArtifact artifact, File dir, WSPLGENJob job) {
509 String river = artifact.getDataAsString("river");
510 String srid = FLYSUtils.getRiverSrid(artifact);
511 String srs = "EPSG:" + srid;
512
513 RiverAxis axis = RiverAxis.getRiverAxis(river);
514 if (axis == null) {
515 logger.warn("Could not find river axis for: '" + river + "'");
516 return;
517 }
518
519 Geometry geom = axis.getGeom();
520
521 SimpleFeatureType ft = GeometryUtils.buildFeatureType(
522 "axis", srs, LineString.class);
523
524 SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
525 builder.add(geom);
526
527 FeatureCollection collection = FeatureCollections.newCollection();
528 collection.add(builder.buildFeature("0"));
529
530 File axisShape = new File(dir, WSPLGEN_AXIS);
531
532 boolean a = GeometryUtils.writeShapefile(
533 axisShape,
534 GeometryUtils.buildFeatureType("axis", srs, LineString.class),
535 collection);
536
537 if (a) {
538 job.setAxis(axisShape.getAbsolutePath());
539 }
540 }
541
542
543 protected void setPro(FLYSArtifact artifact, File dir, WSPLGENJob job) {
544 String river = artifact.getDataAsString("river");
545 String srid = FLYSUtils.getRiverSrid(artifact);
546 String srs = "EPSG:" + srid;
547
548 List<CrossSectionTrack> cst =
549 CrossSectionTrack.getCrossSectionTrack(river);
550
551 logger.debug("Found " + cst.size() + " CrossSectionTracks.");
552
553 Object[][] attrs = new Object[2][];
554 attrs[0] = new Object[] { "ELEVATION", Double.class };
555 attrs[1] = new Object[] { "KILOMETER", Double.class };
556
557 SimpleFeatureType ft = GeometryUtils.buildFeatureType(
558 "qps", srs, LineString.class, attrs);
559
560 SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
561 FeatureCollection collection = FeatureCollections.newCollection();
562
563 int i = 0;
564 for (CrossSectionTrack track: cst) {
565 builder.reset();
566 builder.add(track.getGeom());
567 builder.add(track.getZ().doubleValue());
568 builder.add(track.getKm().doubleValue());
569
570 collection.add(builder.buildFeature(String.valueOf(i++)));
571 }
572
573 File qpsShape = new File(dir, WSPLGEN_QPS);
574
575 boolean q = GeometryUtils.writeShapefile(
576 qpsShape,
577 GeometryUtils.buildFeatureType("qps", srs, LineString.class, attrs),
578 collection);
579
580 if (q) {
581 job.setPro(qpsShape.getAbsolutePath());
582 }
583 }
584
585
586 protected void setDgm(FLYSArtifact artifact, WSPLGENJob job) {
587 String dgm_id = artifact.getDataAsString("dgm");
588
589 int id = -1;
590 try {
591 id = Integer.parseInt(dgm_id);
592 }
593 catch (NumberFormatException nfe) { /* do nothing */ }
594
595 DGM dgm = DGM.getDGM(id);
596
597 if (dgm == null) {
598 logger.warn("Could not find specified DGM.");
599
600 return;
601 }
602
603 job.setDgm(dgm.getPath());
604 }
605
606
607 protected void setArea(FLYSArtifact artifact, File dir, WSPLGENJob job) {
608 String useFloodplain = artifact.getDataAsString("use_floodplain");
609 if (!Boolean.valueOf(useFloodplain)) {
610 logger.debug("WSPLGEN will not use floodplain.");
611 return;
612 }
613
614 String river = artifact.getDataAsString("river");
615 String srid = FLYSUtils.getRiverSrid(artifact);
616 String srs = "EPSG:" + srid;
617
618 Floodplain plain = Floodplain.getFloodplain(river);
619
620 SimpleFeatureType ft = GeometryUtils.buildFeatureType(
621 "talaue", srs, Polygon.class);
622
623 SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft);
624 builder.add(plain.getGeom());
625
626 FeatureCollection collection = FeatureCollections.newCollection();
627 collection.add(builder.buildFeature("0"));
628
629 File talaueShape = new File(dir, WSPLGEN_FLOODPLAIN);
630
631 boolean t = GeometryUtils.writeShapefile(
632 talaueShape,
633 GeometryUtils.buildFeatureType("talaue", srs, Polygon.class),
634 collection);
635
636 if (t) {
637 job.setArea(talaueShape.getAbsolutePath());
638 }
639 }
640
641
642 protected void setOutFile(FLYSArtifact artifact, WSPLGENJob job) {
643 job.setOutFile(WSPLGEN_OUTPUT_FILE);
644 }
645
646
647 protected WQKms getWQKms(FLYSArtifact flys, CallContext cc) {
648 String wspString = flys.getDataAsString(WSP_ARTIFACT);
649 String[] parts = wspString.split(";");
650
651 String otherArtifact = parts[0];
652
653 int idx = -1;
654 try {
655 idx = Integer.parseInt(parts[2]);
656 }
657 catch (NumberFormatException nfe) { /* do nothing */ }
658
659 FLYSArtifact src = otherArtifact != null
660 ? FLYSUtils.getArtifact(otherArtifact, cc)
661 : flys;
662
663 logger.debug("Use waterlevel provided by Artifact: " + src.identifier());
664
665 CalculationResult rawData = (CalculationResult) src.compute(
666 cc,
667 null,
668 WINFO_WSP_STATE_ID,
669 ComputeType.ADVANCE,
670 false);
671
672 WQKms[] wqkms = (WQKms[]) rawData.getData();
673
674 return wqkms == null || idx == -1 || idx >= wqkms.length
675 ? null
676 : wqkms[idx];
677 }
678
679
680 protected void setWsp(
681 FLYSArtifact artifact,
682 CallContext context,
683 File dir,
684 WSPLGENJob job)
685 {
686 logger.debug("FloodMapState.setWsp");
687
688 WQKms data = getWQKms(artifact, context);
689
690 if (data == null) {
691 logger.warn("No WST data found!");
692 return;
693 }
694
695 WstWriter writer = new WstWriter(1);
696
697 // TODO REMOVE job.setWspTag(...) This is only used until the user is
698 // able to select the WSP column himself!
699 boolean writeWspTag = true;
700
701 double[] buf = new double[4];
702 logger.debug("Add WST column: " + data.getName());
703 writer.addColumn(data.getName());
704
705 if (writeWspTag) {
706 job.setWspTag(data.getName());
707 writeWspTag = false;
708 }
709
710 for (int i = 0, num = data.size(); i < num; i++) {
711 data.get(i, buf);
712 writer.add(buf);
713 }
714
715 FileOutputStream fout = null;
716
717 try {
718 File wspFile = new File(dir, WSPLGEN_WSP_FILE);
719 fout = new FileOutputStream(wspFile);
720
721 writer.write(fout);
722
723 job.setWsp(wspFile.getAbsolutePath());
724 }
725 catch (FileNotFoundException fnfe) {
726 logger.warn("Error while writing wsp file: " + fnfe.getMessage());
727 }
728 finally {
729 if (fout != null) {
730 try {
731 fout.close();
732 }
733 catch (IOException ioe) { /* do nothing */ }
734 }
735 }
736 }
737 }
738 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org