Revision 10626 trunk/extensions/extGeoProcessing/src/com/iver/cit/gvsig/geoprocess/impl/spatialjoin/fmap/NearestHeuristicSpatialJoinVisitor.java
NearestHeuristicSpatialJoinVisitor.java | ||
---|---|---|
45 | 45 |
* |
46 | 46 |
* $Id$ |
47 | 47 |
* $Log$ |
48 |
* Revision 1.1 2006-06-20 18:20:45 azabala |
|
48 |
* Revision 1.2 2007-03-06 16:47:58 caballero |
|
49 |
* Exceptions |
|
50 |
* |
|
51 |
* Revision 1.1 2006/06/20 18:20:45 azabala |
|
49 | 52 |
* first version in cvs |
50 | 53 |
* |
51 | 54 |
* Revision 1.2 2006/06/02 18:21:28 azabala |
... | ... | |
64 | 67 |
import java.awt.geom.Rectangle2D; |
65 | 68 |
import java.util.Stack; |
66 | 69 |
|
67 |
import com.iver.cit.gvsig.fmap.DriverException; |
|
70 |
import com.hardcode.gdbms.driver.exceptions.ReadDriverException; |
|
71 |
import com.hardcode.gdbms.engine.data.driver.DriverException; |
|
72 |
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException; |
|
73 |
import com.iver.cit.gvsig.exceptions.visitors.ProcessVisitorException; |
|
74 |
import com.iver.cit.gvsig.exceptions.visitors.StartVisitorException; |
|
75 |
import com.iver.cit.gvsig.exceptions.visitors.VisitorException; |
|
68 | 76 |
import com.iver.cit.gvsig.fmap.core.IFeature; |
69 | 77 |
import com.iver.cit.gvsig.fmap.core.IGeometry; |
70 | 78 |
import com.iver.cit.gvsig.fmap.layers.FBitSet; |
71 | 79 |
import com.iver.cit.gvsig.fmap.layers.FLayer; |
72 | 80 |
import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
73 | 81 |
import com.iver.cit.gvsig.fmap.operations.strategies.FeatureVisitor; |
74 |
import com.iver.cit.gvsig.fmap.operations.strategies.VisitException; |
|
75 | 82 |
import com.iver.cit.gvsig.geoprocess.core.fmap.FeatureProcessor; |
76 | 83 |
import com.vividsolutions.jts.geom.Envelope; |
77 | 84 |
import com.vividsolutions.jts.geom.Geometry; |
... | ... | |
96 | 103 |
* the parent node in the quad-tree structure). |
97 | 104 |
* <br> |
98 | 105 |
* A critical aspect is optimization of the number of levels of quad-tree. |
99 |
*
|
|
106 |
* |
|
100 | 107 |
* If we take very few levels, the spatial query will return a lot of |
101 | 108 |
* candidates to nearest, so we wont get advantage of this stuff. |
102 |
*
|
|
109 |
* |
|
103 | 110 |
* If we take a lot of levels, we wont get result in the spatial queries, |
104 | 111 |
* and we'll have to do a lot of querys. |
105 |
*
|
|
112 |
* |
|
106 | 113 |
* @author azabala |
107 |
*
|
|
114 |
* |
|
108 | 115 |
* FIXME EL ALGORITMO FALLA!!!!!!!! EL QUADTREE ES UNA ESTRUCTURA |
109 | 116 |
* BUENA PARA RECTANGULOS, PERO PARA PUNTOS CREO QUE NO FUNCIONA. |
110 | 117 |
* NO TIENE EN CUENTA LOS EXTREMOS DE LOS RECTANGULOS |
111 | 118 |
* |
112 | 119 |
*/ |
113 | 120 |
public class NearestHeuristicSpatialJoinVisitor extends NearestSpatialJoinVisitor { |
114 |
|
|
121 |
|
|
115 | 122 |
private QuadTreeUtil quadTree = new QuadTreeUtil(); |
116 | 123 |
/** |
117 | 124 |
* Full extent of the layer where we are looking for |
... | ... | |
119 | 126 |
*/ |
120 | 127 |
private Envelope targetLayerEnv = null; |
121 | 128 |
/** |
122 |
*
|
|
129 |
* |
|
123 | 130 |
* @param sourceLayer |
124 | 131 |
* @param targetLayer |
125 | 132 |
* @param processor |
126 | 133 |
* @throws DriverException |
127 | 134 |
*/ |
128 |
public NearestHeuristicSpatialJoinVisitor(FLyrVect sourceLayer,
|
|
129 |
FLyrVect targetLayer,
|
|
130 |
FeatureProcessor processor) throws DriverException { |
|
135 |
public NearestHeuristicSpatialJoinVisitor(FLyrVect sourceLayer, |
|
136 |
FLyrVect targetLayer, |
|
137 |
FeatureProcessor processor) throws ReadDriverException {
|
|
131 | 138 |
super(sourceLayer, targetLayer, processor); |
132 |
|
|
133 |
Rectangle2D rect = targetLayer.getFullExtent(); |
|
134 |
targetLayerEnv = new Envelope(rect.getMinX(), |
|
139 |
|
|
140 |
Rectangle2D rect; |
|
141 |
try { |
|
142 |
rect = targetLayer.getFullExtent(); |
|
143 |
} catch (ExpansionFileReadException e) { |
|
144 |
throw new ReadDriverException(sourceLayer.getName(),e); |
|
145 |
} |
|
146 |
targetLayerEnv = new Envelope(rect.getMinX(), |
|
135 | 147 |
rect.getMaxX(), |
136 | 148 |
rect.getMinY(), |
137 | 149 |
rect.getMaxY()); |
138 |
|
|
150 |
|
|
139 | 151 |
} |
140 | 152 |
// TODO If we need a class to look for nearest feature to a given |
141 | 153 |
//feature, move to a public class |
... | ... | |
158 | 170 |
* consideer features selected. |
159 | 171 |
*/ |
160 | 172 |
FBitSet selection; |
161 |
|
|
173 |
|
|
162 | 174 |
public boolean hasFoundShortest(){ |
163 | 175 |
return nearestFeatureIndex != -1; |
164 | 176 |
} |
165 |
|
|
177 |
|
|
166 | 178 |
public int getNearestFeatureIndex(){ |
167 | 179 |
return nearestFeatureIndex; |
168 | 180 |
} |
169 |
|
|
181 |
|
|
170 | 182 |
public void setSelection(FBitSet bitSet){ |
171 | 183 |
this.selection = bitSet; |
172 | 184 |
} |
173 |
|
|
185 |
|
|
174 | 186 |
public void setGeometry(Geometry firstG){ |
175 | 187 |
this.firstG = firstG; |
176 | 188 |
} |
177 |
|
|
178 |
public void visit(IGeometry g, int index) throws VisitException { |
|
189 |
|
|
190 |
public void visit(IGeometry g, int index) throws VisitorException, ProcessVisitorException {
|
|
179 | 191 |
if(selection != null){ |
180 | 192 |
if(! selection.get(index)){ |
181 | 193 |
return; |
... | ... | |
190 | 202 |
public String getProcessDescription() { |
191 | 203 |
return ""; |
192 | 204 |
} |
193 |
public void stop(FLayer layer) { |
|
205 |
public void stop(FLayer layer) throws VisitorException {
|
|
194 | 206 |
} |
195 |
public boolean start(FLayer layer) { |
|
207 |
public boolean start(FLayer layer) throws StartVisitorException {
|
|
196 | 208 |
return true; |
197 | 209 |
} |
198 | 210 |
}; |
... | ... | |
200 | 212 |
* Processes a Feature of source layer, looking for its nearest feature of |
201 | 213 |
* target layer and taking attributes from it |
202 | 214 |
*/ |
203 |
public void visit(IGeometry g, int sourceIndex) throws VisitException { |
|
215 |
public void visit(IGeometry g, int sourceIndex) throws VisitorException, ProcessVisitorException {
|
|
204 | 216 |
if(g == null) |
205 | 217 |
return; |
206 |
final Geometry geometry = g.toJTSGeometry();
|
|
218 |
final Geometry geometry = g.toJTSGeometry(); |
|
207 | 219 |
Stack stackOfEnvelopes = quadTree.getNearestEnvelopeOfIdealDimension(geometry, |
208 | 220 |
targetLayerEnv); |
209 | 221 |
LookForNearest visitor = new LookForNearest(); |
210 | 222 |
visitor.setGeometry(geometry); |
211 | 223 |
while((stackOfEnvelopes.size() > 0) ) { |
212 | 224 |
Envelope envelope = (Envelope) stackOfEnvelopes.pop(); |
213 |
Rectangle2D.Double rect = new Rectangle2D.Double(envelope.getMinX(),
|
|
225 |
Rectangle2D.Double rect = new Rectangle2D.Double(envelope.getMinX(), |
|
214 | 226 |
envelope.getMinY(), |
215 | 227 |
envelope.getWidth(), |
216 | 228 |
envelope.getHeight()); |
... | ... | |
221 | 233 |
strategy.process(visitor, rect); |
222 | 234 |
if(visitor.hasFoundShortest()){ |
223 | 235 |
int targetIndex = visitor.getNearestFeatureIndex(); |
224 |
IFeature joinedFeature = createFeature(g,
|
|
225 |
sourceIndex,
|
|
236 |
IFeature joinedFeature = createFeature(g, |
|
237 |
sourceIndex, |
|
226 | 238 |
targetIndex, -1); |
227 | 239 |
this.featureProcessor.processFeature(joinedFeature); |
228 | 240 |
return; |
229 | 241 |
} |
230 |
} catch (DriverException e) { |
|
231 |
throw new VisitException("Error accediendo a los datos buscando el feature mas proximo", e);
|
|
232 |
} catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
|
|
233 |
throw new VisitException("Error accediendo a los datos buscando el feature mas proximo", e);
|
|
234 |
}
|
|
242 |
} catch (ReadDriverException e) {
|
|
243 |
throw new ProcessVisitorException(targetRecordset.getName(),e,"Error accediendo a los datos buscando el feature mas proximo");
|
|
244 |
} catch (ExpansionFileReadException e) {
|
|
245 |
throw new ProcessVisitorException(targetRecordset.getName(),e,"Error accediendo a los datos buscando el feature mas proximo");
|
|
246 |
} |
|
235 | 247 |
}//while |
236 |
|
|
248 |
|
|
237 | 249 |
} |
238 |
|
|
250 |
|
|
239 | 251 |
/** |
240 | 252 |
* FIXME Refinar muy mucho, pero de momento me vale para hacer la busqueda |
241 | 253 |
* de la geometria mas proxima a una dada mediante subdivisi?n del espacio. |
242 |
*
|
|
254 |
* |
|
243 | 255 |
* @author azabala |
244 | 256 |
* |
245 | 257 |
*/ |
246 | 258 |
class QuadTreeUtil{ |
247 | 259 |
double DEFAULT_IDEAL_DIMENSION = 500d; |
248 |
|
|
260 |
|
|
249 | 261 |
double idealDimension = DEFAULT_IDEAL_DIMENSION; |
250 | 262 |
|
251 | 263 |
public void setIdealDimension(double idealDimension){ |
252 | 264 |
this.idealDimension = idealDimension; |
253 | 265 |
} |
254 |
|
|
266 |
|
|
255 | 267 |
public double distance(Geometry geo, Envelope rect){ |
256 | 268 |
GeometryFactory geoFact = new GeometryFactory(); |
257 | 269 |
Geometry poly = geoFact.toGeometry(rect); |
258 | 270 |
return DistanceOp.distance(geo, poly); |
259 | 271 |
} |
260 |
|
|
272 |
|
|
261 | 273 |
public double getMaxDimension(Envelope env){ |
262 | 274 |
double w = env.getWidth(); |
263 | 275 |
double h = env.getHeight(); |
264 | 276 |
return (w > h ? w : h); |
265 | 277 |
} |
266 |
|
|
267 |
|
|
278 |
|
|
279 |
|
|
268 | 280 |
public Stack getNearestEnvelopeOfIdealDimension(Geometry nearest, |
269 | 281 |
Envelope originalEnvelope){ |
270 | 282 |
//stack with all the hierarchical envelopes of the solution quad |
... | ... | |
285 | 297 |
firstsolution = quads[1]; |
286 | 298 |
else if(d2 <= d0 && d2 <= d1 && d2 <= d3) |
287 | 299 |
firstsolution = quads[2]; |
288 |
else
|
|
300 |
else |
|
289 | 301 |
firstsolution = quads[3]; |
290 | 302 |
solution.push(firstsolution); |
291 | 303 |
maxDimension = getMaxDimension(firstsolution); |
292 | 304 |
} |
293 | 305 |
return solution; |
294 |
|
|
306 |
|
|
295 | 307 |
} |
296 |
|
|
308 |
|
|
297 | 309 |
public Envelope[] getNextQtreeLevel(Envelope rect){ |
298 | 310 |
Envelope[] solution = new Envelope[4]; |
299 | 311 |
int SW = 0; |
Also available in: Unified diff