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

History | View | Annotate | Download (29.2 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 IGeneralLabelingStrategy {
65

    
66
        private static final Logger logger = LoggerFactory
67
                        .getLogger(GeneralLabelingStrategy.class);
68

    
69
        public static final String GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME = "GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME";
70

    
71
        public static PointPlacementConstraints DefaultPointPlacementConstraints = new PointPlacementConstraints();
72
        public static LinePlacementConstraints DefaultLinePlacementConstraints = new LinePlacementConstraints();
73
        public static PolygonPlacementConstraints DefaultPolygonPlacementConstraints = new PolygonPlacementConstraints();
74

    
75
        private static String[] NO_TEXT = { Messages.getText("text_field") };
76

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

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

    
83
        private boolean allowOverlapping;
84

    
85
        protected FLyrVect layer;
86

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

    
96
        private List<Geometry> drawnGeometryLabels;
97

    
98
        public GeneralLabelingStrategy() {
99
                method = SymbologyLocator.getSymbologyManager()
100
                                .createDefaultLabelingMethod();
101
        }
102

    
103
        public void setLayer(FLayer layer) {
104
                FLyrVect l = (FLyrVect) layer;
105
                this.layer = l;
106
        }
107

    
108
        public ILabelingMethod getLabelingMethod() {
109
                return method;
110
        }
111

    
112
        public void setLabelingMethod(ILabelingMethod method) {
113
                this.method = method;
114
        }
115

    
116
        private class GeometryItem {
117
                public Geometry geom = null;
118
                public int weigh = 0;
119
                public double savedPerimeter;
120

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

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

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

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

    
136
        // offsets for page generation (PDF, PS, direct printing)
137
        int print_offset_x = x;
138
        int print_offset_y = y;
139
        if (printMode) {
140
            // for printing, we never offset the labels themselves
141
            x = 0;
142
            y = 0;
143
            printMode = false;
144
        }
145

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

    
148
        String[] usedFields = getUsedFields();
149

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

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

    
158
        BufferedImage targetBI;
159
        Graphics2D targetGr;
160

    
161
        /*
162
         * get an ordered set of the LabelClasses up on the label priority
163
         */
164
        ILabelClass[] lcs = method.getLabelClasses();
165
        TreeSet<ILabelClass> ts = new TreeSet<ILabelClass>(new LabelClassComparatorByPriority());
166

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

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

    
173
        /*
174
         * now we have an ordered set, it is only need to give a pass for each
175
         * label class to render by priorities.
176
         *
177
         * If no priorities were defined, the following loop only executes once
178
         */
179
        for (ILabelClass lc : ts) {
180

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

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

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

    
198
                // duplicates treatment stuff
199
                /* handle the duplicates mode */
200
                int duplicateMode = getDuplicateLabelsMode();
201
                if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
202
                    // we need to register the labels already placed
203

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

    
207
                boolean bLabelsReallocatable = !isAllowingOverlap();
208

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

    
214
                    if (width < 0) {
215
                        width = 1;
216
                    }
217
                    int height = viewPort.getImageHeight() + print_offset_y;
218
                    if (height < 0) {
219
                        height = 1;
220
                    }
221
                    if (mapImage != null)
222
                        overlapDetectImage =
223
                            new BufferedImage(mapImage.getWidth() + print_offset_x, mapImage.getHeight()
224
                                + print_offset_y, BufferedImage.TYPE_INT_ARGB);
225
                    else
226
                        overlapDetectImage =
227
                            new BufferedImage(viewPort.getImageWidth() + print_offset_x, viewPort.getImageHeight()
228
                                + print_offset_y, BufferedImage.TYPE_INT_ARGB);
229

    
230
                    overlapDetectGraphics = overlapDetectImage.createGraphics();
231
                    overlapDetectGraphics.setRenderingHints(mapGraphics.getRenderingHints());
232
                }
233
                if (bLabelsReallocatable) {
234
                    targetBI = overlapDetectImage;
235
                    targetGr = overlapDetectGraphics;
236
                    targetGr.translate(-x, -y);
237
                } else {
238
                    targetBI = mapImage;
239
                    targetGr = mapGraphics;
240
                }
241

    
242
                try {
243
                    diter = fset.fastIterator();
244
                } catch (DataException e) {
245
                    throw new ReadException(layer.getFeatureStore().getProviderName(), e);
246
                }
247
                Feature featu = null;
248
                Geometry geome = null;
249

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

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

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

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

    
271
                        GeometryItem item = labelsToPlace.get(texts);
272
                        if (item == null) {
273
                            item = new GeometryItem(geome, 0);
274
                            labelsToPlace.put(texts, item);
275
                        }
276
                        if (item.geom != null) {
277

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

    
281
                                Envelope auxBox = geome.getEnvelope();
282
                                double perimeterAux = 2 * (auxBox.getLength(0) + auxBox.getLength(1));
283
                                if (perimeterAux > item.savedPerimeter) {
284
                                    item.geom = geome; // FConverter.jts_to_igeometry(jtsGeom);
285
                                    item.savedPerimeter = perimeterAux;
286
                                }
287
                            } else {
288
                                int weigh = item.weigh;
289

    
290
                                try {
291
                                    Point pointFromLabel = item.geom.centroid();
292
                                    Point pointGeome = geome.centroid();
293
                                    item.geom =
294
                                        GeometryLocator.getGeometryManager().createPoint(
295
                                            (pointFromLabel.getX() * weigh + pointGeome.getX()) / (weigh + 1),
296
                                            (pointFromLabel.getY() * weigh + pointGeome.getY()) / (weigh + 1),
297
                                            Geometry.SUBTYPES.GEOM2D);
298
                                } catch (Exception ex) {
299
                                    throw new ReadException(layer.getFeatureStore().getProviderName(), ex);
300
                                }
301

    
302
                            }
303
                        } else {
304
                            item.geom = geome;
305
                        }
306
                        item.weigh++;
307
                    } else {
308
                        // Check if size is a pixel
309
                        if (isOnePoint(viewPort, geome)) {
310
                            continue;
311
                        }
312

    
313
                        List<Geometry> geome_parts = new ArrayList<Geometry>();
314
                        if (duplicateMode == IPlacementConstraints.ONE_LABEL_PER_FEATURE_PART) {
315
                            geome_parts = getGeometryParts(geome);
316
                        } else {
317
                            geome_parts.add(geome);
318
                        }
319

    
320
                        try {
321
                            int n = geome_parts.size();
322
                            for (int k = 0; k < n; k++) {
323
                                drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, geome_parts.get(k),
324
                                    cancel, dpi, bLabelsReallocatable);
325
                            }
326
                        } catch (GeometryException e) {
327
                            throw new ReadException(layer.getFeatureStore().getProviderName(), e);
328
                        }
329

    
330
                        placedCount++;
331
                    }
332
                }
333

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

    
336
                if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
337
                    Iterator<String[]> textsIt = labelsToPlace.keySet().iterator();
338
                    while (!cancel.isCanceled() && textsIt.hasNext()) {
339
                        notPlacedCount++;
340
                        String[] texts = textsIt.next();
341

    
342
                        GeometryItem item = labelsToPlace.get(texts);
343
                        if (item != null) {
344
                            lc.setTexts(texts);
345
                            // Check if size is a pixel
346
                            if (isOnePoint(viewPort, item.geom)) {
347
                                continue;
348
                            }
349

    
350
                            try {
351
                                drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, item.geom, cancel, dpi,
352
                                    bLabelsReallocatable);
353
                            } catch (GeometryException e) {
354
                                throw new ReadException(layer.getFeatureStore().getProviderName(), e);
355
                            }
356
                        }
357
                    }
358
                }
359

    
360
                if (bLabelsReallocatable) {
361
                    targetGr.translate(x, y);
362
                    if (mapImage != null) {
363
                        mapGraphics.drawImage(overlapDetectImage, null, null);
364
                    } else {
365
                        mapGraphics.drawImage(overlapDetectImage, null, null);
366
                    }
367
                }
368

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

    
379
    }
380

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

    
383
                List<Geometry> resp = new ArrayList<Geometry>();
384
                if (ge != null) {
385
                        if (ge instanceof MultiPrimitive) {
386
                                MultiPrimitive mp = (MultiPrimitive) ge;
387
                                int n = mp.getPrimitivesNumber();
388
                                for (int i = 0; i < n; i++) {
389
                                        resp.add(mp.getPrimitiveAt(i));
390
                                }
391
                        } else {
392
                                resp.add(ge);
393
                        }
394
                }
395
                return resp;
396
        }
397

    
398
        private void drawLabelInGeom(BufferedImage targetBI, Graphics2D targetGr,
399
                        ILabelClass lc, ILabelPlacement placement, ViewPort viewPort,
400
                        Geometry geom, Cancellable cancel, double dpi,
401
                        boolean bLabelsReallocatable) throws GeometryException {
402

    
403
                lc.toCartographicSize(viewPort, dpi, null);
404
                ArrayList<LabelLocationMetrics> llm = null;
405
                llm = placement.guess(lc, geom, getPlacementConstraints(), 0, cancel,
406
                                viewPort);
407

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

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

    
418
        }
419

    
420
        private int getDuplicateLabelsMode() {
421
                if (getPlacementConstraints() == null) {
422
                        return IPlacementConstraints.DefaultDuplicateLabelsMode;
423
                }
424
                return getPlacementConstraints().getDuplicateLabelsMode();
425
        }
426

    
427
        private boolean lookupAndPlaceLabel(BufferedImage bi, Graphics2D g,
428
                        ArrayList<LabelLocationMetrics> llm, ILabelPlacement placement,
429
                        ILabelClass lc, Geometry geom, ViewPort viewPort,
430
                        Cancellable cancel, boolean bLabelsReallocatable)
431
                        throws GeometryException {
432

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

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

    
442
                                GeometryType geom_gt = null;
443

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

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

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

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

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

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

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

    
480
                                                double sizeBefore = lc.getTextSymbol().getFont()
481
                                                                .getSize();
482
                                                double sizeAfter = SymbolUtils.getCartographicLength(
483
                                                                this, sizeBefore, viewPort, viewPort.getDPI());
484
                                                sms.setFontSize(sizeAfter);
485

    
486
                                                smsLc.setTextSymbol(sms);
487
                                                geom.transform(viewPort.getAffineTransform());
488
                                                smsLc.draw(g, null, geom);
489
                                                sms.setFontSize(sizeBefore);
490

    
491
                                        }
492
                                        return true;
493
                                }
494
                        } else {
495
                                if (!pc.isFollowingLine()) {
496
                                        lc.draw(g, labelMetrics, null);
497
                                } else {
498
                                        ILabelClass smsLc = new SmartTextSymbolLabelClass();
499
                                        SmartTextSymbol sms = new SmartTextSymbol(
500
                                                        lc.getTextSymbol(), pc);
501

    
502
                                        double sizeBefore = lc.getTextSymbol().getFont().getSize();
503
                                        double sizeAfter = SymbolUtils.getCartographicLength(this,
504
                                                        sizeBefore, viewPort, viewPort.getDPI());
505
                                        sms.setFontSize(sizeAfter);
506

    
507
                                        smsLc.setTextSymbol(sms);
508
                                        geom.transform(viewPort.getAffineTransform());
509
                                        smsLc.draw(g, null, geom);
510

    
511
                                        sms.setFontSize(sizeBefore);
512
                                }
513
                                return true;
514
                        }
515
                }
516
                return false;
517
        }
518

    
519
        /**
520
         * Divide una cadena de caracteres por el caracter dos puntos siempre que no
521
         * est? entre comillas.
522
         *
523
         * @param str
524
         *            Cadena de caracteres
525
         *
526
         * @return String[]
527
         *
528
         */
529
        private String[] divideExpression(String str) {
530
                ArrayList<String> r = new ArrayList<String>();
531
                boolean inQuotationMarks = false;
532
                int lastIndex = 0;
533
                for (int i = 0; i < str.length(); i++) {
534
                        String currentChar = str.substring(i, i + 1);
535
                        if (currentChar.compareTo("\"") == 0 ) {
536
                                inQuotationMarks = !inQuotationMarks;
537
                                // Si es el cierre de las comillas
538
                                if(!inQuotationMarks){
539
                                        r.add(str.substring(lastIndex, i + 1).replace("\"", "'"));
540
                                        lastIndex = i + 1;
541
                                }
542
                        }
543
                        if (currentChar.compareTo(":") == 0
544
                                        && !inQuotationMarks) {
545
                                if (lastIndex < i) {
546
                                        r.add(str.substring(lastIndex, i));
547
                                }
548
                                lastIndex = i + 1;
549
                        }
550
                }
551
                if (lastIndex < str.length() - 1) {
552
                        r.add(str.substring(lastIndex));
553
                }
554
                String[] result = new String[r.size()];
555
                r.toArray(result);
556
                return result;
557
        }
558

    
559
        /**
560
         * Compute the texts to show in the label and store them in LabelClass.
561
         */
562
        @SuppressWarnings("unchecked")
563
        private boolean setupLabel(Feature featu, ILabelClass lc,
564
                        Cancellable cancel, String[] usedFields, ViewPort viewPort,
565
                        double dpi, int duplicateMode) {
566

    
567
                String expr = lc.getStringLabelExpression();
568

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

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

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

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

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

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

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

    
619
    }
620

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

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

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

    
628
                        Envelope env = geom.getEnvelope();
629
                        double dist1Pixel = viewPort.getDist1pixel();
630
                        onePoint = (env.getLength(0) <= dist1Pixel && env.getLength(1) <= dist1Pixel);
631
                }
632
                return onePoint;
633
        }
634

    
635
        public boolean isAllowingOverlap() {
636
                return allowOverlapping;
637
        }
638

    
639
        public void setAllowOverlapping(boolean allowOverlapping) {
640
                this.allowOverlapping = allowOverlapping;
641
        }
642

    
643
        public IPlacementConstraints getPlacementConstraints() {
644
                if (placementConstraints != null)
645
                        return placementConstraints;
646

    
647
                GeometryType gt = null;
648

    
649
                try {
650
                        gt = layer.getGeometryType();
651
                        // force 2d for comparison
652
                        gt = GeometryLocator.getGeometryManager().getGeometryType(
653
                                        gt.getType(), SUBTYPES.GEOM2D);
654
                } catch (Exception e) {
655
                        logger.error("While getting placements constraints.", e);
656
                        return null;
657
                }
658

    
659
                if (gt.isTypeOf(TYPES.POINT) || gt.isTypeOf(TYPES.MULTIPOINT)) {
660
                        return DefaultPointPlacementConstraints;
661
                } else {
662
                        if (gt.isTypeOf(TYPES.CURVE) || gt.isTypeOf(TYPES.MULTICURVE)) {
663
                                return DefaultLinePlacementConstraints;
664
                        } else {
665
                                if (gt.isTypeOf(TYPES.SURFACE)
666
                                                || gt.isTypeOf(TYPES.MULTISURFACE)) {
667
                                        return DefaultPolygonPlacementConstraints;
668
                                } else {
669
                                        if (gt.isTypeOf(TYPES.AGGREGATE)
670
                                                        || gt.isTypeOf(TYPES.GEOMETRY)) {
671
                                                DefaultMultiShapePlacementConstratints
672
                                                                .setPointConstraints(DefaultPointPlacementConstraints);
673
                                                DefaultMultiShapePlacementConstratints
674
                                                                .setLineConstraints(DefaultLinePlacementConstraints);
675
                                                DefaultMultiShapePlacementConstratints
676
                                                                .setPolygonConstraints(DefaultPolygonPlacementConstraints);
677
                                                return DefaultMultiShapePlacementConstratints;
678
                                        }
679
                                }
680
                        }
681
                }
682
                return null;
683
        }
684

    
685
        public void setPlacementConstraints(IPlacementConstraints constraints) {
686
                this.placementConstraints = constraints;
687
        }
688

    
689
        public IZoomConstraints getZoomConstraints() {
690
                return zoomConstraints;
691
        }
692

    
693
        public void setZoomConstraints(IZoomConstraints constraints) {
694
                this.zoomConstraints = constraints;
695
        }
696

    
697
        public void print(Graphics2D g, double scale, ViewPort viewPort,
698
                        Cancellable cancel, PrintAttributes properties)
699
                        throws ReadException {
700

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

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

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

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

    
719
        public String[] getUsedFields() {
720

    
721
                /*
722
                 * TODO Solve the problem with the [ and ]. Currently SQLJEP evaluator
723
                 * cannot tell which fields are being used. Options: allow [] and remove
724
                 * them or maybe while parsing the SQLJEP evaluator can inform with
725
                 * events like "I have found a field"
726
                 */
727

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

    
736
                int n = atts.length;
737
                String[] resp = new String[n];
738
                for (int i = 0; i < n; i++) {
739
                        resp[i] = atts[i].getName();
740
                }
741
                return resp;
742

    
743
        }
744

    
745
        public boolean shouldDrawLabels(double scale) {
746
                double minScaleView = -1;
747
                double maxScaleView = -1;
748

    
749
                if (zoomConstraints != null) {
750
                        minScaleView = zoomConstraints.getMinScale();
751
                        maxScaleView = zoomConstraints.getMaxScale();
752
                }
753

    
754
                if (minScaleView == -1 && maxScaleView == -1) {
755
                        // parameters not set, so the layer decides.
756
                        return layer.isWithinScale(scale);
757
                }
758

    
759
                if (minScaleView >= scale) {
760
                        return (maxScaleView != -1) ? maxScaleView <= scale : true;
761
                }
762

    
763
                return false;
764
        }
765

    
766
        public void setUnit(int unitIndex) {
767
                unit = unitIndex;
768

    
769
        }
770

    
771
        public int getUnit() {
772
                return unit;
773
        }
774

    
775
        public int getReferenceSystem() {
776
                return referenceSystem;
777
        }
778

    
779
        public void setReferenceSystem(int referenceSystem) {
780
                this.referenceSystem = referenceSystem;
781
        }
782

    
783
        public static void registerPersistent() {
784

    
785
                PersistenceManager manager = ToolsLocator.getPersistenceManager();
786
                if (manager.getDefinition(GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME) == null) {
787
                        DynStruct definition = manager.addDefinition(
788
                                        GeneralLabelingStrategy.class,
789
                                        GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME,
790
                                        GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME
791
                                                        + " Persistence definition", null, null);
792
                        definition.addDynFieldObject("labelingMethod")
793
                                        .setClassOfValue(ILabelingMethod.class).setMandatory(true);
794
                        definition.addDynFieldObject("placementConstraints")
795
                                        .setClassOfValue(IPlacementConstraints.class)
796
                                        .setMandatory(false);
797
                        definition.addDynFieldObject("zoomConstraints")
798
                                        .setClassOfValue(IZoomConstraints.class)
799
                                        .setMandatory(false);
800

    
801
                        definition.addDynFieldBoolean("allowOverlapping")
802
                                        .setMandatory(true);
803
                        definition.addDynFieldInt("unit").setMandatory(true);
804
                        definition.addDynFieldInt("referenceSystem").setMandatory(true);
805
                }
806
        }
807

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

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

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

    
818
                if (state.hasValue("zoomConstraints")) {
819
                        zoomConstraints = (IZoomConstraints) state.get("zoomConstraints");
820
                }
821

    
822
                this.allowOverlapping = state.getBoolean("allowOverlapping");
823
                this.unit = state.getInt("unit");
824
                this.referenceSystem = state.getInt("referenceSystem");
825
        }
826

    
827
        public void saveToState(PersistentState state) throws PersistenceException {
828

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

    
831
                if (placementConstraints != null) {
832
                        state.set("placementConstraints", placementConstraints);
833
                }
834

    
835
                if (zoomConstraints != null) {
836
                        state.set("zoomConstraints", zoomConstraints);
837
                }
838

    
839
                state.set("allowOverlapping", allowOverlapping);
840
                state.set("unit", unit);
841
                state.set("referenceSystem", referenceSystem);
842

    
843
        }
844

    
845
        public double toCartographicSize(ViewPort vp, double dpi, Geometry geom) {
846
                /*
847
                 * This method is not used but we must implement CartographicSupport
848
                 */
849
                return 0;
850
        }
851

    
852
        public void setCartographicSize(double cartographicSize, Geometry geom) {
853
                /*
854
                 * This method is not used but we must implement CartographicSupport
855
                 */
856
        }
857

    
858
        public double getCartographicSize(ViewPort vp, double dpi, Geometry geom) {
859
                /*
860
                 * This method is not used but we must implement CartographicSupport
861
                 */
862
                return 0;
863
        }
864

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

    
869
}