svn-gvsig-desktop / tags / v1_0_2_Build_892 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / rendering / FStyledShapePainter.java @ 10278
History | View | Annotate | Download (17.4 KB)
1 | 268 | fjp | /*
|
---|---|---|---|
2 | * Created on 22-nov-2004
|
||
3 | *
|
||
4 | * TODO To change the template for this generated file go to
|
||
5 | * Window - Preferences - Java - Code Generation - Code and Comments
|
||
6 | */
|
||
7 | /*
|
||
8 | * Geotools2 - OpenSource mapping toolkit
|
||
9 | * http://geotools.org
|
||
10 | * (C) 2002, Geotools Project Managment Committee (PMC)
|
||
11 | *
|
||
12 | * This library is free software; you can redistribute it and/or
|
||
13 | * modify it under the terms of the GNU Lesser General Public
|
||
14 | * License as published by the Free Software Foundation;
|
||
15 | * version 2.1 of the License.
|
||
16 | *
|
||
17 | * This library is distributed in the hope that it will be useful,
|
||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
20 | * Lesser General Public License for more details.
|
||
21 | *
|
||
22 | */
|
||
23 | |||
24 | 1100 | fjp | /* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
25 | *
|
||
26 | * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
|
||
27 | *
|
||
28 | * This program is free software; you can redistribute it and/or
|
||
29 | * modify it under the terms of the GNU General Public License
|
||
30 | * as published by the Free Software Foundation; either version 2
|
||
31 | * of the License, or (at your option) any later version.
|
||
32 | *
|
||
33 | * This program is distributed in the hope that it will be useful,
|
||
34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
36 | * GNU General Public License for more details.
|
||
37 | *
|
||
38 | * You should have received a copy of the GNU General Public License
|
||
39 | * along with this program; if not, write to the Free Software
|
||
40 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
|
||
41 | *
|
||
42 | * For more information, contact:
|
||
43 | *
|
||
44 | * Generalitat Valenciana
|
||
45 | * Conselleria d'Infraestructures i Transport
|
||
46 | * Av. Blasco Ib??ez, 50
|
||
47 | * 46010 VALENCIA
|
||
48 | * SPAIN
|
||
49 | *
|
||
50 | * +34 963862235
|
||
51 | * gvsig@gva.es
|
||
52 | * www.gvsig.gva.es
|
||
53 | *
|
||
54 | * or
|
||
55 | *
|
||
56 | * IVER T.I. S.A
|
||
57 | * Salamanca 50
|
||
58 | * 46005 Valencia
|
||
59 | * Spain
|
||
60 | *
|
||
61 | * +34 963163400
|
||
62 | * dac@iver.es
|
||
63 | */
|
||
64 | 268 | fjp | package com.iver.cit.gvsig.fmap.rendering; |
65 | |||
66 | import org.geotools.renderer.style.GraphicStyle2D; |
||
67 | import org.geotools.renderer.style.LineStyle2D; |
||
68 | import org.geotools.renderer.style.MarkStyle2D; |
||
69 | import org.geotools.renderer.style.PolygonStyle2D; |
||
70 | import org.geotools.renderer.style.Style2D; |
||
71 | import org.geotools.renderer.style.TextStyle2D; |
||
72 | import java.awt.AlphaComposite; |
||
73 | import java.awt.Canvas; |
||
74 | import java.awt.Graphics2D; |
||
75 | import java.awt.Image; |
||
76 | import java.awt.Paint; |
||
77 | import java.awt.Shape; |
||
78 | import java.awt.TexturePaint; |
||
79 | import java.awt.font.GlyphVector; |
||
80 | import java.awt.geom.AffineTransform; |
||
81 | import java.awt.geom.PathIterator; |
||
82 | import java.awt.geom.Point2D; |
||
83 | import java.awt.geom.Rectangle2D; |
||
84 | import java.awt.image.BufferedImage; |
||
85 | import java.util.logging.Level; |
||
86 | import java.util.logging.Logger; |
||
87 | |||
88 | |||
89 | /**
|
||
90 | * A simple class that knows how to paint a Shape object onto a Graphic given a
|
||
91 | * Style2D. It's the last step of the rendering engine, and has been factored
|
||
92 | * out since both renderers do use the same painting logic.
|
||
93 | *
|
||
94 | * @author Andrea Aime
|
||
95 | */
|
||
96 | public class FStyledShapePainter { |
||
97 | private static AffineTransform IDENTITY_TRANSFORM = new AffineTransform(); |
||
98 | |||
99 | /** Observer for image loading */
|
||
100 | private static Canvas imgObserver = new Canvas(); |
||
101 | |||
102 | /** The logger for the rendering module. */
|
||
103 | private static final Logger LOGGER = Logger.getLogger(FStyledShapePainter.class |
||
104 | .getName()); |
||
105 | |||
106 | /**
|
||
107 | * Invoked automatically when a polyline is about to be draw. This
|
||
108 | * implementation paints the polyline according to the rendered style
|
||
109 | *
|
||
110 | * @param graphics The graphics in which to draw.
|
||
111 | * @param shape The polyline to draw.
|
||
112 | * @param style The style to apply, or <code>null</code> if none.
|
||
113 | * @param scale The scale denominator for the current zoom level
|
||
114 | */
|
||
115 | public void paint(final Graphics2D graphics, final Shape shape, |
||
116 | final Style2D style, final double scale) { |
||
117 | if (style == null) { |
||
118 | // TODO: what's going on? Should not be reached...
|
||
119 | LOGGER.severe("ShapePainter has been asked to paint a null style!!");
|
||
120 | |||
121 | return;
|
||
122 | } |
||
123 | |||
124 | // Is the current scale within the style scale range?
|
||
125 | if (!style.isScaleInRange(scale)) {
|
||
126 | LOGGER.fine("Out of scale");
|
||
127 | |||
128 | return;
|
||
129 | 310 | fjp | } |
130 | 268 | fjp | |
131 | // if(LOGGER.isLoggable(Level.FINE)) {
|
||
132 | // LOGGER.fine("Graphics transform: " + graphics.getTransform());
|
||
133 | // }
|
||
134 | |||
135 | if (style instanceof MarkStyle2D) { |
||
136 | // get the point onto the shape has to be painted
|
||
137 | 310 | fjp | // SI ES UN RECTANGULO, ES MEJOR USAR g.fillRect, es mucho m?s
|
138 | // r?pido. Para el resto, va m?s lento.
|
||
139 | 268 | fjp | float[] coords = new float[2]; |
140 | PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
|
||
141 | 310 | fjp | iter.currentSegment(coords); |
142 | 268 | fjp | |
143 | MarkStyle2D ms2d = (MarkStyle2D) style; |
||
144 | Shape transformedShape = ms2d.getTransformedShape(coords[0], |
||
145 | 310 | fjp | coords[1]);
|
146 | // Shape transformedShape = shape;
|
||
147 | 268 | fjp | |
148 | if (transformedShape != null) { |
||
149 | if (ms2d.getFill() != null) { |
||
150 | graphics.setPaint(ms2d.getFill()); |
||
151 | 305 | fjp | // graphics.setComposite(ms2d.getFillComposite());
|
152 | 310 | fjp | if (transformedShape instanceof Rectangle2D) |
153 | { |
||
154 | Rectangle2D rAux = (Rectangle2D) transformedShape; |
||
155 | graphics.fillRect((int) rAux.getX(), (int) rAux.getY(), |
||
156 | (int) rAux.getWidth(), (int) rAux.getHeight()); |
||
157 | } |
||
158 | else
|
||
159 | { |
||
160 | graphics.fill(transformedShape); |
||
161 | } |
||
162 | // graphics.fillRect((int) coords[0], (int) coords[1], 10,10);
|
||
163 | 268 | fjp | } |
164 | |||
165 | if (ms2d.getContour() != null) { |
||
166 | graphics.setPaint(ms2d.getContour()); |
||
167 | graphics.setStroke(ms2d.getStroke()); |
||
168 | 305 | fjp | // graphics.setComposite(ms2d.getContourComposite());
|
169 | 268 | fjp | graphics.draw(transformedShape); |
170 | } |
||
171 | } |
||
172 | } else if (style instanceof GraphicStyle2D) { |
||
173 | // get the point onto the shape has to be painted
|
||
174 | float[] coords = new float[2]; |
||
175 | PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
|
||
176 | iter.currentSegment(coords); |
||
177 | |||
178 | GraphicStyle2D gs2d = (GraphicStyle2D) style; |
||
179 | |||
180 | renderImage(graphics, coords[0], coords[1], |
||
181 | (Image) gs2d.getImage(), gs2d.getRotation(), gs2d.getOpacity());
|
||
182 | } else if (style instanceof TextStyle2D) { |
||
183 | // get the point onto the shape has to be painted
|
||
184 | float[] coords = new float[2]; |
||
185 | PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
|
||
186 | iter.currentSegment(coords); |
||
187 | |||
188 | AffineTransform old = graphics.getTransform();
|
||
189 | AffineTransform temp = new AffineTransform(old); |
||
190 | TextStyle2D ts2d = (TextStyle2D) style; |
||
191 | GlyphVector textGv = ts2d.getTextGlyphVector(graphics);
|
||
192 | Rectangle2D bounds = textGv.getVisualBounds();
|
||
193 | |||
194 | temp.translate(coords[0], coords[1]); |
||
195 | |||
196 | double x = 0; |
||
197 | double y = 0; |
||
198 | |||
199 | if (ts2d.isAbsoluteLineDisplacement()) {
|
||
200 | double offset = ts2d.getDisplacementY();
|
||
201 | |||
202 | if (offset > 0.0) { // to the left of the line |
||
203 | y = -offset; |
||
204 | } else if (offset < 0) { |
||
205 | y = -offset + bounds.getHeight(); |
||
206 | } else {
|
||
207 | y = bounds.getHeight() / 2;
|
||
208 | } |
||
209 | |||
210 | x = -bounds.getWidth() / 2;
|
||
211 | } else {
|
||
212 | x = (ts2d.getAnchorX() * (-bounds.getWidth())) |
||
213 | + ts2d.getDisplacementX(); |
||
214 | y = (ts2d.getAnchorY() * (bounds.getHeight())) |
||
215 | + ts2d.getDisplacementY(); |
||
216 | } |
||
217 | |||
218 | temp.rotate(ts2d.getRotation()); |
||
219 | temp.translate(x, y); |
||
220 | |||
221 | try {
|
||
222 | graphics.setTransform(temp); |
||
223 | |||
224 | if (ts2d.getHaloFill() != null) { |
||
225 | // float radious = ts2d.getHaloRadius();
|
||
226 | |||
227 | // graphics.translate(radious, -radious);
|
||
228 | graphics.setPaint(ts2d.getHaloFill()); |
||
229 | graphics.setComposite(ts2d.getHaloComposite()); |
||
230 | graphics.fill(ts2d.getHaloShape(graphics)); |
||
231 | |||
232 | // graphics.translate(radious, radious);
|
||
233 | } |
||
234 | |||
235 | if (ts2d.getFill() != null) { |
||
236 | graphics.setPaint(ts2d.getFill()); |
||
237 | 382 | vcaballero | /// TODO graphics.setComposite(ts2d.getComposite());
|
238 | 268 | fjp | graphics.drawGlyphVector(textGv, 0, 0); |
239 | } |
||
240 | } finally {
|
||
241 | graphics.setTransform(old); |
||
242 | } |
||
243 | } else {
|
||
244 | // if the style is a polygon one, process it even if the polyline is not
|
||
245 | // closed (by SLD specification)
|
||
246 | if (style instanceof PolygonStyle2D) { |
||
247 | PolygonStyle2D ps2d = (PolygonStyle2D) style; |
||
248 | |||
249 | if (ps2d.getFill() != null) { |
||
250 | Paint paint = ps2d.getFill();
|
||
251 | |||
252 | if (paint instanceof TexturePaint) { |
||
253 | TexturePaint tp = (TexturePaint) paint; |
||
254 | BufferedImage image = tp.getImage();
|
||
255 | Rectangle2D rect = tp.getAnchorRect();
|
||
256 | AffineTransform at = graphics.getTransform();
|
||
257 | double width = rect.getWidth() * at.getScaleX();
|
||
258 | double height = rect.getHeight() * at.getScaleY();
|
||
259 | Rectangle2D scaledRect = new Rectangle2D.Double(0, 0, |
||
260 | width, height); |
||
261 | paint = new TexturePaint(image, scaledRect); |
||
262 | } |
||
263 | |||
264 | graphics.setPaint(paint); |
||
265 | 274 | fjp | if (ps2d.getContourComposite() != null) |
266 | graphics.setComposite(ps2d.getFillComposite()); |
||
267 | 268 | fjp | graphics.fill(shape); |
268 | } |
||
269 | } |
||
270 | |||
271 | if (style instanceof LineStyle2D) { |
||
272 | LineStyle2D ls2d = (LineStyle2D) style; |
||
273 | if (ls2d.getStroke() != null) { |
||
274 | // see if a graphic stroke is to be used, the drawing method is completely
|
||
275 | // different in this case
|
||
276 | if (ls2d.getGraphicStroke() != null) { |
||
277 | drawWithGraphicsStroke(graphics, shape, |
||
278 | ls2d.getGraphicStroke()); |
||
279 | } else {
|
||
280 | Paint paint = ls2d.getContour();
|
||
281 | |||
282 | if (paint instanceof TexturePaint) { |
||
283 | TexturePaint tp = (TexturePaint) paint; |
||
284 | BufferedImage image = tp.getImage();
|
||
285 | Rectangle2D rect = tp.getAnchorRect();
|
||
286 | AffineTransform at = graphics.getTransform();
|
||
287 | double width = rect.getWidth() * at.getScaleX();
|
||
288 | double height = rect.getHeight() * at.getScaleY();
|
||
289 | Rectangle2D scaledRect = new Rectangle2D.Double(0, |
||
290 | 0, width, height);
|
||
291 | paint = new TexturePaint(image, scaledRect); |
||
292 | } |
||
293 | |||
294 | graphics.setPaint(paint); |
||
295 | graphics.setStroke(ls2d.getStroke()); |
||
296 | if (ls2d.getContourComposite() != null) |
||
297 | graphics.setComposite(ls2d.getContourComposite()); |
||
298 | graphics.draw(shape); |
||
299 | } |
||
300 | } |
||
301 | } |
||
302 | } |
||
303 | } |
||
304 | |||
305 | // draws the image along the path
|
||
306 | private void drawWithGraphicsStroke(Graphics2D graphics, Shape shape, |
||
307 | BufferedImage image) {
|
||
308 | PathIterator pi = shape.getPathIterator(null, 10.0); |
||
309 | double[] coords = new double[2]; |
||
310 | int type;
|
||
311 | |||
312 | // I suppose the image has been already scaled and its square
|
||
313 | int imageSize = image.getWidth();
|
||
314 | |||
315 | double[] first = new double[2]; |
||
316 | double[] previous = new double[2]; |
||
317 | type = pi.currentSegment(coords); |
||
318 | first[0] = coords[0]; |
||
319 | first[1] = coords[1]; |
||
320 | previous[0] = coords[0]; |
||
321 | previous[1] = coords[1]; |
||
322 | |||
323 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
324 | LOGGER.finest("starting at " + first[0] + "," + first[1]); |
||
325 | } |
||
326 | |||
327 | pi.next(); |
||
328 | |||
329 | while (!pi.isDone()) {
|
||
330 | type = pi.currentSegment(coords); |
||
331 | |||
332 | switch (type) {
|
||
333 | case PathIterator.SEG_MOVETO: |
||
334 | |||
335 | // nothing to do?
|
||
336 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
337 | LOGGER.finest("moving to " + coords[0] + "," + coords[1]); |
||
338 | } |
||
339 | |||
340 | break;
|
||
341 | |||
342 | case PathIterator.SEG_CLOSE: |
||
343 | |||
344 | // draw back to first from previous
|
||
345 | coords[0] = first[0]; |
||
346 | coords[1] = first[1]; |
||
347 | |||
348 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
349 | LOGGER.finest("closing from " + previous[0] + "," |
||
350 | + previous[1] + " to " + coords[0] + "," + coords[1]); |
||
351 | } |
||
352 | |||
353 | // no break here - fall through to next section
|
||
354 | case PathIterator.SEG_LINETO: |
||
355 | |||
356 | // draw from previous to coords
|
||
357 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
358 | LOGGER.finest("drawing from " + previous[0] + "," |
||
359 | + previous[1] + " to " + coords[0] + "," + coords[1]); |
||
360 | } |
||
361 | |||
362 | double dx = coords[0] - previous[0]; |
||
363 | double dy = coords[1] - previous[1]; |
||
364 | double len = Math.sqrt((dx * dx) + (dy * dy)); // - imageWidth; |
||
365 | |||
366 | double theta = Math.atan2(dx, dy); |
||
367 | dx = (Math.sin(theta) * imageSize);
|
||
368 | dy = (Math.cos(theta) * imageSize);
|
||
369 | |||
370 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
371 | LOGGER.finest("dx = " + dx + " dy " + dy + " step = " |
||
372 | + Math.sqrt((dx * dx) + (dy * dy)));
|
||
373 | } |
||
374 | |||
375 | double rotation = -(theta - (Math.PI / 2d)); |
||
376 | double x = previous[0] + (dx / 2.0); |
||
377 | double y = previous[1] + (dy / 2.0); |
||
378 | |||
379 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
380 | LOGGER.finest("len =" + len + " imageSize " + imageSize); |
||
381 | } |
||
382 | |||
383 | double dist = 0; |
||
384 | |||
385 | for (dist = 0; dist < (len - imageSize); dist += imageSize) { |
||
386 | /*graphic.drawImage(image2,(int)x-midx,(int)y-midy,null); */
|
||
387 | renderImage(graphics, x, y, image, rotation, 1);
|
||
388 | |||
389 | x += dx; |
||
390 | y += dy; |
||
391 | } |
||
392 | |||
393 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
394 | LOGGER.finest("loop end dist " + dist + " len " + len + " " |
||
395 | + (len - dist)); |
||
396 | } |
||
397 | |||
398 | double remainder = len - dist;
|
||
399 | int remainingWidth = (int) remainder; |
||
400 | |||
401 | if (remainingWidth > 0) { |
||
402 | //clip and render image
|
||
403 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
404 | LOGGER.finest("about to use clipped image " + remainder);
|
||
405 | } |
||
406 | |||
407 | BufferedImage img = new BufferedImage(remainingWidth, |
||
408 | imageSize, image.getType()); |
||
409 | Graphics2D ig = img.createGraphics();
|
||
410 | ig.drawImage(image, 0, 0, imgObserver); |
||
411 | |||
412 | renderImage(graphics, x, y, img, rotation, 1);
|
||
413 | } |
||
414 | |||
415 | break;
|
||
416 | |||
417 | default:
|
||
418 | LOGGER.warning( |
||
419 | "default branch reached in drawWithGraphicStroke");
|
||
420 | } |
||
421 | |||
422 | previous[0] = coords[0]; |
||
423 | previous[1] = coords[1]; |
||
424 | pi.next(); |
||
425 | } |
||
426 | } |
||
427 | |||
428 | /**
|
||
429 | * Renders an image on the device
|
||
430 | *
|
||
431 | * @param graphics the image location on the screen, x coordinate
|
||
432 | * @param x the image location on the screen, y coordinate
|
||
433 | * @param y the image
|
||
434 | * @param image DOCUMENT ME!
|
||
435 | * @param rotation the image rotatation
|
||
436 | * @param opacity DOCUMENT ME!
|
||
437 | */
|
||
438 | private void renderImage(Graphics2D graphics, double x, double y, |
||
439 | Image image, double rotation, float opacity) { |
||
440 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
441 | LOGGER.finest("drawing Image @" + x + "," + y); |
||
442 | } |
||
443 | |||
444 | AffineTransform temp = graphics.getTransform();
|
||
445 | AffineTransform markAT = new AffineTransform(); |
||
446 | Point2D mapCentre = new java.awt.geom.Point2D.Double(x, y); |
||
447 | Point2D graphicCentre = new java.awt.geom.Point2D.Double(); |
||
448 | temp.transform(mapCentre, graphicCentre); |
||
449 | markAT.translate(graphicCentre.getX(), graphicCentre.getY()); |
||
450 | |||
451 | double shearY = temp.getShearY();
|
||
452 | double scaleY = temp.getScaleY();
|
||
453 | |||
454 | double originalRotation = Math.atan(shearY / scaleY); |
||
455 | |||
456 | if (LOGGER.isLoggable(Level.FINER)) { |
||
457 | LOGGER.finer("originalRotation " + originalRotation);
|
||
458 | } |
||
459 | |||
460 | markAT.rotate(rotation); |
||
461 | graphics.setTransform(markAT); |
||
462 | graphics.setComposite(AlphaComposite.getInstance(
|
||
463 | AlphaComposite.SRC_OVER, opacity));
|
||
464 | |||
465 | // we moved the origin to the centre of the image.
|
||
466 | graphics.drawImage(image, -image.getWidth(imgObserver) / 2,
|
||
467 | -image.getHeight(imgObserver) / 2, imgObserver);
|
||
468 | |||
469 | graphics.setTransform(temp); |
||
470 | |||
471 | return;
|
||
472 | } |
||
473 | } |