Improved Platform transforms & rendering
*Improved Platform (MiscGroups) transforms. Positions are now 100% accurate, rotations ~90% *Platforms won't be rendered if their tilt is too big *Misc objects now use yawData.yaw as their "y rotation" in rendering *Renamed Platforms layer
This commit is contained in:
parent
0c656f3ca6
commit
872d44a3f0
@ -130,5 +130,5 @@
|
||||
}
|
||||
|
||||
.map svg g.platform rect {
|
||||
fill: #333;
|
||||
fill: #444;
|
||||
}
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
import Constants from "../../../helpers/constants";
|
||||
|
||||
export default function PlatformRenderer(props) {
|
||||
const { object } = props;
|
||||
const [x, y] = object.pos.toSVGCoords();
|
||||
if(!object.def) return null;
|
||||
const tiltNotOk = object.yawData.tilt > Constants.map.platformMaxTilt;
|
||||
if(!object.def || tiltNotOk) return null;
|
||||
|
||||
const [centerX, centerY] = object.def.center.toSVGCoords();
|
||||
const sizeX = object.def.size.x;
|
||||
const sizeY = object.def.size.z;
|
||||
|
||||
return (
|
||||
<g className="platform" transform={`translate(${x}, ${y}) rotate(${object.rot.y})`}>
|
||||
<g className="platform" transform={`translate(${x}, ${y}) rotate(${object.yawData.yaw})`}>
|
||||
<rect
|
||||
x={-sizeX / 2 + centerX}
|
||||
y={-sizeY / 2 + centerY}
|
||||
|
||||
@ -6,8 +6,9 @@ export default function SignalBoxRenderer(props) {
|
||||
const [x, y] = object.pos.toSVGCoords();
|
||||
const text = object.getPrintableSignalBoxName();
|
||||
|
||||
const rotDiff = object.def.undef ? Math.round(object.rot.y / 90) * (-90) : object.def.rot * 90;
|
||||
const rot = object.rot.y + rotDiff;
|
||||
const yaw = object.yawData?.yaw || object.rot.y;
|
||||
const rotDiff = object.def.undef ? Math.round(yaw / 90) * (-90) : object.def.rot * 90;
|
||||
const rot = yaw + rotDiff;
|
||||
|
||||
return (
|
||||
<g className="signalbox" transform={`translate(${x}, ${y}) rotate(${rot})`}>
|
||||
|
||||
@ -5,7 +5,8 @@ const Constants = {
|
||||
zoomMin: 0.03,
|
||||
zoomMax: 200.0,
|
||||
rotationSensitivity: 0.2,
|
||||
forcePointerEvents: false
|
||||
forcePointerEvents: false,
|
||||
platformMaxTilt: 0.5
|
||||
},
|
||||
parser: {
|
||||
logSceneryAfterFinished: true,
|
||||
@ -66,7 +67,7 @@ const Constants = {
|
||||
layers: [
|
||||
{
|
||||
id: 'platforms',
|
||||
name: 'Platforms (WIP)',
|
||||
name: 'Platforms',
|
||||
default: true,
|
||||
cond: () => !Constants.parser.skipPlatforms,
|
||||
},
|
||||
|
||||
@ -23,7 +23,8 @@ export default class MiscGroup {
|
||||
|
||||
getQuaternion() {
|
||||
if (!this.quaternion) {
|
||||
this.quaternion = Quaternion.fromEulerAngles(this.rot.multiply(Math.PI / 180));
|
||||
const rotRad = this.rot.multiply(Math.PI / 180);
|
||||
this.quaternion = Quaternion.fromEulerAngles(rotRad).normalize();
|
||||
}
|
||||
|
||||
return this.quaternion;
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
import AngleHelper from "../../helpers/angleHelper";
|
||||
import Quaternion from "../quaternion";
|
||||
import SceneryObject from "../scenery-object";
|
||||
import Vector3 from "../vector3";
|
||||
|
||||
export default class Misc extends SceneryObject {
|
||||
prefab_name;
|
||||
name;
|
||||
yawData;
|
||||
category = "misc";
|
||||
type = "Misc";
|
||||
|
||||
constructor(id, misc_id, prefab_name, pos, rot, name) {
|
||||
constructor(id, misc_id, prefab_name, pos, rot, yawData, name) {
|
||||
super(id, pos, rot);
|
||||
Object.assign(this, {
|
||||
misc_id,
|
||||
prefab_name,
|
||||
name
|
||||
name,
|
||||
yawData
|
||||
});
|
||||
}
|
||||
|
||||
@ -35,14 +39,19 @@ export default class Misc extends SceneryObject {
|
||||
}
|
||||
|
||||
static applyGroupTransforms(localPos, localRot, miscGroups) {
|
||||
const localRotRad = localRot.multiply(Math.PI / 180);
|
||||
let worldQuat = Quaternion.fromEulerAngles(localRotRad).normalize();
|
||||
let worldPos = localPos.clone();
|
||||
let worldRot = localRot.clone();
|
||||
|
||||
for (const group of miscGroups) {
|
||||
worldPos = group.getQuaternion().rotateVector(worldPos).add(group.pos);
|
||||
worldRot = worldRot.add(group.rot);
|
||||
const groupQuat = group.getQuaternion();
|
||||
worldPos = groupQuat.rotateVector(worldPos).add(group.pos);
|
||||
worldQuat = groupQuat.multiply(worldQuat).normalize();
|
||||
}
|
||||
|
||||
const worldRot = worldQuat.toEulerAngles().multiply(180 / Math.PI);
|
||||
const yawData = worldQuat.getMiscYawData();
|
||||
|
||||
return [ worldPos, worldRot ];
|
||||
return [ worldPos, worldRot, yawData ];
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,8 +7,8 @@ export default class Platform extends Misc {
|
||||
type = "Platform";
|
||||
def = null;
|
||||
|
||||
constructor(id, misc_id, prefab_name, pos, rot, name) {
|
||||
super(id, misc_id, prefab_name, pos, rot, name);
|
||||
constructor(id, misc_id, prefab_name, pos, rot, yawData, name) {
|
||||
super(id, misc_id, prefab_name, pos, rot, yawData, name);
|
||||
|
||||
this.def = Platform.getDef(name, prefab_name);
|
||||
}
|
||||
|
||||
@ -8,8 +8,8 @@ export default class SignalBox extends Misc {
|
||||
applied = false;
|
||||
def = null;
|
||||
|
||||
constructor(id, misc_id, prefab_name, pos, rot, name) {
|
||||
super(id, misc_id, prefab_name, pos, rot, name);
|
||||
constructor(id, misc_id, prefab_name, pos, rot, yawData, name) {
|
||||
super(id, misc_id, prefab_name, pos, rot, yawData, name);
|
||||
|
||||
this.def = SignalBox.getDef(name, prefab_name);
|
||||
}
|
||||
|
||||
@ -14,27 +14,50 @@ export default class Quaternion {
|
||||
}
|
||||
|
||||
static fromEulerAngles(vector) {
|
||||
const { x: rotX, y: rotY, z: rotZ } = vector;
|
||||
const halfZ = vector.z * 0.5;
|
||||
const halfX = vector.x * 0.5;
|
||||
const halfY = vector.y * 0.5;
|
||||
|
||||
const cz = Math.cos(rotZ * 0.5);
|
||||
const sz = Math.sin(rotZ * 0.5);
|
||||
const cx = Math.cos(rotX * 0.5);
|
||||
const sx = Math.sin(rotX * 0.5);
|
||||
const cy = Math.cos(rotY * 0.5);
|
||||
const sy = Math.sin(rotY * 0.5);
|
||||
|
||||
const w = cx * cy * cz + sx * sy * sz;
|
||||
const x = sx * cy * cz + cx * sy * sz;
|
||||
const y = cx * sy * cz - sx * cy * sz;
|
||||
const z = cx * cy * sz - sx * sy * cz;
|
||||
|
||||
return new Quaternion(w, x, y, z);
|
||||
const sz = Math.sin(halfZ);
|
||||
const cz = Math.cos(halfZ);
|
||||
const sx = Math.sin(halfX);
|
||||
const cx = Math.cos(halfX);
|
||||
const sy = Math.sin(halfY);
|
||||
const cy = Math.cos(halfY);
|
||||
|
||||
return new Quaternion(
|
||||
sx * sy * sz + cx * cy * cz,
|
||||
sx * cy * cz + cx * sy * sz,
|
||||
cx * sy * cz - sx * cy * sz,
|
||||
cx * cy * sz - sx * sy * cz
|
||||
)
|
||||
}
|
||||
|
||||
toEulerAngles() {
|
||||
const sinr_cosp = 2 * (this.w * this.x + this.y * this.z);
|
||||
const cosr_cosp = 1 - 2 * (this.x * this.x + this.y * this.y);
|
||||
const roll = Math.atan2(sinr_cosp, cosr_cosp);
|
||||
|
||||
const sinp = 2 * (this.w * this.y - this.z * this.x);
|
||||
let pitch;
|
||||
if (Math.abs(sinp) >= 1) {
|
||||
pitch = Math.sign(sinp) * Math.PI / 2; // use 90 degrees if out of range
|
||||
} else {
|
||||
pitch = -Math.asin(sinp);
|
||||
}
|
||||
|
||||
const siny_cosp = 2 * (this.w * this.z + this.x * this.y);
|
||||
const cosy_cosp = 1 - 2 * (this.y * this.y + this.z * this.z);
|
||||
const yaw = Math.atan2(siny_cosp, cosy_cosp);
|
||||
|
||||
return new Vector3(roll, pitch, yaw);
|
||||
}
|
||||
|
||||
rotateVector(v) {
|
||||
const vecQuat = new Quaternion(0, v.x, v.y, v.z);
|
||||
const resultQuat = this.multiply(vecQuat).multiply(this.conjugate());
|
||||
return new Vector3(resultQuat.x, resultQuat.y, resultQuat.z);
|
||||
const qv = new Quaternion(0, v.x, v.y, v.z);
|
||||
const conjugate = this.conjugate();
|
||||
const rotated = this.multiply(qv).multiply(conjugate);
|
||||
return new Vector3(rotated.x, rotated.y, rotated.z);
|
||||
}
|
||||
|
||||
conjugate() {
|
||||
@ -48,11 +71,33 @@ export default class Quaternion {
|
||||
}
|
||||
|
||||
multiply(q) {
|
||||
const w = this.w * q.w - this.x * q.x - this.y * q.y - this.z * q.z;
|
||||
const x = this.w * q.x + this.x * q.w + this.y * q.z - this.z * q.y;
|
||||
const y = this.w * q.y - this.x * q.z + this.y * q.w + this.z * q.x;
|
||||
const z = this.w * q.z + this.x * q.y - this.y * q.x + this.z * q.w;
|
||||
return new Quaternion(
|
||||
this.w * q.w - this.x * q.x - this.y * q.y - this.z * q.z,
|
||||
this.w * q.x + this.x * q.w + this.y * q.z - this.z * q.y,
|
||||
this.w * q.y - this.x * q.z + this.y * q.w + this.z * q.x,
|
||||
this.w * q.z + this.x * q.y - this.y * q.x + this.z * q.w
|
||||
);
|
||||
}
|
||||
|
||||
return new Quaternion(w, x, y, z);
|
||||
multiplyScalar(scalar) {
|
||||
return new Quaternion(
|
||||
this.w * scalar,
|
||||
this.x * scalar,
|
||||
this.y * scalar,
|
||||
this.z * scalar
|
||||
);
|
||||
}
|
||||
|
||||
getMiscYawData() {
|
||||
const forward = new Vector3(0, 0, -1);
|
||||
const rotatedForward = this.rotateVector(forward);
|
||||
|
||||
const up = new Vector3(0, 1, 0);
|
||||
const rotatedUp = this.rotateVector(up);
|
||||
|
||||
return {
|
||||
yaw: Math.atan2(rotatedForward.x, rotatedForward.z) * 180 / Math.PI,
|
||||
tilt: rotatedUp.x * rotatedUp.x + rotatedUp.z * rotatedUp.z
|
||||
}
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user