/** * Copyright 2008 - 2015 The Loon Game Engine Authors * * 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. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.5 */ package loon.geom; import loon.LSystem; import loon.LTrans; import loon.utils.MathUtils; /** * 以对象存储,而非数组的方式实现一个3x2(标准矩阵应为3x3)的2D仿射矩阵类, * 也就是保留了线的“直线性”和“平行性”,但缺少了长宽高的3D矩阵延展能力。 所以,此类仅适合2D应用中使用. * * 对应的3x3矩阵关系如下所示: * * <pre> * {@code * [ m00, m10, tx ] * [ m01, m11, ty ] * [ 0, 0, 1 ] * } * </pre> */ public class Affine2f implements LTrans, XY { public final static Affine2f multiply(Affine2f a, Affine2f b, Affine2f into) { return multiply(a.m00, a.m01, a.m10, a.m11, a.tx, a.ty, b.m00, b.m01, b.m10, b.m11, b.tx, b.ty, into); } public final static Affine2f multiply(Affine2f a, float m00, float m01, float m10, float m11, float tx, float ty, Affine2f into) { return multiply(a.m00, a.m01, a.m10, a.m11, a.tx, a.ty, m00, m01, m10, m11, tx, ty, into); } public final static Affine2f multiply(float m00, float m01, float m10, float m11, float tx, float ty, Affine2f b, Affine2f into) { return multiply(m00, m01, m10, m11, tx, ty, b.m00, b.m01, b.m10, b.m11, b.tx, b.ty, into); } public final static Affine2f multiply(float am00, float am01, float am10, float am11, float atx, float aty, float bm00, float bm01, float bm10, float bm11, float btx, float bty, Affine2f into) { into.setTransform(am00 * bm00 + am10 * bm01, am01 * bm00 + am11 * bm01, am00 * bm10 + am10 * bm11, am01 * bm10 + am11 * bm11, am00 * btx + am10 * bty + atx, am01 * btx + am11 * bty + aty); return into; } private static Matrix4 projectionMatrix = null; protected Affine2f(Affine2f other) { this(other.scaleX(), other.scaleY(), other.rotation(), other.tx(), other.ty()); } public static Affine2f transform(Affine2f tx, float x, float y, int transform) { switch (transform) { case TRANS_ROT90: { tx.translate(x, y); tx.rotate(ANGLE_90); tx.translate(-x, -y); break; } case TRANS_ROT180: { tx.translate(x, y); tx.rotate(MathUtils.PI); tx.translate(-x, -y); break; } case TRANS_ROT270: { tx.translate(x, y); tx.rotate(ANGLE_270); tx.translate(-x, -y); break; } case TRANS_MIRROR: { tx.translate(x, y); tx.scale(-1, 1); tx.translate(-x, -y); break; } case TRANS_MIRROR_ROT90: { tx.translate(x, y); tx.rotate(ANGLE_90); tx.translate(-x, -y); tx.scale(-1, 1); break; } case TRANS_MIRROR_ROT180: { tx.translate(x, y); tx.scale(-1, 1); tx.translate(-x, -y); tx.translate(x, y); tx.rotate(MathUtils.PI); tx.translate(-x, -y); break; } case TRANS_MIRROR_ROT270: { tx.translate(x, y); tx.rotate(ANGLE_270); tx.translate(-x, -y); tx.scale(-1, 1); break; } } return tx; } public static Affine2f transform(Affine2f tx, float x, float y, int transform, float width, float height) { switch (transform) { case TRANS_ROT90: { float w = x + width / 2; float h = y + height / 2; tx.translate(w, h); tx.rotate(ANGLE_90); tx.translate(-w, -h); break; } case TRANS_ROT180: { float w = x + width / 2; float h = y + height / 2; tx.translate(w, h); tx.rotate(MathUtils.PI); tx.translate(-w, -h); break; } case TRANS_ROT270: { float w = x + width / 2; float h = y + height / 2; tx.translate(w, h); tx.rotate(ANGLE_270); tx.translate(-w, -h); break; } case TRANS_MIRROR: { float w = x + width / 2; float h = y + height / 2; tx.translate(w, h); tx.scale(-1, 1); tx.translate(-w, -h); break; } case TRANS_MIRROR_ROT90: { float w = x + width / 2; float h = y + height / 2; tx.translate(w, h); tx.rotate(ANGLE_90); tx.translate(-w, -h); tx.scale(-1, 1); break; } case TRANS_MIRROR_ROT180: { float w = x + width / 2; float h = y + height / 2; tx.translate(w, h); tx.scale(-1, 1); tx.translate(-w, -h); w = x + width / 2; h = y + height / 2; tx.translate(w, h); tx.rotate(MathUtils.PI); tx.translate(-w, -h); break; } case TRANS_MIRROR_ROT270: { float w = x + width / 2; float h = y + height / 2; tx.translate(w, h); tx.rotate(ANGLE_270); tx.translate(-w, -h); tx.scale(-1, 1); break; } } return tx; } public static Affine2f transformRegion(Affine2f tx, float x, float y, int transform, float width, float height) { switch (transform) { case TRANS_ROT90: { float w = height; float h = y; tx.translate(w, h); tx.rotate(ANGLE_90); tx.translate(-w, -h); break; } case TRANS_ROT180: { float w = x + width; float h = y + height; tx.translate(w, h); tx.rotate(MathUtils.PI); tx.translate(-w, -h); break; } case TRANS_ROT270: { float w = x; float h = y + width; tx.translate(w, h); tx.rotate(ANGLE_270); tx.translate(-w, -h); break; } case TRANS_MIRROR: { float w = x + width; float h = y; tx.translate(w, h); tx.scale(-1, 1); tx.translate(-w, -h); break; } case TRANS_MIRROR_ROT90: { float w = x + height; float h = y; tx.translate(w, h); tx.rotate(ANGLE_90); tx.translate(-w, -h); tx.scale(-1, 1); break; } case TRANS_MIRROR_ROT180: { float w = x + width; float h = y; tx.translate(w, h); tx.scale(-1, 1); tx.translate(-w, -h); w = x + width; h = y + height; tx.translate(w, h); tx.rotate(MathUtils.PI); tx.translate(-w, -h); break; } case TRANS_MIRROR_ROT270: { tx.rotate(ANGLE_270); tx.scale(-1, 1); break; } } return tx; } public Affine2f combined(Matrix4 mat) { float[] m = mat.val; float m00 = m[Matrix4.M00] * this.m00 + m[Matrix4.M01] * this.m10; float m01 = m[Matrix4.M00] * this.m11 + m[Matrix4.M11] * this.m10; float tx = m[Matrix4.M00] * this.m01 + m[Matrix4.M01] * this.m11; float m10 = m[Matrix4.M00] * this.tx + m[Matrix4.M01] * this.ty + m[Matrix4.M02]; float m11 = m[Matrix4.M10] * this.tx + m[Matrix4.M11] * this.ty + m[Matrix4.M12]; m[Matrix4.M00] = m00; m[Matrix4.M01] = m01; m[Matrix4.M03] = tx; m[Matrix4.M10] = m10; m[Matrix4.M11] = m11; m[Matrix4.M13] = ty; return this; } public Affine2f combined4x4(float[] vals) { float[] m = vals; float m00 = m[Matrix4.M00] * this.m00 + m[Matrix4.M01] * this.m10; float m01 = m[Matrix4.M00] * this.m11 + m[Matrix4.M11] * this.m10; float tx = m[Matrix4.M00] * this.m01 + m[Matrix4.M01] * this.m11; float m10 = m[Matrix4.M00] * this.tx + m[Matrix4.M01] * this.ty + m[Matrix4.M02]; float m11 = m[Matrix4.M10] * this.tx + m[Matrix4.M11] * this.ty + m[Matrix4.M12]; m[Matrix4.M00] = m00; m[Matrix4.M01] = m01; m[Matrix4.M03] = tx; m[Matrix4.M10] = m10; m[Matrix4.M11] = m11; m[Matrix4.M13] = ty; return this; } public static final int GENERALITY = 4; /* x scale */ public float m00 = 1.0f; /* y skew */ public float m01 = 0.0f; /* x skew */ public float m10 = 0.0f; /* y scale */ public float m11 = 1.0f; /* x translation */ public float tx = 0.0f; /* y translation */ public float ty = 0.0f; public Affine2f() { this(1, 0, 0, 1, 0, 0); } public Affine2f idt() { this.m00 = 1; this.m01 = 0; this.tx = 0; this.m10 = 0; this.m11 = 1; this.ty = 0; return this; } public final void reset() { this.idt(); } public boolean equals(Object o) { if (null == o) { return false; } if (o == this) { return true; } if (o instanceof Affine2f) { Affine2f a2f = (Affine2f) o; if (a2f.m00 == m00 && a2f.m01 == m01 && a2f.tx == tx && a2f.ty == ty && a2f.m10 == m10 && a2f.m11 == m11) { return true; } } return false; } public boolean equals(Affine2f a2f) { if (a2f == null) { return false; } return a2f.m00 == m00 && a2f.m01 == m01 && a2f.tx == tx && a2f.ty == ty && a2f.m10 == m10 && a2f.m11 == m11; } public Affine2f set(Matrix3 matrix) { float[] other = matrix.val; m00 = other[Matrix3.M00]; m01 = other[Matrix3.M01]; tx = other[Matrix3.M02]; m10 = other[Matrix3.M10]; m11 = other[Matrix3.M11]; ty = other[Matrix3.M12]; return this; } public Affine2f setValue3x3(float[] vals) { m00 = vals[Matrix3.M00]; m01 = vals[Matrix3.M01]; tx = vals[Matrix3.M02]; m10 = vals[Matrix3.M10]; m11 = vals[Matrix3.M11]; ty = vals[Matrix3.M12]; return this; } public Affine2f set(Matrix4 matrix) { float[] other = matrix.val; m00 = other[Matrix4.M00]; m01 = other[Matrix4.M01]; tx = other[Matrix4.M03]; m10 = other[Matrix4.M10]; m11 = other[Matrix4.M11]; ty = other[Matrix4.M13]; return this; } public Affine2f setValue4x4(float[] vals) { m00 = vals[Matrix4.M00]; m01 = vals[Matrix4.M01]; tx = vals[Matrix4.M03]; m10 = vals[Matrix4.M10]; m11 = vals[Matrix4.M11]; ty = vals[Matrix4.M13]; return this; } public final void setThis(final Affine2f aff) { this.m00 = aff.m00; this.m11 = aff.m11; this.m01 = aff.m01; this.m10 = aff.m10; this.tx = aff.tx; this.ty = aff.ty; } public Affine2f(float scale, float angle, float tx, float ty) { this(scale, scale, angle, tx, ty); } public Affine2f(float scaleX, float scaleY, float angle, float tx, float ty) { float sina = MathUtils.sin(angle), cosa = MathUtils.cos(angle); this.m00 = cosa * scaleX; this.m01 = sina * scaleY; this.m10 = -sina * scaleX; this.m11 = cosa * scaleY; this.tx = tx; this.ty = ty; } public Affine2f(float m00, float m01, float m10, float m11, float tx, float ty) { this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; this.tx = tx; this.ty = ty; } public Affine2f set(Affine2f other) { return setTransform(other.m00, other.m01, other.m10, other.m11, other.tx, other.ty); } public float uniformScale() { float cp = m00 * m11 - m01 * m10; return (cp < 0f) ? -MathUtils.sqrt(-cp) : MathUtils.sqrt(cp); } public float scaleX() { return MathUtils.sqrt(m00 * m00 + m01 * m01); } public float scaleY() { return MathUtils.sqrt(m10 * m10 + m11 * m11); } public float rotation() { float n00 = m00, n10 = m10; float n01 = m01, n11 = m11; for (int ii = 0; ii < 10; ii++) { float o00 = n00, o10 = n10; float o01 = n01, o11 = n11; float det = o00 * o11 - o10 * o01; if (MathUtils.abs(det) == 0f) { throw LSystem.runThrow(this.toString()); } float hrdet = 0.5f / det; n00 = +o11 * hrdet + o00 * 0.5f; n10 = -o01 * hrdet + o10 * 0.5f; n01 = -o10 * hrdet + o01 * 0.5f; n11 = +o00 * hrdet + o11 * 0.5f; float d00 = n00 - o00, d10 = n10 - o10; float d01 = n01 - o01, d11 = n11 - o11; if (d00 * d00 + d10 * d10 + d01 * d01 + d11 * d11 < MathUtils.EPSILON) { break; } } return MathUtils.atan2(n01, n00); } public float getAngle() { return MathUtils.toRadians(rotation()); } public float tx() { return this.tx; } public float ty() { return this.ty; } public void get(float[] matrix) { matrix[0] = m00; matrix[1] = m01; matrix[2] = m10; matrix[3] = m11; matrix[4] = tx; matrix[5] = ty; } public Affine2f setUniformScale(float scale) { return (Affine2f) setScale(scale, scale); } public Affine2f setScaleX(float scaleX) { // 计算新的X轴缩放 float mult = scaleX / scaleX(); m00 *= mult; m01 *= mult; return this; } public Affine2f setScaleY(float scaleY) { // 计算新的Y轴缩放 float mult = scaleY / scaleY(); m10 *= mult; m11 *= mult; return this; } public Affine2f setRotation(float angle) { // 提取比例,然后重新应用旋转和缩放在一起 float sx = scaleX(), sy = scaleY(); float sina = MathUtils.sin(angle), cosa = MathUtils.cos(angle); m00 = cosa * sx; m01 = sina * sx; m10 = -sina * sy; m11 = cosa * sy; return this; } public Affine2f rotate(float angle) { float sina = MathUtils.sin(angle), cosa = MathUtils.cos(angle); return multiply(this, cosa, sina, -sina, cosa, 0, 0, this); } public Affine2f rotate(float angle, float x, float y) { float sina = MathUtils.sin(angle), cosa = MathUtils.cos(angle); return multiply(this, cosa, sina, -sina, cosa, x, y, this); } public final Affine2f preRotate(final float angle) { final float angleRad = MathUtils.DEG_TO_RAD * angle; final float sin = MathUtils.sin(angleRad); final float cos = MathUtils.cos(angleRad); final float m00 = this.m00; final float m01 = this.m01; final float m10 = this.m10; final float m11 = this.m11; this.m00 = cos * m00 + sin * m10; this.m01 = cos * m01 + sin * m11; this.m10 = cos * m10 - sin * m00; this.m11 = cos * m11 - sin * m01; return this; } public final Affine2f postRotate(final float angle) { final float angleRad = MathUtils.DEG_TO_RAD * angle; final float sin = MathUtils.sin(angleRad); final float cos = MathUtils.cos(angleRad); final float m00 = this.m00; final float m01 = this.m01; final float m10 = this.m10; final float m11 = this.m11; final float tx = this.tx; final float ty = this.ty; this.m00 = m00 * cos - m01 * sin; this.m01 = m00 * sin + m01 * cos; this.m10 = m10 * cos - m11 * sin; this.m11 = m10 * sin + m11 * cos; this.tx = tx * cos - ty * sin; this.ty = tx * sin + ty * cos; return this; } public final Affine2f setToRotate(final float angle) { final float angleRad = MathUtils.DEG_TO_RAD * angle; final float sin = MathUtils.sin(angleRad); final float cos = MathUtils.cos(angleRad); this.m00 = cos; this.m01 = sin; this.m10 = -sin; this.m11 = cos; this.tx = 0.0f; this.ty = 0.0f; return this; } public Affine2f setTranslation(float tx, float ty) { this.tx = tx; this.ty = ty; return this; } public Affine2f setTx(float tx) { this.tx = tx; return this; } public Affine2f setTy(float ty) { this.ty = ty; return this; } public Affine2f setTo(float m00, float m01, float m10, float m11, float tx, float ty) { return setTransform(m00, m01, m10, m11, tx, ty); } public Affine2f setTransform(float m00, float m01, float m10, float m11, float tx, float ty) { this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; this.tx = tx; this.ty = ty; return this; } public Affine2f uniformScale(float scale) { return scale(scale, scale); } public Affine2f scale(float scaleX, float scaleY) { m00 *= scaleX; m01 *= scaleX; m10 *= scaleY; m11 *= scaleY; return this; } public final Affine2f preScale(final float sx, final float sy) { return scale(sx, sy); } public final Affine2f postScale(final float sx, final float sy) { this.m00 = this.m00 * sx; this.m01 = this.m01 * sy; this.m10 = this.m10 * sx; this.m11 = this.m11 * sy; this.tx = this.tx * sx; this.ty = this.ty * sy; return this; } public final Affine2f setToScale(final float sx, final float sy) { this.m00 = sx; this.m01 = 0.0f; this.m10 = 0.0f; this.m11 = sy; this.tx = 0.0f; this.ty = 0.0f; return this; } public Affine2f scaleX(float scaleX) { return multiply(this, scaleX, 0, 0, 1, 0, 0, this); } public Affine2f scaleY(float scaleY) { return multiply(this, 1, 0, 0, scaleY, 0, 0, this); } public Affine2f translate(float tx, float ty) { this.tx += m00 * tx + m10 * ty; this.ty += m11 * ty + m01 * tx; return this; } public final Affine2f preTranslate(final float tx, final float ty) { return translate(tx, ty); } public final Affine2f postTranslate(final float tx, final float ty) { this.tx += tx; this.ty += ty; return this; } public final Affine2f setToTranslate(final float tx, final float ty) { this.m00 = 1.0f; this.m01 = 0.0f; this.m10 = 0.0f; this.m11 = 1.0f; this.tx = tx; this.ty = ty; return this; } public Affine2f translateX(float tx) { return multiply(this, 1, 0, 0, 1, tx, 0, this); } public Affine2f translateY(float ty) { return multiply(this, 1, 0, 0, 1, 0, ty, this); } public Affine2f shear(float sx, float sy) { return multiply(this, 1, sy, sx, 1, 0, 0, this); } public Affine2f shearX(float sx) { return multiply(this, 1, 0, sx, 1, 0, 0, this); } public Affine2f shearY(float sy) { return multiply(this, 1, sy, 0, 1, 0, 0, this); } public final Affine2f preShear(final float sx, final float sy) { final float tanX = MathUtils.tan(-MathUtils.DEG_TO_RAD * sx); final float tanY = MathUtils.tan(-MathUtils.DEG_TO_RAD * sy); final float m00 = this.m00; final float m01 = this.m01; final float m10 = this.m10; final float m11 = this.m11; final float tx = this.tx; final float ty = this.ty; this.m00 = m00 + tanY * m10; this.m01 = m01 + tanY * m11; this.m10 = tanX * m00 + m10; this.m11 = tanX * m01 + m11; this.tx = tx; this.ty = ty; return this; } public final void postShear(final float sx, final float sy) { final float tanX = MathUtils.tan(-MathUtils.DEG_TO_RAD * sx); final float tanY = MathUtils.tan(-MathUtils.DEG_TO_RAD * sy); final float m00 = this.m00; final float m01 = this.m01; final float m10 = this.m10; final float m11 = this.m11; final float tx = this.tx; final float ty = this.ty; this.m00 = m00 + m01 * tanX; this.m01 = m00 * tanY + m01; this.m10 = m10 + m11 * tanX; this.m11 = m10 * tanY + m11; this.tx = tx + ty * tanX; this.ty = tx * tanY + ty; } public final Affine2f setToShear(final float sx, final float sy) { this.m00 = 1.0f; this.m01 = MathUtils.tan(-MathUtils.DEG_TO_RAD * sy); this.m10 = MathUtils.tan(-MathUtils.DEG_TO_RAD * sx); this.m11 = 1.0f; this.tx = 0.0f; this.ty = 0.0f; return this; } public Affine2f invert() { // 计算行列式,并临时存储数值 float det = m00 * m11 - m10 * m01; if (MathUtils.abs(det) == 0f) { // 行列式为零时,矩阵将不可逆,无法还原所以报错 throw LSystem.runThrow(this.toString()); } float rdet = 1f / det; return new Affine2f(+m11 * rdet, -m10 * rdet, -m01 * rdet, +m00 * rdet, (m10 * ty - m11 * tx) * rdet, (m01 * tx - m00 * ty) * rdet); } public Affine2f concatenate(Affine2f other) { if (generality() < other.generality()) { return other.preConcatenate(this); } if (other instanceof Affine2f) { return multiply(this, (Affine2f) other, new Affine2f()); } else { Affine2f oaff = new Affine2f(other); return multiply(this, oaff, oaff); } } public Affine2f preConcatenate(Affine2f other) { if (generality() < other.generality()) { return other.concatenate(this); } if (other instanceof Affine2f) { return multiply((Affine2f) other, this, new Affine2f()); } else { Affine2f oaff = new Affine2f(other); return multiply(oaff, this, oaff); } } public final Affine2f postConcatenate(final Affine2f t) { return postConcatenate(t.m00, t.m01, t.m10, t.m11, t.tx, t.ty); } public Affine2f postConcatenate(final float ma, final float mb, final float mc, final float md, final float mx, final float my) { final float m00 = this.m00; final float m01 = this.m01; final float m10 = this.m10; final float m11 = this.m11; final float tx = this.tx; final float ty = this.ty; this.m00 = m00 * ma + m01 * mc; this.m01 = m00 * mb + m01 * md; this.m10 = m10 * ma + m11 * mc; this.m11 = m10 * mb + m11 * md; this.tx = tx * ma + ty * mc + mx; this.ty = tx * mb + ty * md + my; return this; } public Affine2f lerp(Affine2f other, float t) { if (generality() < other.generality()) { return other.lerp(this, -t); } Affine2f ot = (other instanceof Affine2f) ? (Affine2f) other : new Affine2f(other); return new Affine2f(m00 + t * (ot.m00 - m00), m01 + t * (ot.m01 - m01), m10 + t * (ot.m10 - m10), m11 + t * (ot.m11 - m11), tx + t * (ot.tx - tx), ty + t * (ot.ty - ty)); } public void transform(Vector2f[] src, int srcOff, Vector2f[] dst, int dstOff, int count) { for (int ii = 0; ii < count; ii++) { transform(src[srcOff++], dst[dstOff++]); } } public void transform(float[] src, int srcOff, float[] dst, int dstOff, int count) { for (int ii = 0; ii < count; ii++) { float x = src[srcOff++], y = src[srcOff++]; dst[dstOff++] = m00 * x + m10 * y + tx; dst[dstOff++] = m01 * x + m11 * y + ty; } } public void transform(final float[] vertices) { int count = vertices.length >> 1; int i = 0; int j = 0; while (--count >= 0) { final float x = vertices[i++]; final float y = vertices[i++]; vertices[j++] = x * this.m00 + y * this.m10 + this.tx; vertices[j++] = x * this.m01 + y * this.m11 + this.ty; } } public PointI transformPoint(int pointX, int pointY, PointI resultPoint) { int x = (int) (this.m00 * pointX + this.m01 * pointY + this.tx); int y = (int) (this.m10 * pointX + this.m11 * pointY + this.ty); if (resultPoint != null) { resultPoint.set(x, y); return resultPoint; } return new PointI(x, y); } public PointF transformPoint(float pointX, float pointY, PointF resultPoint) { float x = this.m00 * pointX + this.m01 * pointY + this.tx; float y = this.m10 * pointX + this.m11 * pointY + this.ty; if (resultPoint != null) { resultPoint.set(x, y); return resultPoint; } return new PointF(x, y); } public Vector2f transformPoint(float pointX, float pointY, Vector2f resultPoint) { float x = this.m00 * pointX + this.m01 * pointY + this.tx; float y = this.m10 * pointX + this.m11 * pointY + this.ty; if (resultPoint != null) { resultPoint.set(x, y); return resultPoint; } return new Vector2f(x, y); } public Vector2f transformPoint(Vector2f v, Vector2f into) { float x = v.x(), y = v.y(); return into.set(m00 * x + m10 * y + tx, m01 * x + m11 * y + ty); } public Vector2f transform(Vector2f v, Vector2f into) { float x = v.x(), y = v.y(); return into.set(m00 * x + m10 * y, m01 * x + m11 * y); } public Vector2f inverseTransform(Vector2f v, Vector2f into) { float x = v.x(), y = v.y(); float det = m00 * m11 - m01 * m10; if (MathUtils.abs(det) == 0f) { // 行列式为零时,矩阵将不可逆,无法还原所以报错 throw LSystem.runThrow(this.toString()); } float rdet = 1 / det; return into.set((x * m11 - y * m10) * rdet, (y * m00 - x * m01) * rdet); } public Matrix4 toViewMatrix4() { Dimension dim = LSystem.viewSize; if (projectionMatrix == null) { projectionMatrix = new Matrix4(); } projectionMatrix.setToOrtho2D(0, 0, dim.width * LSystem.getScaleWidth(), dim.height * LSystem.getScaleHeight()); projectionMatrix.thisCombine(this); return projectionMatrix; } public Affine2f cpy() { return new Affine2f(m00, m01, m10, m11, tx, ty); } public int generality() { return GENERALITY; } public Object tag; public Vector2f scale() { return new Vector2f(scaleX(), scaleY()); } public Vector2f translation() { return new Vector2f(tx(), ty()); } public Affine2f setScale(float scaleX, float scaleY) { setScaleX(scaleX); setScaleY(scaleY); return this; } @Override public float getX() { return tx(); } @Override public float getY() { return ty(); } /** 显示结果上补足了不存在的长高宽坐标,充当完整3x3矩阵…… **/ @Override public String toString() { return "affine [" + MathUtils.toString(m00) + " " + MathUtils.toString(m01) + " " + MathUtils.toString(m10) + " " + MathUtils.toString(m11) + " " + translation() + "][0.0, 0.0, 1.0]"; } }