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 / PictureFillSymbol.java @ 40686

History | View | Annotate | Download (15.7 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
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.impl;
25

    
26
import java.awt.Color;
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.io.IOException;
37
import java.net.URL;
38

    
39
import org.gvsig.compat.print.PrintAttributes;
40
import org.gvsig.fmap.dal.feature.Feature;
41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
43
import org.gvsig.fmap.geom.Geometry.TYPES;
44
import org.gvsig.fmap.geom.GeometryLocator;
45
import org.gvsig.fmap.geom.GeometryManager;
46
import org.gvsig.fmap.geom.exception.CreateGeometryException;
47
import org.gvsig.fmap.geom.primitive.GeneralPathX;
48
import org.gvsig.fmap.geom.primitive.Surface;
49
import org.gvsig.fmap.mapcontext.MapContextLocator;
50
import org.gvsig.fmap.mapcontext.ViewPort;
51
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
52
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
53
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
54
import org.gvsig.fmap.mapcontext.rendering.symbols.styles.IBackgroundFileStyle;
55
import org.gvsig.i18n.Messages;
56
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IPictureFillSymbol;
57
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.BackgroundFileStyle;
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.task.Cancellable;
66
import org.gvsig.tools.util.Callable;
67
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
69

    
70
/**
71
 * PictureFillSymbol allows to use an image file suported by gvSIG as a padding
72
 * for the polygons.This image can be modified using methods to scale or rotate it.
73
 * @author jaume dominguez faus - jaume.dominguez@iver.es
74
 */
75
public class PictureFillSymbol extends AbstractFillSymbol implements IPictureFillSymbol {
76
        private static final Logger logger = LoggerFactory.getLogger(PictureFillSymbol.class);
77

    
78
    public static final String PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME =
79
        "PictureFillSymbol";
80
    private static final String SELECTED = "selected";
81
    private static final String SELECTION_SYMBOL = "selectionSym";
82
    private static final String BACKGROUND_IMAGE = "bgImage";
83
    private static final String BACKGROUND_SELECTION_IMAGE = "bgSelImage";
84
    private static final String ANGLE = "angle";
85
    private static final String X_SCALE = "xScale";
86
    private static final String Y_SCALE = "yScale";
87
    private static final String MARKER_FILL_PROPERTIES = "markerFillProperties";
88

    
89
        private double angle = 0;
90
        private double xScale = 1;
91
        private double yScale = 1;
92
        transient private PictureFillSymbol selectionSym;
93
        private boolean selected;
94
        private IMarkerFillPropertiesStyle markerFillProperties = new SimpleMarkerFillPropertiesStyle();
95
        private BackgroundFileStyle bgImage;
96
        private BackgroundFileStyle bgSelImage;
97
        private PrintAttributes properties;
98
        private GeometryManager geometryManager = GeometryLocator.getGeometryManager();
99

    
100
        private void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Cancellable cancel) {
101
                 Color fillColor = getFillColor();
102
                 
103
                 Shape transf_geom = geom.getShape(affineTransform);
104
                 
105
                if (fillColor != null) {
106
                        g.setColor(fillColor);
107
                        g.fill(transf_geom);
108
                }
109

    
110
                g.setClip(transf_geom);
111
                BackgroundFileStyle bg = (!selected) ? bgImage : bgSelImage ;
112
                if (bg != null && bg.getBounds() != null){
113
                        int sizeW=(int) ((int)bg.getBounds().getWidth() * xScale);
114
                        int sizeH=(int) ((int)bg.getBounds().getHeight() * yScale);
115
                        Rectangle rProv = new Rectangle();
116
                        rProv.setFrame(0,0,sizeW,sizeH);
117
                        Paint resulPatternFill = null;
118
                        BufferedImage sample= null;
119

    
120
                        sample= new BufferedImage(sizeW,sizeH,BufferedImage.TYPE_INT_ARGB);
121
                        Graphics2D gAux = sample.createGraphics();
122

    
123
                        double xSeparation = markerFillProperties.getXSeparation(); // TODO apply CartographicSupport
124
                        double ySeparation = markerFillProperties.getYSeparation(); // TODO apply CartographicSupport
125
                        double xOffset = markerFillProperties.getXOffset();
126
                        double yOffset = markerFillProperties.getYOffset();
127

    
128
                        try {
129
                                bg.drawInsideRectangle(gAux, rProv);
130
                        } catch (SymbolDrawingException e) {
131
                                logger.warn(Messages.getText("label_style_could_not_be_painted"), e);
132
                        }
133

    
134
                        Dimension sz = rProv.getSize();
135
                        sz = new Dimension((int) Math.round(sz.getWidth()+(xSeparation)),
136
                                        (int) Math.round(sz.getHeight() + (ySeparation)));
137
                        rProv.setSize(sz);
138

    
139
                        BufferedImage bi = new BufferedImage(rProv.width, rProv.height, BufferedImage.TYPE_INT_ARGB);
140
                        gAux = bi.createGraphics();
141
                        gAux.drawImage(sample, null, (int) (xSeparation*0.5), (int) (ySeparation*0.5));
142

    
143
                        rProv.x = rProv.x+(int)xOffset;
144
                        rProv.y = rProv.y+(int)yOffset;
145
                        resulPatternFill = new TexturePaint(bi,rProv);
146

    
147
                        g.setColor(null);
148
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
149
                                        RenderingHints.VALUE_ANTIALIAS_ON);
150

    
151
                        g.setPaint(resulPatternFill);
152
                }
153
                
154
                if (angle == 0) {
155
                    g.fill(transf_geom);
156
                } else {
157

    
158
            AffineTransform at = new AffineTransform();
159
            at.rotate(angle);
160

    
161
                    Geometry pixels_geom = geom.cloneGeometry();
162
                    pixels_geom.transform(affineTransform);
163
                    pixels_geom.transform(at);
164
                    
165
                    g.rotate(-angle);
166
                    g.fill(pixels_geom.getShape());
167
                    g.rotate(angle);
168
                }
169

    
170
                g.setClip(null);
171
                if (getOutline()!=null) {
172
                        getOutline().draw(g, affineTransform, geom, null, cancel);
173
                }
174
        }
175

    
176
        /**
177
         * Constructor method
178
         *
179
         */
180
        public PictureFillSymbol() {
181
                super();
182
        }
183
        /**
184
         * Constructor method
185
         * @param imageURL, URL of the normal image
186
         * @param selImageURL, URL of the image when it is selected in the map
187
         * @throws IOException
188
         */
189

    
190
        public PictureFillSymbol(URL imageURL, URL selImageURL) throws IOException {
191
                setImage(imageURL);
192
                if (selImageURL!=null)
193
                        setSelImage(selImageURL);
194
                else setSelImage(imageURL);
195
        }
196

    
197

    
198
        /**
199
         * Sets the URL for the image to be used as a picture fill symbol (when it is selected in the map)
200
         * @param imageFile, File
201
         * @throws IOException
202
         */
203
        public void setSelImage(URL selImageUrl) throws IOException{
204

    
205
                bgSelImage= BackgroundFileStyle.createStyleByURL(selImageUrl);
206
//                selImagePath = selImageUrl.toString();
207
        }
208

    
209

    
210

    
211
        /**
212
         * Defines the URL from where the picture to fill the polygon is taken.
213
         * @param imageFile
214
         * @throws IOException
215
         */
216
        public void setImage(URL imageUrl) throws IOException{
217
                bgImage = BackgroundFileStyle.createStyleByURL(imageUrl);
218
        }
219

    
220

    
221

    
222
        public void drawInsideRectangle(Graphics2D g,
223
                        AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
224
                Surface surf;
225
                try {
226
                        surf = geometryManager.createSurface(new GeneralPathX(r.getPathIterator(new AffineTransform())), SUBTYPES.GEOM2D);
227
                        if (properties==null){
228
                                //                        draw(g, null, new FPolygon2D(new GeneralPathX(r)), null);
229
                                draw(g, null, surf, null);
230
                        } else {
231
                                print(g, new AffineTransform(), surf, properties);
232
                        }
233
                } catch (CreateGeometryException e) {
234
                        throw new SymbolDrawingException(TYPES.POINT);
235
                }
236
        }
237

    
238
        public ISymbol getSymbolForSelection() {
239
                if (selectionSym == null) {
240
                        selectionSym = (PictureFillSymbol) cloneForSelection();
241
                        selectionSym.selected=true;
242
                        selectionSym.selectionSym = selectionSym; // avoid too much lazy creations
243
                }
244
                return selectionSym;
245

    
246
        }
247

    
248
        public int getSymbolType() {
249
                return Geometry.TYPES.SURFACE;
250
        }
251

    
252
        public String getClassName() {
253
                return getClass().getName();
254
        }
255

    
256
        public void print(Graphics2D g, AffineTransform at, Geometry geom,
257
                        PrintAttributes properties) {
258
                this.properties=properties;
259
        draw(g, at, geom, null);
260
        this.properties=null;
261
        }
262
        /**
263
         * Returns the IMarkerFillProperties that allows this class to treat the picture as
264
         * a marker in order to scale it, rotate it and so on.
265
         * @return markerFillProperties,IMarkerFillPropertiesStyle
266
         */
267
        public IMarkerFillPropertiesStyle getMarkerFillProperties() {
268
                return markerFillProperties;
269
        }
270

    
271
        /**
272
         * Sets the MarkerFillProperties in order to allow the user to modify the picture as
273
         * a marker (it is possible to scale it, rotate it and so on)
274
         * @param prop
275
         */
276
        public void setMarkerFillProperties(IMarkerFillPropertiesStyle prop) {
277
                this.markerFillProperties = prop;
278
        }
279
        /**
280
         * Defines the angle for the rotation of the image when it is added to create the
281
         * padding
282
         *
283
         * @return angle
284
         */
285
        public double getAngle() {
286
                return angle;
287
        }
288
        /**
289
         * Sets the angle for the rotation of the image when it is added to create the padding
290
         * @param angle
291
         */
292
        public void setAngle(double angle) {
293
                this.angle = angle;
294
        }
295

    
296
        /**
297
         * Defines the scale for the x axis of the image when it is added to create the
298
         * padding
299
         * @return xScale
300
         */
301
        public double getXScale() {
302
                return xScale;
303
        }
304
        /**
305
         * Returns the scale for the x axis of the image when it is added to create the
306
         * padding
307
         * @param xScale
308
         */
309
        public void setXScale(double xScale) {
310
                this.xScale = xScale;
311
        }
312
        /**
313
         * Defines the scale for the y axis of the image when it is added to create the
314
         * padding
315
         * @return yScale
316
         */
317
        public double getYScale() {
318
                return yScale;
319
        }
320
        /**
321
         * Returns the scale for the y axis of the image when it is added to create the
322
         * padding
323
         * @param yScale
324
         */
325
        public void setYScale(double yScale) {
326
                this.yScale = yScale;
327
        }
328

    
329
        /**
330
         * Returns the URL of the image that is used to create the padding to fill the
331
         * polygon
332
         * @return imagePath
333
         */
334
        public URL getSource() {
335
                if (bgImage != null){
336
                        return bgImage.getSource();
337
                }
338
                return null;
339
        }
340

    
341
        /**
342
         * Returns the URL of the image used when the polygon is selected
343
         * @return
344
         */
345
        public URL getSelectedSource(){
346
                if( bgSelImage != null){
347
                        return bgSelImage.getSource();
348
                }
349
                return null;
350
        }
351

    
352
        
353

    
354
        @Override
355
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
356
                return super.toCartographicSize(viewPort, dpi, geom);
357
                // this symbol cannot apply any cartographic transfomation to its filling
358
        }
359

    
360
        public void draw(Graphics2D g, AffineTransform affineTransform,
361
                        Geometry geom, Feature f, Cancellable cancel) {
362
                draw(g, affineTransform, geom, cancel);
363
                
364
        }
365
        
366
    public Object clone() throws CloneNotSupportedException {
367
            PictureFillSymbol copy = (PictureFillSymbol) super.clone();
368

    
369
        // clone selection
370
            if (selectionSym != null) {
371
                    //Parche por lo que hace el m?todo getSymbolForSelection
372
                    if (this == selectionSym){
373
                            copy.selectionSym = copy;
374
                    } else {
375
                            copy.selectionSym = (PictureFillSymbol) selectionSym.clone();
376
                    }
377
            }
378

    
379
        // clone brackground image
380
        if (bgImage != null) {
381
            copy.bgImage = (BackgroundFileStyle) bgImage.clone();
382
        }
383

    
384
        // clone selection brackground image
385
        if (bgSelImage != null) {
386
            copy.bgSelImage = (BackgroundFileStyle) bgSelImage.clone();
387
        }
388

    
389
        // FIXME: clone properties
390
        
391
        return copy;
392
    }
393

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

    
398
        this.selected = (Boolean) state.get(SELECTED);
399
        this.selectionSym = (PictureFillSymbol) state.get(SELECTION_SYMBOL);
400
        this.bgImage = (BackgroundFileStyle) state.get(BACKGROUND_IMAGE);
401
        this.bgSelImage =
402
            (BackgroundFileStyle) state.get(BACKGROUND_SELECTION_IMAGE);
403

    
404
    
405
        this.angle = (Double) state.get(ANGLE);
406
        this.xScale = (Double) state.get(X_SCALE);
407
        this.yScale = (Double) state.get(Y_SCALE);
408
        this.markerFillProperties = (IMarkerFillPropertiesStyle) state.get(MARKER_FILL_PROPERTIES);
409

    
410
    
411
    }
412

    
413
    public void saveToState(PersistentState state) throws PersistenceException {
414
        // Save parent fill symbol properties
415
        super.saveToState(state);
416

    
417
        // Save own properties
418
        state.set(SELECTED, this.selected);
419
        state.set(SELECTION_SYMBOL, this.getSymbolForSelection());
420
        state.set(BACKGROUND_IMAGE, this.bgImage);
421
        state.set(BACKGROUND_SELECTION_IMAGE, this.bgSelImage);
422
        state.set(ANGLE, this.angle);
423
        state.set(X_SCALE, this.xScale);
424
        state.set(Y_SCALE, this.yScale);
425
        state.set(MARKER_FILL_PROPERTIES, this.markerFillProperties);
426
    }
427

    
428
    public static class RegisterPersistence implements Callable {
429

    
430
        public Object call() throws Exception {
431
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
432
            if (manager.getDefinition(PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) {
433
                DynStruct definition =
434
                    manager.addDefinition(PictureFillSymbol.class,
435
                                    PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
436
                                    PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME
437
                            + " Persistence definition",
438
                        null,
439
                        null);
440

    
441
                // Extend the Style base definition
442
                definition.extend(manager.getDefinition(FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME));
443

    
444
                definition.addDynFieldBoolean(SELECTED).setMandatory(false);
445
                definition.addDynFieldObject(SELECTION_SYMBOL)
446
                    .setClassOfValue(PictureFillSymbol.class).setMandatory(false);
447
                definition.addDynFieldObject(BACKGROUND_IMAGE)
448
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
449
                definition.addDynFieldObject(BACKGROUND_SELECTION_IMAGE)
450
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
451
                definition.addDynFieldDouble(ANGLE).setMandatory(true);
452
                definition.addDynFieldDouble(X_SCALE).setMandatory(true);
453
                definition.addDynFieldDouble(Y_SCALE).setMandatory(true);
454
                definition.addDynFieldObject(MARKER_FILL_PROPERTIES)
455
                .setClassOfValue(IMarkerFillPropertiesStyle.class).setMandatory(true);
456
            }
457
            return Boolean.TRUE;
458
        }
459
    }
460

    
461
        public static class RegisterSymbol implements Callable {
462

    
463
                public Object call() throws Exception {
464
                SymbolManager manager = MapContextLocator.getSymbolManager();
465
                
466
                manager.registerSymbol(PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
467
                    PictureFillSymbol.class);
468

    
469
                        return Boolean.TRUE;
470
                }
471
                
472
        }
473

    
474
        public IBackgroundFileStyle getBackgroundFileStyle() {
475
                return this.bgImage;
476
        }
477

    
478
        public IBackgroundFileStyle getSelectedBackgroundFileStyle() {
479
                return this.bgSelImage;
480
        }
481

    
482
}