Statistics
| Revision:

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
}