@kitschpatrol/tweakpane-plugin-rotation
Version:
A fork of tweakpane-plugin-rotation with build optimizations.
1,227 lines (1,198 loc) • 59.7 kB
JavaScript
import { SVG_NS, ClassName, createValue, PointerHandler, isArrowKey, getStepForKey, getHorizontalStepKeys, getVerticalStepKeys, bindValueMap, valueToClassName, Foldable, PointNdTextController, PopupController, connectValues, bindFoldable, forceCast, findNextTarget, supportsTouch, ValueMap, createNumberFormatter, isEmpty, StepConstraint, RangeConstraint, CompositeConstraint, createPlugin, PointNdConstraint, TpError, parseNumber, parseRecord, parsePointDimensionParams, parsePickerLayout } from '@tweakpane/core';
class Rotation {
multiply(b) {
return this.format(this.quat.multiply(b.quat));
}
premultiply(a) {
return this.format(a.multiply(this));
}
slerp(b, t) {
return this.format(this.quat.slerp(b.quat, t));
}
}
function clamp(x, l, h) {
return Math.min(Math.max(x, l), h);
}
function lofi(x, d) {
return Math.floor(x / d) * d;
}
function mod(x, d) {
return x - lofi(x, d);
}
function sanitizeAngle(angle) {
return mod(angle + Math.PI, Math.PI * 2.0) - Math.PI;
}
class Euler extends Rotation {
static fromQuaternion(quat, order, unit) {
const m = quat.toMat3();
const [i, j, k, sign] = order === 'XYZ' ? [0, 1, 2, 1] :
order === 'XZY' ? [0, 2, 1, -1] :
order === 'YXZ' ? [1, 0, 2, -1] :
order === 'YZX' ? [1, 2, 0, 1] :
order === 'ZXY' ? [2, 0, 1, 1] :
[2, 1, 0, -1];
const result = [0.0, 0.0, 0.0];
const c = m[k + i * 3];
result[j] = -sign * Math.asin(clamp(c, -1, 1.0));
if (Math.abs(c) < 0.999999) {
result[i] = sign * Math.atan2(m[k + j * 3], m[k * 4]);
result[k] = sign * Math.atan2(m[j + i * 3], m[i * 4]);
}
else {
// "y is 90deg" cases
result[i] = sign * Math.atan2(-m[j + k * 3], m[j * 4]);
}
if (Math.abs(result[i]) + Math.abs(result[k]) > Math.PI) {
// "two big revolutions" cases
result[i] = sanitizeAngle(result[i] + Math.PI);
result[j] = sanitizeAngle(Math.PI - result[j]);
result[k] = sanitizeAngle(result[k] + Math.PI);
}
return new Euler(...result, order).reunit(unit);
}
constructor(x, y, z, order, unit) {
super();
this.x = x !== null && x !== void 0 ? x : 0.0;
this.y = y !== null && y !== void 0 ? y : 0.0;
this.z = z !== null && z !== void 0 ? z : 0.0;
this.order = order !== null && order !== void 0 ? order : 'XYZ';
this.unit = unit !== null && unit !== void 0 ? unit : 'rad';
}
get quat() {
return Quaternion.fromEuler(this);
}
getComponents() {
return [this.x, this.y, this.z];
}
toEuler(order, unit) {
return this.reorder(order).reunit(unit);
}
format(r) {
if (r instanceof Euler) {
return r.reorder(this.order);
}
return r.toEuler(this.order, this.unit);
}
reorder(order) {
if (order === this.order) {
return this;
}
return this.quat.toEuler(order, this.unit);
}
reunit(unit) {
const prev2Rad = {
deg: Math.PI / 180.0,
rad: 1.0,
turn: 2.0 * Math.PI,
}[this.unit];
const rad2Next = {
deg: 180.0 / Math.PI,
rad: 1.0,
turn: 0.5 / Math.PI,
}[unit];
const prev2Next = prev2Rad * rad2Next;
return new Euler(prev2Next * this.x, prev2Next * this.y, prev2Next * this.z, this.order, unit);
}
}
class Quaternion extends Rotation {
static fromAxisAngle(axis, angle) {
const halfAngle = angle / 2.0;
const sinHalfAngle = Math.sin(halfAngle);
return new Quaternion(axis.x * sinHalfAngle, axis.y * sinHalfAngle, axis.z * sinHalfAngle, Math.cos(halfAngle));
}
static fromEuler(eulerr) {
const euler = eulerr.reunit('rad');
const [i, j, k, sign] = euler.order === 'XYZ' ? [0, 1, 2, 1] :
euler.order === 'XZY' ? [0, 2, 1, -1] :
euler.order === 'YXZ' ? [1, 0, 2, -1] :
euler.order === 'YZX' ? [1, 2, 0, 1] :
euler.order === 'ZXY' ? [2, 0, 1, 1] :
[2, 1, 0, -1];
const compo = euler.getComponents();
const ti = 0.5 * compo[i];
const tj = 0.5 * sign * compo[j];
const tk = 0.5 * compo[k];
const ci = Math.cos(ti);
const cj = Math.cos(tj);
const ck = Math.cos(tk);
const si = Math.sin(ti);
const sj = Math.sin(tj);
const sk = Math.sin(tk);
const result = [
0.0,
0.0,
0.0,
ck * cj * ci + sk * sj * si,
];
result[i] = ck * cj * si - sk * sj * ci;
result[j] = sign * (ck * sj * ci + sk * cj * si);
result[k] = sk * cj * ci - ck * sj * si;
return new Quaternion(...result);
}
static lookRotation(look, up) {
const { normal, tangent, binormal } = look.orthoNormalize(up);
const m11 = binormal.x;
const m12 = tangent.x;
const m13 = normal.x;
const m21 = binormal.y;
const m22 = tangent.y;
const m23 = normal.y;
const m31 = binormal.z;
const m32 = tangent.z;
const m33 = normal.z;
// Ref: https://github.com/mrdoob/three.js/blob/master/src/math/Quaternion.js
// Ref: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
const trace = m11 + m22 + m33;
if (trace > 0.0) {
const s = 0.5 / Math.sqrt(trace + 1.0);
return new Quaternion((m32 - m23) * s, (m13 - m31) * s, (m21 - m12) * s, 0.25 / s);
}
else if (m11 > m22 && m11 > m33) {
const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
return new Quaternion(0.25 * s, (m12 + m21) / s, (m13 + m31) / s, (m32 - m23) / s);
}
else if (m22 > m33) {
const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
return new Quaternion((m12 + m21) / s, 0.25 * s, (m23 + m32) / s, (m13 - m31) / s);
}
else {
const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
return new Quaternion((m13 + m31) / s, (m23 + m32) / s, 0.25 * s, (m21 - m12) / s);
}
}
constructor(x, y, z, w) {
super();
this.x = x !== null && x !== void 0 ? x : 0.0;
this.y = y !== null && y !== void 0 ? y : 0.0;
this.z = z !== null && z !== void 0 ? z : 0.0;
this.w = w !== null && w !== void 0 ? w : 1.0;
}
get quat() {
return this;
}
getComponents() {
return [this.x, this.y, this.z, this.w];
}
toEuler(order, unit) {
return Euler.fromQuaternion(this, order, unit);
}
get lengthSq() {
return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
}
get length() {
return Math.sqrt(this.lengthSq);
}
get normalized() {
const l = this.length;
if (l === 0.0) {
return new Quaternion();
}
return new Quaternion(this.x / l, this.y / l, this.z / l, this.w / l);
}
get negated() {
return new Quaternion(-this.x, -this.y, -this.z, -this.w);
}
get ban360s() {
return (this.w < 0.0) ? this.negated : this;
}
multiply(br) {
const b = br.quat;
return new Quaternion(this.w * b.x + this.x * b.w + this.y * b.z - this.z * b.y, this.w * b.y - this.x * b.z + this.y * b.w + this.z * b.x, this.w * b.z + this.x * b.y - this.y * b.x + this.z * b.w, this.w * b.w - this.x * b.x - this.y * b.y - this.z * b.z);
}
format(r) {
return r.quat;
}
slerp(br, t) {
let b = br.quat;
if (t === 0.0) {
return this;
}
if (t === 1.0) {
return b;
}
// Ref: https://github.com/mrdoob/three.js/blob/master/src/math/Quaternion.js
// Ref: http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
const a = this.ban360s;
b = b.ban360s;
let cosHalfTheta = a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;
if (cosHalfTheta < 0.0) {
b = b.negated;
cosHalfTheta = -cosHalfTheta;
}
// I think you two are same
if (cosHalfTheta >= 1.0) {
return a;
}
const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
// fallback to simple lerp
if (sqrSinHalfTheta <= Number.EPSILON) {
const s = 1.0 - t;
return new Quaternion(s * a.x + t * b.x, s * a.y + t * b.y, s * a.z + t * b.z, s * a.w + t * b.w).normalized;
}
// welcome
const sinHalfTheta = Math.sqrt(sqrSinHalfTheta);
const halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta);
const ratioA = Math.sin((1.0 - t) * halfTheta) / sinHalfTheta;
const ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
return new Quaternion(a.x * ratioA + b.x * ratioB, a.y * ratioA + b.y * ratioB, a.z * ratioA + b.z * ratioB, a.w * ratioA + b.w * ratioB);
}
toMat3() {
const { x, y, z, w } = this;
return [
1.0 - 2.0 * y * y - 2.0 * z * z, 2.0 * x * y + 2.0 * z * w, 2.0 * x * z - 2.0 * y * w,
2.0 * x * y - 2.0 * z * w, 1.0 - 2.0 * x * x - 2.0 * z * z, 2.0 * y * z + 2.0 * x * w,
2.0 * x * z + 2.0 * y * w, 2.0 * y * z - 2.0 * x * w, 1.0 - 2.0 * x * x - 2.0 * y * y,
];
}
}
class PointProjector {
constructor() {
this.offset = [0.0, 0.0, -5];
this.fov = 30.0;
this.aspect = 1.0;
this.viewport = [0, 0, 1, 1];
}
project(v) {
const vcx = (this.viewport[0] + this.viewport[2]) * 0.5;
const vcy = (this.viewport[1] + this.viewport[3]) * 0.5;
const vw = (this.viewport[2] - this.viewport[0]);
const vh = (this.viewport[3] - this.viewport[1]);
const p = 1.0 / Math.tan(this.fov * Math.PI / 360.0);
const sz = -(v.z + this.offset[2]);
const sx = vcx + (v.x + this.offset[0]) / sz * p * vw * 0.5 / this.aspect;
const sy = vcy - (v.y + this.offset[1]) / sz * p * vh * 0.5;
return [sx, sy];
}
}
class SVGLineStrip {
constructor(doc, vertices, projector) {
this.element = doc.createElementNS(SVG_NS, 'path');
this.vertices = vertices;
this.projector = projector;
}
/**
* Make sure rotation is normalized!
*/
setRotation(rotation) {
let pathStr = '';
this.vertices.forEach((vertex, iVertex) => {
const transformed = vertex.applyQuaternion(rotation);
const [sx, sy] = this.projector.project(transformed);
const cmd = iVertex === 0 ? 'M' : 'L';
pathStr += `${cmd}${sx} ${sy}`;
});
this.element.setAttributeNS(null, 'd', pathStr);
return this;
}
}
class Vector3 {
constructor(x, y, z) {
this.x = x !== null && x !== void 0 ? x : 0.0;
this.y = y !== null && y !== void 0 ? y : 0.0;
this.z = z !== null && z !== void 0 ? z : 0.0;
}
getComponents() {
return [this.x, this.y, this.z];
}
get lengthSq() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
get length() {
return Math.sqrt(this.lengthSq);
}
get normalized() {
const l = this.length;
if (l === 0.0) {
return new Vector3();
}
return new Vector3(this.x / l, this.y / l, this.z / l);
}
get negated() {
return new Vector3(-this.x, -this.y, -this.z);
}
add(v) {
return new Vector3(this.x + v.x, this.y + v.y, this.z + v.z);
}
sub(v) {
return new Vector3(this.x - v.x, this.y - v.y, this.z - v.z);
}
scale(s) {
return new Vector3(this.x * s, this.y * s, this.z * s);
}
dot(v) {
return this.x * v.x + this.y * v.y + this.z * v.z;
}
cross(v) {
return new Vector3(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x);
}
orthoNormalize(tangent) {
const normal = this.normalized;
tangent = tangent.normalized;
let dotNT = normal.dot(tangent);
if (dotNT === 1.0) {
if (Math.abs(normal.y) > Math.abs(normal.z)) {
tangent = new Vector3(0.0, 0.0, 1.0);
}
else {
tangent = new Vector3(0.0, 1.0, 0.0);
}
dotNT = normal.dot(tangent);
}
tangent = tangent.sub(normal.scale(dotNT)).normalized;
const binormal = tangent.cross(normal);
return {
normal,
tangent,
binormal,
};
}
applyQuaternion(q) {
const ix = q.w * this.x + q.y * this.z - q.z * this.y;
const iy = q.w * this.y + q.z * this.x - q.x * this.z;
const iz = q.w * this.z + q.x * this.y - q.y * this.x;
const iw = -q.x * this.x - q.y * this.y - q.z * this.z;
return new Vector3(ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y, iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z, iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x);
}
}
function createArcRotation(axis, front) {
const b = front.z > 0.0
? new Quaternion(0.0, 0.0, 0.0, 1.0)
: new Quaternion(0.0, 0.0, 1.0, 0.0);
if (Math.abs(axis.z) > 0.9999) {
return b;
}
return Quaternion.lookRotation(axis, front);
}
function createArcVerticesArray(thetaStart, thetaLength, segments, cosAxis, sinAxis, radius = 1.0) {
const vertices = [];
for (let i = 0; i < segments; i++) {
const t = thetaStart + thetaLength * i / (segments - 1);
const vector = new Vector3();
vector[cosAxis] = radius * Math.cos(t);
vector[sinAxis] = radius * Math.sin(t);
vertices.push(vector);
}
return vertices;
}
const className$2 = ClassName('rotationgizmo');
const VEC3_ZERO = new Vector3(0.0, 0.0, 0.0);
const VEC3_XP$2 = new Vector3(1.0, 0.0, 0.0);
const VEC3_YP$2 = new Vector3(0.0, 1.0, 0.0);
const VEC3_ZP$2 = new Vector3(0.0, 0.0, 1.0);
const VEC3_ZN = new Vector3(0.0, 0.0, -1);
const VEC3_XP70 = new Vector3(0.7, 0.0, 0.0);
const VEC3_YP70 = new Vector3(0.0, 0.7, 0.0);
const VEC3_ZP70 = new Vector3(0.0, 0.0, 0.7);
const VEC3_XN70 = new Vector3(-0.7, 0.0, 0.0);
const VEC3_YN70 = new Vector3(0.0, -0.7, 0.0);
const VEC3_ZN70 = new Vector3(0.0, 0.0, -0.7);
const QUAT_IDENTITY$2 = new Quaternion(0.0, 0.0, 0.0, 1.0);
function createLabel(doc, circleClass, labelText) {
const label = doc.createElementNS(SVG_NS, 'g');
const circle = doc.createElementNS(SVG_NS, 'circle');
circle.classList.add(className$2(circleClass));
circle.setAttributeNS(null, 'cx', '0');
circle.setAttributeNS(null, 'cy', '0');
circle.setAttributeNS(null, 'r', '8');
label.appendChild(circle);
const text = doc.createElementNS(SVG_NS, 'text');
text.classList.add(className$2('labeltext'));
text.setAttributeNS(null, 'y', '4');
text.setAttributeNS(null, 'text-anchor', 'middle');
text.setAttributeNS(null, 'font-size', '10');
text.textContent = labelText;
label.appendChild(text);
return label;
}
class RotationInputGizmoView {
get xArcBElement() { return this.xArcBC_.element; }
get yArcBElement() { return this.yArcBC_.element; }
get zArcBElement() { return this.zArcBC_.element; }
get xArcFElement() { return this.xArcFC_.element; }
get yArcFElement() { return this.yArcFC_.element; }
get zArcFElement() { return this.zArcFC_.element; }
get rArcElement() { return this.rArcC_.element; }
constructor(doc, config) {
this.onFoldableChange_ = this.onFoldableChange_.bind(this);
this.onValueChange_ = this.onValueChange_.bind(this);
this.onModeChange_ = this.onModeChange_.bind(this);
this.element = doc.createElement('div');
this.element.classList.add(className$2());
if (config.pickerLayout === 'popup') {
this.element.classList.add(className$2(undefined, 'p'));
}
const padElem = doc.createElement('div');
padElem.classList.add(className$2('p'));
config.viewProps.bindTabIndex(padElem);
this.element.appendChild(padElem);
this.padElement = padElem;
const svgElem = doc.createElementNS(SVG_NS, 'svg');
svgElem.classList.add(className$2('g'));
this.padElement.appendChild(svgElem);
this.svgElem_ = svgElem;
this.projector_ = new PointProjector();
this.projector_.viewport = [0, 0, 136, 136];
const arcArray = createArcVerticesArray(0.0, Math.PI, 33, 'x', 'y');
const arcArrayR = createArcVerticesArray(0.0, 2.0 * Math.PI, 65, 'x', 'y', 1.1);
// back arc
this.xArcB_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.xArcB_.element.classList.add(className$2('arcx'));
this.svgElem_.appendChild(this.xArcB_.element);
this.yArcB_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.yArcB_.element.classList.add(className$2('arcy'));
this.svgElem_.appendChild(this.yArcB_.element);
this.zArcB_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.zArcB_.element.classList.add(className$2('arcz'));
this.svgElem_.appendChild(this.zArcB_.element);
this.xArcBC_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.xArcBC_.element.classList.add(className$2('arcc'));
this.svgElem_.appendChild(this.xArcBC_.element);
this.yArcBC_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.yArcBC_.element.classList.add(className$2('arcc'));
this.svgElem_.appendChild(this.yArcBC_.element);
this.zArcBC_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.zArcBC_.element.classList.add(className$2('arcc'));
this.svgElem_.appendChild(this.zArcBC_.element);
// axes
const axesElem = doc.createElementNS(SVG_NS, 'g');
svgElem.classList.add(className$2('axes'));
this.svgElem_.appendChild(axesElem);
this.axesElem_ = axesElem;
this.xAxis_ = new SVGLineStrip(doc, [VEC3_ZERO, VEC3_XP70], this.projector_);
this.xAxis_.element.classList.add(className$2('axisx'));
this.axesElem_.appendChild(this.xAxis_.element);
this.yAxis_ = new SVGLineStrip(doc, [VEC3_ZERO, VEC3_YP70], this.projector_);
this.yAxis_.element.classList.add(className$2('axisy'));
this.axesElem_.appendChild(this.yAxis_.element);
this.zAxis_ = new SVGLineStrip(doc, [VEC3_ZERO, VEC3_ZP70], this.projector_);
this.zAxis_.element.classList.add(className$2('axisz'));
this.axesElem_.appendChild(this.zAxis_.element);
this.xnAxis_ = new SVGLineStrip(doc, [VEC3_ZERO, VEC3_XN70], this.projector_);
this.xnAxis_.element.classList.add(className$2('axisn'));
this.axesElem_.appendChild(this.xnAxis_.element);
this.ynAxis_ = new SVGLineStrip(doc, [VEC3_ZERO, VEC3_YN70], this.projector_);
this.ynAxis_.element.classList.add(className$2('axisn'));
this.axesElem_.appendChild(this.ynAxis_.element);
this.znAxis_ = new SVGLineStrip(doc, [VEC3_ZERO, VEC3_ZN70], this.projector_);
this.znAxis_.element.classList.add(className$2('axisn'));
this.axesElem_.appendChild(this.znAxis_.element);
// front arc
this.xArcF_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.xArcF_.element.classList.add(className$2('arcx'));
this.svgElem_.appendChild(this.xArcF_.element);
this.yArcF_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.yArcF_.element.classList.add(className$2('arcy'));
this.svgElem_.appendChild(this.yArcF_.element);
this.zArcF_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.zArcF_.element.classList.add(className$2('arcz'));
this.svgElem_.appendChild(this.zArcF_.element);
this.xArcFC_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.xArcFC_.element.classList.add(className$2('arcc'));
this.svgElem_.appendChild(this.xArcFC_.element);
this.yArcFC_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.yArcFC_.element.classList.add(className$2('arcc'));
this.svgElem_.appendChild(this.yArcFC_.element);
this.zArcFC_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.zArcFC_.element.classList.add(className$2('arcc'));
this.svgElem_.appendChild(this.zArcFC_.element);
// roll arc
this.rArc_ = new SVGLineStrip(doc, arcArrayR, this.projector_);
this.rArc_.element.classList.add(className$2('arcr'));
this.rArc_.setRotation(QUAT_IDENTITY$2);
this.svgElem_.appendChild(this.rArc_.element);
this.rArcC_ = new SVGLineStrip(doc, arcArrayR, this.projector_);
this.rArcC_.element.classList.add(className$2('arcc'));
this.rArcC_.setRotation(QUAT_IDENTITY$2);
this.svgElem_.appendChild(this.rArcC_.element);
// labels
const labelsElem = doc.createElementNS(SVG_NS, 'g');
svgElem.classList.add(className$2('labels'));
this.svgElem_.appendChild(labelsElem);
this.labelsElem_ = labelsElem;
this.xLabel = createLabel(doc, 'labelcirclex', 'X');
this.labelsElem_.appendChild(this.xLabel);
this.yLabel = createLabel(doc, 'labelcircley', 'Y');
this.labelsElem_.appendChild(this.yLabel);
this.zLabel = createLabel(doc, 'labelcirclez', 'Z');
this.labelsElem_.appendChild(this.zLabel);
this.xnLabel = createLabel(doc, 'labelcirclen', '-X');
this.labelsElem_.appendChild(this.xnLabel);
this.ynLabel = createLabel(doc, 'labelcirclen', '-Y');
this.labelsElem_.appendChild(this.ynLabel);
this.znLabel = createLabel(doc, 'labelcirclen', '-Z');
this.labelsElem_.appendChild(this.znLabel);
// arc hover
const onHoverXArc = () => {
this.xArcB_.element.classList.add(className$2('arcx_hover'));
this.xArcF_.element.classList.add(className$2('arcx_hover'));
};
const onLeaveXArc = () => {
this.xArcB_.element.classList.remove(className$2('arcx_hover'));
this.xArcF_.element.classList.remove(className$2('arcx_hover'));
};
this.xArcBC_.element.addEventListener('mouseenter', onHoverXArc);
this.xArcBC_.element.addEventListener('mouseleave', onLeaveXArc);
this.xArcFC_.element.addEventListener('mouseenter', onHoverXArc);
this.xArcFC_.element.addEventListener('mouseleave', onLeaveXArc);
const onHoverYArc = () => {
this.yArcB_.element.classList.add(className$2('arcy_hover'));
this.yArcF_.element.classList.add(className$2('arcy_hover'));
};
const onLeaveYArc = () => {
this.yArcB_.element.classList.remove(className$2('arcy_hover'));
this.yArcF_.element.classList.remove(className$2('arcy_hover'));
};
this.yArcBC_.element.addEventListener('mouseenter', onHoverYArc);
this.yArcBC_.element.addEventListener('mouseleave', onLeaveYArc);
this.yArcFC_.element.addEventListener('mouseenter', onHoverYArc);
this.yArcFC_.element.addEventListener('mouseleave', onLeaveYArc);
const onHoverZArc = () => {
this.zArcB_.element.classList.add(className$2('arcz_hover'));
this.zArcF_.element.classList.add(className$2('arcz_hover'));
};
const onLeaveZArc = () => {
this.zArcB_.element.classList.remove(className$2('arcz_hover'));
this.zArcF_.element.classList.remove(className$2('arcz_hover'));
};
this.zArcBC_.element.addEventListener('mouseenter', onHoverZArc);
this.zArcBC_.element.addEventListener('mouseleave', onLeaveZArc);
this.zArcFC_.element.addEventListener('mouseenter', onHoverZArc);
this.zArcFC_.element.addEventListener('mouseleave', onLeaveZArc);
const onHoverRArc = () => {
this.rArc_.element.classList.add(className$2('arcr_hover'));
};
const onLeaveRArc = () => {
this.rArc_.element.classList.remove(className$2('arcr_hover'));
};
this.rArcC_.element.addEventListener('mouseenter', onHoverRArc);
this.rArcC_.element.addEventListener('mouseleave', onLeaveRArc);
config.value.emitter.on('change', this.onValueChange_);
this.value = config.value;
config.mode.emitter.on('change', this.onModeChange_);
this.mode_ = config.mode;
this.update_();
}
get allFocusableElements() {
return [this.padElement];
}
update_() {
const q = this.value.rawValue.quat.normalized;
// rotate axes
this.xAxis_.setRotation(q);
this.yAxis_.setRotation(q);
this.zAxis_.setRotation(q);
this.xnAxis_.setRotation(q);
this.ynAxis_.setRotation(q);
this.znAxis_.setRotation(q);
// """z-sort""" axes
const xp = VEC3_XP$2.applyQuaternion(q);
const yp = VEC3_YP$2.applyQuaternion(q);
const zp = VEC3_ZP$2.applyQuaternion(q);
const xn = xp.negated;
const yn = yp.negated;
const zn = zp.negated;
[
{ el: this.xAxis_.element, v: xp },
{ el: this.yAxis_.element, v: yp },
{ el: this.zAxis_.element, v: zp },
{ el: this.xnAxis_.element, v: xn },
{ el: this.ynAxis_.element, v: yn },
{ el: this.znAxis_.element, v: zn },
]
.map(({ el, v }) => {
this.axesElem_.removeChild(el);
return { el, v };
})
.sort((a, b) => a.v.z - b.v.z)
.forEach(({ el }) => {
this.axesElem_.appendChild(el);
});
// rotate arcs
this.xArcB_.setRotation(createArcRotation(xp, VEC3_ZN));
this.yArcB_.setRotation(createArcRotation(yp, VEC3_ZN));
this.zArcB_.setRotation(createArcRotation(zp, VEC3_ZN));
this.xArcBC_.setRotation(createArcRotation(xp, VEC3_ZN));
this.yArcBC_.setRotation(createArcRotation(yp, VEC3_ZN));
this.zArcBC_.setRotation(createArcRotation(zp, VEC3_ZN));
this.xArcF_.setRotation(createArcRotation(xp, VEC3_ZP$2));
this.yArcF_.setRotation(createArcRotation(yp, VEC3_ZP$2));
this.zArcF_.setRotation(createArcRotation(zp, VEC3_ZP$2));
this.xArcFC_.setRotation(createArcRotation(xp, VEC3_ZP$2));
this.yArcFC_.setRotation(createArcRotation(yp, VEC3_ZP$2));
this.zArcFC_.setRotation(createArcRotation(zp, VEC3_ZP$2));
// rotate labels
[
{ el: this.xLabel, v: VEC3_XP70 },
{ el: this.yLabel, v: VEC3_YP70 },
{ el: this.zLabel, v: VEC3_ZP70 },
{ el: this.xnLabel, v: VEC3_XN70 },
{ el: this.ynLabel, v: VEC3_YN70 },
{ el: this.znLabel, v: VEC3_ZN70 },
].forEach(({ el, v }) => {
const [x, y] = this.projector_.project(v.applyQuaternion(q));
el.setAttributeNS(null, 'transform', `translate( ${x}, ${y} )`);
});
// """z-sort""" labels
[
{ el: this.xLabel, v: xp },
{ el: this.yLabel, v: yp },
{ el: this.zLabel, v: zp },
{ el: this.xnLabel, v: xn },
{ el: this.ynLabel, v: yn },
{ el: this.znLabel, v: zn },
].map(({ el, v }) => {
this.labelsElem_.removeChild(el);
return { el, v };
})
.sort((a, b) => a.v.z - b.v.z)
.forEach(({ el }) => {
this.labelsElem_.appendChild(el);
});
}
onValueChange_() {
this.update_();
}
onFoldableChange_() {
this.update_();
}
onModeChange_() {
const mode = this.mode_.rawValue;
const x = mode === 'angle-x' ? 'add' : 'remove';
const y = mode === 'angle-y' ? 'add' : 'remove';
const z = mode === 'angle-z' ? 'add' : 'remove';
const r = mode === 'angle-r' ? 'add' : 'remove';
this.xArcB_.element.classList[x](className$2('arcx_active'));
this.yArcB_.element.classList[y](className$2('arcy_active'));
this.zArcB_.element.classList[z](className$2('arcz_active'));
this.xArcF_.element.classList[x](className$2('arcx_active'));
this.yArcF_.element.classList[y](className$2('arcy_active'));
this.zArcF_.element.classList[z](className$2('arcz_active'));
this.rArc_.element.classList[r](className$2('arcr_active'));
}
}
function saturate(x) {
return clamp(x, 0.0, 1.0);
}
/**
* hand-picked random polynomial that looks cool
* clamped in [0.0 - 1.0]
*/
function iikanjiEaseout(x) {
if (x <= 0.0) {
return 0.0;
}
if (x >= 1.0) {
return 1.0;
}
const xt = 1.0 - x;
const y = xt * (xt * (xt * (xt * (xt * (xt * (xt * (-6) + 7))))));
return saturate(1.0 - y);
}
function linearstep(a, b, x) {
return saturate((x - a) / (b - a));
}
const INV_SQRT2 = 1.0 / Math.sqrt(2.0);
const VEC3_XP$1 = new Vector3(1.0, 0.0, 0.0);
const VEC3_YP$1 = new Vector3(0.0, 1.0, 0.0);
const VEC3_ZP$1 = new Vector3(0.0, 0.0, 1.0);
const QUAT_IDENTITY$1 = new Quaternion(0.0, 0.0, 0.0, 1.0);
const QUAT_TOP = new Quaternion(INV_SQRT2, 0.0, 0.0, INV_SQRT2);
const QUAT_RIGHT = new Quaternion(0.0, -INV_SQRT2, 0.0, INV_SQRT2);
const QUAT_BOTTOM = new Quaternion(-INV_SQRT2, 0.0, 0.0, INV_SQRT2);
const QUAT_LEFT = new Quaternion(0.0, INV_SQRT2, 0.0, INV_SQRT2);
const QUAT_BACK = new Quaternion(0.0, 1.0, 0.0, 0.0);
class RotationInputGizmoController {
constructor(doc, config) {
this.onPadKeyDown_ = this.onPadKeyDown_.bind(this);
this.onPointerDown_ = this.onPointerDown_.bind(this);
this.onPointerMove_ = this.onPointerMove_.bind(this);
this.onPointerUp_ = this.onPointerUp_.bind(this);
this.value = config.value;
this.viewProps = config.viewProps;
this.mode_ = createValue('free');
this.view = new RotationInputGizmoView(doc, {
value: this.value,
mode: this.mode_,
viewProps: this.viewProps,
pickerLayout: config.pickerLayout,
});
this.ptHandler_ = new PointerHandler(this.view.padElement);
this.ptHandler_.emitter.on('down', this.onPointerDown_);
this.ptHandler_.emitter.on('move', this.onPointerMove_);
this.ptHandler_.emitter.on('up', this.onPointerUp_);
this.view.padElement.addEventListener('keydown', this.onPadKeyDown_);
const ptHandlerXArcB = new PointerHandler(this.view.xArcBElement);
ptHandlerXArcB.emitter.on('down', () => this.changeModeIfNotAuto_('angle-x'));
ptHandlerXArcB.emitter.on('up', () => this.changeModeIfNotAuto_('free'));
const ptHandlerXArcF = new PointerHandler(this.view.xArcFElement);
ptHandlerXArcF.emitter.on('down', () => this.changeModeIfNotAuto_('angle-x'));
ptHandlerXArcF.emitter.on('up', () => this.changeModeIfNotAuto_('free'));
const ptHandlerYArcB = new PointerHandler(this.view.yArcBElement);
ptHandlerYArcB.emitter.on('down', () => this.changeModeIfNotAuto_('angle-y'));
ptHandlerYArcB.emitter.on('up', () => this.changeModeIfNotAuto_('free'));
const ptHandlerYArcF = new PointerHandler(this.view.yArcFElement);
ptHandlerYArcF.emitter.on('down', () => this.changeModeIfNotAuto_('angle-y'));
ptHandlerYArcF.emitter.on('up', () => this.changeModeIfNotAuto_('free'));
const ptHandlerZArcB = new PointerHandler(this.view.zArcBElement);
ptHandlerZArcB.emitter.on('down', () => this.changeModeIfNotAuto_('angle-z'));
ptHandlerZArcB.emitter.on('up', () => this.changeModeIfNotAuto_('free'));
const ptHandlerZArcF = new PointerHandler(this.view.zArcFElement);
ptHandlerZArcF.emitter.on('down', () => this.changeModeIfNotAuto_('angle-z'));
ptHandlerZArcF.emitter.on('up', () => this.changeModeIfNotAuto_('free'));
const ptHandlerRArc = new PointerHandler(this.view.rArcElement);
ptHandlerRArc.emitter.on('down', () => this.changeModeIfNotAuto_('angle-r'));
ptHandlerRArc.emitter.on('up', () => this.changeModeIfNotAuto_('free'));
[
{ el: this.view.xLabel, q: QUAT_RIGHT },
{ el: this.view.yLabel, q: QUAT_TOP },
{ el: this.view.zLabel, q: QUAT_IDENTITY$1 },
{ el: this.view.xnLabel, q: QUAT_LEFT },
{ el: this.view.ynLabel, q: QUAT_BOTTOM },
{ el: this.view.znLabel, q: QUAT_BACK },
].forEach(({ el, q }) => {
const ptHandler = new PointerHandler(el);
ptHandler.emitter.on('down', () => this.autoRotate_(q));
});
this.px_ = null;
this.py_ = null;
this.angleState_ = null;
}
handlePointerEvent_(d) {
if (!d.point) {
return;
}
const mode = this.mode_.rawValue;
const x = d.point.x;
const y = d.point.y;
if (mode === 'auto') ;
else if (mode === 'free') {
if (this.px_ != null && this.py_ != null) {
const dx = x - this.px_;
const dy = y - this.py_;
const l = Math.sqrt(dx * dx + dy * dy);
if (l === 0.0) {
return;
}
const axis = new Vector3(dy / l, dx / l, 0.0);
const quat = Quaternion.fromAxisAngle(axis, l / 68.0);
this.value.rawValue = this.value.rawValue.premultiply(quat);
}
this.px_ = x;
this.py_ = y;
}
else if (mode === 'angle-r') {
const cx = d.bounds.width / 2.0;
const cy = d.bounds.height / 2.0;
const angle = Math.atan2(y - cy, x - cx);
if (this.angleState_ == null) {
const axis = new Vector3(0.0, 0.0, 1.0);
this.angleState_ = {
initialRotation: this.value.rawValue,
initialAngle: angle,
axis,
reverseAngle: true,
};
}
else {
const { initialRotation, initialAngle, axis } = this.angleState_;
const angleDiff = -sanitizeAngle(angle - initialAngle);
const quat = Quaternion.fromAxisAngle(axis, angleDiff);
this.value.rawValue = initialRotation.premultiply(quat);
}
}
else {
const cx = d.bounds.width / 2.0;
const cy = d.bounds.height / 2.0;
const angle = Math.atan2(y - cy, x - cx);
if (this.angleState_ == null) {
const axis = mode === 'angle-x' ? VEC3_XP$1 :
mode === 'angle-y' ? VEC3_YP$1 :
VEC3_ZP$1;
const reverseAngle = axis.applyQuaternion(this.value.rawValue.quat).z > 0.0;
this.angleState_ = {
initialRotation: this.value.rawValue,
initialAngle: angle,
axis,
reverseAngle,
};
}
else {
const { initialRotation, initialAngle, axis, reverseAngle } = this.angleState_;
let angleDiff = sanitizeAngle(angle - initialAngle);
angleDiff = reverseAngle ? -angleDiff : angleDiff;
const quat = Quaternion.fromAxisAngle(axis, angleDiff);
this.value.rawValue = initialRotation.multiply(quat);
}
}
}
onPointerDown_(ev) {
this.handlePointerEvent_(ev.data);
}
onPointerMove_(ev) {
this.handlePointerEvent_(ev.data);
}
onPointerUp_() {
this.px_ = null;
this.py_ = null;
this.angleState_ = null;
}
onPadKeyDown_(ev) {
if (isArrowKey(ev.key)) {
ev.preventDefault();
}
const x = getStepForKey(1.0, getHorizontalStepKeys(ev));
const y = getStepForKey(1.0, getVerticalStepKeys(ev));
if (x !== 0 || y !== 0) {
const axis = new Vector3(-y, x, 0.0);
const quat = Quaternion.fromAxisAngle(axis, Math.PI / 16.0);
this.value.rawValue = this.value.rawValue.premultiply(quat);
}
}
changeModeIfNotAuto_(mode) {
if (this.mode_.rawValue !== 'auto') {
this.mode_.rawValue = mode;
}
}
autoRotate_(to) {
this.mode_.rawValue = 'auto';
const from = this.value.rawValue;
const beginTime = Date.now();
const update = () => {
const now = Date.now();
const t = iikanjiEaseout(linearstep(0.0, 300.0, now - beginTime));
this.value.rawValue = from.slerp(to, t);
if (t === 1.0) {
this.mode_.rawValue = 'free';
return;
}
requestAnimationFrame(update);
};
requestAnimationFrame(update);
}
}
const className$1 = ClassName('rotationswatch');
const VEC3_XP = new Vector3(1.0, 0.0, 0.0);
const VEC3_YP = new Vector3(0.0, 1.0, 0.0);
const VEC3_ZP = new Vector3(0.0, 0.0, 1.0);
const QUAT_IDENTITY = new Quaternion(0.0, 0.0, 0.0, 1.0);
class RotationInputSwatchView {
constructor(doc, config) {
this.onValueChange_ = this.onValueChange_.bind(this);
config.value.emitter.on('change', this.onValueChange_);
this.value = config.value;
this.element = doc.createElement('div');
this.element.classList.add(className$1());
config.viewProps.bindClassModifiers(this.element);
const buttonElem = doc.createElement('button');
buttonElem.classList.add(className$1('b'));
config.viewProps.bindDisabled(buttonElem);
this.element.appendChild(buttonElem);
this.buttonElement = buttonElem;
const svgElem = doc.createElementNS(SVG_NS, 'svg');
svgElem.classList.add(className$1('g'));
buttonElem.appendChild(svgElem);
this.svgElem_ = svgElem;
this.projector_ = new PointProjector();
this.projector_.viewport = [0, 0, 20, 20];
const arcArray = createArcVerticesArray(0.0, Math.PI, 33, 'x', 'y');
const arcArrayR = createArcVerticesArray(0.0, 2.0 * Math.PI, 65, 'x', 'y');
// arc
this.rArc_ = new SVGLineStrip(doc, arcArrayR, this.projector_);
this.rArc_.element.classList.add(className$1('arcr'));
svgElem.appendChild(this.rArc_.element);
this.rArc_.setRotation(QUAT_IDENTITY);
this.xArc_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.xArc_.element.classList.add(className$1('arc'));
svgElem.appendChild(this.xArc_.element);
this.yArc_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.yArc_.element.classList.add(className$1('arc'));
svgElem.appendChild(this.yArc_.element);
this.zArc_ = new SVGLineStrip(doc, arcArray, this.projector_);
this.zArc_.element.classList.add(className$1('arc'));
svgElem.appendChild(this.zArc_.element);
this.update_();
}
update_() {
const q = this.value.rawValue.quat.normalized;
// rotate axes
const xp = VEC3_XP.applyQuaternion(q);
const yp = VEC3_YP.applyQuaternion(q);
const zp = VEC3_ZP.applyQuaternion(q);
this.xArc_.setRotation(createArcRotation(xp, VEC3_ZP));
this.yArc_.setRotation(createArcRotation(yp, VEC3_ZP));
this.zArc_.setRotation(createArcRotation(zp, VEC3_ZP));
}
onValueChange_() {
this.update_();
}
}
class RotationInputSwatchController {
constructor(doc, config) {
this.value = config.value;
this.viewProps = config.viewProps;
this.view = new RotationInputSwatchView(doc, {
value: this.value,
viewProps: this.viewProps,
});
}
}
const className = ClassName('rotation');
class RotationInputView {
constructor(doc, config) {
this.element = doc.createElement('div');
this.element.classList.add(className());
config.foldable.bindExpandedClass(this.element, className(undefined, 'expanded'));
bindValueMap(config.foldable, 'completed', valueToClassName(this.element, className(undefined, 'cpl')));
if (config.rotationMode === 'quaternion') {
this.element.classList.add(className('quat'));
}
const headElem = doc.createElement('div');
headElem.classList.add(className('h'));
this.element.appendChild(headElem);
const swatchElem = doc.createElement('div');
swatchElem.classList.add(className('s'));
headElem.appendChild(swatchElem);
this.swatchElement = swatchElem;
const textElem = doc.createElement('div');
textElem.classList.add(className('t'));
headElem.appendChild(textElem);
this.textElement = textElem;
if (config.pickerLayout === 'inline') {
const pickerElem = doc.createElement('div');
pickerElem.classList.add(className('g'));
this.element.appendChild(pickerElem);
this.pickerElement = pickerElem;
}
else {
this.pickerElement = null;
}
}
}
class RotationInputController {
constructor(doc, config) {
this.onButtonBlur_ = this.onButtonBlur_.bind(this);
this.onButtonClick_ = this.onButtonClick_.bind(this);
this.onPopupChildBlur_ = this.onPopupChildBlur_.bind(this);
this.onPopupChildKeydown_ = this.onPopupChildKeydown_.bind(this);
this.value = config.value;
this.viewProps = config.viewProps;
this.foldable_ = Foldable.create(config.expanded);
this.swatchC_ = new RotationInputSwatchController(doc, {
value: this.value,
viewProps: this.viewProps,
});
const buttonElem = this.swatchC_.view.buttonElement;
buttonElem.addEventListener('blur', this.onButtonBlur_);
buttonElem.addEventListener('click', this.onButtonClick_);
this.textC_ = new PointNdTextController(doc, {
assembly: config.assembly, // TODO: resolve type puzzle
axes: config.axes,
parser: config.parser,
value: this.value,
viewProps: this.viewProps,
});
this.view = new RotationInputView(doc, {
rotationMode: config.rotationMode,
foldable: this.foldable_,
pickerLayout: config.pickerLayout,
});
this.view.swatchElement.appendChild(this.swatchC_.view.element);
this.view.textElement.appendChild(this.textC_.view.element);
this.popC_ =
config.pickerLayout === 'popup'
? new PopupController(doc, {
viewProps: this.viewProps,
})
: null;
const gizmoC = new RotationInputGizmoController(doc, {
value: this.value,
viewProps: this.viewProps,
pickerLayout: config.pickerLayout,
});
gizmoC.view.allFocusableElements.forEach((elem) => {
elem.addEventListener('blur', this.onPopupChildBlur_);
elem.addEventListener('keydown', this.onPopupChildKeydown_);
});
this.gizmoC_ = gizmoC;
if (this.popC_) {
this.view.element.appendChild(this.popC_.view.element);
this.popC_.view.element.appendChild(gizmoC.view.element);
connectValues({
primary: this.foldable_.value('expanded'),
secondary: this.popC_.shows,
forward: (p) => p,
backward: (_, s) => s,
});
}
else if (this.view.pickerElement) {
this.view.pickerElement.appendChild(this.gizmoC_.view.element);
bindFoldable(this.foldable_, this.view.pickerElement);
}
}
onButtonBlur_(e) {
if (!this.popC_) {
return;
}
const elem = this.view.element;
const nextTarget = forceCast(e.relatedTarget);
if (!nextTarget || !elem.contains(nextTarget)) {
this.popC_.shows.rawValue = false;
}
}
onButtonClick_() {
this.foldable_.set('expanded', !this.foldable_.get('expanded'));
if (this.foldable_.get('expanded')) {
this.gizmoC_.view.allFocusableElements[0].focus();
}
}
onPopupChildBlur_(ev) {
if (!this.popC_) {
return;
}
const elem = this.popC_.view.element;
const nextTarget = findNextTarget(ev);
if (nextTarget && elem.contains(nextTarget)) {
// Next target is in the picker
return;
}
if (nextTarget &&
nextTarget === this.swatchC_.view.buttonElement &&
!supportsTouch(elem.ownerDocument)) {
// Next target is the trigger button
return;
}
this.popC_.shows.rawValue = false;
}
onPopupChildKeydown_(ev) {
if (this.popC_) {
if (ev.key === 'Escape') {
this.popC_.shows.rawValue = false;
}
}
else if (this.view.pickerElement) {
if (ev.key === 'Escape') {
this.swatchC_.view.buttonElement.focus();
}
}
}
}
function createAxisEuler(digits, constraint) {
const step = Math.pow(0.1, digits);
return {
baseStep: step,
constraint: constraint,
textProps: ValueMap.fromObject({
formatter: createNumberFormatter(digits),
keyScale: step,
pointerScale: step,
}),
};
}
function createDimensionConstraint(params) {
if (!params) {
return undefined;
}
const constraints = [];
if (!isEmpty(params.step)) {
constraints.push(new StepConstraint(params.step));
}
if (!isEmpty(params.max) || !isEmpty(params.min)) {
constraints.push(new RangeConstraint({
max: params.max,
min: params.min,
}));
}
return new CompositeConstraint(constraints);
}
function createEulerAssembly(order, unit) {
return {
toComponents: (r) => r.getComponents(),
fromComponents: (c) => new Euler(c[0], c[1], c[2], order, unit),
};
}
function parseEuler(exValue, order, unit) {
if (typeof (exValue === null || exValue === void 0 ? void 0 : exValue.x) === 'number' &&
typeof (exValue === null || exValue === void 0 ? void 0 : exValue.y) === 'number' &&
typeof (exValue === null || exValue === void 0 ? void 0 : exValue.z) === 'number') {
return new Euler(exValue.x, exValue.y, exValue.z, order, unit);
}
else {
return new Euler(0.0, 0.0, 0.0, order, unit);
}
}
function parseEulerOrder(value) {
switch (value) {
case 'XYZ':
case 'XZY':
case 'YXZ':
case 'YZX':
case 'ZXY':
case 'ZYX':
return value;
default:
return undefined;
}
}
function parseEulerUnit(value) {
switch (value) {
case 'rad':
case 'deg':
case 'turn':
return value;
default:
return undefined;
}
}
const RotationInputPluginEuler = createPlugin({
id: 'rotation',
type: 'input',
accept(exValue, params) {
var _a, _b;
// Parse parameters object
const result = parseRecord(params, (p) => ({
view: p.required.constant('rotation'),
label: p.optional.string,
picker: p.optional.custom(parsePickerLayout),
expanded: p.optional.boolean,
rotationMode: p.required.constant('euler'),
x: p.optional.custom(parsePointDimensionParams),
y: p.optional.custom(parsePointDimensionParams),
z: p.optional.custom(parsePointDimensionParams),
order: p.optional.custom(parseEulerOrder),
unit: p.optional.custom(parseEulerUnit),
}));
return result ? {
initialValue: parseEuler(exValue, (_a = result.order) !== null && _a !== void 0 ? _a : 'XYZ', (_b = result.unit) !== null && _b !== void 0 ? _b : 'rad'),
params: result,
} : null;
},
binding: {
reader({ params }) {
return (exValue) => {
var _a, _b;
return parseEuler(exValue, (_a = params.order) !== null && _a !== void 0 ? _a : 'XYZ', (_b = params.unit) !== null && _b !== void 0 ? _b : 'rad');
};
},
constraint({ params }) {
var _a, _b;
return new PointNdConstraint({
assembly: createEulerAssembly((_a = params.order) !== null && _a !== void 0 ? _a : 'XYZ', (_b = params.unit) !== null && _b !== void 0 ? _b : 'rad'),
components: [
createDimensionConstraint('x' in params ? params.x : undefined),
createDimensionConstraint('y' in params ? params.y : undefined),
createDimensionConstraint('z' in params ? params.z : undefined),
]
});
},
writer(_args) {
return (target, inValue) => {
target.writeProperty('x', inValue.x);
target.writeProperty('y', inValue.y);
target.writeProperty('z', inValue.z);
};
},
},
controller({ document, value, constraint, params, viewProps }) {
var _a, _b;
if (!(constraint instanceof PointNdConstraint)) {
throw TpError.shouldNeverHappen();