aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-02-11 21:03:17 +0100
committerSven Gothel <[email protected]>2023-02-12 00:22:02 +0100
commitf27023506cb89896e0feb9754cafd28c5d34c06b (patch)
tree0f7dd22834ae583f1d5b713253cf09b37e62b3e5
parent0d10cb9976e243cfc2915677649dde5ad26de734 (diff)
Glyoh*: Maintain ID and AABBox, add toString() and clearPointData() for optional memory release. TTGlyph: Drop added origin and advanceWidth, keep points original
-rw-r--r--src/main/java/net/java/dev/typecast/math/AABBox.java376
-rw-r--r--src/main/java/net/java/dev/typecast/ot/Glyph.java23
-rw-r--r--src/main/java/net/java/dev/typecast/ot/T2Glyph.java41
-rw-r--r--src/main/java/net/java/dev/typecast/ot/TTGlyph.java25
4 files changed, 446 insertions, 19 deletions
diff --git a/src/main/java/net/java/dev/typecast/math/AABBox.java b/src/main/java/net/java/dev/typecast/math/AABBox.java
new file mode 100644
index 0000000..fdff0e0
--- /dev/null
+++ b/src/main/java/net/java/dev/typecast/math/AABBox.java
@@ -0,0 +1,376 @@
+/*
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2015 David Schweinsberg
+ * Copyright (c) 2010-2023 JogAmp Community
+ * Copyright (c) 2010-2023 Gothel Software e.K.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * And this file is also licensed under the simplified BSD license w/o any warranties etc,
+ * same as the Apache 2.0 license.
+ */
+package net.java.dev.typecast.math;
+
+/**
+ * Axis Aligned Bounding Box. Defined by two 3D coordinates (low and high)
+ * The low being the the lower left corner of the box, and the high being the upper
+ * right corner of the box.
+ * <p>
+ * This is a simplified variation of the class maintained within JOGL
+ * for compatibility purposes of our patched typecast branch.
+ * </p>
+ */
+public class AABBox {
+ private final float[] low = new float[3];
+ private final float[] high = new float[3];
+ private final float[] center = new float[3];
+
+ /**
+ * Create an Axis Aligned bounding box (AABBox)
+ * where the low and and high MAX float Values.
+ */
+ public AABBox() {
+ reset();
+ }
+
+ /**
+ * Create an AABBox copying all values from the given one
+ * @param src the box value to be used for the new instance
+ */
+ public AABBox(final AABBox src) {
+ copy(src);
+ }
+
+ /**
+ * Create an AABBox specifying the coordinates
+ * of the low and high
+ * @param lx min x-coordinate
+ * @param ly min y-coordnate
+ * @param lz min z-coordinate
+ * @param hx max x-coordinate
+ * @param hy max y-coordinate
+ * @param hz max z-coordinate
+ */
+ public AABBox(final float lx, final float ly, final float lz,
+ final float hx, final float hy, final float hz) {
+ setSize(lx, ly, lz, hx, hy, hz);
+ }
+
+ /**
+ * Create a AABBox defining the low and high
+ * @param low min xyz-coordinates
+ * @param high max xyz-coordinates
+ */
+ public AABBox(final float[] low, final float[] high) {
+ setSize(low, high);
+ }
+
+ /**
+ * resets this box to the inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit.
+ * @return this AABBox for chaining
+ */
+ public final AABBox reset() {
+ setLow(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE);
+ setHigh(-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE);
+ center[0] = 0f;
+ center[1] = 0f;
+ center[2] = 0f;
+ return this;
+ }
+
+ /** Get the max xyz-coordinates
+ * @return a float array containing the max xyz coordinates
+ */
+ public final float[] getHigh() {
+ return high;
+ }
+
+ private final void setHigh(final float hx, final float hy, final float hz) {
+ this.high[0] = hx;
+ this.high[1] = hy;
+ this.high[2] = hz;
+ }
+
+ /** Get the min xyz-coordinates
+ * @return a float array containing the min xyz coordinates
+ */
+ public final float[] getLow() {
+ return low;
+ }
+
+ private final void setLow(final float lx, final float ly, final float lz) {
+ this.low[0] = lx;
+ this.low[1] = ly;
+ this.low[2] = lz;
+ }
+
+ private final void computeCenter() {
+ center[0] = (high[0] + low[0])/2f;
+ center[1] = (high[1] + low[1])/2f;
+ center[2] = (high[2] + low[2])/2f;
+ }
+
+ /**
+ * Copy given AABBox 'src' values to this AABBox.
+ *
+ * @param src source AABBox
+ * @return this AABBox for chaining
+ */
+ public final AABBox copy(final AABBox src) {
+ System.arraycopy(src.low, 0, low, 0, 3);
+ System.arraycopy(src.high, 0, high, 0, 3);
+ System.arraycopy(src.center, 0, center, 0, 3);
+ return this;
+ }
+
+ /**
+ * Set size of the AABBox specifying the coordinates
+ * of the low and high.
+ *
+ * @param low min xyz-coordinates
+ * @param high max xyz-coordinates
+ * @return this AABBox for chaining
+ */
+ public final AABBox setSize(final float[] low, final float[] high) {
+ return setSize(low[0],low[1],low[2], high[0],high[1],high[2]);
+ }
+
+ /**
+ * Set size of the AABBox specifying the coordinates
+ * of the low and high.
+ *
+ * @param lx min x-coordinate
+ * @param ly min y-coordnate
+ * @param lz min z-coordinate
+ * @param hx max x-coordinate
+ * @param hy max y-coordinate
+ * @param hz max z-coordinate
+ * @return this AABBox for chaining
+ */
+ public final AABBox setSize(final float lx, final float ly, final float lz,
+ final float hx, final float hy, final float hz) {
+ this.low[0] = lx;
+ this.low[1] = ly;
+ this.low[2] = lz;
+ this.high[0] = hx;
+ this.high[1] = hy;
+ this.high[2] = hz;
+ computeCenter();
+ return this;
+ }
+
+ /**
+ * Resize the AABBox to encapsulate another AABox
+ * @param newBox AABBox to be encapsulated in
+ * @return this AABBox for chaining
+ */
+ public final AABBox resize(final AABBox newBox) {
+ final float[] newLow = newBox.getLow();
+ final float[] newHigh = newBox.getHigh();
+
+ /** test low */
+ if (newLow[0] < low[0])
+ low[0] = newLow[0];
+ if (newLow[1] < low[1])
+ low[1] = newLow[1];
+ if (newLow[2] < low[2])
+ low[2] = newLow[2];
+
+ /** test high */
+ if (newHigh[0] > high[0])
+ high[0] = newHigh[0];
+ if (newHigh[1] > high[1])
+ high[1] = newHigh[1];
+ if (newHigh[2] > high[2])
+ high[2] = newHigh[2];
+
+ computeCenter();
+ return this;
+ }
+
+ /**
+ * Resize the AABBox to encapsulate the passed
+ * xyz-coordinates.
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @param z z-axis coordinate value
+ * @return this AABBox for chaining
+ */
+ public final AABBox resize(final float x, final float y, final float z) {
+ /** test low */
+ if (x < low[0]) {
+ low[0] = x;
+ }
+ if (y < low[1]) {
+ low[1] = y;
+ }
+ if (z < low[2]) {
+ low[2] = z;
+ }
+
+ /** test high */
+ if (x > high[0]) {
+ high[0] = x;
+ }
+ if (y > high[1]) {
+ high[1] = y;
+ }
+ if (z > high[2]) {
+ high[2] = z;
+ }
+
+ computeCenter();
+ return this;
+ }
+
+ /**
+ * Resize the AABBox to encapsulate the passed
+ * xyz-coordinates.
+ * @param xyz xyz-axis coordinate values
+ * @param offset of the array
+ * @return this AABBox for chaining
+ */
+ public final AABBox resize(final float[] xyz, final int offset) {
+ return resize(xyz[0+offset], xyz[1+offset], xyz[2+offset]);
+ }
+
+ /**
+ * Resize the AABBox to encapsulate the passed
+ * xyz-coordinates.
+ * @param xyz xyz-axis coordinate values
+ * @return this AABBox for chaining
+ */
+ public final AABBox resize(final float[] xyz) {
+ return resize(xyz[0], xyz[1], xyz[2]);
+ }
+
+ /**
+ * Check if the x & y coordinates are bounded/contained
+ * by this AABBox
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @return true if x belong to (low.x, high.x) and
+ * y belong to (low.y, high.y)
+ */
+ public final boolean contains(final float x, final float y) {
+ if(x<low[0] || x>high[0]){
+ return false;
+ }
+ if(y<low[1]|| y>high[1]){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Check if the xyz coordinates are bounded/contained
+ * by this AABBox.
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @param z z-axis coordinate value
+ * @return true if x belong to (low.x, high.x) and
+ * y belong to (low.y, high.y) and z belong to (low.z, high.z)
+ */
+ public final boolean contains(final float x, final float y, final float z) {
+ if(x<low[0] || x>high[0]){
+ return false;
+ }
+ if(y<low[1]|| y>high[1]){
+ return false;
+ }
+ if(z<low[2] || z>high[2]){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Check if there is a common region between this AABBox and the passed
+ * 2D region irrespective of z range
+ * @param x lower left x-coord
+ * @param y lower left y-coord
+ * @param w width
+ * @param h hight
+ * @return true if this AABBox might have a common region with this 2D region
+ */
+ public final boolean intersects2DRegion(final float x, final float y, final float w, final float h) {
+ if (w <= 0 || h <= 0) {
+ return false;
+ }
+
+ final float _w = getWidth();
+ final float _h = getHeight();
+ if (_w <= 0 || _h <= 0) {
+ return false;
+ }
+
+ final float x0 = getMinX();
+ final float y0 = getMinY();
+ return (x + w > x0 &&
+ y + h > y0 &&
+ x < x0 + _w &&
+ y < y0 + _h);
+ }
+
+ /**
+ * Get the Center of this AABBox
+ * @return the xyz-coordinates of the center of the AABBox
+ */
+ public final float[] getCenter() {
+ return center;
+ }
+
+ public final float getMinX() {
+ return low[0];
+ }
+
+ public final float getMinY() {
+ return low[1];
+ }
+
+ public final float getMinZ() {
+ return low[2];
+ }
+
+ public final float getMaxX() {
+ return high[0];
+ }
+
+ public final float getMaxY() {
+ return high[1];
+ }
+
+ public final float getMaxZ() {
+ return high[2];
+ }
+
+ public final float getWidth(){
+ return high[0] - low[0];
+ }
+
+ public final float getHeight() {
+ return high[1] - low[1];
+ }
+
+ public final float getDepth() {
+ return high[2] - low[2];
+ }
+
+ @Override
+ public final String toString() {
+ return "[ dim "+getWidth()+" x "+getHeight()+" x "+getDepth()+
+ ", box "+low[0]+" / "+low[1]+" / "+low[2]+" .. "+high[0]+" / "+high[1]+" / "+high[2]+
+ ", ctr "+center[0]+" / "+center[1]+" / "+center[2]+" ]";
+ }
+}
diff --git a/src/main/java/net/java/dev/typecast/ot/Glyph.java b/src/main/java/net/java/dev/typecast/ot/Glyph.java
index af3fb46..d0cc4c1 100644
--- a/src/main/java/net/java/dev/typecast/ot/Glyph.java
+++ b/src/main/java/net/java/dev/typecast/ot/Glyph.java
@@ -18,17 +18,38 @@
package net.java.dev.typecast.ot;
+import net.java.dev.typecast.math.AABBox;
+
/**
* An individual glyph within a font.
* @author <a href="mailto:[email protected]">David Schweinsberg</a>
*/
public abstract class Glyph {
+ final int _glyph_id;
+ protected AABBox _bbox;
- public abstract int getAdvanceWidth();
+ public Glyph(final int glyph_id) {
+ _glyph_id = glyph_id;
+ }
+
+ /** Return the assigned glyph ID of this instance */
+ public final int getGlyphIndex() { return _glyph_id; }
+
+ public abstract void clearPointData();
+ /** Return the AABBox in font-units */
+ public final AABBox getBBox() { return _bbox; }
+
+ /** hmtx value */
+ public abstract int getAdvanceWidth();
+
+ /** hmtx value */
public abstract short getLeftSideBearing();
public abstract Point getPoint(int i);
public abstract int getPointCount();
+
+ @Override
+ public abstract String toString();
}
diff --git a/src/main/java/net/java/dev/typecast/ot/T2Glyph.java b/src/main/java/net/java/dev/typecast/ot/T2Glyph.java
index 9e7afa8..d5c7b3d 100644
--- a/src/main/java/net/java/dev/typecast/ot/T2Glyph.java
+++ b/src/main/java/net/java/dev/typecast/ot/T2Glyph.java
@@ -17,10 +17,9 @@
*/
package net.java.dev.typecast.ot;
-import java.awt.Rectangle;
-import java.awt.geom.Rectangle2D;
import net.java.dev.typecast.cff.CharstringType2;
import net.java.dev.typecast.cff.T2Interpreter;
+import net.java.dev.typecast.math.AABBox;
/**
* An individual Type 2 Charstring glyph within a font.
@@ -29,28 +28,44 @@ import net.java.dev.typecast.cff.T2Interpreter;
public class T2Glyph extends Glyph {
private final short _leftSideBearing;
private final int _advanceWidth;
- private final Point[] _points;
- private final Integer[] _hstems;
- private final Integer[] _vstems;
+ private Point[] _points;
+ private Integer[] _hstems;
+ private Integer[] _vstems;
/**
* Construct a Glyph from a PostScript outline described by a Charstring.
+ * @param glyph_id the assigned glyph_id of this instance
* @param cs The CharstringType2 describing the glyph.
* @param lsb The Left Side Bearing.
* @param advance The advance width.
*/
public T2Glyph(
+ final int glyph_id,
CharstringType2 cs,
short lsb,
int advance) {
+ super( glyph_id );
_leftSideBearing = lsb;
_advanceWidth = advance;
T2Interpreter t2i = new T2Interpreter();
_points = t2i.execute(cs);
_hstems = t2i.getHStems();
_vstems = t2i.getVStems();
+ {
+ AABBox bbox = new AABBox();
+ for (Point p : _points) {
+ bbox.resize(p.x, p.y, 0);
+ }
+ _bbox = bbox;
+ }
}
+ public final void clearPointData() {
+ _points = null;
+ _hstems = null;
+ _vstems = null;
+ }
+
@Override
public int getAdvanceWidth() {
return _advanceWidth;
@@ -79,14 +94,12 @@ public class T2Glyph extends Glyph {
return _vstems;
}
- public Rectangle2D getBounds() {
- Rectangle r = null;
- for (Point p : _points) {
- if (r == null) {
- r = new Rectangle(p.x, p.y, 0, 0);
- }
- r.add(new java.awt.Point(p.x, p.y));
- }
- return r != null ? r : new Rectangle(0, 0, 0, 0);
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("T2Glyph id ").append(_glyph_id).append(", points ").append(_points.length)
+ .append(", advance ").append(getAdvanceWidth())
+ .append(", ").append(_bbox)
+ .toString();
}
}
diff --git a/src/main/java/net/java/dev/typecast/ot/TTGlyph.java b/src/main/java/net/java/dev/typecast/ot/TTGlyph.java
index 4ec844a..add2bb5 100644
--- a/src/main/java/net/java/dev/typecast/ot/TTGlyph.java
+++ b/src/main/java/net/java/dev/typecast/ot/TTGlyph.java
@@ -17,6 +17,7 @@
*/
package net.java.dev.typecast.ot;
+import net.java.dev.typecast.math.AABBox;
import net.java.dev.typecast.ot.table.GlyfDescript;
import net.java.dev.typecast.ot.table.GlyphDescription;
@@ -29,7 +30,7 @@ public class TTGlyph extends Glyph {
private short _leftSideBearing;
private int _advanceWidth;
private Point[] _points;
-
+
/**
* Construct a Glyph from a TrueType outline described by
* a GlyphDescription.
@@ -38,11 +39,16 @@ public class TTGlyph extends Glyph {
* @param advance The advance width.
*/
public TTGlyph(GlyphDescription gd, short lsb, int advance) {
+ super( gd.getGlyphIndex() );
_leftSideBearing = lsb;
_advanceWidth = advance;
describe(gd);
}
+ public final void clearPointData() {
+ _points = null;
+ }
+
@Override
public int getAdvanceWidth() {
return _advanceWidth;
@@ -89,7 +95,7 @@ public class TTGlyph extends Glyph {
private void describe(GlyphDescription gd) {
int endPtIndex = 0;
int pointCount = gd != null ? gd.getPointCount() : 0;
- _points = new Point[pointCount + 2];
+ _points = new Point[pointCount /* + 2 */];
for (int i = 0; i < pointCount; i++) {
boolean endPt = gd.getEndPtOfContours(endPtIndex) == i;
if (endPt) {
@@ -103,7 +109,18 @@ public class TTGlyph extends Glyph {
}
// Append the origin and advanceWidth points (n & n+1)
- _points[pointCount] = new Point(0, 0, true, true);
- _points[pointCount+1] = new Point(_advanceWidth, 0, true, true);
+ // _points[pointCount] = new Point(0, 0, true, true);
+ // _points[pointCount+1] = new Point(_advanceWidth, 0, true, true);
+
+ _bbox = new AABBox(gd.getXMinimum(), gd.getYMinimum(), 0, gd.getXMaximum(), gd.getYMaximum(), 0);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("TTGlyph id ").append(_glyph_id).append(", points ").append(_points.length)
+ .append(", advance ").append(getAdvanceWidth())
+ .append(", ").append(_bbox)
+ .toString();
}
}