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

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