svn-gvsig-desktop / trunk / extensions / extSymbology / src / org / gvsig / symbology / fmap / labeling / GeneralLabelingStrategy.java @ 23918
History | View | Annotate | Download (20.4 KB)
1 | 20768 | jdominguez | /* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
---|---|---|---|
2 | *
|
||
3 | * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
|
||
4 | *
|
||
5 | * This program is free software; you can redistribute it and/or
|
||
6 | * modify it under the terms of the GNU General Public License
|
||
7 | * as published by the Free Software Foundation; either version 2
|
||
8 | * of the License, or (at your option) any later version.
|
||
9 | *
|
||
10 | * This program is distributed in the hope that it will be useful,
|
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
13 | * GNU General Public License for more details.
|
||
14 | *
|
||
15 | * You should have received a copy of the GNU General Public License
|
||
16 | * along with this program; if not, write to the Free Software
|
||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
||
18 | *
|
||
19 | * For more information, contact:
|
||
20 | *
|
||
21 | * Generalitat Valenciana
|
||
22 | * Conselleria d'Infraestructures i Transport
|
||
23 | * Av. Blasco Ib??ez, 50
|
||
24 | * 46010 VALENCIA
|
||
25 | * SPAIN
|
||
26 | *
|
||
27 | * +34 963862235
|
||
28 | * gvsig@gva.es
|
||
29 | * www.gvsig.gva.es
|
||
30 | *
|
||
31 | * or
|
||
32 | *
|
||
33 | * IVER T.I. S.A
|
||
34 | * Salamanca 50
|
||
35 | * 46005 Valencia
|
||
36 | * Spain
|
||
37 | *
|
||
38 | * +34 963163400
|
||
39 | * dac@iver.es
|
||
40 | */
|
||
41 | |||
42 | /* CVS MESSAGES:
|
||
43 | *
|
||
44 | * $Id: GeneralLabelingStrategy.java 13749 2007-09-17 14:16:11Z jaume $
|
||
45 | * $Log$
|
||
46 | * Revision 1.2 2007-09-17 14:16:11 jaume
|
||
47 | * multilayer symbols sizing bug fixed
|
||
48 | *
|
||
49 | * Revision 1.1 2007/05/22 12:17:41 jaume
|
||
50 | * *** empty log message ***
|
||
51 | *
|
||
52 | * Revision 1.1 2007/05/22 10:05:31 jaume
|
||
53 | * *** empty log message ***
|
||
54 | *
|
||
55 | * Revision 1.10 2007/05/17 09:32:06 jaume
|
||
56 | * *** empty log message ***
|
||
57 | *
|
||
58 | * Revision 1.9 2007/05/09 11:04:58 jaume
|
||
59 | * refactored legend hierarchy
|
||
60 | *
|
||
61 | * Revision 1.8 2007/04/13 11:59:30 jaume
|
||
62 | * *** empty log message ***
|
||
63 | *
|
||
64 | * Revision 1.7 2007/04/12 14:28:43 jaume
|
||
65 | * basic labeling support for lines
|
||
66 | *
|
||
67 | * Revision 1.6 2007/04/11 16:01:08 jaume
|
||
68 | * maybe a label placer refactor
|
||
69 | *
|
||
70 | * Revision 1.5 2007/04/10 16:34:01 jaume
|
||
71 | * towards a styled labeling
|
||
72 | *
|
||
73 | * Revision 1.4 2007/04/02 16:34:56 jaume
|
||
74 | * Styled labeling (start commiting)
|
||
75 | *
|
||
76 | * Revision 1.3 2007/03/28 16:48:01 jaume
|
||
77 | * *** empty log message ***
|
||
78 | *
|
||
79 | * Revision 1.2 2007/03/26 14:40:38 jaume
|
||
80 | * added print method (BUT UNIMPLEMENTED)
|
||
81 | *
|
||
82 | * Revision 1.1 2007/03/20 16:16:20 jaume
|
||
83 | * refactored to use ISymbol instead of FSymbol
|
||
84 | *
|
||
85 | * Revision 1.2 2007/03/09 11:20:57 jaume
|
||
86 | * Advanced symbology (start committing)
|
||
87 | *
|
||
88 | * Revision 1.1 2007/03/09 08:33:43 jaume
|
||
89 | * *** empty log message ***
|
||
90 | *
|
||
91 | * Revision 1.1.2.5 2007/02/21 07:34:08 jaume
|
||
92 | * labeling starts working
|
||
93 | *
|
||
94 | * Revision 1.1.2.4 2007/02/15 16:23:44 jaume
|
||
95 | * *** empty log message ***
|
||
96 | *
|
||
97 | * Revision 1.1.2.3 2007/02/09 07:47:05 jaume
|
||
98 | * Isymbol moved
|
||
99 | *
|
||
100 | * Revision 1.1.2.2 2007/02/02 16:21:24 jaume
|
||
101 | * start commiting labeling stuff
|
||
102 | *
|
||
103 | * Revision 1.1.2.1 2007/02/01 17:46:49 jaume
|
||
104 | * *** empty log message ***
|
||
105 | *
|
||
106 | *
|
||
107 | */
|
||
108 | package org.gvsig.symbology.fmap.labeling; |
||
109 | |||
110 | import java.awt.Graphics2D; |
||
111 | 23367 | vcaballero | import java.awt.geom.NoninvertibleTransformException; |
112 | import java.awt.geom.PathIterator; |
||
113 | import java.awt.geom.Point2D; |
||
114 | 20768 | jdominguez | import java.awt.geom.Rectangle2D; |
115 | import java.awt.image.BufferedImage; |
||
116 | import java.io.CharArrayReader; |
||
117 | 22516 | jvidal | import java.io.StringReader; |
118 | 20768 | jdominguez | import java.text.NumberFormat; |
119 | import java.util.ArrayList; |
||
120 | 22187 | jdominguez | import java.util.Hashtable; |
121 | 20768 | jdominguez | import java.util.TreeSet; |
122 | |||
123 | import javax.print.attribute.PrintRequestAttributeSet; |
||
124 | |||
125 | import org.apache.log4j.Logger; |
||
126 | import org.cresques.cts.ICoordTrans; |
||
127 | import org.gvsig.symbology.fmap.labeling.parse.LabelExpressionParser; |
||
128 | import org.gvsig.symbology.fmap.labeling.parse.ParseException; |
||
129 | import org.gvsig.symbology.fmap.labeling.placements.ILabelPlacement; |
||
130 | 22082 | vcaballero | import org.gvsig.symbology.fmap.labeling.placements.LinePlacementConstraints; |
131 | import org.gvsig.symbology.fmap.labeling.placements.MultiShapePlacementConstraints; |
||
132 | import org.gvsig.symbology.fmap.labeling.placements.PointPlacementConstraints; |
||
133 | import org.gvsig.symbology.fmap.labeling.placements.PolygonPlacementConstraints; |
||
134 | 20768 | jdominguez | import org.gvsig.symbology.fmap.labeling.placements.RemoveDuplicatesComparator; |
135 | 22187 | jdominguez | import org.gvsig.symbology.fmap.rendering.filter.operations.Expression; |
136 | import org.gvsig.symbology.fmap.rendering.filter.operations.ExpressionException; |
||
137 | 23367 | vcaballero | import org.gvsig.symbology.fmap.symbols.SmartTextSymbol; |
138 | 20768 | jdominguez | |
139 | import com.hardcode.gdbms.driver.exceptions.ReadDriverException; |
||
140 | import com.hardcode.gdbms.engine.values.Value; |
||
141 | import com.iver.cit.gvsig.fmap.ViewPort; |
||
142 | import com.iver.cit.gvsig.fmap.core.FShape; |
||
143 | 23367 | vcaballero | import com.iver.cit.gvsig.fmap.core.GeneralPathX; |
144 | 20768 | jdominguez | import com.iver.cit.gvsig.fmap.core.IFeature; |
145 | import com.iver.cit.gvsig.fmap.core.IGeometry; |
||
146 | 23367 | vcaballero | import com.iver.cit.gvsig.fmap.core.SymbologyFactory; |
147 | import com.iver.cit.gvsig.fmap.core.symbols.ITextSymbol; |
||
148 | import com.iver.cit.gvsig.fmap.core.v02.FConstant; |
||
149 | 20768 | jdominguez | import com.iver.cit.gvsig.fmap.core.v02.FConverter; |
150 | import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator; |
||
151 | import com.iver.cit.gvsig.fmap.layers.FLayer; |
||
152 | import com.iver.cit.gvsig.fmap.layers.FLyrVect; |
||
153 | import com.iver.cit.gvsig.fmap.rendering.styling.labeling.ILabelingMethod; |
||
154 | import com.iver.cit.gvsig.fmap.rendering.styling.labeling.ILabelingStrategy; |
||
155 | import com.iver.cit.gvsig.fmap.rendering.styling.labeling.IPlacementConstraints; |
||
156 | import com.iver.cit.gvsig.fmap.rendering.styling.labeling.IZoomConstraints; |
||
157 | import com.iver.cit.gvsig.fmap.rendering.styling.labeling.LabelClass; |
||
158 | import com.iver.cit.gvsig.fmap.rendering.styling.labeling.LabelLocationMetrics; |
||
159 | import com.iver.cit.gvsig.fmap.rendering.styling.labeling.LabelingFactory; |
||
160 | import com.iver.utiles.XMLEntity; |
||
161 | import com.iver.utiles.swing.threads.Cancellable; |
||
162 | |||
163 | /**
|
||
164 | 22516 | jvidal | *
|
165 | 20768 | jdominguez | * GeneralLabelingStrategy.java
|
166 | *
|
||
167 | 22516 | jvidal | *
|
168 | 20768 | jdominguez | * @author jaume dominguez faus - jaume.dominguez@iver.es Jan 4, 2008
|
169 | *
|
||
170 | */
|
||
171 | 20905 | jdominguez | public class GeneralLabelingStrategy implements ILabelingStrategy, Cloneable { |
172 | 22082 | vcaballero | public static IPlacementConstraints DefaultPointPlacementConstraints = new PointPlacementConstraints(); |
173 | public static IPlacementConstraints DefaultLinePlacementConstraints = new LinePlacementConstraints(); |
||
174 | public static IPlacementConstraints DefaultPolygonPlacementConstraints = new PolygonPlacementConstraints(); |
||
175 | 22216 | jdominguez | private static String[] NO_TEXT = new String[] { "text " }; |
176 | 22082 | vcaballero | private static MultiShapePlacementConstraints DefaultMultiShapePlacementConstratints = new MultiShapePlacementConstraints(); |
177 | 20768 | jdominguez | private ILabelingMethod method;
|
178 | private IPlacementConstraints placementConstraints;
|
||
179 | protected FLyrVect layer;
|
||
180 | private IZoomConstraints zoomConstraints;
|
||
181 | private boolean allowOverlapping; |
||
182 | 22082 | vcaballero | private long parseTime; |
183 | 22516 | jvidal | |
184 | 20768 | jdominguez | public void setLayer(FLayer layer) throws ReadDriverException { |
185 | FLyrVect l = (FLyrVect) layer; |
||
186 | this.layer = l;
|
||
187 | } |
||
188 | |||
189 | public ILabelingMethod getLabelingMethod() {
|
||
190 | return method;
|
||
191 | } |
||
192 | |||
193 | public void setLabelingMethod(ILabelingMethod method) { |
||
194 | this.method = method;
|
||
195 | } |
||
196 | |||
197 | 22160 | vcaballero | public void draw(BufferedImage mapImage, Graphics2D mapGraphics, |
198 | ViewPort viewPort, Cancellable cancel, double dpi) throws ReadDriverException { |
||
199 | |||
200 | // boolean bVisualFXEnabled = false; // if true, the user can see how the labeling is drawing up
|
||
201 | 20768 | jdominguez | TreeSet<?> placedLabels = null; |
202 | 22082 | vcaballero | parseTime =0;
|
203 | 20768 | jdominguez | long t1 = System.currentTimeMillis(); |
204 | String[] usedFields = getUsedFields(); |
||
205 | 22516 | jvidal | |
206 | 20768 | jdominguez | int notPlacedCount = 0; |
207 | int placedCount = 0; |
||
208 | 22516 | jvidal | |
209 | 22160 | vcaballero | /*
|
210 | * Get the label placement solvers according the user's settings
|
||
211 | */
|
||
212 | 20768 | jdominguez | ILabelPlacement placement = PlacementManager.getPlacement(getPlacementConstraints(), layer.getShapeType()); |
213 | |||
214 | 22516 | jvidal | /*
|
215 | * get an ordered set of the LabelClasses up on the
|
||
216 | 20768 | jdominguez | * label priority
|
217 | */
|
||
218 | LabelClass[] lcs = method.getLabelClasses();
|
||
219 | TreeSet<LabelClass> ts = new TreeSet<LabelClass>(new LabelClassComparatorByPriority()); |
||
220 | |||
221 | for (int i = 0; i < lcs.length; i++) ts.add(lcs[i]); |
||
222 | 22516 | jvidal | |
223 | 22160 | vcaballero | if (ts.size()==0) return; |
224 | 22516 | jvidal | |
225 | 22160 | vcaballero | // // -- visual FX stuff
|
226 | // BufferedImage visualFXim = null;
|
||
227 | // Graphics2D visualFXgr = null;
|
||
228 | // if (bVisualFXEnabled) {
|
||
229 | // visualFXim = new BufferedImage(mapImage.getWidth(),
|
||
230 | // mapImage.getHeight(),
|
||
231 | // BufferedImage.TYPE_INT_ARGB);
|
||
232 | // visualFXgr = visualFXim.createGraphics();
|
||
233 | // visualFXgr.drawImage(mapImage, null, null);
|
||
234 | // }
|
||
235 | // int drawEach = 300; // (milliseconds)
|
||
236 | // long lastTime = System.currentTimeMillis();
|
||
237 | // // -- end visual FX stuff
|
||
238 | 22516 | jvidal | |
239 | /*
|
||
240 | 20768 | jdominguez | * now we have an ordered set, it is only need to give a pass
|
241 | * for each label class to render by priorities.
|
||
242 | 22516 | jvidal | *
|
243 | 20768 | jdominguez | * If no priorities were defined, the following loop only executes
|
244 | * once
|
||
245 | */
|
||
246 | for (LabelClass lc : ts) {
|
||
247 | IFeatureIterator it = method.getFeatureIteratorByLabelClass(layer, lc, viewPort, usedFields); |
||
248 | 22516 | jvidal | |
249 | // duplicates treatment stuff
|
||
250 | 22160 | vcaballero | /* handle the duplicates mode */
|
251 | int duplicateMode = getDuplicateLabelsMode();
|
||
252 | 20768 | jdominguez | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
253 | // we need to register the labels already placed
|
||
254 | 22516 | jvidal | if (placedLabels == null) |
255 | 20768 | jdominguez | placedLabels = new TreeSet<String[]>( |
256 | new RemoveDuplicatesComparator());
|
||
257 | else placedLabels.clear();
|
||
258 | } |
||
259 | 22516 | jvidal | |
260 | |||
261 | 20905 | jdominguez | boolean bLabelsReallocatable = !isAllowingOverlap();
|
262 | 22160 | vcaballero | |
263 | BufferedImage overlapDetectImage = null; |
||
264 | Graphics2D overlapDetectGraphics = null; |
||
265 | 20768 | jdominguez | if (bLabelsReallocatable) {
|
266 | 22160 | vcaballero | overlapDetectImage = new BufferedImage( |
267 | 22082 | vcaballero | mapImage.getWidth(), |
268 | mapImage.getHeight(), |
||
269 | 22160 | vcaballero | BufferedImage.TYPE_INT_ARGB
|
270 | ); |
||
271 | overlapDetectGraphics = overlapDetectImage.createGraphics(); |
||
272 | overlapDetectGraphics.setRenderingHints(mapGraphics.getRenderingHints()); |
||
273 | 20768 | jdominguez | } |
274 | 22516 | jvidal | |
275 | 20768 | jdominguez | while ( !cancel.isCanceled() && it.hasNext()) {
|
276 | IFeature feat = it.next(); |
||
277 | IGeometry geom = feat.getGeometry(); |
||
278 | |||
279 | if (!setupLabel(feat, lc, cancel, usedFields, viewPort, dpi, duplicateMode, placedLabels))
|
||
280 | continue;
|
||
281 | 22516 | jvidal | |
282 | 20768 | jdominguez | // Check if size is a pixel
|
283 | if (isOnePoint(viewPort, geom)) {
|
||
284 | continue;
|
||
285 | } |
||
286 | 22516 | jvidal | |
287 | 23367 | vcaballero | |
288 | 20768 | jdominguez | // Calculate the label possible places
|
289 | ArrayList<LabelLocationMetrics> llm = placement.guess(
|
||
290 | 22516 | jvidal | lc, |
291 | 20768 | jdominguez | FConverter.transformToInts(geom, viewPort.getAffineTransform()), |
292 | getPlacementConstraints(), |
||
293 | 0,
|
||
294 | cancel); |
||
295 | 22516 | jvidal | |
296 | 23367 | vcaballero | |
297 | 22160 | vcaballero | BufferedImage targetBI;
|
298 | Graphics2D targetGr;
|
||
299 | if (bLabelsReallocatable) {
|
||
300 | targetBI = overlapDetectImage; |
||
301 | targetGr = overlapDetectGraphics; |
||
302 | } else {
|
||
303 | // // -- visual FX stuff
|
||
304 | // if (bVisualFXEnabled) {
|
||
305 | // targetBI = visualFXim;
|
||
306 | // targetGr = visualFXgr;
|
||
307 | // } else {
|
||
308 | // // -- end visual FX stuff
|
||
309 | targetBI = mapImage; |
||
310 | targetGr = mapGraphics; |
||
311 | // }
|
||
312 | } |
||
313 | 20768 | jdominguez | |
314 | 23367 | vcaballero | |
315 | |||
316 | 22516 | jvidal | /*
|
317 | 20768 | jdominguez | * search if there is room left by the previous and
|
318 | * with more priority labels, then check the current
|
||
319 | * level
|
||
320 | */
|
||
321 | 22516 | jvidal | if (lookupAndPlaceLabel(targetBI, targetGr, llm,
|
322 | 22160 | vcaballero | placement, lc, geom, viewPort, cancel, bLabelsReallocatable)) { |
323 | 20768 | jdominguez | placedCount++; |
324 | } else {
|
||
325 | notPlacedCount++; |
||
326 | } |
||
327 | 22516 | jvidal | |
328 | 22160 | vcaballero | // // -- visual FX stuff
|
329 | // if (bVisualFXEnabled && System.currentTimeMillis() - lastTime > drawEach) {
|
||
330 | // lastTime = System.currentTimeMillis();
|
||
331 | // mapGraphics.drawImage(visualFXim, null, null);
|
||
332 | // }
|
||
333 | // // -- end visual FX stuff
|
||
334 | 20768 | jdominguez | } |
335 | 22516 | jvidal | |
336 | 22160 | vcaballero | if (bLabelsReallocatable) {
|
337 | // // -- visual FX stuff
|
||
338 | 22516 | jvidal | // if (bVisualFXEnabled)
|
339 | 22160 | vcaballero | // visualFXgr.drawImage(overlapDetectImage, null, null);
|
340 | 22516 | jvidal | // else
|
341 | 22160 | vcaballero | // // -- end visual FX stuff
|
342 | mapGraphics.drawImage(overlapDetectImage, null, null); |
||
343 | } |
||
344 | 20768 | jdominguez | } |
345 | 22516 | jvidal | |
346 | 20768 | jdominguez | int total = placedCount+notPlacedCount;
|
347 | |||
348 | 22082 | vcaballero | double totalTime = (System.currentTimeMillis()-t1); |
349 | 22516 | jvidal | |
350 | 20905 | jdominguez | if (total>0) |
351 | 22160 | vcaballero | Logger.getLogger(getClass()).info("Labeled layer '"+layer.getName()+ |
352 | "' "+totalTime/1000D+" seconds. "+placedCount+"/"+total+ |
||
353 | " labels placed ("+NumberFormat.getInstance(). |
||
354 | format(100*placedCount/(double) total)+"%)"); |
||
355 | 20768 | jdominguez | |
356 | 22082 | vcaballero | if (cancel.isCanceled()) {
|
357 | 22160 | vcaballero | Logger.getLogger(getClass()).info("Layer labeling canceled: '"+ |
358 | layer.getName()+"'");
|
||
359 | 22082 | vcaballero | } else {
|
360 | 22160 | vcaballero | Logger.getLogger(getClass()).info("Total labels parse time = "+ |
361 | parseTime+" ("+NumberFormat.getInstance(). |
||
362 | format(parseTime*100/totalTime)+"%)"); |
||
363 | 22082 | vcaballero | } |
364 | 22516 | jvidal | |
365 | 22160 | vcaballero | // // -- visual FX stuff
|
366 | // if (bVisualFXEnabled) {
|
||
367 | // mapGraphics.drawImage(visualFXim, null, null);
|
||
368 | // }
|
||
369 | // // -- end visual FX stuff
|
||
370 | 20768 | jdominguez | } |
371 | 22516 | jvidal | |
372 | 20768 | jdominguez | private int getDuplicateLabelsMode() { |
373 | if (getPlacementConstraints() == null) { |
||
374 | return IPlacementConstraints.DefaultDuplicateLabelsMode;
|
||
375 | } |
||
376 | return getPlacementConstraints().getDuplicateLabelsMode();
|
||
377 | } |
||
378 | |||
379 | 22516 | jvidal | private boolean lookupAndPlaceLabel(BufferedImage bi, Graphics2D g, |
380 | 22082 | vcaballero | ArrayList<LabelLocationMetrics> llm, ILabelPlacement placement,
|
381 | LabelClass lc, IGeometry geom, ViewPort viewPort, |
||
382 | Cancellable cancel, boolean bLabelsReallocatable) {
|
||
383 | 20768 | jdominguez | int i;
|
384 | for (i = 0; !cancel.isCanceled() && i < llm.size(); i++) { |
||
385 | LabelLocationMetrics labelMetrics = llm.get(i); |
||
386 | |||
387 | if (bLabelsReallocatable) {
|
||
388 | 23367 | vcaballero | if (!isOverlapping(bi, lc.getShape(labelMetrics))) {
|
389 | if(!getPlacementConstraints().isFollowingLine()){
|
||
390 | lc.draw(g, labelMetrics, (FShape) geom.getInternalShape()); |
||
391 | } |
||
392 | else{
|
||
393 | SmartTextSymbolLabelClass smsLc = new SmartTextSymbolLabelClass();
|
||
394 | SmartTextSymbol sms = new SmartTextSymbol(lc.getTextSymbol(),getPlacementConstraints());
|
||
395 | smsLc.setTextSymbol(sms); |
||
396 | geom.transform(viewPort.getAffineTransform()); |
||
397 | smsLc.draw(g, null, (FShape) geom.getInternalShape());
|
||
398 | |||
399 | } |
||
400 | 22187 | jdominguez | return true; |
401 | 22516 | jvidal | } |
402 | 20768 | jdominguez | } else {
|
403 | 23367 | vcaballero | if(!getPlacementConstraints().isFollowingLine())
|
404 | lc.draw(g, labelMetrics, null);
|
||
405 | else{
|
||
406 | SmartTextSymbolLabelClass smsLc = new SmartTextSymbolLabelClass();
|
||
407 | SmartTextSymbol sms = new SmartTextSymbol(lc.getTextSymbol(),getPlacementConstraints());
|
||
408 | smsLc.setTextSymbol(sms); |
||
409 | geom.transform(viewPort.getAffineTransform()); |
||
410 | smsLc.draw(g, null, (FShape) geom.getInternalShape());
|
||
411 | } |
||
412 | 20768 | jdominguez | return true; |
413 | } |
||
414 | 22516 | jvidal | } |
415 | 20768 | jdominguez | return false; |
416 | } |
||
417 | 22516 | jvidal | |
418 | 20768 | jdominguez | @SuppressWarnings("unchecked") |
419 | 22516 | jvidal | private boolean setupLabel(IFeature feat, LabelClass lc, |
420 | 20768 | jdominguez | Cancellable cancel, String[] usedFields, ViewPort viewPort, |
421 | double dpi, int duplicateMode, TreeSet<?> placedLabels) { |
||
422 | |||
423 | Value[] vv = feat.getAttributes();
|
||
424 | String expr = lc.getLabelExpression();
|
||
425 | 22516 | jvidal | |
426 | 22187 | jdominguez | long pt1 = System.currentTimeMillis(); |
427 | 22216 | jdominguez | String[] texts = NO_TEXT; |
428 | 22187 | jdominguez | try {
|
429 | |||
430 | 22082 | vcaballero | for (int i = 0; !cancel.isCanceled() && i < usedFields.length; i++) { |
431 | 22187 | jdominguez | symbol_table.put(usedFields[i], vv[i]); |
432 | 20768 | jdominguez | } |
433 | 22516 | jvidal | |
434 | 22216 | jdominguez | if (expr != null) { |
435 | 22952 | vcaballero | |
436 | if(expr.equals(";")) |
||
437 | expr = texts[0];
|
||
438 | |||
439 | 22216 | jdominguez | // parse (if it hasn't been parsed yet) and evaluate the expression
|
440 | 22516 | jvidal | Object labelContents = getEvaluator(expr).evaluate();
|
441 | 22216 | jdominguez | if (String[].class.equals(labelContents.getClass())) { |
442 | texts = (String[]) labelContents; |
||
443 | } else {
|
||
444 | texts = new String[] { labelContents.toString() }; |
||
445 | } |
||
446 | parseTime += System.currentTimeMillis()-pt1;
|
||
447 | 22187 | jdominguez | } |
448 | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
||
449 | // check if this text (so label) is already present in the map
|
||
450 | 22516 | jvidal | if (placedLabels.contains(texts))
|
451 | 22187 | jdominguez | // the label has already placed before
|
452 | return false; |
||
453 | 20768 | jdominguez | |
454 | 22187 | jdominguez | /*
|
455 | * the text is not present, it will be registered for next to
|
||
456 | * be avoided
|
||
457 | */
|
||
458 | ((TreeSet<String[]>) placedLabels).add(texts); |
||
459 | } |
||
460 | lc.setTexts(texts); |
||
461 | } catch (ExpressionException e) {
|
||
462 | e.printStackTrace(); |
||
463 | return false; |
||
464 | 22516 | jvidal | } |
465 | 22082 | vcaballero | |
466 | 20768 | jdominguez | lc.toCartographicSize(viewPort, dpi, null);
|
467 | return true; |
||
468 | } |
||
469 | 22187 | jdominguez | private Hashtable<String, Value> symbol_table = new Hashtable<String, Value>(); |
470 | private Hashtable<String, Expression> evaluators = new Hashtable<String, Expression>(); |
||
471 | 22516 | jvidal | |
472 | 22187 | jdominguez | private Expression getEvaluator(String strExpr) { |
473 | Expression expr = evaluators.get(strExpr);
|
||
474 | if (expr == null) { |
||
475 | LabelExpressionParser p = new LabelExpressionParser(
|
||
476 | 22516 | jvidal | new StringReader(strExpr),symbol_table); |
477 | |||
478 | 22187 | jdominguez | try {
|
479 | p.LabelExpression(); |
||
480 | } catch (ParseException e) { |
||
481 | e.printStackTrace(); |
||
482 | } |
||
483 | expr = (Expression) p.getStack().pop();
|
||
484 | evaluators.put(strExpr, expr); |
||
485 | } |
||
486 | return expr;
|
||
487 | } |
||
488 | 22516 | jvidal | |
489 | 20768 | jdominguez | private boolean isOverlapping(BufferedImage bi, FShape labelShape) { |
490 | 22516 | jvidal | |
491 | 20768 | jdominguez | Rectangle2D rPixels = labelShape.getBounds2D();
|
492 | for (int i= (int) rPixels.getX(); i<rPixels.getMaxX(); i++){ |
||
493 | for (int j= (int) rPixels.getY(); j<rPixels.getMaxY(); j++){ |
||
494 | if (!labelShape.contains(i, j)) {
|
||
495 | continue;
|
||
496 | } |
||
497 | 22516 | jvidal | |
498 | 20768 | jdominguez | if (i<0 || j<0) { |
499 | continue;
|
||
500 | } |
||
501 | 22516 | jvidal | |
502 | 20768 | jdominguez | if (bi.getWidth()<i+1 || bi.getHeight()<j+1) { |
503 | continue;
|
||
504 | } |
||
505 | 22516 | jvidal | |
506 | 20768 | jdominguez | if (bi.getRGB(i,j)!=0){ |
507 | return true; |
||
508 | } |
||
509 | } |
||
510 | } |
||
511 | return false; |
||
512 | } |
||
513 | 22516 | jvidal | |
514 | 20768 | jdominguez | private boolean isOnePoint(ViewPort viewPort, IGeometry geom) { |
515 | boolean onePoint = false; |
||
516 | int shapeType = geom.getGeometryType();
|
||
517 | if (shapeType!=FShape.POINT && shapeType!=FShape.MULTIPOINT) {
|
||
518 | |||
519 | Rectangle2D geomBounds = geom.getBounds2D();
|
||
520 | ICoordTrans ct = layer.getCoordTrans(); |
||
521 | |||
522 | if (ct!=null) { |
||
523 | geomBounds = ct.convert(geomBounds); |
||
524 | } |
||
525 | |||
526 | double dist1Pixel = viewPort.getDist1pixel();
|
||
527 | onePoint = (geomBounds.getWidth() <= dist1Pixel |
||
528 | && geomBounds.getHeight() <= dist1Pixel); |
||
529 | } |
||
530 | return onePoint;
|
||
531 | } |
||
532 | |||
533 | public String getClassName() { |
||
534 | return getClass().getName();
|
||
535 | } |
||
536 | |||
537 | public XMLEntity getXMLEntity() {
|
||
538 | XMLEntity xml = new XMLEntity();
|
||
539 | xml.putProperty("className", getClassName());
|
||
540 | 22082 | vcaballero | xml.putProperty("allowsOverlapping", allowOverlapping);
|
541 | // xml.putProperty("minScaleView", minScaleView);
|
||
542 | // xml.putProperty("maxScaleView", maxScaleView);
|
||
543 | 22516 | jvidal | |
544 | 20768 | jdominguez | if (method!=null) { |
545 | XMLEntity methodEntity = method.getXMLEntity(); |
||
546 | methodEntity.putProperty("id", "LabelingMethod"); |
||
547 | xml.addChild(methodEntity); |
||
548 | } |
||
549 | 22516 | jvidal | |
550 | 20768 | jdominguez | if (placementConstraints != null) { |
551 | XMLEntity pcEntity = placementConstraints.getXMLEntity(); |
||
552 | pcEntity.putProperty("id", "PlacementConstraints"); |
||
553 | xml.addChild(pcEntity); |
||
554 | } |
||
555 | 22516 | jvidal | |
556 | 20768 | jdominguez | if (zoomConstraints != null) { |
557 | XMLEntity zcEntity = zoomConstraints.getXMLEntity(); |
||
558 | zcEntity.putProperty("id", "ZoomConstraints"); |
||
559 | xml.addChild(zcEntity); |
||
560 | } |
||
561 | return xml;
|
||
562 | } |
||
563 | |||
564 | public void setXMLEntity(XMLEntity xml) { |
||
565 | XMLEntity aux = xml.firstChild("id", "LabelingMethod"); |
||
566 | |||
567 | // overlapping mode
|
||
568 | if (xml.contains("allowsOverlapping")) { |
||
569 | allowOverlapping = xml.getBooleanProperty("allowsOverlapping");
|
||
570 | } |
||
571 | 22516 | jvidal | |
572 | |||
573 | 20768 | jdominguez | if (aux != null) { |
574 | method = LabelingFactory.createMethodFromXML(aux); |
||
575 | } |
||
576 | 22516 | jvidal | |
577 | 20768 | jdominguez | aux = xml.firstChild("id", "PlacementConstraints"); |
578 | if (aux != null) { |
||
579 | placementConstraints = LabelingFactory.createPlacementConstraintsFromXML(aux); |
||
580 | } |
||
581 | 22516 | jvidal | |
582 | 20768 | jdominguez | aux = xml.firstChild("id", "ZoomConstraints"); |
583 | if (aux != null) { |
||
584 | zoomConstraints = LabelingFactory.createZoomConstraintsFromXML(aux); |
||
585 | } |
||
586 | } |
||
587 | |||
588 | 20905 | jdominguez | public boolean isAllowingOverlap() { |
589 | 20768 | jdominguez | return allowOverlapping;
|
590 | } |
||
591 | 22516 | jvidal | |
592 | 20768 | jdominguez | public void setAllowOverlapping(boolean allowOverlapping) { |
593 | this.allowOverlapping = allowOverlapping;
|
||
594 | } |
||
595 | 22516 | jvidal | |
596 | 20768 | jdominguez | public IPlacementConstraints getPlacementConstraints() {
|
597 | 22082 | vcaballero | if (placementConstraints != null) |
598 | return placementConstraints;
|
||
599 | 22516 | jvidal | |
600 | 22082 | vcaballero | try {
|
601 | switch (layer.getShapeType()) {
|
||
602 | case FShape.POINT:
|
||
603 | 22494 | fpenarrubia | case FShape.MULTIPOINT:
|
604 | 22082 | vcaballero | return DefaultPointPlacementConstraints;
|
605 | case FShape.LINE:
|
||
606 | return DefaultLinePlacementConstraints;
|
||
607 | case FShape.POLYGON:
|
||
608 | return DefaultPolygonPlacementConstraints;
|
||
609 | case FShape.MULTI:
|
||
610 | DefaultMultiShapePlacementConstratints.setPointConstraints(DefaultPointPlacementConstraints); |
||
611 | DefaultMultiShapePlacementConstratints.setLineConstraints(DefaultLinePlacementConstraints); |
||
612 | DefaultMultiShapePlacementConstratints.setPolygonConstraints(DefaultPolygonPlacementConstraints); |
||
613 | return DefaultMultiShapePlacementConstratints;
|
||
614 | } |
||
615 | |||
616 | } catch (ReadDriverException e) {
|
||
617 | 22516 | jvidal | |
618 | 22082 | vcaballero | } |
619 | return null; |
||
620 | 20768 | jdominguez | } |
621 | |||
622 | public void setPlacementConstraints(IPlacementConstraints constraints) { |
||
623 | this.placementConstraints = constraints;
|
||
624 | } |
||
625 | |||
626 | public IZoomConstraints getZoomConstraints() {
|
||
627 | return zoomConstraints;
|
||
628 | } |
||
629 | |||
630 | public void setZoomConstraints(IZoomConstraints constraints) { |
||
631 | this.zoomConstraints = constraints;
|
||
632 | } |
||
633 | |||
634 | public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, PrintRequestAttributeSet properties) throws ReadDriverException { |
||
635 | |||
636 | } |
||
637 | 22516 | jvidal | |
638 | 20768 | jdominguez | public String[] getUsedFields() { |
639 | LabelClass[] lcs = method.getLabelClasses();
|
||
640 | 22516 | jvidal | ArrayList<String> fieldNames = new ArrayList<String>(); |
641 | 20768 | jdominguez | for (int i = 0; i < lcs.length; i++) { |
642 | String expr = lcs[i].getLabelExpression();
|
||
643 | int start;
|
||
644 | 22516 | jvidal | while (expr != null && |
645 | 22187 | jdominguez | (start = expr.indexOf("[")) != -1) { |
646 | 22516 | jvidal | int end = expr.indexOf("]"); |
647 | 20768 | jdominguez | String field = expr.substring(start+1, end).trim(); |
648 | if (!fieldNames.contains(field))
|
||
649 | fieldNames.add(field); |
||
650 | expr = expr.substring(end+1, expr.length());
|
||
651 | } |
||
652 | |||
653 | } |
||
654 | return fieldNames.toArray(new String[fieldNames.size()]); |
||
655 | } |
||
656 | 22516 | jvidal | |
657 | 20768 | jdominguez | public boolean shouldDrawLabels(double scale) { |
658 | 22082 | vcaballero | double minScaleView = -1; |
659 | double maxScaleView = -1; |
||
660 | 22516 | jvidal | |
661 | 22082 | vcaballero | if (zoomConstraints != null) { |
662 | minScaleView = zoomConstraints.getMinScale(); |
||
663 | maxScaleView = zoomConstraints.getMaxScale(); |
||
664 | } |
||
665 | 22516 | jvidal | |
666 | 20768 | jdominguez | if (minScaleView == -1 && maxScaleView == -1) { |
667 | // parameters not set, so the layer decides.
|
||
668 | return layer.isWithinScale(scale);
|
||
669 | } |
||
670 | 22516 | jvidal | |
671 | 20768 | jdominguez | if (minScaleView <= scale) {
|
672 | return (maxScaleView != -1) ? maxScaleView >= scale : true; |
||
673 | } |
||
674 | 22516 | jvidal | |
675 | 20768 | jdominguez | return false; |
676 | } |
||
677 | |||
678 | } |