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
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
import java.util.List;
9
import java.util.TreeMap;
10
import java.util.TreeSet;
11
import org.cresques.cts.ICoordTrans;
12

    
13
import org.slf4j.Logger;
14
import org.slf4j.LoggerFactory;
15

    
16
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
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
29
import org.gvsig.fmap.geom.operation.GeometryOperationException;
30
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
31
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

    
64
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
        private static String[] NO_TEXT = { Messages.getText("text_field") };
77

    
78
        private static MultiShapePlacementConstraints DefaultMultiShapePlacementConstratints = new MultiShapePlacementConstraints();
79

    
80
        private ILabelingMethod method;
81
        private IPlacementConstraints placementConstraints;
82
        private IZoomConstraints zoomConstraints;
83

    
84
        private boolean allowOverlapping;
85

    
86
        protected FLyrVect layer;
87

    
88
        // private long parseTime;
89
        private int unit;
90
        private int referenceSystem;
91
        // private double sizeAfter;
92
        private boolean printMode = false; /*
93
                                                                                 * indicate whether output is for a
94
                                                                                 * print product (PDF, PS, ...)
95
                                                                                 */
96

    
97
        private List<Geometry> drawnGeometryLabels;
98

    
99
        public GeneralLabelingStrategy() {
100
                method = SymbologyLocator.getSymbologyManager()
101
                                .createDefaultLabelingMethod();
102
        }
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
        private class GeometryItem {
118
                public Geometry geom = null;
119
                public int weigh = 0;
120
                public double savedPerimeter;
121

    
122
                public GeometryItem(Geometry geom, int weigh) {
123
                        this.geom = geom;
124
                        this.weigh = weigh;
125
                        this.savedPerimeter = 0;
126
                }
127
        }
128

    
129
    public void draw(BufferedImage mapImage, Graphics2D mapGraphics, double scale, ViewPort viewPort,
130
        Cancellable cancel, double dpi) throws ReadException {
131

    
132
        drawnGeometryLabels = new ArrayList<Geometry>(1000);
133

    
134
        int x = (int) viewPort.getOffset().getX();
135
        int y = (int) viewPort.getOffset().getY();
136

    
137
        // 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

    
147
        TreeMap<String[], GeometryItem> labelsToPlace = null;
148

    
149
        String[] usedFields = getUsedFields();
150

    
151
        int notPlacedCount = 0;
152
        int placedCount = 0;
153

    
154
        /*
155
         * Get the label placement solvers according the user's settings
156
         */
157
        ILabelPlacement placement = PlacementManager.getPlacement(getPlacementConstraints(), layer.getShapeType());
158

    
159
        BufferedImage targetBI;
160
        Graphics2D targetGr;
161

    
162
        /*
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

    
168
        for (int i = 0; i < lcs.length; i++)
169
            ts.add(lcs[i]);
170

    
171
        if (ts.size() == 0)
172
            return;
173

    
174
        /*
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

    
182
            if (!lc.isVisible(scale)) {
183
                /*
184
                 * Avoid non-visible labels
185
                 */
186
                continue;
187
            }
188

    
189
            FeatureSet fset = null;
190
            DisposableIterator diter = null;
191
            try {
192

    
193
                try {
194
                    fset = method.getFeatureIteratorByLabelClass(layer, lc, viewPort, usedFields);
195
                } catch (DataException e) {
196
                    throw new ReadException(layer.getFeatureStore().getProviderName(), e);
197
                }
198

    
199
                // 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

    
205
                    labelsToPlace = new TreeMap<String[], GeometryItem>(new RemoveDuplicatesComparator());
206
                }
207

    
208
                boolean bLabelsReallocatable = !isAllowingOverlap();
209

    
210
                BufferedImage overlapDetectImage = null;
211
                Graphics2D overlapDetectGraphics = null;
212
                if (bLabelsReallocatable) {
213
                    int width = viewPort.getImageWidth() + print_offset_x;
214

    
215
                    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

    
231
                    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

    
243
                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

    
251
                while (!cancel.isCanceled() && diter.hasNext()) {
252

    
253
                    featu = ((Feature) diter.next()).getCopy();
254
                    geome = featu.getDefaultGeometry();
255
                    if (geome == null || geome.getType() == Geometry.TYPES.NULL) {
256
                        continue;
257
                    }
258
                    ICoordTrans ct = layer.getCoordTrans();
259
                    if( ct!=null ) {
260
                        geome.reProject(ct);
261
                    }
262
                    if (!setupLabel(featu, lc, cancel, usedFields, viewPort, dpi, duplicateMode)) {
263
                        continue;
264
                    }
265

    
266
                    String[] texts = lc.getTexts();
267

    
268
                    if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
269
                        // check if this text (so label) is already present in
270
                        // the map
271

    
272
                        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

    
279
                            notPlacedCount++;
280
                            if (geome.getType() != Geometry.TYPES.POINT) {
281

    
282
                                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

    
291
                                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

    
303
                            }
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

    
314
                        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

    
321
                        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

    
331
                        placedCount++;
332
                    }
333
                }
334

    
335
                // ======= End iteration in feature set ====================
336

    
337
                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

    
343
                        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

    
351
                            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

    
361
                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

    
370
            } finally {
371
                if (diter != null) {
372
                    diter.dispose();
373
                }
374
                if (fset != null) {
375
                    fset.dispose();
376
                }
377
            }
378
        } // big iteration
379

    
380
    }
381

    
382
        private List<Geometry> getGeometryParts(Geometry ge) {
383

    
384
                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

    
399
        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
                lc.toCartographicSize(viewPort, dpi, null);
405
                ArrayList<LabelLocationMetrics> llm = null;
406
                llm = placement.guess(lc, geom, getPlacementConstraints(), 0, cancel,
407
                                viewPort);
408

    
409
                setReferenceSystem(lc.getReferenceSystem());
410
                setUnit(lc.getUnit());
411

    
412
                /*
413
                 * search if there is room left by the previous and with more priority
414
                 * labels, then check the current level
415
                 */
416
                lookupAndPlaceLabel(targetBI, targetGr, llm, placement, lc, geom,
417
                                viewPort, cancel, bLabelsReallocatable);
418

    
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
                        ILabelClass lc, Geometry geom, ViewPort viewPort,
431
                        Cancellable cancel, boolean bLabelsReallocatable)
432
                        throws GeometryException {
433

    
434
            GeometryManager gm = GeometryLocator.getGeometryManager();
435
                int i;
436
                for (i = 0; !cancel.isCanceled() && i < llm.size(); i++) {
437
                        LabelLocationMetrics labelMetrics = llm.get(i);
438

    
439
                        IPlacementConstraints pc = getPlacementConstraints();
440
                        if (pc instanceof MultiShapePlacementConstraints) {
441
                                MultiShapePlacementConstraints mpc = (MultiShapePlacementConstraints) pc;
442

    
443
                                GeometryType geom_gt = null;
444

    
445
                                geom_gt = gm.getGeometryType(geom.getType(), SUBTYPES.GEOM2D);
446

    
447
                                if (geom_gt.getType() == TYPES.POINT
448
                                                || geom_gt.getType() == TYPES.MULTIPOINT) {
449
                                        pc = mpc.getPointConstraints();
450
                                } else {
451
                                        if (geom_gt.isTypeOf(TYPES.CURVE)
452
                                                        || geom_gt.getType() == TYPES.MULTICURVE) {
453
                                                pc = mpc.getLineConstraints();
454
                                        } else {
455
                                                if (geom_gt.isTypeOf(TYPES.SURFACE)
456
                                                                || geom_gt.getType() == TYPES.MULTISURFACE) {
457
                                                        pc = mpc.getPolygonConstraints();
458
                                                }
459
                                        }
460
                                }
461
                        }
462

    
463
                        /*
464
                         * Ver comentario en el metodo drawLabelInGeom
465
                         */
466
                        if (bLabelsReallocatable) {
467

    
468
                                Geometry aux_geom = null;
469
                                aux_geom = lc.getShape(labelMetrics);
470

    
471
                                if (!isOverlapping(bi, aux_geom)) {
472

    
473
                                        if (!pc.isFollowingLine()) {
474
                                                lc.draw(g, labelMetrics, geom);
475
                                        } else {
476

    
477
                                                ILabelClass smsLc = new SmartTextSymbolLabelClass();
478
                                                SmartTextSymbol sms = new SmartTextSymbol(
479
                                                                lc.getTextSymbol(), pc);
480

    
481
                                                double sizeBefore = lc.getTextSymbol().getFont()
482
                                                                .getSize();
483
                                                double sizeAfter = SymbolUtils.getCartographicLength(
484
                                                                this, sizeBefore, viewPort, viewPort.getDPI());
485
                                                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
                                if (!pc.isFollowingLine()) {
497
                                        lc.draw(g, labelMetrics, null);
498
                                } else {
499
                                        ILabelClass smsLc = new SmartTextSymbolLabelClass();
500
                                        SmartTextSymbol sms = new SmartTextSymbol(
501
                                                        lc.getTextSymbol(), pc);
502

    
503
                                        double sizeBefore = lc.getTextSymbol().getFont().getSize();
504
                                        double sizeAfter = SymbolUtils.getCartographicLength(this,
505
                                                        sizeBefore, viewPort, viewPort.getDPI());
506
                                        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
         * Divide una cadena de caracteres por el caracter dos puntos siempre que no
522
         * est? entre comillas.
523
         *
524
         * @param str
525
         *            Cadena de caracteres
526
         *
527
         * @return String[]
528
         *
529
         */
530
        private String[] divideExpression(String str) {
531
                ArrayList<String> r = new ArrayList<String>();
532
                boolean inQuotationMarks = false;
533
                int lastIndex = 0;
534
                for (int i = 0; i < str.length(); i++) {
535
                        String currentChar = str.substring(i, i + 1);
536
                        if (currentChar.compareTo("\"") == 0 ) {
537
                                inQuotationMarks = !inQuotationMarks;
538
                                // 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
                        }
544
                        if (currentChar.compareTo(":") == 0
545
                                        && !inQuotationMarks) {
546
                                if (lastIndex < i) {
547
                                        r.add(str.substring(lastIndex, i));
548
                                }
549
                                lastIndex = i + 1;
550
                        }
551
                }
552
                if (lastIndex < str.length() - 1) {
553
                        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
                        double dpi, int duplicateMode) {
567

    
568
                String expr = lc.getStringLabelExpression();
569

    
570
                long pt1 = System.currentTimeMillis();
571
                String[] texts = NO_TEXT;
572
                List<String> preTexts = new ArrayList<String>();
573
                try {
574
                        if (expr != null) {
575

    
576
                                if (expr.equals("")) {
577
                                        expr = texts[0];
578
                                }
579

    
580
                                String[] multiexpr = divideExpression(expr);
581
                                for (int i = 0; i < multiexpr.length; i++) {
582

    
583
                                        expr = multiexpr[i];
584
                                        Object res = LabelClassUtils.evaluate(expr,
585
                                                        featu.getEvaluatorData());
586
                                        if (res != null) {
587
                                                preTexts.add(res.toString());
588
                                        } else {
589
                                                preTexts.add("");
590
                                        }
591
                                }
592
                                texts = new String[preTexts.size()];
593
                                preTexts.toArray(texts);
594
                                // parseTime += System.currentTimeMillis()-pt1;
595
                        }
596
                        lc.setTexts(texts);
597

    
598
                } catch (Exception e) {
599
                        logger.warn("While setting up label", e);
600
                        return false;
601
                }
602
                return true;
603
        }
604

    
605
    private boolean isOverlapping(BufferedImage bi, Geometry lblgeom) {
606

    
607
        for (Iterator iterator = drawnGeometryLabels.iterator(); iterator.hasNext();) {
608
            Geometry drawnGeometry = (Geometry) iterator.next();
609
            try {
610
                if (drawnGeometry.intersects(lblgeom)) {
611
                    return true;
612
                }
613
            } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
614
                logger.warn("Can't check overlapping geometry");
615
            }
616
        }
617
        drawnGeometryLabels.add(lblgeom);
618
        return false;
619

    
620
    }
621

    
622
        private boolean isOnePoint(ViewPort viewPort, Geometry geom) {
623

    
624
                boolean onePoint = false;
625
                int shapeType = geom.getType();
626

    
627
                if (shapeType != TYPES.POINT && shapeType != TYPES.MULTIPOINT) {
628

    
629
                        Envelope env = geom.getEnvelope();
630
                        double dist1Pixel = viewPort.getDist1pixel();
631
                        onePoint = (env.getLength(0) <= dist1Pixel && env.getLength(1) <= dist1Pixel);
632
                }
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

    
650
                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

    
660
                if (gt.isTypeOf(TYPES.POINT) || gt.isTypeOf(TYPES.MULTIPOINT)) {
661
                        return DefaultPointPlacementConstraints;
662
                } else {
663
                        if (gt.isTypeOf(TYPES.CURVE) || gt.isTypeOf(TYPES.MULTICURVE)) {
664
                                return DefaultLinePlacementConstraints;
665
                        } else {
666
                                if (gt.isTypeOf(TYPES.SURFACE)
667
                                                || gt.isTypeOf(TYPES.MULTISURFACE)) {
668
                                        return DefaultPolygonPlacementConstraints;
669
                                } else {
670
                                        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
                                                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
        public void print(Graphics2D g, double scale, ViewPort viewPort,
699
                        Cancellable cancel, PrintAttributes properties)
700
                        throws ReadException {
701

    
702
                double dpi = 100;
703
                int pq = properties.getPrintQuality();
704
                if (pq == PrintAttributes.PRINT_QUALITY_NORMAL) {
705
                        dpi = 300;
706
                } else if (pq == PrintAttributes.PRINT_QUALITY_HIGH) {
707
                        dpi = 600;
708
                } else if (pq == PrintAttributes.PRINT_QUALITY_DRAFT) {
709
                        dpi = 72;
710
                }
711

    
712
                viewPort.setOffset(new Point2D.Double(0, 0));
713

    
714
                /* signal printing output */
715
                printMode = true;
716

    
717
                draw(null, g, scale, viewPort, cancel, dpi);
718
        }
719

    
720
        public String[] getUsedFields() {
721

    
722
                /*
723
                 * 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
                 */
728

    
729
                FeatureAttributeDescriptor[] atts = null;
730
                try {
731
                        atts = layer.getFeatureStore().getDefaultFeatureType()
732
                                        .getAttributeDescriptors();
733
                } catch (DataException e) {
734
                        logger.error("While getting atributes.", e);
735
                }
736

    
737
                int n = atts.length;
738
                String[] resp = new String[n];
739
                for (int i = 0; i < n; i++) {
740
                        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

    
784
        public static void registerPersistent() {
785

    
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
        }
808

    
809
        public void loadFromState(PersistentState state)
810
                        throws PersistenceException {
811

    
812
                method = (ILabelingMethod) state.get("labelingMethod");
813

    
814
                if (state.hasValue("placementConstraints")) {
815
                        placementConstraints = (IPlacementConstraints) state
816
                                        .get("placementConstraints");
817
                }
818

    
819
                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

    
830
                state.set("labelingMethod", method);
831

    
832
                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

    
866
        public Object clone() throws CloneNotSupportedException {
867
                return LabelClassUtils.clone(this);
868
        }
869

    
870
}