Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extSymbology / src / org / gvsig / symbology / fmap / labeling / GeneralLabelingStrategy.java @ 25453

History | View | Annotate | Download (24.1 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41

    
42
/* CVS MESSAGES:
43
 *
44
 * $Id: GeneralLabelingStrategy.java 13749 2007-09-17 14:16:11Z jaume $
45
 * $Log$
46
 * Revision 1.2  2007-09-17 14:16:11  jaume
47
 * multilayer symbols sizing bug fixed
48
 *
49
 * Revision 1.1  2007/05/22 12:17:41  jaume
50
 * *** empty log message ***
51
 *
52
 * Revision 1.1  2007/05/22 10:05:31  jaume
53
 * *** empty log message ***
54
 *
55
 * Revision 1.10  2007/05/17 09:32:06  jaume
56
 * *** empty log message ***
57
 *
58
 * Revision 1.9  2007/05/09 11:04:58  jaume
59
 * refactored legend hierarchy
60
 *
61
 * Revision 1.8  2007/04/13 11:59:30  jaume
62
 * *** empty log message ***
63
 *
64
 * Revision 1.7  2007/04/12 14:28:43  jaume
65
 * basic labeling support for lines
66
 *
67
 * Revision 1.6  2007/04/11 16:01:08  jaume
68
 * maybe a label placer refactor
69
 *
70
 * Revision 1.5  2007/04/10 16:34:01  jaume
71
 * towards a styled labeling
72
 *
73
 * Revision 1.4  2007/04/02 16:34:56  jaume
74
 * Styled labeling (start commiting)
75
 *
76
 * Revision 1.3  2007/03/28 16:48:01  jaume
77
 * *** empty log message ***
78
 *
79
 * Revision 1.2  2007/03/26 14:40:38  jaume
80
 * added print method (BUT UNIMPLEMENTED)
81
 *
82
 * Revision 1.1  2007/03/20 16:16:20  jaume
83
 * refactored to use ISymbol instead of FSymbol
84
 *
85
 * Revision 1.2  2007/03/09 11:20:57  jaume
86
 * Advanced symbology (start committing)
87
 *
88
 * Revision 1.1  2007/03/09 08:33:43  jaume
89
 * *** empty log message ***
90
 *
91
 * Revision 1.1.2.5  2007/02/21 07:34:08  jaume
92
 * labeling starts working
93
 *
94
 * Revision 1.1.2.4  2007/02/15 16:23:44  jaume
95
 * *** empty log message ***
96
 *
97
 * Revision 1.1.2.3  2007/02/09 07:47:05  jaume
98
 * Isymbol moved
99
 *
100
 * Revision 1.1.2.2  2007/02/02 16:21:24  jaume
101
 * start commiting labeling stuff
102
 *
103
 * Revision 1.1.2.1  2007/02/01 17:46:49  jaume
104
 * *** empty log message ***
105
 *
106
 *
107
 */
108
package org.gvsig.symbology.fmap.labeling;
109

    
110
import java.awt.Graphics2D;
111
import java.awt.geom.NoninvertibleTransformException;
112
import java.awt.geom.PathIterator;
113
import java.awt.geom.Point2D;
114
import java.awt.geom.Rectangle2D;
115
import java.awt.image.BufferedImage;
116
import java.io.CharArrayReader;
117
import java.io.StringReader;
118
import java.text.NumberFormat;
119
import java.util.ArrayList;
120
import java.util.Hashtable;
121
import java.util.TreeSet;
122

    
123
import javax.print.attribute.PrintRequestAttributeSet;
124

    
125
import org.apache.log4j.Logger;
126
import org.cresques.cts.ICoordTrans;
127
import org.gvsig.symbology.fmap.labeling.parse.LabelExpressionParser;
128
import org.gvsig.symbology.fmap.labeling.parse.ParseException;
129
import org.gvsig.symbology.fmap.labeling.placements.AbstractPlacementConstraints;
130
import org.gvsig.symbology.fmap.labeling.placements.ILabelPlacement;
131
import org.gvsig.symbology.fmap.labeling.placements.LinePlacementConstraints;
132
import org.gvsig.symbology.fmap.labeling.placements.MultiShapePlacementConstraints;
133
import org.gvsig.symbology.fmap.labeling.placements.PointPlacementConstraints;
134
import org.gvsig.symbology.fmap.labeling.placements.PolygonPlacementConstraints;
135
import org.gvsig.symbology.fmap.labeling.placements.PolygonPlacementOnCentroid;
136
import org.gvsig.symbology.fmap.labeling.placements.PolygonPlacementParallel;
137
import org.gvsig.symbology.fmap.labeling.placements.RemoveDuplicatesComparator;
138
import org.gvsig.symbology.fmap.rendering.filter.operations.Expression;
139
import org.gvsig.symbology.fmap.rendering.filter.operations.ExpressionException;
140
import org.gvsig.symbology.fmap.symbols.SmartTextSymbol;
141

    
142
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
143
import com.hardcode.gdbms.engine.values.Value;
144
import com.iver.andami.PluginServices;
145
import com.iver.cit.gvsig.fmap.MapContext;
146
import com.iver.cit.gvsig.fmap.ViewPort;
147
import com.iver.cit.gvsig.fmap.core.CartographicSupport;
148
import com.iver.cit.gvsig.fmap.core.CartographicSupportToolkit;
149
import com.iver.cit.gvsig.fmap.core.FShape;
150
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
151
import com.iver.cit.gvsig.fmap.core.IFeature;
152
import com.iver.cit.gvsig.fmap.core.IGeometry;
153
import com.iver.cit.gvsig.fmap.core.SymbologyFactory;
154
import com.iver.cit.gvsig.fmap.core.symbols.ITextSymbol;
155
import com.iver.cit.gvsig.fmap.core.v02.FConstant;
156
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
157
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
158
import com.iver.cit.gvsig.fmap.layers.FLayer;
159
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
160
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.ILabelingMethod;
161
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.ILabelingStrategy;
162
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.IPlacementConstraints;
163
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.IZoomConstraints;
164
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.LabelClass;
165
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.LabelLocationMetrics;
166
import com.iver.cit.gvsig.fmap.rendering.styling.labeling.LabelingFactory;
167
import com.iver.utiles.XMLEntity;
168
import com.iver.utiles.swing.threads.Cancellable;
169

    
170
/**
171
 *
172
 * GeneralLabelingStrategy.java
173
 *
174
 *
175
 * @author jaume dominguez faus - jaume.dominguez@iver.es Jan 4, 2008
176
 *
177
 */
178
public class GeneralLabelingStrategy implements ILabelingStrategy, Cloneable,CartographicSupport {
179
        public static IPlacementConstraints DefaultPointPlacementConstraints = new PointPlacementConstraints();
180
        public static IPlacementConstraints DefaultLinePlacementConstraints = new LinePlacementConstraints();
181
        public static IPlacementConstraints DefaultPolygonPlacementConstraints = new PolygonPlacementConstraints();
182
        private static String[] NO_TEXT = {PluginServices.getText(null, "text_field")};
183
        private static MultiShapePlacementConstraints DefaultMultiShapePlacementConstratints = new MultiShapePlacementConstraints();
184
        private ILabelingMethod method;
185
        private IPlacementConstraints placementConstraints;
186
        protected FLyrVect layer;
187
        private IZoomConstraints zoomConstraints;
188
        private boolean allowOverlapping;
189
        private long parseTime;
190
        private int unit;
191
        private int referenceSystem;
192
        private double sizeAfter;
193

    
194
        public void setLayer(FLayer layer) throws ReadDriverException {
195
                FLyrVect l = (FLyrVect) layer;
196
                this.layer = l;
197
        }
198

    
199
        public ILabelingMethod getLabelingMethod() {
200
                return method;
201
        }
202

    
203
        public void setLabelingMethod(ILabelingMethod method) {
204
                this.method = method;
205
        }
206

    
207
        public void draw(BufferedImage mapImage, Graphics2D mapGraphics,
208
                        ViewPort viewPort,        Cancellable cancel, double dpi) throws ReadDriverException {
209

    
210
//                boolean bVisualFXEnabled = false; // if true, the user can see how the labeling is drawing up
211
                TreeSet<?> placedLabels = null;
212
                parseTime =0;
213
                long t1 = System.currentTimeMillis();
214
                String[] usedFields = getUsedFields();
215

    
216
                int notPlacedCount = 0;
217
                int placedCount = 0;
218

    
219
                /*
220
                 * Get the label placement solvers according the user's settings
221
                 */
222
                ILabelPlacement placement = PlacementManager.getPlacement(getPlacementConstraints(), layer.getShapeType());
223

    
224
                /*
225
                 * get an ordered set of the LabelClasses up on the
226
                 * label priority
227
                 */
228
                LabelClass[] lcs = method.getLabelClasses();
229
                TreeSet<LabelClass> ts = new TreeSet<LabelClass>(new LabelClassComparatorByPriority());
230

    
231
                for (int i = 0; i < lcs.length; i++) ts.add(lcs[i]);
232

    
233
                if (ts.size()==0) return;
234

    
235
//                // -- visual FX stuff
236
//                BufferedImage visualFXim = null;
237
//                Graphics2D visualFXgr = null;
238
//                if (bVisualFXEnabled) {
239
//                visualFXim = new BufferedImage(mapImage.getWidth(),
240
//                mapImage.getHeight(),
241
//                BufferedImage.TYPE_INT_ARGB);
242
//                visualFXgr = visualFXim.createGraphics();
243
//                visualFXgr.drawImage(mapImage, null, null);
244
//                }
245
//                int drawEach = 300; // (milliseconds)
246
//                long lastTime = System.currentTimeMillis();
247
//                // -- end visual FX stuff
248

    
249
                /*
250
                 * now we have an ordered set, it is only need to give a pass
251
                 * for each label class to render by priorities.
252
                 *
253
                 * If no priorities were defined, the following loop only executes
254
                 * once
255
                 */
256
                for (LabelClass lc : ts) {
257
                        IFeatureIterator it =  method.getFeatureIteratorByLabelClass(layer, lc, viewPort, usedFields);
258

    
259
                        // duplicates treatment stuff
260
                        /* handle the duplicates mode */
261
                        int duplicateMode = getDuplicateLabelsMode();
262
                        if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
263
                                // we need to register the labels already placed
264
                                if (placedLabels == null)
265
                                        placedLabels = new TreeSet<String[]>(
266
                                                        new RemoveDuplicatesComparator());
267
                                        else placedLabels.clear();
268
                        }
269

    
270

    
271
                        boolean bLabelsReallocatable = !isAllowingOverlap();
272

    
273
                        BufferedImage overlapDetectImage = null;
274
                        Graphics2D overlapDetectGraphics = null;
275
                        if (bLabelsReallocatable) {
276
                                overlapDetectImage = new BufferedImage(
277
                                                viewPort.getImageWidth()+(int)viewPort.getOffset().getX(),
278
                                                viewPort.getImageHeight()+(int)viewPort.getOffset().getY(),
279
                                                BufferedImage.TYPE_INT_ARGB
280
                                );
281
                                overlapDetectGraphics = overlapDetectImage.createGraphics();
282
                                overlapDetectGraphics.setRenderingHints(mapGraphics.getRenderingHints());
283
                        }
284

    
285
                        while ( !cancel.isCanceled() && it.hasNext()) {
286
                                IFeature feat = it.next();
287
                                IGeometry geom = feat.getGeometry();
288

    
289
                                if (!setupLabel(feat, lc, cancel, usedFields, viewPort, dpi, duplicateMode, placedLabels))
290
                                        continue;
291

    
292
                                // Check if size is a pixel
293
                                if (isOnePoint(viewPort, geom)) {
294
                                        continue;
295
                                }
296

    
297
                                ArrayList<LabelLocationMetrics> llm = null;
298
                                // Calculate the label possible places
299
//                                if (placement instanceof PolygonPlacementOnCentroid){
300
//                                llm = ((PolygonPlacementOnCentroid)placement).guess(
301
//                                lc,
302
//                                (FShape)geom.getInternalShape(),
303
//                                getPlacementConstraints(),
304
//                                0,
305
//                                cancel,viewPort);
306
//                                }else if(placement instanceof PolygonPlacementParallel){
307
//                                llm = ((PolygonPlacementParallel)placement).guess(
308
//                                lc,
309
//                                (FShape)geom.getInternalShape(),
310
//                                getPlacementConstraints(),
311
//                                0,
312
//                                cancel,viewPort);
313
//                                }else{
314
//                                llm = placement.guess(
315
//                                lc,
316
//                                FConverter.transformToInts(geom, viewPort.getAffineTransform()),
317
//                                getPlacementConstraints(),
318
//                                0,
319
//                                cancel);
320
//                                }
321

    
322

    
323

    
324

    
325

    
326
                                llm = placement.guess(
327
                                                lc,
328
                                                geom,
329
                                                getPlacementConstraints(),
330
                                                0,
331
                                                cancel,viewPort);
332

    
333
                                BufferedImage targetBI;
334
                                Graphics2D targetGr;
335
                                if (bLabelsReallocatable) {
336
                                        targetBI = overlapDetectImage;
337
                                        targetGr = overlapDetectGraphics;
338
                                } else {
339
//                                        // -- visual FX stuff
340
//                                        if (bVisualFXEnabled) {
341
//                                        targetBI = visualFXim;
342
//                                        targetGr = visualFXgr;
343
//                                        } else {
344
//                                        // -- end visual FX stuff
345
                                        targetBI = mapImage;
346
                                        targetGr = mapGraphics;
347
//                                        }
348
                                }
349

    
350

    
351

    
352
                                setReferenceSystem(lc.getReferenceSystem());
353
                                setUnit(lc.getUnit());
354

    
355
                                double sizeBefore = lc.getTextSymbol().getFont().getSize();
356

    
357

    
358
                                sizeAfter = CartographicSupportToolkit.getCartographicLength(this,
359
                                                sizeBefore,
360
                                                viewPort,
361
                                                MapContext.getScreenDPI());
362

    
363

    
364

    
365

    
366
                                /*
367
                                 * search if there is room left by the previous and
368
                                 * with more priority labels, then check the current
369
                                 * level
370
                                 */
371
                                if (lookupAndPlaceLabel(targetBI, targetGr, llm,
372
                                                placement, lc, geom, viewPort, cancel,        bLabelsReallocatable)) {
373
                                        placedCount++;
374
                                } else {
375
                                        notPlacedCount++;
376
                                }
377

    
378
                                lc.getTextSymbol().setFontSize(sizeBefore);
379

    
380
//                                // -- visual FX stuff
381
//                                if (bVisualFXEnabled && System.currentTimeMillis() - lastTime > drawEach) {
382
//                                lastTime = System.currentTimeMillis();
383
//                                mapGraphics.drawImage(visualFXim, null, null);
384
//                                }
385
//                                // -- end visual FX stuff
386
                        }
387

    
388
                        if (bLabelsReallocatable) {
389
//                                // -- visual FX stuff
390
//                                if (bVisualFXEnabled)
391
//                                visualFXgr.drawImage(overlapDetectImage, null, null);
392
//                                else
393
//                                // -- end visual FX stuff
394
                                mapGraphics.drawImage(overlapDetectImage, null, null);
395
                        }
396
                }
397

    
398
                int total = placedCount+notPlacedCount;
399

    
400
                double totalTime = (System.currentTimeMillis()-t1);
401

    
402
                if (total>0)
403
                        Logger.getLogger(getClass()).info("Labeled layer '"+layer.getName()+
404
                                        "' "+totalTime/1000D+" seconds. "+placedCount+"/"+total+
405
                                        " labels placed ("+NumberFormat.getInstance().
406
                                        format(100*placedCount/(double) total)+"%)");
407

    
408
                if (cancel.isCanceled()) {
409
                        Logger.getLogger(getClass()).info("Layer labeling canceled: '"+
410
                                        layer.getName()+"'");
411
                } else {
412
                        Logger.getLogger(getClass()).info("Total labels parse time = "+
413
                                        parseTime+" ("+NumberFormat.getInstance().
414
                                        format(parseTime*100/totalTime)+"%)");
415
                }
416

    
417
//                // -- visual FX stuff
418
//                if (bVisualFXEnabled) {
419
//                mapGraphics.drawImage(visualFXim, null, null);
420
//                }
421
//                // -- end visual FX stuff
422
        }
423

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

    
431
        private boolean lookupAndPlaceLabel(BufferedImage bi, Graphics2D g,
432
                        ArrayList<LabelLocationMetrics> llm, ILabelPlacement placement,
433
                        LabelClass lc, IGeometry geom,        ViewPort viewPort,
434
                        Cancellable cancel, boolean bLabelsReallocatable) {
435
                int i;
436

    
437
                for (i = 0; !cancel.isCanceled() && i < llm.size(); i++) {
438
                        LabelLocationMetrics labelMetrics = llm.get(i);
439

    
440
                        if (bLabelsReallocatable) {
441
                                if (!isOverlapping(bi, lc.getShape(labelMetrics))) {
442
                                        lc.getTextSymbol().setFontSize(sizeAfter * FConstant.FONT_HEIGHT_SCALE_FACTOR);
443
                                        if(!getPlacementConstraints().isFollowingLine()){
444
                                                lc.draw(g, labelMetrics, (FShape) geom.getInternalShape());
445
                                        }
446
                                        else{
447
                                                SmartTextSymbolLabelClass smsLc = new SmartTextSymbolLabelClass();
448
                                                SmartTextSymbol sms = new SmartTextSymbol(lc.getTextSymbol(),getPlacementConstraints());
449
                                                smsLc.setTextSymbol(sms);
450
                                                geom.transform(viewPort.getAffineTransform());
451
                                                smsLc.draw(g, null, (FShape) geom.getInternalShape());
452

    
453
                                        }
454
                                        return true;
455
                                }
456
                        } else {
457
                                lc.getTextSymbol().setFontSize(sizeAfter * FConstant.FONT_HEIGHT_SCALE_FACTOR);
458
                                if(!getPlacementConstraints().isFollowingLine()){
459
                                        lc.draw(g, labelMetrics, null);
460
                                }
461
                                else{
462
                                        SmartTextSymbolLabelClass smsLc = new SmartTextSymbolLabelClass();
463
                                        SmartTextSymbol sms = new SmartTextSymbol(lc.getTextSymbol(),getPlacementConstraints());
464
                                        smsLc.setTextSymbol(sms);
465
                                        geom.transform(viewPort.getAffineTransform());
466
                                        smsLc.draw(g, null, (FShape) geom.getInternalShape());
467
                                }
468
                                return true;
469
                        }
470
                }
471
                return false;
472
        }
473

    
474
        @SuppressWarnings("unchecked")
475
        private boolean setupLabel(IFeature feat, LabelClass lc,
476
                        Cancellable cancel, String[] usedFields, ViewPort viewPort,
477
                        double dpi, int duplicateMode, TreeSet<?> placedLabels) {
478

    
479
                Value[] vv = feat.getAttributes();
480
                String expr = lc.getStringLabelExpression();
481

    
482
                long pt1 = System.currentTimeMillis();
483
                String[] texts = NO_TEXT;
484
//                String[] texts = {PluginServices.getText(this, "text_field")};
485
                try {
486

    
487
                        for (int i = 0; !cancel.isCanceled() && i < usedFields.length; i++) {
488
                                try {
489
                                        int index = layer.getSource().getRecordset().getFieldIndexByName(usedFields[i]);
490
                                        if(index != -1)
491
                                                symbol_table.put(usedFields[i], feat.getAttribute(index));
492
                                } catch (ReadDriverException e) {
493
                                        // TODO Auto-generated catch block
494
                                        e.printStackTrace();
495
                                }
496
                        }
497

    
498
                        if (expr != null) {
499

    
500
                                if(expr.equals("") || expr.equals(LabelExpressionParser.tokenFor(LabelExpressionParser.EOEXPR)))
501
                                        expr = texts[0];
502

    
503
                                // parse (if it hasn't been parsed yet) and evaluate the expression
504
                                Object labelContents = getEvaluator(expr).evaluate();
505
                                if (String[].class.equals(labelContents.getClass())) {
506
                                        texts = (String[]) labelContents;
507
                                } else {
508
                                        texts = new String[] { labelContents.toString() };
509
                                }
510
                                parseTime += System.currentTimeMillis()-pt1;
511
                        }
512
                        if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
513
                                // check if this text (so label) is already present in the map
514
                                if (placedLabels.contains(texts))
515
                                        // the label has already placed before
516
                                        return false;
517

    
518
                                /*
519
                                 *  the text is not present, it will be registered for next to
520
                                 *  be avoided
521
                                 */
522
                                ((TreeSet<String[]>) placedLabels).add(texts);
523
                        }
524
                        lc.setTexts(texts);
525

    
526
                } catch (ExpressionException e) {
527
                        e.printStackTrace();
528
                        return false;
529
                }
530

    
531
                lc.toCartographicSize(viewPort, dpi, null);
532
                return true;
533
        }
534
        private Hashtable<String, Value> symbol_table = new Hashtable<String, Value>();
535
        private Hashtable<String, Expression> evaluators = new Hashtable<String, Expression>();
536

    
537
        private Expression getEvaluator(String strExpr) {
538
                Expression expr = evaluators.get(strExpr);
539
                if (expr == null) {
540
                        LabelExpressionParser p = new LabelExpressionParser(
541
                                        new StringReader(strExpr),symbol_table);
542

    
543
                        try {
544
                                p.LabelExpression();
545
                        } catch (ParseException e) {
546
                                e.printStackTrace();
547
                        }
548
                        expr = (Expression) p.getStack().pop();
549
                        evaluators.put(strExpr, expr);
550
                }
551
                return expr;
552
        }
553

    
554
        private boolean isOverlapping(BufferedImage bi, FShape labelShape) {
555

    
556
                Rectangle2D rPixels = labelShape.getBounds2D();
557
                for (int i= (int) rPixels.getX(); i<rPixels.getMaxX(); i++){
558
                        for (int j= (int) rPixels.getY(); j<rPixels.getMaxY(); j++){
559
                                if (!labelShape.contains(i, j)) {
560
                                        continue;
561
                                }
562

    
563
                                if (i<0 || j<0) {
564
                                        continue;
565
                                }
566

    
567
                                if (bi.getWidth()<i+1 || bi.getHeight()<j+1) {
568
                                        continue;
569
                                }
570

    
571
                                if (bi.getRGB(i,j)!=0){
572
                                        return true;
573
                                }
574
                        }
575
                }
576
                return false;
577
        }
578

    
579
        private boolean isOnePoint(ViewPort viewPort, IGeometry geom) {
580
                boolean onePoint = false;
581
                int shapeType = geom.getGeometryType();
582
                if (shapeType!=FShape.POINT && shapeType!=FShape.MULTIPOINT) {
583

    
584
                        Rectangle2D geomBounds = geom.getBounds2D();
585
                        ICoordTrans ct = layer.getCoordTrans();
586

    
587
                        if (ct!=null) {
588
                                geomBounds = ct.convert(geomBounds);
589
                        }
590

    
591
                        double dist1Pixel = viewPort.getDist1pixel();
592
                        onePoint = (geomBounds.getWidth() <= dist1Pixel
593
                                        && geomBounds.getHeight() <= dist1Pixel);
594
                }
595
                return onePoint;
596
        }
597

    
598
        public String getClassName() {
599
                return getClass().getName();
600
        }
601

    
602
        public XMLEntity getXMLEntity() {
603
                XMLEntity xml = new XMLEntity();
604
                xml.putProperty("labelingStrategy", "labelingStrategy");
605
                xml.putProperty("className", getClassName());
606
                xml.putProperty("allowsOverlapping", allowOverlapping);
607
//                xml.putProperty("minScaleView", minScaleView);
608
//                xml.putProperty("maxScaleView", maxScaleView);
609

    
610
                if (method!=null) {
611
                        XMLEntity methodEntity = method.getXMLEntity();
612
                        methodEntity.putProperty("id", "LabelingMethod");
613
                        xml.addChild(methodEntity);
614
                }
615

    
616
                if (placementConstraints != null) {
617
                        XMLEntity pcEntity = placementConstraints.getXMLEntity();
618
                        pcEntity.putProperty("id", "PlacementConstraints");
619
                        xml.addChild(pcEntity);
620
                }
621

    
622
                if (zoomConstraints != null) {
623
                        XMLEntity zcEntity = zoomConstraints.getXMLEntity();
624
                        zcEntity.putProperty("id", "ZoomConstraints");
625
                        xml.addChild(zcEntity);
626
                }
627
                return xml;
628
        }
629

    
630
        public void setXMLEntity(XMLEntity xml) {
631
                XMLEntity aux = xml.firstChild("id", "LabelingMethod");
632

    
633
                // overlapping mode
634
                if (xml.contains("allowsOverlapping")) {
635
                        allowOverlapping = xml.getBooleanProperty("allowsOverlapping");
636
                }
637

    
638

    
639
                if (aux != null) {
640
                        method = LabelingFactory.createMethodFromXML(aux);
641
                }
642

    
643
                aux = xml.firstChild("id", "PlacementConstraints");
644
                if (aux != null) {
645
                        placementConstraints = LabelingFactory.createPlacementConstraintsFromXML(aux);
646
                }
647

    
648
                aux = xml.firstChild("id", "ZoomConstraints");
649
                if (aux != null) {
650
                        zoomConstraints = LabelingFactory.createZoomConstraintsFromXML(aux);
651
                }
652
        }
653

    
654
        public boolean isAllowingOverlap() {
655
                return allowOverlapping;
656
        }
657

    
658
        public void setAllowOverlapping(boolean allowOverlapping) {
659
                this.allowOverlapping = allowOverlapping;
660
        }
661

    
662
        public IPlacementConstraints getPlacementConstraints() {
663
                if (placementConstraints != null)
664
                        return placementConstraints;
665

    
666
                try {
667
                        switch (layer.getShapeType()) {
668
                        case FShape.POINT:
669
                        case FShape.MULTIPOINT:
670
                                return DefaultPointPlacementConstraints;
671
                        case FShape.LINE:
672
                                return DefaultLinePlacementConstraints;
673
                        case FShape.POLYGON:
674
                                return DefaultPolygonPlacementConstraints;
675
                        case FShape.MULTI:
676
                                DefaultMultiShapePlacementConstratints.setPointConstraints(DefaultPointPlacementConstraints);
677
                                DefaultMultiShapePlacementConstratints.setLineConstraints(DefaultLinePlacementConstraints);
678
                                DefaultMultiShapePlacementConstratints.setPolygonConstraints(DefaultPolygonPlacementConstraints);
679
                                return DefaultMultiShapePlacementConstratints;
680
                        }
681

    
682
                } catch (ReadDriverException e) {
683

    
684
                }
685
                return null;
686
        }
687

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

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

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

    
700
        public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, PrintRequestAttributeSet properties) throws ReadDriverException {
701
                double dpi=100;
702
                draw(null,g,viewPort,cancel,dpi);
703
        }
704

    
705
        public String[] getUsedFields() {
706
                LabelClass[] lcs = method.getLabelClasses();
707
                ArrayList<String> fieldNames = new ArrayList<String>();
708
                for (int i = 0; i < lcs.length; i++) {
709
                        if(lcs[i].getLabelExpressions() != null){
710
                                for (int j = 0; j < lcs[i].getLabelExpressions().length; j++) {
711
                                        String expr = lcs[i].getLabelExpressions()[j];
712
                                        int start;
713
                                        while (expr != null &&
714
                                                        (start = expr.indexOf("[")) != -1) {
715
                                                int end = expr.indexOf("]");
716
                                                String field = expr.substring(start+1, end).trim();
717
                                                if (!fieldNames.contains(field))
718
                                                        fieldNames.add(field);
719
                                                expr = expr.substring(end+1, expr.length());
720
                                        }
721
                                }
722
                        }
723
                }
724
                return fieldNames.toArray(new String[fieldNames.size()]);
725
        }
726

    
727

    
728
        public boolean shouldDrawLabels(double scale) {
729
                double minScaleView = -1;
730
                double maxScaleView = -1;
731

    
732
                if (zoomConstraints != null) {
733
                        minScaleView = zoomConstraints.getMinScale();
734
                        maxScaleView = zoomConstraints.getMaxScale();
735
                }
736

    
737
                if (minScaleView == -1 && maxScaleView == -1) {
738
                        // parameters not set, so the layer decides.
739
                        return layer.isWithinScale(scale);
740
                }
741

    
742
                if (minScaleView <= scale) {
743
                        return (maxScaleView != -1) ? maxScaleView >= scale : true;
744
                }
745

    
746
                return false;
747
        }
748

    
749
        public void setUnit(int unitIndex) {
750
                unit = unitIndex;
751

    
752
        }
753

    
754
        public int getUnit() {
755
                return unit;
756
        }
757

    
758
        public int getReferenceSystem() {
759
                return referenceSystem;
760
        }
761

    
762
        public void setReferenceSystem(int referenceSystem) {
763
                this.referenceSystem = referenceSystem;
764
        }
765

    
766
        public double toCartographicSize(ViewPort viewPort, double dpi, FShape shp) {
767
                // TODO Auto-generated method stub
768
                return 0;
769
        }
770

    
771
        public void setCartographicSize(double cartographicSize, FShape shp) {
772
                // TODO Auto-generated method stub
773

    
774
        }
775

    
776
        public double getCartographicSize(ViewPort viewPort, double dpi, FShape shp) {
777
                // TODO Auto-generated method stub
778
                return 0;
779
        }
780

    
781
}