Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation3D.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 | 44415ae01ddb |
children | 9a828e5a2390 |
comparison
equal
deleted
inserted
replaced
590:5f5f273c8566 | 657:af3f56758f59 |
---|---|
1 package de.intevation.gnv.math; | |
2 | |
3 import com.vividsolutions.jts.geom.Coordinate; | |
4 import com.vividsolutions.jts.geom.Envelope; | |
5 | |
6 import com.vividsolutions.jts.index.strtree.STRtree; | |
7 | |
8 import java.awt.Dimension; | |
9 | |
10 import java.io.Serializable; | |
11 | |
12 import java.util.Arrays; | |
13 import java.util.List; | |
14 | |
15 import org.apache.log4j.Logger; | |
16 | |
17 /** | |
18 * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) | |
19 */ | |
20 public class Interpolation3D | |
21 implements Serializable | |
22 { | |
23 private static Logger log = Logger.getLogger(Interpolation3D.class); | |
24 | |
25 public static final int DEFAULT_WIDTH = 1024; | |
26 public static final int DEFAULT_HEIGHT = 768; | |
27 | |
28 public static final double EPS = 1e-6d; | |
29 | |
30 protected int width; | |
31 protected int height; | |
32 | |
33 protected double cellWidth; | |
34 protected double cellHeight; | |
35 | |
36 protected double [] raster; | |
37 protected double [] depths; | |
38 | |
39 public Interpolation3D() { | |
40 this(DEFAULT_WIDTH, DEFAULT_HEIGHT); | |
41 } | |
42 | |
43 public Interpolation3D(Dimension size) { | |
44 this(size.width, size.height); | |
45 } | |
46 | |
47 public Interpolation3D(int width, int height) { | |
48 this.width = width; | |
49 this.height = height; | |
50 } | |
51 | |
52 public int getHeight() { | |
53 return height; | |
54 } | |
55 | |
56 public int getWidth() { | |
57 return width; | |
58 } | |
59 | |
60 public double getCellWidth() { | |
61 return cellWidth; | |
62 } | |
63 | |
64 public double getCellHeight() { | |
65 return cellHeight; | |
66 } | |
67 | |
68 public double [] getRaster() { | |
69 return raster; | |
70 } | |
71 | |
72 public double [] getDepths() { | |
73 return depths; | |
74 } | |
75 | |
76 public double getMaxDepth() { | |
77 double maxDepth = Double.MAX_VALUE; | |
78 for (int i = depths!=null?depths.length-1:0; i >= 0; --i) { | |
79 double d = depths[i]; | |
80 if (!Double.isNaN(d) && d < maxDepth) { | |
81 maxDepth = d; | |
82 } | |
83 } | |
84 return maxDepth; | |
85 } | |
86 | |
87 public boolean interpolate( | |
88 List<? extends Coordinate> path, | |
89 List<? extends XYColumn> points, | |
90 double from, | |
91 double to, | |
92 Metrics metrics, | |
93 XYDepth xyDepth | |
94 ) { | |
95 boolean debug = log.isDebugEnabled(); | |
96 | |
97 int N = path.size(); | |
98 int M = points.size(); | |
99 | |
100 if (debug) { | |
101 log.debug("Size of path: " + N); | |
102 log.debug("Size of points: " + M); | |
103 } | |
104 | |
105 if (M < 1 || N < 2) { // nothing to do | |
106 return false; | |
107 } | |
108 | |
109 List<GridCell> cells = GridCell.pointsToGridCells( | |
110 points, Interpolation2D.relevantArea(path, points)); | |
111 | |
112 if (cells.isEmpty()) { | |
113 log.warn("no cells found"); | |
114 return false; | |
115 } | |
116 | |
117 // put into spatial index to speed up finding neighbors. | |
118 STRtree spatialIndex = new STRtree(); | |
119 | |
120 for (GridCell cell: cells) { | |
121 spatialIndex.insert(cell.getEnvelope(), cell); | |
122 } | |
123 | |
124 LinearToMap linearToMap = new LinearToMap( | |
125 path, from, to, metrics); | |
126 | |
127 double [] depths = new double[width]; | |
128 Arrays.fill(depths, Double.NaN); | |
129 | |
130 double cellWidth = (to - from)/width; | |
131 | |
132 double maxDepth = Double.MAX_VALUE; | |
133 | |
134 int i = 0; | |
135 Coordinate center = new Coordinate(); | |
136 for (double p = cellWidth*0.5; i < depths.length; ++i, p += cellWidth) { | |
137 if (linearToMap.locate(p, center)) { | |
138 double depth = xyDepth.depth(center); | |
139 depths[i] = depth; | |
140 if (depth < maxDepth) { | |
141 maxDepth = depth; | |
142 } | |
143 } | |
144 } | |
145 | |
146 if (maxDepth == Double.MAX_VALUE) { | |
147 log.warn("no depth found -> no interpolation"); | |
148 return false; | |
149 } | |
150 | |
151 double cellHeight = Math.abs(maxDepth)/height; | |
152 | |
153 if (debug) { | |
154 log.debug("max depth found: " + maxDepth); | |
155 log.debug("cell size: " + cellWidth + " x " + cellHeight); | |
156 } | |
157 | |
158 double [] raster = new double[width*height]; | |
159 Arrays.fill(raster, Double.NaN); | |
160 | |
161 Envelope queryBuffer = new Envelope(); | |
162 GridCell.CellFinder finder = new GridCell.CellFinder(); | |
163 | |
164 i = 0; | |
165 for (double p = cellWidth*0.5; i < depths.length; ++i, p += cellWidth) { | |
166 double depth = depths[i]; | |
167 if (Double.isNaN(depth) || depth >= 0d) { | |
168 continue; | |
169 } | |
170 linearToMap.locate(p, center); | |
171 | |
172 queryBuffer.init( | |
173 center.x - EPS, center.x + EPS, | |
174 center.y - EPS, center.y + EPS); | |
175 | |
176 finder.prepare(center); | |
177 spatialIndex.query(queryBuffer, finder); | |
178 | |
179 GridCell found = finder.found; | |
180 | |
181 if (found == null) { | |
182 continue; | |
183 } | |
184 | |
185 XYColumn n0 = (XYColumn)found.p1; | |
186 XYColumn n1 = (XYColumn)found.p2; | |
187 XYColumn n2 = (XYColumn)found.p3; | |
188 XYColumn n3 = (XYColumn)found.p4; | |
189 | |
190 if (n0.prepare(xyDepth) | |
191 && n1.prepare(xyDepth) | |
192 && n2.prepare(xyDepth) | |
193 && n3.prepare(xyDepth) | |
194 ) { | |
195 double y1 = Interpolation2D.interpolate( | |
196 n0.x, n0.y, | |
197 n1.x, n1.y, | |
198 center.x); | |
199 double y2 = Interpolation2D.interpolate( | |
200 n2.x, n2.y, | |
201 n3.x, n3.y, | |
202 center.x); | |
203 double z = -cellHeight*0.5; | |
204 for (int j = i; | |
205 j < raster.length && z >= depth; | |
206 z -= cellHeight, j += width) { | |
207 | |
208 double v0 = n0.value(z); | |
209 double v1 = n1.value(z); | |
210 double v2 = n2.value(z); | |
211 double v3 = n3.value(z); | |
212 | |
213 double z1 = Interpolation2D.interpolate( | |
214 n0.x, v0, | |
215 n1.x, v1, | |
216 center.x); | |
217 double z2 = Interpolation2D.interpolate( | |
218 n2.x, v2, | |
219 n3.x, v3, | |
220 center.x); | |
221 double value = Interpolation2D.interpolate( | |
222 y1, z1, | |
223 y2, z2, | |
224 center.y); | |
225 raster[j] = value; | |
226 } | |
227 // XXX: Adjusted depth to create no gap | |
228 // between last value and ground. | |
229 depths[i] = z+0.5d*cellHeight; | |
230 } // down the x/y column | |
231 } // all along the track | |
232 | |
233 this.depths = depths; | |
234 this.raster = raster; | |
235 this.cellWidth = cellWidth; | |
236 this.cellHeight = cellHeight; | |
237 | |
238 return true; | |
239 } | |
240 } | |
241 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: |