root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / rendering / FStyledShapePainter.java @ 12207
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 java.awt.AlphaComposite; |
||
67 | import java.awt.Canvas; |
||
68 | import java.awt.Graphics2D; |
||
69 | import java.awt.Image; |
||
70 | import java.awt.Paint; |
||
71 | import java.awt.Shape; |
||
72 | import java.awt.TexturePaint; |
||
73 | import java.awt.font.GlyphVector; |
||
74 | import java.awt.geom.AffineTransform; |
||
75 | import java.awt.geom.PathIterator; |
||
76 | import java.awt.geom.Point2D; |
||
77 | import java.awt.geom.Rectangle2D; |
||
78 | import java.awt.image.BufferedImage; |
||
79 | import java.util.logging.Level; |
||
80 | import java.util.logging.Logger; |
||
81 | |||
82 | 10627 | caballero | import org.geotools.renderer.style.GraphicStyle2D; |
83 | import org.geotools.renderer.style.LineStyle2D; |
||
84 | import org.geotools.renderer.style.MarkStyle2D; |
||
85 | import org.geotools.renderer.style.PolygonStyle2D; |
||
86 | import org.geotools.renderer.style.Style2D; |
||
87 | import org.geotools.renderer.style.TextStyle2D; |
||
88 | 268 | fjp | |
89 | 10627 | caballero | |
90 | 268 | fjp | /**
|
91 | * A simple class that knows how to paint a Shape object onto a Graphic given a
|
||
92 | * Style2D. It's the last step of the rendering engine, and has been factored
|
||
93 | * out since both renderers do use the same painting logic.
|
||
94 | *
|
||
95 | * @author Andrea Aime
|
||
96 | */
|
||
97 | public class FStyledShapePainter { |
||
98 | private static AffineTransform IDENTITY_TRANSFORM = new AffineTransform(); |
||
99 | |||
100 | /** Observer for image loading */
|
||
101 | private static Canvas imgObserver = new Canvas(); |
||
102 | |||
103 | /** The logger for the rendering module. */
|
||
104 | private static final Logger LOGGER = Logger.getLogger(FStyledShapePainter.class |
||
105 | .getName()); |
||
106 | |||
107 | /**
|
||
108 | * Invoked automatically when a polyline is about to be draw. This
|
||
109 | * implementation paints the polyline according to the rendered style
|
||
110 | *
|
||
111 | * @param graphics The graphics in which to draw.
|
||
112 | * @param shape The polyline to draw.
|
||
113 | * @param style The style to apply, or <code>null</code> if none.
|
||
114 | * @param scale The scale denominator for the current zoom level
|
||
115 | */
|
||
116 | public void paint(final Graphics2D graphics, final Shape shape, |
||
117 | final Style2D style, final double scale) { |
||
118 | if (style == null) { |
||
119 | // TODO: what's going on? Should not be reached...
|
||
120 | LOGGER.severe("ShapePainter has been asked to paint a null style!!");
|
||
121 | |||
122 | return;
|
||
123 | } |
||
124 | |||
125 | // Is the current scale within the style scale range?
|
||
126 | if (!style.isScaleInRange(scale)) {
|
||
127 | LOGGER.fine("Out of scale");
|
||
128 | |||
129 | return;
|
||
130 | 310 | fjp | } |
131 | 268 | fjp | |
132 | // if(LOGGER.isLoggable(Level.FINE)) {
|
||
133 | // LOGGER.fine("Graphics transform: " + graphics.getTransform());
|
||
134 | // }
|
||
135 | |||
136 | if (style instanceof MarkStyle2D) { |
||
137 | // get the point onto the shape has to be painted
|
||
138 | 310 | fjp | // SI ES UN RECTANGULO, ES MEJOR USAR g.fillRect, es mucho m?s
|
139 | // r?pido. Para el resto, va m?s lento.
|
||
140 | 268 | fjp | float[] coords = new float[2]; |
141 | PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
|
||
142 | 310 | fjp | iter.currentSegment(coords); |
143 | 268 | fjp | |
144 | MarkStyle2D ms2d = (MarkStyle2D) style; |
||
145 | Shape transformedShape = ms2d.getTransformedShape(coords[0], |
||
146 | 310 | fjp | coords[1]);
|
147 | // Shape transformedShape = shape;
|
||
148 | 268 | fjp | |
149 | if (transformedShape != null) { |
||
150 | if (ms2d.getFill() != null) { |
||
151 | graphics.setPaint(ms2d.getFill()); |
||
152 | 305 | fjp | // graphics.setComposite(ms2d.getFillComposite());
|
153 | 310 | fjp | if (transformedShape instanceof Rectangle2D) |
154 | { |
||
155 | Rectangle2D rAux = (Rectangle2D) transformedShape; |
||
156 | graphics.fillRect((int) rAux.getX(), (int) rAux.getY(), |
||
157 | (int) rAux.getWidth(), (int) rAux.getHeight()); |
||
158 | } |
||
159 | else
|
||
160 | { |
||
161 | graphics.fill(transformedShape); |
||
162 | } |
||
163 | // graphics.fillRect((int) coords[0], (int) coords[1], 10,10);
|
||
164 | 268 | fjp | } |
165 | |||
166 | if (ms2d.getContour() != null) { |
||
167 | graphics.setPaint(ms2d.getContour()); |
||
168 | graphics.setStroke(ms2d.getStroke()); |
||
169 | 305 | fjp | // graphics.setComposite(ms2d.getContourComposite());
|
170 | 268 | fjp | graphics.draw(transformedShape); |
171 | } |
||
172 | } |
||
173 | } else if (style instanceof GraphicStyle2D) { |
||
174 | // get the point onto the shape has to be painted
|
||
175 | float[] coords = new float[2]; |
||
176 | PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
|
||
177 | iter.currentSegment(coords); |
||
178 | |||
179 | GraphicStyle2D gs2d = (GraphicStyle2D) style; |
||
180 | |||
181 | renderImage(graphics, coords[0], coords[1], |
||
182 | (Image) gs2d.getImage(), gs2d.getRotation(), gs2d.getOpacity());
|
||
183 | } else if (style instanceof TextStyle2D) { |
||
184 | // get the point onto the shape has to be painted
|
||
185 | float[] coords = new float[2]; |
||
186 | PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
|
||
187 | iter.currentSegment(coords); |
||
188 | |||
189 | AffineTransform old = graphics.getTransform();
|
||
190 | AffineTransform temp = new AffineTransform(old); |
||
191 | TextStyle2D ts2d = (TextStyle2D) style; |
||
192 | GlyphVector textGv = ts2d.getTextGlyphVector(graphics);
|
||
193 | Rectangle2D bounds = textGv.getVisualBounds();
|
||
194 | |||
195 | temp.translate(coords[0], coords[1]); |
||
196 | |||
197 | double x = 0; |
||
198 | double y = 0; |
||
199 | |||
200 | if (ts2d.isAbsoluteLineDisplacement()) {
|
||
201 | double offset = ts2d.getDisplacementY();
|
||
202 | |||
203 | if (offset > 0.0) { // to the left of the line |
||
204 | y = -offset; |
||
205 | } else if (offset < 0) { |
||
206 | y = -offset + bounds.getHeight(); |
||
207 | } else {
|
||
208 | y = bounds.getHeight() / 2;
|
||
209 | } |
||
210 | |||
211 | x = -bounds.getWidth() / 2;
|
||
212 | } else {
|
||
213 | x = (ts2d.getAnchorX() * (-bounds.getWidth())) |
||
214 | + ts2d.getDisplacementX(); |
||
215 | y = (ts2d.getAnchorY() * (bounds.getHeight())) |
||
216 | + ts2d.getDisplacementY(); |
||
217 | } |
||
218 | |||
219 | temp.rotate(ts2d.getRotation()); |
||
220 | temp.translate(x, y); |
||
221 | |||
222 | try {
|
||
223 | graphics.setTransform(temp); |
||
224 | |||
225 | if (ts2d.getHaloFill() != null) { |
||
226 | // float radious = ts2d.getHaloRadius();
|
||
227 | |||
228 | // graphics.translate(radious, -radious);
|
||
229 | graphics.setPaint(ts2d.getHaloFill()); |
||
230 | graphics.setComposite(ts2d.getHaloComposite()); |
||
231 | graphics.fill(ts2d.getHaloShape(graphics)); |
||
232 | |||
233 | // graphics.translate(radious, radious);
|
||
234 | } |
||
235 | |||
236 | if (ts2d.getFill() != null) { |
||
237 | graphics.setPaint(ts2d.getFill()); |
||
238 | 382 | vcaballero | /// TODO graphics.setComposite(ts2d.getComposite());
|
239 | 268 | fjp | graphics.drawGlyphVector(textGv, 0, 0); |
240 | } |
||
241 | } finally {
|
||
242 | graphics.setTransform(old); |
||
243 | } |
||
244 | } else {
|
||
245 | // if the style is a polygon one, process it even if the polyline is not
|
||
246 | // closed (by SLD specification)
|
||
247 | if (style instanceof PolygonStyle2D) { |
||
248 | PolygonStyle2D ps2d = (PolygonStyle2D) style; |
||
249 | |||
250 | if (ps2d.getFill() != null) { |
||
251 | Paint paint = ps2d.getFill();
|
||
252 | |||
253 | if (paint instanceof TexturePaint) { |
||
254 | TexturePaint tp = (TexturePaint) paint; |
||
255 | BufferedImage image = tp.getImage();
|
||
256 | Rectangle2D rect = tp.getAnchorRect();
|
||
257 | AffineTransform at = graphics.getTransform();
|
||
258 | double width = rect.getWidth() * at.getScaleX();
|
||
259 | double height = rect.getHeight() * at.getScaleY();
|
||
260 | Rectangle2D scaledRect = new Rectangle2D.Double(0, 0, |
||
261 | width, height); |
||
262 | paint = new TexturePaint(image, scaledRect); |
||
263 | } |
||
264 | |||
265 | graphics.setPaint(paint); |
||
266 | 274 | fjp | if (ps2d.getContourComposite() != null) |
267 | graphics.setComposite(ps2d.getFillComposite()); |
||
268 | 268 | fjp | graphics.fill(shape); |
269 | } |
||
270 | } |
||
271 | |||
272 | if (style instanceof LineStyle2D) { |
||
273 | LineStyle2D ls2d = (LineStyle2D) style; |
||
274 | if (ls2d.getStroke() != null) { |
||
275 | // see if a graphic stroke is to be used, the drawing method is completely
|
||
276 | // different in this case
|
||
277 | if (ls2d.getGraphicStroke() != null) { |
||
278 | drawWithGraphicsStroke(graphics, shape, |
||
279 | ls2d.getGraphicStroke()); |
||
280 | } else {
|
||
281 | Paint paint = ls2d.getContour();
|
||
282 | |||
283 | if (paint instanceof TexturePaint) { |
||
284 | TexturePaint tp = (TexturePaint) paint; |
||
285 | BufferedImage image = tp.getImage();
|
||
286 | Rectangle2D rect = tp.getAnchorRect();
|
||
287 | AffineTransform at = graphics.getTransform();
|
||
288 | double width = rect.getWidth() * at.getScaleX();
|
||
289 | double height = rect.getHeight() * at.getScaleY();
|
||
290 | Rectangle2D scaledRect = new Rectangle2D.Double(0, |
||
291 | 0, width, height);
|
||
292 | paint = new TexturePaint(image, scaledRect); |
||
293 | } |
||
294 | |||
295 | graphics.setPaint(paint); |
||
296 | graphics.setStroke(ls2d.getStroke()); |
||
297 | if (ls2d.getContourComposite() != null) |
||
298 | graphics.setComposite(ls2d.getContourComposite()); |
||
299 | graphics.draw(shape); |
||
300 | } |
||
301 | } |
||
302 | } |
||
303 | } |
||
304 | } |
||
305 | |||
306 | // draws the image along the path
|
||
307 | private void drawWithGraphicsStroke(Graphics2D graphics, Shape shape, |
||
308 | BufferedImage image) {
|
||
309 | PathIterator pi = shape.getPathIterator(null, 10.0); |
||
310 | double[] coords = new double[2]; |
||
311 | int type;
|
||
312 | |||
313 | // I suppose the image has been already scaled and its square
|
||
314 | int imageSize = image.getWidth();
|
||
315 | |||
316 | double[] first = new double[2]; |
||
317 | double[] previous = new double[2]; |
||
318 | type = pi.currentSegment(coords); |
||
319 | first[0] = coords[0]; |
||
320 | first[1] = coords[1]; |
||
321 | previous[0] = coords[0]; |
||
322 | previous[1] = coords[1]; |
||
323 | |||
324 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
325 | LOGGER.finest("starting at " + first[0] + "," + first[1]); |
||
326 | } |
||
327 | |||
328 | pi.next(); |
||
329 | |||
330 | while (!pi.isDone()) {
|
||
331 | type = pi.currentSegment(coords); |
||
332 | |||
333 | switch (type) {
|
||
334 | case PathIterator.SEG_MOVETO: |
||
335 | |||
336 | // nothing to do?
|
||
337 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
338 | LOGGER.finest("moving to " + coords[0] + "," + coords[1]); |
||
339 | } |
||
340 | |||
341 | break;
|
||
342 | |||
343 | case PathIterator.SEG_CLOSE: |
||
344 | |||
345 | // draw back to first from previous
|
||
346 | coords[0] = first[0]; |
||
347 | coords[1] = first[1]; |
||
348 | |||
349 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
350 | LOGGER.finest("closing from " + previous[0] + "," |
||
351 | + previous[1] + " to " + coords[0] + "," + coords[1]); |
||
352 | } |
||
353 | |||
354 | // no break here - fall through to next section
|
||
355 | case PathIterator.SEG_LINETO: |
||
356 | |||
357 | // draw from previous to coords
|
||
358 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
359 | LOGGER.finest("drawing from " + previous[0] + "," |
||
360 | + previous[1] + " to " + coords[0] + "," + coords[1]); |
||
361 | } |
||
362 | |||
363 | double dx = coords[0] - previous[0]; |
||
364 | double dy = coords[1] - previous[1]; |
||
365 | double len = Math.sqrt((dx * dx) + (dy * dy)); // - imageWidth; |
||
366 | |||
367 | double theta = Math.atan2(dx, dy); |
||
368 | dx = (Math.sin(theta) * imageSize);
|
||
369 | dy = (Math.cos(theta) * imageSize);
|
||
370 | |||
371 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
372 | LOGGER.finest("dx = " + dx + " dy " + dy + " step = " |
||
373 | + Math.sqrt((dx * dx) + (dy * dy)));
|
||
374 | } |
||
375 | |||
376 | double rotation = -(theta - (Math.PI / 2d)); |
||
377 | double x = previous[0] + (dx / 2.0); |
||
378 | double y = previous[1] + (dy / 2.0); |
||
379 | |||
380 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
381 | LOGGER.finest("len =" + len + " imageSize " + imageSize); |
||
382 | } |
||
383 | |||
384 | double dist = 0; |
||
385 | |||
386 | for (dist = 0; dist < (len - imageSize); dist += imageSize) { |
||
387 | /*graphic.drawImage(image2,(int)x-midx,(int)y-midy,null); */
|
||
388 | renderImage(graphics, x, y, image, rotation, 1);
|
||
389 | |||
390 | x += dx; |
||
391 | y += dy; |
||
392 | } |
||
393 | |||
394 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
395 | LOGGER.finest("loop end dist " + dist + " len " + len + " " |
||
396 | + (len - dist)); |
||
397 | } |
||
398 | |||
399 | double remainder = len - dist;
|
||
400 | int remainingWidth = (int) remainder; |
||
401 | |||
402 | if (remainingWidth > 0) { |
||
403 | //clip and render image
|
||
404 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
405 | LOGGER.finest("about to use clipped image " + remainder);
|
||
406 | } |
||
407 | |||
408 | BufferedImage img = new BufferedImage(remainingWidth, |
||
409 | imageSize, image.getType()); |
||
410 | Graphics2D ig = img.createGraphics();
|
||
411 | ig.drawImage(image, 0, 0, imgObserver); |
||
412 | |||
413 | renderImage(graphics, x, y, img, rotation, 1);
|
||
414 | } |
||
415 | |||
416 | break;
|
||
417 | |||
418 | default:
|
||
419 | LOGGER.warning( |
||
420 | "default branch reached in drawWithGraphicStroke");
|
||
421 | } |
||
422 | |||
423 | previous[0] = coords[0]; |
||
424 | previous[1] = coords[1]; |
||
425 | pi.next(); |
||
426 | } |
||
427 | } |
||
428 | |||
429 | /**
|
||
430 | * Renders an image on the device
|
||
431 | *
|
||
432 | * @param graphics the image location on the screen, x coordinate
|
||
433 | * @param x the image location on the screen, y coordinate
|
||
434 | * @param y the image
|
||
435 | * @param image DOCUMENT ME!
|
||
436 | * @param rotation the image rotatation
|
||
437 | * @param opacity DOCUMENT ME!
|
||
438 | */
|
||
439 | private void renderImage(Graphics2D graphics, double x, double y, |
||
440 | Image image, double rotation, float opacity) { |
||
441 | if (LOGGER.isLoggable(Level.FINEST)) { |
||
442 | LOGGER.finest("drawing Image @" + x + "," + y); |
||
443 | } |
||
444 | |||
445 | AffineTransform temp = graphics.getTransform();
|
||
446 | AffineTransform markAT = new AffineTransform(); |
||
447 | Point2D mapCentre = new java.awt.geom.Point2D.Double(x, y); |
||
448 | Point2D graphicCentre = new java.awt.geom.Point2D.Double(); |
||
449 | temp.transform(mapCentre, graphicCentre); |
||
450 | markAT.translate(graphicCentre.getX(), graphicCentre.getY()); |
||
451 | |||
452 | double shearY = temp.getShearY();
|
||
453 | double scaleY = temp.getScaleY();
|
||
454 | |||
455 | double originalRotation = Math.atan(shearY / scaleY); |
||
456 | |||
457 | if (LOGGER.isLoggable(Level.FINER)) { |
||
458 | LOGGER.finer("originalRotation " + originalRotation);
|
||
459 | } |
||
460 | |||
461 | markAT.rotate(rotation); |
||
462 | graphics.setTransform(markAT); |
||
463 | graphics.setComposite(AlphaComposite.getInstance(
|
||
464 | AlphaComposite.SRC_OVER, opacity));
|
||
465 | |||
466 | // we moved the origin to the centre of the image.
|
||
467 | graphics.drawImage(image, -image.getWidth(imgObserver) / 2,
|
||
468 | -image.getHeight(imgObserver) / 2, imgObserver);
|
||
469 | |||
470 | graphics.setTransform(temp); |
||
471 | |||
472 | return;
|
||
473 | } |
||
474 | } |