root / tags / v2_0_0_Build_2047 / libraries / org.gvsig.symbology / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / legend / impl / AbstractVectorialLegend.java @ 38365
History | View | Annotate | Download (33.2 KB)
1 | 34294 | fdiaz | /* gvSIG. Geographic Information System of the Valencian Government
|
---|---|---|---|
2 | *
|
||
3 | * Copyright (C) 2007-2008 Infrastructures and Transports Department
|
||
4 | * of the Valencian Government (CIT)
|
||
5 | *
|
||
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | * as published by the Free Software Foundation; either version 2
|
||
9 | * of the License, or (at your option) any later version.
|
||
10 | *
|
||
11 | * This program is distributed in the hope that it will be useful,
|
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 | * GNU General Public License for more details.
|
||
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
19 | * MA 02110-1301, USA.
|
||
20 | *
|
||
21 | */
|
||
22 | |||
23 | /*
|
||
24 | * AUTHORS (In addition to CIT):
|
||
25 | * 2009 {DiSiD Technologies} {{Task}}
|
||
26 | */
|
||
27 | package org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl; |
||
28 | |||
29 | import java.awt.Graphics2D; |
||
30 | import java.awt.geom.Point2D; |
||
31 | import java.awt.image.BufferedImage; |
||
32 | 38207 | cordinyana | import java.util.ConcurrentModificationException; |
33 | 34294 | fdiaz | import java.util.Iterator; |
34 | import java.util.Map; |
||
35 | import java.util.Map.Entry; |
||
36 | |||
37 | import org.cresques.cts.ICoordTrans; |
||
38 | import org.cresques.cts.IProjection; |
||
39 | import org.gvsig.compat.CompatLocator; |
||
40 | import org.gvsig.compat.print.PrintAttributes; |
||
41 | import org.gvsig.fmap.dal.exception.DataException; |
||
42 | import org.gvsig.fmap.dal.exception.ReadException; |
||
43 | import org.gvsig.fmap.dal.feature.Feature; |
||
44 | import org.gvsig.fmap.dal.feature.FeatureQuery; |
||
45 | import org.gvsig.fmap.dal.feature.FeatureSelection; |
||
46 | import org.gvsig.fmap.dal.feature.FeatureSet; |
||
47 | import org.gvsig.fmap.dal.feature.FeatureStore; |
||
48 | import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException; |
||
49 | import org.gvsig.fmap.geom.Geometry; |
||
50 | import org.gvsig.fmap.geom.GeometryLocator; |
||
51 | import org.gvsig.fmap.geom.GeometryManager; |
||
52 | import org.gvsig.fmap.geom.aggregate.Aggregate; |
||
53 | import org.gvsig.fmap.geom.exception.CreateGeometryException; |
||
54 | import org.gvsig.fmap.geom.operation.DrawInts; |
||
55 | import org.gvsig.fmap.geom.operation.DrawOperationContext; |
||
56 | import org.gvsig.fmap.geom.operation.GeometryOperationException; |
||
57 | import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException; |
||
58 | import org.gvsig.fmap.geom.primitive.Envelope; |
||
59 | import org.gvsig.fmap.mapcontext.MapContext; |
||
60 | import org.gvsig.fmap.mapcontext.MapContextException; |
||
61 | import org.gvsig.fmap.mapcontext.ViewPort; |
||
62 | import org.gvsig.fmap.mapcontext.layers.vectorial.IntersectsEnvelopeEvaluator; |
||
63 | import org.gvsig.fmap.mapcontext.rendering.legend.ILegend; |
||
64 | import org.gvsig.fmap.mapcontext.rendering.legend.IVectorLegend; |
||
65 | import org.gvsig.fmap.mapcontext.rendering.legend.LegendException; |
||
66 | import org.gvsig.fmap.mapcontext.rendering.legend.ZSort; |
||
67 | import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport; |
||
68 | import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol; |
||
69 | import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol; |
||
70 | import org.gvsig.tools.ToolsLocator; |
||
71 | import org.gvsig.tools.dispose.DisposableIterator; |
||
72 | import org.gvsig.tools.dynobject.DynStruct; |
||
73 | import org.gvsig.tools.exception.BaseException; |
||
74 | import org.gvsig.tools.persistence.PersistenceManager; |
||
75 | import org.gvsig.tools.persistence.PersistentState; |
||
76 | import org.gvsig.tools.persistence.exception.PersistenceException; |
||
77 | import org.gvsig.tools.task.Cancellable; |
||
78 | 34935 | jjdelcerro | import org.gvsig.tools.task.SimpleTaskStatus; |
79 | 34294 | fdiaz | import org.gvsig.tools.util.Callable; |
80 | import org.gvsig.tools.visitor.VisitCanceledException; |
||
81 | import org.gvsig.tools.visitor.Visitor; |
||
82 | |||
83 | /**
|
||
84 | * Base implementation for Vectorial data Legends.
|
||
85 | *
|
||
86 | * Provides a draw method implementation which loads the {@link Feature}s and
|
||
87 | * uses the {@link ISymbol} objects to draw the {@link Geometry} objects.
|
||
88 | *
|
||
89 | * @author 2009- <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
|
||
90 | */
|
||
91 | public abstract class AbstractVectorialLegend extends AbstractLegend implements |
||
92 | 35329 | jpiera | IVectorLegend { |
93 | 34294 | fdiaz | |
94 | 38207 | cordinyana | private static final int DRAW_MAX_ATTEMPTS = 3; |
95 | 34294 | fdiaz | |
96 | 38207 | cordinyana | public static final String VECTORIAL_LEGEND_PERSISTENCE_DEFINITION_NAME = "VectorialLegend"; |
97 | |||
98 | 35329 | jpiera | private static final String FIELD_HAS_ZSORT = "hasZSort"; |
99 | private static final String FIELD_SHAPETYPE = "shapeType"; |
||
100 | private static final String FIELD_DEFAULT_SYMBOL = "defaultSymbol"; |
||
101 | 34294 | fdiaz | |
102 | 35329 | jpiera | private static final GeometryManager geomManager = GeometryLocator |
103 | .getGeometryManager(); |
||
104 | 34294 | fdiaz | |
105 | 35329 | jpiera | protected ZSort zSort;
|
106 | 34294 | fdiaz | |
107 | 35329 | jpiera | public ZSort getZSort() {
|
108 | return zSort;
|
||
109 | } |
||
110 | 34294 | fdiaz | |
111 | 35329 | jpiera | public void setZSort(ZSort zSort) { |
112 | if (zSort == null) { |
||
113 | removeLegendListener(this.zSort);
|
||
114 | } |
||
115 | this.zSort = zSort;
|
||
116 | addLegendListener(zSort); |
||
117 | } |
||
118 | |||
119 | @SuppressWarnings("unchecked") |
||
120 | public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, |
||
121 | Cancellable cancel, double scale, Map queryParameters, |
||
122 | ICoordTrans coordTrans, FeatureStore featureStore) |
||
123 | throws LegendException {
|
||
124 | double dpi = MapContext.getScreenDPI();
|
||
125 | draw(image, g, viewPort, cancel, scale, queryParameters, coordTrans, |
||
126 | featureStore, null, dpi);
|
||
127 | } |
||
128 | |||
129 | @SuppressWarnings("unchecked") |
||
130 | public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, |
||
131 | Cancellable cancel, double scale, Map queryParameters, |
||
132 | ICoordTrans coordTrans, FeatureStore featureStore, FeatureQuery featureQuery) |
||
133 | throws LegendException {
|
||
134 | double dpi = MapContext.getScreenDPI();
|
||
135 | draw(image, g, viewPort, cancel, scale, queryParameters, coordTrans, |
||
136 | featureStore, featureQuery, dpi); |
||
137 | } |
||
138 | 34294 | fdiaz | |
139 | 35329 | jpiera | @SuppressWarnings("unchecked") |
140 | public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, |
||
141 | double scale, Map queryParameters, ICoordTrans coordTrans, |
||
142 | FeatureStore featureStore, PrintAttributes properties) |
||
143 | throws LegendException {
|
||
144 | print(g, viewPort, cancel, scale, queryParameters, coordTrans, |
||
145 | featureStore, null, properties);
|
||
146 | } |
||
147 | |||
148 | @SuppressWarnings("unchecked") |
||
149 | public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, |
||
150 | double scale, Map queryParameters, ICoordTrans coordTrans, |
||
151 | FeatureStore featureStore, FeatureQuery featureQuery, PrintAttributes properties) |
||
152 | throws LegendException {
|
||
153 | double dpi = 72; |
||
154 | 34294 | fdiaz | |
155 | 35329 | jpiera | int resolution = properties.getPrintQuality();
|
156 | 34294 | fdiaz | |
157 | 35329 | jpiera | if (resolution == PrintAttributes.PRINT_QUALITY_NORMAL) {
|
158 | dpi = 300;
|
||
159 | } else if (resolution == PrintAttributes.PRINT_QUALITY_HIGH) { |
||
160 | dpi = 600;
|
||
161 | } else if (resolution == PrintAttributes.PRINT_QUALITY_DRAFT) { |
||
162 | dpi = 72;
|
||
163 | } |
||
164 | 34294 | fdiaz | |
165 | 35329 | jpiera | FeatureSet featureSet = null;
|
166 | DisposableIterator it = null;
|
||
167 | try {
|
||
168 | ZSort zSort = getZSort(); |
||
169 | 34294 | fdiaz | |
170 | 35329 | jpiera | // if layer has map levels it will use a ZSort
|
171 | boolean useZSort = zSort != null && zSort.isUsingZSort(); |
||
172 | 34294 | fdiaz | |
173 | 35329 | jpiera | int mapLevelCount = (useZSort) ? zSort.getLevelCount() : 1; |
174 | for (int mapPass = 0; mapPass < mapLevelCount; mapPass++) { |
||
175 | // Get the iterator over the visible features
|
||
176 | String[] fieldNames = getRequiredFeatureAttributeNames(featureStore); |
||
177 | 34294 | fdiaz | |
178 | 35329 | jpiera | if (featureQuery == null){ |
179 | featureQuery = featureStore.createFeatureQuery(); |
||
180 | } |
||
181 | featureQuery.setAttributeNames(fieldNames); |
||
182 | featureQuery.setScale(scale); |
||
183 | 34294 | fdiaz | |
184 | 37421 | jpiera | IntersectsEnvelopeEvaluator iee = new IntersectsEnvelopeEvaluator(
|
185 | 35329 | jpiera | viewPort.getAdjustedEnvelope(), |
186 | viewPort.getProjection(), |
||
187 | featureStore.getDefaultFeatureType(), featureStore |
||
188 | .getDefaultFeatureType() |
||
189 | .getDefaultGeometryAttributeName()); |
||
190 | featureQuery.addFilter(iee); |
||
191 | featureSet = featureStore.getFeatureSet(featureQuery); |
||
192 | it = featureSet.fastIterator(); |
||
193 | 34294 | fdiaz | |
194 | 35329 | jpiera | // Iteration over each feature
|
195 | while (!cancel.isCanceled() && it.hasNext()) {
|
||
196 | Feature feat = (Feature) it.next(); |
||
197 | Geometry geom = feat.getDefaultGeometry(); |
||
198 | 34294 | fdiaz | |
199 | 35329 | jpiera | // retrieve the symbol associated to such feature
|
200 | ISymbol sym = getSymbolByFeature(feat); |
||
201 | if (sym == null) { |
||
202 | continue;
|
||
203 | } |
||
204 | if (useZSort) {
|
||
205 | int[] symLevels = zSort.getLevels(sym); |
||
206 | if (symLevels != null) { |
||
207 | 34294 | fdiaz | |
208 | 35329 | jpiera | // Check if this symbol is a multilayer
|
209 | if (sym instanceof IMultiLayerSymbol) { |
||
210 | // if so, get the layer corresponding to the
|
||
211 | // current level. If none, continue to next
|
||
212 | // iteration
|
||
213 | IMultiLayerSymbol mlSym = (IMultiLayerSymbol) sym; |
||
214 | for (int i = 0; i < mlSym.getLayerCount(); i++) { |
||
215 | ISymbol mySym = mlSym.getLayer(i); |
||
216 | if (symLevels[i] == mapPass) {
|
||
217 | sym = mySym; |
||
218 | break;
|
||
219 | } |
||
220 | } |
||
221 | 34294 | fdiaz | |
222 | 35329 | jpiera | } else {
|
223 | // else, just draw the symbol in its level
|
||
224 | if (symLevels[0] != mapPass) { |
||
225 | continue;
|
||
226 | } |
||
227 | } |
||
228 | } |
||
229 | } |
||
230 | 34294 | fdiaz | |
231 | 35329 | jpiera | // Check if this symbol is sized with CartographicSupport
|
232 | CartographicSupport csSym = null;
|
||
233 | int symbolType = sym.getSymbolType();
|
||
234 | 34294 | fdiaz | |
235 | 35329 | jpiera | if (symbolType == Geometry.TYPES.POINT
|
236 | || symbolType == Geometry.TYPES.CURVE |
||
237 | || sym instanceof CartographicSupport) {
|
||
238 | 34294 | fdiaz | |
239 | 35329 | jpiera | csSym = (CartographicSupport) sym; |
240 | } |
||
241 | 34294 | fdiaz | |
242 | 35329 | jpiera | DrawOperationContext doc = new DrawOperationContext();
|
243 | doc.setGraphics(g); |
||
244 | doc.setViewPort(viewPort); |
||
245 | if (csSym == null) { |
||
246 | doc.setSymbol(sym); |
||
247 | } else {
|
||
248 | doc.setDPI(dpi); |
||
249 | doc.setCancellable(cancel); |
||
250 | doc.setSymbol((ISymbol) csSym); |
||
251 | } |
||
252 | geom.invokeOperation(DrawInts.CODE, doc); |
||
253 | } |
||
254 | } |
||
255 | } catch (ReadException e) {
|
||
256 | throw new LegendDrawingException(e); |
||
257 | } catch (GeometryOperationNotSupportedException e) {
|
||
258 | throw new LegendDrawingException(e); |
||
259 | } catch (GeometryOperationException e) {
|
||
260 | throw new LegendDrawingException(e); |
||
261 | } catch (DataException e) {
|
||
262 | throw new LegendDrawingException(e); |
||
263 | } catch (MapContextException e) {
|
||
264 | throw new LegendDrawingException(e); |
||
265 | } finally {
|
||
266 | if (it != null) { |
||
267 | it.dispose(); |
||
268 | } |
||
269 | if (featureSet != null) { |
||
270 | featureSet.dispose(); |
||
271 | } |
||
272 | } |
||
273 | } |
||
274 | 34294 | fdiaz | |
275 | 35329 | jpiera | /**
|
276 | * Draws the features from the {@link FeatureStore}, filtered with the scale
|
||
277 | * and the query parameters, with the symbols of the legend.
|
||
278 | */
|
||
279 | @SuppressWarnings("unchecked") |
||
280 | protected void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, |
||
281 | Cancellable cancel, double scale, Map queryParameters, |
||
282 | ICoordTrans coordTrans, FeatureStore featureStore, FeatureQuery featureQuery, double dpi)
|
||
283 | throws LegendException {
|
||
284 | 34294 | fdiaz | |
285 | 38207 | cordinyana | int retryCount = 0; |
286 | SimpleTaskStatus taskStatus = ToolsLocator.getTaskStatusManager() |
||
287 | .createDefaultSimpleTaskStatus(featureStore.getName()); |
||
288 | taskStatus.add(); |
||
289 | boolean drawPerformed = false; |
||
290 | while (retryCount < DRAW_MAX_ATTEMPTS && !drawPerformed) {
|
||
291 | try {
|
||
292 | internalDraw(image, g, viewPort, cancel, scale, |
||
293 | queryParameters, coordTrans, featureStore, |
||
294 | featureQuery, dpi, taskStatus); |
||
295 | drawPerformed = true;
|
||
296 | 38221 | cordinyana | } catch (IllegalStateException e) { |
297 | 38207 | cordinyana | retryCount++; |
298 | if (retryCount >= DRAW_MAX_ATTEMPTS) {
|
||
299 | throw e;
|
||
300 | } |
||
301 | 38221 | cordinyana | } catch (ConcurrentModificationException e) { |
302 | retryCount++; |
||
303 | if (retryCount >= DRAW_MAX_ATTEMPTS) {
|
||
304 | throw e;
|
||
305 | } |
||
306 | } catch (ConcurrentDataModificationException e) {
|
||
307 | retryCount++; |
||
308 | if (retryCount >= DRAW_MAX_ATTEMPTS) {
|
||
309 | throw e;
|
||
310 | } |
||
311 | 38207 | cordinyana | } finally {
|
312 | if (taskStatus != null) { |
||
313 | taskStatus.terminate(); |
||
314 | taskStatus.remove(); |
||
315 | taskStatus = null;
|
||
316 | } |
||
317 | } |
||
318 | } |
||
319 | } |
||
320 | 34294 | fdiaz | |
321 | 38207 | cordinyana | protected void internalDraw(BufferedImage image, Graphics2D g, |
322 | ViewPort viewPort, Cancellable cancel, double scale,
|
||
323 | Map queryParameters, ICoordTrans coordTrans,
|
||
324 | FeatureStore featureStore, FeatureQuery featureQuery, double dpi,
|
||
325 | SimpleTaskStatus taskStatus) throws LegendDrawingException {
|
||
326 | 34294 | fdiaz | |
327 | 38207 | cordinyana | if (!getDefaultSymbol().isShapeVisible()) {
|
328 | return;
|
||
329 | } |
||
330 | 34294 | fdiaz | |
331 | 38207 | cordinyana | if (cancel.isCanceled()) {
|
332 | return;
|
||
333 | } |
||
334 | 34294 | fdiaz | |
335 | 38207 | cordinyana | IProjection dataProjection; |
336 | Envelope reprojectedDataEnvelop; |
||
337 | 34294 | fdiaz | |
338 | 38207 | cordinyana | try {
|
339 | if (coordTrans == null) { |
||
340 | dataProjection = featureStore.getDefaultFeatureType() |
||
341 | .getDefaultSRS(); |
||
342 | 34294 | fdiaz | |
343 | 38207 | cordinyana | // If the data does not provide a projection, use the
|
344 | // current view one
|
||
345 | if (dataProjection == null) { |
||
346 | dataProjection = viewPort.getProjection(); |
||
347 | } |
||
348 | 34294 | fdiaz | |
349 | 38207 | cordinyana | reprojectedDataEnvelop = featureStore.getEnvelope(); |
350 | } else {
|
||
351 | dataProjection = coordTrans.getPOrig(); |
||
352 | 34294 | fdiaz | |
353 | 38207 | cordinyana | Envelope env = featureStore.getEnvelope(); |
354 | if (!env.isEmpty()) {
|
||
355 | reprojectedDataEnvelop = env.convert(coordTrans); |
||
356 | } else {
|
||
357 | reprojectedDataEnvelop = env; |
||
358 | } |
||
359 | } |
||
360 | } catch (DataException e) {
|
||
361 | throw new LegendDrawingException(e); |
||
362 | } |
||
363 | 34294 | fdiaz | |
364 | 38207 | cordinyana | // Gets the view envelope
|
365 | Envelope viewPortEnvelope = viewPort.getAdjustedEnvelope(); |
||
366 | 34294 | fdiaz | |
367 | 38207 | cordinyana | // Gets the data envelope with the viewport SRS
|
368 | Envelope myEnvelope = reprojectedDataEnvelop; |
||
369 | 34294 | fdiaz | |
370 | 38207 | cordinyana | // TODO: in some cases, the legend may need a different check to
|
371 | // decide if the data must be drawn or not
|
||
372 | // Checks if the viewport envelope intersects with the data envelope
|
||
373 | if (!viewPortEnvelope.intersects(myEnvelope)) {
|
||
374 | // The data is not visible in the current viewport, do nothing.
|
||
375 | return;
|
||
376 | } |
||
377 | 34294 | fdiaz | |
378 | 38207 | cordinyana | // Check if all the data is contained into the viewport envelope
|
379 | boolean containsAll = viewPortEnvelope.contains(myEnvelope);
|
||
380 | 34294 | fdiaz | |
381 | 38207 | cordinyana | // Create the drawing notification to be reused on each iteration
|
382 | DefaultFeatureDrawnNotification drawnNotification = new DefaultFeatureDrawnNotification();
|
||
383 | 34294 | fdiaz | |
384 | 38207 | cordinyana | if (cancel.isCanceled()) {
|
385 | return;
|
||
386 | } |
||
387 | 34294 | fdiaz | |
388 | 38207 | cordinyana | FeatureSet featureSet = null;
|
389 | try {
|
||
390 | taskStatus.message("Retrieve selection");
|
||
391 | FeatureSelection selection = featureStore.getFeatureSelection(); |
||
392 | 34294 | fdiaz | |
393 | 38207 | cordinyana | if (featureQuery == null) { |
394 | featureQuery = featureStore.createFeatureQuery(); |
||
395 | } |
||
396 | 34294 | fdiaz | |
397 | 38207 | cordinyana | completeQuery(featureStore, featureQuery, scale, queryParameters, |
398 | coordTrans, dataProjection, viewPortEnvelope, containsAll); |
||
399 | 34294 | fdiaz | |
400 | 38207 | cordinyana | taskStatus.message("Retrieve data");
|
401 | featureSet = featureStore.getFeatureSet(featureQuery); |
||
402 | 34294 | fdiaz | |
403 | 38207 | cordinyana | if (cancel.isCanceled()) {
|
404 | return;
|
||
405 | } |
||
406 | 34294 | fdiaz | |
407 | 38207 | cordinyana | taskStatus.message("Drawing");
|
408 | drawFeatures(image, g, viewPort, cancel, coordTrans, dpi, |
||
409 | drawnNotification, featureSet, selection); |
||
410 | |||
411 | } catch (BaseException e) {
|
||
412 | throw new LegendDrawingException(e); |
||
413 | } finally {
|
||
414 | if (featureSet != null) { |
||
415 | featureSet.dispose(); |
||
416 | } |
||
417 | } |
||
418 | } |
||
419 | |||
420 | 35329 | jpiera | /**
|
421 | * Complete a {@link FeatureQuery} to load the {@link Feature}s to draw.
|
||
422 | */
|
||
423 | @SuppressWarnings("unchecked") |
||
424 | private FeatureQuery completeQuery(FeatureStore featureStore, FeatureQuery featureQuery, double scale, |
||
425 | Map queryParameters, ICoordTrans coordTrans,
|
||
426 | IProjection dataProjection, Envelope viewPortEnvelope, |
||
427 | boolean containsAll) throws DataException { |
||
428 | 34294 | fdiaz | |
429 | 35329 | jpiera | featureQuery.setScale(scale); |
430 | |||
431 | //Adds the attributes
|
||
432 | String[] fieldNames = getRequiredFeatureAttributeNames(featureStore); |
||
433 | for (int i=0 ; i<fieldNames.length ;i++){ |
||
434 | featureQuery.addAttributeName(fieldNames[i]); |
||
435 | } |
||
436 | |||
437 | // TODO: Mobile has it's own IntersectsEnvelopeEvaluator
|
||
438 | if (!containsAll) {
|
||
439 | // Gets the viewport envelope with the data SRS
|
||
440 | Envelope viewPortEnvelopeInMyProj = viewPortEnvelope; |
||
441 | // FIXME
|
||
442 | if (coordTrans != null) { |
||
443 | viewPortEnvelopeInMyProj = viewPortEnvelope.convert(coordTrans |
||
444 | .getInverted()); |
||
445 | } |
||
446 | 34294 | fdiaz | |
447 | 35329 | jpiera | if (dataProjection == null) { |
448 | throw new IllegalArgumentException( |
||
449 | "Error, the projection parameter value is null");
|
||
450 | } |
||
451 | 34294 | fdiaz | |
452 | 35329 | jpiera | IntersectsEnvelopeEvaluator iee = new IntersectsEnvelopeEvaluator(
|
453 | viewPortEnvelopeInMyProj, dataProjection, |
||
454 | featureStore.getDefaultFeatureType(), featureStore |
||
455 | .getDefaultFeatureType() |
||
456 | .getDefaultGeometryAttributeName()); |
||
457 | featureQuery.addFilter(iee); |
||
458 | } |
||
459 | if (queryParameters != null) { |
||
460 | Iterator iterEntry = queryParameters.entrySet().iterator();
|
||
461 | Entry entry; |
||
462 | while (iterEntry.hasNext()) {
|
||
463 | entry = (Entry) iterEntry.next(); |
||
464 | featureQuery.setQueryParameter((String) entry.getKey(),
|
||
465 | entry.getValue()); |
||
466 | } |
||
467 | } |
||
468 | return featureQuery;
|
||
469 | } |
||
470 | 34294 | fdiaz | |
471 | 35329 | jpiera | /**
|
472 | * Draws the features from the {@link FeatureSet}, with the symbols of the
|
||
473 | * legend.
|
||
474 | */
|
||
475 | private void drawFeatures(BufferedImage image, Graphics2D g, |
||
476 | ViewPort viewPort, Cancellable cancel, ICoordTrans coordTrans, |
||
477 | double dpi, DefaultFeatureDrawnNotification drawnNotification,
|
||
478 | FeatureSet featureSet, FeatureSelection selection) |
||
479 | throws BaseException {
|
||
480 | if (isUseZSort()) {
|
||
481 | drawFeaturesMultiLayer(image, g, viewPort, cancel, coordTrans, dpi, |
||
482 | drawnNotification, featureSet, selection); |
||
483 | } else {
|
||
484 | drawFeaturesSingleLayer(image, g, viewPort, cancel, coordTrans, |
||
485 | dpi, drawnNotification, featureSet, selection); |
||
486 | } |
||
487 | } |
||
488 | 34294 | fdiaz | |
489 | 35329 | jpiera | /**
|
490 | * Draws the features from the {@link FeatureSet}, with the symbols of the
|
||
491 | * legend, using a single drawing layer.
|
||
492 | */
|
||
493 | private void drawFeaturesSingleLayer(final BufferedImage image, |
||
494 | final Graphics2D g, final ViewPort viewPort, |
||
495 | final Cancellable cancel, final ICoordTrans coordTrans, |
||
496 | final double dpi, |
||
497 | final DefaultFeatureDrawnNotification drawnNotification,
|
||
498 | FeatureSet featureSet, final FeatureSelection selection)
|
||
499 | throws BaseException {
|
||
500 | 34294 | fdiaz | |
501 | 35329 | jpiera | try {
|
502 | featureSet.accept(new Visitor() {
|
||
503 | public void visit(Object obj) throws VisitCanceledException, |
||
504 | BaseException { |
||
505 | Feature feat = (Feature) obj; |
||
506 | drawFeatureSingleLayer(image, g, viewPort, cancel, |
||
507 | coordTrans, dpi, drawnNotification, feat, selection); |
||
508 | } |
||
509 | }); |
||
510 | 34294 | fdiaz | |
511 | 35329 | jpiera | } catch (ConcurrentDataModificationException e) {
|
512 | cancel.setCanceled(true);
|
||
513 | return;
|
||
514 | } |
||
515 | } |
||
516 | 34294 | fdiaz | |
517 | 35329 | jpiera | /**
|
518 | * Draws a Feature with the symbols of the legend, using a single drawing
|
||
519 | * layer.
|
||
520 | */
|
||
521 | private void drawFeatureSingleLayer(BufferedImage image, Graphics2D g, |
||
522 | ViewPort viewPort, Cancellable cancel, ICoordTrans coordTrans, |
||
523 | double dpi, DefaultFeatureDrawnNotification drawnNotification,
|
||
524 | Feature feat, FeatureSelection selection) |
||
525 | throws MapContextException, CreateGeometryException {
|
||
526 | 34294 | fdiaz | |
527 | 35329 | jpiera | Geometry geom = feat.getDefaultGeometry(); |
528 | if (geom == null) { |
||
529 | return;
|
||
530 | } |
||
531 | 34294 | fdiaz | |
532 | 35329 | jpiera | if (geom.getType() == Geometry.TYPES.NULL) {
|
533 | return;
|
||
534 | } |
||
535 | 34294 | fdiaz | |
536 | 35329 | jpiera | ISymbol sym = getSymbol(feat, selection); |
537 | if (sym == null) { |
||
538 | return;
|
||
539 | } |
||
540 | 34294 | fdiaz | |
541 | 35329 | jpiera | if (coordTrans != null) { |
542 | geom = geom.cloneGeometry(); |
||
543 | geom.reProject(coordTrans); |
||
544 | } |
||
545 | 34294 | fdiaz | |
546 | 35329 | jpiera | if (cancel.isCanceled()) {
|
547 | return;
|
||
548 | } |
||
549 | 34294 | fdiaz | |
550 | 35329 | jpiera | drawGeometry(geom, image, feat, sym, viewPort, g, dpi, cancel); |
551 | 34294 | fdiaz | |
552 | 35329 | jpiera | // Notify the drawing observers
|
553 | drawnNotification.setFeature(feat); |
||
554 | drawnNotification.setDrawnGeometry(geom); |
||
555 | notifyObservers(drawnNotification); |
||
556 | } |
||
557 | 34294 | fdiaz | |
558 | 35329 | jpiera | /**
|
559 | * Draws the features from the {@link FeatureSet}, with the symbols of the
|
||
560 | * legend, using a multiple drawing layer.
|
||
561 | */
|
||
562 | private void drawFeaturesMultiLayer(BufferedImage image, Graphics2D g, |
||
563 | ViewPort viewPort, Cancellable cancel, ICoordTrans coordTrans, |
||
564 | double dpi, DefaultFeatureDrawnNotification drawnNotification,
|
||
565 | FeatureSet featureSet, FeatureSelection selection) |
||
566 | throws MapContextException, CreateGeometryException, DataException {
|
||
567 | 34294 | fdiaz | |
568 | 35329 | jpiera | // -- visual FX stuff
|
569 | long time = System.currentTimeMillis(); |
||
570 | 34294 | fdiaz | |
571 | 35329 | jpiera | boolean bSymbolLevelError = false; |
572 | // render temporary map each screenRefreshRate milliseconds;
|
||
573 | int screenRefreshDelay = (int) ((1D / MapContext.getDrawFrameRate()) * 3 * 1000); |
||
574 | BufferedImage[] imageLevels = null; |
||
575 | Graphics2D[] graphics = null; |
||
576 | 34294 | fdiaz | |
577 | 35329 | jpiera | imageLevels = new BufferedImage[getZSort().getLevelCount()]; |
578 | graphics = new Graphics2D[imageLevels.length]; |
||
579 | for (int i = 0; !cancel.isCanceled() && i < imageLevels.length; i++) { |
||
580 | 34294 | fdiaz | |
581 | 35329 | jpiera | imageLevels[i] = CompatLocator.getGraphicsUtils() |
582 | .createBufferedImage(image.getWidth(), image.getHeight(), |
||
583 | image.getType()); |
||
584 | 34294 | fdiaz | |
585 | 35329 | jpiera | graphics[i] = imageLevels[i].createGraphics(); |
586 | graphics[i].setTransform(g.getTransform()); |
||
587 | graphics[i].setRenderingHints(g.getRenderingHints()); |
||
588 | } |
||
589 | // -- end visual FX stuff
|
||
590 | 34294 | fdiaz | |
591 | 35329 | jpiera | DisposableIterator it = null;
|
592 | try {
|
||
593 | it = featureSet.fastIterator(); |
||
594 | // Iteration over each feature
|
||
595 | while (it.hasNext()) {
|
||
596 | if (cancel.isCanceled()) {
|
||
597 | return;
|
||
598 | } |
||
599 | Feature feat = (Feature) it.next(); |
||
600 | 34294 | fdiaz | |
601 | 35329 | jpiera | bSymbolLevelError |= drawFeatureMultiLayer(image, g, viewPort, |
602 | cancel, coordTrans, dpi, drawnNotification, selection, |
||
603 | time, screenRefreshDelay, imageLevels, graphics, feat); |
||
604 | 34294 | fdiaz | |
605 | 35329 | jpiera | } |
606 | } catch (ConcurrentDataModificationException e) {
|
||
607 | cancel.setCanceled(true);
|
||
608 | return;
|
||
609 | } finally {
|
||
610 | if (it != null) { |
||
611 | it.dispose(); |
||
612 | } |
||
613 | } |
||
614 | 34294 | fdiaz | |
615 | 35329 | jpiera | g.drawImage(image, 0, 0, null); |
616 | 34294 | fdiaz | |
617 | 35329 | jpiera | Point2D offset = viewPort.getOffset();
|
618 | CompatLocator.getGraphicsUtils().translate(g, offset.getX(), |
||
619 | offset.getY()); |
||
620 | 34294 | fdiaz | |
621 | 35329 | jpiera | for (int i = 0; !cancel.isCanceled() && i < imageLevels.length; i++) { |
622 | g.drawImage(imageLevels[i], 0, 0, null); |
||
623 | imageLevels[i] = null;
|
||
624 | graphics[i] = null;
|
||
625 | } |
||
626 | 34294 | fdiaz | |
627 | 35329 | jpiera | CompatLocator.getGraphicsUtils().translate(g, -offset.getX(), |
628 | -offset.getY()); |
||
629 | 34294 | fdiaz | |
630 | 35329 | jpiera | imageLevels = null;
|
631 | graphics = null;
|
||
632 | 34294 | fdiaz | |
633 | 35329 | jpiera | if (bSymbolLevelError) {
|
634 | setZSort(null);
|
||
635 | } |
||
636 | } |
||
637 | 34294 | fdiaz | |
638 | 35329 | jpiera | /**
|
639 | * Draws a Feature with the symbols of the legend, using a multiple drawing
|
||
640 | * layer.
|
||
641 | */
|
||
642 | private boolean drawFeatureMultiLayer(BufferedImage image, Graphics2D g, |
||
643 | ViewPort viewPort, Cancellable cancel, ICoordTrans coordTrans, |
||
644 | double dpi, DefaultFeatureDrawnNotification drawnNotification,
|
||
645 | FeatureSelection selection, long time, int screenRefreshDelay, |
||
646 | BufferedImage[] imageLevels, Graphics2D[] graphics, Feature feat) |
||
647 | throws MapContextException, CreateGeometryException {
|
||
648 | 34294 | fdiaz | |
649 | 35329 | jpiera | Geometry geom = feat.getDefaultGeometry(); |
650 | boolean bSymbolLevelError = false; |
||
651 | long drawingTime = time;
|
||
652 | 34294 | fdiaz | |
653 | 35329 | jpiera | if (geom.getType() == Geometry.TYPES.NULL) {
|
654 | return false; |
||
655 | } |
||
656 | 34294 | fdiaz | |
657 | 35329 | jpiera | ISymbol sym = getSymbol(feat, selection); |
658 | 34294 | fdiaz | |
659 | 35329 | jpiera | if (sym == null) { |
660 | return false; |
||
661 | } |
||
662 | 34294 | fdiaz | |
663 | 35329 | jpiera | if (coordTrans != null) { |
664 | geom = geom.cloneGeometry(); |
||
665 | geom.reProject(coordTrans); |
||
666 | } |
||
667 | 34294 | fdiaz | |
668 | 35329 | jpiera | if (cancel.isCanceled()) {
|
669 | return false; |
||
670 | } |
||
671 | 34294 | fdiaz | |
672 | 35329 | jpiera | // Check if this symbol is a multilayer
|
673 | int[] symLevels = getZSort().getLevels(sym); |
||
674 | if (sym instanceof IMultiLayerSymbol) { |
||
675 | // if so, treat each of its layers as a single
|
||
676 | // symbol
|
||
677 | // in its corresponding map level
|
||
678 | IMultiLayerSymbol mlSym = (IMultiLayerSymbol) sym; |
||
679 | for (int i = 0; !cancel.isCanceled() && i < mlSym.getLayerCount(); i++) { |
||
680 | ISymbol mySym = mlSym.getLayer(i); |
||
681 | int symbolLevel = 0; |
||
682 | if (symLevels != null) { |
||
683 | symbolLevel = symLevels[i]; |
||
684 | } else {
|
||
685 | /*
|
||
686 | * an error occured when managing symbol levels some of the
|
||
687 | * legend changed events regarding the symbols did not
|
||
688 | * finish satisfactory and the legend is now inconsistent.
|
||
689 | * For this drawing, it will finish as it was at the bottom
|
||
690 | * (level 0) but, when done, the ZSort will be reset to
|
||
691 | * avoid app crashes. This is a bug that has to be fixed.
|
||
692 | */
|
||
693 | bSymbolLevelError = true;
|
||
694 | } |
||
695 | drawGeometry(geom, imageLevels[symbolLevel], feat, mySym, |
||
696 | viewPort, graphics[symbolLevel], dpi, cancel); |
||
697 | } |
||
698 | } else {
|
||
699 | // else, just draw the symbol in its level
|
||
700 | int symbolLevel = 0; |
||
701 | if (symLevels != null) { |
||
702 | symbolLevel = symLevels[0];
|
||
703 | } |
||
704 | drawGeometry(geom, imageLevels[symbolLevel], feat, sym, viewPort, |
||
705 | graphics[symbolLevel], dpi, cancel); |
||
706 | } |
||
707 | 34294 | fdiaz | |
708 | 35329 | jpiera | // -- visual FX stuff
|
709 | // Cuando el offset!=0 se est? dibujando sobre el
|
||
710 | // Layout y por tanto no tiene que ejecutar el
|
||
711 | // siguiente c?digo.
|
||
712 | Point2D offset = viewPort.getOffset();
|
||
713 | if (offset.getX() == 0 && offset.getY() == 0) { |
||
714 | if ((System.currentTimeMillis() - drawingTime) > screenRefreshDelay) { |
||
715 | 34294 | fdiaz | |
716 | 35329 | jpiera | BufferedImage virtualBim = CompatLocator.getGraphicsUtils()
|
717 | .createBufferedImage(image.getWidth(), |
||
718 | image.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||
719 | 34294 | fdiaz | |
720 | 35329 | jpiera | Graphics2D virtualGraphics = virtualBim.createGraphics();
|
721 | virtualGraphics.drawImage(image, 0, 0, null); |
||
722 | for (int i = 0; !cancel.isCanceled() && i < imageLevels.length; i++) { |
||
723 | virtualGraphics.drawImage(imageLevels[i], 0, 0, null); |
||
724 | } |
||
725 | g.clearRect(0, 0, image.getWidth(), image.getHeight()); |
||
726 | g.drawImage(virtualBim, 0, 0, null); |
||
727 | drawingTime = System.currentTimeMillis();
|
||
728 | } |
||
729 | // -- end visual FX stuff
|
||
730 | 34294 | fdiaz | |
731 | 35329 | jpiera | } |
732 | // Notify the drawing observers
|
||
733 | drawnNotification.setFeature(feat); |
||
734 | drawnNotification.setDrawnGeometry(geom); |
||
735 | notifyObservers(drawnNotification); |
||
736 | return bSymbolLevelError;
|
||
737 | } |
||
738 | 34294 | fdiaz | |
739 | 35329 | jpiera | /**
|
740 | * Returns the symbol to use to draw a {@link Feature} taking into account
|
||
741 | * if it is selected.
|
||
742 | */
|
||
743 | private ISymbol getSymbol(Feature feat, FeatureSelection selection)
|
||
744 | throws MapContextException {
|
||
745 | // retrieve the symbol associated to such feature
|
||
746 | ISymbol sym = getSymbolByFeature(feat); |
||
747 | 34294 | fdiaz | |
748 | 35329 | jpiera | if (sym != null && selection.isSelected(feat)) { |
749 | sym = sym.getSymbolForSelection(); |
||
750 | } |
||
751 | return sym;
|
||
752 | } |
||
753 | 34294 | fdiaz | |
754 | 35329 | jpiera | /**
|
755 | * Returns if the legend is using a ZSort.
|
||
756 | */
|
||
757 | private boolean isUseZSort() { |
||
758 | return getZSort() != null && getZSort().isUsingZSort(); |
||
759 | } |
||
760 | 34294 | fdiaz | |
761 | 35329 | jpiera | /**
|
762 | * Draws a {@link Geometry} using the given {@link ISymbol}, over the
|
||
763 | * {@link Graphics2D} object.
|
||
764 | */
|
||
765 | private void drawGeometry(Geometry geom, BufferedImage image, |
||
766 | Feature feature, ISymbol symbol, ViewPort viewPort, |
||
767 | Graphics2D graphics, double dpi, Cancellable cancellable) |
||
768 | throws CreateGeometryException {
|
||
769 | 34294 | fdiaz | |
770 | 35329 | jpiera | if (geom instanceof Aggregate) { |
771 | drawAggregate((Aggregate) geom, image, feature, symbol, viewPort, |
||
772 | graphics, dpi, cancellable); |
||
773 | } else {
|
||
774 | boolean bDrawCartographicSupport = false; |
||
775 | if (symbol instanceof CartographicSupport) { |
||
776 | bDrawCartographicSupport = ((CartographicSupport) symbol) |
||
777 | .getUnit() != -1;
|
||
778 | } |
||
779 | 34294 | fdiaz | |
780 | 35329 | jpiera | double previousSize = 0.0d; |
781 | 34294 | fdiaz | |
782 | 35329 | jpiera | if (bDrawCartographicSupport) {
|
783 | // make the symbol to resize itself with the current rendering
|
||
784 | // context
|
||
785 | previousSize = ((CartographicSupport) symbol) |
||
786 | .toCartographicSize(viewPort, dpi, geom); |
||
787 | } |
||
788 | 34294 | fdiaz | |
789 | 35329 | jpiera | try {
|
790 | // draw it as normally
|
||
791 | double[] dot = new double[2]; |
||
792 | boolean onePoint = symbol.isOneDotOrPixel(geom, dot, viewPort,
|
||
793 | (int) dpi);
|
||
794 | 34294 | fdiaz | |
795 | 35329 | jpiera | if (onePoint) {
|
796 | if (dot[0] < 0 || dot[1] < 0 || dot[0] >= image.getWidth() |
||
797 | || dot[1] >= image.getHeight()) {
|
||
798 | return;
|
||
799 | } |
||
800 | // FIXME: setRgb should change to draw
|
||
801 | image.setRGB((int) dot[0], (int) dot[1], |
||
802 | symbol.getOnePointRgb()); |
||
803 | } else {
|
||
804 | symbol.draw(graphics, viewPort.getAffineTransform(), |
||
805 | 35472 | jpiera | geom, feature, cancellable); |
806 | 35329 | jpiera | } |
807 | 34294 | fdiaz | |
808 | 35329 | jpiera | } finally {
|
809 | if (bDrawCartographicSupport) {
|
||
810 | // restore previous size
|
||
811 | ((CartographicSupport) symbol).setCartographicSize( |
||
812 | previousSize, geom); |
||
813 | } |
||
814 | } |
||
815 | } |
||
816 | } |
||
817 | 34294 | fdiaz | |
818 | 35329 | jpiera | /**
|
819 | * Draws an {@link Aggregate} using the given {@link ISymbol}, over the
|
||
820 | * {@link Graphics2D} object.
|
||
821 | */
|
||
822 | private void drawAggregate(Aggregate aggregate, BufferedImage image, |
||
823 | Feature feature, ISymbol symbol, ViewPort viewPort, |
||
824 | Graphics2D graphics, double dpi, Cancellable cancellable) |
||
825 | throws CreateGeometryException {
|
||
826 | for (int i = 0; i < aggregate.getPrimitivesNumber(); i++) { |
||
827 | Geometry prim = aggregate.getPrimitiveAt(i); |
||
828 | drawGeometry(prim, image, feature, symbol, viewPort, graphics, dpi, |
||
829 | cancellable); |
||
830 | } |
||
831 | } |
||
832 | 34294 | fdiaz | |
833 | 35329 | jpiera | public Object clone() throws CloneNotSupportedException { |
834 | AbstractVectorialLegend clone = (AbstractVectorialLegend) super.clone();
|
||
835 | 34294 | fdiaz | |
836 | 35329 | jpiera | // Clone zSort
|
837 | ZSort zSort = getZSort(); |
||
838 | if (zSort != null) { |
||
839 | clone.setZSort(new ZSort(clone));
|
||
840 | } |
||
841 | return clone;
|
||
842 | } |
||
843 | 34294 | fdiaz | |
844 | 35329 | jpiera | public void loadFromState(PersistentState state) |
845 | throws PersistenceException {
|
||
846 | // Set parent properties
|
||
847 | super.loadFromState(state);
|
||
848 | // Set own properties
|
||
849 | 34294 | fdiaz | |
850 | 35329 | jpiera | setShapeType(state.getInt(FIELD_SHAPETYPE)); |
851 | if (state.getBoolean(FIELD_HAS_ZSORT)) {
|
||
852 | setZSort(new ZSort(this)); |
||
853 | } |
||
854 | setDefaultSymbol((ISymbol) state.get(FIELD_DEFAULT_SYMBOL)); |
||
855 | } |
||
856 | 34294 | fdiaz | |
857 | 35329 | jpiera | public void saveToState(PersistentState state) throws PersistenceException { |
858 | // Save parent properties
|
||
859 | super.saveToState(state);
|
||
860 | // Save own properties
|
||
861 | state.set(FIELD_SHAPETYPE, getShapeType()); |
||
862 | state.set(FIELD_HAS_ZSORT, this.zSort != null); |
||
863 | state.set(FIELD_DEFAULT_SYMBOL, getDefaultSymbol()); |
||
864 | } |
||
865 | 34294 | fdiaz | |
866 | 35329 | jpiera | public static class RegisterPersistence implements Callable { |
867 | 34294 | fdiaz | |
868 | 35329 | jpiera | public Object call() throws Exception { |
869 | PersistenceManager manager = ToolsLocator.getPersistenceManager(); |
||
870 | if (manager
|
||
871 | .getDefinition(VECTORIAL_LEGEND_PERSISTENCE_DEFINITION_NAME) == null) {
|
||
872 | DynStruct definition = manager.addDefinition( |
||
873 | AbstractVectorialLegend.class, |
||
874 | VECTORIAL_LEGEND_PERSISTENCE_DEFINITION_NAME, |
||
875 | VECTORIAL_LEGEND_PERSISTENCE_DEFINITION_NAME |
||
876 | + " persistence definition", null, null); |
||
877 | // Extend the Legend base definition
|
||
878 | definition.extend(manager |
||
879 | .getDefinition(LEGEND_PERSISTENCE_DEFINITION_NAME)); |
||
880 | 34935 | jjdelcerro | |
881 | 35329 | jpiera | // Shapetype
|
882 | definition.addDynFieldInt(FIELD_SHAPETYPE).setMandatory(true);
|
||
883 | // ZSort
|
||
884 | definition.addDynFieldBoolean(FIELD_HAS_ZSORT).setMandatory( |
||
885 | true);
|
||
886 | // Default symbol
|
||
887 | definition.addDynFieldObject(FIELD_DEFAULT_SYMBOL) |
||
888 | .setClassOfValue(ISymbol.class).setMandatory(true);
|
||
889 | } |
||
890 | return Boolean.TRUE; |
||
891 | } |
||
892 | 34935 | jjdelcerro | |
893 | 35329 | jpiera | } |
894 | 34935 | jjdelcerro | |
895 | 35329 | jpiera | /**
|
896 | * Returns the names of the {@link Feature} attributes required for the
|
||
897 | * {@link ILegend} to operate.
|
||
898 | *
|
||
899 | * @param featureStore
|
||
900 | * the store where the {@link Feature}s belong to
|
||
901 | * @return the names of required {@link Feature} attribute names
|
||
902 | * @throws DataException
|
||
903 | * if there is an error getting the attribute names
|
||
904 | */
|
||
905 | protected abstract String[] getRequiredFeatureAttributeNames( |
||
906 | FeatureStore featureStore) throws DataException;
|
||
907 | 38221 | cordinyana | } |