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

History | View | Annotate | Download (15.4 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.i18n.Messages;
55
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IPictureFillSymbol;
56
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.BackgroundFileStyle;
57
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.IMarkerFillPropertiesStyle;
58
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.SimpleMarkerFillPropertiesStyle;
59
import org.gvsig.tools.ToolsLocator;
60
import org.gvsig.tools.dynobject.DynStruct;
61
import org.gvsig.tools.persistence.PersistenceManager;
62
import org.gvsig.tools.persistence.PersistentState;
63
import org.gvsig.tools.persistence.exception.PersistenceException;
64
import org.gvsig.tools.task.Cancellable;
65
import org.gvsig.tools.util.Callable;
66
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
68

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
196

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

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

    
208

    
209

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

    
219

    
220

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

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

    
245
        }
246

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

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

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

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

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

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

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

    
351
        
352

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

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

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

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

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

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

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

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

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

    
409
    
410
    }
411

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

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

    
427
    public static class RegisterPersistence implements Callable {
428

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

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

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

    
460
        public static class RegisterSymbol implements Callable {
461

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

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

    
473
}