geomerative 0.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/LICENSE +662 -0
- data/LICENSE.md +9 -0
- data/README.md +2 -0
- data/Rakefile +37 -0
- data/examples/README.md +7 -0
- data/examples/data/FreeSans.ttf +0 -0
- data/examples/data/ReplicaBold.ttf +0 -0
- data/examples/data/bot1.svg +160 -0
- data/examples/hello_svg_to_pdf.rb +26 -0
- data/examples/hello_world.rb +23 -0
- data/examples/physics_type.rb +77 -0
- data/examples/rotate_first_letter.rb +28 -0
- data/geomerative.gemspec +32 -0
- data/lib/geomerative.rb +12 -0
- data/lib/geomerative/version.rb +3 -0
- data/pom.xml +110 -0
- data/src/geomerative/FastRClip.java +2715 -0
- data/src/geomerative/RClip.java +2892 -0
- data/src/geomerative/RClosest.java +64 -0
- data/src/geomerative/RCommand.java +1941 -0
- data/src/geomerative/RContour.java +348 -0
- data/src/geomerative/RFont.java +583 -0
- data/src/geomerative/RG.java +753 -0
- data/src/geomerative/RGeomElem.java +1075 -0
- data/src/geomerative/RGroup.java +888 -0
- data/src/geomerative/RMatrix.java +401 -0
- data/src/geomerative/RMesh.java +420 -0
- data/src/geomerative/RPath.java +1095 -0
- data/src/geomerative/RPoint.java +419 -0
- data/src/geomerative/RPolygon.java +1110 -0
- data/src/geomerative/RRectangle.java +91 -0
- data/src/geomerative/RSVG.java +976 -0
- data/src/geomerative/RShape.java +2045 -0
- data/src/geomerative/RStrip.java +221 -0
- data/src/geomerative/RStyle.java +469 -0
- data/src/org/apache/batik/svggen/font/.SVGFont.java.swp +0 -0
- data/src/org/apache/batik/svggen/font/Font.java +188 -0
- data/src/org/apache/batik/svggen/font/Glyph.java +113 -0
- data/src/org/apache/batik/svggen/font/Messages.java.bak +72 -0
- data/src/org/apache/batik/svggen/font/Point.java +38 -0
- data/src/org/apache/batik/svggen/font/RandomAccessFileEmulator.java +15 -0
- data/src/org/apache/batik/svggen/font/table/ClassDef.java +42 -0
- data/src/org/apache/batik/svggen/font/table/ClassDefFormat1.java +55 -0
- data/src/org/apache/batik/svggen/font/table/ClassDefFormat2.java +49 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat.java +81 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat0.java +60 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat2.java +48 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat4.java +147 -0
- data/src/org/apache/batik/svggen/font/table/CmapFormat6.java +60 -0
- data/src/org/apache/batik/svggen/font/table/CmapIndexEntry.java +84 -0
- data/src/org/apache/batik/svggen/font/table/CmapTable.java +87 -0
- data/src/org/apache/batik/svggen/font/table/Coverage.java +50 -0
- data/src/org/apache/batik/svggen/font/table/CoverageFormat1.java +59 -0
- data/src/org/apache/batik/svggen/font/table/CoverageFormat2.java +56 -0
- data/src/org/apache/batik/svggen/font/table/CvtTable.java +48 -0
- data/src/org/apache/batik/svggen/font/table/Device.java +63 -0
- data/src/org/apache/batik/svggen/font/table/DirectoryEntry.java +73 -0
- data/src/org/apache/batik/svggen/font/table/Feature.java +56 -0
- data/src/org/apache/batik/svggen/font/table/FeatureList.java +70 -0
- data/src/org/apache/batik/svggen/font/table/FeatureRecord.java +52 -0
- data/src/org/apache/batik/svggen/font/table/FeatureTags.java +30 -0
- data/src/org/apache/batik/svggen/font/table/FpgmTable.java +38 -0
- data/src/org/apache/batik/svggen/font/table/GlyfCompositeComp.java +165 -0
- data/src/org/apache/batik/svggen/font/table/GlyfCompositeDescript.java +160 -0
- data/src/org/apache/batik/svggen/font/table/GlyfDescript.java +79 -0
- data/src/org/apache/batik/svggen/font/table/GlyfSimpleDescript.java +155 -0
- data/src/org/apache/batik/svggen/font/table/GlyfTable.java +111 -0
- data/src/org/apache/batik/svggen/font/table/GlyphDescription.java +39 -0
- data/src/org/apache/batik/svggen/font/table/GposTable.java +80 -0
- data/src/org/apache/batik/svggen/font/table/GsubTable.java +118 -0
- data/src/org/apache/batik/svggen/font/table/HeadTable.java +159 -0
- data/src/org/apache/batik/svggen/font/table/HheaTable.java +109 -0
- data/src/org/apache/batik/svggen/font/table/HmtxTable.java +99 -0
- data/src/org/apache/batik/svggen/font/table/KernSubtable.java +58 -0
- data/src/org/apache/batik/svggen/font/table/KernSubtableFormat0.java +65 -0
- data/src/org/apache/batik/svggen/font/table/KernSubtableFormat2.java +56 -0
- data/src/org/apache/batik/svggen/font/table/KernTable.java +64 -0
- data/src/org/apache/batik/svggen/font/table/KerningPair.java +53 -0
- data/src/org/apache/batik/svggen/font/table/LangSys.java +58 -0
- data/src/org/apache/batik/svggen/font/table/LangSysRecord.java +52 -0
- data/src/org/apache/batik/svggen/font/table/Ligature.java +57 -0
- data/src/org/apache/batik/svggen/font/table/LigatureSet.java +55 -0
- data/src/org/apache/batik/svggen/font/table/LigatureSubst.java +40 -0
- data/src/org/apache/batik/svggen/font/table/LigatureSubstFormat1.java +63 -0
- data/src/org/apache/batik/svggen/font/table/LocaTable.java +72 -0
- data/src/org/apache/batik/svggen/font/table/Lookup.java +77 -0
- data/src/org/apache/batik/svggen/font/table/LookupList.java +68 -0
- data/src/org/apache/batik/svggen/font/table/LookupSubtable.java +27 -0
- data/src/org/apache/batik/svggen/font/table/LookupSubtableFactory.java +31 -0
- data/src/org/apache/batik/svggen/font/table/MaxpTable.java +124 -0
- data/src/org/apache/batik/svggen/font/table/NameRecord.java +98 -0
- data/src/org/apache/batik/svggen/font/table/NameTable.java +67 -0
- data/src/org/apache/batik/svggen/font/table/Os2Table.java +232 -0
- data/src/org/apache/batik/svggen/font/table/Panose.java +108 -0
- data/src/org/apache/batik/svggen/font/table/PostTable.java +379 -0
- data/src/org/apache/batik/svggen/font/table/PrepTable.java +38 -0
- data/src/org/apache/batik/svggen/font/table/Program.java +49 -0
- data/src/org/apache/batik/svggen/font/table/RangeRecord.java +57 -0
- data/src/org/apache/batik/svggen/font/table/Script.java +72 -0
- data/src/org/apache/batik/svggen/font/table/ScriptList.java +78 -0
- data/src/org/apache/batik/svggen/font/table/ScriptRecord.java +52 -0
- data/src/org/apache/batik/svggen/font/table/ScriptTags.java +28 -0
- data/src/org/apache/batik/svggen/font/table/SingleSubst.java +47 -0
- data/src/org/apache/batik/svggen/font/table/SingleSubstFormat1.java +67 -0
- data/src/org/apache/batik/svggen/font/table/SingleSubstFormat2.java +67 -0
- data/src/org/apache/batik/svggen/font/table/Table.java +204 -0
- data/src/org/apache/batik/svggen/font/table/TableDirectory.java +94 -0
- data/src/org/apache/batik/svggen/font/table/TableFactory.java +121 -0
- metadata +206 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2004-2008 Ricard Marxer <email@ricardmarxer.com>
|
|
3
|
+
*
|
|
4
|
+
This file is part of Geomerative.
|
|
5
|
+
*
|
|
6
|
+
* Geomerative is free software: you can redistribute it and/or modify it under
|
|
7
|
+
* the terms of the GNU General Public License as published by the Free Software
|
|
8
|
+
* Foundation, either version 3 of the License, or (at your option) any later
|
|
9
|
+
* version.
|
|
10
|
+
*
|
|
11
|
+
* Geomerative is distributed in the hope that it will be useful, but WITHOUT
|
|
12
|
+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
13
|
+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
14
|
+
* details.
|
|
15
|
+
*
|
|
16
|
+
* You should have received a copy of the GNU General Public License along with
|
|
17
|
+
* Geomerative. If not, see <http://www.gnu.org/licenses/>.
|
|
18
|
+
*/
|
|
19
|
+
package geomerative;
|
|
20
|
+
|
|
21
|
+
import processing.core.*;
|
|
22
|
+
|
|
23
|
+
import java.util.List;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* RContour is a reduced interface for creating, holding and drawing contours.
|
|
27
|
+
* Contours are ordered lists of points (RPoint) which define the outlines of
|
|
28
|
+
* polygons. Contours can be self-intersecting.
|
|
29
|
+
*
|
|
30
|
+
* @eexample RContour
|
|
31
|
+
* @usage Geometry
|
|
32
|
+
* @related RPoint
|
|
33
|
+
* @related RPolygon
|
|
34
|
+
* @extended
|
|
35
|
+
*/
|
|
36
|
+
public class RContour extends RGeomElem {
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @invisible
|
|
40
|
+
*/
|
|
41
|
+
public int type = RGeomElem.CONTOUR;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Array of RPoint objects holding the points of the contour.
|
|
45
|
+
*
|
|
46
|
+
* @eexample points
|
|
47
|
+
* @related RPoint
|
|
48
|
+
* @related countPoints ( )
|
|
49
|
+
* @related addPoint ( )
|
|
50
|
+
*/
|
|
51
|
+
public RPoint[] points;
|
|
52
|
+
boolean isContributing = true;
|
|
53
|
+
boolean isHole = false;
|
|
54
|
+
boolean closed = true;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Use this method to count the number of points in the contour.
|
|
58
|
+
*
|
|
59
|
+
* @eexample countPoints
|
|
60
|
+
* @return int, the number points in the contour
|
|
61
|
+
*/
|
|
62
|
+
public int countPoints() {
|
|
63
|
+
if (this.points == null) {
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return this.points.length;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a countour given an array of points.
|
|
72
|
+
*
|
|
73
|
+
* @param contourpoints the points of the new contour
|
|
74
|
+
* @invisible
|
|
75
|
+
*/
|
|
76
|
+
public RContour(RPoint[] contourpoints) {
|
|
77
|
+
this.points = contourpoints;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public RContour() {
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public RContour(RContour c) {
|
|
84
|
+
for (int i = 0; i < c.countPoints(); i++) {
|
|
85
|
+
this.append(new RPoint(c.points[i]));
|
|
86
|
+
}
|
|
87
|
+
isHole = c.isHole;
|
|
88
|
+
isContributing = c.isContributing;
|
|
89
|
+
|
|
90
|
+
setStyle(c);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Use this method to draw the contour.
|
|
95
|
+
*
|
|
96
|
+
* @eexample drawContour
|
|
97
|
+
* @param g PGraphics, the graphics object on which to draw the contour
|
|
98
|
+
*/
|
|
99
|
+
@Override
|
|
100
|
+
public void draw(PGraphics g) {
|
|
101
|
+
int numPoints = countPoints();
|
|
102
|
+
boolean beforeFill = g.fill;
|
|
103
|
+
g.noFill();
|
|
104
|
+
g.beginShape();
|
|
105
|
+
for (int i = 0; i < numPoints; i++) {
|
|
106
|
+
g.vertex(points[i].x, points[i].y);
|
|
107
|
+
}
|
|
108
|
+
g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
|
|
109
|
+
if (beforeFill) {
|
|
110
|
+
g.fill(g.fillColor);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@Override
|
|
115
|
+
public void draw(PApplet g) {
|
|
116
|
+
int numPoints = countPoints();
|
|
117
|
+
boolean beforeFill = g.g.fill;
|
|
118
|
+
g.noFill();
|
|
119
|
+
g.beginShape();
|
|
120
|
+
for (int i = 0; i < numPoints; i++) {
|
|
121
|
+
g.vertex(points[i].x, points[i].y);
|
|
122
|
+
}
|
|
123
|
+
g.endShape(closed ? PConstants.CLOSE : PConstants.OPEN);
|
|
124
|
+
if (beforeFill) {
|
|
125
|
+
g.fill(g.g.fillColor);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Use this method to add new points to the contour.
|
|
131
|
+
*
|
|
132
|
+
* @param p
|
|
133
|
+
* @eexample addPoint ( )
|
|
134
|
+
*/
|
|
135
|
+
public void addPoint(RPoint p) {
|
|
136
|
+
this.append(p);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public void addPoint(float x, float y) {
|
|
140
|
+
this.append(new RPoint(x, y));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Efficiently add an array of points to the contour.
|
|
145
|
+
*
|
|
146
|
+
* @param morePoints
|
|
147
|
+
*/
|
|
148
|
+
public void addPoints(RPoint[] morePoints) {
|
|
149
|
+
if (points == null) {
|
|
150
|
+
this.points = morePoints;
|
|
151
|
+
} else {
|
|
152
|
+
RPoint[] newPoints = new RPoint[this.points.length + morePoints.length];
|
|
153
|
+
System.arraycopy(this.points, 0, newPoints, 0, this.points.length);
|
|
154
|
+
System.arraycopy(morePoints, 0, newPoints, this.points.length, morePoints.length);
|
|
155
|
+
this.points = newPoints;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Efficiently add a list of points to the contour.
|
|
161
|
+
*
|
|
162
|
+
* @param morePoints
|
|
163
|
+
*/
|
|
164
|
+
public void addPoints(List<RPoint> morePoints) {
|
|
165
|
+
int start = 0;
|
|
166
|
+
if (points == null) {
|
|
167
|
+
this.points = new RPoint[morePoints.size()];
|
|
168
|
+
} else {
|
|
169
|
+
RPoint[] newPoints = new RPoint[this.points.length + morePoints.size()];
|
|
170
|
+
System.arraycopy(this.points, 0, newPoints, 0, this.points.length);
|
|
171
|
+
this.points = newPoints;
|
|
172
|
+
start = morePoints.size();
|
|
173
|
+
}
|
|
174
|
+
// it would be nice to be able to access the ArrayList's internal array!
|
|
175
|
+
for (int i = start, j = 0; i < points.length; i++) {
|
|
176
|
+
points[i] = morePoints.get(j);
|
|
177
|
+
j++;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Use this to return the points of the contour. It returns the points in
|
|
183
|
+
* the way of an array of RPoint.
|
|
184
|
+
*
|
|
185
|
+
* @eexample RContour_getHandles
|
|
186
|
+
* @return RPoint[], the points returned in an array.
|
|
187
|
+
*
|
|
188
|
+
*/
|
|
189
|
+
@Override
|
|
190
|
+
public RPoint[] getHandles() {
|
|
191
|
+
return points;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Use this to return the points of the contour. It returns the points in
|
|
196
|
+
* the way of an array of RPoint.
|
|
197
|
+
*
|
|
198
|
+
* @eexample RContour_getPoints
|
|
199
|
+
* @return RPoint[], the points returned in an array.
|
|
200
|
+
*
|
|
201
|
+
*/
|
|
202
|
+
@Override
|
|
203
|
+
public RPoint[] getPoints() {
|
|
204
|
+
return points;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
*
|
|
209
|
+
* @param t
|
|
210
|
+
* @return
|
|
211
|
+
*/
|
|
212
|
+
@Override
|
|
213
|
+
public RPoint getPoint(float t) {
|
|
214
|
+
PApplet.println("Feature not yet implemented for this class.");
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@Override
|
|
219
|
+
public RPoint getTangent(float t) {
|
|
220
|
+
PApplet.println("Feature not yet implemented for this class.");
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@Override
|
|
225
|
+
public RPoint[] getTangents() {
|
|
226
|
+
PApplet.println("Feature not yet implemented for this class.");
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@Override
|
|
231
|
+
public RPoint[][] getPointsInPaths() {
|
|
232
|
+
PApplet.println("Feature not yet implemented for this class.");
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
*
|
|
238
|
+
* @return
|
|
239
|
+
*/
|
|
240
|
+
@Override
|
|
241
|
+
public RPoint[][] getHandlesInPaths() {
|
|
242
|
+
PApplet.println("Feature not yet implemented for this class.");
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@Override
|
|
247
|
+
public RPoint[][] getTangentsInPaths() {
|
|
248
|
+
PApplet.println("Feature not yet implemented for this class.");
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
*
|
|
254
|
+
* @param p
|
|
255
|
+
* @return
|
|
256
|
+
*/
|
|
257
|
+
@Override
|
|
258
|
+
public boolean contains(RPoint p) {
|
|
259
|
+
PApplet.println("Feature not yet implemented for this class.");
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Use this method to know if the contour is a hole. Remember to use the
|
|
265
|
+
* method update() on the polygon before using this method.
|
|
266
|
+
*
|
|
267
|
+
* @eexample RPolygon_isHole
|
|
268
|
+
* @return boolean, true if it is a hole
|
|
269
|
+
* @related update ( )
|
|
270
|
+
*/
|
|
271
|
+
public boolean isHole() {
|
|
272
|
+
return isHole;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
*
|
|
277
|
+
*/
|
|
278
|
+
@Override
|
|
279
|
+
public void print() {
|
|
280
|
+
System.out.println("contour: ");
|
|
281
|
+
for (int i = 0; i < countPoints(); i++) {
|
|
282
|
+
System.out.println("--- point " + i + " ---");
|
|
283
|
+
points[i].print();
|
|
284
|
+
System.out.println("---------------");
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
public void addClose() {
|
|
289
|
+
if (points == null) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if ((points[0].x == points[points.length - 1].x) && (points[0].y == points[points.length - 1].y)) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
addPoint(new RPoint(points[0].x, points[0].y));
|
|
298
|
+
closed = true;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* @return @invisible
|
|
303
|
+
*/
|
|
304
|
+
@Override
|
|
305
|
+
public RPolygon toPolygon() {
|
|
306
|
+
return new RPolygon(this);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* @return @invisible
|
|
311
|
+
*/
|
|
312
|
+
@Override
|
|
313
|
+
public RShape toShape() throws RuntimeException {
|
|
314
|
+
throw new RuntimeException("Transforming a Contour to a Shape is not yet implemented.");
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @return @invisible
|
|
319
|
+
*/
|
|
320
|
+
@Override
|
|
321
|
+
public RMesh toMesh() {
|
|
322
|
+
return this.toPolygon().toMesh();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Use this method to get the type of element this is.
|
|
327
|
+
*
|
|
328
|
+
* @eexample RPolygon_getType
|
|
329
|
+
* @return int, will allways return RGeomElem.POLYGON
|
|
330
|
+
*/
|
|
331
|
+
@Override
|
|
332
|
+
public int getType() {
|
|
333
|
+
return type;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
final void append(RPoint nextpoint) {
|
|
337
|
+
RPoint[] newpoints;
|
|
338
|
+
if (points == null) {
|
|
339
|
+
newpoints = new RPoint[1];
|
|
340
|
+
newpoints[0] = nextpoint;
|
|
341
|
+
} else {
|
|
342
|
+
newpoints = new RPoint[this.points.length + 1];
|
|
343
|
+
System.arraycopy(this.points, 0, newpoints, 0, this.points.length);
|
|
344
|
+
newpoints[this.points.length] = nextpoint;
|
|
345
|
+
}
|
|
346
|
+
this.points = newpoints;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright 2004-2008 Ricard Marxer <email@ricardmarxer.com>
|
|
3
|
+
|
|
4
|
+
This file is part of Geomerative.
|
|
5
|
+
|
|
6
|
+
Geomerative is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
Geomerative is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU General Public License
|
|
17
|
+
along with Geomerative. If not, see <http://www.gnu.org/licenses/>.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
package geomerative;
|
|
21
|
+
import processing.core.*;
|
|
22
|
+
|
|
23
|
+
import org.apache.batik.svggen.font.*;
|
|
24
|
+
import org.apache.batik.svggen.font.table.*;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* RShape is a reduced interface for creating, holding and drawing text from TrueType Font files. It's a basic interpreter of TrueType fonts enabling to access any String in the form of a group of shapes. Enabling us in this way to access their geometry.
|
|
28
|
+
* @eexample RFont
|
|
29
|
+
* @usage Geometry
|
|
30
|
+
* @related RGroup
|
|
31
|
+
*
|
|
32
|
+
* @extended
|
|
33
|
+
*/
|
|
34
|
+
public class RFont implements PConstants{
|
|
35
|
+
Font f;
|
|
36
|
+
float scaleFactor = 0.2F;
|
|
37
|
+
//int scaleFactorFixed = 1;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The point size of the font.
|
|
41
|
+
* @eexample size
|
|
42
|
+
* @related setSize ( )
|
|
43
|
+
* @related RFont
|
|
44
|
+
*/
|
|
45
|
+
public int size = DEFAULT_SIZE;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The alignment of the font. This property can take the following values: RFont.LEFT, RFont.CENTER and RFont.RIGHT
|
|
49
|
+
* @eexample align
|
|
50
|
+
* @related setAlign ( )
|
|
51
|
+
* @related RFont
|
|
52
|
+
*/
|
|
53
|
+
public int align = DEFAULT_ALIGN;
|
|
54
|
+
|
|
55
|
+
final static int DEFAULT_SIZE = 48;
|
|
56
|
+
final static int DEFAULT_RESOLUTION = 72;
|
|
57
|
+
final static int DEFAULT_ALIGN = RFont.LEFT;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Should we try to use ASCII, rather than Unicode?
|
|
61
|
+
*/
|
|
62
|
+
public boolean forceAscii = false;
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The constructor of the RFont object. Use this in order to create a font with which we will be able to draw and obtain outlines of text.
|
|
67
|
+
* @eexample RFont
|
|
68
|
+
* @param fontPath String, the name of the TrueType Font file which should be situated in the data folder of the sketch.
|
|
69
|
+
* @param size int, the point size of the font in points.
|
|
70
|
+
* @param align int, this can only take the following values: RFont.LEFT, RFont.CENTER and RFont.RIGHT.
|
|
71
|
+
* @related toGroup ( )
|
|
72
|
+
* @related toShape ( )
|
|
73
|
+
* @related toPolygon ( )
|
|
74
|
+
* @related toMesh ( )
|
|
75
|
+
* @related draw ( )
|
|
76
|
+
*/
|
|
77
|
+
public RFont(String fontPath, int size, int align) throws RuntimeException{
|
|
78
|
+
// Try to find the font as font path
|
|
79
|
+
byte[] bs = RG.parent().loadBytes(fontPath);
|
|
80
|
+
f = Font.create(bs);
|
|
81
|
+
|
|
82
|
+
setSize(size);
|
|
83
|
+
setAlign(align);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public RFont(String fontPath, int size) throws RuntimeException{
|
|
87
|
+
this(fontPath, size, DEFAULT_ALIGN);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public RFont(String fontPath) throws RuntimeException{
|
|
91
|
+
this(fontPath, DEFAULT_SIZE, DEFAULT_ALIGN);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Use this method to reset the point size of the font.
|
|
96
|
+
* @eexample setSize
|
|
97
|
+
* @param size int, the point size of the font in points.
|
|
98
|
+
* @related size
|
|
99
|
+
* @related RFont
|
|
100
|
+
*/
|
|
101
|
+
public void setSize(int size){
|
|
102
|
+
short unitsPerEm = f.getHeadTable().getUnitsPerEm();
|
|
103
|
+
int resolution = RG.dpi();
|
|
104
|
+
this.scaleFactor = ((float)size * (float)resolution) / (72F * (float)unitsPerEm);
|
|
105
|
+
//this.scaleFactorFixed = (int)(this.scaleFactor * 65536F);
|
|
106
|
+
//System.out.println(scaleFactor);
|
|
107
|
+
//System.out.println(scaleFactorFixed);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public float getLineSpacing() {
|
|
111
|
+
// More info at:
|
|
112
|
+
// http://fontforge.sourceforge.net/faq.html#linespace
|
|
113
|
+
// http://typophile.com/node/13081
|
|
114
|
+
short unitsPerEm = f.getHeadTable().getUnitsPerEm();
|
|
115
|
+
System.out.println("UnitsPerEm (emsize): " + unitsPerEm);
|
|
116
|
+
|
|
117
|
+
// HHEA table method:
|
|
118
|
+
float hheaLineGap = (f.getHheaTable().getAscender() - f.getHheaTable().getDescender() + f.getHheaTable().getLineGap()) * this.scaleFactor;
|
|
119
|
+
System.out.println("HHEA lineGap: " + hheaLineGap);
|
|
120
|
+
|
|
121
|
+
// OS2 table typographic line gap method:
|
|
122
|
+
float os2TypoLineGap = (f.getOS2Table().getTypoAscender() - f.getOS2Table().getTypoDescender() + f.getOS2Table().getTypoLineGap()) * this.scaleFactor;
|
|
123
|
+
System.out.println("Os2 Typo lineGap: " + os2TypoLineGap);
|
|
124
|
+
|
|
125
|
+
// OS2 table win line gap method:
|
|
126
|
+
float os2WinLineGap = (f.getOS2Table().getWinAscent() + f.getOS2Table().getWinDescent()) * this.scaleFactor;
|
|
127
|
+
System.out.println("Os2 Win lineGap: " + os2WinLineGap);
|
|
128
|
+
|
|
129
|
+
// Automatic calculation
|
|
130
|
+
float autoLineGap = f.getHeadTable().getUnitsPerEm() * 1.25f * this.scaleFactor;
|
|
131
|
+
System.out.println("Automatic lineGap: " + autoLineGap);
|
|
132
|
+
|
|
133
|
+
return hheaLineGap;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Use this method to reset the alignment of the font. This property can take the following values: RFont.LEFT, RFont.CENTER and RFont.RIGHT
|
|
138
|
+
* @eexample setAlign
|
|
139
|
+
* @param align int, this can only take the following values: RFont.LEFT, RFont.CENTER and RFont.RIGHT.
|
|
140
|
+
* @related align
|
|
141
|
+
* @related RFont
|
|
142
|
+
*/
|
|
143
|
+
public void setAlign(int align) throws RuntimeException{
|
|
144
|
+
if(align!=LEFT && align!=CENTER && align!=RIGHT){
|
|
145
|
+
throw new RuntimeException("Alignment unknown. The only accepted values are: RFont.LEFT, RFont.CENTER and RFont.RIGHT");
|
|
146
|
+
}
|
|
147
|
+
this.align = align;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @invisible
|
|
152
|
+
**/
|
|
153
|
+
public String getFamily(){
|
|
154
|
+
return f.getNameTable().getRecord(org.apache.batik.svggen.font.table.Table.nameFontFamilyName);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Use this method to get the outlines of a character in the form of an RShape.
|
|
159
|
+
* @eexample RFont_toShape
|
|
160
|
+
* @param character char, the character we want the outline from.
|
|
161
|
+
* @return RShape, the outline of the character.
|
|
162
|
+
* @related toGroup ( )
|
|
163
|
+
* @related toPolygon ( )
|
|
164
|
+
* @related draw ( )
|
|
165
|
+
*/
|
|
166
|
+
public RShape toShape(char character){
|
|
167
|
+
RGroup grp = toGroup(Character.toString(character));
|
|
168
|
+
if(grp.countElements()>0) return (RShape)(grp.elements[0]);
|
|
169
|
+
return new RShape();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Use this method to get the outlines of a character in the form of an RPolygon.
|
|
174
|
+
* @eexample RFont_toPolygon
|
|
175
|
+
* @param character char, the character we want the outline from.
|
|
176
|
+
* @return RPolygon, the outline of the character.
|
|
177
|
+
* @related toGroup ( )
|
|
178
|
+
* @related toShape ( )
|
|
179
|
+
* @related draw ( )
|
|
180
|
+
*/
|
|
181
|
+
public RPolygon toPolygon(char character) {
|
|
182
|
+
return toShape(character).toPolygon();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
private CmapFormat getCmapFormat() {
|
|
187
|
+
if (forceAscii) {
|
|
188
|
+
// We've been asked to use the ASCII/Macintosh cmap format
|
|
189
|
+
return f.getCmapTable().getCmapFormat(
|
|
190
|
+
org.apache.batik.svggen.font.table.Table.platformMacintosh,
|
|
191
|
+
org.apache.batik.svggen.font.table.Table.encodingRoman );
|
|
192
|
+
} else {
|
|
193
|
+
short[] platforms = new short[] {
|
|
194
|
+
org.apache.batik.svggen.font.table.Table.platformMicrosoft,
|
|
195
|
+
org.apache.batik.svggen.font.table.Table.platformAppleUnicode,
|
|
196
|
+
org.apache.batik.svggen.font.table.Table.platformMacintosh
|
|
197
|
+
};
|
|
198
|
+
short[] encodings = new short[] {
|
|
199
|
+
org.apache.batik.svggen.font.table.Table.encodingUGL,
|
|
200
|
+
org.apache.batik.svggen.font.table.Table.encodingKorean,
|
|
201
|
+
org.apache.batik.svggen.font.table.Table.encodingHebrew,
|
|
202
|
+
org.apache.batik.svggen.font.table.Table.encodingUndefined
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
CmapFormat cmapFmt;
|
|
206
|
+
for(int i = 0; i < encodings.length; i++) {
|
|
207
|
+
for(int j = 0; j < platforms.length; j++) {
|
|
208
|
+
|
|
209
|
+
cmapFmt = f.getCmapTable().getCmapFormat(platforms[j], encodings[i]);
|
|
210
|
+
if (cmapFmt != null) {
|
|
211
|
+
return cmapFmt;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Use this method to get the outlines of a string in the form of an RGroup. All the elements of the group will be RShapes.
|
|
222
|
+
* @eexample RFont_toGroup
|
|
223
|
+
* @param text String, the string we want the outlines from.
|
|
224
|
+
* @return RGroup, the group of outlines of the character. All the elements are RShapes.
|
|
225
|
+
* @related toShape ( )
|
|
226
|
+
* @related draw ( )
|
|
227
|
+
*/
|
|
228
|
+
public RGroup toGroup(String text) throws RuntimeException{
|
|
229
|
+
RGroup result = new RGroup();
|
|
230
|
+
|
|
231
|
+
// Decide upon a cmap table to use for our character to glyph look-up
|
|
232
|
+
CmapFormat cmapFmt = getCmapFormat();
|
|
233
|
+
|
|
234
|
+
if (cmapFmt == null) {
|
|
235
|
+
throw new RuntimeException("Cannot find a suitable cmap table");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// If this font includes arabic script, we want to specify
|
|
239
|
+
// substitutions for initial, medial, terminal & isolated
|
|
240
|
+
// cases.
|
|
241
|
+
/*
|
|
242
|
+
GsubTable gsub = (GsubTable) f.getTable(Table.GSUB);
|
|
243
|
+
SingleSubst initialSubst = null;
|
|
244
|
+
SingleSubst medialSubst = null;
|
|
245
|
+
SingleSubst terminalSubst = null;
|
|
246
|
+
if (gsub != null) {
|
|
247
|
+
Script s = gsub.getScriptList().findScript(ScriptTags.SCRIPT_TAG_ARAB);
|
|
248
|
+
if (s != null) {
|
|
249
|
+
LangSys ls = s.getDefaultLangSys();
|
|
250
|
+
if (ls != null) {
|
|
251
|
+
Feature init = gsub.getFeatureList().findFeature(ls, FeatureTags.FEATURE_TAG_INIT);
|
|
252
|
+
Feature medi = gsub.getFeatureList().findFeature(ls, FeatureTags.FEATURE_TAG_MEDI);
|
|
253
|
+
Feature fina = gsub.getFeatureList().findFeature(ls, FeatureTags.FEATURE_TAG_FINA);
|
|
254
|
+
|
|
255
|
+
initialSubst = (SingleSubst)
|
|
256
|
+
gsub.getLookupList().getLookup(init, 0).getSubtable(0);
|
|
257
|
+
medialSubst = (SingleSubst)
|
|
258
|
+
gsub.getLookupList().getLookup(medi, 0).getSubtable(0);
|
|
259
|
+
terminalSubst = (SingleSubst)
|
|
260
|
+
gsub.getLookupList().getLookup(fina, 0).getSubtable(0);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}*/
|
|
264
|
+
|
|
265
|
+
int x = 0;
|
|
266
|
+
for (short i = 0; i < text.length(); i++) {
|
|
267
|
+
int glyphIndex = cmapFmt.mapCharCode(text.charAt(i));
|
|
268
|
+
Glyph glyph = f.getGlyph(glyphIndex);
|
|
269
|
+
int default_advance_x = f.getHmtxTable().getAdvanceWidth(glyphIndex);
|
|
270
|
+
if (glyph != null) {
|
|
271
|
+
glyph.scale(scaleFactor);
|
|
272
|
+
// Add the Glyph to the Shape with an horizontal offset of x
|
|
273
|
+
result.addElement(getGlyphAsShape(f,glyph, glyphIndex,x));
|
|
274
|
+
x += glyph.getAdvanceWidth();
|
|
275
|
+
}else{
|
|
276
|
+
x += (int)((float)default_advance_x*scaleFactor);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if(align!=LEFT && align!=CENTER && align!=RIGHT){
|
|
282
|
+
throw new RuntimeException("Alignment unknown. The only accepted values are: RFont.LEFT, RFont.CENTER and RFont.RIGHT");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
RRectangle r;
|
|
286
|
+
RMatrix mattrans;
|
|
287
|
+
|
|
288
|
+
switch(this.align){
|
|
289
|
+
case RFont.CENTER:
|
|
290
|
+
r = result.getBounds();
|
|
291
|
+
mattrans = new RMatrix();
|
|
292
|
+
mattrans.translate((r.getMinX()-r.getMaxX())/2,0);
|
|
293
|
+
result.transform(mattrans);
|
|
294
|
+
break;
|
|
295
|
+
case RFont.RIGHT:
|
|
296
|
+
r = result.getBounds();
|
|
297
|
+
mattrans = new RMatrix();
|
|
298
|
+
mattrans.translate((r.getMinX()-r.getMaxX()),0);
|
|
299
|
+
result.transform(mattrans);
|
|
300
|
+
break;
|
|
301
|
+
case RFont.LEFT:
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
public RShape toShape(String text) throws RuntimeException{
|
|
308
|
+
RShape result = new RShape();
|
|
309
|
+
|
|
310
|
+
// Decide upon a cmap table to use for our character to glyph look-up
|
|
311
|
+
CmapFormat cmapFmt = getCmapFormat();
|
|
312
|
+
|
|
313
|
+
if (cmapFmt == null) {
|
|
314
|
+
throw new RuntimeException("Cannot find a suitable cmap table");
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// If this font includes arabic script, we want to specify
|
|
318
|
+
// substitutions for initial, medial, terminal & isolated
|
|
319
|
+
// cases.
|
|
320
|
+
/*
|
|
321
|
+
GsubTable gsub = (GsubTable) f.getTable(Table.GSUB);
|
|
322
|
+
SingleSubst initialSubst = null;
|
|
323
|
+
SingleSubst medialSubst = null;
|
|
324
|
+
SingleSubst terminalSubst = null;
|
|
325
|
+
if (gsub != null) {
|
|
326
|
+
Script s = gsub.getScriptList().findScript(ScriptTags.SCRIPT_TAG_ARAB);
|
|
327
|
+
if (s != null) {
|
|
328
|
+
LangSys ls = s.getDefaultLangSys();
|
|
329
|
+
if (ls != null) {
|
|
330
|
+
Feature init = gsub.getFeatureList().findFeature(ls, FeatureTags.FEATURE_TAG_INIT);
|
|
331
|
+
Feature medi = gsub.getFeatureList().findFeature(ls, FeatureTags.FEATURE_TAG_MEDI);
|
|
332
|
+
Feature fina = gsub.getFeatureList().findFeature(ls, FeatureTags.FEATURE_TAG_FINA);
|
|
333
|
+
|
|
334
|
+
initialSubst = (SingleSubst)
|
|
335
|
+
gsub.getLookupList().getLookup(init, 0).getSubtable(0);
|
|
336
|
+
medialSubst = (SingleSubst)
|
|
337
|
+
gsub.getLookupList().getLookup(medi, 0).getSubtable(0);
|
|
338
|
+
terminalSubst = (SingleSubst)
|
|
339
|
+
gsub.getLookupList().getLookup(fina, 0).getSubtable(0);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}*/
|
|
343
|
+
|
|
344
|
+
int x = 0;
|
|
345
|
+
for (short i = 0; i < text.length(); i++) {
|
|
346
|
+
int glyphIndex = cmapFmt.mapCharCode(text.charAt(i));
|
|
347
|
+
Glyph glyph = f.getGlyph(glyphIndex);
|
|
348
|
+
int default_advance_x = f.getHmtxTable().getAdvanceWidth(glyphIndex);
|
|
349
|
+
if (glyph != null) {
|
|
350
|
+
glyph.scale(scaleFactor);
|
|
351
|
+
// Add the Glyph to the Shape with an horizontal offset of x
|
|
352
|
+
result.addChild(getGlyphAsShape(f,glyph, glyphIndex,x));
|
|
353
|
+
x += glyph.getAdvanceWidth();
|
|
354
|
+
}else{
|
|
355
|
+
x += (int)((float)default_advance_x*scaleFactor);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if(align!=LEFT && align!=CENTER && align!=RIGHT){
|
|
361
|
+
throw new RuntimeException("Alignment unknown. The only accepted values are: RFont.LEFT, RFont.CENTER and RFont.RIGHT");
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
RRectangle r;
|
|
365
|
+
RMatrix mattrans;
|
|
366
|
+
|
|
367
|
+
switch(this.align){
|
|
368
|
+
case RFont.CENTER:
|
|
369
|
+
r = result.getBounds();
|
|
370
|
+
mattrans = new RMatrix();
|
|
371
|
+
mattrans.translate((r.getMinX()-r.getMaxX())/2,0);
|
|
372
|
+
result.transform(mattrans);
|
|
373
|
+
break;
|
|
374
|
+
case RFont.RIGHT:
|
|
375
|
+
r = result.getBounds();
|
|
376
|
+
mattrans = new RMatrix();
|
|
377
|
+
mattrans.translate((r.getMinX()-r.getMaxX()),0);
|
|
378
|
+
result.transform(mattrans);
|
|
379
|
+
break;
|
|
380
|
+
case RFont.LEFT:
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Use this method to draw a character on a certain canvas.
|
|
388
|
+
* @eexample RFont_draw
|
|
389
|
+
* @param character the character to be drawn
|
|
390
|
+
* @param g the canvas where to draw
|
|
391
|
+
* @related toShape ( )
|
|
392
|
+
* @related toGroup ( )
|
|
393
|
+
*/
|
|
394
|
+
public void draw(char character, PGraphics g) throws RuntimeException{
|
|
395
|
+
this.toShape(character).draw(g);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Use this method to draw a character on a certain canvas.
|
|
400
|
+
* @eexample RFont_draw
|
|
401
|
+
* @param text the string to be drawn
|
|
402
|
+
* @param g the canvas where to draw
|
|
403
|
+
* @related toShape ( )
|
|
404
|
+
* @related toGroup ( )
|
|
405
|
+
*/
|
|
406
|
+
public void draw(String text, PGraphics g) throws RuntimeException{
|
|
407
|
+
this.toGroup(text).draw(g);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Use this method to draw a character on a certain canvas.
|
|
412
|
+
* @eexample RFont_draw
|
|
413
|
+
* @param character char, the character to be drawn
|
|
414
|
+
* @param g the canvas where to draw
|
|
415
|
+
* @related toShape ( )
|
|
416
|
+
* @related toGroup ( )
|
|
417
|
+
*/
|
|
418
|
+
public void draw(char character, PApplet g) throws RuntimeException{
|
|
419
|
+
this.toShape(character).draw(g);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Use this method to draw a character on a certain canvas.
|
|
424
|
+
* @eexample RFont_draw
|
|
425
|
+
* @param text the string to be drawn
|
|
426
|
+
* @param g the canvas where to draw
|
|
427
|
+
* @related toShape ( )
|
|
428
|
+
* @related toGroup ( )
|
|
429
|
+
*/
|
|
430
|
+
public void draw(String text, PApplet g) throws RuntimeException{
|
|
431
|
+
this.toGroup(text).draw(g);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public void draw(String text) throws RuntimeException{
|
|
435
|
+
this.toGroup(text).draw();
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
public void draw(char character) throws RuntimeException{
|
|
439
|
+
this.toShape(character).draw();
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
private static float midValue(float a, float b) {
|
|
445
|
+
return a + (b - a)/2;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
protected static RShape getContourAsShape(Glyph glyph, int startIndex, int count) {
|
|
449
|
+
return getContourAsShape(glyph, startIndex, count, 0);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
protected static RShape getContourAsShape(Glyph glyph, int startIndex, int count, float xadv) {
|
|
453
|
+
|
|
454
|
+
// If this is a single point on it's own, weSystem.out.println("Value of pointx: "+pointx); can't do anything with it
|
|
455
|
+
if (glyph.getPoint(startIndex).endOfContour) {
|
|
456
|
+
return new RShape();
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
RShape result = new RShape();
|
|
460
|
+
int offset = 0;
|
|
461
|
+
//float originx = 0F,originy = 0F;
|
|
462
|
+
|
|
463
|
+
while (offset < count) {
|
|
464
|
+
Point point = glyph.getPoint(startIndex + offset%count);
|
|
465
|
+
Point point_plus1 = glyph.getPoint(startIndex + (offset+1)%count);
|
|
466
|
+
Point point_plus2 = glyph.getPoint(startIndex + (offset+2)%count);
|
|
467
|
+
|
|
468
|
+
float pointx = ((float)point.x + xadv);
|
|
469
|
+
float pointy = ((float)point.y);
|
|
470
|
+
float point_plus1x = ((float)point_plus1.x + xadv);
|
|
471
|
+
float point_plus1y = ((float)point_plus1.y);
|
|
472
|
+
float point_plus2x = ((float)point_plus2.x + xadv);
|
|
473
|
+
float point_plus2y = ((float)point_plus2.y);
|
|
474
|
+
|
|
475
|
+
if (offset == 0) {
|
|
476
|
+
// move command
|
|
477
|
+
result.addMoveTo(pointx,pointy);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (point.onCurve && point_plus1.onCurve) {
|
|
481
|
+
// line command
|
|
482
|
+
result.addLineTo(point_plus1x,point_plus1y);
|
|
483
|
+
offset++;
|
|
484
|
+
} else if (point.onCurve && !point_plus1.onCurve && point_plus2.onCurve) {
|
|
485
|
+
// This is a curve with no implied points
|
|
486
|
+
// quadratic bezier command
|
|
487
|
+
result.addQuadTo(point_plus1x, point_plus1y, point_plus2x, point_plus2y);
|
|
488
|
+
offset+=2;
|
|
489
|
+
} else if (point.onCurve && !point_plus1.onCurve && !point_plus2.onCurve) {
|
|
490
|
+
// This is a curve with one implied point
|
|
491
|
+
// quadratic bezier command avec le endPoint implicit
|
|
492
|
+
result.addQuadTo(point_plus1x, point_plus1y, midValue(point_plus1x, point_plus2x), midValue(point_plus1y, point_plus2y));
|
|
493
|
+
offset+=2;
|
|
494
|
+
} else if (!point.onCurve && !point_plus1.onCurve) {
|
|
495
|
+
// This is a curve with two implied points
|
|
496
|
+
// quadratic bezier with
|
|
497
|
+
result.addQuadTo(pointx, pointy, midValue(pointx, point_plus1x), midValue(pointy, point_plus1y));
|
|
498
|
+
offset++;
|
|
499
|
+
} else if (!point.onCurve && point_plus1.onCurve) {
|
|
500
|
+
// This is a curve with no implied points
|
|
501
|
+
result.addQuadTo(pointx, pointy, point_plus1x, point_plus1y);
|
|
502
|
+
offset++;
|
|
503
|
+
} else {
|
|
504
|
+
System.out.println("drawGlyph case not catered for!!");
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
result.addClose();
|
|
509
|
+
return result;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
protected static RShape getGlyphAsShape(Font font, Glyph glyph, int glyphIndex) {
|
|
513
|
+
return getGlyphAsShape(font,glyph,glyphIndex,0);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
protected static RShape getGlyphAsShape(Font font, Glyph glyph, int glyphIndex,float xadv) {
|
|
517
|
+
|
|
518
|
+
RShape result = new RShape();
|
|
519
|
+
int firstIndex = 0;
|
|
520
|
+
int count = 0;
|
|
521
|
+
int i;
|
|
522
|
+
|
|
523
|
+
if (glyph != null) {
|
|
524
|
+
for (i = 0; i < glyph.getPointCount(); i++) {
|
|
525
|
+
count++;
|
|
526
|
+
if (glyph.getPoint(i).endOfContour) {
|
|
527
|
+
result.addShape(getContourAsShape(glyph, firstIndex, count, xadv));
|
|
528
|
+
firstIndex = i + 1;
|
|
529
|
+
count = 0;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return result;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
protected static RShape getGlyphAsShape(Font font, Glyph glyph, int glyphIndex, SingleSubst arabInitSubst, SingleSubst arabMediSubst, SingleSubst arabTermSubst) {
|
|
538
|
+
return getGlyphAsShape(font, glyph, glyphIndex, arabInitSubst, arabMediSubst, arabTermSubst, 0);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
protected static RShape getGlyphAsShape(Font font, Glyph glyph, int glyphIndex, SingleSubst arabInitSubst, SingleSubst arabMediSubst, SingleSubst arabTermSubst, float xadv) {
|
|
542
|
+
|
|
543
|
+
RShape result = new RShape();
|
|
544
|
+
boolean substituted = false;
|
|
545
|
+
|
|
546
|
+
// arabic = "initial | medial | terminal | isolated"
|
|
547
|
+
int arabInitGlyphIndex = glyphIndex;
|
|
548
|
+
int arabMediGlyphIndex = glyphIndex;
|
|
549
|
+
int arabTermGlyphIndex = glyphIndex;
|
|
550
|
+
if (arabInitSubst != null) {
|
|
551
|
+
arabInitGlyphIndex = arabInitSubst.substitute(glyphIndex);
|
|
552
|
+
}
|
|
553
|
+
if (arabMediSubst != null) {
|
|
554
|
+
arabMediGlyphIndex = arabMediSubst.substitute(glyphIndex);
|
|
555
|
+
}
|
|
556
|
+
if (arabTermSubst != null) {
|
|
557
|
+
arabTermGlyphIndex = arabTermSubst.substitute(glyphIndex);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (arabInitGlyphIndex != glyphIndex) {
|
|
561
|
+
result.addShape(getGlyphAsShape(font,font.getGlyph(arabInitGlyphIndex),arabInitGlyphIndex));
|
|
562
|
+
substituted = true;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (arabMediGlyphIndex != glyphIndex) {
|
|
566
|
+
result.addShape(getGlyphAsShape(font,font.getGlyph(arabMediGlyphIndex),arabMediGlyphIndex));
|
|
567
|
+
substituted = true;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (arabTermGlyphIndex != glyphIndex) {
|
|
571
|
+
result.addShape(getGlyphAsShape(font,font.getGlyph(arabTermGlyphIndex),arabTermGlyphIndex));
|
|
572
|
+
substituted = true;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (substituted) {
|
|
576
|
+
result.addShape(getGlyphAsShape(font,glyph,glyphIndex));
|
|
577
|
+
} else {
|
|
578
|
+
result.addShape(getGlyphAsShape(font,glyph,glyphIndex));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return result;
|
|
582
|
+
}
|
|
583
|
+
}
|