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

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.io.File;
7
import java.io.IOException;
8
import java.util.ArrayList;
9
import java.util.Iterator;
10
import java.util.List;
11
import java.util.TreeMap;
12
import java.util.TreeSet;
13
import java.util.logging.Level;
14
import javax.imageio.ImageIO;
15
import org.cresques.cts.ICoordTrans;
16

    
17
import org.slf4j.Logger;
18
import org.slf4j.LoggerFactory;
19

    
20
import org.gvsig.compat.print.PrintAttributes;
21
import org.gvsig.fmap.dal.exception.DataException;
22
import org.gvsig.fmap.dal.exception.ReadException;
23
import org.gvsig.fmap.dal.feature.Feature;
24
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
25
import org.gvsig.fmap.dal.feature.FeatureSet;
26
import org.gvsig.fmap.geom.Geometry;
27
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
28
import org.gvsig.fmap.geom.Geometry.TYPES;
29
import org.gvsig.fmap.geom.GeometryException;
30
import org.gvsig.fmap.geom.GeometryLocator;
31
import org.gvsig.fmap.geom.GeometryManager;
32
import org.gvsig.fmap.geom.aggregate.MultiPrimitive;
33
import org.gvsig.fmap.geom.operation.GeometryOperationException;
34
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
35
import org.gvsig.fmap.geom.primitive.Envelope;
36
import org.gvsig.fmap.geom.primitive.Point;
37
import org.gvsig.fmap.geom.type.GeometryType;
38
import org.gvsig.fmap.mapcontext.ViewPort;
39
import org.gvsig.fmap.mapcontext.layers.FLayer;
40
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
41
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelClass;
42
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingMethod;
43
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingStrategy;
44
import org.gvsig.fmap.mapcontext.rendering.legend.styling.IPlacementConstraints;
45
import org.gvsig.fmap.mapcontext.rendering.legend.styling.IZoomConstraints;
46
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
47
import org.gvsig.i18n.Messages;
48
import org.gvsig.labeling.lang.LabelClassUtils;
49
import org.gvsig.labeling.placements.ILabelPlacement;
50
import org.gvsig.labeling.placements.LinePlacementConstraints;
51
import org.gvsig.labeling.placements.MultiShapePlacementConstraints;
52
import org.gvsig.labeling.placements.PlacementManager;
53
import org.gvsig.labeling.placements.PointPlacementConstraints;
54
import org.gvsig.labeling.placements.PolygonPlacementConstraints;
55
import org.gvsig.labeling.placements.RemoveDuplicatesComparator;
56
import org.gvsig.labeling.symbol.SmartTextSymbol;
57
import org.gvsig.labeling.symbol.SymbolUtils;
58
import org.gvsig.symbology.SymbologyLocator;
59
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.styling.LabelLocationMetrics;
60
import org.gvsig.tools.ToolsLocator;
61
import org.gvsig.tools.dispose.DisposableIterator;
62
import org.gvsig.tools.dynobject.DynStruct;
63
import org.gvsig.tools.persistence.PersistenceManager;
64
import org.gvsig.tools.persistence.PersistentState;
65
import org.gvsig.tools.persistence.exception.PersistenceException;
66
import org.gvsig.tools.swing.api.SimpleImage;
67
import org.gvsig.tools.swing.api.ToolsSwingLocator;
68
import org.gvsig.tools.task.Cancellable;
69

    
70
public class GeneralLabelingStrategy implements IGeneralLabelingStrategy {
71

    
72
        private static final Logger logger = LoggerFactory
73
                        .getLogger(GeneralLabelingStrategy.class);
74

    
75
        public static final String GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME = "GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME";
76

    
77
        public static PointPlacementConstraints DefaultPointPlacementConstraints = new PointPlacementConstraints();
78
        public static LinePlacementConstraints DefaultLinePlacementConstraints = new LinePlacementConstraints();
79
        public static PolygonPlacementConstraints DefaultPolygonPlacementConstraints = new PolygonPlacementConstraints();
80

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

    
83
        private static MultiShapePlacementConstraints DefaultMultiShapePlacementConstratints = new MultiShapePlacementConstraints();
84

    
85
        private ILabelingMethod method;
86
        private IPlacementConstraints placementConstraints;
87
        private IZoomConstraints zoomConstraints;
88

    
89
        private boolean allowOverlapping;
90

    
91
        protected FLyrVect layer;
92

    
93
        // private long parseTime;
94
        private int unit;
95
        private int referenceSystem;
96
        // private double sizeAfter;
97
        private boolean printMode = false; /*
98
                                                                                 * indicate whether output is for a
99
                                                                                 * print product (PDF, PS, ...)
100
                                                                                 */
101

    
102
        private List<Geometry> drawnGeometryLabels;
103

    
104
        public GeneralLabelingStrategy() {
105
                method = SymbologyLocator.getSymbologyManager()
106
                                .createDefaultLabelingMethod();
107
        }
108

    
109
        public void setLayer(FLayer layer) {
110
                FLyrVect l = (FLyrVect) layer;
111
                this.layer = l;
112
        }
113

    
114
        public ILabelingMethod getLabelingMethod() {
115
                return method;
116
        }
117

    
118
        public void setLabelingMethod(ILabelingMethod method) {
119
                this.method = method;
120
        }
121

    
122
        private class GeometryItem {
123
                public Geometry geom = null;
124
                public int weigh = 0;
125
                public double savedPerimeter;
126

    
127
                public GeometryItem(Geometry geom, int weigh) {
128
                        this.geom = geom;
129
                        this.weigh = weigh;
130
                        this.savedPerimeter = 0;
131
                }
132
        }
133

    
134
    public void draw(BufferedImage mapImage, Graphics2D mapGraphics, double scale, ViewPort viewPort,
135
        Cancellable cancel, double dpi) throws ReadException {
136

    
137
        drawnGeometryLabels = new ArrayList<Geometry>(1000);
138

    
139
        int x = (int) viewPort.getOffset().getX();
140
        int y = (int) viewPort.getOffset().getY();
141

    
142
        // offsets for page generation (PDF, PS, direct printing)
143
        int print_offset_x = x;
144
        int print_offset_y = y;
145
        if (printMode) {
146
            // for printing, we never offset the labels themselves
147
            x = 0;
148
            y = 0;
149
            printMode = false;
150
        }
151

    
152
        TreeMap<String[], GeometryItem> labelsToPlace = null;
153

    
154
        String[] usedFields = getUsedFields();
155

    
156
        int notPlacedCount = 0;
157
        int placedCount = 0;
158

    
159
        /*
160
         * Get the label placement solvers according the user's settings
161
         */
162
        ILabelPlacement placement = PlacementManager.getPlacement(getPlacementConstraints(), layer.getShapeType());
163

    
164
        BufferedImage targetBI;
165
        Graphics2D targetGr;
166

    
167
        /*
168
         * get an ordered set of the LabelClasses up on the label priority
169
         */
170
        ILabelClass[] lcs = method.getLabelClasses();
171
        TreeSet<ILabelClass> ts = new TreeSet<ILabelClass>(new LabelClassComparatorByPriority());
172

    
173
        for (int i = 0; i < lcs.length; i++)
174
            ts.add(lcs[i]);
175

    
176
        if (ts.size() == 0)
177
            return;
178

    
179
        /*
180
         * now we have an ordered set, it is only need to give a pass for each
181
         * label class to render by priorities.
182
         *
183
         * If no priorities were defined, the following loop only executes once
184
         */
185
        for (ILabelClass lc : ts) {
186

    
187
            if (!lc.isVisible(scale)) {
188
                /*
189
                 * Avoid non-visible labels
190
                 */
191
                continue;
192
            }
193

    
194
            FeatureSet fset = null;
195
            DisposableIterator diter = null;
196
            try {
197

    
198
                try {
199
                    fset = method.getFeatureIteratorByLabelClass(layer, lc, viewPort, usedFields);
200
                } catch (DataException e) {
201
                    throw new ReadException(layer.getFeatureStore().getProviderName(), e);
202
                }
203

    
204
                // duplicates treatment stuff
205
                /* handle the duplicates mode */
206
                int duplicateMode = getDuplicateLabelsMode();
207
                if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
208
                    // we need to register the labels already placed
209

    
210
                    labelsToPlace = new TreeMap<String[], GeometryItem>(new RemoveDuplicatesComparator());
211
                }
212

    
213
                boolean bLabelsReallocatable = !isAllowingOverlap();
214

    
215
                BufferedImage overlapDetectImage = null;
216
                Graphics2D overlapDetectGraphics = null;
217
                if (bLabelsReallocatable) {
218
                    int width = viewPort.getImageWidth() + print_offset_x;
219

    
220
                    if (width < 0) {
221
                        width = 1;
222
                    }
223
                    int height = viewPort.getImageHeight() + print_offset_y;
224
                    if (height < 0) {
225
                        height = 1;
226
                    }
227
                    if (mapImage != null)
228
                        overlapDetectImage =
229
                            new BufferedImage(mapImage.getWidth() + print_offset_x, mapImage.getHeight()
230
                                + print_offset_y, BufferedImage.TYPE_INT_ARGB);
231
                    else
232
                        overlapDetectImage =
233
                            new BufferedImage(viewPort.getImageWidth() + print_offset_x, viewPort.getImageHeight()
234
                                + print_offset_y, BufferedImage.TYPE_INT_ARGB);
235

    
236
                    overlapDetectGraphics = overlapDetectImage.createGraphics();
237
                    overlapDetectGraphics.setRenderingHints(mapGraphics.getRenderingHints());
238
                }
239
                if (bLabelsReallocatable) {
240
                    targetBI = overlapDetectImage;
241
                    targetGr = overlapDetectGraphics;
242
                    targetGr.translate(-x, -y);
243
                } else {
244
                    targetBI = mapImage;
245
                    targetGr = mapGraphics;
246
                }
247

    
248
                try {
249
                    diter = fset.fastIterator();
250
                } catch (DataException e) {
251
                    throw new ReadException(layer.getFeatureStore().getProviderName(), e);
252
                }
253
                Feature featu = null;
254
                Geometry geome = null;
255

    
256
                while (!cancel.isCanceled() && diter.hasNext()) {
257

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

    
271
                    String[] texts = lc.getTexts();
272

    
273
                    if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
274
                        // check if this text (so label) is already present in
275
                        // the map
276

    
277
                        GeometryItem item = labelsToPlace.get(texts);
278
                        if (item == null) {
279
                            item = new GeometryItem(geome, 0);
280
                            labelsToPlace.put(texts, item);
281
                        }
282
                        if (item.geom != null) {
283

    
284
                            notPlacedCount++;
285
                            if (geome.getType() != Geometry.TYPES.POINT) {
286

    
287
                                Envelope auxBox = geome.getEnvelope();
288
                                double perimeterAux = 2 * (auxBox.getLength(0) + auxBox.getLength(1));
289
                                if (perimeterAux > item.savedPerimeter) {
290
                                    item.geom = geome; // FConverter.jts_to_igeometry(jtsGeom);
291
                                    item.savedPerimeter = perimeterAux;
292
                                }
293
                            } else {
294
                                int weigh = item.weigh;
295

    
296
                                try {
297
                                    Point pointFromLabel = item.geom.centroid();
298
                                    Point pointGeome = geome.centroid();
299
                                    item.geom =
300
                                        GeometryLocator.getGeometryManager().createPoint(
301
                                            (pointFromLabel.getX() * weigh + pointGeome.getX()) / (weigh + 1),
302
                                            (pointFromLabel.getY() * weigh + pointGeome.getY()) / (weigh + 1),
303
                                            Geometry.SUBTYPES.GEOM2D);
304
                                } catch (Exception ex) {
305
                                    throw new ReadException(layer.getFeatureStore().getProviderName(), ex);
306
                                }
307

    
308
                            }
309
                        } else {
310
                            item.geom = geome;
311
                        }
312
                        item.weigh++;
313
                    } else {
314
                        // Check if size is a pixel
315
                        if (isOnePoint(viewPort, geome)) {
316
                            continue;
317
                        }
318

    
319
                        List<Geometry> geome_parts = new ArrayList<Geometry>();
320
                        if (duplicateMode == IPlacementConstraints.ONE_LABEL_PER_FEATURE_PART) {
321
                            geome_parts = getGeometryParts(geome);
322
                        } else {
323
                            geome_parts.add(geome);
324
                        }
325

    
326
                        try {
327
                            int n = geome_parts.size();
328
                            for (int k = 0; k < n; k++) {
329
                                drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, geome_parts.get(k),
330
                                    cancel, dpi, bLabelsReallocatable);
331
                            }
332
                        } catch (GeometryException e) {
333
                            throw new ReadException(layer.getFeatureStore().getProviderName(), e);
334
                        }
335

    
336
                        placedCount++;
337
                    }
338
                }
339

    
340
                // ======= End iteration in feature set ====================
341

    
342
                if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
343
                    Iterator<String[]> textsIt = labelsToPlace.keySet().iterator();
344
                    while (!cancel.isCanceled() && textsIt.hasNext()) {
345
                        notPlacedCount++;
346
                        String[] texts = textsIt.next();
347

    
348
                        GeometryItem item = labelsToPlace.get(texts);
349
                        if (item != null) {
350
                            lc.setTexts(texts);
351
                            // Check if size is a pixel
352
                            if (isOnePoint(viewPort, item.geom)) {
353
                                continue;
354
                            }
355

    
356
                            try {
357
                                drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, item.geom, cancel, dpi,
358
                                    bLabelsReallocatable);
359
                            } catch (GeometryException e) {
360
                                throw new ReadException(layer.getFeatureStore().getProviderName(), e);
361
                            }
362
                        }
363
                    }
364
                }
365

    
366
                if (bLabelsReallocatable) {
367
                    targetGr.translate(x, y);
368
                    mapGraphics.drawImage(targetBI, null, null);
369
                }
370

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

    
381
    }
382

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

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

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

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

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

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

    
420
        }
421

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

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

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

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

    
444
                                GeometryType geom_gt = null;
445

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
569
                String expr = lc.getStringLabelExpression();
570

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

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

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

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

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

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

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

    
621
    }
622

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

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

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

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

    
637
        public boolean isAllowingOverlap() {
638
                return allowOverlapping;
639
        }
640

    
641
        public void setAllowOverlapping(boolean allowOverlapping) {
642
                this.allowOverlapping = allowOverlapping;
643
        }
644

    
645
        public IPlacementConstraints getPlacementConstraints() {
646
                if (placementConstraints != null)
647
                        return placementConstraints;
648

    
649
                GeometryType gt = null;
650

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

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

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

    
691
        public IZoomConstraints getZoomConstraints() {
692
                return zoomConstraints;
693
        }
694

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

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

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

    
713
                //refs: #5270
714
//                viewPort.setOffset(new Point2D.Double(0, 0));
715

    
716
                /* signal printing output */
717
                printMode = true;
718

    
719
                draw(null, g, scale, viewPort, cancel, dpi);
720
        }
721

    
722
        public String[] getUsedFields() {
723

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

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

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

    
746
        }
747

    
748
        public boolean shouldDrawLabels(double scale) {
749
                double minScaleView = -1;
750
                double maxScaleView = -1;
751

    
752
                if (zoomConstraints != null) {
753
                        minScaleView = zoomConstraints.getMinScale();
754
                        maxScaleView = zoomConstraints.getMaxScale();
755
                }
756

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

    
762
                if (minScaleView >= scale) {
763
                        return (maxScaleView != -1) ? maxScaleView <= scale : true;
764
                }
765

    
766
                return false;
767
        }
768

    
769
        public void setUnit(int unitIndex) {
770
                unit = unitIndex;
771

    
772
        }
773

    
774
        public int getUnit() {
775
                return unit;
776
        }
777

    
778
        public int getReferenceSystem() {
779
                return referenceSystem;
780
        }
781

    
782
        public void setReferenceSystem(int referenceSystem) {
783
                this.referenceSystem = referenceSystem;
784
        }
785

    
786
        public static void registerPersistent() {
787

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

    
804
                        definition.addDynFieldBoolean("allowOverlapping")
805
                                        .setMandatory(true);
806
                        definition.addDynFieldInt("unit").setMandatory(true);
807
                        definition.addDynFieldInt("referenceSystem").setMandatory(true);
808
                }
809
        }
810

    
811
        public void loadFromState(PersistentState state)
812
                        throws PersistenceException {
813

    
814
                method = (ILabelingMethod) state.get("labelingMethod");
815

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

    
821
                if (state.hasValue("zoomConstraints")) {
822
                        zoomConstraints = (IZoomConstraints) state.get("zoomConstraints");
823
                }
824

    
825
                this.allowOverlapping = state.getBoolean("allowOverlapping");
826
                this.unit = state.getInt("unit");
827
                this.referenceSystem = state.getInt("referenceSystem");
828
        }
829

    
830
        public void saveToState(PersistentState state) throws PersistenceException {
831

    
832
                state.set("labelingMethod", method);
833

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

    
838
                if (zoomConstraints != null) {
839
                        state.set("zoomConstraints", zoomConstraints);
840
                }
841

    
842
                state.set("allowOverlapping", allowOverlapping);
843
                state.set("unit", unit);
844
                state.set("referenceSystem", referenceSystem);
845

    
846
        }
847

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

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

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

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

    
872
}