Statistics
| Revision:

root / branches / v2_0_0_prep / 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 @ 34294

History | View | Annotate | Download (15.6 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.TexturePaint;
50
import java.awt.geom.AffineTransform;
51
import java.awt.image.BufferedImage;
52
import java.io.IOException;
53
import java.net.URL;
54

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

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

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

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

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

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

    
132
                        sample= new BufferedImage(sizeW,sizeH,BufferedImage.TYPE_INT_ARGB);
133
                        Graphics2D gAux = sample.createGraphics();
134

    
135
                        double xSeparation = markerFillProperties.getXSeparation(); // TODO apply CartographicSupport
136
                        double ySeparation = markerFillProperties.getYSeparation(); // TODO apply CartographicSupport
137
                        double xOffset = markerFillProperties.getXOffset();
138
                        double yOffset = markerFillProperties.getYOffset();
139

    
140
                        try {
141
                                bg.drawInsideRectangle(gAux, rProv);
142
                        } catch (SymbolDrawingException e) {
143
                                logger.warn(Messages.getText("label_style_could_not_be_painted"), e);
144
                        }
145

    
146
                        Dimension sz = rProv.getSize();
147
                        sz = new Dimension((int) Math.round(sz.getWidth()+(xSeparation)),
148
                                        (int) Math.round(sz.getHeight() + (ySeparation)));
149
                        rProv.setSize(sz);
150

    
151
                        BufferedImage bi = new BufferedImage(rProv.width, rProv.height, BufferedImage.TYPE_INT_ARGB);
152
                        gAux = bi.createGraphics();
153
                        gAux.drawImage(sample, null, (int) (xSeparation*0.5), (int) (ySeparation*0.5));
154

    
155
                        rProv.x = rProv.x+(int)xOffset;
156
                        rProv.y = rProv.y+(int)yOffset;
157
                        resulPatternFill = new TexturePaint(bi,rProv);
158

    
159
                        g.setColor(null);
160
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
161
                                        RenderingHints.VALUE_ANTIALIAS_ON);
162

    
163
                        g.setPaint(resulPatternFill);
164
                }
165
                g.rotate(-angle);
166
                AffineTransform at = new AffineTransform();
167
                at.rotate(angle);
168
                geom.transform(at);
169
                g.fill(geom);
170
                at.rotate(-angle*2);
171
                geom.transform(at);
172
                g.rotate(angle);
173
                g.setClip(null);
174
                if (getOutline()!=null) {
175
                        getOutline().draw(g, affineTransform, geom, null, cancel);
176
                }
177
        }
178

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

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

    
200

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

    
208
                bgSelImage= BackgroundFileStyle.createStyleByURL(selImageUrl);
209
//                selImagePath = selImageUrl.toString();
210
        }
211

    
212

    
213

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

    
223

    
224

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

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

    
249
        }
250

    
251
        public int getSymbolType() {
252
                return Geometry.TYPES.SURFACE;
253
        }
254

    
255
        public String getClassName() {
256
                return getClass().getName();
257
        }
258

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

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

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

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

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

    
355
        
356

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

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

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

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

    
387
        // clone selection brackground image
388
        if (bgSelImage != null) {
389
            copy.bgSelImage = (BackgroundFileStyle) bgSelImage.clone();
390
        }
391

    
392
        // FIXME: clone properties
393
        
394
        return copy;
395
    }
396

    
397
    public void loadFromState(PersistentState state) throws PersistenceException {
398
        // Set parent style properties
399
        super.loadFromState(state);
400

    
401
        this.selected = (Boolean) state.get(SELECTED);
402
        this.selectionSym = (PictureFillSymbol) state.get(SELECTION_SYMBOL);
403
        this.bgImage = (BackgroundFileStyle) state.get(BACKGROUND_IMAGE);
404
        this.bgSelImage =
405
            (BackgroundFileStyle) state.get(BACKGROUND_SELECTION_IMAGE);
406

    
407
    
408
        this.angle = (Double) state.get(ANGLE);
409
        this.xScale = (Double) state.get(X_SCALE);
410
        this.yScale = (Double) state.get(Y_SCALE);
411
        this.markerFillProperties = (IMarkerFillPropertiesStyle) state.get(MARKER_FILL_PROPERTIES);
412

    
413
    
414
    }
415

    
416
    public void saveToState(PersistentState state) throws PersistenceException {
417
        // Save parent fill symbol properties
418
        super.saveToState(state);
419

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

    
431
    public static class RegisterPersistence implements Callable {
432

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

    
444
                // Extend the Style base definition
445
                definition.extend(manager.getDefinition(FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME));
446

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

    
464
        public static class RegisterSymbol implements Callable {
465

    
466
                public Object call() throws Exception {
467
                int[] shapeTypes;
468
                SymbolManager manager = MapContextLocator.getSymbolManager();
469
                
470
                shapeTypes =
471
                    new int[] { Geometry.TYPES.SURFACE, Geometry.TYPES.CIRCLE,
472
                        Geometry.TYPES.ELLIPSE, Geometry.TYPES.MULTISURFACE };
473
                manager.registerMultiLayerSymbol(PICTURE_FILL_SYMBOL_PERSISTENCE_DEFINITION_NAME,
474
                    shapeTypes,
475
                    PictureFillSymbol.class);
476

    
477
                        return Boolean.TRUE;
478
                }
479
                
480
        }
481

    
482
}