Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / fill / impl / MarkerFillSymbol.java @ 47476

History | View | Annotate | Download (19.8 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

    
25
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.impl;
26

    
27
import java.awt.Dimension;
28
import java.awt.Graphics2D;
29
import java.awt.Paint;
30
import java.awt.Rectangle;
31
import java.awt.RenderingHints;
32
import java.awt.Shape;
33
import java.awt.TexturePaint;
34
import java.awt.geom.AffineTransform;
35
import java.awt.image.BufferedImage;
36
import java.util.Random;
37
import org.gvsig.fmap.dal.feature.Feature;
38
import org.gvsig.fmap.geom.Geometry;
39
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
40
import org.gvsig.fmap.geom.GeometryLocator;
41
import org.gvsig.fmap.geom.GeometryManager;
42
import org.gvsig.fmap.geom.exception.CreateGeometryException;
43
import org.gvsig.fmap.geom.primitive.Envelope;
44
import org.gvsig.fmap.geom.primitive.Point;
45
import org.gvsig.fmap.mapcontext.MapContext;
46
import org.gvsig.fmap.mapcontext.MapContextLocator;
47
import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport;
48
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
49
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol_v2;
50
import org.gvsig.fmap.mapcontext.rendering.symbols.IWarningSymbol;
51
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
52
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
53
import org.gvsig.i18n.Messages;
54
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IFillSymbol;
55
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IMarkerFillSymbol;
56
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
57
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol_v2;
58
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.IMarkerFillPropertiesStyle;
59
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.SimpleMarkerFillPropertiesStyle;
60
import org.gvsig.tools.ToolsLocator;
61
import org.gvsig.tools.dynobject.DynStruct;
62
import org.gvsig.tools.persistence.PersistenceManager;
63
import org.gvsig.tools.persistence.PersistentState;
64
import org.gvsig.tools.persistence.exception.PersistenceException;
65
import org.gvsig.tools.swing.api.ToolsSwingLocator;
66
import org.gvsig.tools.task.Cancellable;
67
import org.gvsig.tools.util.Callable;
68
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
70

    
71
/**
72
 * Allows to define a marker symbol of any type as a path image to be used for a filled of a
73
 * polygon's padding
74
 *
75
 * @author   gvSIG Team
76
 */
77
public class MarkerFillSymbol extends AbstractFillSymbol implements IMarkerFillSymbol {
78
        private static final Logger logger = LoggerFactory.getLogger(MarkerFillSymbol.class);
79

    
80
    public static final String MARK_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME =
81
        "MarkerFillSymbol";
82
    private static final String MARKER_SYMBOL = "markerSymbol";
83
    private static final String SELECTION_SYMBOL = "selectionSymbol";
84
    private static final String MARKER_FILL_PROPERTIES = "markerFillProperties";
85
    private static final String PREVIOUS_MARKERSIZE = "previousMarkerSize";
86

    
87
        public static final int RANDOM_FILL = 3;
88
        public static final int GRID_FILL = 1;
89
        public static final int SINGLE_CENTERED_SYMBOL = 2;
90
        public static int DefaultFillStyle = GRID_FILL;
91
        private MarkerFillSymbol selectionSymbol;
92
        private IMarkerFillPropertiesStyle markerFillProperties = new SimpleMarkerFillPropertiesStyle();
93
        private IMarkerSymbol markerSymbol = (IMarkerSymbol) MapContextLocator.getSymbolManager().createSymbol(IMarkerSymbol.SYMBOL_NAME);
94

    
95
    @Override
96
    public ISymbol getSymbolForSelection() {
97
        if (selectionSymbol == null) {
98
            selectionSymbol = (MarkerFillSymbol) cloneForSelection();
99
            selectionSymbol.setMarker((IMarkerSymbol) selectionSymbol.getMarker().getSymbolForSelection());
100
            selectionSymbol.setFillColor(MapContext.getSelectionColor());
101
        } else {
102
            selectionSymbol.setColor(MapContext.getSelectionColor());
103
        }
104
        if (selectionSymbol instanceof CartographicSupport) {
105
            ((CartographicSupport) selectionSymbol).setUnit(this.getUnit());
106
        }
107
        if (selectionSymbol.getMarker() instanceof CartographicSupport) {
108
            ((CartographicSupport) selectionSymbol.getMarker()).setUnit(this.getUnit());
109
        }
110

    
111
        return selectionSymbol;
112
    }
113

    
114
    @Override
115
    public void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Feature f, Cancellable cancel, Rectangle rect) {
116
        GeometryManager geometryManager = GeometryLocator.getGeometryManager();
117
        Point centroid = null;
118
        Point p;
119

    
120
        if (this.markerSymbol instanceof CartographicSupport) {
121
            this.markerSymbol.setCartographicContext(this.getCartographicContext());
122
        }
123

    
124
        if (rect != null) {
125
            geom = getSampleGeometry(rect);
126
        }
127
        switch (markerFillProperties.getFillStyle()) {
128
            case SINGLE_CENTERED_SYMBOL:
129
                // case a single marker is used into a polygon shapetype
130
                //                        Geometry geom = FConverter.java2d_to_jts(geom);
131
                //                        com.vividsolutions.jts.geom.Point centroid = geom.getCentroid();
132
                try {
133
                    centroid = geom.centroid();
134
                } catch (Exception e2) {
135
                    logger.warn("Can't get centroid", e2);
136
                }
137

    
138
                /*
139
                                             * Hay ocasiones en que jts no puede calcular un centroide y devuelve NaN
140
                                             * (por ejemplo con geometr?as poligonales cuyos puntos tienen todos la misma
141
                                             * abscisa y distinta ordenada con tan solo una diferencia de 1 ? 2 unidades)
142
                                             * entonces, en lugar de utilizar este centroide tomamos el centro del
143
                                             * bounds del shp (la geometr?a es tan peque?a que consideramos que deben coincidir).
144
                 */
145
                p = null;
146
                if (centroid != null && !(Double.isNaN(centroid.getX()) || Double.isNaN(centroid.getY()))) {
147
                    double pX = centroid.getX() + markerFillProperties.getXOffset();
148
                    double pY = centroid.getY() + markerFillProperties.getYOffset();
149
                    try {
150
                        p = geometryManager.createPoint(pX, pY, SUBTYPES.GEOM2D);
151
                    } catch (CreateGeometryException e) {
152
                        logger.error("Can't create the point (" + pX + "," + pY + ")", e);
153
                    }
154
                    if (p != null) {
155
                        if (markerSymbol instanceof IMarkerSymbol_v2) {
156
                            ((IMarkerSymbol_v2) markerSymbol).draw(g, affineTransform, p, f, null, null);
157
                        } else {
158
                            markerSymbol.draw(g, affineTransform, p, f, null);
159
                        }
160
                    }
161
                } else {
162
                    //                Rectangle bounds = geom.getShape().getBounds();
163
                    //                double pX = bounds.getCenterX();
164
                    //                double pY = bounds.getCenterY();
165
                    Envelope env = geom.getEnvelope();
166
                    double pX = env.getCenter(Geometry.DIMENSIONS.X);
167
                    double pY = env.getCenter(Geometry.DIMENSIONS.Y);
168
                    try {
169
                        p = geometryManager.createPoint(pX, pY, SUBTYPES.GEOM2D);
170
                    } catch (CreateGeometryException e) {
171
                        logger.error("Can't create the point (" + pX + "," + pY + ")", e);
172
                    }
173
                    if (p != null) {
174
                        if (markerSymbol instanceof IMarkerSymbol_v2) {
175
                            ((IMarkerSymbol_v2) markerSymbol).draw(g, affineTransform, p, f, null, null);
176
                        } else {
177
                            markerSymbol.draw(g, affineTransform, p, f, null);
178
                        }
179
                    }
180
                }
181
                break;
182
            case GRID_FILL: { // case a grid fill is used
183
                Rectangle rClip = null;
184
                if (g.getClipBounds() != null) {
185
                    rClip = (Rectangle) g.getClipBounds().clone();
186
                    g.setClip(rClip.x, rClip.y, rClip.width, rClip.height);
187
                }
188
                g.clip(geom.getShape(affineTransform));
189

    
190
                int size = (int) this.toCartographicUnits(markerSymbol.getSize());
191
                Dimension maxSize = ToolsSwingLocator.getToolsSwingManager().getMaxPhysicalSizeOfBufferedImage();
192
                if (size > 0 && size <= maxSize.width && size <= maxSize.height) {
193
                    Rectangle rProv = new Rectangle();
194
                    rProv.setFrame(0, 0, size, size);
195
                    Paint resulPatternFill = null;
196

    
197
                    double xSeparation = this.toCartographicUnits(markerFillProperties.getXSeparation()); // TODO apply CartographicSupport
198
                    double ySeparation = this.toCartographicUnits(markerFillProperties.getYSeparation()); // TODO apply CartographicSupport
199
                    double xOffset = this.toCartographicUnits(markerFillProperties.getXOffset());
200
                    double yOffset = this.toCartographicUnits(markerFillProperties.getYOffset());
201

    
202
                    BufferedImage sample = null;
203
                    //                                    sample = ToolsSwingLocator.getToolsSwingManager().createBufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
204
                    Graphics2D gAux = null;
205
                    if (size > 0) {
206
                        sample = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
207
                        gAux = sample.createGraphics();
208

    
209
                        try {
210
                            markerSymbol.drawInsideRectangle(gAux, gAux.getTransform(), rProv);
211
                        } catch (SymbolDrawingException e) {
212
                            if (e.getType() == SymbolDrawingException.UNSUPPORTED_SET_OF_SETTINGS) {
213
                                try {
214
                                    IWarningSymbol warning
215
                                            = (IWarningSymbol) MapContextLocator.getSymbolManager()
216
                                                    .getWarningSymbol(
217
                                                            SymbolDrawingException.STR_UNSUPPORTED_SET_OF_SETTINGS,
218
                                                            "",
219
                                                            SymbolDrawingException.UNSUPPORTED_SET_OF_SETTINGS);
220
                                    warning.drawInsideRectangle(gAux, gAux.getTransform(), rProv);
221
                                } catch (SymbolDrawingException e1) {
222
                                    // IMPOSSIBLE TO REACH THIS
223
                                }
224
                            } else {
225
                                // should be unreachable code
226
                                throw new Error(Messages.getText("symbol_shapetype_mismatch"));
227
                            }
228
                        }
229
                        rProv.setRect(xOffset, yOffset,
230
                                rProv.getWidth() + xSeparation,
231
                                rProv.getHeight() + ySeparation);
232

    
233
                        BufferedImage bi = new BufferedImage(rProv.width, rProv.height, BufferedImage.TYPE_INT_ARGB);
234
                        gAux = bi.createGraphics();
235
                        gAux.drawImage(sample, null, 0 , 0 ); //(int) (xSeparation * 0.5), (int) (ySeparation * 0.5));
236

    
237
                        resulPatternFill = new TexturePaint(bi, rProv);
238
                        sample = null;
239
                        if (gAux != null) {
240
                            gAux.dispose();
241
                        }
242

    
243
                        g.setColor(null);
244
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
245
                                RenderingHints.VALUE_ANTIALIAS_ON);
246

    
247
                        g.setPaint(resulPatternFill);
248
                        g.fill(geom.getShape(affineTransform));
249
                        g.setClip(rClip);
250
                        bi = null;
251
                    }
252
                    break;
253
                }
254
            }
255
            case RANDOM_FILL: {
256

    
257
                double s = markerSymbol.getSize();
258
                Shape shp = geom.getShape(affineTransform);
259
                Rectangle r = shp.getBounds();
260
                int drawCount = (int) (Math.min(r.getWidth(), r.getHeight()) / s);
261
                Random random = new Random();
262

    
263
                int minx = r.x;
264
                int miny = r.y;
265
                int width = r.width;
266
                int height = r.height;
267

    
268
                r = new Rectangle();
269
                g.setClip(shp);
270

    
271
                for (int i = 0; (cancel == null || !cancel.isCanceled()) && i < drawCount; i++) {
272
                    int x = (int) Math.abs(random.nextDouble() * width);
273
                    int y = (int) Math.abs(random.nextDouble() * height);
274
                    x = x + minx;
275
                    y = y + miny;
276
                    //                                markerSymbol.draw(g, new AffineTransform(), new FPoint2D(x, y), cancel);
277
                    p = null;
278
                    try {
279
                        p = geometryManager.createPoint(x, y, SUBTYPES.GEOM2D);
280
                    } catch (CreateGeometryException e) {
281
                        logger.error("Can't create the point (" + x + "," + y + ")", e);
282
                    }
283
                    if (p != null) {
284
                        if (markerSymbol instanceof IMarkerSymbol_v2) {
285
                            ((IMarkerSymbol_v2) markerSymbol).draw(g, new AffineTransform(), p, f, cancel, null);
286
                        } else {
287
                            markerSymbol.draw(g, new AffineTransform(), p, f, cancel);
288
                        }
289
                    }
290
                }
291
                g.setClip(null);
292
                break;
293
            }
294
        }
295
        if (getOutline() != null) {
296
            getOutline().setCartographicContext(this.getCartographicContext());
297
            if (getOutline() instanceof ISymbol_v2) {
298
                ((ISymbol_v2) getOutline()).draw(g, affineTransform, geom, f, cancel, null);
299
            } else {
300
                getOutline().draw(g, affineTransform, geom, f, cancel);
301
            }
302
        }
303
    }
304

    
305
        @Override
306
        public int getSymbolType() {
307
                return Geometry.TYPES.SURFACE;
308
        }
309

    
310
        public String getClassName() {
311
                return getClass().getName();
312
        }
313

    
314
        @Override
315
        public void setMarker(IMarkerSymbol marker) {
316
                this.markerSymbol = marker;
317
        }
318

    
319
        @Override
320
        public IMarkerSymbol getMarker() {
321
                return markerSymbol;
322
        }
323

    
324
        /**
325
         * Sets the markerfillproperties to be used by the class
326
         *
327
         * @param markerFillStyle,IMarkerFillPropertiesStyle
328
         */
329
        @Override
330
        public void setMarkerFillProperties(IMarkerFillPropertiesStyle markerFillStyle) {
331
                this.markerFillProperties = markerFillStyle;
332
        }
333

    
334
        /**
335
         * Returns the markerfillproperties that are used by the class
336
         *
337
         * @return markerFillProperties,IMarkerFillPropertiesStyle
338
         */
339
        @Override
340
        public IMarkerFillPropertiesStyle getMarkerFillProperties() {
341
                return markerFillProperties;
342
        }
343

    
344
        @Override
345
        public void setUnit(int unitIndex) {
346
                super.setUnit(unitIndex);
347
                if (getMarker()!=null) {
348
                        getMarker().setUnit(unitIndex);
349
                }
350
        }
351

    
352
        @Override
353
        public void setReferenceSystem(int system) {
354
                super.setReferenceSystem(system);
355
                if (getMarker()!=null) {
356
                        getMarker().setReferenceSystem(system);
357
                }
358
        }
359

    
360
    @Override
361
    public void setCartographicContext(CartographicContext ctx) {
362
        super.setCartographicContext(ctx);
363
        IMarkerSymbol marker = getMarker();
364
        if (marker != null) {
365
            marker.setCartographicContext(ctx);
366
        }
367
        
368
    }
369

    
370
    @Override
371
    public Object clone() throws CloneNotSupportedException {
372
            MarkerFillSymbol copy = (MarkerFillSymbol) super.clone();
373

    
374
        // clone marker
375
        if (markerSymbol != null) {
376
            copy.markerSymbol = (IMarkerSymbol) markerSymbol.clone();
377
        }
378

    
379
        // clone selection
380
        if (selectionSymbol != null) {
381
            copy.selectionSymbol = (MarkerFillSymbol) selectionSymbol.clone();
382
        }
383

    
384
        // clone markerFillProperties
385
        if (markerFillProperties != null) {
386
            copy.markerFillProperties = (IMarkerFillPropertiesStyle) markerFillProperties.clone();
387
        }
388

    
389
        // FIXME: clone properties
390

    
391
        return copy;
392
    }
393

    
394
    @Override
395
    public void loadFromState(PersistentState state) throws PersistenceException {
396
        // Set parent style properties
397
        super.loadFromState(state);
398

    
399
        this.markerSymbol =  (IMarkerSymbol) state.get(MARKER_SYMBOL);
400
        this.selectionSymbol = (MarkerFillSymbol) state.get(SELECTION_SYMBOL);
401
        this.markerFillProperties = (IMarkerFillPropertiesStyle) state.get(MARKER_FILL_PROPERTIES);
402
    }
403

    
404
        @Override
405
    public void saveToState(PersistentState state) throws PersistenceException {
406
        // Save parent fill symbol properties
407
        super.saveToState(state);
408

    
409
        // Save own properties
410
        state.set(MARKER_SYMBOL, this.markerSymbol);
411
        state.set(SELECTION_SYMBOL, this.selectionSymbol);
412
        state.set(MARKER_FILL_PROPERTIES, this.markerFillProperties);
413
    }
414

    
415
    public static class RegisterPersistence implements Callable {
416

    
417
        @Override
418
        public Object call() throws Exception {
419
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
420
            if (manager.getDefinition(MARK_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) {
421
                DynStruct definition =
422
                    manager.addDefinition(MarkerFillSymbol.class,
423
                                    MARK_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
424
                                    MARK_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME
425
                            + " Persistence definition",
426
                        null,
427
                        null);
428

    
429
                // Extend the Style base definition
430
                definition.extend(manager.getDefinition(FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME));
431

    
432
                definition.addDynFieldObject(MARKER_SYMBOL)
433
                .setClassOfValue(IMarkerSymbol.class).setMandatory(true);
434
                definition.addDynFieldObject(SELECTION_SYMBOL)
435
                    .setClassOfValue(IMarkerFillSymbol.class).setMandatory(false);
436
                definition.addDynFieldObject(MARKER_FILL_PROPERTIES)
437
                .setClassOfValue(IMarkerFillPropertiesStyle.class).setMandatory(true);
438
                definition.addDynFieldDouble(PREVIOUS_MARKERSIZE);
439
            }
440
            return Boolean.TRUE;
441
        }
442
    }
443

    
444
        public static class RegisterSymbol implements Callable {
445

    
446
                @Override
447
                public Object call() throws Exception {
448
                int[] shapeTypes;
449
                SymbolManager manager = MapContextLocator.getSymbolManager();
450

    
451
                shapeTypes =
452
                    new int[] { Geometry.TYPES.SURFACE, Geometry.TYPES.CIRCLE,
453
                        Geometry.TYPES.ELLIPSE, Geometry.TYPES.MULTISURFACE };
454
                manager.registerMultiLayerSymbol(IFillSymbol.SYMBOL_NAME,
455
                    shapeTypes,
456
                    MarkerFillSymbol.class);
457

    
458
                        return Boolean.TRUE;
459
                }
460

    
461
        }
462

    
463
}