svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.labeling.app / org.gvsig.labeling.app.mainplugin / src / main / java / org / gvsig / labeling / label / GeneralLabelingStrategy.java @ 45028
History | View | Annotate | Download (29.3 KB)
1 | 40911 | jldominguez | package org.gvsig.labeling.label; |
---|---|---|---|
2 | |||
3 | import java.awt.Graphics2D; |
||
4 | import java.awt.geom.Point2D; |
||
5 | import java.awt.image.BufferedImage; |
||
6 | 45028 | fdiaz | import java.io.File; |
7 | import java.io.IOException; |
||
8 | 40911 | jldominguez | import java.util.ArrayList; |
9 | import java.util.Iterator; |
||
10 | 41227 | jldominguez | import java.util.List; |
11 | 40911 | jldominguez | import java.util.TreeMap; |
12 | import java.util.TreeSet; |
||
13 | 45028 | fdiaz | import java.util.logging.Level; |
14 | import javax.imageio.ImageIO; |
||
15 | 43510 | jjdelcerro | import org.cresques.cts.ICoordTrans; |
16 | 40911 | jldominguez | |
17 | 42980 | fdiaz | import org.slf4j.Logger; |
18 | import org.slf4j.LoggerFactory; |
||
19 | |||
20 | 40911 | jldominguez | import org.gvsig.compat.print.PrintAttributes; |
21 | import org.gvsig.fmap.dal.exception.DataException; |
||
22 | import org.gvsig.fmap.dal.exception.ReadException; |
||
23 | import org.gvsig.fmap.dal.feature.Feature; |
||
24 | import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor; |
||
25 | import org.gvsig.fmap.dal.feature.FeatureSet; |
||
26 | import org.gvsig.fmap.geom.Geometry; |
||
27 | import org.gvsig.fmap.geom.Geometry.SUBTYPES; |
||
28 | import org.gvsig.fmap.geom.Geometry.TYPES; |
||
29 | import org.gvsig.fmap.geom.GeometryException; |
||
30 | import org.gvsig.fmap.geom.GeometryLocator; |
||
31 | import org.gvsig.fmap.geom.GeometryManager; |
||
32 | 41227 | jldominguez | import org.gvsig.fmap.geom.aggregate.MultiPrimitive; |
33 | 42555 | fdiaz | import org.gvsig.fmap.geom.operation.GeometryOperationException; |
34 | import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException; |
||
35 | 40911 | jldominguez | import org.gvsig.fmap.geom.primitive.Envelope; |
36 | import org.gvsig.fmap.geom.primitive.Point; |
||
37 | import org.gvsig.fmap.geom.type.GeometryType; |
||
38 | import org.gvsig.fmap.mapcontext.ViewPort; |
||
39 | import org.gvsig.fmap.mapcontext.layers.FLayer; |
||
40 | import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect; |
||
41 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelClass; |
||
42 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingMethod; |
||
43 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingStrategy; |
||
44 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.IPlacementConstraints; |
||
45 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.IZoomConstraints; |
||
46 | import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport; |
||
47 | import org.gvsig.i18n.Messages; |
||
48 | import org.gvsig.labeling.lang.LabelClassUtils; |
||
49 | import org.gvsig.labeling.placements.ILabelPlacement; |
||
50 | import org.gvsig.labeling.placements.LinePlacementConstraints; |
||
51 | import org.gvsig.labeling.placements.MultiShapePlacementConstraints; |
||
52 | import org.gvsig.labeling.placements.PlacementManager; |
||
53 | import org.gvsig.labeling.placements.PointPlacementConstraints; |
||
54 | import org.gvsig.labeling.placements.PolygonPlacementConstraints; |
||
55 | import org.gvsig.labeling.placements.RemoveDuplicatesComparator; |
||
56 | import org.gvsig.labeling.symbol.SmartTextSymbol; |
||
57 | import org.gvsig.labeling.symbol.SymbolUtils; |
||
58 | import org.gvsig.symbology.SymbologyLocator; |
||
59 | import org.gvsig.symbology.fmap.mapcontext.rendering.legend.styling.LabelLocationMetrics; |
||
60 | import org.gvsig.tools.ToolsLocator; |
||
61 | import org.gvsig.tools.dispose.DisposableIterator; |
||
62 | import org.gvsig.tools.dynobject.DynStruct; |
||
63 | import org.gvsig.tools.persistence.PersistenceManager; |
||
64 | import org.gvsig.tools.persistence.PersistentState; |
||
65 | import org.gvsig.tools.persistence.exception.PersistenceException; |
||
66 | 45028 | fdiaz | import org.gvsig.tools.swing.api.SimpleImage; |
67 | import org.gvsig.tools.swing.api.ToolsSwingLocator; |
||
68 | 40911 | jldominguez | import org.gvsig.tools.task.Cancellable; |
69 | 42555 | fdiaz | |
70 | 44534 | omartinez | public class GeneralLabelingStrategy implements IGeneralLabelingStrategy { |
71 | 41789 | fdiaz | |
72 | private static final Logger logger = LoggerFactory |
||
73 | .getLogger(GeneralLabelingStrategy.class); |
||
74 | |||
75 | public static final String GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME = "GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME"; |
||
76 | |||
77 | public static PointPlacementConstraints DefaultPointPlacementConstraints = new PointPlacementConstraints(); |
||
78 | public static LinePlacementConstraints DefaultLinePlacementConstraints = new LinePlacementConstraints(); |
||
79 | public static PolygonPlacementConstraints DefaultPolygonPlacementConstraints = new PolygonPlacementConstraints(); |
||
80 | |||
81 | 40911 | jldominguez | private static String[] NO_TEXT = { Messages.getText("text_field") }; |
82 | 41789 | fdiaz | |
83 | private static MultiShapePlacementConstraints DefaultMultiShapePlacementConstratints = new MultiShapePlacementConstraints(); |
||
84 | |||
85 | 40911 | jldominguez | private ILabelingMethod method;
|
86 | private IPlacementConstraints placementConstraints;
|
||
87 | private IZoomConstraints zoomConstraints;
|
||
88 | 41789 | fdiaz | |
89 | 40911 | jldominguez | private boolean allowOverlapping; |
90 | 41789 | fdiaz | |
91 | 40911 | jldominguez | protected FLyrVect layer;
|
92 | |||
93 | 41789 | fdiaz | // private long parseTime;
|
94 | 40911 | jldominguez | private int unit; |
95 | private int referenceSystem; |
||
96 | // private double sizeAfter;
|
||
97 | 41789 | fdiaz | private boolean printMode = false; /* |
98 | * indicate whether output is for a
|
||
99 | * print product (PDF, PS, ...)
|
||
100 | */
|
||
101 | |||
102 | 42980 | fdiaz | private List<Geometry> drawnGeometryLabels; |
103 | |||
104 | 40911 | jldominguez | public GeneralLabelingStrategy() {
|
105 | 41789 | fdiaz | method = SymbologyLocator.getSymbologyManager() |
106 | .createDefaultLabelingMethod(); |
||
107 | 40911 | jldominguez | } |
108 | |||
109 | public void setLayer(FLayer layer) { |
||
110 | FLyrVect l = (FLyrVect) layer; |
||
111 | this.layer = l;
|
||
112 | } |
||
113 | |||
114 | public ILabelingMethod getLabelingMethod() {
|
||
115 | return method;
|
||
116 | } |
||
117 | |||
118 | public void setLabelingMethod(ILabelingMethod method) { |
||
119 | this.method = method;
|
||
120 | } |
||
121 | |||
122 | 41789 | fdiaz | private class GeometryItem { |
123 | 40911 | jldominguez | public Geometry geom = null; |
124 | public int weigh = 0; |
||
125 | public double savedPerimeter; |
||
126 | |||
127 | 41789 | fdiaz | public GeometryItem(Geometry geom, int weigh) { |
128 | 40911 | jldominguez | this.geom = geom;
|
129 | this.weigh = weigh;
|
||
130 | this.savedPerimeter = 0; |
||
131 | } |
||
132 | } |
||
133 | 41789 | fdiaz | |
134 | 42980 | fdiaz | public void draw(BufferedImage mapImage, Graphics2D mapGraphics, double scale, ViewPort viewPort, |
135 | Cancellable cancel, double dpi) throws ReadException { |
||
136 | 40911 | jldominguez | |
137 | 42980 | fdiaz | drawnGeometryLabels = new ArrayList<Geometry>(1000); |
138 | 41789 | fdiaz | |
139 | 42980 | fdiaz | int x = (int) viewPort.getOffset().getX(); |
140 | int y = (int) viewPort.getOffset().getY(); |
||
141 | 40911 | jldominguez | |
142 | 42980 | fdiaz | // offsets for page generation (PDF, PS, direct printing)
|
143 | int print_offset_x = x;
|
||
144 | int print_offset_y = y;
|
||
145 | if (printMode) {
|
||
146 | // for printing, we never offset the labels themselves
|
||
147 | x = 0;
|
||
148 | y = 0;
|
||
149 | printMode = false;
|
||
150 | } |
||
151 | 41789 | fdiaz | |
152 | 42980 | fdiaz | TreeMap<String[], GeometryItem> labelsToPlace = null; |
153 | 40911 | jldominguez | |
154 | 42980 | fdiaz | String[] usedFields = getUsedFields(); |
155 | 40911 | jldominguez | |
156 | 42980 | fdiaz | int notPlacedCount = 0; |
157 | int placedCount = 0; |
||
158 | 40911 | jldominguez | |
159 | 42980 | fdiaz | /*
|
160 | * Get the label placement solvers according the user's settings
|
||
161 | */
|
||
162 | ILabelPlacement placement = PlacementManager.getPlacement(getPlacementConstraints(), layer.getShapeType()); |
||
163 | 40911 | jldominguez | |
164 | 42980 | fdiaz | BufferedImage targetBI;
|
165 | Graphics2D targetGr;
|
||
166 | 40911 | jldominguez | |
167 | 42980 | fdiaz | /*
|
168 | * get an ordered set of the LabelClasses up on the label priority
|
||
169 | */
|
||
170 | ILabelClass[] lcs = method.getLabelClasses();
|
||
171 | TreeSet<ILabelClass> ts = new TreeSet<ILabelClass>(new LabelClassComparatorByPriority()); |
||
172 | 40911 | jldominguez | |
173 | 42980 | fdiaz | for (int i = 0; i < lcs.length; i++) |
174 | ts.add(lcs[i]); |
||
175 | 40911 | jldominguez | |
176 | 42980 | fdiaz | if (ts.size() == 0) |
177 | return;
|
||
178 | 41789 | fdiaz | |
179 | 42980 | fdiaz | /*
|
180 | * now we have an ordered set, it is only need to give a pass for each
|
||
181 | * label class to render by priorities.
|
||
182 | *
|
||
183 | * If no priorities were defined, the following loop only executes once
|
||
184 | */
|
||
185 | for (ILabelClass lc : ts) {
|
||
186 | 41789 | fdiaz | |
187 | 42980 | fdiaz | if (!lc.isVisible(scale)) {
|
188 | /*
|
||
189 | * Avoid non-visible labels
|
||
190 | */
|
||
191 | continue;
|
||
192 | } |
||
193 | 40911 | jldominguez | |
194 | 42980 | fdiaz | FeatureSet fset = null;
|
195 | DisposableIterator diter = null;
|
||
196 | try {
|
||
197 | 40911 | jldominguez | |
198 | 42980 | fdiaz | try {
|
199 | fset = method.getFeatureIteratorByLabelClass(layer, lc, viewPort, usedFields); |
||
200 | } catch (DataException e) {
|
||
201 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
202 | } |
||
203 | 40911 | jldominguez | |
204 | 42980 | fdiaz | // duplicates treatment stuff
|
205 | /* handle the duplicates mode */
|
||
206 | int duplicateMode = getDuplicateLabelsMode();
|
||
207 | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
||
208 | // we need to register the labels already placed
|
||
209 | 40911 | jldominguez | |
210 | 42980 | fdiaz | labelsToPlace = new TreeMap<String[], GeometryItem>(new RemoveDuplicatesComparator()); |
211 | } |
||
212 | 40911 | jldominguez | |
213 | 42980 | fdiaz | boolean bLabelsReallocatable = !isAllowingOverlap();
|
214 | 41790 | fdiaz | |
215 | 42980 | fdiaz | BufferedImage overlapDetectImage = null; |
216 | Graphics2D overlapDetectGraphics = null; |
||
217 | if (bLabelsReallocatable) {
|
||
218 | int width = viewPort.getImageWidth() + print_offset_x;
|
||
219 | 41790 | fdiaz | |
220 | 42980 | fdiaz | if (width < 0) { |
221 | width = 1;
|
||
222 | } |
||
223 | int height = viewPort.getImageHeight() + print_offset_y;
|
||
224 | if (height < 0) { |
||
225 | height = 1;
|
||
226 | } |
||
227 | if (mapImage != null) |
||
228 | overlapDetectImage = |
||
229 | new BufferedImage(mapImage.getWidth() + print_offset_x, mapImage.getHeight() |
||
230 | + print_offset_y, BufferedImage.TYPE_INT_ARGB);
|
||
231 | else
|
||
232 | overlapDetectImage = |
||
233 | new BufferedImage(viewPort.getImageWidth() + print_offset_x, viewPort.getImageHeight() |
||
234 | + print_offset_y, BufferedImage.TYPE_INT_ARGB);
|
||
235 | 40911 | jldominguez | |
236 | 42980 | fdiaz | overlapDetectGraphics = overlapDetectImage.createGraphics(); |
237 | overlapDetectGraphics.setRenderingHints(mapGraphics.getRenderingHints()); |
||
238 | } |
||
239 | if (bLabelsReallocatable) {
|
||
240 | targetBI = overlapDetectImage; |
||
241 | targetGr = overlapDetectGraphics; |
||
242 | targetGr.translate(-x, -y); |
||
243 | } else {
|
||
244 | targetBI = mapImage; |
||
245 | targetGr = mapGraphics; |
||
246 | } |
||
247 | 40911 | jldominguez | |
248 | 42980 | fdiaz | try {
|
249 | diter = fset.fastIterator(); |
||
250 | } catch (DataException e) {
|
||
251 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
252 | } |
||
253 | Feature featu = null;
|
||
254 | Geometry geome = null;
|
||
255 | 40911 | jldominguez | |
256 | 42980 | fdiaz | while (!cancel.isCanceled() && diter.hasNext()) {
|
257 | 40911 | jldominguez | |
258 | 43313 | fdiaz | featu = ((Feature) diter.next()).getCopy(); |
259 | 42980 | fdiaz | geome = featu.getDefaultGeometry(); |
260 | if (geome == null || geome.getType() == Geometry.TYPES.NULL) { |
||
261 | continue;
|
||
262 | } |
||
263 | 43510 | jjdelcerro | ICoordTrans ct = layer.getCoordTrans(); |
264 | if( ct!=null ) { |
||
265 | geome.reProject(ct); |
||
266 | } |
||
267 | 42980 | fdiaz | if (!setupLabel(featu, lc, cancel, usedFields, viewPort, dpi, duplicateMode)) {
|
268 | continue;
|
||
269 | } |
||
270 | 41789 | fdiaz | |
271 | 42980 | fdiaz | String[] texts = lc.getTexts(); |
272 | 41789 | fdiaz | |
273 | 42980 | fdiaz | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
274 | // check if this text (so label) is already present in
|
||
275 | // the map
|
||
276 | 41789 | fdiaz | |
277 | 42980 | fdiaz | GeometryItem item = labelsToPlace.get(texts); |
278 | if (item == null) { |
||
279 | item = new GeometryItem(geome, 0); |
||
280 | labelsToPlace.put(texts, item); |
||
281 | } |
||
282 | if (item.geom != null) { |
||
283 | 41789 | fdiaz | |
284 | 42980 | fdiaz | notPlacedCount++; |
285 | if (geome.getType() != Geometry.TYPES.POINT) {
|
||
286 | 41789 | fdiaz | |
287 | 42980 | fdiaz | Envelope auxBox = geome.getEnvelope(); |
288 | double perimeterAux = 2 * (auxBox.getLength(0) + auxBox.getLength(1)); |
||
289 | if (perimeterAux > item.savedPerimeter) {
|
||
290 | item.geom = geome; // FConverter.jts_to_igeometry(jtsGeom);
|
||
291 | item.savedPerimeter = perimeterAux; |
||
292 | } |
||
293 | } else {
|
||
294 | int weigh = item.weigh;
|
||
295 | 41789 | fdiaz | |
296 | 42980 | fdiaz | try {
|
297 | Point pointFromLabel = item.geom.centroid();
|
||
298 | Point pointGeome = geome.centroid();
|
||
299 | item.geom = |
||
300 | GeometryLocator.getGeometryManager().createPoint( |
||
301 | (pointFromLabel.getX() * weigh + pointGeome.getX()) / (weigh + 1),
|
||
302 | (pointFromLabel.getY() * weigh + pointGeome.getY()) / (weigh + 1),
|
||
303 | Geometry.SUBTYPES.GEOM2D); |
||
304 | } catch (Exception ex) { |
||
305 | throw new ReadException(layer.getFeatureStore().getProviderName(), ex); |
||
306 | } |
||
307 | 40911 | jldominguez | |
308 | 42980 | fdiaz | } |
309 | } else {
|
||
310 | item.geom = geome; |
||
311 | } |
||
312 | item.weigh++; |
||
313 | } else {
|
||
314 | // Check if size is a pixel
|
||
315 | if (isOnePoint(viewPort, geome)) {
|
||
316 | continue;
|
||
317 | } |
||
318 | 41789 | fdiaz | |
319 | 42980 | fdiaz | List<Geometry> geome_parts = new ArrayList<Geometry>(); |
320 | if (duplicateMode == IPlacementConstraints.ONE_LABEL_PER_FEATURE_PART) {
|
||
321 | geome_parts = getGeometryParts(geome); |
||
322 | } else {
|
||
323 | geome_parts.add(geome); |
||
324 | } |
||
325 | 41789 | fdiaz | |
326 | 42980 | fdiaz | try {
|
327 | int n = geome_parts.size();
|
||
328 | for (int k = 0; k < n; k++) { |
||
329 | drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, geome_parts.get(k), |
||
330 | cancel, dpi, bLabelsReallocatable); |
||
331 | } |
||
332 | } catch (GeometryException e) {
|
||
333 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
334 | } |
||
335 | 41789 | fdiaz | |
336 | 42980 | fdiaz | placedCount++; |
337 | } |
||
338 | } |
||
339 | 41789 | fdiaz | |
340 | 42980 | fdiaz | // ======= End iteration in feature set ====================
|
341 | 40911 | jldominguez | |
342 | 42980 | fdiaz | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
343 | Iterator<String[]> textsIt = labelsToPlace.keySet().iterator(); |
||
344 | while (!cancel.isCanceled() && textsIt.hasNext()) {
|
||
345 | notPlacedCount++; |
||
346 | String[] texts = textsIt.next(); |
||
347 | 40911 | jldominguez | |
348 | 42980 | fdiaz | GeometryItem item = labelsToPlace.get(texts); |
349 | if (item != null) { |
||
350 | lc.setTexts(texts); |
||
351 | // Check if size is a pixel
|
||
352 | if (isOnePoint(viewPort, item.geom)) {
|
||
353 | continue;
|
||
354 | } |
||
355 | 40911 | jldominguez | |
356 | 42980 | fdiaz | try {
|
357 | drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, item.geom, cancel, dpi, |
||
358 | bLabelsReallocatable); |
||
359 | } catch (GeometryException e) {
|
||
360 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
361 | } |
||
362 | } |
||
363 | } |
||
364 | } |
||
365 | 41790 | fdiaz | |
366 | 42980 | fdiaz | if (bLabelsReallocatable) {
|
367 | targetGr.translate(x, y); |
||
368 | 45028 | fdiaz | mapGraphics.drawImage(targetBI, null, null); |
369 | 42980 | fdiaz | } |
370 | 40911 | jldominguez | |
371 | 42980 | fdiaz | } finally {
|
372 | if (diter != null) { |
||
373 | diter.dispose(); |
||
374 | } |
||
375 | if (fset != null) { |
||
376 | fset.dispose(); |
||
377 | } |
||
378 | } |
||
379 | } // big iteration
|
||
380 | 41789 | fdiaz | |
381 | 42980 | fdiaz | } |
382 | |||
383 | 41227 | jldominguez | private List<Geometry> getGeometryParts(Geometry ge) { |
384 | |||
385 | 41789 | fdiaz | List<Geometry> resp = new ArrayList<Geometry>(); |
386 | if (ge != null) { |
||
387 | if (ge instanceof MultiPrimitive) { |
||
388 | MultiPrimitive mp = (MultiPrimitive) ge; |
||
389 | int n = mp.getPrimitivesNumber();
|
||
390 | for (int i = 0; i < n; i++) { |
||
391 | resp.add(mp.getPrimitiveAt(i)); |
||
392 | } |
||
393 | } else {
|
||
394 | resp.add(ge); |
||
395 | } |
||
396 | } |
||
397 | return resp;
|
||
398 | } |
||
399 | 40911 | jldominguez | |
400 | 41789 | fdiaz | private void drawLabelInGeom(BufferedImage targetBI, Graphics2D targetGr, |
401 | ILabelClass lc, ILabelPlacement placement, ViewPort viewPort, |
||
402 | Geometry geom, Cancellable cancel, double dpi,
|
||
403 | boolean bLabelsReallocatable) throws GeometryException { |
||
404 | |||
405 | 40911 | jldominguez | lc.toCartographicSize(viewPort, dpi, null);
|
406 | ArrayList<LabelLocationMetrics> llm = null; |
||
407 | 41789 | fdiaz | llm = placement.guess(lc, geom, getPlacementConstraints(), 0, cancel,
|
408 | viewPort); |
||
409 | 40911 | jldominguez | |
410 | setReferenceSystem(lc.getReferenceSystem()); |
||
411 | setUnit(lc.getUnit()); |
||
412 | |||
413 | /*
|
||
414 | 41789 | fdiaz | * search if there is room left by the previous and with more priority
|
415 | * labels, then check the current level
|
||
416 | 40911 | jldominguez | */
|
417 | 41789 | fdiaz | lookupAndPlaceLabel(targetBI, targetGr, llm, placement, lc, geom, |
418 | viewPort, cancel, bLabelsReallocatable); |
||
419 | 40911 | jldominguez | |
420 | } |
||
421 | |||
422 | private int getDuplicateLabelsMode() { |
||
423 | if (getPlacementConstraints() == null) { |
||
424 | return IPlacementConstraints.DefaultDuplicateLabelsMode;
|
||
425 | } |
||
426 | return getPlacementConstraints().getDuplicateLabelsMode();
|
||
427 | } |
||
428 | |||
429 | private boolean lookupAndPlaceLabel(BufferedImage bi, Graphics2D g, |
||
430 | ArrayList<LabelLocationMetrics> llm, ILabelPlacement placement,
|
||
431 | 41789 | fdiaz | ILabelClass lc, Geometry geom, ViewPort viewPort, |
432 | 40911 | jldominguez | Cancellable cancel, boolean bLabelsReallocatable)
|
433 | 41789 | fdiaz | throws GeometryException {
|
434 | |||
435 | 42980 | fdiaz | GeometryManager gm = GeometryLocator.getGeometryManager(); |
436 | 40911 | jldominguez | int i;
|
437 | for (i = 0; !cancel.isCanceled() && i < llm.size(); i++) { |
||
438 | LabelLocationMetrics labelMetrics = llm.get(i); |
||
439 | |||
440 | IPlacementConstraints pc = getPlacementConstraints(); |
||
441 | 41789 | fdiaz | if (pc instanceof MultiShapePlacementConstraints) { |
442 | MultiShapePlacementConstraints mpc = (MultiShapePlacementConstraints) pc; |
||
443 | |||
444 | 40911 | jldominguez | GeometryType geom_gt = null;
|
445 | 41789 | fdiaz | |
446 | 40911 | jldominguez | geom_gt = gm.getGeometryType(geom.getType(), SUBTYPES.GEOM2D); |
447 | |||
448 | 41789 | fdiaz | if (geom_gt.getType() == TYPES.POINT
|
449 | || geom_gt.getType() == TYPES.MULTIPOINT) { |
||
450 | 40911 | jldominguez | pc = mpc.getPointConstraints(); |
451 | } else {
|
||
452 | 41789 | fdiaz | if (geom_gt.isTypeOf(TYPES.CURVE)
|
453 | || geom_gt.getType() == TYPES.MULTICURVE) { |
||
454 | 40911 | jldominguez | pc = mpc.getLineConstraints(); |
455 | } else {
|
||
456 | 41789 | fdiaz | if (geom_gt.isTypeOf(TYPES.SURFACE)
|
457 | || geom_gt.getType() == TYPES.MULTISURFACE) { |
||
458 | 40911 | jldominguez | pc = mpc.getPolygonConstraints(); |
459 | } |
||
460 | } |
||
461 | } |
||
462 | } |
||
463 | |||
464 | /*
|
||
465 | * Ver comentario en el metodo drawLabelInGeom
|
||
466 | */
|
||
467 | if (bLabelsReallocatable) {
|
||
468 | 41789 | fdiaz | |
469 | 40911 | jldominguez | Geometry aux_geom = null;
|
470 | aux_geom = lc.getShape(labelMetrics); |
||
471 | 41789 | fdiaz | |
472 | 40911 | jldominguez | if (!isOverlapping(bi, aux_geom)) {
|
473 | |||
474 | 41789 | fdiaz | if (!pc.isFollowingLine()) {
|
475 | 40911 | jldominguez | lc.draw(g, labelMetrics, geom); |
476 | } else {
|
||
477 | 41789 | fdiaz | |
478 | 41131 | jldominguez | ILabelClass smsLc = new SmartTextSymbolLabelClass();
|
479 | 41789 | fdiaz | SmartTextSymbol sms = new SmartTextSymbol(
|
480 | lc.getTextSymbol(), pc); |
||
481 | 40911 | jldominguez | |
482 | 41789 | fdiaz | double sizeBefore = lc.getTextSymbol().getFont()
|
483 | .getSize(); |
||
484 | double sizeAfter = SymbolUtils.getCartographicLength(
|
||
485 | this, sizeBefore, viewPort, viewPort.getDPI());
|
||
486 | 40911 | jldominguez | sms.setFontSize(sizeAfter); |
487 | |||
488 | smsLc.setTextSymbol(sms); |
||
489 | geom.transform(viewPort.getAffineTransform()); |
||
490 | smsLc.draw(g, null, geom);
|
||
491 | sms.setFontSize(sizeBefore); |
||
492 | |||
493 | } |
||
494 | return true; |
||
495 | } |
||
496 | } else {
|
||
497 | 41789 | fdiaz | if (!pc.isFollowingLine()) {
|
498 | 40911 | jldominguez | lc.draw(g, labelMetrics, null);
|
499 | 41789 | fdiaz | } else {
|
500 | ILabelClass smsLc = new SmartTextSymbolLabelClass();
|
||
501 | SmartTextSymbol sms = new SmartTextSymbol(
|
||
502 | lc.getTextSymbol(), pc); |
||
503 | 40911 | jldominguez | |
504 | double sizeBefore = lc.getTextSymbol().getFont().getSize();
|
||
505 | double sizeAfter = SymbolUtils.getCartographicLength(this, |
||
506 | 41789 | fdiaz | sizeBefore, viewPort, viewPort.getDPI()); |
507 | 40911 | jldominguez | sms.setFontSize(sizeAfter); |
508 | |||
509 | smsLc.setTextSymbol(sms); |
||
510 | geom.transform(viewPort.getAffineTransform()); |
||
511 | smsLc.draw(g, null, geom);
|
||
512 | |||
513 | sms.setFontSize(sizeBefore); |
||
514 | } |
||
515 | return true; |
||
516 | } |
||
517 | } |
||
518 | return false; |
||
519 | } |
||
520 | |||
521 | /**
|
||
522 | 41789 | fdiaz | * Divide una cadena de caracteres por el caracter dos puntos siempre que no
|
523 | * est? entre comillas.
|
||
524 | 40911 | jldominguez | *
|
525 | * @param str
|
||
526 | * Cadena de caracteres
|
||
527 | *
|
||
528 | * @return String[]
|
||
529 | *
|
||
530 | */
|
||
531 | 41789 | fdiaz | private String[] divideExpression(String str) { |
532 | 40911 | jldominguez | ArrayList<String> r = new ArrayList<String>(); |
533 | boolean inQuotationMarks = false; |
||
534 | int lastIndex = 0; |
||
535 | 41789 | fdiaz | for (int i = 0; i < str.length(); i++) { |
536 | 42171 | jbadia | String currentChar = str.substring(i, i + 1); |
537 | if (currentChar.compareTo("\"") == 0 ) { |
||
538 | 40911 | jldominguez | inQuotationMarks = !inQuotationMarks; |
539 | 42171 | jbadia | // Si es el cierre de las comillas
|
540 | if(!inQuotationMarks){
|
||
541 | r.add(str.substring(lastIndex, i + 1).replace("\"", "'")); |
||
542 | lastIndex = i + 1;
|
||
543 | } |
||
544 | 40911 | jldominguez | } |
545 | 42171 | jbadia | if (currentChar.compareTo(":") == 0 |
546 | 41789 | fdiaz | && !inQuotationMarks) { |
547 | if (lastIndex < i) {
|
||
548 | 40911 | jldominguez | r.add(str.substring(lastIndex, i)); |
549 | } |
||
550 | 41789 | fdiaz | lastIndex = i + 1;
|
551 | 40911 | jldominguez | } |
552 | } |
||
553 | 41789 | fdiaz | if (lastIndex < str.length() - 1) { |
554 | 40911 | jldominguez | r.add(str.substring(lastIndex)); |
555 | } |
||
556 | String[] result = new String[r.size()]; |
||
557 | r.toArray(result); |
||
558 | return result;
|
||
559 | } |
||
560 | |||
561 | /**
|
||
562 | * Compute the texts to show in the label and store them in LabelClass.
|
||
563 | */
|
||
564 | @SuppressWarnings("unchecked") |
||
565 | private boolean setupLabel(Feature featu, ILabelClass lc, |
||
566 | Cancellable cancel, String[] usedFields, ViewPort viewPort, |
||
567 | 41789 | fdiaz | double dpi, int duplicateMode) { |
568 | 40911 | jldominguez | |
569 | String expr = lc.getStringLabelExpression();
|
||
570 | |||
571 | long pt1 = System.currentTimeMillis(); |
||
572 | String[] texts = NO_TEXT; |
||
573 | 41421 | jjdelcerro | List<String> preTexts = new ArrayList<String>(); |
574 | 40911 | jldominguez | try {
|
575 | if (expr != null) { |
||
576 | |||
577 | if (expr.equals("")) { |
||
578 | expr = texts[0];
|
||
579 | } |
||
580 | |||
581 | String[] multiexpr = divideExpression(expr); |
||
582 | 41789 | fdiaz | for (int i = 0; i < multiexpr.length; i++) { |
583 | |||
584 | 40911 | jldominguez | expr = multiexpr[i]; |
585 | 41789 | fdiaz | Object res = LabelClassUtils.evaluate(expr,
|
586 | featu.getEvaluatorData()); |
||
587 | 40911 | jldominguez | if (res != null) { |
588 | preTexts.add(res.toString()); |
||
589 | } else {
|
||
590 | 41421 | jjdelcerro | preTexts.add("");
|
591 | 40911 | jldominguez | } |
592 | } |
||
593 | texts = new String[preTexts.size()]; |
||
594 | preTexts.toArray(texts); |
||
595 | 41789 | fdiaz | // parseTime += System.currentTimeMillis()-pt1;
|
596 | 40911 | jldominguez | } |
597 | lc.setTexts(texts); |
||
598 | |||
599 | } catch (Exception e) { |
||
600 | 41421 | jjdelcerro | logger.warn("While setting up label", e);
|
601 | 40911 | jldominguez | return false; |
602 | } |
||
603 | return true; |
||
604 | } |
||
605 | 41789 | fdiaz | |
606 | 42980 | fdiaz | private boolean isOverlapping(BufferedImage bi, Geometry lblgeom) { |
607 | 41789 | fdiaz | |
608 | 42980 | fdiaz | for (Iterator iterator = drawnGeometryLabels.iterator(); iterator.hasNext();) { |
609 | Geometry drawnGeometry = (Geometry) iterator.next(); |
||
610 | try {
|
||
611 | if (drawnGeometry.intersects(lblgeom)) {
|
||
612 | 42555 | fdiaz | return true; |
613 | } |
||
614 | 42980 | fdiaz | } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
|
615 | logger.warn("Can't check overlapping geometry");
|
||
616 | 42555 | fdiaz | } |
617 | } |
||
618 | 42980 | fdiaz | drawnGeometryLabels.add(lblgeom); |
619 | return false; |
||
620 | 40911 | jldominguez | |
621 | 42980 | fdiaz | } |
622 | |||
623 | 40911 | jldominguez | private boolean isOnePoint(ViewPort viewPort, Geometry geom) { |
624 | 41789 | fdiaz | |
625 | 40911 | jldominguez | boolean onePoint = false; |
626 | int shapeType = geom.getType();
|
||
627 | 41789 | fdiaz | |
628 | 40911 | jldominguez | if (shapeType != TYPES.POINT && shapeType != TYPES.MULTIPOINT) {
|
629 | |||
630 | Envelope env = geom.getEnvelope(); |
||
631 | double dist1Pixel = viewPort.getDist1pixel();
|
||
632 | 41789 | fdiaz | onePoint = (env.getLength(0) <= dist1Pixel && env.getLength(1) <= dist1Pixel); |
633 | 40911 | jldominguez | } |
634 | return onePoint;
|
||
635 | } |
||
636 | |||
637 | public boolean isAllowingOverlap() { |
||
638 | return allowOverlapping;
|
||
639 | } |
||
640 | |||
641 | public void setAllowOverlapping(boolean allowOverlapping) { |
||
642 | this.allowOverlapping = allowOverlapping;
|
||
643 | } |
||
644 | |||
645 | public IPlacementConstraints getPlacementConstraints() {
|
||
646 | if (placementConstraints != null) |
||
647 | return placementConstraints;
|
||
648 | |||
649 | GeometryType gt = null;
|
||
650 | 41789 | fdiaz | |
651 | 40911 | jldominguez | try {
|
652 | gt = layer.getGeometryType(); |
||
653 | // force 2d for comparison
|
||
654 | gt = GeometryLocator.getGeometryManager().getGeometryType( |
||
655 | gt.getType(), SUBTYPES.GEOM2D); |
||
656 | } catch (Exception e) { |
||
657 | logger.error("While getting placements constraints.", e);
|
||
658 | return null; |
||
659 | } |
||
660 | 41789 | fdiaz | |
661 | if (gt.isTypeOf(TYPES.POINT) || gt.isTypeOf(TYPES.MULTIPOINT)) {
|
||
662 | 40911 | jldominguez | return DefaultPointPlacementConstraints;
|
663 | } else {
|
||
664 | 41789 | fdiaz | if (gt.isTypeOf(TYPES.CURVE) || gt.isTypeOf(TYPES.MULTICURVE)) {
|
665 | 40911 | jldominguez | return DefaultLinePlacementConstraints;
|
666 | } else {
|
||
667 | if (gt.isTypeOf(TYPES.SURFACE)
|
||
668 | || gt.isTypeOf(TYPES.MULTISURFACE)) { |
||
669 | return DefaultPolygonPlacementConstraints;
|
||
670 | } else {
|
||
671 | 41789 | fdiaz | if (gt.isTypeOf(TYPES.AGGREGATE)
|
672 | || gt.isTypeOf(TYPES.GEOMETRY)) { |
||
673 | DefaultMultiShapePlacementConstratints |
||
674 | .setPointConstraints(DefaultPointPlacementConstraints); |
||
675 | DefaultMultiShapePlacementConstratints |
||
676 | .setLineConstraints(DefaultLinePlacementConstraints); |
||
677 | DefaultMultiShapePlacementConstratints |
||
678 | .setPolygonConstraints(DefaultPolygonPlacementConstraints); |
||
679 | 40911 | jldominguez | return DefaultMultiShapePlacementConstratints;
|
680 | } |
||
681 | } |
||
682 | } |
||
683 | } |
||
684 | return null; |
||
685 | } |
||
686 | |||
687 | public void setPlacementConstraints(IPlacementConstraints constraints) { |
||
688 | this.placementConstraints = constraints;
|
||
689 | } |
||
690 | |||
691 | public IZoomConstraints getZoomConstraints() {
|
||
692 | return zoomConstraints;
|
||
693 | } |
||
694 | |||
695 | public void setZoomConstraints(IZoomConstraints constraints) { |
||
696 | this.zoomConstraints = constraints;
|
||
697 | } |
||
698 | |||
699 | 41789 | fdiaz | public void print(Graphics2D g, double scale, ViewPort viewPort, |
700 | 40911 | jldominguez | Cancellable cancel, PrintAttributes properties) |
701 | throws ReadException {
|
||
702 | 41789 | fdiaz | |
703 | 40911 | jldominguez | double dpi = 100; |
704 | int pq = properties.getPrintQuality();
|
||
705 | 41789 | fdiaz | if (pq == PrintAttributes.PRINT_QUALITY_NORMAL) {
|
706 | 40911 | jldominguez | dpi = 300;
|
707 | 41789 | fdiaz | } else if (pq == PrintAttributes.PRINT_QUALITY_HIGH) { |
708 | 40911 | jldominguez | dpi = 600;
|
709 | 41789 | fdiaz | } else if (pq == PrintAttributes.PRINT_QUALITY_DRAFT) { |
710 | 40911 | jldominguez | dpi = 72;
|
711 | } |
||
712 | |||
713 | 45028 | fdiaz | //refs: #5270
|
714 | // viewPort.setOffset(new Point2D.Double(0, 0));
|
||
715 | 41789 | fdiaz | |
716 | 40911 | jldominguez | /* signal printing output */
|
717 | printMode = true;
|
||
718 | |||
719 | 41789 | fdiaz | draw(null, g, scale, viewPort, cancel, dpi);
|
720 | 40911 | jldominguez | } |
721 | |||
722 | public String[] getUsedFields() { |
||
723 | |||
724 | /*
|
||
725 | 41789 | fdiaz | * TODO Solve the problem with the [ and ]. Currently SQLJEP evaluator
|
726 | * cannot tell which fields are being used. Options: allow [] and remove
|
||
727 | * them or maybe while parsing the SQLJEP evaluator can inform with
|
||
728 | * events like "I have found a field"
|
||
729 | 40911 | jldominguez | */
|
730 | 41789 | fdiaz | |
731 | 40911 | jldominguez | FeatureAttributeDescriptor[] atts = null; |
732 | try {
|
||
733 | 41789 | fdiaz | atts = layer.getFeatureStore().getDefaultFeatureType() |
734 | .getAttributeDescriptors(); |
||
735 | 40911 | jldominguez | } catch (DataException e) {
|
736 | logger.error("While getting atributes.", e);
|
||
737 | } |
||
738 | 41789 | fdiaz | |
739 | 40911 | jldominguez | int n = atts.length;
|
740 | String[] resp = new String[n]; |
||
741 | 41789 | fdiaz | for (int i = 0; i < n; i++) { |
742 | 40911 | jldominguez | resp[i] = atts[i].getName(); |
743 | } |
||
744 | return resp;
|
||
745 | |||
746 | } |
||
747 | |||
748 | public boolean shouldDrawLabels(double scale) { |
||
749 | double minScaleView = -1; |
||
750 | double maxScaleView = -1; |
||
751 | |||
752 | if (zoomConstraints != null) { |
||
753 | minScaleView = zoomConstraints.getMinScale(); |
||
754 | maxScaleView = zoomConstraints.getMaxScale(); |
||
755 | } |
||
756 | |||
757 | if (minScaleView == -1 && maxScaleView == -1) { |
||
758 | // parameters not set, so the layer decides.
|
||
759 | return layer.isWithinScale(scale);
|
||
760 | } |
||
761 | |||
762 | if (minScaleView >= scale) {
|
||
763 | return (maxScaleView != -1) ? maxScaleView <= scale : true; |
||
764 | } |
||
765 | |||
766 | return false; |
||
767 | } |
||
768 | |||
769 | public void setUnit(int unitIndex) { |
||
770 | unit = unitIndex; |
||
771 | |||
772 | } |
||
773 | |||
774 | public int getUnit() { |
||
775 | return unit;
|
||
776 | } |
||
777 | |||
778 | public int getReferenceSystem() { |
||
779 | return referenceSystem;
|
||
780 | } |
||
781 | |||
782 | public void setReferenceSystem(int referenceSystem) { |
||
783 | this.referenceSystem = referenceSystem;
|
||
784 | } |
||
785 | 41789 | fdiaz | |
786 | 40911 | jldominguez | public static void registerPersistent() { |
787 | 41789 | fdiaz | |
788 | PersistenceManager manager = ToolsLocator.getPersistenceManager(); |
||
789 | if (manager.getDefinition(GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME) == null) { |
||
790 | DynStruct definition = manager.addDefinition( |
||
791 | GeneralLabelingStrategy.class, |
||
792 | GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME, |
||
793 | GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME |
||
794 | + " Persistence definition", null, null); |
||
795 | definition.addDynFieldObject("labelingMethod")
|
||
796 | .setClassOfValue(ILabelingMethod.class).setMandatory(true);
|
||
797 | definition.addDynFieldObject("placementConstraints")
|
||
798 | .setClassOfValue(IPlacementConstraints.class) |
||
799 | .setMandatory(false);
|
||
800 | definition.addDynFieldObject("zoomConstraints")
|
||
801 | .setClassOfValue(IZoomConstraints.class) |
||
802 | .setMandatory(false);
|
||
803 | |||
804 | definition.addDynFieldBoolean("allowOverlapping")
|
||
805 | .setMandatory(true);
|
||
806 | definition.addDynFieldInt("unit").setMandatory(true); |
||
807 | definition.addDynFieldInt("referenceSystem").setMandatory(true); |
||
808 | } |
||
809 | 40911 | jldominguez | } |
810 | 41789 | fdiaz | |
811 | public void loadFromState(PersistentState state) |
||
812 | throws PersistenceException {
|
||
813 | |||
814 | 40911 | jldominguez | method = (ILabelingMethod) state.get("labelingMethod");
|
815 | 41789 | fdiaz | |
816 | 40911 | jldominguez | if (state.hasValue("placementConstraints")) { |
817 | 41789 | fdiaz | placementConstraints = (IPlacementConstraints) state |
818 | .get("placementConstraints");
|
||
819 | 40911 | jldominguez | } |
820 | 41789 | fdiaz | |
821 | 40911 | jldominguez | if (state.hasValue("zoomConstraints")) { |
822 | zoomConstraints = (IZoomConstraints) state.get("zoomConstraints");
|
||
823 | } |
||
824 | |||
825 | this.allowOverlapping = state.getBoolean("allowOverlapping"); |
||
826 | this.unit = state.getInt("unit"); |
||
827 | this.referenceSystem = state.getInt("referenceSystem"); |
||
828 | } |
||
829 | |||
830 | public void saveToState(PersistentState state) throws PersistenceException { |
||
831 | 41789 | fdiaz | |
832 | 40911 | jldominguez | state.set("labelingMethod", method);
|
833 | 41789 | fdiaz | |
834 | 40911 | jldominguez | if (placementConstraints != null) { |
835 | state.set("placementConstraints", placementConstraints);
|
||
836 | } |
||
837 | |||
838 | if (zoomConstraints != null) { |
||
839 | state.set("zoomConstraints", zoomConstraints);
|
||
840 | } |
||
841 | |||
842 | state.set("allowOverlapping", allowOverlapping);
|
||
843 | state.set("unit", unit);
|
||
844 | state.set("referenceSystem", referenceSystem);
|
||
845 | |||
846 | } |
||
847 | |||
848 | public double toCartographicSize(ViewPort vp, double dpi, Geometry geom) { |
||
849 | /*
|
||
850 | * This method is not used but we must implement CartographicSupport
|
||
851 | */
|
||
852 | return 0; |
||
853 | } |
||
854 | |||
855 | public void setCartographicSize(double cartographicSize, Geometry geom) { |
||
856 | /*
|
||
857 | * This method is not used but we must implement CartographicSupport
|
||
858 | */
|
||
859 | } |
||
860 | |||
861 | public double getCartographicSize(ViewPort vp, double dpi, Geometry geom) { |
||
862 | /*
|
||
863 | * This method is not used but we must implement CartographicSupport
|
||
864 | */
|
||
865 | return 0; |
||
866 | } |
||
867 | 41789 | fdiaz | |
868 | 40911 | jldominguez | public Object clone() throws CloneNotSupportedException { |
869 | return LabelClassUtils.clone(this); |
||
870 | } |
||
871 | |||
872 | } |