Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / rendering / FStyledShapePainter.java @ 305

History | View | Annotate | Download (15.6 KB)

1
/*
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
package com.iver.cit.gvsig.fmap.rendering;
25

    
26
import org.geotools.renderer.style.GraphicStyle2D;
27
import org.geotools.renderer.style.LineStyle2D;
28
import org.geotools.renderer.style.MarkStyle2D;
29
import org.geotools.renderer.style.PolygonStyle2D;
30
import org.geotools.renderer.style.Style2D;
31
import org.geotools.renderer.style.TextStyle2D;
32
import java.awt.AlphaComposite;
33
import java.awt.Canvas;
34
import java.awt.Graphics2D;
35
import java.awt.Image;
36
import java.awt.Paint;
37
import java.awt.Shape;
38
import java.awt.TexturePaint;
39
import java.awt.font.GlyphVector;
40
import java.awt.geom.AffineTransform;
41
import java.awt.geom.PathIterator;
42
import java.awt.geom.Point2D;
43
import java.awt.geom.Rectangle2D;
44
import java.awt.image.BufferedImage;
45
import java.util.logging.Level;
46
import java.util.logging.Logger;
47

    
48

    
49
/**
50
 * A simple class that knows how to paint a Shape object onto a Graphic given a
51
 * Style2D. It's the last step of the rendering engine, and has been factored
52
 * out since both renderers do use the same painting logic.
53
 *
54
 * @author Andrea Aime
55
 */
56
public class FStyledShapePainter {
57
    private static AffineTransform IDENTITY_TRANSFORM = new AffineTransform();
58

    
59
    /** Observer for image loading */
60
    private static Canvas imgObserver = new Canvas();
61

    
62
    /** The logger for the rendering module. */
63
    private static final Logger LOGGER = Logger.getLogger(FStyledShapePainter.class
64
            .getName());
65

    
66
    /**
67
     * Invoked automatically when a polyline is about to be draw. This
68
     * implementation paints the polyline according to the rendered style
69
     *
70
     * @param graphics The graphics in which to draw.
71
     * @param shape The polyline to draw.
72
     * @param style The style to apply, or <code>null</code> if none.
73
     * @param scale The scale denominator for the current zoom level
74
     */
75
    public void paint(final Graphics2D graphics, final Shape shape,
76
        final Style2D style, final double scale) {
77
        if (style == null) {
78
            // TODO: what's going on? Should not be reached...
79
            LOGGER.severe("ShapePainter has been asked to paint a null style!!");
80

    
81
            return;
82
        }
83

    
84
        // Is the current scale within the style scale range? 
85
        if (!style.isScaleInRange(scale)) {
86
            LOGGER.fine("Out of scale");
87

    
88
            return;
89
        }
90
        
91
//        if(LOGGER.isLoggable(Level.FINE)) {
92
//            LOGGER.fine("Graphics transform: " + graphics.getTransform());
93
//        }
94

    
95
        if (style instanceof MarkStyle2D) {
96
            // get the point onto the shape has to be painted
97
            float[] coords = new float[2];
98
            PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
99
            iter.currentSegment(coords);
100

    
101
            MarkStyle2D ms2d = (MarkStyle2D) style;
102
            Shape transformedShape = ms2d.getTransformedShape(coords[0],
103
                    coords[1]);
104

    
105
            if (transformedShape != null) {
106
                if (ms2d.getFill() != null) {
107
                    graphics.setPaint(ms2d.getFill());
108
                    // graphics.setComposite(ms2d.getFillComposite());
109
                    graphics.fill(transformedShape);
110
                }
111

    
112
                if (ms2d.getContour() != null) {
113
                    graphics.setPaint(ms2d.getContour());
114
                    graphics.setStroke(ms2d.getStroke());
115
                    // graphics.setComposite(ms2d.getContourComposite());
116
                    graphics.draw(transformedShape);
117
                }
118
            }
119
        } else if (style instanceof GraphicStyle2D) {
120
            // get the point onto the shape has to be painted
121
            float[] coords = new float[2];
122
            PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
123
            iter.currentSegment(coords);
124

    
125
            GraphicStyle2D gs2d = (GraphicStyle2D) style;
126

    
127
            renderImage(graphics, coords[0], coords[1],
128
                (Image) gs2d.getImage(), gs2d.getRotation(), gs2d.getOpacity());
129
        } else if (style instanceof TextStyle2D) {
130
            // get the point onto the shape has to be painted
131
            float[] coords = new float[2];
132
            PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
133
            iter.currentSegment(coords);
134

    
135
            AffineTransform old = graphics.getTransform();
136
            AffineTransform temp = new AffineTransform(old);
137
            TextStyle2D ts2d = (TextStyle2D) style;
138
            GlyphVector textGv = ts2d.getTextGlyphVector(graphics);
139
            Rectangle2D bounds = textGv.getVisualBounds();
140

    
141
            temp.translate(coords[0], coords[1]);
142

    
143
            double x = 0;
144
            double y = 0;
145

    
146
            if (ts2d.isAbsoluteLineDisplacement()) {
147
                double offset = ts2d.getDisplacementY();
148

    
149
                if (offset > 0.0) { // to the left of the line
150
                    y = -offset;
151
                } else if (offset < 0) {
152
                    y = -offset + bounds.getHeight();
153
                } else {
154
                    y = bounds.getHeight() / 2;
155
                }
156

    
157
                x = -bounds.getWidth() / 2;
158
            } else {
159
                x = (ts2d.getAnchorX() * (-bounds.getWidth()))
160
                    + ts2d.getDisplacementX();
161
                y = (ts2d.getAnchorY() * (bounds.getHeight()))
162
                    + ts2d.getDisplacementY();
163
            }
164

    
165
            temp.rotate(ts2d.getRotation());
166
            temp.translate(x, y);
167

    
168
            try {
169
                graphics.setTransform(temp);
170
                
171
                if (ts2d.getHaloFill() != null) {
172
                    // float radious = ts2d.getHaloRadius();
173

    
174
                    // graphics.translate(radious, -radious);
175
                    graphics.setPaint(ts2d.getHaloFill());
176
                    graphics.setComposite(ts2d.getHaloComposite());
177
                    graphics.fill(ts2d.getHaloShape(graphics));
178

    
179
                    // graphics.translate(radious, radious);
180
                }
181

    
182
                if (ts2d.getFill() != null) {
183
                    graphics.setPaint(ts2d.getFill());
184
                    graphics.setComposite(ts2d.getComposite());
185
                    graphics.drawGlyphVector(textGv, 0, 0);
186
                }
187
            } finally {
188
                graphics.setTransform(old);
189
            }
190
        } else {
191
            // if the style is a polygon one, process it even if the polyline is not
192
            // closed (by SLD specification)
193
            if (style instanceof PolygonStyle2D) {
194
                PolygonStyle2D ps2d = (PolygonStyle2D) style;
195

    
196
                if (ps2d.getFill() != null) {
197
                    Paint paint = ps2d.getFill();
198

    
199
                    if (paint instanceof TexturePaint) {
200
                        TexturePaint tp = (TexturePaint) paint;
201
                        BufferedImage image = tp.getImage();
202
                        Rectangle2D rect = tp.getAnchorRect();
203
                        AffineTransform at = graphics.getTransform();
204
                        double width = rect.getWidth() * at.getScaleX();
205
                        double height = rect.getHeight() * at.getScaleY();
206
                        Rectangle2D scaledRect = new Rectangle2D.Double(0, 0,
207
                                width, height);
208
                        paint = new TexturePaint(image, scaledRect);
209
                    }
210

    
211
                    graphics.setPaint(paint);
212
                    if (ps2d.getContourComposite() != null)
213
                            graphics.setComposite(ps2d.getFillComposite());
214
                    graphics.fill(shape);
215
                }
216
            }
217

    
218
            if (style instanceof LineStyle2D) {
219
                LineStyle2D ls2d = (LineStyle2D) style;
220

    
221
                if (ls2d.getStroke() != null) {
222
                    // see if a graphic stroke is to be used, the drawing method is completely
223
                    // different in this case
224
                    if (ls2d.getGraphicStroke() != null) {
225
                        drawWithGraphicsStroke(graphics, shape,
226
                            ls2d.getGraphicStroke());
227
                    } else {
228
                        Paint paint = ls2d.getContour();
229

    
230
                        if (paint instanceof TexturePaint) {
231
                            TexturePaint tp = (TexturePaint) paint;
232
                            BufferedImage image = tp.getImage();
233
                            Rectangle2D rect = tp.getAnchorRect();
234
                            AffineTransform at = graphics.getTransform();
235
                            double width = rect.getWidth() * at.getScaleX();
236
                            double height = rect.getHeight() * at.getScaleY();
237
                            Rectangle2D scaledRect = new Rectangle2D.Double(0,
238
                                    0, width, height);
239
                            paint = new TexturePaint(image, scaledRect);
240
                        }
241

    
242
                        graphics.setPaint(paint);
243
                        graphics.setStroke(ls2d.getStroke());
244
                        if (ls2d.getContourComposite() != null)
245
                                graphics.setComposite(ls2d.getContourComposite());
246
                        graphics.draw(shape);
247
                    }
248
                }
249
            }
250
        }
251
    }
252

    
253
    // draws the image along the path
254
    private void drawWithGraphicsStroke(Graphics2D graphics, Shape shape,
255
        BufferedImage image) {
256
        PathIterator pi = shape.getPathIterator(null, 10.0);
257
        double[] coords = new double[2];
258
        int type;
259

    
260
        // I suppose the image has been already scaled and its square
261
        int imageSize = image.getWidth();
262

    
263
        double[] first = new double[2];
264
        double[] previous = new double[2];
265
        type = pi.currentSegment(coords);
266
        first[0] = coords[0];
267
        first[1] = coords[1];
268
        previous[0] = coords[0];
269
        previous[1] = coords[1];
270

    
271
        if (LOGGER.isLoggable(Level.FINEST)) {
272
            LOGGER.finest("starting at " + first[0] + "," + first[1]);
273
        }
274

    
275
        pi.next();
276

    
277
        while (!pi.isDone()) {
278
            type = pi.currentSegment(coords);
279

    
280
            switch (type) {
281
            case PathIterator.SEG_MOVETO:
282

    
283
                // nothing to do?
284
                if (LOGGER.isLoggable(Level.FINEST)) {
285
                    LOGGER.finest("moving to " + coords[0] + "," + coords[1]);
286
                }
287

    
288
                break;
289

    
290
            case PathIterator.SEG_CLOSE:
291

    
292
                // draw back to first from previous
293
                coords[0] = first[0];
294
                coords[1] = first[1];
295

    
296
                if (LOGGER.isLoggable(Level.FINEST)) {
297
                    LOGGER.finest("closing from " + previous[0] + ","
298
                        + previous[1] + " to " + coords[0] + "," + coords[1]);
299
                }
300

    
301
            // no break here - fall through to next section
302
            case PathIterator.SEG_LINETO:
303

    
304
                // draw from previous to coords
305
                if (LOGGER.isLoggable(Level.FINEST)) {
306
                    LOGGER.finest("drawing from " + previous[0] + ","
307
                        + previous[1] + " to " + coords[0] + "," + coords[1]);
308
                }
309

    
310
                double dx = coords[0] - previous[0];
311
                double dy = coords[1] - previous[1];
312
                double len = Math.sqrt((dx * dx) + (dy * dy)); // - imageWidth;
313

    
314
                double theta = Math.atan2(dx, dy);
315
                dx = (Math.sin(theta) * imageSize);
316
                dy = (Math.cos(theta) * imageSize);
317

    
318
                if (LOGGER.isLoggable(Level.FINEST)) {
319
                    LOGGER.finest("dx = " + dx + " dy " + dy + " step = "
320
                        + Math.sqrt((dx * dx) + (dy * dy)));
321
                }
322

    
323
                double rotation = -(theta - (Math.PI / 2d));
324
                double x = previous[0] + (dx / 2.0);
325
                double y = previous[1] + (dy / 2.0);
326

    
327
                if (LOGGER.isLoggable(Level.FINEST)) {
328
                    LOGGER.finest("len =" + len + " imageSize " + imageSize);
329
                }
330

    
331
                double dist = 0;
332

    
333
                for (dist = 0; dist < (len - imageSize); dist += imageSize) {
334
                    /*graphic.drawImage(image2,(int)x-midx,(int)y-midy,null); */
335
                    renderImage(graphics, x, y, image, rotation, 1);
336

    
337
                    x += dx;
338
                    y += dy;
339
                }
340

    
341
                if (LOGGER.isLoggable(Level.FINEST)) {
342
                    LOGGER.finest("loop end dist " + dist + " len " + len + " "
343
                        + (len - dist));
344
                }
345

    
346
                double remainder = len - dist;
347
                int remainingWidth = (int) remainder;
348

    
349
                if (remainingWidth > 0) {
350
                    //clip and render image
351
                    if (LOGGER.isLoggable(Level.FINEST)) {
352
                        LOGGER.finest("about to use clipped image " + remainder);
353
                    }
354

    
355
                    BufferedImage img = new BufferedImage(remainingWidth,
356
                            imageSize, image.getType());
357
                    Graphics2D ig = img.createGraphics();
358
                    ig.drawImage(image, 0, 0, imgObserver);
359

    
360
                    renderImage(graphics, x, y, img, rotation, 1);
361
                }
362

    
363
                break;
364

    
365
            default:
366
                LOGGER.warning(
367
                    "default branch reached in drawWithGraphicStroke");
368
            }
369

    
370
            previous[0] = coords[0];
371
            previous[1] = coords[1];
372
            pi.next();
373
        }
374
    }
375

    
376
    /**
377
     * Renders an image on the device
378
     *
379
     * @param graphics the image location on the screen, x coordinate
380
     * @param x the image location on the screen, y coordinate
381
     * @param y the image
382
     * @param image DOCUMENT ME!
383
     * @param rotation the image rotatation
384
     * @param opacity DOCUMENT ME!
385
     */
386
    private void renderImage(Graphics2D graphics, double x, double y,
387
        Image image, double rotation, float opacity) {
388
        if (LOGGER.isLoggable(Level.FINEST)) {
389
            LOGGER.finest("drawing Image @" + x + "," + y);
390
        }
391

    
392
        AffineTransform temp = graphics.getTransform();
393
        AffineTransform markAT = new AffineTransform();
394
        Point2D mapCentre = new java.awt.geom.Point2D.Double(x, y);
395
        Point2D graphicCentre = new java.awt.geom.Point2D.Double();
396
        temp.transform(mapCentre, graphicCentre);
397
        markAT.translate(graphicCentre.getX(), graphicCentre.getY());
398

    
399
        double shearY = temp.getShearY();
400
        double scaleY = temp.getScaleY();
401

    
402
        double originalRotation = Math.atan(shearY / scaleY);
403

    
404
        if (LOGGER.isLoggable(Level.FINER)) {
405
            LOGGER.finer("originalRotation " + originalRotation);
406
        }
407

    
408
        markAT.rotate(rotation);
409
        graphics.setTransform(markAT);
410
        graphics.setComposite(AlphaComposite.getInstance(
411
                AlphaComposite.SRC_OVER, opacity));
412

    
413
        // we moved the origin to the centre of the image.
414
        graphics.drawImage(image, -image.getWidth(imgObserver) / 2,
415
            -image.getHeight(imgObserver) / 2, imgObserver);
416

    
417
        graphics.setTransform(temp);
418

    
419
        return;
420
    }
421
}