Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_mapcontext / src / org / gvsig / fmap / mapcontext / rendering / legend / styling / TextPath.java @ 21298

History | View | Annotate | Download (7.85 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41

    
42
/* CVS MESSAGES:
43
*
44
* $Id: TextPath.java 21105 2008-06-03 10:20:03Z vcaballero $
45
* $Log$
46
* Revision 1.2  2007-03-09 11:20:57  jaume
47
* Advanced symbology (start committing)
48
*
49
* Revision 1.1.2.3  2007/02/21 07:34:09  jaume
50
* labeling starts working
51
*
52
* Revision 1.1.2.2  2007/02/09 07:47:05  jaume
53
* Isymbol moved
54
*
55
* Revision 1.1.2.1  2007/02/06 17:01:04  jaume
56
* first version (only lines)
57
*
58
*
59
*/
60
package org.gvsig.fmap.mapcontext.rendering.legend.styling;
61

    
62
import java.awt.Font;
63
import java.awt.Graphics2D;
64
import java.awt.font.FontRenderContext;
65
import java.awt.font.GlyphVector;
66
import java.awt.geom.Point2D;
67

    
68
import org.apache.batik.ext.awt.geom.PathLength;
69
import org.apache.log4j.Logger;
70
import org.gvsig.fmap.geom.Geometry;
71
import org.gvsig.fmap.mapcontext.Messages;
72
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
73
import org.gvsig.fmap.mapcontext.rendering.symbols.ITextSymbol;
74

    
75
/**
76
 * <p>Class that represents baseline of a string and allows the baseline to
77
 * be composed as contiguous segments with distinct slope each.<br></p>
78
 *
79
 * <p>Once a TextPath is created for a string it is possible to know where
80
 * the character at a determined position in the string is placed and
81
 * rotated.<br></p>
82
 *
83
 * @author jaume dominguez faus - jaume.dominguez@iver.es
84
 *
85
 */
86
public class TextPath {
87

    
88
        public static final int NO_POS = -9999;
89
        private char[] text;
90
        private double[][] pos;
91
        private int alignment;
92
        private float characterSpacing;
93
        private boolean kerning;
94
        private float wordSpacing;
95
        private float margin;
96
        private boolean rightToLeft;
97
        private int numGlyphs;
98
        private float characterWidth;
99

    
100
        /**
101
         * <p>Creates a new instance of TextPath with the current graphics
102
         * context.<br></p>
103
         *
104
         * <p>Given a <b>Graphics2D</b>, TextPath can know which Font and FontRenderContext
105
         * is in use. So, it can calculate the position and rotation of each
106
         * character in <b>char[] text</b> based in the path defined by the
107
         * <b>FShape path</b> argument.</p>
108
         * @param g, Graphics2D
109
         * @param path, FShape
110
         * @param text, char[]
111
         */
112
        public TextPath(Graphics2D g, Geometry path, char[] text, Font font,
113
                        float characterSpacing, float characterWidth, boolean kerning,
114
                        float leading, int alignment, float wordSpacing, float margin,
115
                        boolean rightToLeft) {
116
                this.text = text;
117
                if (alignment == ITextSymbol.SYMBOL_STYLE_ALIGNMENT_LEFT ||
118
                                alignment == ITextSymbol.SYMBOL_STYLE_ALIGNMENT_RIGHT ||
119
                                alignment == ITextSymbol.SYMBOL_STYLE_ALIGNMENT_CENTERED ||
120
                                alignment == ITextSymbol.SYMBOL_STYLE_ALIGNMENT_JUSTIFY) {
121
                        this.alignment = alignment;
122
                } else throw new IllegalArgumentException(
123
                                Messages.getString("invalid_value_for") + ": " +
124
                                Messages.getString("alignment")+" ( "+alignment+")");
125
                this.characterWidth = characterWidth;
126
                this.characterSpacing = characterSpacing;
127
                this.kerning = kerning;
128
                this.wordSpacing = wordSpacing;
129
                this.margin = margin;
130
                this.rightToLeft = rightToLeft;
131

    
132
                compute(g, path);
133
        }
134

    
135
        /**
136
         * Initializes the position vector.
137
         * @param g
138
         * @param path
139
         */
140
        private void compute(Graphics2D g, Geometry path) {
141
                PathLength pl = new PathLength(path);
142

    
143
                Font font = g.getFont();
144
                FontRenderContext frc = g.getFontRenderContext();
145

    
146
                /* java 6 code
147
                 * TODO keep this!!
148
                if (kerning) {
149
                        HashMap<TextAttribute, Object> attrs = new HashMap<TextAttribute, Object>();
150
                        attrs.put(TextAttribute.KERNING , TextAttribute.KERNING_ON);
151
                }
152
                */
153

    
154
                GlyphVector gv = font.createGlyphVector(frc, text);
155

    
156
                numGlyphs = gv.getNumGlyphs();
157
                pos = new double[numGlyphs][3];
158
                float[] charAnchors = new float[numGlyphs];
159

    
160
                float leftMargin = 0;
161
                float rightMargin = 0;
162

    
163
                // first compute margins and substract it to the distance available
164
                // for the glyphs
165
                if (alignment == ITextSymbol.SYMBOL_STYLE_ALIGNMENT_LEFT) {
166
                        leftMargin = margin;
167
                } else if (alignment == ITextSymbol.SYMBOL_STYLE_ALIGNMENT_CENTERED){
168
                        float halfMargin = margin*0.5f;
169
                        leftMargin = halfMargin;
170
                        rightMargin = halfMargin;
171
                } else if (alignment == ITextSymbol.SYMBOL_STYLE_ALIGNMENT_RIGHT) {
172
                        rightMargin = margin;
173
                }
174

    
175
                String[] words = new String(text).split(" +");
176
                float spaceBetweenAllWords = words.length * wordSpacing;
177
                float spaceBetweenAllChars = 0;
178
                for (int i = 0; i < words.length; i++) {
179
                        spaceBetweenAllChars += words[i].length()*characterSpacing;
180
                }
181

    
182
                float lengthOfPath = pl.lengthOfPath();
183
                float lineLength = (lengthOfPath / numGlyphs)
184
                                                                - leftMargin
185
                                                                - rightMargin
186
                                                                - spaceBetweenAllWords
187
                                                                - spaceBetweenAllChars;
188

    
189
                float invLineLength = 1/lineLength;
190
                float charDistance = leftMargin;
191
                int charsCosumed = 0;
192
                for (int i = 0; i < words.length; i++) {
193
                        charAnchors[charsCosumed++] = charDistance;
194
                        for (int j = 1; j < words[i].length(); j++) {
195
                                charDistance += invLineLength*j+characterSpacing;
196
                                charAnchors[charsCosumed] = charDistance;
197
                                charDistance += Math.max(gv.getGlyphMetrics(charsCosumed).getAdvance(), characterWidth);
198
                                charsCosumed++;
199
                        }
200

    
201
                        charDistance += wordSpacing;
202
                        charsCosumed++;
203
                }
204
//                for (int i = 0; i < numGlyphs; i++) {
205
//                        if (text[i] == ' ') {
206
//                                charDistance += wordSpacing;
207
//                                charAnchors[i] = charDistance;
208
//                                while (i<numGlyphs && text[i+1] == ' ') i++;
209
//                        } else {
210
////                                if (!spaced && i > 0) {
211
//                                        // not to apply the character spacing if this is the first character of a word
212
//                                        charDistance += characterSpacing;
213
////                                }
214
//                                charDistance += invLineLength*i;
215
//
216
//                                charAnchors[i] = charDistance;
217
//
218
//                                charDistance += Math.max(gv.getGlyphMetrics(i).getAdvance(), characterWidth);
219
//                        }
220
//                }
221

    
222
                for (int i = 0; i < charAnchors.length; i++) {
223
                        float anchor = (rightToLeft) ? charAnchors[charAnchors.length-1-i] : charAnchors[i];
224
                        Point2D p = pl.pointAtLength( anchor );
225
                        if (p == null) {
226
                                Logger.getLogger(getClass()).error(
227
                                                Messages.getString("glyph_distance_out_of_range")+" "+anchor);
228
                                pos[i][0] = NO_POS;
229
                                pos[i][1] = NO_POS;
230
                                continue;
231
                        }
232
                        pos[i][0] = p.getX();
233
                        pos[i][1] = p.getY();
234
                        pos[i][2] = pl.angleAtLength( anchor );
235
                }
236
        }
237

    
238
        /**
239
         * <p>Returns the placement of the next character to draw and the corresponding
240
         * rotation in a double array of three elements with this order:</p><br>
241
         *
242
         * <p><b>double[0]</b> Position in X in the screen</p>
243
         * <p><b>double[1]</b> Position in Y in the screen</p>
244
         * <p><b>double[2]</b> Angle of the character.</p>
245
         * @return
246
         */
247
        public double[] nextPosForGlyph(int glyphIndex) {
248
                return pos[glyphIndex];
249
        }
250

    
251
        public int getGlyphCount() {
252
                return numGlyphs;
253
        }
254

    
255

    
256
}