Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2057 / libraries / 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 @ 39193

History | View | Annotate | Download (15.7 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2004 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
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.impl;
42

    
43
import java.awt.Color;
44
import java.awt.Dimension;
45
import java.awt.Graphics2D;
46
import java.awt.Paint;
47
import java.awt.Rectangle;
48
import java.awt.RenderingHints;
49
import java.awt.Shape;
50
import java.awt.TexturePaint;
51
import java.awt.geom.AffineTransform;
52
import java.awt.image.BufferedImage;
53
import java.io.IOException;
54
import java.net.URL;
55

    
56
import org.gvsig.compat.print.PrintAttributes;
57
import org.gvsig.fmap.dal.feature.Feature;
58
import org.gvsig.fmap.geom.Geometry;
59
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
60
import org.gvsig.fmap.geom.Geometry.TYPES;
61
import org.gvsig.fmap.geom.GeometryLocator;
62
import org.gvsig.fmap.geom.GeometryManager;
63
import org.gvsig.fmap.geom.exception.CreateGeometryException;
64
import org.gvsig.fmap.geom.primitive.GeneralPathX;
65
import org.gvsig.fmap.geom.primitive.Surface;
66
import org.gvsig.fmap.mapcontext.MapContextLocator;
67
import org.gvsig.fmap.mapcontext.ViewPort;
68
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
69
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
70
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
71
import org.gvsig.i18n.Messages;
72
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IPictureFillSymbol;
73
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.BackgroundFileStyle;
74
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.IMarkerFillPropertiesStyle;
75
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.SimpleMarkerFillPropertiesStyle;
76
import org.gvsig.tools.ToolsLocator;
77
import org.gvsig.tools.dynobject.DynStruct;
78
import org.gvsig.tools.persistence.PersistenceManager;
79
import org.gvsig.tools.persistence.PersistentState;
80
import org.gvsig.tools.persistence.exception.PersistenceException;
81
import org.gvsig.tools.task.Cancellable;
82
import org.gvsig.tools.util.Callable;
83
import org.slf4j.Logger;
84
import org.slf4j.LoggerFactory;
85

    
86
/**
87
 * PictureFillSymbol allows to use an image file suported by gvSIG as a padding
88
 * for the polygons.This image can be modified using methods to scale or rotate it.
89
 * @author jaume dominguez faus - jaume.dominguez@iver.es
90
 */
91
public class PictureFillSymbol extends AbstractFillSymbol implements IPictureFillSymbol {
92
        private static final Logger logger = LoggerFactory.getLogger(PictureFillSymbol.class);
93

    
94
    public static final String PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME =
95
        "PictureFillSymbol";
96
    private static final String SELECTED = "selected";
97
    private static final String SELECTION_SYMBOL = "selectionSym";
98
    private static final String BACKGROUND_IMAGE = "bgImage";
99
    private static final String BACKGROUND_SELECTION_IMAGE = "bgSelImage";
100
    private static final String ANGLE = "angle";
101
    private static final String X_SCALE = "xScale";
102
    private static final String Y_SCALE = "yScale";
103
    private static final String MARKER_FILL_PROPERTIES = "markerFillProperties";
104

    
105
        private double angle = 0;
106
        private double xScale = 1;
107
        private double yScale = 1;
108
        transient private PictureFillSymbol selectionSym;
109
        private boolean selected;
110
        private IMarkerFillPropertiesStyle markerFillProperties = new SimpleMarkerFillPropertiesStyle();
111
        private BackgroundFileStyle bgImage;
112
        private BackgroundFileStyle bgSelImage;
113
        private PrintAttributes properties;
114
        private GeometryManager geometryManager = GeometryLocator.getGeometryManager();
115

    
116
        private void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Cancellable cancel) {
117
                 Color fillColor = getFillColor();
118
                 
119
                 Shape transf_geom = geom.getShape(affineTransform);
120
                 
121
                if (fillColor != null) {
122
                        g.setColor(fillColor);
123
                        g.fill(transf_geom);
124
                }
125

    
126
                g.setClip(transf_geom);
127
                BackgroundFileStyle bg = (!selected) ? bgImage : bgSelImage ;
128
                if (bg != null && bg.getBounds() != null){
129
                        int sizeW=(int) ((int)bg.getBounds().getWidth() * xScale);
130
                        int sizeH=(int) ((int)bg.getBounds().getHeight() * yScale);
131
                        Rectangle rProv = new Rectangle();
132
                        rProv.setFrame(0,0,sizeW,sizeH);
133
                        Paint resulPatternFill = null;
134
                        BufferedImage sample= null;
135

    
136
                        sample= new BufferedImage(sizeW,sizeH,BufferedImage.TYPE_INT_ARGB);
137
                        Graphics2D gAux = sample.createGraphics();
138

    
139
                        double xSeparation = markerFillProperties.getXSeparation(); // TODO apply CartographicSupport
140
                        double ySeparation = markerFillProperties.getYSeparation(); // TODO apply CartographicSupport
141
                        double xOffset = markerFillProperties.getXOffset();
142
                        double yOffset = markerFillProperties.getYOffset();
143

    
144
                        try {
145
                                bg.drawInsideRectangle(gAux, rProv);
146
                        } catch (SymbolDrawingException e) {
147
                                logger.warn(Messages.getText("label_style_could_not_be_painted"), e);
148
                        }
149

    
150
                        Dimension sz = rProv.getSize();
151
                        sz = new Dimension((int) Math.round(sz.getWidth()+(xSeparation)),
152
                                        (int) Math.round(sz.getHeight() + (ySeparation)));
153
                        rProv.setSize(sz);
154

    
155
                        BufferedImage bi = new BufferedImage(rProv.width, rProv.height, BufferedImage.TYPE_INT_ARGB);
156
                        gAux = bi.createGraphics();
157
                        gAux.drawImage(sample, null, (int) (xSeparation*0.5), (int) (ySeparation*0.5));
158

    
159
                        rProv.x = rProv.x+(int)xOffset;
160
                        rProv.y = rProv.y+(int)yOffset;
161
                        resulPatternFill = new TexturePaint(bi,rProv);
162

    
163
                        g.setColor(null);
164
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
165
                                        RenderingHints.VALUE_ANTIALIAS_ON);
166

    
167
                        g.setPaint(resulPatternFill);
168
                }
169
                
170
                if (angle == 0) {
171
                    g.fill(transf_geom);
172
                } else {
173

    
174
            AffineTransform at = new AffineTransform();
175
            at.rotate(angle);
176

    
177
                    Geometry pixels_geom = geom.cloneGeometry();
178
                    pixels_geom.transform(affineTransform);
179
                    pixels_geom.transform(at);
180
                    
181
                    g.rotate(-angle);
182
                    g.fill(pixels_geom.getShape());
183
                    g.rotate(angle);
184
                }
185

    
186
                g.setClip(null);
187
                if (getOutline()!=null) {
188
                        getOutline().draw(g, affineTransform, geom, null, cancel);
189
                }
190
        }
191

    
192
        /**
193
         * Constructor method
194
         *
195
         */
196
        public PictureFillSymbol() {
197
                super();
198
        }
199
        /**
200
         * Constructor method
201
         * @param imageURL, URL of the normal image
202
         * @param selImageURL, URL of the image when it is selected in the map
203
         * @throws IOException
204
         */
205

    
206
        public PictureFillSymbol(URL imageURL, URL selImageURL) throws IOException {
207
                setImage(imageURL);
208
                if (selImageURL!=null)
209
                        setSelImage(selImageURL);
210
                else setSelImage(imageURL);
211
        }
212

    
213

    
214
        /**
215
         * Sets the URL for the image to be used as a picture fill symbol (when it is selected in the map)
216
         * @param imageFile, File
217
         * @throws IOException
218
         */
219
        public void setSelImage(URL selImageUrl) throws IOException{
220

    
221
                bgSelImage= BackgroundFileStyle.createStyleByURL(selImageUrl);
222
//                selImagePath = selImageUrl.toString();
223
        }
224

    
225

    
226

    
227
        /**
228
         * Defines the URL from where the picture to fill the polygon is taken.
229
         * @param imageFile
230
         * @throws IOException
231
         */
232
        public void setImage(URL imageUrl) throws IOException{
233
                bgImage = BackgroundFileStyle.createStyleByURL(imageUrl);
234
        }
235

    
236

    
237

    
238
        public void drawInsideRectangle(Graphics2D g,
239
                        AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
240
                Surface surf;
241
                try {
242
                        surf = geometryManager.createSurface(new GeneralPathX(r.getPathIterator(new AffineTransform())), SUBTYPES.GEOM2D);
243
                        if (properties==null){
244
                                //                        draw(g, null, new FPolygon2D(new GeneralPathX(r)), null);
245
                                draw(g, null, surf, null);
246
                        } else {
247
                                print(g, new AffineTransform(), surf, properties);
248
                        }
249
                } catch (CreateGeometryException e) {
250
                        throw new SymbolDrawingException(TYPES.POINT);
251
                }
252
        }
253

    
254
        public ISymbol getSymbolForSelection() {
255
                if (selectionSym == null) {
256
                        selectionSym = (PictureFillSymbol) cloneForSelection();
257
                        selectionSym.selected=true;
258
                        selectionSym.selectionSym = selectionSym; // avoid too much lazy creations
259
                }
260
                return selectionSym;
261

    
262
        }
263

    
264
        public int getSymbolType() {
265
                return Geometry.TYPES.SURFACE;
266
        }
267

    
268
        public String getClassName() {
269
                return getClass().getName();
270
        }
271

    
272
        public void print(Graphics2D g, AffineTransform at, Geometry geom,
273
                        PrintAttributes properties) {
274
                this.properties=properties;
275
        draw(g, at, geom, null);
276
        this.properties=null;
277
        }
278
        /**
279
         * Returns the IMarkerFillProperties that allows this class to treat the picture as
280
         * a marker in order to scale it, rotate it and so on.
281
         * @return markerFillProperties,IMarkerFillPropertiesStyle
282
         */
283
        public IMarkerFillPropertiesStyle getMarkerFillProperties() {
284
                return markerFillProperties;
285
        }
286

    
287
        /**
288
         * Sets the MarkerFillProperties in order to allow the user to modify the picture as
289
         * a marker (it is possible to scale it, rotate it and so on)
290
         * @param prop
291
         */
292
        public void setMarkerFillProperties(IMarkerFillPropertiesStyle prop) {
293
                this.markerFillProperties = prop;
294
        }
295
        /**
296
         * Defines the angle for the rotation of the image when it is added to create the
297
         * padding
298
         *
299
         * @return angle
300
         */
301
        public double getAngle() {
302
                return angle;
303
        }
304
        /**
305
         * Sets the angle for the rotation of the image when it is added to create the padding
306
         * @param angle
307
         */
308
        public void setAngle(double angle) {
309
                this.angle = angle;
310
        }
311

    
312
        /**
313
         * Defines the scale for the x axis of the image when it is added to create the
314
         * padding
315
         * @return xScale
316
         */
317
        public double getXScale() {
318
                return xScale;
319
        }
320
        /**
321
         * Returns the scale for the x axis of the image when it is added to create the
322
         * padding
323
         * @param xScale
324
         */
325
        public void setXScale(double xScale) {
326
                this.xScale = xScale;
327
        }
328
        /**
329
         * Defines the scale for the y axis of the image when it is added to create the
330
         * padding
331
         * @return yScale
332
         */
333
        public double getYScale() {
334
                return yScale;
335
        }
336
        /**
337
         * Returns the scale for the y axis of the image when it is added to create the
338
         * padding
339
         * @param yScale
340
         */
341
        public void setYScale(double yScale) {
342
                this.yScale = yScale;
343
        }
344

    
345
        /**
346
         * Returns the URL of the image that is used to create the padding to fill the
347
         * polygon
348
         * @return imagePath
349
         */
350
        public URL getSource() {
351
                if (bgImage != null){
352
                        return bgImage.getSource();
353
                }
354
                return null;
355
        }
356

    
357
        /**
358
         * Returns the URL of the image used when the polygon is selected
359
         * @return
360
         */
361
        public URL getSelectedSource(){
362
                if( bgSelImage != null){
363
                        return bgSelImage.getSource();
364
                }
365
                return null;
366
        }
367

    
368
        
369

    
370
        @Override
371
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
372
                return super.toCartographicSize(viewPort, dpi, geom);
373
                // this symbol cannot apply any cartographic transfomation to its filling
374
        }
375

    
376
        public void draw(Graphics2D g, AffineTransform affineTransform,
377
                        Geometry geom, Feature f, Cancellable cancel) {
378
                draw(g, affineTransform, geom, cancel);
379
                
380
        }
381
        
382
    public Object clone() throws CloneNotSupportedException {
383
            PictureFillSymbol copy = (PictureFillSymbol) super.clone();
384

    
385
        // clone selection
386
            if (selectionSym != null) {
387
                    //Parche por lo que hace el m?todo getSymbolForSelection
388
                    if (this == selectionSym){
389
                            copy.selectionSym = copy;
390
                    } else {
391
                            copy.selectionSym = (PictureFillSymbol) selectionSym.clone();
392
                    }
393
            }
394

    
395
        // clone brackground image
396
        if (bgImage != null) {
397
            copy.bgImage = (BackgroundFileStyle) bgImage.clone();
398
        }
399

    
400
        // clone selection brackground image
401
        if (bgSelImage != null) {
402
            copy.bgSelImage = (BackgroundFileStyle) bgSelImage.clone();
403
        }
404

    
405
        // FIXME: clone properties
406
        
407
        return copy;
408
    }
409

    
410
    public void loadFromState(PersistentState state) throws PersistenceException {
411
        // Set parent style properties
412
        super.loadFromState(state);
413

    
414
        this.selected = (Boolean) state.get(SELECTED);
415
        this.selectionSym = (PictureFillSymbol) state.get(SELECTION_SYMBOL);
416
        this.bgImage = (BackgroundFileStyle) state.get(BACKGROUND_IMAGE);
417
        this.bgSelImage =
418
            (BackgroundFileStyle) state.get(BACKGROUND_SELECTION_IMAGE);
419

    
420
    
421
        this.angle = (Double) state.get(ANGLE);
422
        this.xScale = (Double) state.get(X_SCALE);
423
        this.yScale = (Double) state.get(Y_SCALE);
424
        this.markerFillProperties = (IMarkerFillPropertiesStyle) state.get(MARKER_FILL_PROPERTIES);
425

    
426
    
427
    }
428

    
429
    public void saveToState(PersistentState state) throws PersistenceException {
430
        // Save parent fill symbol properties
431
        super.saveToState(state);
432

    
433
        // Save own properties
434
        state.set(SELECTED, this.selected);
435
        state.set(SELECTION_SYMBOL, this.getSymbolForSelection());
436
        state.set(BACKGROUND_IMAGE, this.bgImage);
437
        state.set(BACKGROUND_SELECTION_IMAGE, this.bgSelImage);
438
        state.set(ANGLE, this.angle);
439
        state.set(X_SCALE, this.xScale);
440
        state.set(Y_SCALE, this.yScale);
441
        state.set(MARKER_FILL_PROPERTIES, this.markerFillProperties);
442
    }
443

    
444
    public static class RegisterPersistence implements Callable {
445

    
446
        public Object call() throws Exception {
447
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
448
            if (manager.getDefinition(PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) {
449
                DynStruct definition =
450
                    manager.addDefinition(PictureFillSymbol.class,
451
                                    PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
452
                                    PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME
453
                            + " Persistence definition",
454
                        null,
455
                        null);
456

    
457
                // Extend the Style base definition
458
                definition.extend(manager.getDefinition(FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME));
459

    
460
                definition.addDynFieldBoolean(SELECTED).setMandatory(false);
461
                definition.addDynFieldObject(SELECTION_SYMBOL)
462
                    .setClassOfValue(PictureFillSymbol.class).setMandatory(false);
463
                definition.addDynFieldObject(BACKGROUND_IMAGE)
464
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
465
                definition.addDynFieldObject(BACKGROUND_SELECTION_IMAGE)
466
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
467
                definition.addDynFieldDouble(ANGLE).setMandatory(true);
468
                definition.addDynFieldDouble(X_SCALE).setMandatory(true);
469
                definition.addDynFieldDouble(Y_SCALE).setMandatory(true);
470
                definition.addDynFieldObject(MARKER_FILL_PROPERTIES)
471
                .setClassOfValue(IMarkerFillPropertiesStyle.class).setMandatory(true);
472
            }
473
            return Boolean.TRUE;
474
        }
475
    }
476

    
477
        public static class RegisterSymbol implements Callable {
478

    
479
                public Object call() throws Exception {
480
                SymbolManager manager = MapContextLocator.getSymbolManager();
481
                
482
                manager.registerSymbol(PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
483
                    PictureFillSymbol.class);
484

    
485
                        return Boolean.TRUE;
486
                }
487
                
488
        }
489

    
490
}