Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java @ 376:d8f3ef441bf2
merged gnv-artifacts/0.3
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:47 +0200 |
parents | 086e3af38b96 |
children | 04a242c67fe6 |
comparison
equal
deleted
inserted
replaced
293:6b0ef2324d02 | 376:d8f3ef441bf2 |
---|---|
1 package de.intevation.gnv.math; | |
2 | |
3 import java.util.ArrayList; | |
4 import java.util.List; | |
5 import java.util.HashMap; | |
6 import java.util.Collections; | |
7 | |
8 import com.vividsolutions.jts.geom.Coordinate; | |
9 import com.vividsolutions.jts.geom.Envelope; | |
10 | |
11 import com.vividsolutions.jts.index.quadtree.Quadtree; | |
12 | |
13 import org.apache.log4j.Logger; | |
14 | |
15 /** | |
16 * @author Sascha L. Teichmann | |
17 */ | |
18 public final class Interpolation2D | |
19 { | |
20 private static Logger log = Logger.getLogger(Interpolation2D.class); | |
21 | |
22 public interface Consumer { | |
23 void interpolated(Coordinate point); | |
24 } // interface Consumer | |
25 | |
26 private Interpolation2D() { | |
27 } | |
28 | |
29 public static void interpolate( | |
30 List<? extends Coordinate> path, | |
31 List<? extends Point2d> points, | |
32 double from, | |
33 double to, | |
34 int steps, | |
35 Metrics metrics, | |
36 Consumer consumer | |
37 ) { | |
38 int N = path.size(); | |
39 int M = points.size(); | |
40 | |
41 log.debug("Size of path: " + N); | |
42 log.debug("Size of points: " + M); | |
43 | |
44 if (M < 1 || N < 2) { // nothing to do | |
45 return; | |
46 } | |
47 | |
48 HashMap<Integer, ArrayList<Point2d>> map = new HashMap<Integer, ArrayList<Point2d>>(); | |
49 | |
50 for (int k = M-1; k >= 0; --k) { | |
51 Point2d p = points.get(k); | |
52 | |
53 ArrayList<Point2d> list = map.get(p.j); | |
54 | |
55 if (list == null) { | |
56 map.put(p.j, list = new ArrayList<Point2d>()); | |
57 } | |
58 list.add(p); | |
59 } | |
60 | |
61 double dxMax = -Double.MAX_VALUE; | |
62 | |
63 for (ArrayList<Point2d> v: map.values()) { | |
64 Collections.sort(v, Point2d.X_COMPARATOR); | |
65 for (int i = 1, L = v.size(); i < L; ++i) { | |
66 double dx = Math.abs(v.get(i).x - v.get(i-1).x); | |
67 if (dx > dxMax) { | |
68 dxMax = dx; | |
69 } | |
70 } | |
71 } | |
72 | |
73 dxMax = dxMax + 1e-5d; | |
74 | |
75 map.clear(); | |
76 | |
77 for (int k = M-1; k >= 0; --k) { | |
78 Point2d p = points.get(k); | |
79 | |
80 ArrayList<Point2d> list = map.get(p.i); | |
81 | |
82 if (list == null) { | |
83 map.put(p.i, list = new ArrayList<Point2d>()); | |
84 } | |
85 list.add(p); | |
86 } | |
87 | |
88 double dyMax = -Double.MAX_VALUE; | |
89 | |
90 for (ArrayList<Point2d> v: map.values()) { | |
91 Collections.sort(v, Point2d.Y_COMPARATOR); | |
92 for (int i = 1, L = v.size(); i < L; ++i) { | |
93 double dy = Math.abs(v.get(i).y - v.get(i-1).y); | |
94 if (dy > dyMax) { | |
95 dyMax = dy; | |
96 } | |
97 } | |
98 } | |
99 | |
100 dyMax = dyMax + 1e-5d; | |
101 | |
102 map = null; | |
103 | |
104 log.debug("buffer size: " + dxMax + " / " + dyMax); | |
105 | |
106 // put into spatial index to speed up finding neighbors. | |
107 Quadtree spatialIndex = new Quadtree(); | |
108 | |
109 for (int i = 0; i < M; ++i) { | |
110 Point2d p = points.get(i); | |
111 spatialIndex.insert(p.envelope(), p); | |
112 } | |
113 | |
114 LinearToMap linearToMap = new LinearToMap( | |
115 path, from, to, metrics); | |
116 | |
117 double dP = (to - from)/steps; | |
118 | |
119 Coordinate center = new Coordinate(); | |
120 | |
121 Envelope queryBuffer = new Envelope(); | |
122 | |
123 Point2d [] neighbors = new Point2d[4]; | |
124 | |
125 int missedInterpolations = 0; | |
126 int interpolations = 0; | |
127 | |
128 for (double p = from; p <= to; p += dP) { | |
129 if (!linearToMap.locate(p, center)) { | |
130 continue; | |
131 } | |
132 queryBuffer.init( | |
133 center.x - dxMax, center.x + dxMax, | |
134 center.y - dyMax, center.y + dyMax); | |
135 | |
136 List potential = spatialIndex.query(queryBuffer); | |
137 | |
138 L1Comparator invL1 = new L1Comparator(center); | |
139 Collections.sort(potential, invL1); | |
140 | |
141 neighbors[0] = neighbors[1] = | |
142 neighbors[2] = neighbors[3] = null; | |
143 | |
144 /* bit code of neighbors | |
145 0---1 | |
146 | x | | |
147 2---3 | |
148 */ | |
149 | |
150 int mask = 0; | |
151 // reversed order is essential here! | |
152 for (int i = potential.size()-1; i >= 0; --i) { | |
153 Point2d n = (Point2d)potential.get(i); | |
154 int code = n.x > center.x ? 1 : 0; | |
155 if (n.y > center.y) code |= 2; | |
156 neighbors[code] = n; | |
157 mask |= 1 << code; | |
158 } | |
159 | |
160 int numNeighbors = Integer.bitCount(mask); | |
161 | |
162 // only interpolate if we have all four neighbors | |
163 // and we do not have any gaps. | |
164 if (numNeighbors == 4 | |
165 && !neighbors[0].hasIGap(neighbors[1]) | |
166 && !neighbors[1].hasJGap(neighbors[3]) | |
167 && !neighbors[3].hasIGap(neighbors[2]) | |
168 && !neighbors[2].hasJGap(neighbors[0]) | |
169 ) { | |
170 double z1 = interpolate( | |
171 neighbors[0].x, neighbors[0].z, | |
172 neighbors[1].x, neighbors[1].z, | |
173 center.x); | |
174 double z2 = interpolate( | |
175 neighbors[2].x, neighbors[2].z, | |
176 neighbors[3].x, neighbors[3].z, | |
177 center.x); | |
178 double y1 = interpolate( | |
179 neighbors[0].x, neighbors[0].y, | |
180 neighbors[1].x, neighbors[1].y, | |
181 center.x); | |
182 double y2 = interpolate( | |
183 neighbors[2].x, neighbors[2].y, | |
184 neighbors[3].x, neighbors[3].y, | |
185 center.x); | |
186 center.z = interpolate( | |
187 y1, z1, | |
188 y2, z2, | |
189 center.y); | |
190 consumer.interpolated(center); | |
191 ++interpolations; | |
192 } | |
193 else { | |
194 ++missedInterpolations; | |
195 } | |
196 } | |
197 | |
198 log.debug("interpolations: " + interpolations + " / " + missedInterpolations); | |
199 } | |
200 | |
201 public static final double interpolate( | |
202 double x1, double y1, | |
203 double x2, double y2, | |
204 double x | |
205 ) { | |
206 if (x2 == x1) { | |
207 return (y1 + y2)*0.5d; | |
208 } | |
209 double m = (y2-y1)/(x2-x1); | |
210 double b = y1 - m*x1; | |
211 return m*x + b; | |
212 } | |
213 } | |
214 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: |