    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/graphics/sld/Mark.java $
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036    package org.deegree.graphics.sld;
    037
    038    import static org.deegree.framework.xml.XMLTools.escape;
    039
    040    import java.awt.BasicStroke;
    041    import java.awt.Color;
    042    import java.awt.FontMetrics;
    043    import java.awt.Graphics2D;
    044    import java.awt.Polygon;
    045    import java.awt.image.BufferedImage;
    046
    047    import org.deegree.framework.util.StringTools;
    048    import org.deegree.framework.xml.Marshallable;
    049    import org.deegree.model.feature.Feature;
    050    import org.deegree.model.filterencoding.FilterEvaluationException;
    051
    052    /**
    053     * A Mark takes a "shape" and applies coloring to it. The shape can be derived either from a well-known name (such as
    054     * "square"), an external URL in various formats (such as, perhaps GIF), or from a glyph of a font. Multiple external
    055     * formats may be used with the semantic that they all contain the equivalent shape in different formats. If an image
    056     * format is used that has inherent coloring, the coloring is discarded and only the opacity channel (or equivalent) is
    057     * used. A Halo, Fill, and/or Stroke is applied as appropriate for the shape's source format.
    058     * <p>
    059     *
    060     * @author <a href="mailto:k.lupp@web.de">Katharina Lupp </a>
    061     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
    062     * @version $Revision: 18195 $ $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    063     */
    064
    065    public class Mark implements Marshallable {
    066
    067        private BufferedImage image = null;
    068
    069        private Fill fill = null;
    070
    071        private String wellKnownName = null;
    072
    073        private Stroke stroke = null;
    074
    075        /**
    076         * Constructor for the default <tt>Mark</tt>.
    077         */
    078        Mark() {
    079            // nothing to do
    080        }
    081
    082        /**
    083         * constructor initializing the class with the <Mark>
    084         *
    085         * @param wellKnownName
    086         * @param stroke
    087         * @param fill
    088         */
    089        Mark( String wellKnownName, Stroke stroke, Fill fill ) {
    090            setWellKnownName( wellKnownName );
    091            setStroke( stroke );
    092            setFill( fill );
    093        }
    094
    095        /**
    096         * Gives the well known name of a Mark's shape. Allowed values include at least "square", "circle", "triangle",
    097         * "star", "cross", and "x", though map servers may draw a different symbol instead if they don't have a shape for
    098         * all of these. Renderings of these marks may be made solid or hollow depending on Fill and Stroke parameters. The
    099         * default value is "square".
    100         *
    101         * @return the WK-Name of the mark
    102         *
    103         */
    104        public String getWellKnownName() {
    105            return wellKnownName;
    106        }
    107
    108        /**
    109         * Sets the well known name of a Mark's shape. Allowed values include at least "square", "circle", "triangle",
    110         * "star", "cross", and "x", though map servers may draw a different symbol instead if they don't have a shape for
    111         * all of these. Renderings of these marks may be made solid or hollow depending on Fill and Stroke parameters. The
    112         * default value is "square".
    113         *
    114         * @param wellKnownName
    115         *            the WK-Name of the mark
    116         *
    117         */
    118        public void setWellKnownName( String wellKnownName ) {
    119            this.wellKnownName = wellKnownName;
    120        }
    121
    122        /**
    123         * A Fill allows area geometries to be filled. There are two types of fills: solid-color and repeated GraphicFill.
    124         * In general, if a Fill element is omitted in its containing element, no fill will be rendered. The default is a
    125         * solid 50%-gray (color "#808080") opaque fill.
    126         *
    127         * @return the fill of the mark
    128         */
    129        public Fill getFill() {
    130            return fill;
    131        }
    132
    133        /**
    134         * sets the <Fill>
    135         *
    136         * @param fill
    137         *            the fill of the mark
    138         */
    139        public void setFill( Fill fill ) {
    140            this.fill = fill;
    141        }
    142
    143        /**
    144         * A Stroke allows a string of line segments (or any linear geometry) to be rendered. There are three basic types of
    145         * strokes: solid Color, GraphicFill (stipple), and repeated GraphicStroke. A repeated graphic is plotted linearly
    146         * and has its graphic symbol bended around the curves of the line string. The default is a solid black line (Color
    147         * "#000000").
    148         *
    149         * @return the stroke of the mark
    150         */
    151        public Stroke getStroke() {
    152            return stroke;
    153        }
    154
    155        /**
    156         * sets <Stroke>
    157         *
    158         * @param stroke
    159         *            the stroke of the mark
    160         */
    161        public void setStroke( Stroke stroke ) {
    162            this.stroke = stroke;
    163        }
    164
    165        /**
    166         * Draws the given feature on the buffered image. The drawing values are used from the 'Fill' object (if set). or
    167         * white as a default fill color and black as a stroke color. If the stroke is null the BasicStroke values
    168         * (CAP_ROUND, JOIN_ROUND) will be used.
    169         * <p>
    170         * Be careful to set the buffered image first!.
    171         *
    172         * @param feature
    173         *
    174         * @param size
    175         *            DOCUMENT ME!
    176         *
    177         * @return The feature as a buffered image with a the 'Fill' values. or white as a default fill color and black as a
    178         *         stroke color.
    179         * @throws FilterEvaluationException
    180         */
    181        public BufferedImage getAsImage( Feature feature, int size )
    182                                throws FilterEvaluationException {
    183            double fillOpacity = 1.0;
    184            double strokeOpacity = 1.0;
    185            float[] dash = null;
    186            float dashOffset = 0;
    187            int cap = BasicStroke.CAP_ROUND;
    188            int join = BasicStroke.JOIN_ROUND;
    189            float width = 1;
    190            Color fillColor = new Color( 128, 128, 128 );
    191            Color strokeColor = new Color( 0, 0, 0 );
    192
    193            if ( fill != null ) {
    194                fillOpacity = fill.getOpacity( feature );
    195                fillColor = fill.getFill( feature );
    196            }
    197
    198            if ( stroke != null ) {
    199                strokeOpacity = stroke.getOpacity( feature );
    200                strokeColor = stroke.getStroke( feature );
    201                dash = stroke.getDashArray( feature );
    202                cap = stroke.getLineCap( feature );
    203                join = stroke.getLineJoin( feature );
    204                width = (float) stroke.getWidth( feature );
    205                dashOffset = stroke.getDashOffset( feature );
    206            }
    207
    208            if ( wellKnownName == null ) {
    209                wellKnownName = "square";
    210            }
    211
    212            if ( wellKnownName.equalsIgnoreCase( "circle" ) ) {
    213                image = drawCircle( size, fillOpacity, fillColor, strokeOpacity, strokeColor, dash, dashOffset, width, cap,
    214                                    join );
    215            } else if ( wellKnownName.equalsIgnoreCase( "triangle" ) ) {
    216                image = drawTriangle( size, fillOpacity, fillColor, strokeOpacity, strokeColor, dash, dashOffset, width,
    217                                      cap, join );
    218            } else if ( wellKnownName.equalsIgnoreCase( "cross" ) ) {
    219                image = drawCross1( size, strokeOpacity, strokeColor, dash, dashOffset, width, cap, join );
    220            } else if ( wellKnownName.equalsIgnoreCase( "x" ) ) {
    221                image = drawCross2( size, strokeOpacity, strokeColor, dash, dashOffset, width, cap, join );
    222            } else if ( wellKnownName.startsWith( "CHAR" ) ) {
    223                image = drawCharacter( size, fillOpacity, fillColor, strokeOpacity, strokeColor, wellKnownName );
    224            } else if ( wellKnownName.equalsIgnoreCase( "star" ) ) {
    225                image = drawStar( size, fillOpacity, fillColor, strokeOpacity, strokeColor, dash, dashOffset, width, cap,
    226                                  join );
    227            } else {
    228                image = drawSquare( size, fillOpacity, fillColor, strokeOpacity, strokeColor, dash, dashOffset, width, cap,
    229                                    join );
    230            }
    231
    232            return image;
    233        }
    234
    235        /**
    236         * Sets the mark as an image. RThis method is not part of the sld specifications but it is added to speed up
    237         * applications.
    238         *
    239         * @param bufferedImage
    240         *            the bufferedImage to be set for the mark
    241         */
    242        public void setAsImage( BufferedImage bufferedImage ) {
    243            this.image = bufferedImage;
    244        }
    245
    246        /**
    247         *
    248         * @param dash
    249         * @param dashOffset
    250         * @param width
    251         * @param cap
    252         * @param join
    253         * @return the basic stroke
    254         */
    255        private BasicStroke createBasicStroke( float[] dash, float dashOffset, float width, int cap, int join ) {
    256            BasicStroke bs2 = null;
    257            if ( ( dash == null ) || ( dash.length < 2 ) ) {
    258                bs2 = new BasicStroke( width, cap, join );
    259            } else {
    260                bs2 = new BasicStroke( width, cap, join, 10.0f, dash, dashOffset );
    261            }
    262            return bs2;
    263        }
    264
    265        /**
    266         * Draws a scaled instance of a triangle mark according to the given parameters.
    267         *
    268         * @param size
    269         *            resulting image's height and width
    270         * @param fillOpacity
    271         *            opacity value for the filled parts of the image
    272         * @param fillColor
    273         *            <tt>Color</tt> to be used for the fill
    274         * @param strokeOpacity
    275         *            opacity value for the stroked parts of the image
    276         * @param strokeColor
    277         *            <tt>Color</tt> to be used for the strokes
    278         * @param dash
    279         *            dash array for rendering boundary line
    280         * @param width
    281         *            of the boundary line
    282         * @param cap
    283         *            of the boundary line
    284         * @param join
    285         *            of the boundary line
    286         * @param dashOffset
    287         *
    288         * @return image displaying a triangle
    289         */
    290        public BufferedImage drawTriangle( int size, double fillOpacity, Color fillColor, double strokeOpacity,
    291                                           Color strokeColor, float[] dash, float dashOffset, float width, int cap, int join ) {
    292
    293            int offset = (int) ( width * 2 + 1 ) / 2;
    294            BufferedImage image = new BufferedImage( size + offset * 2, size + offset * 2, BufferedImage.TYPE_INT_ARGB );
    295
    296            int[] x_ = new int[3];
    297            int[] y_ = new int[3];
    298            x_[0] = offset;
    299            y_[0] = offset;
    300            x_[1] = size / 2 + offset;
    301            y_[1] = size - 1 + offset;
    302            x_[2] = size - 1 + offset;
    303            y_[2] = offset;
    304
    305            Graphics2D g2D = (Graphics2D) image.getGraphics();
    306            BasicStroke bs = createBasicStroke( dash, dashOffset, width, cap, join );
    307            g2D.setStroke( bs );
    308            setColor( g2D, fillColor, fillOpacity );
    309            g2D.fillPolygon( x_, y_, 3 );
    310            setColor( g2D, strokeColor, strokeOpacity );
    311            g2D.drawPolygon( x_, y_, 3 );
    312
    313            return image;
    314        }
    315
    316        /**
    317         * Draws a five-pointed star (pentagram) according to the given parameters.
    318         *
    319         * @param size
    320         *            resulting image's height and width
    321         * @param fillOpacity
    322         *            opacity value for the filled parts of the image
    323         * @param fillColor
    324         *            <tt>Color</tt> to be used for the fill
    325         * @param strokeOpacity
    326         *            opacity value for the stroked parts of the image
    327         * @param strokeColor
    328         *            <tt>Color</tt> to be used for the strokes
    329         * @param dash
    330         *            dash array for rendering boundary line
    331         * @param width
    332         *            of the boundary line
    333         * @param cap
    334         *            of the boundary line
    335         * @param join
    336         *            of the boundary line
    337         * @param dashOffset
    338         *
    339         * @return an image of a pentagram
    340         */
    341        public BufferedImage drawStar( int size, double fillOpacity, Color fillColor, double strokeOpacity,
    342                                       Color strokeColor, float[] dash, float dashOffset, float width, int cap, int join ) {
    343            int offset = (int) ( width * 2 + 1 ) / 2;
    344            BufferedImage image = new BufferedImage( size + offset * 2, size + offset * 2, BufferedImage.TYPE_INT_ARGB );
    345
    346            Graphics2D g2D = image.createGraphics();
    347            BasicStroke bs = createBasicStroke( dash, dashOffset, width, cap, join );
    348            g2D.setStroke( bs );
    349            int s = size / 2;
    350            int x0 = s;
    351            int y0 = s;
    352            double sin36 = Math.sin( Math.toRadians( 36 ) );
    353            double cos36 = Math.cos( Math.toRadians( 36 ) );
    354            double sin18 = Math.sin( Math.toRadians( 18 ) );
    355            double cos18 = Math.cos( Math.toRadians( 18 ) );
    356            int smallRadius = (int) ( s * sin18 / Math.sin( Math.toRadians( 54 ) ) );
    357
    358            int p0X = x0;
    359            int p0Y = y0 - s;
    360            int p1X = x0 + (int) ( smallRadius * sin36 );
    361            int p1Y = y0 - (int) ( smallRadius * cos36 );
    362            int p2X = x0 + (int) ( s * cos18 );
    363            int p2Y = y0 - (int) ( s * sin18 );
    364            int p3X = x0 + (int) ( smallRadius * cos18 );
    365            int p3Y = y0 + (int) ( smallRadius * sin18 );
    366            int p4X = x0 + (int) ( s * sin36 );
    367            int p4Y = y0 + (int) ( s * cos36 );
    368            int p5Y = y0 + smallRadius;
    369            int p6X = x0 - (int) ( s * sin36 );
    370            int p7X = x0 - (int) ( smallRadius * cos18 );
    371            int p8X = x0 - (int) ( s * cos18 );
    372            int p9X = x0 - (int) ( smallRadius * sin36 );
    373
    374            int[] x = new int[] { p0X, p1X, p2X, p3X, p4X, p0X, p6X, p7X, p8X, p9X };
    375            int[] y = new int[] { p0Y, p1Y, p2Y, p3Y, p4Y, p5Y, p4Y, p3Y, p2Y, p1Y };
    376            for ( int i = 0; i < y.length; i++ ) {
    377                x[i] = x[i] + offset;
    378                y[i] = y[i] + offset;
    379            }
    380            Polygon shape = new Polygon( x, y, 10 );
    381
    382            setColor( g2D, fillColor, fillOpacity );
    383            g2D.fill( shape );
    384            setColor( g2D, strokeColor, strokeOpacity );
    385            g2D.draw( shape );
    386
    387            g2D.dispose();
    388
    389            return image;
    390        }
    391
    392        /**
    393         * Draws a scaled instance of a circle mark according to the given parameters.
    394         *
    395         * @param size
    396         *            resulting image's height and widthh
    397         * @param fillOpacity
    398         *            opacity value for the filled parts of the image
    399         * @param fillColor
    400         *            <tt>Color</tt> to be used for the fill
    401         * @param strokeOpacity
    402         *            opacity value for the stroked parts of the image
    403         * @param strokeColor
    404         *            <tt>Color</tt> to be used for the strokes
    405         * @param dash
    406         *            dash array for rendering boundary line
    407         * @param width
    408         *            of the boundary line
    409         * @param cap
    410         *            of the boundary line
    411         * @param join
    412         *            of the boundary line
    413         * @param dashOffset
    414         *
    415         * @return image displaying a circle
    416         */
    417        public BufferedImage drawCircle( int size, double fillOpacity, Color fillColor, double strokeOpacity,
    418                                         Color strokeColor, float[] dash, float dashOffset, float width, int cap, int join ) {
    419            int offset = (int) ( width * 2 + 1 ) / 2;
    420            BufferedImage image = new BufferedImage( size + offset * 2, size + offset * 2, BufferedImage.TYPE_INT_ARGB );
    421
    422            Graphics2D g2D = (Graphics2D) image.getGraphics();
    423            BasicStroke bs = createBasicStroke( dash, dashOffset, width, cap, join );
    424            g2D.setStroke( bs );
    425            setColor( g2D, fillColor, fillOpacity );
    426            g2D.fillOval( offset, offset, size, size );
    427
    428            setColor( g2D, strokeColor, strokeOpacity );
    429            g2D.drawOval( offset, offset, size, size );
    430
    431            return image;
    432        }
    433
    434        /**
    435         * Draws a scaled instance of a square mark according to the given parameters.
    436         *
    437         * @param size
    438         *            resulting image's height and widthh
    439         * @param fillOpacity
    440         *            opacity value for the filled parts of the image
    441         * @param fillColor
    442         *            <tt>Color</tt> to be used for the fill
    443         * @param strokeOpacity
    444         *            opacity value for the stroked parts of the image
    445         * @param strokeColor
    446         *            <tt>Color</tt> to be used for the strokes
    447         * @param dash
    448         *            dash array for rendering boundary line
    449         * @param width
    450         *            of the boundary line
    451         * @param cap
    452         *            of the boundary line
    453         * @param join
    454         *            of the boundary line
    455         * @param dashOffset
    456         *
    457         * @return image displaying a square
    458         */
    459        public BufferedImage drawSquare( int size, double fillOpacity, Color fillColor, double strokeOpacity,
    460                                         Color strokeColor, float[] dash, float dashOffset, float width, int cap, int join ) {
    461            int offset = (int) ( width * 2 + 1 ) / 2;
    462            BufferedImage image = new BufferedImage( size + offset * 2, size + offset * 2, BufferedImage.TYPE_INT_ARGB );
    463
    464            Graphics2D g2D = (Graphics2D) image.getGraphics();
    465            BasicStroke bs = createBasicStroke( dash, dashOffset, width, cap, join );
    466            g2D.setStroke( bs );
    467            setColor( g2D, fillColor, fillOpacity );
    468            g2D.fillRect( offset, offset, size, size );
    469
    470            setColor( g2D, strokeColor, strokeOpacity );
    471            g2D.drawRect( offset, offset, size - 1, size - 1 );
    472
    473            return image;
    474        }
    475
    476        /**
    477         * Draws a scaled instance of a cross mark (a "+") according to the given parameters.
    478         *
    479         * @param size
    480         *            resulting image's height and widthh
    481         * @param strokeOpacity
    482         *            opacity value for the stroked parts of the image
    483         * @param strokeColor
    484         *            <tt>Color</tt> to be used for the strokes
    485         * @param dash
    486         *            dash array for rendering boundary line
    487         * @param width
    488         *            of the boundary line
    489         * @param cap
    490         *            of the boundary line
    491         * @param join
    492         *            of the boundary line
    493         * @param dashOffset
    494         *
    495         * @return image displaying a cross (a "+")
    496         */
    497        public BufferedImage drawCross1( int size, double strokeOpacity, Color strokeColor, float[] dash, float dashOffset,
    498                                         float width, int cap, int join ) {
    499
    500            int offset = (int) ( width * 2 + 1 ) / 2;
    501            BufferedImage image = new BufferedImage( size + offset * 2, size + offset * 2, BufferedImage.TYPE_INT_ARGB );
    502
    503            Graphics2D g2D = (Graphics2D) image.getGraphics();
    504
    505            BasicStroke bs = createBasicStroke( dash, dashOffset, width, cap, join );
    506            g2D.setStroke( bs );
    507
    508            setColor( g2D, strokeColor, strokeOpacity );
    509            g2D.drawLine( offset, size / 2 + offset, size - 1 + offset, size / 2 + offset );
    510            g2D.drawLine( size / 2 + offset, offset, size / 2 + offset, size - 1 + offset );
    511
    512            return image;
    513        }
    514
    515        /**
    516         * Draws a scaled instance of a cross mark (an "X") according to the given parameters.
    517         *
    518         * @param size
    519         *            resulting image's height and widthh
    520         * @param strokeOpacity
    521         *            opacity value for the stroked parts of the image
    522         * @param strokeColor
    523         *            <tt>Color</tt> to be used for the strokes
    524         * @param dash
    525         *            dash array for rendering boundary line
    526         * @param width
    527         *            of the boundary line
    528         * @param cap
    529         *            of the boundary line
    530         * @param join
    531         *            of the boundary line
    532         * @param dashOffset
    533         *
    534         * @return image displaying a cross (a "X")
    535         */
    536        public BufferedImage drawCross2( int size, double strokeOpacity, Color strokeColor, float[] dash, float dashOffset,
    537                                         float width, int cap, int join ) {
    538
    539            int offset = (int) ( width * 2 + 1 ) / 2;
    540            BufferedImage image = new BufferedImage( size + offset * 2, size + offset * 2, BufferedImage.TYPE_INT_ARGB );
    541
    542            Graphics2D g2D = (Graphics2D) image.getGraphics();
    543
    544            BasicStroke bs = createBasicStroke( dash, dashOffset, width, cap, join );
    545            g2D.setStroke( bs );
    546
    547            setColor( g2D, strokeColor, strokeOpacity );
    548            g2D.drawLine( offset, offset, size - 1 + offset, size - 1 + offset );
    549            g2D.drawLine( offset, size - 1 + offset, size - 1 + offset, offset );
    550
    551            return image;
    552        }
    553
    554        /**
    555         *
    556         * @param size
    557         * @param fillOpacity
    558         * @param fillColor
    559         * @param strokeOpacity
    560         * @param strokeColor
    561         * @param charDesc
    562         *            e.g. CHAR:Times New Roman:45
    563         */
    564        private BufferedImage drawCharacter( int size, double fillOpacity, Color fillColor, double strokeOpacity,
    565                                             Color strokeColor, String charDesc ) {
    566
    567            String[] tmp = StringTools.toArray( charDesc, ":", false );
    568
    569            BufferedImage image = new BufferedImage( size, size, BufferedImage.TYPE_INT_ARGB );
    570
    571            Graphics2D g2 = (Graphics2D) image.getGraphics();
    572            setColor( g2, fillColor, fillOpacity );
    573            g2.fillRect( 0, 0, size, size );
    574
    575            java.awt.Font font = new java.awt.Font( tmp[1], java.awt.Font.PLAIN, size );
    576            g2.setFont( font );
    577            FontMetrics fm = g2.getFontMetrics();
    578
    579            char c = (char) Integer.parseInt( tmp[2] );
    580            int w = fm.charWidth( c );
    581            int h = fm.getHeight();
    582
    583            String s = "" + c;
    584            setColor( g2, strokeColor, strokeOpacity );
    585            g2.drawString( s, size / 2 - w / 2, size / 2 + h / 2 - fm.getDescent() );
    586            g2.dispose();
    587            return image;
    588        }
    589
    590        /**
    591         * @param g2D
    592         * @param color
    593         * @param opacity
    594         */
    595        private void setColor( Graphics2D g2D, Color color, double opacity ) {
    596            if ( opacity < 0.999 ) {
    597                final int alpha = (int) Math.round( opacity * 255 );
    598                final int red = color.getRed();
    599                final int green = color.getGreen();
    600                final int blue = color.getBlue();
    601                color = new Color( red, green, blue, alpha );
    602            }
    603
    604            g2D.setColor( color );
    605        }
    606
    607        /**
    608         * exports the content of the Mark as XML formated String
    609         *
    610         * @return xml representation of the Mark
    611         */
    612        public String exportAsXML() {
    613
    614            StringBuffer sb = new StringBuffer( 1000 );
    615            sb.append( "<Mark>" );
    616            if ( wellKnownName != null && !wellKnownName.equals( "" ) ) {
    617                sb.append( "<WellKnownName>" ).append( escape( wellKnownName ) );
    618                sb.append( "</WellKnownName>" );
    619            }
    620            if ( fill != null ) {
    621                sb.append( ( (Marshallable) fill ).exportAsXML() );
    622            }
    623            if ( stroke != null ) {
    624                sb.append( ( (Marshallable) stroke ).exportAsXML() );
    625            }
    626
    627            sb.append( "</Mark>" );
    628
    629            return sb.toString();
    630        }
    631
    632        // private void drawUnicode(Graphics2D g2, int x, int y, double rotation,
    633        // double size, String m, Mark mark) {
    634        // int sz = (int)size;
    635        // double fo = mark.getFill().getOpacity();
    636        // double so = mark.getStroke().getOpacity();
    637        //
    638        // java.awt.Font font = new java.awt.Font("sans serif", java.awt.Font.PLAIN,
    639        // sz);
    640        // g2.setFont( font );
    641        // FontMetrics fm = g2.getFontMetrics();
    642        //
    643        // char c = (char)m.charAt(0);
    644        // int w = fm.charWidth(c);
    645        // int h = fm.getHeight();
    646        //
    647        // g2 = setColor( g2, mark.getFill().getFill(), fo );
    648        // g2.fillRect( x-w/2, y-h/2, w, h);
    649        // g2 = setColor( g2, mark.getStroke().getStroke(), so );
    650        //
    651        // String s = "" + c;
    652        // g2.drawString( s, x-w/2, y+h/2-fm.getDescent());
    653        // }
    654        // else {
    655        //
    656        // Mark[] marks = sym.getGraphic().getMarks();
    657        // double rotation = sym.getGraphic().getRotation();
    658        // double size = sym.getGraphic().getSize();
    659        // if (marks != null) {
    660        //
    661        // for (int k = 0; k > marks.length; k++) {
    662        //
    663        // float w = (float)marks[k].getStroke().getWidth();
    664        // g2.setStroke( new BasicStroke( w ) );
    665        //
    666        // if (marks[k].getWellKnownName().equalsIgnoreCase("triangle") ) {
    667        // drawTriangle( g2, x, y, rotation, size, marks[k] );
    668        // }
    669        // else
    670        // if (marks[k].getWellKnownName().equalsIgnoreCase("circle") ) {
    671        // drawCircle( g2, x, y, rotation, size, marks[k] );
    672        // }
    673        // else
    674        // if (marks[k].getWellKnownName().equalsIgnoreCase("square") ) {
    675        // drawSquare( g2, x, y, rotation, size, marks[k] );
    676        // }
    677        // else
    678        // if (marks[k].getWellKnownName().equalsIgnoreCase("cross") ) {
    679        // drawCross1( g2, x, y, rotation, size, marks[k] );
    680        // }
    681        // else
    682        // if (marks[k].getWellKnownName().equalsIgnoreCase("x") ) {
    683        // drawCross2( g2, x, y, rotation, size, marks[k] );
    684        // }
    685        // else
    686        // if (marks[k].getWellKnownName().length() == 0 ) {
    687        // drawSquare( g2, x, y, rotation, size, marks[k] );
    688        // }
    689        // else {
    690        // drawUnicode( g2, x, y, rotation, size,
    691        // marks[k].getWellKnownName(), marks[k] );
    692        // }
    693        // }
    694        // }
    695        // }
    696    }