Statistics
| Revision:

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 @ 42980

History | View | Annotate | Download (32.2 KB)

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