Statistics
| Revision:

root / org.gvsig.legend.aggregate / trunk / org.gvsig.legend.aggregate / org.gvsig.legend.aggregate.lib / org.gvsig.legend.aggregate.lib.impl / src / main / java / org / gvsig / legend / aggregate / lib / impl / DefaultAggregateLegend.java @ 1846

History | View | Annotate | Download (14.2 KB)

1
package org.gvsig.legend.aggregate.lib.impl;
2

    
3
import java.awt.Color;
4
import java.awt.Dimension;
5
import java.awt.Font;
6
import java.awt.FontMetrics;
7
import java.awt.Graphics2D;
8
import java.awt.Rectangle;
9
import java.awt.geom.AffineTransform;
10
import java.awt.geom.Ellipse2D;
11
import java.awt.geom.Rectangle2D;
12
import java.awt.image.BufferedImage;
13
import java.util.ArrayList;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.logging.Level;
17
import javax.swing.UIManager;
18

    
19
import org.cresques.cts.ICoordTrans;
20
import org.slf4j.Logger;
21
import org.slf4j.LoggerFactory;
22

    
23
import org.gvsig.fmap.dal.exception.DataException;
24
import org.gvsig.fmap.dal.feature.Feature;
25
import org.gvsig.fmap.dal.feature.FeatureQuery;
26
import org.gvsig.fmap.dal.feature.FeatureSelection;
27
import org.gvsig.fmap.dal.feature.FeatureSet;
28
import org.gvsig.fmap.dal.feature.FeatureStore;
29
import org.gvsig.fmap.geom.Geometry;
30
import org.gvsig.fmap.geom.primitive.Point;
31
import org.gvsig.fmap.mapcontext.MapContextException;
32
import org.gvsig.fmap.mapcontext.ViewPort;
33
import org.gvsig.fmap.mapcontext.rendering.legend.LegendException;
34
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
35
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
36
import org.gvsig.fmap.mapcontext.rendering.symbols.styles.ILabelStyle;
37
import org.gvsig.legend.aggregate.lib.api.AggregateLegend;
38
import org.gvsig.legend.aggregate.lib.api.AggregateLegendLocator;
39
import org.gvsig.legend.aggregate.lib.api.Operation;
40
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.AbstractVectorialLegend;
41
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.DefaultFeatureDrawnNotification;
42
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.impl.SimpleFillSymbol;
43
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.impl.SimpleLineSymbol;
44
import org.gvsig.tools.exception.BaseException;
45
import org.gvsig.tools.logger.FilteredLogger;
46
import org.gvsig.tools.task.Cancellable;
47
import org.gvsig.tools.visitor.VisitCanceledException;
48
import org.gvsig.tools.visitor.Visitor;
49

    
50
public class DefaultAggregateLegend extends AbstractVectorialLegend implements AggregateLegend {
51

    
52
    private static class Group {
53

    
54
//        private final Point pointGeo;
55
//        private final Rectangle2D rectangle;
56
        private Operation op;
57
        private final Point pointPixels;
58
        private final Ellipse2D circle;
59

    
60
        public Group(Point pointGeo, Point pointPixels, double size, Operation op) {
61
            this.op = op;
62
            this.op.reset();
63
//            this.pointGeo = pointGeo;
64
            this.pointPixels = pointPixels;
65
            double d2 = size * 2;
66
//            this.rectangle = new Rectangle2D.Double(pointPixels.getX() - distance, pointPixels.getY() - distance, d2, d2);
67
            this.circle = new Ellipse2D.Double(pointPixels.getX() - size, pointPixels.getY() - size, d2, d2);
68
        }
69

    
70
        public boolean contains(Point pointPixels) {
71
//            return this.rectangle.contains(pointPixels.getX(), pointPixels.getY());
72
          return this.circle.contains(pointPixels.getX(), pointPixels.getY());
73
        }
74

    
75
        public void add(Feature feature) {
76
            op.perform(feature);
77
        }
78
        
79
        public Operation getOperation() {
80
            return this.op;
81
        }
82
    }
83

    
84
    private static final Logger LOG = LoggerFactory.getLogger(DefaultAggregateLegend.class);
85

    
86
    private List<Group> groups;
87

    
88
    private int symbolSize; // Pixels
89
    private Color fillColor;
90
    private Color outlineColor;
91
    private Color textColor;
92
    private boolean showBounds;
93
    private Font font;
94

    
95
    private boolean useStyle;
96
    private ILabelStyle labelStyle;
97
    
98
    private Operation operation;
99
    
100
    private SimpleFillSymbol defaultSymbol;
101

    
102
    public DefaultAggregateLegend() {
103
        this.groups = null;
104
        
105
        this.useStyle = false;
106
        this.symbolSize = 30;
107
        this.fillColor = new Color(0xd0ffcccc, true); // Un rojo
108
        this.outlineColor = new Color(0xff5f60de, true); // un azul
109
        this.textColor = new Color(0xff000000, true); // negro
110
        this.showBounds = false;
111
        this.labelStyle = null;        
112
        this.font = UIManager.getFont("Label.font");
113
        this.operation = AggregateLegendLocator.getAggregateLegendManager().getDefaultOperation().clone();
114
        this.defaultSymbol = new SimpleFillSymbol();
115
        this.defaultSymbol.setOutline(new SimpleLineSymbol());
116
        this.defaultSymbol.getOutline().setLineColor(this.outlineColor);
117
        this.defaultSymbol.setFillColor(this.fillColor);
118
        
119
    }
120

    
121
    @Override
122
    protected String[] getRequiredFeatureAttributeNames(FeatureStore featureStore) throws DataException {
123
        if( this.operation.isAttributeRequiered() && this.operation.getAttributeName()!=null ) {
124
            return new String[]{
125
                this.operation.getAttributeName(),
126
                featureStore.getDefaultFeatureType().getDefaultGeometryAttributeName()
127
            };
128
        }
129
        return new String[]{
130
            featureStore.getDefaultFeatureType().getDefaultGeometryAttributeName()
131
        };
132
    }
133

    
134
    @Override
135
    public ISymbol getDefaultSymbol() {
136
        return this.defaultSymbol;
137
    }
138

    
139
    @Override
140
    public void setDefaultSymbol(ISymbol is) {
141
    }
142

    
143
    @Override
144
    public ISymbol getSymbolByFeature(Feature ftr) throws MapContextException {
145
        return this.getDefaultSymbol();
146
    }
147

    
148
    @Override
149
    public int getShapeType() {
150
        return Geometry.TYPES.GEOMETRY;
151
    }
152

    
153
    @Override
154
    public void setShapeType(int i) {
155
    }
156

    
157
    @Override
158
    public boolean isUseDefaultSymbol() {
159
        return true;
160
    }
161

    
162
    @Override
163
    public void useDefaultSymbol(boolean bln) {
164
    }
165

    
166
    @Override
167
    public boolean isSuitableForShapeType(int shapeType) {
168
        return true;
169
    }
170

    
171
    @Override
172
    protected void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale, Map queryParameters, ICoordTrans coordTrans, FeatureStore featureStore, FeatureQuery featureQuery, double dpi) throws LegendException {
173
        super.draw(image, g, viewPort, cancel, scale, queryParameters, coordTrans, featureStore, featureQuery, dpi);
174
        this.drawGroups(image, g, cancel, viewPort.getAffineTransform());
175
    }
176

    
177
    @Override
178
    protected void drawFeatures(
179
        BufferedImage image,
180
        Graphics2D g,
181
        final ViewPort viewPort,
182
        final Cancellable cancel,
183
        final ICoordTrans coordTrans,
184
        double dpi,
185
        DefaultFeatureDrawnNotification drawnNotification,
186
        FeatureSet featureSet,
187
        FeatureSelection selection
188
    ) throws BaseException {
189
        this.groups = new ArrayList<>();
190
        featureSet.accept(new Visitor() {
191
            @Override
192
            public void visit(Object o) throws VisitCanceledException, BaseException {
193
                if( cancel.isCanceled() ) {
194
                    throw new VisitCanceledException();
195
                }
196
                Feature feature = (Feature) o;
197
                Geometry geom = feature.getDefaultGeometry();
198
                if( geom != null ) {
199
                    Point pointGeo = geom.centroid();
200
                    if( coordTrans != null ) {
201
                        pointGeo.reProject(coordTrans);
202
                    }
203
                    Point pointPixels = (Point) pointGeo.cloneGeometry();
204
                    pointPixels.transform(viewPort.getAffineTransform());
205
                    boolean inGroup = false;
206
                    for( Group group : groups ) {
207
                        if( group.contains(pointPixels) ) {
208
                            group.add(feature);
209
                            inGroup = true;
210
                            break;
211
                        }
212
                    }
213
                    if( !inGroup ) {
214
                        groups.add(new Group(pointGeo, pointPixels, getSymbolSize(), getOperation().clone()));
215
                    }
216
                }
217
            }
218
        });
219
    }
220

    
221
    private void drawGroups(BufferedImage image, Graphics2D g, Cancellable cancel, AffineTransform affineTransform) {
222
        FilteredLogger logger = new FilteredLogger(LOG, "", 10);
223
        AffineTransform identity = new AffineTransform();
224
        
225
        g.setFont(this.font);
226
        FontMetrics fm = g.getFontMetrics();
227
        int fontAscent = fm.getAscent();
228
        int fontAscentAddDescentDiv2 = ((fm.getAscent() + fm.getDescent())) / 2;        
229

    
230
        for( Group group : groups ) {
231
            if( cancel.isCanceled() ) {
232
                return;
233
            }
234
            try {
235
                int x = (int) group.pointPixels.getX();
236
                int y = (int) group.pointPixels.getY();
237
                String txt = group.getOperation().format();
238
                if( this.useStyle && this.labelStyle != null ) {
239
                    Dimension size = this.labelStyle.getSize();
240
                    this.labelStyle.setTextFields(new String[]{txt});
241
                    g.setTransform(identity);
242
                    g.translate(x-size.getWidth()/2, y-size.getHeight()/2);
243
                    Rectangle rect = new Rectangle(
244
                        0,
245
                        0,
246
                        (int)size.getWidth(),
247
                        (int)size.getHeight());
248
                    this.labelStyle.drawInsideRectangle(g, rect);
249
                    Rectangle2D[] bounds = this.labelStyle.getTextBounds();
250
                    if(bounds.length>0){
251
                        Rectangle2D bound = bounds[0];
252
                        Rectangle2D expandedBound = new Rectangle2D.Double(
253
                            bound.getMinX()*size.getWidth(),
254
                            bound.getMinY()*size.getHeight(),
255
                            bound.getWidth()*size.getWidth(),
256
                            bound.getHeight()*size.getHeight());
257
                        drawCenteredString(txt, expandedBound, g);
258
                    }
259
                    g.translate(-(x-size.getWidth()/2), -(y-size.getHeight()/2));
260
                } else {
261
                    int r = symbolSize/2;
262
                    g.setColor(this.fillColor);
263
                    g.fillOval( x-r, y-r, 2*r, 2*r);
264
                    g.setColor(this.outlineColor);
265
                    g.drawOval( x-r, y-r, 2*r, 2*r);
266
                    if( this.showBounds ) {
267
                        g.drawRect( x-r, y-r, 2*r, 2*r);
268
                    }
269
                    g.setColor(this.textColor);
270
                    int txtX = x - (fm.stringWidth(txt) / 2);
271
                    int txtY = fontAscent + y - fontAscentAddDescentDiv2; //((fm.getAscent() + fm.getDescent())) / 2;
272
                    g.drawString(txt, txtX, txtY);
273
                }
274
            } catch (Exception ex) {
275
                logger.warn("Can't draw group",ex);
276
            }
277
        }
278
    }
279

    
280
    private void drawCenteredString(String s, Rectangle2D rect, Graphics2D g) {
281

    
282
        double x = rect.getMinX();
283
        double y = rect.getMinY();
284
        double w = rect.getWidth();
285
        double h = rect.getHeight();
286

    
287
        FontMetrics fm = g.getFontMetrics();
288
        int auxX = (int)(x+((w - fm.stringWidth(s)) / 2));
289
        int auxY = (int)(y+((fm.getAscent() + (h - (fm.getAscent() + fm.getDescent())) / 2)));
290
        g.setColor(Color.BLACK);
291
        g.drawString(s, auxX, auxY);
292
      }
293

    
294
    @Override
295
    public ILabelStyle getLabelStyle() {
296
        return this.labelStyle;
297
    }
298

    
299
    @Override
300
    public void setLabelStyle(ILabelStyle labelStyle) {
301
        this.labelStyle = labelStyle;
302
    }
303

    
304
    @Override
305
    public int getSymbolSize() {
306
        return this.symbolSize;
307
    }
308

    
309
    @Override
310
    public void setSymbolSize(int simbolSize) {
311
        boolean changed = (this.symbolSize == simbolSize);
312
        this.symbolSize = simbolSize;
313
        if( changed ) {
314
            this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
315
        }
316
    }
317

    
318
    @Override
319
    public Operation getOperation() {
320
        return this.operation;
321
    }
322
    
323
    @Override
324
    public void setOperation(Operation operation) {
325
        boolean changed = (this.operation.getName().equalsIgnoreCase(operation.getName()));
326
        this.operation = operation;
327
        if( changed ) {
328
            this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
329
        }
330
    }
331

    
332
    @Override
333
    public Color getFillColor() {
334
        return fillColor;
335
    }
336

    
337
    @Override
338
    public void setFillColor(Color fillColor) {
339
        boolean changed = (this.fillColor.equals(fillColor));
340
        this.fillColor = fillColor;
341
        this.defaultSymbol.setFillColor(this.fillColor);
342
        if( changed ) {
343
            this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
344
        }
345
    }
346

    
347
    @Override
348
    public Color getOutlineColor() {
349
        return outlineColor;
350
    }
351

    
352
    @Override
353
    public void setOutlineColor(Color outlineColor) {
354
        boolean changed = (this.outlineColor.equals(outlineColor));
355
        this.outlineColor = outlineColor;
356
        this.defaultSymbol.getOutline().setLineColor(this.outlineColor);
357
        if( changed ) {
358
            this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
359
        }
360
    }
361

    
362
    @Override
363
    public boolean isShowBounds() {
364
        return showBounds;
365
    }
366

    
367
    @Override
368
    public void setShowBounds(boolean showBounds) {
369
        boolean changed = (this.showBounds == showBounds);
370
        this.showBounds = showBounds;
371
        if( changed ) {
372
            this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
373
        }
374
    }
375

    
376
    @Override
377
    public Font getFont() {
378
        return font;
379
    }
380

    
381
    @Override
382
    public void setFont(Font font) {
383
        this.font = font;
384
        this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
385
    }
386

    
387
    @Override
388
    public boolean isUseStyle() {
389
        return useStyle;
390
    }
391

    
392
    @Override
393
    public void setUseStyle(boolean useStyle) {
394
        boolean changed = (this.useStyle == useStyle);
395
        this.useStyle = useStyle;
396
        if( changed ) {
397
            this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
398
        }
399
    }
400

    
401
    @Override
402
    public Color getTextColor() {
403
        return this.textColor;
404
    }
405

    
406
    @Override
407
    public void setTextColor(Color textColor) {
408
        boolean changed = (this.textColor.equals(textColor));
409
        this.textColor = textColor;
410
        if( changed ) {
411
            this.fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null,null));
412
        }
413
    }
414
}