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 / line / impl / PictureLineSymbol.java @ 43510
History | View | Annotate | Download (13.4 KB)
1 | 40560 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40560 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | 40435 | jjdelcerro | *
|
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 | 40560 | jjdelcerro | * as published by the Free Software Foundation; either version 3
|
9 | 40435 | jjdelcerro | * 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 | 40560 | jjdelcerro | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
19 | * MA 02110-1301, USA.
|
||
20 | 40435 | jjdelcerro | *
|
21 | 40560 | jjdelcerro | * For any additional information, do not hesitate to contact us
|
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | 40435 | jjdelcerro | */
|
24 | package org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.impl; |
||
25 | |||
26 | import java.awt.BasicStroke; |
||
27 | import java.awt.Graphics2D; |
||
28 | import java.awt.Rectangle; |
||
29 | import java.awt.Shape; |
||
30 | import java.awt.geom.AffineTransform; |
||
31 | import java.awt.geom.PathIterator; |
||
32 | import java.awt.geom.Point2D; |
||
33 | import java.io.IOException; |
||
34 | import java.net.URL; |
||
35 | |||
36 | 43156 | jjdelcerro | import org.apache.batik.ext.awt.geom.DefaultPathLength; |
37 | 40435 | jjdelcerro | import org.gvsig.compat.print.PrintAttributes; |
38 | import org.gvsig.fmap.dal.feature.Feature; |
||
39 | import org.gvsig.fmap.geom.Geometry; |
||
40 | 42439 | dmartinezizquierdo | import org.gvsig.fmap.mapcontext.MapContext; |
41 | 40435 | jjdelcerro | import org.gvsig.fmap.mapcontext.MapContextLocator; |
42 | import org.gvsig.fmap.mapcontext.ViewPort; |
||
43 | import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol; |
||
44 | import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException; |
||
45 | import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager; |
||
46 | import org.gvsig.i18n.Messages; |
||
47 | 43156 | jjdelcerro | import org.gvsig.symbology.PathLength; |
48 | 40435 | jjdelcerro | import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.impl.CartographicSupportToolkit; |
49 | import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.line.IPictureLineSymbol; |
||
50 | import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.style.BackgroundFileStyle; |
||
51 | import org.gvsig.tools.ToolsLocator; |
||
52 | import org.gvsig.tools.dynobject.DynStruct; |
||
53 | import org.gvsig.tools.persistence.PersistenceManager; |
||
54 | import org.gvsig.tools.persistence.PersistentState; |
||
55 | import org.gvsig.tools.persistence.exception.PersistenceException; |
||
56 | import org.gvsig.tools.task.Cancellable; |
||
57 | import org.gvsig.tools.util.Callable; |
||
58 | import org.slf4j.Logger; |
||
59 | import org.slf4j.LoggerFactory; |
||
60 | |||
61 | |||
62 | /**
|
||
63 | * PictureLineSymbol allows to use any symbol defined as an image (by an image file)
|
||
64 | * supported by gvSIG.This symbol will be used as an initial object.The line will be
|
||
65 | * painted as a succession of puntual symbols through the path defined by it(the line).
|
||
66 | */
|
||
67 | public class PictureLineSymbol extends AbstractLineSymbol implements IPictureLineSymbol { |
||
68 | |||
69 | private static final Logger logger = LoggerFactory.getLogger(PictureLineSymbol.class); |
||
70 | |||
71 | public static final String PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME = |
||
72 | "PictureLineSymbol";
|
||
73 | private static final String SELECTED = "selected"; |
||
74 | private static final String SELECTION_SYMBOL = "selectionSym"; |
||
75 | private static final String BACKGROUND_IMAGE = "bgImage"; |
||
76 | private static final String BACKGROUND_SELECTION_IMAGE = "bgSelImage"; |
||
77 | private static final String WIDTH = "width"; |
||
78 | |||
79 | transient private PictureLineSymbol selectionSym; |
||
80 | private double width; |
||
81 | private boolean selected; |
||
82 | private double xScale = 1, csXScale = xScale; |
||
83 | private double yScale = 1, csYScale = yScale; |
||
84 | |||
85 | private BackgroundFileStyle bgImage;
|
||
86 | private BackgroundFileStyle bgSelImage;
|
||
87 | private PrintAttributes properties;
|
||
88 | |||
89 | /**
|
||
90 | * Constructor method
|
||
91 | *
|
||
92 | */
|
||
93 | public PictureLineSymbol() {
|
||
94 | super();
|
||
95 | } |
||
96 | /**
|
||
97 | * Constructor method
|
||
98 | * @param imageURL, URL of the normal image
|
||
99 | * @param selImageURL, URL of the image when it is selected in the map
|
||
100 | * @throws IOException
|
||
101 | */
|
||
102 | |||
103 | public PictureLineSymbol(URL imageURL, URL selImageURL) throws IOException { |
||
104 | setImage(imageURL); |
||
105 | if (selImageURL!=null) |
||
106 | setSelImage(selImageURL); |
||
107 | else setSelImage(imageURL);
|
||
108 | } |
||
109 | /**
|
||
110 | * Sets the URL for the image to be used as a picture line symbol
|
||
111 | * @param imageFile, File
|
||
112 | * @throws IOException
|
||
113 | */
|
||
114 | public void setImage(URL imageUrl) throws IOException{ |
||
115 | |||
116 | bgImage= BackgroundFileStyle.createStyleByURL(imageUrl); |
||
117 | } |
||
118 | /**
|
||
119 | * Sets the URL for the image to be used as a picture line symbol (when it is selected in the map)
|
||
120 | * @param imageFile, File
|
||
121 | * @throws IOException
|
||
122 | */
|
||
123 | public void setSelImage(URL selImageUrl) throws IOException{ |
||
124 | |||
125 | bgSelImage= BackgroundFileStyle.createStyleByURL(selImageUrl); |
||
126 | } |
||
127 | |||
128 | |||
129 | public void setLineWidth(double width) { |
||
130 | this.width = width;
|
||
131 | getLineStyle().setLineWidth((float) width);
|
||
132 | } |
||
133 | |||
134 | public double getLineWidth() { |
||
135 | return width;
|
||
136 | } |
||
137 | |||
138 | public ISymbol getSymbolForSelection() {
|
||
139 | if (selectionSym == null) { |
||
140 | selectionSym = (PictureLineSymbol) cloneForSelection(); |
||
141 | selectionSym.selected=true;
|
||
142 | selectionSym.selectionSym = selectionSym; // avoid too much lazy creations
|
||
143 | 42439 | dmartinezizquierdo | }else{
|
144 | selectionSym.setColor(MapContext.getSelectionColor()); |
||
145 | 40435 | jjdelcerro | } |
146 | return selectionSym;
|
||
147 | |||
148 | } |
||
149 | |||
150 | public void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Feature f, Cancellable cancel) { |
||
151 | draw(g, affineTransform, geom, cancel); |
||
152 | } |
||
153 | |||
154 | private void draw(Graphics2D g, AffineTransform affineTransform, Geometry geom, Cancellable cancel) { |
||
155 | |||
156 | if (csXScale<=0 && csYScale<=0) { |
||
157 | return;
|
||
158 | } |
||
159 | |||
160 | float csWidth = getLineStyle().getLineWidth();
|
||
161 | 42439 | dmartinezizquierdo | |
162 | 40435 | jjdelcerro | BasicStroke bs = new BasicStroke( |
163 | (float) csWidth,
|
||
164 | BasicStroke.CAP_ROUND,
|
||
165 | BasicStroke.CAP_ROUND);
|
||
166 | 42439 | dmartinezizquierdo | |
167 | 40435 | jjdelcerro | Shape geom_transf_clip = geom.getShape(affineTransform);
|
168 | g.setClip(bs.createStrokedShape(geom_transf_clip)); |
||
169 | 42439 | dmartinezizquierdo | |
170 | 40435 | jjdelcerro | BackgroundFileStyle bg = (!selected) ? bgImage : bgSelImage ; |
171 | |||
172 | Rectangle bounds = bg.getBounds();
|
||
173 | final double imageWidth = bounds.getWidth() * csXScale; |
||
174 | final double imageHeight = bounds.getHeight() * csYScale; |
||
175 | |||
176 | if (imageWidth==0 || imageHeight==0) return; |
||
177 | int height = (int) csWidth; |
||
178 | |||
179 | 43156 | jjdelcerro | PathLength pl = new DefaultPathLength(geom_transf_clip);
|
180 | 40435 | jjdelcerro | PathIterator iterator = geom_transf_clip.getPathIterator(null, 0.8); |
181 | double[] theData = new double[6]; |
||
182 | Point2D firstPoint = null, startPoint = null, endPoint = null; |
||
183 | if (!iterator.isDone()) {
|
||
184 | if ( iterator.currentSegment(theData) != PathIterator.SEG_CLOSE) { |
||
185 | firstPoint = new Point2D.Double(theData[0], theData[1]); |
||
186 | } |
||
187 | } |
||
188 | float currentPathLength = 1; |
||
189 | |||
190 | Rectangle rect = new Rectangle(); |
||
191 | |||
192 | while ((cancel==null || !cancel.isCanceled()) && !iterator.isDone()) { |
||
193 | |||
194 | int theType = iterator.currentSegment(theData);
|
||
195 | switch (theType) {
|
||
196 | case PathIterator.SEG_MOVETO: |
||
197 | startPoint = new Point2D.Double(theData[0], theData[1]); |
||
198 | |||
199 | endPoint = null;
|
||
200 | iterator.next(); |
||
201 | |||
202 | continue;
|
||
203 | |||
204 | case PathIterator.SEG_LINETO: |
||
205 | case PathIterator.SEG_QUADTO: |
||
206 | case PathIterator.SEG_CUBICTO: |
||
207 | endPoint = new Point2D.Double(theData[0], theData[1]); |
||
208 | |||
209 | break;
|
||
210 | case PathIterator.SEG_CLOSE: |
||
211 | endPoint = startPoint; |
||
212 | startPoint = firstPoint; |
||
213 | break;
|
||
214 | } |
||
215 | |||
216 | double a = endPoint.getX() - startPoint.getX();
|
||
217 | double b = endPoint.getY() - startPoint.getY();
|
||
218 | double theta = pl.angleAtLength(currentPathLength);
|
||
219 | |||
220 | double x = startPoint.getX();
|
||
221 | double y = startPoint.getY();
|
||
222 | |||
223 | // Theorem of Pythagoras
|
||
224 | float segmentLength = (float) Math.sqrt(a*a + b*b); |
||
225 | |||
226 | // compute how many times the image has to be drawn
|
||
227 | // to completely cover this segment's length
|
||
228 | int count = (int) Math.ceil(segmentLength/imageWidth); |
||
229 | |||
230 | for (int i = 0; (cancel==null || !cancel.isCanceled()) && i < count; i++) { |
||
231 | g.translate(x, y); |
||
232 | g.rotate(theta); |
||
233 | |||
234 | double xOffsetTranslation = imageWidth*i;
|
||
235 | g.translate(xOffsetTranslation, -csWidth); |
||
236 | |||
237 | rect.setBounds(0, (int) Math.round(height*.5), (int) Math.ceil(imageWidth), height); |
||
238 | try {
|
||
239 | bg.drawInsideRectangle(g, rect, false);
|
||
240 | } catch (SymbolDrawingException e) {
|
||
241 | logger.warn(Messages.getText("label_style_could_not_be_painted"), e);
|
||
242 | } |
||
243 | g.translate(-xOffsetTranslation, csWidth); |
||
244 | |||
245 | g.rotate(-theta); |
||
246 | g.translate(-x, -y); |
||
247 | } |
||
248 | |||
249 | startPoint = endPoint; |
||
250 | currentPathLength += segmentLength; |
||
251 | iterator.next(); |
||
252 | } |
||
253 | g.setClip(null);
|
||
254 | } |
||
255 | |||
256 | /**
|
||
257 | * Sets the yscale for the picture line symbol
|
||
258 | * @param yScale
|
||
259 | */
|
||
260 | public void setYScale(double yScale) { |
||
261 | this.yScale = yScale;
|
||
262 | this.csYScale = yScale;
|
||
263 | } |
||
264 | /**
|
||
265 | * Sets the xscale for the picture line symbol
|
||
266 | * @param xScale
|
||
267 | */
|
||
268 | public void setXScale(double xScale) { |
||
269 | this.xScale = xScale;
|
||
270 | this.csXScale = xScale;
|
||
271 | } |
||
272 | |||
273 | public String getClassName() { |
||
274 | return getClass().getName();
|
||
275 | } |
||
276 | |||
277 | public void print(Graphics2D g, AffineTransform at, Geometry geom, |
||
278 | PrintAttributes properties) { |
||
279 | this.properties=properties;
|
||
280 | draw(g, at, geom, null);
|
||
281 | this.properties=null; |
||
282 | |||
283 | } |
||
284 | 42439 | dmartinezizquierdo | |
285 | 40435 | jjdelcerro | /**
|
286 | * Returns the URL of the image that is used as a picture line symbol (when it
|
||
287 | * is selected in the map)
|
||
288 | * @return selimagePath,URL
|
||
289 | */
|
||
290 | public URL getSelectedSource(){ |
||
291 | return bgSelImage.getSource();
|
||
292 | } |
||
293 | /**
|
||
294 | * Returns the URL of the image that is used as a picture line symbol
|
||
295 | * @return imagePath,URL
|
||
296 | */
|
||
297 | public URL getSource() { |
||
298 | return bgImage.getSource();
|
||
299 | } |
||
300 | 42439 | dmartinezizquierdo | |
301 | 40435 | jjdelcerro | /**
|
302 | * Returns the xscale for the picture line symbol
|
||
303 | * @param xScale
|
||
304 | */
|
||
305 | public double getXScale() { |
||
306 | return xScale;
|
||
307 | } |
||
308 | /**
|
||
309 | * Returns the yscale for the picture line symbol
|
||
310 | * @param yScale
|
||
311 | */
|
||
312 | public double getYScale() { |
||
313 | return yScale;
|
||
314 | } |
||
315 | |||
316 | @Override
|
||
317 | public void setCartographicSize(double cartographicSize, Geometry geom) { |
||
318 | getLineStyle().setLineWidth((float) cartographicSize);
|
||
319 | double scale = cartographicSize/width;
|
||
320 | csXScale = xScale * scale; |
||
321 | csYScale = yScale * scale; |
||
322 | } |
||
323 | |||
324 | @Override
|
||
325 | public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) { |
||
326 | double s = super.toCartographicSize(viewPort, dpi, geom); |
||
327 | setCartographicSize(CartographicSupportToolkit. |
||
328 | getCartographicLength(this, width, viewPort, dpi), geom);
|
||
329 | return s;
|
||
330 | } |
||
331 | 42439 | dmartinezizquierdo | |
332 | |||
333 | 40435 | jjdelcerro | public Object clone() throws CloneNotSupportedException { |
334 | PictureLineSymbol copy = (PictureLineSymbol) super.clone();
|
||
335 | |||
336 | // clone selection
|
||
337 | if (selectionSym != null) { |
||
338 | //to avoid an infinite loop
|
||
339 | if (this == selectionSym){ |
||
340 | copy.selectionSym = copy; |
||
341 | } else {
|
||
342 | copy.selectionSym = (PictureLineSymbol) selectionSym.clone(); |
||
343 | } |
||
344 | } |
||
345 | |||
346 | // clone brackground image
|
||
347 | if (bgImage != null) { |
||
348 | copy.bgImage = (BackgroundFileStyle) bgImage.clone(); |
||
349 | } |
||
350 | |||
351 | // clone selection brackground image
|
||
352 | if (bgSelImage != null) { |
||
353 | copy.bgSelImage = (BackgroundFileStyle) bgSelImage.clone(); |
||
354 | } |
||
355 | |||
356 | // FIXME: clone properties
|
||
357 | 42439 | dmartinezizquierdo | |
358 | 40435 | jjdelcerro | return copy;
|
359 | } |
||
360 | |||
361 | public void loadFromState(PersistentState state) throws PersistenceException { |
||
362 | // Set parent style properties
|
||
363 | super.loadFromState(state);
|
||
364 | |||
365 | this.selected = (Boolean) state.get(SELECTED); |
||
366 | this.selectionSym = (PictureLineSymbol) state.get(SELECTION_SYMBOL);
|
||
367 | this.bgImage = (BackgroundFileStyle) state.get(BACKGROUND_IMAGE);
|
||
368 | this.bgSelImage =
|
||
369 | (BackgroundFileStyle) state.get(BACKGROUND_SELECTION_IMAGE); |
||
370 | this.setLineWidth(state.getDouble(WIDTH));
|
||
371 | } |
||
372 | |||
373 | public void saveToState(PersistentState state) throws PersistenceException { |
||
374 | // Save parent fill symbol properties
|
||
375 | super.saveToState(state);
|
||
376 | |||
377 | // Save own properties
|
||
378 | state.set(SELECTED, this.selected);
|
||
379 | state.set(SELECTION_SYMBOL, this.getSymbolForSelection());
|
||
380 | state.set(BACKGROUND_IMAGE, this.bgImage);
|
||
381 | state.set(BACKGROUND_SELECTION_IMAGE, this.bgSelImage);
|
||
382 | state.set(WIDTH, width); |
||
383 | } |
||
384 | |||
385 | public static class RegisterPersistence implements Callable { |
||
386 | |||
387 | public Object call() throws Exception { |
||
388 | PersistenceManager manager = ToolsLocator.getPersistenceManager(); |
||
389 | if (manager.getDefinition(PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME) == null) { |
||
390 | DynStruct definition = |
||
391 | manager.addDefinition(PictureLineSymbol.class, |
||
392 | PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME, |
||
393 | PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME |
||
394 | + " Persistence definition",
|
||
395 | null,
|
||
396 | null);
|
||
397 | |||
398 | // Extend the Style base definition
|
||
399 | definition.extend(manager.getDefinition(LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME)); |
||
400 | |||
401 | definition.addDynFieldBoolean(SELECTED).setMandatory(false);
|
||
402 | definition.addDynFieldObject(SELECTION_SYMBOL) |
||
403 | .setClassOfValue(PictureLineSymbol.class).setMandatory(false);
|
||
404 | definition.addDynFieldObject(BACKGROUND_IMAGE) |
||
405 | .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
|
||
406 | definition.addDynFieldObject(BACKGROUND_SELECTION_IMAGE) |
||
407 | .setClassOfValue(BackgroundFileStyle.class).setMandatory(false);
|
||
408 | 42439 | dmartinezizquierdo | |
409 | 40435 | jjdelcerro | definition.addDynFieldObject(WIDTH) |
410 | .setClassOfValue(Double.class).setMandatory(true); |
||
411 | } |
||
412 | return Boolean.TRUE; |
||
413 | } |
||
414 | } |
||
415 | 42439 | dmartinezizquierdo | |
416 | 40435 | jjdelcerro | public static class RegisterSymbol implements Callable { |
417 | |||
418 | public Object call() throws Exception { |
||
419 | SymbolManager manager = MapContextLocator.getSymbolManager(); |
||
420 | |||
421 | manager.registerSymbol(PICTURE_LINE_SYMBOL_PERSISTENCE_DEFINITION_NAME, |
||
422 | PictureLineSymbol.class); |
||
423 | |||
424 | return Boolean.TRUE; |
||
425 | } |
||
426 | } |
||
427 | } |