Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/SedimentLoadFacet.java @ 5653:5231e6b849ce
issue1077: Handle overlapping measurement station ranges, refactored Generator,
Allow gaps in graph (not sorting, living with NaNs).
author | Felix Wolfsteller <felix.wolfsteller@intevation.de> |
---|---|
date | Thu, 11 Apr 2013 10:52:56 +0200 |
parents | 4feda81c38bc |
children | 5bb179d4fd5f |
comparison
equal
deleted
inserted
replaced
5652:2e420f65c5e0 | 5653:5231e6b849ce |
---|---|
1 package de.intevation.flys.artifacts.model.minfo; | 1 package de.intevation.flys.artifacts.model.minfo; |
2 | 2 |
3 import org.apache.log4j.Logger; | 3 import org.apache.log4j.Logger; |
4 | 4 |
5 import java.util.ArrayList; | 5 import java.util.ArrayList; |
6 import java.util.Arrays; | |
7 import java.util.Collections; | |
8 import java.util.Comparator; | |
6 import java.util.List; | 9 import java.util.List; |
10 import java.util.Map; | |
11 import java.util.TreeMap; | |
7 | 12 |
8 import de.intevation.artifactdatabase.state.Facet; | 13 import de.intevation.artifactdatabase.state.Facet; |
9 import de.intevation.artifacts.Artifact; | 14 import de.intevation.artifacts.Artifact; |
10 import de.intevation.artifacts.CallContext; | 15 import de.intevation.artifacts.CallContext; |
11 import de.intevation.flys.artifacts.FLYSArtifact; | 16 import de.intevation.flys.artifacts.FLYSArtifact; |
52 SedimentLoadResult result = data != null && data.length > index ? (SedimentLoadResult)data[index] : null; | 57 SedimentLoadResult result = data != null && data.length > index ? (SedimentLoadResult)data[index] : null; |
53 if (result == null) { | 58 if (result == null) { |
54 return null; | 59 return null; |
55 } | 60 } |
56 | 61 |
62 List<Double> sortedStarts = new ArrayList<Double>(); | |
57 // Filter stations according to type. | 63 // Filter stations according to type. |
58 List<MeasurementStation> stations = new ArrayList<MeasurementStation>(); | 64 List<MeasurementStation> stations = new ArrayList<MeasurementStation>(); |
59 for (MeasurementStation station: allStations) { | 65 for (MeasurementStation station: allStations) { |
60 if (station.getRange() == null || station.getMeasurementType() == null) { | 66 if (station.getRange() == null || station.getMeasurementType() == null) { |
61 continue; | 67 continue; |
62 } | 68 } |
63 if (FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) | 69 if (FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) |
64 && station.getMeasurementType().equals("Geschiebe")) | 70 && station.getMeasurementType().equals("Geschiebe")) { |
65 stations.add(station); | 71 stations.add(station); |
72 sortedStarts.add(station.getStation()); | |
73 } | |
66 else if (!FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) | 74 else if (!FacetTypes.IS.SEDIMENT_LOAD_NO_FLOAT(this.getName()) |
67 && station.getMeasurementType().equals("Schwebstoff")) | 75 && station.getMeasurementType().equals("Schwebstoff")) { |
68 stations.add(station); | 76 stations.add(station); |
77 sortedStarts.add(station.getStation()); | |
78 } | |
69 } | 79 } |
80 Collections.sort(sortedStarts); | |
70 | 81 |
71 // Access data according to type. | 82 // Access data according to type. |
72 double[][] sd = getLoadData(result); | 83 double[][] sd = getLoadData(result); |
73 | 84 |
85 // Sort by km. | |
86 TreeMap<Double, Double> sortData = new TreeMap<Double,Double>(); | |
87 | |
74 double[] km = sd[0]; | 88 double[] km = sd[0]; |
75 double[] load = sd[1]; | 89 double[] load = sd[1]; |
76 | 90 |
91 for (int i = 0 ; i < km.length; i++) { | |
92 sortData.put(km[i], load[i]); | |
93 } | |
94 | |
77 double[][] values = new double[2][]; | 95 double[][] values = new double[2][]; |
78 values[0] = new double[km.length*2]; | 96 values[0] = new double[km.length*3]; |
79 values[1] = new double[km.length*2]; | 97 values[1] = new double[km.length*3]; |
98 | |
99 List<double[]> kmWithoutStation = new ArrayList<double[]>(); | |
80 | 100 |
81 // Find station via its station (km). | 101 // Find station via its station (km). |
82 // TODO what to do with gaps in measurement stations. | 102 // TODO use a binarySearch instead of linear absdiff approach |
83 for (int i = 0; i < km.length; i++) { | 103 int i = 0; |
104 for (Map.Entry<Double, Double> entry: sortData.entrySet()) { | |
84 boolean matchFound = false; | 105 boolean matchFound = false; |
106 // For now, ignore overlaps like (B> next A) | |
85 for (MeasurementStation station: stations) { | 107 for (MeasurementStation station: stations) { |
86 if (Math.abs(station.getStation() - km[i]) < EPSILON) { | 108 if (Math.abs(station.getStation() - entry.getKey()) < EPSILON) { |
87 values[0][i*2] = station.getRange().getA().doubleValue(); | 109 values[0][i*3] = station.getRange().getA().doubleValue() + EPSILON; |
88 values[1][i*2] = load[i]; | 110 values[1][i*3] = entry.getValue(); |
89 values[0][i*2+1] = station.getRange().getB().doubleValue(); | 111 values[0][i*3+1] = station.getRange().getB().doubleValue() - EPSILON; |
90 values[1][i*2+1] = load[i]; | 112 values[1][i*3+1] = entry.getValue(); |
113 values[0][i*3+2] = station.getRange().getB().doubleValue(); | |
114 values[1][i*3+2] = entry.getValue(); | |
91 matchFound = true; | 115 matchFound = true; |
92 } | 116 } |
93 } | 117 } |
94 // For now, add point if no matching measurement station found. | 118 // Store points without match for later assessment. |
95 if (!matchFound) { | 119 if (!matchFound) { |
96 values[0][i*2] = km[i]; | 120 kmWithoutStation.add(new double[] {entry.getKey(), entry.getValue(), i}); |
97 values[1][i*2] = load[i]; | 121 } |
98 logger.debug("No measurement station for km " + km[i]); | 122 i++; |
123 } | |
124 | |
125 // Find fitting measurement stations for values without match. | |
126 for (double misses[]: kmWithoutStation) { | |
127 int idc = Math.abs(Collections.binarySearch(sortedStarts, misses[0])); | |
128 double locationA = sortedStarts.get(idc-2); | |
129 double locationB = sortedStarts.get(idc-1); | |
130 values[0][(int)misses[2]*3] = locationA + EPSILON; | |
131 values[1][(int)misses[2]*3] = misses[1]; | |
132 values[0][(int)misses[2]*3+1] = locationB - EPSILON; | |
133 values[1][(int)misses[2]*3+1] = misses[1]; | |
134 values[0][(int)misses[2]*3+2] = locationB ; | |
135 values[1][(int)misses[2]*3+2] = misses[1]; | |
136 } | |
137 | |
138 | |
139 for (int x = 0; x < values[0].length-1; x++) { | |
140 // Correct measurement stationo overlap. | |
141 if (values[0][x] > values[0][x+1]) { | |
142 values[0][x+1] = values[0][x] + EPSILON; | |
143 } | |
144 // Introduce gaps where no data in measurement station. | |
145 if (Math.abs(values[0][x+1] - values[0][x]) > 3*EPSILON | |
146 && values[1][x+1] != values[1][x]) { | |
147 values[0][x] = Double.NaN; | |
148 values[1][x] = Double.NaN; | |
99 } | 149 } |
100 } | 150 } |
151 | |
101 return values; | 152 return values; |
102 } | 153 } |
103 | 154 |
104 | 155 |
105 /** Get data according to type of facet. */ | 156 /** Get data according to type of facet. */ |