Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2031 / libraries / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / style / ArrowDecoratorStyle.java @ 36104

History | View | Annotate | Download (12.7 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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 2
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
 */
22
package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style;
23

    
24
import java.awt.Graphics2D;
25
import java.awt.Rectangle;
26
import java.awt.geom.AffineTransform;
27
import java.awt.geom.Point2D;
28

    
29
import org.apache.batik.ext.awt.geom.PathLength;
30
import org.gvsig.fmap.dal.feature.Feature;
31
import org.gvsig.fmap.geom.Geometry;
32
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
33
import org.gvsig.fmap.geom.GeometryLocator;
34
import org.gvsig.fmap.geom.GeometryManager;
35
import org.gvsig.fmap.geom.exception.CreateGeometryException;
36
import org.gvsig.fmap.geom.primitive.Point;
37
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
38
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.ILineSymbol;
39
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IArrowMarkerSymbol;
40
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
41
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.impl.ArrowMarkerSymbol;
42
import org.gvsig.tools.ToolsLocator;
43
import org.gvsig.tools.dynobject.DynStruct;
44
import org.gvsig.tools.persistence.PersistenceManager;
45
import org.gvsig.tools.persistence.PersistentState;
46
import org.gvsig.tools.persistence.exception.PersistenceException;
47
import org.gvsig.tools.util.Callable;
48

    
49
/**
50
 * Class ArrowDecoratorStyle. It is used to store the information about the
51
 * different options to draw an arrow in a line (and draw it too). This
52
 * information is taken from the panel.
53
 *
54
 * @author 2005-2008 jaume dominguez faus - jaume.dominguez@iver.es
55
 * @author 2009- <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
56
 */
57
public class ArrowDecoratorStyle extends AbstractStyle implements IArrowDecoratorStyle  {
58
        public static final String ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME = "ArrowDecoratorStyle";
59

    
60
        private static final String FIELD_FLIP_ALL = "flipAll";
61
        private static final String FIELD_FLIP_FIRST = "flipFirst";
62
        private static final String FIELD_ARROW_MARKER_COUNT = "arrowMarkerCount";
63
        private static final String FIELD_FOLLOW_LINE_ANGLE = "followLineAngle";
64
        private static final String FIELD_MARKER = "marker";
65

    
66
        private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
67
        private boolean flipAll = false;
68
        private boolean flipFirst = false;
69
        private int arrowMarkerCount = 2;
70
        private boolean followLineAngle = true;
71
        private IMarkerSymbol marker = getDefaultMarker();
72

    
73
        public ArrowDecoratorStyle() {
74
                marker.setSize(10);
75
                ((IArrowMarkerSymbol) marker).setSharpness(30);
76
        }
77

    
78
        private IMarkerSymbol getDefaultMarker() {
79
                return new ArrowMarkerSymbol();
80
        }
81
        
82
        /**
83
         * Obtains the number of arrows that the user wants to draw in the same line.
84
         * @return
85
         */
86
        public int getArrowMarkerCount() {
87
                return arrowMarkerCount;
88
        }
89

    
90
        /**
91
         * Defines the number of arrows that the user wants to draw in the same line.
92
         * @return
93
         */
94
        public void setArrowMarkerCount(int arrowMarkerCount) {
95
                this.arrowMarkerCount = arrowMarkerCount;
96
        }
97

    
98
        /**
99
         * Defines the flipAll attribute.If the value of this attribute is true all the
100
         * arrows that we had drawn in the same line will be flipped.
101
         * @return
102
         */
103
        public boolean isFlipAll() {
104
                return flipAll;
105
        }
106

    
107
        /**
108
         * Obtains the flipAll attribute.If the value of this attribute is true all the
109
         * arrows that we had drawn in the same line will be flipped.
110
         * @return
111
         */
112
        public void setFlipAll(boolean flipAll) {
113
                this.flipAll = flipAll;
114
        }
115

    
116
        /**
117
         * Obtains the flipFirst attribute.If it is true only the first arrow of the line
118
         * will be flipped.The rest will keep the same orientation.
119
         * @return
120
         */
121
        public boolean isFlipFirst() {
122
                return flipFirst;
123
        }
124

    
125
        /**
126
         * Sets the flipFirst attribute.If it is true only the first arrow of the line
127
         * will be flipped.The rest will keep the same orientation.
128
         * @return
129
         */
130
        public void setFlipFirst(boolean flipFirst) {
131
                this.flipFirst = flipFirst;
132
        }
133

    
134
        /**
135
         * Gets the followLineAngle attribute.This attribute allows the arrow that we are
136
         * going to draw to be more or less aligned with the line where it will be included (depending on the angle) .
137
         * @return
138
         */
139
        public boolean isFollowLineAngle() {
140
                return followLineAngle;
141
        }
142

    
143
        /**
144
         * Sets the followLineAngle attribute.This attribute allows the arrow that we are
145
         * going to draw to be more or less aligned with the line where it will be included.
146
         * (depending on the angle).
147
         * @param followingLineAngle
148
         * @return
149
         */
150
        public void setFollowLineAngle(boolean followLineAngle) {
151
                this.followLineAngle = followLineAngle;
152
        }
153
        /**
154
         * Draws an arrow(or other symbol that substitutes an arrow selected by the user)
155
         * in a line.When the line is drawn, the symbol is added and takes care of the different
156
         * options of the user(for example if he wants to flip the first symbol or all and
157
         * the number of symbols per line to be drawn)
158
         * @param g
159
         * @param affineTransform
160
         * @param feature 
161
         * @param shp
162
         * @throws CreateGeometryException 
163
         */
164
        public void draw(Graphics2D g, AffineTransform affineTransform,
165
                        Geometry geom, Feature feature) throws CreateGeometryException {
166
                if (arrowMarkerCount <= 0) return;
167

    
168
                Geometry geomToDraw = geom.cloneGeometry();
169
                geomToDraw.transform(affineTransform);
170
                PathLength pl = new PathLength(geomToDraw.getShape());
171
                float size = (float) marker.getSize();
172
                marker.setRotation(0.0);
173
                float myLineLength = pl.lengthOfPath();
174
                if (size > myLineLength){
175
                        return;
176
                }
177
                float step = arrowMarkerCount>2 ? myLineLength/(arrowMarkerCount-1) : pl.lengthOfPath();
178
                float rotation1 = 0; // rotation at the arrow's vertex
179
                float rotation2 = 0; // rotation at the arrow's back;
180

    
181
                Point startP = null;
182

    
183
                // the first arrow at the end of the line
184
                float theLength = pl.lengthOfPath();
185
                {
186

    
187
                        if ((flipFirst || flipAll) && (flipFirst != flipAll) && followLineAngle) { // logical XOR
188
                                Point2D p = pl.pointAtLength(theLength-size);
189
                                if (p!=null){
190
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
191
                                        if(followLineAngle){
192
                                                rotation1 = pl.angleAtLength(theLength-size);
193
                                                rotation2 = pl.angleAtLength(theLength);
194
                                                marker.setRotation(rotation1);
195
                                        }
196
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
197
                                }
198
                        } else {
199
                                Point2D p = pl.pointAtLength(theLength);
200
                                if (p!=null){
201
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
202
                                        if(followLineAngle){
203
                                                rotation1 = pl.angleAtLength(theLength-size)+(float) Math.PI;
204
                                                rotation2 = pl.angleAtLength(theLength)+(float) Math.PI;
205
                                                marker.setRotation(rotation2);
206
                                        }
207
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
208
                                }
209
                        }
210
                }
211
                // the other arrows but the first and the last
212
                float aLength;
213
                for (int i = 1; i < arrowMarkerCount-1; i++) {
214
                        aLength = (float) (step*i);
215

    
216
                        if (flipAll && followLineAngle) {
217
                                Point2D p = pl.pointAtLength(aLength);
218
                                if (p==null){
219
                                        p = pl.pointAtLength(theLength);
220
                                }
221
                                startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
222
                                if(followLineAngle){
223
                                        rotation1 = (float) pl.angleAtLength(aLength);
224
                                        rotation2 = (float) pl.angleAtLength((float)(aLength+size));
225
                                        marker.setRotation(rotation1);
226
                                }
227
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
228
                        } else {
229
                                Point2D p = pl.pointAtLength(aLength+size);
230
                                if (p==null){
231
                                        p = pl.pointAtLength(theLength);
232
                                }
233

    
234
                                startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
235
                                if(followLineAngle){
236
                                        rotation1 = (float) (pl.angleAtLength(aLength) + Math.PI);
237
                                        rotation2 = (float) (pl.angleAtLength((float)(aLength+size)) + Math.PI);
238
                                        marker.setRotation(rotation2);
239
                                }
240
                                marker.draw(g, new AffineTransform(), startP, feature, null);
241
                        }
242
                }
243

    
244
                startP = null;
245
                // and the last arrow at the begining of the line
246
                if (arrowMarkerCount>1) {
247
                        if (flipAll) {
248
                                Point2D p = null;
249
                                p = pl.pointAtLength(0);
250
                                if (p!=null){
251
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
252
                                        if(followLineAngle){
253
                                                rotation1 = (float) pl.angleAtLength(size);
254
                                                rotation2 = (float) pl.angleAtLength(0);
255
                                                marker.setRotation(rotation2);
256
                                        }
257
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
258
                                }                                
259
                        } else {
260
                                Point2D p = null;
261
                                if(followLineAngle){
262
                                        p = pl.pointAtLength(size);
263
                                } else {
264
                                        p = pl.pointAtLength(0);
265
                                }
266
                                if (p!=null){
267
                                        startP = geomManager.createPoint(p.getX(), p.getY(), SUBTYPES.GEOM2D);
268
                                        if(followLineAngle){
269
                                                rotation1 = (float) (pl.angleAtLength(size) + Math.PI);
270
                                                rotation2 = (float) (pl.angleAtLength(0) + Math.PI);
271
                                                marker.setRotation(rotation1);
272
                                        }
273
                                        marker.draw(g, new AffineTransform(), startP, feature, null);
274
                                }
275
                        }
276
                }
277
        }
278

    
279
        public void drawInsideRectangle(Graphics2D g, Rectangle r) {
280
                // TODO Auto-generated method stub
281
                throw new Error("Not yet implemented!");
282
        }
283

    
284
        public void drawOutline(Graphics2D g, Rectangle r) {
285
                // TODO Auto-generated method stub
286
                throw new Error("Not yet implemented!");
287
        }
288

    
289
        public boolean isSuitableFor(ISymbol symbol) {
290
                return symbol instanceof ILineSymbol;
291
        }
292

    
293
        public String getClassName() {
294
                return getClass().getName();
295
        }
296

    
297
        public IMarkerSymbol getMarker() {
298
                if(marker == null){
299
                        marker = getDefaultMarker();
300
                }
301
                return marker;
302
        }
303

    
304
        public void setMarker(IMarkerSymbol marker) {
305
                this.marker = marker;
306
        }
307
        
308
        public Object clone() throws CloneNotSupportedException {
309
                ArrowDecoratorStyle copy  = (ArrowDecoratorStyle) super.clone();
310
                if (marker != null) {
311
                        copy.marker = (IMarkerSymbol) marker.clone();
312
                }
313
                return copy;
314
        }
315

    
316
        public void loadFromState(PersistentState state)
317
                        throws PersistenceException {
318
                // Set parent style properties
319
                super.loadFromState(state);
320

    
321
                // Set own properties
322
                setArrowMarkerCount(state.getInt(FIELD_ARROW_MARKER_COUNT));
323
                setFlipAll(state.getBoolean(FIELD_FLIP_ALL));
324
                setFlipFirst(state.getBoolean(FIELD_FLIP_FIRST));
325
                setFollowLineAngle(state.getBoolean(FIELD_FOLLOW_LINE_ANGLE));
326
                setMarker((IMarkerSymbol) state.get(FIELD_MARKER));
327
        }
328

    
329
        public void saveToState(PersistentState state) throws PersistenceException {
330
                // Save parent fill symbol properties
331
                super.saveToState(state);
332

    
333
                // Save own properties
334
                state.set(FIELD_ARROW_MARKER_COUNT, getArrowMarkerCount());
335
                state.set(FIELD_FLIP_ALL, isFlipAll());
336
                state.set(FIELD_FLIP_FIRST, isFlipFirst());
337
                state.set(FIELD_FOLLOW_LINE_ANGLE, isFollowLineAngle());
338
                state.set(FIELD_MARKER, getMarker());
339
        }
340
        
341
        public static class RegisterPersistence implements Callable {
342

    
343
                public Object call() throws Exception {
344
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
345
                        if( manager.getDefinition(ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME)==null ) {
346
                                DynStruct definition = manager.addDefinition(
347
                                                ArrowDecoratorStyle.class,
348
                                                ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME,
349
                                                ARROR_DECORATOR_STYLE_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
350
                                                null, 
351
                                                null
352
                                );
353
                                
354
                                // Extend the Style base definition
355
                                definition.extend(manager.getDefinition(STYLE_PERSISTENCE_DEFINITION_NAME));
356

    
357
                                // Arrow marker count
358
                                definition.addDynFieldInt(FIELD_ARROW_MARKER_COUNT).setMandatory(true);
359
                                // Flip all
360
                                definition.addDynFieldBoolean(FIELD_FLIP_ALL).setMandatory(true);
361
                                // flip first
362
                                definition.addDynFieldBoolean(FIELD_FLIP_FIRST).setMandatory(true);
363
                                // Follow line angles
364
                                definition.addDynFieldBoolean(FIELD_FOLLOW_LINE_ANGLE).setMandatory(true);
365
                                // Marker
366
                                definition.addDynFieldObject(FIELD_MARKER)
367
                                        .setClassOfValue(IMarkerSymbol.class)
368
                                        .setMandatory(true);
369

    
370
                        }
371
                        return Boolean.TRUE;
372
                }
373
                
374
        }
375

    
376
}