Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2058 / libraries / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / line / impl / PictureLineSymbol.java @ 39268

History | View | Annotate | Download (13.6 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 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.line.impl;
42

    
43
import java.awt.BasicStroke;
44
import java.awt.Color;
45
import java.awt.Graphics2D;
46
import java.awt.Rectangle;
47
import java.awt.Shape;
48
import java.awt.geom.AffineTransform;
49
import java.awt.geom.PathIterator;
50
import java.awt.geom.Point2D;
51
import java.io.IOException;
52
import java.net.URL;
53

    
54
import org.apache.batik.ext.awt.geom.PathLength;
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.mapcontext.MapContextLocator;
59
import org.gvsig.fmap.mapcontext.ViewPort;
60
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
61
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
62
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
63
import org.gvsig.i18n.Messages;
64
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.impl.CartographicSupportToolkit;
65
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.IPictureLineSymbol;
66
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.BackgroundFileStyle;
67
import org.gvsig.tools.ToolsLocator;
68
import org.gvsig.tools.dynobject.DynStruct;
69
import org.gvsig.tools.persistence.PersistenceManager;
70
import org.gvsig.tools.persistence.PersistentState;
71
import org.gvsig.tools.persistence.exception.PersistenceException;
72
import org.gvsig.tools.task.Cancellable;
73
import org.gvsig.tools.util.Callable;
74
import org.slf4j.Logger;
75
import org.slf4j.LoggerFactory;
76

    
77

    
78
/**
79
 * PictureLineSymbol allows to use any symbol defined as an image (by an image file)
80
 * supported  by gvSIG.This symbol will be used as an initial object.The line will be
81
 * painted as a succession of puntual symbols through the path defined by it(the line).
82
 *
83
 * @author jaume dominguez faus - jaume.dominguez@iver.es
84
 */
85
public class PictureLineSymbol extends AbstractLineSymbol implements IPictureLineSymbol  {
86

    
87
        private static final Logger logger = LoggerFactory.getLogger(PictureLineSymbol.class);
88

    
89
    public static final String PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME =
90
        "PictureLineSymbol";
91
    private static final String SELECTED = "selected";
92
    private static final String SELECTION_SYMBOL = "selectionSym";
93
    private static final String BACKGROUND_IMAGE = "bgImage";
94
    private static final String BACKGROUND_SELECTION_IMAGE = "bgSelImage";
95
    private static final String WIDTH = "width";
96

    
97
        transient private PictureLineSymbol selectionSym;
98
        private double width;
99
        private boolean selected;
100
        private double xScale = 1, csXScale = xScale;
101
        private double yScale = 1, csYScale = yScale;
102

    
103
        private BackgroundFileStyle bgImage;
104
        private BackgroundFileStyle bgSelImage;
105
        private PrintAttributes properties;
106

    
107
        /**
108
         * Constructor method
109
         *
110
         */
111
        public PictureLineSymbol() {
112
                super();
113
        }
114
        /**
115
         * Constructor method
116
         * @param imageURL, URL of the normal image
117
         * @param selImageURL, URL of the image when it is selected in the map
118
         * @throws IOException
119
         */
120

    
121
        public PictureLineSymbol(URL imageURL, URL selImageURL) throws IOException {
122
                setImage(imageURL);
123
                if (selImageURL!=null)
124
                        setSelImage(selImageURL);
125
                else setSelImage(imageURL);
126
        }
127
        /**
128
         * Sets the URL for the image to be used as a picture line symbol
129
         * @param imageFile, File
130
         * @throws IOException
131
         */
132
        public void setImage(URL imageUrl) throws IOException{
133

    
134
                bgImage= BackgroundFileStyle.createStyleByURL(imageUrl);
135
        }
136
        /**
137
         * Sets the URL for the image to be used as a picture line symbol (when it is selected in the map)
138
         * @param imageFile, File
139
         * @throws IOException
140
         */
141
        public void setSelImage(URL selImageUrl) throws IOException{
142

    
143
                bgSelImage= BackgroundFileStyle.createStyleByURL(selImageUrl);
144
        }
145

    
146

    
147
        public void setLineWidth(double width) {
148
                this.width = width;
149
                getLineStyle().setLineWidth((float) width);
150
        }
151

    
152
        public double getLineWidth() {
153
                return width;
154
        }
155

    
156
        public ISymbol getSymbolForSelection() {
157
                if (selectionSym == null) {
158
                        selectionSym = (PictureLineSymbol) cloneForSelection();
159
                        selectionSym.selected=true;
160
                        selectionSym.selectionSym = selectionSym; // avoid too much lazy creations
161

    
162
                }
163
                return selectionSym;
164

    
165
        }
166

    
167
        public void draw(Graphics2D g, AffineTransform affineTransform,        Geometry geom, Feature f, Cancellable cancel) {
168
                draw(g, affineTransform, geom, cancel);
169
        }
170

    
171
        private void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Cancellable cancel) {
172

    
173
            if (csXScale<=0 && csYScale<=0) {
174
                return;
175
            }
176

    
177
            float csWidth = getLineStyle().getLineWidth();
178
                
179
                BasicStroke bs = new BasicStroke(
180
                    (float) csWidth,
181
                    BasicStroke.CAP_ROUND,
182
                    BasicStroke.CAP_ROUND);
183
                
184
                Shape geom_transf_clip = geom.getShape(affineTransform);
185
                g.setClip(bs.createStrokedShape(geom_transf_clip));
186
                
187
                BackgroundFileStyle bg = (!selected) ? bgImage : bgSelImage ;
188

    
189
                Rectangle bounds = bg.getBounds();
190
                final double imageWidth  = bounds.getWidth()  * csXScale;
191
                final double imageHeight = bounds.getHeight() * csYScale;
192

    
193
                if (imageWidth==0 || imageHeight==0) return;
194
                int height = (int) csWidth;
195

    
196
                PathLength pl = new PathLength(geom_transf_clip);
197
                PathIterator iterator = geom_transf_clip.getPathIterator(null, 0.8);
198
                double[] theData = new double[6];
199
                Point2D firstPoint = null, startPoint = null, endPoint = null;
200
                if (!iterator.isDone()) {
201
                        if ( iterator.currentSegment(theData) != PathIterator.SEG_CLOSE) {
202
                                firstPoint = new Point2D.Double(theData[0], theData[1]);
203
                        }
204
                }
205
                float currentPathLength = 1;
206

    
207
                Rectangle rect = new Rectangle();
208

    
209
                while ((cancel==null || !cancel.isCanceled()) && !iterator.isDone()) {
210

    
211
                        int theType = iterator.currentSegment(theData);
212
                        switch (theType) {
213
                        case PathIterator.SEG_MOVETO:
214
                                startPoint = new Point2D.Double(theData[0], theData[1]);
215

    
216
                                endPoint = null;
217
                                iterator.next();
218

    
219
                                continue;
220

    
221
                        case PathIterator.SEG_LINETO:
222
                        case PathIterator.SEG_QUADTO:
223
                        case PathIterator.SEG_CUBICTO:
224
                                endPoint = new Point2D.Double(theData[0], theData[1]);
225

    
226
                                break;
227
                        case PathIterator.SEG_CLOSE:
228
                                endPoint = startPoint;
229
                                startPoint = firstPoint;
230
                                break;
231
                        }
232

    
233
                        double a = endPoint.getX() - startPoint.getX();
234
                        double b = endPoint.getY() - startPoint.getY();
235
                        double theta = pl.angleAtLength(currentPathLength);
236

    
237
                        double x = startPoint.getX();
238
                        double y = startPoint.getY();
239

    
240
                        // Theorem of Pythagoras
241
                        float segmentLength = (float) Math.sqrt(a*a + b*b);
242

    
243
                        // compute how many times the image has to be drawn
244
                        // to completely cover this segment's length
245
                        int count = (int) Math.ceil(segmentLength/imageWidth);
246

    
247
                        for (int i = 0; (cancel==null || !cancel.isCanceled()) && i < count; i++) {
248
                                g.translate(x, y);
249
                                g.rotate(theta);
250

    
251
                                double xOffsetTranslation = imageWidth*i;
252
                                g.translate(xOffsetTranslation, -csWidth);
253

    
254
                                rect.setBounds(0, (int) Math.round(height*.5), (int) Math.ceil(imageWidth), height);
255
                                try {
256
                                        bg.drawInsideRectangle(g, rect, false);
257
                                } catch (SymbolDrawingException e) {
258
                                        logger.warn(Messages.getText("label_style_could_not_be_painted"), e);
259
                                }
260
                                g.translate(-xOffsetTranslation, csWidth);
261

    
262
                                g.rotate(-theta);
263
                                g.translate(-x, -y);
264
                        }
265

    
266
                        startPoint = endPoint;
267
                        currentPathLength += segmentLength;
268
                        iterator.next();
269
                }
270
                g.setClip(null);
271
        }
272

    
273
        /**
274
         * Sets the yscale for the picture line symbol
275
         * @param yScale
276
         */
277
        public void setYScale(double yScale) {
278
                this.yScale = yScale;
279
                this.csYScale = yScale;
280
        }
281
        /**
282
         * Sets the xscale for the picture line symbol
283
         * @param xScale
284
         */
285
        public void setXScale(double xScale) {
286
                this.xScale = xScale;
287
                this.csXScale = xScale;
288
        }
289

    
290
        public String getClassName() {
291
                return getClass().getName();
292
        }
293

    
294
        public void print(Graphics2D g, AffineTransform at, Geometry geom,
295
                        PrintAttributes properties) {
296
                this.properties=properties;
297
        draw(g, at, geom, null);
298
        this.properties=null;
299

    
300
        }
301
        
302
        /**
303
         * Returns the URL of the image that is used as a picture line symbol (when it
304
         * is selected in the map)
305
         * @return selimagePath,URL
306
         */
307
        public URL getSelectedSource(){
308
                return bgSelImage.getSource();
309
        }
310
        /**
311
         * Returns the URL of the image that is used as a picture line symbol
312
         * @return imagePath,URL
313
         */
314
        public URL getSource() {
315
                return bgImage.getSource();
316
        }
317
        
318
        /**
319
         * Returns the xscale for the picture line symbol
320
         * @param xScale
321
         */
322
        public double getXScale() {
323
                return xScale;
324
        }
325
        /**
326
         * Returns the yscale for the picture line symbol
327
         * @param yScale
328
         */
329
        public double getYScale() {
330
                return yScale;
331
        }
332

    
333
        @Override
334
        public void setCartographicSize(double cartographicSize, Geometry geom) {
335
                getLineStyle().setLineWidth((float) cartographicSize);
336
                double scale = cartographicSize/width;
337
                csXScale = xScale * scale;
338
                csYScale = yScale * scale;
339
        }
340

    
341
        @Override
342
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
343
                double s = super.toCartographicSize(viewPort, dpi, geom);
344
                setCartographicSize(CartographicSupportToolkit.
345
                                getCartographicLength(this, width, viewPort, dpi), geom);
346
                return s;
347
        }
348
        
349
        
350
    public Object clone() throws CloneNotSupportedException {
351
        PictureLineSymbol copy = (PictureLineSymbol) super.clone();
352

    
353
        // clone selection
354
        if (selectionSym != null) {
355
                //to avoid an infinite loop
356
                if (this == selectionSym){
357
                        copy.selectionSym = copy;
358
                } else {
359
                        copy.selectionSym = (PictureLineSymbol) selectionSym.clone();
360
                }
361
        }
362

    
363
        // clone brackground image
364
        if (bgImage != null) {
365
            copy.bgImage = (BackgroundFileStyle) bgImage.clone();
366
        }
367

    
368
        // clone selection brackground image
369
        if (bgSelImage != null) {
370
            copy.bgSelImage = (BackgroundFileStyle) bgSelImage.clone();
371
        }
372

    
373
        // FIXME: clone properties
374
        
375
        return copy;
376
    }
377

    
378
    public void loadFromState(PersistentState state) throws PersistenceException {
379
        // Set parent style properties
380
        super.loadFromState(state);
381

    
382
        this.selected = (Boolean) state.get(SELECTED);
383
        this.selectionSym = (PictureLineSymbol) state.get(SELECTION_SYMBOL);
384
        this.bgImage = (BackgroundFileStyle) state.get(BACKGROUND_IMAGE);
385
        this.bgSelImage =
386
            (BackgroundFileStyle) state.get(BACKGROUND_SELECTION_IMAGE);
387
        this.setLineWidth(state.getDouble(WIDTH));
388
    }
389

    
390
    public void saveToState(PersistentState state) throws PersistenceException {
391
        // Save parent fill symbol properties
392
        super.saveToState(state);
393

    
394
        // Save own properties
395
        state.set(SELECTED, this.selected);
396
        state.set(SELECTION_SYMBOL, this.getSymbolForSelection());
397
        state.set(BACKGROUND_IMAGE, this.bgImage);
398
        state.set(BACKGROUND_SELECTION_IMAGE, this.bgSelImage);
399
        state.set(WIDTH, width);
400
    }
401

    
402
    public static class RegisterPersistence implements Callable {
403

    
404
        public Object call() throws Exception {
405
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
406
            if (manager.getDefinition(PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) {
407
                DynStruct definition =
408
                    manager.addDefinition(PictureLineSymbol.class,
409
                                    PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
410
                                    PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME
411
                            + " Persistence definition",
412
                        null,
413
                        null);
414

    
415
                // Extend the Style base definition
416
                definition.extend(manager.getDefinition(LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME));
417

    
418
                definition.addDynFieldBoolean(SELECTED).setMandatory(false);
419
                definition.addDynFieldObject(SELECTION_SYMBOL)
420
                    .setClassOfValue(PictureLineSymbol.class).setMandatory(false);
421
                definition.addDynFieldObject(BACKGROUND_IMAGE)
422
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
423
                definition.addDynFieldObject(BACKGROUND_SELECTION_IMAGE)
424
                    .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
425
                
426
                definition.addDynFieldObject(WIDTH)
427
                    .setClassOfValue(Double.class).setMandatory(true);
428
            }
429
            return Boolean.TRUE;
430
        }
431
    }
432
    
433
        public static class RegisterSymbol implements Callable {
434

    
435
                public Object call() throws Exception {
436
                        SymbolManager manager = MapContextLocator.getSymbolManager();
437

    
438
                        manager.registerSymbol(PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME,
439
                            PictureLineSymbol.class);
440

    
441
                        return Boolean.TRUE;
442
                }
443
        }
444
}