From 92164921a5dba94f0c1b7630eb441aed846c9a96 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Fri, 13 Jan 2023 22:28:09 -0400 Subject: [PATCH] Cleaned up trigonometry. * Do one conversion to radians for sin and cos. * Added atan2Deg. * PathConstraint wasn't using SpineUtils. * PointAttachment was using MathUtils. --- .../src/com/esotericsoftware/spine/Bone.java | 101 ++++++++++-------- .../esotericsoftware/spine/IkConstraint.java | 4 +- .../spine/PathConstraint.java | 30 +++--- .../spine/PhysicsConstraint.java | 2 +- .../com/esotericsoftware/spine/Skeleton.java | 11 +- .../spine/attachments/PointAttachment.java | 6 +- .../spine/attachments/RegionAttachment.java | 13 +-- .../spine/utils/SpineUtils.java | 14 ++- 8 files changed, 95 insertions(+), 86 deletions(-) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java index 16def0359..7a5ad5418 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java @@ -110,11 +110,13 @@ public class Bone implements Updatable { Bone parent = this.parent; if (parent == null) { // Root bone. Skeleton skeleton = this.skeleton; - float rotationY = rotation + 90 + shearY, sx = skeleton.scaleX, sy = skeleton.scaleY; - a = cosDeg(rotation + shearX) * scaleX * sx; - b = cosDeg(rotationY) * scaleY * sx; - c = sinDeg(rotation + shearX) * scaleX * sy; - d = sinDeg(rotationY) * scaleY * sy; + float sx = skeleton.scaleX, sy = skeleton.scaleY; + float rx = (rotation + shearX) * degRad; + float ry = (rotation + 90 + shearY) * degRad; + a = cos(rx) * scaleX * sx; + b = cos(ry) * scaleY * sx; + c = sin(rx) * scaleX * sy; + d = sin(ry) * scaleY * sy; worldX = x * sx + skeleton.x; worldY = y * sy + skeleton.y; return; @@ -126,11 +128,12 @@ public class Bone implements Updatable { switch (data.transformMode) { case normal: { - float rotationY = rotation + 90 + shearY; - float la = cosDeg(rotation + shearX) * scaleX; - float lb = cosDeg(rotationY) * scaleY; - float lc = sinDeg(rotation + shearX) * scaleX; - float ld = sinDeg(rotationY) * scaleY; + float rx = (rotation + shearX) * degRad; + float ry = (rotation + 90 + shearY) * degRad; + float la = cos(rx) * scaleX; + float lb = cos(ry) * scaleY; + float lc = sin(rx) * scaleX; + float ld = sin(ry) * scaleY; a = pa * la + pb * lc; b = pa * lb + pb * ld; c = pc * la + pd * lc; @@ -138,11 +141,12 @@ public class Bone implements Updatable { return; } case onlyTranslation: { - float rotationY = rotation + 90 + shearY; - a = cosDeg(rotation + shearX) * scaleX; - b = cosDeg(rotationY) * scaleY; - c = sinDeg(rotation + shearX) * scaleX; - d = sinDeg(rotationY) * scaleY; + float rx = (rotation + shearX) * degRad; + float ry = (rotation + 90 + shearY) * degRad; + a = cos(rx) * scaleX; + b = cos(ry) * scaleY; + c = sin(rx) * scaleX; + d = sin(ry) * scaleY; break; } case noRotationOrReflection: { @@ -153,18 +157,18 @@ public class Bone implements Updatable { pc /= skeleton.scaleY; pb = pc * s; pd = pa * s; - prx = atan2(pc, pa) * radDeg; + prx = atan2Deg(pc, pa); } else { pa = 0; pc = 0; - prx = 90 - atan2(pd, pb) * radDeg; + prx = 90 - atan2Deg(pd, pb); } - float rx = rotation + shearX - prx; - float ry = rotation + shearY - prx + 90; - float la = cosDeg(rx) * scaleX; - float lb = cosDeg(ry) * scaleY; - float lc = sinDeg(rx) * scaleX; - float ld = sinDeg(ry) * scaleY; + float rx = (rotation + shearX - prx) * degRad; + float ry = (rotation + shearY - prx + 90) * degRad; + float la = cos(rx) * scaleX; + float lb = cos(ry) * scaleY; + float lc = sin(rx) * scaleX; + float ld = sin(ry) * scaleY; a = pa * la - pb * lc; b = pa * lb - pb * ld; c = pc * la + pd * lc; @@ -173,7 +177,8 @@ public class Bone implements Updatable { } case noScale: case noScaleOrReflection: - float cos = cosDeg(rotation), sin = sinDeg(rotation); + rotation *= degRad; + float cos = cos(rotation), sin = sin(rotation); float za = (pa * cos + pb * sin) / skeleton.scaleX; float zc = (pc * cos + pd * sin) / skeleton.scaleY; float s = (float)Math.sqrt(za * za + zc * zc); @@ -183,13 +188,15 @@ public class Bone implements Updatable { s = (float)Math.sqrt(za * za + zc * zc); if (data.transformMode == TransformMode.noScale && (pa * pd - pb * pc < 0) != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s; - float r = PI / 2 + atan2(zc, za); - float zb = cos(r) * s; - float zd = sin(r) * s; - float la = cosDeg(shearX) * scaleX; - float lb = cosDeg(90 + shearY) * scaleY; - float lc = sinDeg(shearX) * scaleX; - float ld = sinDeg(90 + shearY) * scaleY; + rotation = PI / 2 + atan2(zc, za); + float zb = cos(rotation) * s; + float zd = sin(rotation) * s; + shearX *= degRad; + shearY = (90 + shearY) * degRad; + float la = cos(shearX) * scaleX; + float lb = cos(shearY) * scaleY; + float lc = sin(shearX) * scaleX; + float ld = sin(shearY) * scaleY; a = za * la + zb * lc; b = za * lb + zb * ld; c = zc * la + zd * lc; @@ -398,11 +405,11 @@ public class Bone implements Updatable { ax = worldX - skeleton.x; ay = worldY - skeleton.y; float a = this.a, b = this.b, c = this.c, d = this.d; - arotation = atan2(c, a) * radDeg; + arotation = atan2Deg(c, a); ascaleX = (float)Math.sqrt(a * a + c * c); ascaleY = (float)Math.sqrt(b * b + d * d); ashearX = 0; - ashearY = atan2(a * b + c * d, a * d - b * c) * radDeg; + ashearY = atan2Deg(a * b + c * d, a * d - b * c); return; } @@ -434,7 +441,7 @@ public class Bone implements Updatable { } case noScale: case noScaleOrReflection: - float cos = cosDeg(rotation), sin = sinDeg(rotation); + float r = rotation * degRad, cos = cos(r), sin = sin(r); pa = (pa * cos + pb * sin) / skeleton.scaleX; pc = (pc * cos + pd * sin) / skeleton.scaleY; float s = (float)Math.sqrt(pa * pa + pc * pc); @@ -443,7 +450,7 @@ public class Bone implements Updatable { pc *= s; s = (float)Math.sqrt(pa * pa + pc * pc); if (data.transformMode == TransformMode.noScale && pid < 0 != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s; - float r = PI / 2 + atan2(pc, pa); + r = PI / 2 + atan2(pc, pa); pb = cos(r) * s; pd = sin(r) * s; pid = 1 / (pa * pd - pb * pc); @@ -463,13 +470,13 @@ public class Bone implements Updatable { if (ascaleX > 0.0001f) { float det = ra * rd - rb * rc; ascaleY = det / ascaleX; - ashearY = -atan2(ra * rb + rc * rd, det) * radDeg; - arotation = atan2(rc, ra) * radDeg; + ashearY = -atan2Deg(ra * rb + rc * rd, det); + arotation = atan2Deg(rc, ra); } else { ascaleX = 0; ascaleY = (float)Math.sqrt(rb * rb + rd * rd); ashearY = 0; - arotation = 90 - atan2(rd, rb) * radDeg; + arotation = 90 - atan2Deg(rd, rb); } } @@ -531,12 +538,12 @@ public class Bone implements Updatable { /** The world rotation for the X axis, calculated using {@link #a} and {@link #c}. */ public float getWorldRotationX () { - return atan2(c, a) * radDeg; + return atan2Deg(c, a); } /** The world rotation for the Y axis, calculated using {@link #b} and {@link #d}. */ public float getWorldRotationY () { - return atan2(d, b) * radDeg; + return atan2Deg(d, b); } /** The magnitude (always positive) of the world scale X, calculated using {@link #a} and {@link #c}. */ @@ -585,15 +592,16 @@ public class Bone implements Updatable { /** Transforms a world rotation to a local rotation. */ public float worldToLocalRotation (float worldRotation) { - float sin = sinDeg(worldRotation), cos = cosDeg(worldRotation); - return atan2(a * sin - c * cos, d * cos - b * sin) * radDeg + rotation - shearX; + worldRotation *= degRad; + float sin = sin(worldRotation), cos = cos(worldRotation); + return atan2Deg(a * sin - c * cos, d * cos - b * sin) + rotation - shearX; } /** Transforms a local rotation to a world rotation. */ public float localToWorldRotation (float localRotation) { - localRotation -= rotation - shearX; - float sin = sinDeg(localRotation), cos = cosDeg(localRotation); - return atan2(cos * c + sin * d, cos * a + sin * b) * radDeg; + localRotation = (localRotation - rotation - shearX) * degRad; + float sin = sin(localRotation), cos = cos(localRotation); + return atan2Deg(cos * c + sin * d, cos * a + sin * b); } /** Rotates the world transform the specified amount. @@ -601,7 +609,8 @@ public class Bone implements Updatable { * After changes are made to the world transform, {@link #updateAppliedTransform()} should be called and {@link #update()} will * need to be called on any child bones, recursively. */ public void rotateWorld (float degrees) { - float cos = cosDeg(degrees), sin = sinDeg(degrees); + degrees *= degRad; + float sin = sin(degrees), cos = cos(degrees); a = cos * a - sin * c; b = cos * b - sin * d; c = sin * a + cos * c; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index ed585199f..9cfda305f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -200,7 +200,7 @@ public class IkConstraint implements Updatable { float sc = pc / bone.skeleton.scaleY; pb = -sc * s * bone.skeleton.scaleX; pd = sa * s * bone.skeleton.scaleY; - rotationIK += atan2(sc, sa) * radDeg; + rotationIK += atan2Deg(sc, sa); // Fall through. default: float x = targetX - p.worldX, y = targetY - p.worldY; @@ -208,7 +208,7 @@ public class IkConstraint implements Updatable { tx = (x * pd - y * pb) / d - bone.ax; ty = (y * pa - x * pc) / d - bone.ay; } - rotationIK += atan2(ty, tx) * radDeg; + rotationIK += atan2Deg(ty, tx); if (bone.ascaleX < 0) rotationIK += 180; if (rotationIK > 180) rotationIK -= 360; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java index 71b48b3ea..4576d19b8 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -203,11 +203,11 @@ public class PathConstraint implements Updatable { else if (spaces[i + 1] < epsilon) r = positions[p + 2]; else - r = (float)Math.atan2(dy, dx); - r -= (float)Math.atan2(c, a); + r = atan2(dy, dx); + r -= atan2(c, a); if (tip) { - cos = (float)Math.cos(r); - sin = (float)Math.sin(r); + cos = cos(r); + sin = sin(r); float length = bone.data.length; boneX += (length * (cos * a - sin * c) - dx) * mixRotate; boneY += (length * (sin * a + cos * c) - dy) * mixRotate; @@ -218,8 +218,8 @@ public class PathConstraint implements Updatable { else if (r < -PI) // r += PI2; r *= mixRotate; - cos = (float)Math.cos(r); - sin = (float)Math.sin(r); + cos = cos(r); + sin = sin(r); bone.a = cos * a - sin * c; bone.b = cos * b - sin * d; bone.c = sin * a + cos * c; @@ -465,16 +465,16 @@ public class PathConstraint implements Updatable { } private void addBeforePosition (float p, float[] temp, int i, float[] out, int o) { - float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = (float)Math.atan2(dy, dx); - out[o] = x1 + p * (float)Math.cos(r); - out[o + 1] = y1 + p * (float)Math.sin(r); + float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = atan2(dy, dx); + out[o] = x1 + p * cos(r); + out[o + 1] = y1 + p * sin(r); out[o + 2] = r; } private void addAfterPosition (float p, float[] temp, int i, float[] out, int o) { - float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = (float)Math.atan2(dy, dx); - out[o] = x1 + p * (float)Math.cos(r); - out[o + 1] = y1 + p * (float)Math.sin(r); + float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = atan2(dy, dx); + out[o] = x1 + p * cos(r); + out[o + 1] = y1 + p * sin(r); out[o + 2] = r; } @@ -483,7 +483,7 @@ public class PathConstraint implements Updatable { if (p < epsilon || Float.isNaN(p)) { out[o] = x1; out[o + 1] = y1; - out[o + 2] = (float)Math.atan2(cy1 - y1, cx1 - x1); + out[o + 2] = atan2(cy1 - y1, cx1 - x1); return; } float tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; @@ -493,9 +493,9 @@ public class PathConstraint implements Updatable { out[o + 1] = y; if (tangents) { if (p < 0.001f) - out[o + 2] = (float)Math.atan2(cy1 - y1, cx1 - x1); + out[o + 2] = atan2(cy1 - y1, cx1 - x1); else - out[o + 2] = (float)Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + out[o + 2] = atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java index 8daae0a0d..2afd10827 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java @@ -371,7 +371,7 @@ public class PhysicsConstraint implements Updatable { float s = (float)Math.sqrt(dx * dx + dy * dy) / length, r = atan2(dy, dx), sin = sin(r), cos = cos(r); if (constraint.mix == 1) { bone.updateWorldTransform(bone.ax, bone.ay, - atan2(bone.a * sin - bone.c * cos, bone.d * cos - bone.b * sin) * radDeg + bone.arotation - bone.ashearX, + atan2Deg(bone.a * sin - bone.c * cos, bone.d * cos - bone.b * sin) + bone.arotation - bone.ashearX, bone.ascaleX * s, bone.ascaleY, bone.ashearX, bone.ashearY); } else { // BOZO diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java index 150b2d7ee..f67bcf8e4 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -444,11 +444,12 @@ public class Skeleton { rootBone.worldX = pa * x + pb * y + parent.worldX; rootBone.worldY = pc * x + pd * y + parent.worldY; - float rotationY = rootBone.rotation + 90 + rootBone.shearY; - float la = cosDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; - float lb = cosDeg(rotationY) * rootBone.scaleY; - float lc = sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; - float ld = sinDeg(rotationY) * rootBone.scaleY; + float rx = (rootBone.rotation + rootBone.shearX) * degRad; + float ry = (rootBone.rotation + 90 + rootBone.shearY) * degRad; + float la = cos(rx) * rootBone.scaleX; + float lb = cos(ry) * rootBone.scaleY; + float lc = sin(rx) * rootBone.scaleX; + float ld = sin(ry) * rootBone.scaleY; rootBone.a = (pa * la + pb * lc) * scaleX; rootBone.b = (pa * lb + pb * ld) * scaleX; rootBone.c = (pc * la + pd * lc) * scaleY; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PointAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PointAttachment.java index 4a3e5a14a..d1bc50083 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PointAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PointAttachment.java @@ -29,7 +29,7 @@ package com.esotericsoftware.spine.attachments; -import static com.badlogic.gdx.math.MathUtils.*; +import static com.esotericsoftware.spine.utils.SpineUtils.*; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; @@ -97,10 +97,10 @@ public class PointAttachment extends Attachment { } public float computeWorldRotation (Bone bone) { - float cos = cosDeg(rotation), sin = sinDeg(rotation); + float r = rotation * degRad, cos = cos(r), sin = sin(r); float x = cos * bone.getA() + sin * bone.getB(); float y = cos * bone.getC() + sin * bone.getD(); - return (float)Math.atan2(y, x) * radDeg; + return atan2Deg(y, x); } public PointAttachment copy () { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java index 2ea4d4a90..a82fd56af 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java @@ -93,8 +93,7 @@ public class RegionAttachment extends Attachment implements HasTextureRegion { return; } - float width = getWidth(); - float height = getHeight(); + float width = getWidth(), height = getHeight(); float localX2 = width / 2; float localY2 = height / 2; float localX = -localX2; @@ -113,17 +112,13 @@ public class RegionAttachment extends Attachment implements HasTextureRegion { localY2 -= (region.originalHeight - region.offsetY - region.packedHeight) / region.originalHeight * height; } } - float scaleX = getScaleX(); - float scaleY = getScaleY(); + float scaleX = getScaleX(), scaleY = getScaleY(); localX *= scaleX; localY *= scaleY; localX2 *= scaleX; localY2 *= scaleY; - float rotation = getRotation(); - float cos = (float)Math.cos(degRad * rotation); - float sin = (float)Math.sin(degRad * rotation); - float x = getX(); - float y = getY(); + float r = getRotation() * degRad, cos = cos(r), sin = sin(r); + float x = getX(), y = getY(); float localXCos = localX * cos + x; float localXSin = localX * sin; float localYCos = localY * cos + y; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SpineUtils.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SpineUtils.java index f5acfae18..29f76288b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SpineUtils.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SpineUtils.java @@ -37,23 +37,27 @@ public class SpineUtils { static public final float degreesToRadians = PI / 180; static public final float degRad = degreesToRadians; - public static float cosDeg (float degrees) { + static public float cosDeg (float degrees) { return (float)Math.cos(degrees * degRad); } - public static float sinDeg (float degrees) { + static public float sinDeg (float degrees) { return (float)Math.sin(degrees * degRad); } - public static float cos (float radians) { + static public float cos (float radians) { return (float)Math.cos(radians); } - public static float sin (float radians) { + static public float sin (float radians) { return (float)Math.sin(radians); } - public static float atan2 (float y, float x) { + static public float atan2Deg (float y, float x) { + return (float)Math.atan2(y, x) * radDeg; + } + + static public float atan2 (float y, float x) { return (float)Math.atan2(y, x); }