Statistics
| Revision:

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

History | View | Annotate | Download (17.4 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
/* 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
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
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

    
89

    
90
/**
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
        } 
131
        
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
                // SI ES UN RECTANGULO, ES MEJOR USAR g.fillRect, es mucho m?s
139
                // r?pido. Para el resto, va m?s lento.
140
            float[] coords = new float[2];
141
            PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
142
            iter.currentSegment(coords); 
143

    
144
            MarkStyle2D ms2d = (MarkStyle2D) style;
145
            Shape transformedShape = ms2d.getTransformedShape(coords[0],
146
                    coords[1]);  
147
            // Shape transformedShape = shape;
148

    
149
            if (transformedShape != null) {
150
                if (ms2d.getFill() != null) {
151
                    graphics.setPaint(ms2d.getFill());
152
                    // graphics.setComposite(ms2d.getFillComposite());
153
                    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
                }
165

    
166
                if (ms2d.getContour() != null) {
167
                    graphics.setPaint(ms2d.getContour());
168
                    graphics.setStroke(ms2d.getStroke());
169
                    // graphics.setComposite(ms2d.getContourComposite());
170
                    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
                   /// TODO graphics.setComposite(ts2d.getComposite());
239
                    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
                    if (ps2d.getContourComposite() != null)
267
                            graphics.setComposite(ps2d.getFillComposite());
268
                    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
}