Skip to content

Commit

Permalink
Merge pull request #195 from cocopon/point-4d
Browse files Browse the repository at this point in the history
Add support for Point4D, #186
  • Loading branch information
cocopon authored Mar 13, 2021
2 parents 0e53fc7 + 4f21cc4 commit 308a3aa
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 8 deletions.
8 changes: 8 additions & 0 deletions lib/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ export interface Point3dInputParams extends BaseInputParams {
z?: PointDimensionParams;
}

export interface Point4dInputParams extends BaseInputParams {
x?: PointDimensionParams;
y?: PointDimensionParams;
z?: PointDimensionParams;
w?: PointDimensionParams;
}

export type StringInputType = 'string';

export interface StringInputParams extends BaseInputParams {
Expand All @@ -67,6 +74,7 @@ export type InputParams =
| NumberInputParams
| Point2dInputParams
| Point3dInputParams
| Point4dInputParams
| StringInputParams;

export interface BaseMonitorParams extends BaseParams, LabelableParams {
Expand Down
2 changes: 2 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {StringColorInputPlugin} from './plugin/input-bindings/color/plugin-strin
import {NumberInputPlugin} from './plugin/input-bindings/number/plugin';
import {Point2dInputPlugin} from './plugin/input-bindings/point-2d/plugin';
import {Point3dInputPlugin} from './plugin/input-bindings/point-3d/plugin';
import {Point4dInputPlugin} from './plugin/input-bindings/point-4d/plugin';
import {StringInputPlugin} from './plugin/input-bindings/string/plugin';
import {MonitorBindingPlugin} from './plugin/monitor-binding';
import {BooleanMonitorPlugin} from './plugin/monitor-bindings/boolean/plugin';
Expand Down Expand Up @@ -107,6 +108,7 @@ function registerDefaultPlugins() {
[
Point2dInputPlugin,
Point3dInputPlugin,
Point4dInputPlugin,
StringInputPlugin,
NumberInputPlugin,
StringColorInputPlugin,
Expand Down
1 change: 1 addition & 0 deletions lib/misc/type-util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type Class<T> = new (...args: any[]) => T;
export type Tuple4<T> = [T, T, T, T];

export function forceCast<T>(v: any): T {
return v;
Expand Down
83 changes: 83 additions & 0 deletions lib/pane/input-point-4d-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {assert} from 'chai';
import {describe as context, describe, it} from 'mocha';

import Tweakpane from '../index';
import {TestUtil} from '../misc/test-util';
import {findConstraint} from '../plugin/common/constraint/composite';
import {RangeConstraint} from '../plugin/common/constraint/range';
import {StepConstraint} from '../plugin/common/constraint/step';
import {PointNdConstraint} from '../plugin/input-bindings/common/constraint/point-nd';
import {PointNdTextController} from '../plugin/input-bindings/common/controller/point-nd-text';

function createPane(): Tweakpane {
return new Tweakpane({
document: TestUtil.createWindow().document,
});
}

describe(Tweakpane.name, () => {
[
{
params: {},
value: {x: 12, y: 34, z: 56, w: 78},
},
].forEach((testCase) => {
context(`when params = ${JSON.stringify(testCase.params)}`, () => {
it('should return controller for Point4d', () => {
const pane = createPane();
const obj = {foo: testCase.value};
const bapi = pane.addInput(obj, 'foo', testCase.params);

const ic = bapi.controller.controller;
if (!(ic instanceof PointNdTextController)) {
throw new Error('unexpected controller class');
}
assert.strictEqual(ic.view.textViews.length, 4);
});
});
});

it('should create appropriate step constraint', () => {
const pane = createPane();
const obj = {foo: {x: 12, y: 34, z: 56, w: 78}};
const bapi = pane.addInput(obj, 'foo', {
w: {
step: 1,
},
});

const c = bapi.controller.binding.value.constraint;
if (!(c instanceof PointNdConstraint)) {
throw new Error('Unexpected constraint');
}
const wc = c.components[3];
if (!wc) {
throw new Error('Unexpected constraint');
}
const sc = findConstraint(wc, StepConstraint);
assert.strictEqual(sc && sc.step, 1);
});

it('should create appropriate range constraint', () => {
const pane = createPane();
const obj = {foo: {x: 12, y: 34, z: 56, w: 78}};
const bapi = pane.addInput(obj, 'foo', {
w: {
max: 456,
min: -123,
},
});

const c = bapi.controller.binding.value.constraint;
if (!(c instanceof PointNdConstraint)) {
throw new Error('Unexpected constraint');
}
const wc = c.components[3];
if (!wc) {
throw new Error('Unexpected constraint');
}
const rc = findConstraint(wc, RangeConstraint);
assert.strictEqual(rc && rc.minValue, -123);
assert.strictEqual(rc && rc.maxValue, 456);
});
});
23 changes: 23 additions & 0 deletions lib/plugin/input-bindings/point-4d/converter/point-4d-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {assert} from 'chai';
import {describe, it} from 'mocha';

import {BindingTarget} from '../../../common/binding/target';
import {Point4d} from '../model/point-4d';
import {writePoint4d} from './point-4d';

describe(writePoint4d.name, () => {
it('should write value without destruction', () => {
const obj = {
foo: {x: 12, y: 34, z: -56, w: 78},
};
const objFoo = obj.foo;
const t = new BindingTarget(obj, 'foo');
writePoint4d(t, new Point4d(56, 78, 901, 23));

assert.strictEqual(obj.foo, objFoo);
assert.strictEqual(obj.foo.x, 56);
assert.strictEqual(obj.foo.y, 78);
assert.strictEqual(obj.foo.z, 901);
assert.strictEqual(obj.foo.w, 23);
});
});
18 changes: 18 additions & 0 deletions lib/plugin/input-bindings/point-4d/converter/point-4d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {BindingTarget} from '../../../common/binding/target';
import {Point4d} from '../model/point-4d';

/**
* @hidden
*/
export function point4dFromUnknown(value: unknown): Point4d {
return Point4d.isObject(value)
? new Point4d(value.x, value.y, value.z, value.w)
: new Point4d();
}

export function writePoint4d(target: BindingTarget, value: Point4d) {
target.writeProperty('x', value.x);
target.writeProperty('y', value.y);
target.writeProperty('z', value.z);
target.writeProperty('w', value.w);
}
67 changes: 67 additions & 0 deletions lib/plugin/input-bindings/point-4d/model/point-4d-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {assert} from 'chai';
import {describe as context, describe, it} from 'mocha';

import {Point4d} from './point-4d';

describe(Point4d.name, () => {
[
{
object: null,
expected: false,
},
{
object: undefined,
expected: false,
},
{
object: {x: 0, y: 1},
expected: false,
},
{
object: {x: -1, y: 0, z: 1},
expected: false,
},
{
object: {x: -1, y: 0, z: 1, w: 0},
expected: true,
},
{
object: {x: 1, y: 2, z: 3, w: '4'},
expected: false,
},
].forEach((testCase) => {
context(`when object = ${JSON.stringify(testCase.object)}`, () => {
it(`should regard input as object: ${testCase.expected}`, () => {
assert.strictEqual(
Point4d.isObject(testCase.object),
testCase.expected,
);
});
});
});

[
{
object: new Point4d(0, 1, 2),
expected: {x: 0, y: 1, z: 2, w: 0},
},
{
object: new Point4d(),
expected: {x: 0, y: 0, z: 0, w: 0},
},
{
object: new Point4d(-100),
expected: {x: -100, y: 0, z: 0, w: 0},
},
{
object: new Point4d(1, 2, 3, 4),
expected: {x: 1, y: 2, z: 3, w: 4},
},
].forEach((testCase) => {
context(`when Point3d = ${JSON.stringify(testCase.object)}`, () => {
it(`should convert into object: ${testCase.expected}`, () => {
assert.deepStrictEqual(testCase.object.toObject(), testCase.expected);
});
});
});
});
66 changes: 66 additions & 0 deletions lib/plugin/input-bindings/point-4d/model/point-4d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {isEmpty, Tuple4} from '../../../../misc/type-util';
import {PointNdAssembly} from '../../common/model/point-nd';

export interface Point4dObject {
x: number;
y: number;
z: number;
w: number;
}

export class Point4d {
public x: number;
public y: number;
public z: number;
public w: number;

constructor(x = 0, y = 0, z = 0, w = 0) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}

public getComponents(): Tuple4<number> {
return [this.x, this.y, this.z, this.w];
}

public static isObject(obj: any): obj is Point4dObject {
if (isEmpty(obj)) {
return false;
}

const x = obj.x;
const y = obj.y;
const z = obj.z;
const w = obj.w;
if (
typeof x !== 'number' ||
typeof y !== 'number' ||
typeof z !== 'number' ||
typeof w !== 'number'
) {
return false;
}

return true;
}

public static equals(v1: Point4d, v2: Point4d): boolean {
return v1.x === v2.x && v1.y === v2.y && v1.z === v2.z && v1.w === v2.w;
}

public toObject(): Point4dObject {
return {
x: this.x,
y: this.y,
z: this.z,
w: this.w,
};
}
}

export const Point4dAssembly: PointNdAssembly<Point4d> = {
toComponents: (p: Point4d) => p.getComponents(),
fromComponents: (comps: number[]) => new Point4d(...comps),
};
Loading

0 comments on commit 308a3aa

Please sign in to comment.