mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 08:25:19 +01:00
assembly infrastructure
This commit is contained in:
parent
06682ab003
commit
4ddf018fc6
85 changed files with 1951 additions and 504 deletions
2
modules/lstream/index.d.ts
vendored
2
modules/lstream/index.d.ts
vendored
|
|
@ -52,7 +52,7 @@ export function distinctState<T>(initialValue: T): StateStream<T>;
|
|||
|
||||
export function externalState<T>(get: any, set: any): StateStream<T>;
|
||||
|
||||
export function never<T>(): Stream<T>
|
||||
export function never<T>(): Emitter<T>
|
||||
|
||||
export function constant<T>(value: T): Stream<T>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ export class NeverStream extends StreamBase {
|
|||
attach(observer) {
|
||||
return NOOP;
|
||||
}
|
||||
|
||||
next(value) {
|
||||
}
|
||||
}
|
||||
|
||||
NeverStream.INSTANCE = new NeverStream();
|
||||
|
|
|
|||
|
|
@ -30,25 +30,27 @@ export default class CSys {
|
|||
w() {
|
||||
return this.z.dot(this.origin);
|
||||
}
|
||||
|
||||
|
||||
get outTransformation3x3() {
|
||||
return new Matrix3().setBasisAxises(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
get outTransformation() {
|
||||
if (!this._outTr) {
|
||||
const mx = new Matrix3().setBasisAxises(this.x, this.y, this.z);
|
||||
mx.tx = this.origin.x;
|
||||
mx.ty = this.origin.y;
|
||||
mx.tz = this.origin.z;
|
||||
this._outTr = mx;
|
||||
}
|
||||
return this._outTr;
|
||||
const mx = new Matrix3().setBasisAxises(this.x, this.y, this.z);
|
||||
mx.tx = this.origin.x;
|
||||
mx.ty = this.origin.y;
|
||||
mx.tz = this.origin.z;
|
||||
return mx;
|
||||
}
|
||||
|
||||
get inTransformation3x3() {
|
||||
return this.outTransformation3x3.invert();
|
||||
}
|
||||
|
||||
get inTransformation() {
|
||||
if (!this._inTr) {
|
||||
this._inTr = this.outTransformation.invert();
|
||||
}
|
||||
return this._inTr;
|
||||
return this.outTransformation.invert();
|
||||
}
|
||||
|
||||
|
||||
copy(csys) {
|
||||
this.origin.setV(csys.origin);
|
||||
this.x.setV(csys.x);
|
||||
|
|
@ -65,7 +67,16 @@ export default class CSys {
|
|||
this.origin.set(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
invert() {
|
||||
const tr = this.inTransformation;
|
||||
return new CSys(
|
||||
new Vector(tr.tx, tr.ty, tr.tz),
|
||||
new Vector(tr.mxx, tr.myx, tr.mzx),
|
||||
new Vector(tr.mxy, tr.myy, tr.mzy),
|
||||
new Vector(tr.mxz, tr.myz, tr.mzz)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CSys.ORIGIN = CSys.origin();
|
||||
371
modules/math/l3space.ts
Normal file
371
modules/math/l3space.ts
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
import Vector from 'math/vector';
|
||||
|
||||
export type Basis = [Vector, Vector, Vector];
|
||||
|
||||
export type Vec3 = [number, number, number];
|
||||
|
||||
const freeze = Object.freeze;
|
||||
|
||||
const ORIGIN = freeze(new Vector(0, 0, 0));
|
||||
|
||||
const AXIS = freeze({
|
||||
X: freeze(new Vector(1, 0, 0)),
|
||||
Y: freeze(new Vector(0, 1, 0)),
|
||||
Z: freeze(new Vector(0, 0, 1))
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
const IDENTITY_BASIS: Basis = Object.freeze([AXIS.X, AXIS.Y, AXIS.Z]);
|
||||
|
||||
export const STANDARD_BASES = freeze({
|
||||
'XY': IDENTITY_BASIS,
|
||||
'XZ': [AXIS.X, AXIS.Z, AXIS.Y],
|
||||
'ZY': [AXIS.Z, AXIS.Y, AXIS.X]
|
||||
});
|
||||
|
||||
export class Matrix3 {
|
||||
|
||||
mxx: number = 1;
|
||||
mxy: number = 0;
|
||||
mxz: number = 0;
|
||||
tx: number = 0;
|
||||
myx: number = 0;
|
||||
myy: number = 1;
|
||||
myz: number = 0;
|
||||
ty: number = 0;
|
||||
mzx: number = 0;
|
||||
mzy: number = 0;
|
||||
mzz: number = 1;
|
||||
tz: number = 0;
|
||||
|
||||
reset(): Matrix3 {
|
||||
this.mxx = 1;
|
||||
this.mxy = 0;
|
||||
this.mxz = 0;
|
||||
this.tx = 0;
|
||||
this.myx = 0;
|
||||
this.myy = 1;
|
||||
this.myz = 0;
|
||||
this.ty = 0;
|
||||
this.mzx = 0;
|
||||
this.mzy = 0;
|
||||
this.mzz = 1;
|
||||
this.tz = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
setBasis(basis: [Vector, Vector, Vector]): Matrix3 {
|
||||
var b = basis;
|
||||
this.mxx = b[0].x;
|
||||
this.mxy = b[1].x;
|
||||
this.mxz = b[2].x;
|
||||
this.tx = 0;
|
||||
this.myx = b[0].y;
|
||||
this.myy = b[1].y;
|
||||
this.myz = b[2].y;
|
||||
this.ty = 0;
|
||||
this.mzx = b[0].z;
|
||||
this.mzy = b[1].z;
|
||||
this.mzz = b[2].z;
|
||||
this.tz = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
setBasisAxises(x: Vector, y: Vector, z: Vector): Matrix3 {
|
||||
this.mxx = x.x;
|
||||
this.mxy = y.x;
|
||||
this.mxz = z.x;
|
||||
this.tx = 0;
|
||||
this.myx = x.y;
|
||||
this.myy = y.y;
|
||||
this.myz = z.y;
|
||||
this.ty = 0;
|
||||
this.mzx = x.z;
|
||||
this.mzy = y.z;
|
||||
this.mzz = z.z;
|
||||
this.tz = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
setBasisAndTranslation(basis: [Vector, Vector, Vector], translation: Vector): Matrix3 {
|
||||
this.setBasis(basis);
|
||||
this.tx = translation.x;
|
||||
this.ty = translation.y;
|
||||
this.tz = translation.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
scale(dx: number, dy: number, dz: number): Matrix3{
|
||||
this.mxx *= dx;
|
||||
this.myy *= dy;
|
||||
this.mzz *= dz;
|
||||
return this;
|
||||
};
|
||||
|
||||
translate(dx: number, dy: number, dz: number): Matrix3 {
|
||||
this.tx += dx;
|
||||
this.ty += dy;
|
||||
this.tz += dz;
|
||||
return this;
|
||||
};
|
||||
|
||||
set3(
|
||||
mxx: number, mxy: number, mxz: number,
|
||||
myx: number, myy: number, myz: number,
|
||||
mzx: number, mzy: number, mzz: number
|
||||
): Matrix3 {
|
||||
this.mxx = mxx;
|
||||
this.mxy = mxy;
|
||||
this.mxz = mxz;
|
||||
this.myx = myx;
|
||||
this.myy = myy;
|
||||
this.myz = myz;
|
||||
this.mzx = mzx;
|
||||
this.mzy = mzy;
|
||||
this.mzz = mzz;
|
||||
return this;
|
||||
};
|
||||
|
||||
set34(
|
||||
mxx: number, mxy: number, mxz: number, tx: number,
|
||||
myx: number, myy: number, myz: number, ty: number,
|
||||
mzx: number, mzy: number, mzz: number, tz: number
|
||||
): Matrix3 {
|
||||
this.mxx = mxx;
|
||||
this.mxy = mxy;
|
||||
this.mxz = mxz;
|
||||
this.tx = tx;
|
||||
this.myx = myx;
|
||||
this.myy = myy;
|
||||
this.myz = myz;
|
||||
this.ty = ty;
|
||||
this.mzx = mzx;
|
||||
this.mzy = mzy;
|
||||
this.mzz = mzz;
|
||||
this.tz = tz;
|
||||
return this;
|
||||
};
|
||||
|
||||
setMatrix(m: Matrix3): Matrix3 {
|
||||
this.mxx = m.mxx;
|
||||
this.mxy = m.mxy;
|
||||
this.mxz = m.mxz;
|
||||
this.tx = m.tx;
|
||||
this.myx = m.myx;
|
||||
this.myy = m.myy;
|
||||
this.myz = m.myz;
|
||||
this.ty = m.ty;
|
||||
this.mzx = m.mzx;
|
||||
this.mzy = m.mzy;
|
||||
this.mzz = m.mzz;
|
||||
this.tz = m.tz;
|
||||
return this;
|
||||
};
|
||||
|
||||
setToMatrix(m: any): void {
|
||||
m.set(
|
||||
this.mxx, this.mxy, this.mxz, this.tx,
|
||||
this.myx, this.myy, this.myz, this.ty,
|
||||
this.mzx, this.mzy, this.mzz, this.tz,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
};
|
||||
|
||||
toArray(): [[number, number, number, number],[number, number, number, number],[number, number, number, number]] {
|
||||
return [
|
||||
[this.mxx, this.mxy, this.mxz, this.tx],
|
||||
[this.myx, this.myy, this.myz, this.ty],
|
||||
[this.mzx, this.mzy, this.mzz, this.tz]
|
||||
];
|
||||
};
|
||||
|
||||
invert(): Matrix3 {
|
||||
return this.__invert(new Matrix3());
|
||||
};
|
||||
|
||||
_invert(): Matrix3 {
|
||||
return this.__invert(this);
|
||||
};
|
||||
|
||||
__invert(out: Matrix3): Matrix3 {
|
||||
|
||||
var det =
|
||||
this.mxx * (this.myy * this.mzz - this.mzy * this.myz) +
|
||||
this.mxy * (this.myz * this.mzx - this.mzz * this.myx) +
|
||||
this.mxz * (this.myx * this.mzy - this.mzx * this.myy);
|
||||
|
||||
if (det == 0.0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var cxx = this.myy * this.mzz - this.myz * this.mzy;
|
||||
var cyx = -this.myx * this.mzz + this.myz * this.mzx;
|
||||
var czx = this.myx * this.mzy - this.myy * this.mzx;
|
||||
var cxt = -this.mxy * (this.myz * this.tz - this.mzz * this.ty)
|
||||
- this.mxz * (this.ty * this.mzy - this.tz * this.myy)
|
||||
- this.tx * (this.myy * this.mzz - this.mzy * this.myz);
|
||||
var cxy = -this.mxy * this.mzz + this.mxz * this.mzy;
|
||||
var cyy = this.mxx * this.mzz - this.mxz * this.mzx;
|
||||
var czy = -this.mxx * this.mzy + this.mxy * this.mzx;
|
||||
var cyt = this.mxx * (this.myz * this.tz - this.mzz * this.ty)
|
||||
+ this.mxz * (this.ty * this.mzx - this.tz * this.myx)
|
||||
+ this.tx * (this.myx * this.mzz - this.mzx * this.myz);
|
||||
var cxz = this.mxy * this.myz - this.mxz * this.myy;
|
||||
var cyz = -this.mxx * this.myz + this.mxz * this.myx;
|
||||
var czz = this.mxx * this.myy - this.mxy * this.myx;
|
||||
var czt = -this.mxx * (this.myy * this.tz - this.mzy * this.ty)
|
||||
- this.mxy * (this.ty * this.mzx - this.tz * this.myx)
|
||||
- this.tx * (this.myx * this.mzy - this.mzx * this.myy);
|
||||
|
||||
out.mxx = cxx / det;
|
||||
out.mxy = cxy / det;
|
||||
out.mxz = cxz / det;
|
||||
out.tx = cxt / det;
|
||||
out.myx = cyx / det;
|
||||
out.myy = cyy / det;
|
||||
out.myz = cyz / det;
|
||||
out.ty = cyt / det;
|
||||
out.mzx = czx / det;
|
||||
out.mzy = czy / det;
|
||||
out.mzz = czz / det;
|
||||
out.tz = czt / det;
|
||||
return out;
|
||||
};
|
||||
|
||||
combine(transform: Matrix3, out?: Matrix3): Matrix3 {
|
||||
var txx = transform.mxx;
|
||||
var txy = transform.mxy;
|
||||
var txz = transform.mxz;
|
||||
var ttx = transform.tx;
|
||||
var tyx = transform.myx;
|
||||
var tyy = transform.myy;
|
||||
var tyz = transform.myz;
|
||||
var tty = transform.ty;
|
||||
var tzx = transform.mzx;
|
||||
var tzy = transform.mzy;
|
||||
var tzz = transform.mzz;
|
||||
var ttz = transform.tz;
|
||||
|
||||
var m = out || new Matrix3();
|
||||
m.mxx = (this.mxx * txx + this.mxy * tyx + this.mxz * tzx);
|
||||
m.mxy = (this.mxx * txy + this.mxy * tyy + this.mxz * tzy);
|
||||
m.mxz = (this.mxx * txz + this.mxy * tyz + this.mxz * tzz);
|
||||
m.tx = (this.mxx * ttx + this.mxy * tty + this.mxz * ttz + this.tx);
|
||||
m.myx = (this.myx * txx + this.myy * tyx + this.myz * tzx);
|
||||
m.myy = (this.myx * txy + this.myy * tyy + this.myz * tzy);
|
||||
m.myz = (this.myx * txz + this.myy * tyz + this.myz * tzz);
|
||||
m.ty = (this.myx * ttx + this.myy * tty + this.myz * ttz + this.ty);
|
||||
m.mzx = (this.mzx * txx + this.mzy * tyx + this.mzz * tzx);
|
||||
m.mzy = (this.mzx * txy + this.mzy * tyy + this.mzz * tzy);
|
||||
m.mzz = (this.mzx * txz + this.mzy * tyz + this.mzz * tzz);
|
||||
m.tz = (this.mzx * ttx + this.mzy * tty + this.mzz * ttz + this.tz);
|
||||
|
||||
return m;
|
||||
};
|
||||
|
||||
_apply(vector: Vector): Vector {
|
||||
return this.__apply(vector, vector);
|
||||
};
|
||||
|
||||
__apply(vector: Vector, out: Vector): Vector {
|
||||
let x = vector.x;
|
||||
let y = vector.y;
|
||||
let z = vector.z;
|
||||
out.x = this.mxx * x + this.mxy * y + this.mxz * z + this.tx;
|
||||
out.y = this.myx * x + this.myy * y + this.myz * z + this.ty;
|
||||
out.z = this.mzx * x + this.mzy * y + this.mzz * z + this.tz;
|
||||
return out;
|
||||
};
|
||||
|
||||
apply3(data: Vec3): Vec3 {
|
||||
return this.__apply3(data, [0,0,0])
|
||||
};
|
||||
|
||||
_apply3(data: Vec3): Vec3 {
|
||||
return this.__apply3(data, data);
|
||||
};
|
||||
|
||||
__apply3([x, y, z]: Vec3, out: Vec3): Vec3 {
|
||||
out[0] = this.mxx * x + this.mxy * y + this.mxz * z + this.tx;
|
||||
out[1] = this.myx * x + this.myy * y + this.myz * z + this.ty;
|
||||
out[2] = this.mzx * x + this.mzy * y + this.mzz * z + this.tz;
|
||||
return out;
|
||||
};
|
||||
|
||||
rotateWithSphericalAxis(axisAzimuth: number, axisInclination: number, angle: number, pivot: Vector) {
|
||||
|
||||
const axis = new Vector(
|
||||
Math.sin(axisAzimuth) * Math.cos(axisInclination),
|
||||
Math.sin(axisAzimuth) * Math.sin(axisInclination),
|
||||
Math.cos(axisAzimuth)
|
||||
);
|
||||
|
||||
return Matrix3.rotateMatrix(angle, axis, pivot, this);
|
||||
};
|
||||
|
||||
rotate(angle: number, axis: Vector, pivot: Vector) {
|
||||
return Matrix3.rotateMatrix(angle, axis, pivot, this);
|
||||
};
|
||||
|
||||
static rotateMatrix(angle: number, axis: Vector, pivot: Vector, matrix: Matrix3): Matrix3 {
|
||||
var sin = Math.sin(angle);
|
||||
var cos = Math.cos(angle);
|
||||
var axisX, axisY, axisZ;
|
||||
var m = matrix || new Matrix3();
|
||||
|
||||
if (axis === AXIS.X || axis === AXIS.Y || axis === AXIS.Z) {
|
||||
axisX = axis.x;
|
||||
axisY = axis.y;
|
||||
axisZ = axis.z;
|
||||
} else {
|
||||
// normalize
|
||||
var mag = axis.length();
|
||||
|
||||
if (mag == 0.0) {
|
||||
return m;
|
||||
} else {
|
||||
axisX = axis.x / mag;
|
||||
axisY = axis.y / mag;
|
||||
axisZ = axis.z / mag;
|
||||
}
|
||||
}
|
||||
|
||||
var px = pivot.x;
|
||||
var py = pivot.y;
|
||||
var pz = pivot.z;
|
||||
|
||||
m.mxx = cos + axisX * axisX * (1 - cos);
|
||||
m.mxy = axisX * axisY * (1 - cos) - axisZ * sin;
|
||||
m.mxz = axisX * axisZ * (1 - cos) + axisY * sin;
|
||||
|
||||
m.tx = px * (1 - m.mxx) - py * m.mxy - pz * m.mxz;
|
||||
|
||||
m.myx = axisY * axisX * (1 - cos) + axisZ * sin;
|
||||
m.myy = cos + axisY * axisY * (1 - cos);
|
||||
m.myz = axisY * axisZ * (1 - cos) - axisX * sin;
|
||||
m.ty = py * (1 - m.myy) - px * m.myx - pz * m.myz;
|
||||
|
||||
m.mzx = axisZ * axisX * (1 - cos) - axisY * sin;
|
||||
m.mzy = axisZ * axisY * (1 - cos) + axisX * sin;
|
||||
m.mzz = cos + axisZ * axisZ * (1 - cos);
|
||||
m.tz = pz * (1 - m.mzz) - px * m.mzx - py * m.mzy;
|
||||
return m;
|
||||
};
|
||||
|
||||
apply = vector => this.__apply(vector, new Vector());
|
||||
}
|
||||
|
||||
|
||||
function BasisForPlane(normal: Vector, alignY: Vector = AXIS.Y, alignZ: Vector = AXIS.Z): [number, number, Vector] {
|
||||
let alignPlane, x, y;
|
||||
if (Math.abs(normal.dot(alignY)) < 0.5) {
|
||||
alignPlane = normal.cross(alignY);
|
||||
} else {
|
||||
alignPlane = normal.cross(alignZ);
|
||||
}
|
||||
y = alignPlane.cross(normal);
|
||||
x = y.cross(normal);
|
||||
return [x, y, normal];
|
||||
}
|
||||
|
||||
export {ORIGIN, IDENTITY_BASIS, AXIS, BasisForPlane};
|
||||
34
modules/math/quaternion.ts
Normal file
34
modules/math/quaternion.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
|
||||
export class Quaternion {
|
||||
|
||||
x: number = 0;
|
||||
y: number = 0;
|
||||
z: number = 0;
|
||||
w: number = 1;
|
||||
|
||||
|
||||
setAxisAndAngle(axisX, axisY, axisZ, angle) {
|
||||
const halfAngle = angle/2;
|
||||
const sin = Math.sin(halfAngle);
|
||||
this.x = axisX*sin;
|
||||
this.y = axisY*sin;
|
||||
this.z = axisZ*sin;
|
||||
this.w = Math.cos(halfAngle);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
setSphericalAxisAndAngle(azimuth, inclination, angle) {
|
||||
|
||||
this.setAxisAndAngle(
|
||||
Math.sin(azimuth) * Math.cos(inclination),
|
||||
Math.sin(azimuth) * Math.sin(inclination),
|
||||
Math.cos(azimuth),
|
||||
angle
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ import {AmbientLight, PerspectiveCamera, Scene, SpotLight, WebGLRenderer} from '
|
|||
import DPR from '../dpr';
|
||||
import {MeshArrow} from './objects/auxiliary';
|
||||
import * as SceneGraph from './sceneGraph';
|
||||
import {AXIS} from '../../web/app/math/l3space';
|
||||
import {AXIS} from '../math/l3space';
|
||||
|
||||
export default function(container) {
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {advancePseudoFrenetFrame, frenetFrame, pseudoFrenetFrame} from '../../..
|
|||
import * as vec from 'math/vec';
|
||||
import {viewScaleFactor} from '../scaleHelper';
|
||||
import {arrToThree} from 'math/vectorAdapters';
|
||||
import {ORIGIN} from '../../../web/app/math/l3space';
|
||||
import {ORIGIN} from '../../math/l3space';
|
||||
import {getSceneSetup} from '../sceneSetup';
|
||||
import calcFaceNormal from '../utils/calcFaceNormal';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
@import "~ui/styles/theme.less";
|
||||
|
||||
.root {
|
||||
background-color: @bg-color-2;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
|||
44
modules/ui/components/GenericWizard.tsx
Normal file
44
modules/ui/components/GenericWizard.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import React from 'react';
|
||||
import Window, {WindowControlButton, WindowProps} from 'ui/components/Window';
|
||||
import {DocumentationTopic$} from "doc/DocumentationWindow";
|
||||
import {IoMdHelp} from "react-icons/io";
|
||||
import cx from 'classnames';
|
||||
import Stack from "ui/components/Stack";
|
||||
import ButtonGroup from "ui/components/controls/ButtonGroup";
|
||||
import Button from "ui/components/controls/Button";
|
||||
|
||||
export function GenericWizard({topicId, title, left, className, children, onCancel, onOK, infoText, ...props}: {
|
||||
topicId: string,
|
||||
title: string,
|
||||
left?: number,
|
||||
onCancel: () => any,
|
||||
onOK: () => any,
|
||||
infoText: string
|
||||
} & WindowProps ) {
|
||||
|
||||
return <Window initWidth={250}
|
||||
initLeft={left || 15}
|
||||
title={(title||'').toUpperCase()}
|
||||
className={cx('mid-typography', className)}
|
||||
controlButtons={<>
|
||||
<WindowControlButton title='help' onClick={(e) => DocumentationTopic$.next({
|
||||
topic: topicId,
|
||||
x: e.pageX + 40,
|
||||
y: e.pageY
|
||||
})}>
|
||||
<IoMdHelp />
|
||||
</WindowControlButton>
|
||||
</>} {...props} >
|
||||
{children}
|
||||
<Stack>
|
||||
<ButtonGroup>
|
||||
<Button className='dialog-cancel' onClick={onCancel}>Cancel</Button>
|
||||
<Button className='dialog-ok' type='accent' onClick={onOK}>OK</Button>
|
||||
</ButtonGroup>
|
||||
{infoText}
|
||||
</Stack>
|
||||
|
||||
</Window>
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ function _maskTest(mask, value) {
|
|||
export function WindowControlButton({danger, ...props}: {
|
||||
danger?: boolean;
|
||||
children: any;
|
||||
onClick: () => void;
|
||||
} & JSX.IntrinsicAttributes) {
|
||||
onClick: (e: any) => any;
|
||||
} & React.HTMLAttributes<HTMLSpanElement>) {
|
||||
return <span className={cx(ls.button, danger&&ls.danger)} {...props} />;
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import ls from './ButtonGroup.less'
|
||||
import cx from 'classnames';
|
||||
|
||||
export default function ButtonGroup({className, ...props}) {
|
||||
export default function ButtonGroup({className, ...props}: React.HTMLAttributes<HTMLSpanElement>) {
|
||||
|
||||
return <div className={cx(ls.root, className)} {...props}/>;
|
||||
|
||||
|
|
@ -1,52 +1,59 @@
|
|||
import React from 'react';
|
||||
import React, {useCallback, useRef} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import InputControl from './InputControl';
|
||||
|
||||
export default class NumberControl extends React.Component {
|
||||
|
||||
render() {
|
||||
let {onChange, onFocus, value} = this.props;
|
||||
return <InputControl type='number'
|
||||
onWheel={this.onWheel}
|
||||
value={ value }
|
||||
onChange={this.onChange}
|
||||
onFocus={onFocus}
|
||||
inputRef={input => this.input = input} />
|
||||
}
|
||||
|
||||
onChange = e => {
|
||||
this.props.onChange(e.target.value);
|
||||
export default function NumberControl(props) {
|
||||
|
||||
let {onChange, onFocus, value} = props;
|
||||
|
||||
const onChangeFromTarget = e => {
|
||||
onChange(e.target.value);
|
||||
};
|
||||
|
||||
onWheel = (e) => {
|
||||
let {baseStep, round, min, max, onChange, accelerator} = this.props;
|
||||
let delta = e.deltaY;
|
||||
let step = baseStep * (e.shiftKey ? accelerator : 1);
|
||||
let val = parseFloat(e.target.value);
|
||||
if (isNaN(val)) val = 0;
|
||||
val = val + (delta < 0 ? -step : step);
|
||||
if (min !== undefined && val < min) {
|
||||
val = min;
|
||||
|
||||
const attachWheelListener = useCallback((input) => {
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
if (max !== undefined && val > max) {
|
||||
val = max;
|
||||
}
|
||||
if (round !== 0) {
|
||||
val = val.toFixed(round);
|
||||
}
|
||||
this.input.value = val;
|
||||
onChange(val);
|
||||
// e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
const onWheel = (e) => {
|
||||
let {baseStep, round, min, max, onChange, accelerator} = props;
|
||||
let delta = e.shiftKey ? e.deltaX : e.deltaY;
|
||||
let step = baseStep * (e.shiftKey ? accelerator : 1);
|
||||
let val = parseFloat(e.target.value);
|
||||
if (isNaN(val)) val = 0;
|
||||
val = val + (delta < 0 ? -step : step);
|
||||
if (min !== undefined && val < min) {
|
||||
val = min;
|
||||
}
|
||||
if (max !== undefined && val > max) {
|
||||
val = max;
|
||||
}
|
||||
if (round !== 0) {
|
||||
val = val.toFixed(round);
|
||||
}
|
||||
input.value = val;
|
||||
onChange(val);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
input.addEventListener('wheel', onWheel, {passive: false});
|
||||
}, []);
|
||||
|
||||
return <InputControl type='number'
|
||||
value={value}
|
||||
onChange={onChangeFromTarget}
|
||||
onFocus={onFocus}
|
||||
inputRef={attachWheelListener}/>
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
NumberControl.propTypes = {
|
||||
baseStep: PropTypes.number,
|
||||
round: PropTypes.number,
|
||||
min: PropTypes.number,
|
||||
max: PropTypes.number,
|
||||
accelerator: PropTypes.number,
|
||||
baseStep: PropTypes.number,
|
||||
round: PropTypes.number,
|
||||
min: PropTypes.number,
|
||||
max: PropTypes.number,
|
||||
accelerator: PropTypes.number,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ export function useStream<T>(getStream: (ctx: ApplicationContext) => Stream<T>)
|
|||
const basicStreams = useContext(StreamsContext);
|
||||
const [state, setState] = useState<{data: T}>();
|
||||
|
||||
const stream = typeof getStream === 'function' ? getStream(basicStreams) : getStream;
|
||||
const stream = resolveStream(getStream, basicStreams);
|
||||
|
||||
if (!stream) {
|
||||
console.log(getStream);
|
||||
throw "no stream ^";
|
||||
}
|
||||
|
||||
useEffect(() => stream.attach(data => setState({data})), EMPTY_ARR);
|
||||
useEffect(() => stream.attach(data => setState({data})), [stream]);
|
||||
|
||||
// @ts-ignore
|
||||
return state ? state.data : (stream.value !== undefined ? stream.value : null);
|
||||
|
|
@ -26,7 +26,7 @@ export function useStreamWithUpdater<T>(getStream: (ctx: ApplicationContext) =>
|
|||
const data = useStream(getStream);
|
||||
const basicStreams = useContext(StreamsContext);
|
||||
|
||||
const stream = typeof getStream === 'function' ? getStream(basicStreams) : getStream;
|
||||
const stream = resolveStream(getStream, basicStreams);
|
||||
|
||||
const updater = useCallback((val) => {
|
||||
|
||||
|
|
@ -41,5 +41,6 @@ export function useStreamWithUpdater<T>(getStream: (ctx: ApplicationContext) =>
|
|||
|
||||
}
|
||||
|
||||
|
||||
const EMPTY_ARR = [];
|
||||
function resolveStream(getStream, basicStreams) {
|
||||
return typeof getStream === 'function' ? getStream(basicStreams) : getStream
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as test from '../../test'
|
||||
import {deepMerge} from '../coreTests/utils/deep-merge'
|
||||
import {Matrix3} from '../../../../web/app/math/l3space'
|
||||
import {Matrix3} from '../../../../modules/math/l3space'
|
||||
|
||||
const OPERANDS_MODE = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {Face} from './topo/face';
|
|||
import {Edge} from './topo/edge';
|
||||
import BrepCurve from './geom/curves/brepCurve';
|
||||
import {Plane} from './geom/impl/plane';
|
||||
import {BasisForPlane, Matrix3} from '../math/l3space';
|
||||
import {BasisForPlane, Matrix3} from 'math/l3space';
|
||||
import * as cad_utils from '../cad/cad-utils';
|
||||
import * as math from '../math/math';
|
||||
import {createBoundingSurface} from './brep-builder';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import {Point} from './geom/point'
|
||||
import {Plane} from './geom/impl/plane'
|
||||
import {createPrism, enclose} from './brep-enclose'
|
||||
import {AXIS, Matrix3} from '../math/l3space'
|
||||
import {AXIS, Matrix3} from 'math/l3space'
|
||||
import {Circle} from '../cad/sketch/sketchModel'
|
||||
import CSys from '../math/csys';
|
||||
import CSys from 'math/csys';
|
||||
|
||||
export function box(w, h, d, tr) {
|
||||
const wh = w * 0.5;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import NurbsCurve from "./nurbsCurve";
|
||||
import {Matrix3} from '../../../math/l3space'
|
||||
import {Matrix3} from '../../../../../modules/math/l3space'
|
||||
import {areEqual} from '../../../math/math'
|
||||
|
||||
import {eqSqTol, ueq, veq, veq3, veqNeg} from "../tolerance";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Point} from '../point';
|
||||
import {Line} from './line';
|
||||
import {AXIS, BasisForPlane, Matrix3} from '../../../math/l3space';
|
||||
import {AXIS, BasisForPlane, Matrix3} from '../../../../../modules/math/l3space';
|
||||
import {eqTol, veq} from '../tolerance';
|
||||
|
||||
export class Plane {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {AXIS, ORIGIN} from '../../math/l3space';
|
||||
import {AXIS, ORIGIN} from '../../../../modules/math/l3space';
|
||||
import Vector from 'math/vector';
|
||||
import {RiCamera2Line} from "react-icons/ri";
|
||||
|
||||
|
|
|
|||
145
web/app/cad/assembly/assembly.ts
Normal file
145
web/app/cad/assembly/assembly.ts
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
import {MObject} from "../model/mobject";
|
||||
import {Param} from "../../sketcher/shapes/param";
|
||||
import Vector from "math/vector";
|
||||
import {Matrix3} from "math/l3space";
|
||||
import {ISolveStage, SolvableObject} from "../../sketcher/constr/solvableObject";
|
||||
import {AlgNumConstraint} from "../../sketcher/constr/ANConstraints";
|
||||
import {Constraints3D} from "./constraints3d";
|
||||
|
||||
export abstract class AssemblyNode implements SolvableObject {
|
||||
|
||||
constraints: Set<AlgNumConstraint> = new Set();
|
||||
|
||||
model: MObject;
|
||||
|
||||
stage: ISolveStage;
|
||||
|
||||
id: string;
|
||||
|
||||
protected constructor(model: MObject) {
|
||||
this.model = model;
|
||||
this.id = 'assembly-node:' + model.id;
|
||||
}
|
||||
|
||||
abstract visitParams(cb);
|
||||
|
||||
abstract reset();
|
||||
|
||||
createConsistencyConstraints(): AlgNumConstraint[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
createRigidBodyLink(body: AssemblyCSysNode): AlgNumConstraint[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
get params(): Param[] {
|
||||
const paramArray = [];
|
||||
this.visitParams(p => paramArray.push(p));
|
||||
return paramArray;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AssemblyUnitVectorNode extends AssemblyNode {
|
||||
|
||||
x = new Param(0, 'X');
|
||||
y = new Param(0, 'Y');
|
||||
z = new Param(0, 'Z');
|
||||
getVector: () => Vector;
|
||||
|
||||
constructor(model: MObject, getVector: () => Vector) {
|
||||
super(model);
|
||||
this.getVector = getVector;
|
||||
}
|
||||
|
||||
visitParams(cb) {
|
||||
cb(this.x);
|
||||
cb(this.y);
|
||||
cb(this.z);
|
||||
}
|
||||
|
||||
reset() {
|
||||
const {x, y, z} = this.getVector();
|
||||
this.x.set(x);
|
||||
this.y.set(y);
|
||||
this.z.set(z);
|
||||
}
|
||||
|
||||
createConsistencyConstraints() {
|
||||
return [
|
||||
new AlgNumConstraint(Constraints3D.UnitVectorConsistency, [this])
|
||||
];
|
||||
}
|
||||
|
||||
createRigidBodyLink(body: AssemblyCSysNode) {
|
||||
return [
|
||||
new AlgNumConstraint(Constraints3D.RigidBodyLink3x3, [body, this])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AssemblyCSysNode extends AssemblyNode {
|
||||
|
||||
ox = new Param(0, 'X');
|
||||
oy = new Param(0, 'Y');
|
||||
oz = new Param(0, 'Z');
|
||||
ix = new Param(1, 'X');
|
||||
iy = new Param(0, 'Y');
|
||||
iz = new Param(0, 'Z');
|
||||
jx = new Param(0, 'X');
|
||||
jy = new Param(1, 'Y');
|
||||
jz = new Param(0, 'Z');
|
||||
kx = new Param(0, 'X');
|
||||
ky = new Param(0, 'Y');
|
||||
kz = new Param(1, 'Z');
|
||||
getTransformation: () => Matrix3;
|
||||
|
||||
constructor(model: MObject, getTransformation: () => Matrix3) {
|
||||
super(model);
|
||||
this.getTransformation = getTransformation;
|
||||
}
|
||||
|
||||
visitParams(cb) {
|
||||
cb(this.ox);
|
||||
cb(this.oy);
|
||||
cb(this.oz);
|
||||
cb(this.ix);
|
||||
cb(this.iy);
|
||||
cb(this.iz);
|
||||
cb(this.jx);
|
||||
cb(this.jy);
|
||||
cb(this.jz);
|
||||
cb(this.kx);
|
||||
cb(this.ky);
|
||||
cb(this.kz);
|
||||
}
|
||||
|
||||
reset() {
|
||||
const mx = this.getTransformation();
|
||||
this.ox.set(mx.tx);
|
||||
this.oy.set(mx.ty);
|
||||
this.oz.set(mx.tz);
|
||||
|
||||
this.ix.set(mx.mxx);
|
||||
this.iy.set(mx.myx);
|
||||
this.iz.set(mx.mzx);
|
||||
|
||||
this.jx.set(mx.mxy);
|
||||
this.jy.set(mx.myy);
|
||||
this.jz.set(mx.mzy);
|
||||
|
||||
this.kx.set(mx.mxz);
|
||||
this.ky.set(mx.myz);
|
||||
this.kz.set(mx.mzz);
|
||||
|
||||
}
|
||||
|
||||
createConsistencyConstraints() {
|
||||
return [
|
||||
new AlgNumConstraint(Constraints3D.CSysConsistency, [this])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
111
web/app/cad/assembly/assemblySolver.ts
Normal file
111
web/app/cad/assembly/assemblySolver.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import {AlgNumConstraint} from "../../sketcher/constr/ANConstraints";
|
||||
import {AlgNumSubSystem} from "../../sketcher/constr/AlgNumSystem";
|
||||
import Vector from "math/vector";
|
||||
import CSys from "math/csys";
|
||||
import {AssemblyCSysNode, AssemblyNode} from "./assembly";
|
||||
import {ISolveStage} from "../../sketcher/constr/solvableObject";
|
||||
import {MObject} from "../model/mobject";
|
||||
import {MShell} from "../model/mshell";
|
||||
import {Constraints3D} from "./constraints3d";
|
||||
|
||||
export function solveAssembly(constraints: AlgNumConstraint[]) {
|
||||
|
||||
const objects = new Set<AssemblyNode>();
|
||||
|
||||
constraints.forEach(c => c.objects.forEach(o => objects.add(o)));
|
||||
|
||||
const stage: ISolveStage = {
|
||||
objects: objects,
|
||||
index: 0
|
||||
};
|
||||
|
||||
const roots = new Set<MShell>();
|
||||
objects.forEach(o => {
|
||||
const root = o.model.root;
|
||||
if (root instanceof MShell) {
|
||||
roots.add(root);
|
||||
objects.add(root.assemblyNodes.location)
|
||||
}
|
||||
});
|
||||
|
||||
objects.forEach(o => {
|
||||
o.stage = stage;
|
||||
o.reset();
|
||||
});
|
||||
|
||||
// const algNumConstraint = new AlgNumConstraint(Constraints3D.FaceParallel, objects);
|
||||
|
||||
const system = new AlgNumSubSystem(() => 0.001, val => val, stage);
|
||||
// __DEBUG__.AddNormal(face1.csys.origin, new Vector().set3(objects[0].normal.map(p => p.get())))
|
||||
// __DEBUG__.AddNormal(face2.csys.origin, new Vector().set3(objects[1].normal.map(p => p.get())))
|
||||
|
||||
system.startTransaction();
|
||||
constraints.forEach(c => system.addConstraint(c));
|
||||
objects.forEach(assemblyNode => {
|
||||
const internalConstraints = assemblyNode.createConsistencyConstraints();
|
||||
internalConstraints.forEach(c => {
|
||||
c.internal = true;
|
||||
system.addConstraint(c);
|
||||
});
|
||||
|
||||
const root = assemblyNode.model.root;
|
||||
if (root instanceof MShell) {
|
||||
const rigidBodyLinks = assemblyNode.createRigidBodyLink(root.assemblyNodes.location);
|
||||
rigidBodyLinks.forEach(c => {
|
||||
c.internal = true;
|
||||
system.addConstraint(c);
|
||||
});
|
||||
} else {
|
||||
throw 'unsupported: needs location implementation';
|
||||
}
|
||||
});
|
||||
|
||||
system.prepare();
|
||||
system.solveFine();
|
||||
system.finishTransaction();
|
||||
|
||||
// __DEBUG__.AddNormal(face1.csys.origin, new Vector().set3(objects[0].normal.map(p => p.get())))
|
||||
// __DEBUG__.AddNormal(face2.csys.origin, new Vector().set3(objects[1].normal.map(p => p.get())))
|
||||
|
||||
roots.forEach(root => {
|
||||
applyResults(root, root.assemblyNodes.location);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function applyResults(shell: MShell, targetCsysParams: AssemblyCSysNode): void {
|
||||
const [
|
||||
ox, oy, oz, ix, iy, iz, jx, jy, jz, kx, ky, kz
|
||||
] = targetCsysParams.params.map(p => p.get());
|
||||
|
||||
const targetCsys = new CSys(
|
||||
new Vector(ox, oy, oz),
|
||||
new Vector(ix, iy, iz),
|
||||
new Vector(jx, jy, jz),
|
||||
new Vector(kx, ky, kz),
|
||||
);
|
||||
|
||||
const basis = [
|
||||
new Vector(ix, iy, iz),
|
||||
new Vector(jx, jy, jz),
|
||||
new Vector(kx, ky, kz),
|
||||
];
|
||||
|
||||
// __DEBUG__.AddCSys(shell.csys);
|
||||
// __DEBUG__.AddCSys(targetCsys);
|
||||
|
||||
const tr = shell.csys.inTransformation3x3;
|
||||
basis.forEach(r => tr._apply(r));
|
||||
|
||||
shell.location$.update(csys => {
|
||||
return targetCsys;
|
||||
});
|
||||
// shell.location$.mutate(csys => {
|
||||
// csys.x = basis[0];
|
||||
// csys.y = basis[1];
|
||||
// csys.z = basis[2];
|
||||
// csys.origin = new Vector(ox, oy, oz)._minus(shell.csys.origin);
|
||||
// });
|
||||
|
||||
}
|
||||
248
web/app/cad/assembly/constraints3d.ts
Normal file
248
web/app/cad/assembly/constraints3d.ts
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
import {Polynomial, POW_1_FN, POW_2_FN} from "../../sketcher/constr/polynomial";
|
||||
import {NoIcon} from "../../sketcher/icons/NoIcon";
|
||||
import {AlgNumConstraint, ConstantsDefinitions, ConstraintSchema} from "../../sketcher/constr/ANConstraints";
|
||||
import {MObject} from "../model/mobject";
|
||||
import {SolvableObject} from "../../sketcher/constr/solvableObject";
|
||||
|
||||
export const Constraints3D = {
|
||||
|
||||
FaceParallel: {
|
||||
id: 'FaceParallel',
|
||||
name: 'Face Parallel',
|
||||
icon: NoIcon,
|
||||
|
||||
defineAssemblyScope: ([face1, face2]) => {
|
||||
return [
|
||||
face1.assemblyNodes.normal,
|
||||
face2.assemblyNodes.normal
|
||||
];
|
||||
},
|
||||
|
||||
defineParamsScope: ([n1, n2], cb) => {
|
||||
n1.visitParams(cb);
|
||||
n2.visitParams(cb);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params) => {
|
||||
|
||||
const [
|
||||
nx1, ny1, nz1, nx2, ny2, nz2,
|
||||
] = params;
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(1)
|
||||
.monomial()
|
||||
.term(nx1, POW_1_FN)
|
||||
.term(nx2, POW_1_FN)
|
||||
.monomial()
|
||||
.term(ny1, POW_1_FN)
|
||||
.term(ny2, POW_1_FN)
|
||||
.monomial()
|
||||
.term(nz1, POW_1_FN)
|
||||
.term(nz2, POW_1_FN)
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
UnitVectorConsistency: {
|
||||
id: 'UnitVectorConsistency',
|
||||
name: 'UnitVectorConsistency',
|
||||
icon: NoIcon,
|
||||
|
||||
defineParamsScope: ([vec], cb) => {
|
||||
vec.visitParams(cb);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params) => {
|
||||
|
||||
const [x, y, z] = params;
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(x, POW_2_FN)
|
||||
.monomial()
|
||||
.term(y, POW_2_FN)
|
||||
.monomial()
|
||||
.term(z, POW_2_FN)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
CSysConsistency: {
|
||||
id: 'CSysConsistency',
|
||||
name: 'CSysConsistency',
|
||||
icon: NoIcon,
|
||||
|
||||
defineParamsScope: ([csys], cb) => {
|
||||
cb(csys.ix);
|
||||
cb(csys.iy);
|
||||
cb(csys.iz);
|
||||
cb(csys.jx);
|
||||
cb(csys.jy);
|
||||
cb(csys.jz);
|
||||
cb(csys.kx);
|
||||
cb(csys.ky);
|
||||
cb(csys.kz);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params) => {
|
||||
|
||||
const [
|
||||
ix,
|
||||
iy,
|
||||
iz,
|
||||
jx,
|
||||
jy,
|
||||
jz,
|
||||
kx,
|
||||
ky,
|
||||
kz] = params;
|
||||
|
||||
//let's keep matrix orthogonal and unit basis
|
||||
polynomials.push(new Polynomial(0)
|
||||
.monomial()
|
||||
.term(ix, POW_1_FN)
|
||||
.term(jx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iy, POW_1_FN)
|
||||
.term(jy, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iz, POW_1_FN)
|
||||
.term(jz, POW_1_FN));
|
||||
|
||||
polynomials.push(new Polynomial(0)
|
||||
.monomial()
|
||||
.term(ix, POW_1_FN)
|
||||
.term(kx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iy, POW_1_FN)
|
||||
.term(ky, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iz, POW_1_FN)
|
||||
.term(kz, POW_1_FN));
|
||||
|
||||
polynomials.push(new Polynomial(0)
|
||||
.monomial()
|
||||
.term(jx, POW_1_FN)
|
||||
.term(kx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(jy, POW_1_FN)
|
||||
.term(ky, POW_1_FN)
|
||||
.monomial()
|
||||
.term(jz, POW_1_FN)
|
||||
.term(kz, POW_1_FN));
|
||||
|
||||
polynomials.push(new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(ix, POW_2_FN)
|
||||
.monomial()
|
||||
.term(iy, POW_2_FN)
|
||||
.monomial()
|
||||
.term(iz, POW_2_FN));
|
||||
|
||||
polynomials.push(new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(jx, POW_2_FN)
|
||||
.monomial()
|
||||
.term(jy, POW_2_FN)
|
||||
.monomial()
|
||||
.term(jz, POW_2_FN));
|
||||
|
||||
polynomials.push(new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(kx, POW_2_FN)
|
||||
.monomial()
|
||||
.term(ky, POW_2_FN)
|
||||
.monomial()
|
||||
.term(kz, POW_2_FN));
|
||||
},
|
||||
},
|
||||
|
||||
RigidBodyLink3x3: {
|
||||
id: 'RigidBodyLink3x3',
|
||||
name: 'RigidBodyLink3x3',
|
||||
icon: NoIcon,
|
||||
|
||||
defineParamsScope: ([csys, vec], cb) => {
|
||||
cb(csys.ix);
|
||||
cb(csys.iy);
|
||||
cb(csys.iz);
|
||||
cb(csys.jx);
|
||||
cb(csys.jy);
|
||||
cb(csys.jz);
|
||||
cb(csys.kx);
|
||||
cb(csys.ky);
|
||||
cb(csys.kz);
|
||||
vec.visitParams(cb);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params, _, objects) => {
|
||||
const [csys, vec] = objects;
|
||||
|
||||
const {x: nStarX, y: nStarY, z: nStarZ} = vec.getVector();
|
||||
|
||||
const [ix, iy, iz, jx, jy, jz, kx, ky, kz, x, y, z] = params;
|
||||
|
||||
// out.x = this.mxx * x + this.mxy * y + this.mxz * z + this.tx;
|
||||
// out.y = this.myx * x + this.myy * y + this.myz * z + this.ty;
|
||||
// out.z = this.mzx * x + this.mzy * y + this.mzz * z + this.tz;
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(x, POW_1_FN)
|
||||
.monomial(nStarX)
|
||||
.term(ix, POW_1_FN)
|
||||
.monomial(nStarY)
|
||||
.term(jx, POW_1_FN)
|
||||
.monomial(nStarZ)
|
||||
.term(kx, POW_1_FN)
|
||||
);
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(y, POW_1_FN)
|
||||
.monomial(nStarX)
|
||||
.term(iy, POW_1_FN)
|
||||
.monomial(nStarY)
|
||||
.term(jy, POW_1_FN)
|
||||
.monomial(nStarZ)
|
||||
.term(ky, POW_1_FN),
|
||||
|
||||
);
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(z, POW_1_FN)
|
||||
.monomial(nStarX)
|
||||
.term(iz, POW_1_FN)
|
||||
.monomial(nStarY)
|
||||
.term(jz, POW_1_FN)
|
||||
.monomial(nStarZ)
|
||||
.term(kz, POW_1_FN)
|
||||
);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
export interface AssemblyConstraintSchema extends ConstraintSchema {
|
||||
defineAssemblyScope: (objects: MObject[]) => SolvableObject[],
|
||||
}
|
||||
|
||||
|
||||
export function createAssemblyConstraint(schema: AssemblyConstraintSchema,
|
||||
objects: MObject[],
|
||||
constants?: ConstantsDefinitions,
|
||||
internal?: boolean = false) {
|
||||
|
||||
return new AlgNumConstraint(schema, schema.defineAssemblyScope(objects), constants, internal);
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ import BBox from '../math/bbox'
|
|||
import {HashTable} from '../utils/hashmap'
|
||||
import {Graph} from '../math/graph'
|
||||
import * as math from '../math/math'
|
||||
import {Matrix3, AXIS, ORIGIN} from '../math/l3space'
|
||||
import {Matrix3, AXIS, ORIGIN} from '../../../modules/math/l3space'
|
||||
import {MeshSceneSolid} from './scene/wrappers/meshSceneObject'
|
||||
|
||||
export const FACE_COLOR = 0xB0C4DE;
|
||||
|
|
|
|||
|
|
@ -56,9 +56,13 @@ export function activate(ctx: ApplicationContext) {
|
|||
function findEntity(entity, id) {
|
||||
return index().get(id);
|
||||
}
|
||||
|
||||
|
||||
function find(id) {
|
||||
return index().get(id);
|
||||
}
|
||||
|
||||
services.cadRegistry = {
|
||||
getAllShells, findShell, findFace, findEdge, findSketchObject, findEntity, findDatum, findDatumAxis, findLoop,
|
||||
getAllShells, findShell, findFace, findEdge, findSketchObject, findEntity, findDatum, findDatumAxis, findLoop, find,
|
||||
get modelIndex() {
|
||||
return streams.cadRegistry.modelIndex.value;
|
||||
},
|
||||
|
|
@ -85,6 +89,7 @@ export interface CadRegistry {
|
|||
findDatum(id: string): MObject;
|
||||
findDatumAxis(id: string): MObject;
|
||||
findLoop(id: string): MObject;
|
||||
find(id: string): MObject;
|
||||
modelIndex: Map<String, MObject>;
|
||||
models: MObject[];
|
||||
shells: MObject[];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {Matrix3} from '../../../math/l3space'
|
||||
import {Matrix3} from '../../../../../modules/math/l3space'
|
||||
import * as math from '../../../math/math'
|
||||
import {enclose} from '../../../brep/brep-enclose'
|
||||
import {BooleanOperation, combineShells} from '../booleanOperation'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import DatumWizard from './CreateDatumWizard';
|
|||
import schema from './createDatumOpSchema';
|
||||
import DatumObject3D from '../datumObject';
|
||||
import * as SceneGraph from 'scene/sceneGraph';
|
||||
import CSys from '../../../../math/csys';
|
||||
import CSys from '../../../../../../modules/math/csys';
|
||||
import {MDatum} from '../../../model/mdatum';
|
||||
import {roundInteractiveInput} from '../../wizard/roundUtils';
|
||||
import {DatumParamsRenderer} from '../DatumParamsRenderer';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {MeshLambertMaterial, Object3D} from 'three';
|
||||
import {AXIS} from '../../../math/l3space';
|
||||
import {AXIS} from '../../../../../modules/math/l3space';
|
||||
import {MeshArrow} from 'scene/objects/auxiliary';
|
||||
import {viewScaleFactor} from '../../../../../modules/scene/scaleHelper';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import schema from './rotateDatumOpSchema';
|
||||
import {MDatum} from '../../../model/mdatum';
|
||||
import RotateDatumWizard from './RotateDatumWizard';
|
||||
import {Matrix3, ORIGIN} from '../../../../math/l3space';
|
||||
import {Matrix3, ORIGIN} from '../../../../../../modules/math/l3space';
|
||||
import {DEG_RAD} from '../../../../math/math';
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {Mesh, ConeGeometry, Matrix4, CylinderGeometry} from 'three';
|
|||
import schema from './coneOpSchema';
|
||||
import ConeWizard from './ConeWizard';
|
||||
import {IMAGINARY_SURFACE_MATERIAL} from '../../../preview/scenePreviewer';
|
||||
import CSys from '../../../../math/csys';
|
||||
import CSys from '../../../../../../modules/math/csys';
|
||||
import * as SceneGraph from '../../../../../../modules/scene/sceneGraph';
|
||||
import datumConsumingOperation from '../datumConsumingOperation';
|
||||
import {assignBooleanParams} from '../booleanOptionHelper';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import CSys from '../../../math/csys';
|
||||
import CSys from '../../../../../modules/math/csys';
|
||||
|
||||
export default function datumConsumingOperation(params, services, run) {
|
||||
let mDatum = params.datum && services.cadRegistry.findDatum(params.datum);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {BoxGeometry, Matrix4, Mesh} from 'three';
|
||||
import {IMAGINARY_SURFACE_MATERIAL} from '../../preview/scenePreviewer';
|
||||
import CSys from '../../../math/csys';
|
||||
import CSys from '../../../../../modules/math/csys';
|
||||
import * as SceneGraph from '../../../../../modules/scene/sceneGraph';
|
||||
|
||||
export default function primitivePreviewer(createThreePrimitiveGeometry, paramsToScales, shift) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {createMeshGeometry} from 'scene/geoms';
|
||||
import {STANDARD_BASES} from '../../../../math/l3space';
|
||||
import {STANDARD_BASES} from '../../../../../../modules/math/l3space';
|
||||
import {Plane} from '../../../../brep/geom/impl/plane';
|
||||
import Vector from 'math/vector';
|
||||
import PlaneWizard from './SimplePlaneWizard';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {Mesh, TorusGeometry} from 'three';
|
|||
import schema from './torusOpSchema';
|
||||
import TorusWizard from './TorusWizard';
|
||||
import {IMAGINARY_SURFACE_MATERIAL} from '../../../preview/scenePreviewer';
|
||||
import CSys from '../../../../math/csys';
|
||||
import CSys from '../../../../../../modules/math/csys';
|
||||
import * as SceneGraph from '../../../../../../modules/scene/sceneGraph';
|
||||
import datumConsumingOperation from '../datumConsumingOperation';
|
||||
import {assignBooleanParams} from '../booleanOptionHelper';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import CSys from '../../../math/csys';
|
||||
import CSys from '../../../../../modules/math/csys';
|
||||
import {MDatum} from '../../model/mdatum';
|
||||
|
||||
import spatialCurveOpSchema from './spatialCurveOpSchema';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import Window, {WindowControlButton} from 'ui/components/Window';
|
||||
import Stack from 'ui/components/Stack';
|
||||
import Button from 'ui/components/controls/Button';
|
||||
import ButtonGroup from 'ui/components/controls/ButtonGroup';
|
||||
|
|
@ -9,8 +8,7 @@ import CadError from '../../../../utils/errors';
|
|||
import {FormContext} from './form/Form';
|
||||
import connect from 'ui/connect';
|
||||
import {combine} from 'lstream';
|
||||
import {DocumentationTopic$} from "../../../../../../modules/doc/DocumentationWindow";
|
||||
import {IoMdHelp} from "react-icons/io";
|
||||
import {GenericWizard} from "ui/components/GenericWizard";
|
||||
|
||||
@connect((streams, props) => combine(props.context.workingRequest$, props.context.state$)
|
||||
.map(([workingRequest, state]) => ({
|
||||
|
|
@ -56,42 +54,31 @@ export default class Wizard extends React.Component {
|
|||
let Form = operation.form;
|
||||
|
||||
const error = this.props.error;
|
||||
return <Window initWidth={250}
|
||||
initLeft={left || 15}
|
||||
return <GenericWizard
|
||||
left={left}
|
||||
title={title}
|
||||
onClose={this.cancel}
|
||||
onKeyDown={this.onKeyDown}
|
||||
setFocus={this.focusFirstInput}
|
||||
className='Wizard mid-typography'
|
||||
className='Wizard'
|
||||
data-operation-id={operation.id}
|
||||
controlButtons={<>
|
||||
<WindowControlButton title='help' onClick={(e) => DocumentationTopic$.next({
|
||||
topic: operation.id,
|
||||
x: e.pageX + 40,
|
||||
y: e.pageY
|
||||
})}>
|
||||
<IoMdHelp />
|
||||
</WindowControlButton>
|
||||
</>}>
|
||||
topicId={operation.id}
|
||||
onCancel={this.cancel}
|
||||
onOK={this.onOK}
|
||||
infoText={error && <div className={ls.errorMessage}>
|
||||
{CadError.ALGORITHM_ERROR_KINDS.includes(error.kind) && <span>
|
||||
performing operation with current parameters leads to an invalid object
|
||||
(self-intersecting / zero-thickness / complete degeneration or unsupported cases)
|
||||
</span>}
|
||||
{error.code && <div className={ls.errorCode}>{error.code}</div>}
|
||||
{error.userMessage && <div className={ls.userErrorMessage}>{error.userMessage}</div>}
|
||||
{!error.userMessage && <div>internal error processing operation, check the log</div>}
|
||||
</div>}
|
||||
>
|
||||
<FormContext.Provider value={formContext}>
|
||||
<Form/>
|
||||
</FormContext.Provider>
|
||||
<Stack>
|
||||
<ButtonGroup>
|
||||
<Button className='dialog-cancel' onClick={this.cancel}>Cancel</Button>
|
||||
<Button className='dialog-ok' type='accent' onClick={this.onOK}>OK</Button>
|
||||
</ButtonGroup>
|
||||
{error && <div className={ls.errorMessage}>
|
||||
{CadError.ALGORITMTHM_ERROR_KINDS.includes(error.kind) && <span>
|
||||
performing operation with current parameters leads to an invalid object
|
||||
(self-intersecting / zero-thickness / complete degeneration or unsupported cases)
|
||||
</span>}
|
||||
{error.code && <div className={ls.errorCode}>{error.code}</div>}
|
||||
{error.userMessage && <div className={ls.userErrorMessage}>{error.userMessage}</div>}
|
||||
{!error.userMessage && <div>internal error processing operation, check the log</div>}
|
||||
</div>}
|
||||
</Stack>
|
||||
</Window>;
|
||||
</GenericWizard>;
|
||||
}
|
||||
|
||||
onKeyDown = e => {
|
||||
|
|
|
|||
|
|
@ -181,6 +181,12 @@ function addGlobalDebugActions({viewer, cadScene, cadRegistry}) {
|
|||
AddSurfaceNormal: (surface) => {
|
||||
__DEBUG__.AddNormal(surface.pointInMiddle(), surface.normalInMiddle());
|
||||
},
|
||||
AddCSys: (csys, scale) => {
|
||||
scale = scale || 100;
|
||||
__DEBUG__.AddNormal(csys.origin, csys.x, 0xff0000, scale)
|
||||
__DEBUG__.AddNormal(csys.origin, csys.y, 0x00ff00, scale)
|
||||
__DEBUG__.AddNormal(csys.origin, csys.z, 0x0000ff, scale)
|
||||
},
|
||||
AddTessDump: (triangles, color) => {
|
||||
const vec = arr => new THREE.Vector3().fromArray(arr);
|
||||
color = color || 0xffffff;
|
||||
|
|
|
|||
377
web/app/cad/dom/components/ModellerContextualActions.tsx
Normal file
377
web/app/cad/dom/components/ModellerContextualActions.tsx
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
import React, {useContext} from 'react';
|
||||
import {AppContext} from "./AppContext";
|
||||
import {useStream} from "ui/effects";
|
||||
import {ApplicationContext} from "context";
|
||||
import {AlgNumSubSystem} from "../../../sketcher/constr/AlgNumSystem";
|
||||
import {ParallelConstraintIcon} from "../../../sketcher/icons/constraints/ConstraintIcons";
|
||||
import {DEG_RAD, makeAngle0_360} from "../../../math/math";
|
||||
import {AlgNumConstraint} from "../../../sketcher/constr/ANConstraints";
|
||||
import {Param} from "../../../sketcher/shapes/param";
|
||||
import {COS_FN, Polynomial, POW_1_FN, POW_2_FN, SIN_FN} from "../../../sketcher/constr/polynomial";
|
||||
import {Matrix3} from "math/l3space";
|
||||
import CSys from "math/csys";
|
||||
import Vector from "math/vector";
|
||||
import {Dialog} from "ui/components/Dialog";
|
||||
import {MObject} from "../../model/mobject";
|
||||
import {MBrepFace} from "../../model/mface";
|
||||
import {solveAssembly} from "../../assembly/assemblySolver";
|
||||
import {Constraints3D, createAssemblyConstraint} from "../../assembly/constraints3d";
|
||||
|
||||
export function ModellerContextualActions({}) {
|
||||
|
||||
const ctx = useContext(AppContext);
|
||||
|
||||
const faceSelection: string[] = useStream(ctx => ctx.streams.selection.face);
|
||||
|
||||
if (faceSelection.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const actions = [];
|
||||
|
||||
if (faceSelection.length === 2) {
|
||||
|
||||
actions.push(<button key='faceParallel' onClick={() => faceParallel(ctx, faceSelection)}>Face Parallel</button>);
|
||||
|
||||
}
|
||||
|
||||
return <Dialog initRight={50} title='AVAILABLE ACTIONS' onClose={() => {}}>
|
||||
{actions}
|
||||
</Dialog>;
|
||||
}
|
||||
|
||||
const XConstraints3D = {
|
||||
FaceParallel: {
|
||||
id: 'FaceParallel',
|
||||
name: 'FaceParallel',
|
||||
icon: ParallelConstraintIcon,
|
||||
|
||||
defineAssemblyScope: ([face1, face2], cb) => {
|
||||
cb(face1.assemblyNodes.normal);
|
||||
cb(face2.assemblyNodes.normal);
|
||||
},
|
||||
|
||||
defineParamsScope: (objects, cb) => {
|
||||
|
||||
const [face1W, face2W, csys1W, csys2W] = objects;
|
||||
|
||||
const n1 = face1W.normal;
|
||||
const n2 = face2W.normal;
|
||||
|
||||
|
||||
const [nx1, ny1, nz1] = n1;
|
||||
const [nx2, ny2, nz2] = n2;
|
||||
|
||||
const csysParams1 = csys1W.params;
|
||||
const [
|
||||
ox1, oy1, oz1, ix1, iy1, iz1, jx1, jy1, jz1, kx1, ky1, kz1
|
||||
] = csysParams1;
|
||||
|
||||
const csysParams2 = csys2W.params;
|
||||
const [
|
||||
ox2, oy2, oz2, ix2, iy2, iz2, jx2, jy2, jz2, kx2, ky2, kz2
|
||||
] = csysParams2;
|
||||
|
||||
[
|
||||
nx1, ny1, nz1, nx2, ny2, nz2,
|
||||
ox1, oy1, oz1, ix1, iy1, iz1, jx1, jy1, jz1, kx1, ky1, kz1,
|
||||
ox2, oy2, oz2, ix2, iy2, iz2, jx2, jy2, jz2, kx2, ky2, kz2
|
||||
].forEach(cb);
|
||||
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params, constants, [face1, face2, csys1, csys2]) => {
|
||||
|
||||
const [
|
||||
nx1, ny1, nz1, nx2, ny2, nz2,
|
||||
ox1, oy1, oz1, ix1, iy1, iz1, jx1, jy1, jz1, kx1, ky1, kz1,
|
||||
ox2, oy2, oz2, ix2, iy2, iz2, jx2, jy2, jz2, kx2, ky2, kz2
|
||||
] = params;
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(1)
|
||||
.monomial()
|
||||
.term(nx1, POW_1_FN)
|
||||
.term(nx2, POW_1_FN)
|
||||
.monomial()
|
||||
.term(ny1, POW_1_FN)
|
||||
.term(ny2, POW_1_FN)
|
||||
.monomial()
|
||||
.term(nz1, POW_1_FN)
|
||||
.term(nz2, POW_1_FN)
|
||||
);
|
||||
|
||||
rigidBodyLink3x3(
|
||||
[ix1, iy1, iz1, jx1, jy1, jz1, kx1, ky1, kz1],
|
||||
csys1.csys,
|
||||
face1.normal
|
||||
).forEach(p => polynomials.push(p));
|
||||
|
||||
rigidBodyLink3x3(
|
||||
[ix2, iy2, iz2, jx2, jy2, jz2, kx2, ky2, kz2],
|
||||
csys2.csys,
|
||||
face2.normal
|
||||
).forEach(p => polynomials.push(p));
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(nx1, POW_2_FN)
|
||||
.monomial()
|
||||
.term(ny1, POW_2_FN)
|
||||
.monomial()
|
||||
.term(nz1, POW_2_FN)
|
||||
);
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(nx2, POW_2_FN)
|
||||
.monomial()
|
||||
.term(ny2, POW_2_FN)
|
||||
.monomial()
|
||||
.term(nz2, POW_2_FN)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
function vectorParams(vec) {
|
||||
const {x, y, z} = vec;
|
||||
return [new Param(x, 'X'), new Param(y, 'Y'), new Param(z, 'Z')];
|
||||
}
|
||||
|
||||
function csysParams(csys) {
|
||||
const {x, y, z} = csys.origin;
|
||||
return [
|
||||
new Param(x, 'X'),
|
||||
new Param(y, 'Y'),
|
||||
new Param(z, 'Z'),
|
||||
new Param(csys.x.x, 'X'),
|
||||
new Param(csys.x.y, 'Y'),
|
||||
new Param(csys.x.z, 'Z'),
|
||||
new Param(csys.y.x, 'X'),
|
||||
new Param(csys.y.y, 'Y'),
|
||||
new Param(csys.y.z, 'Z'),
|
||||
new Param(csys.z.x, 'X'),
|
||||
new Param(csys.z.y, 'Y'),
|
||||
new Param(csys.z.z, 'Z')
|
||||
];
|
||||
}
|
||||
|
||||
function faceWrapper(face: MBrepFace) {
|
||||
|
||||
return {
|
||||
constraints: new Set(),
|
||||
normal: vectorParams(face.normal()),
|
||||
face,
|
||||
visitParams(cb) {
|
||||
this.normal.forEach(cb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function csysWrapper(csys: CSys) {
|
||||
|
||||
return {
|
||||
constraints: new Set(),
|
||||
params: csysParams(csys),
|
||||
csys,
|
||||
visitParams(cb) {
|
||||
this.params.forEach(cb);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
function faceParallel(ctx: ApplicationContext, faceSelection: string[]) {
|
||||
|
||||
const [face1, face2] = faceSelection.map(id => ctx.cadRegistry.find(id));
|
||||
|
||||
const constraints = [
|
||||
createAssemblyConstraint(Constraints3D.FaceParallel, [face1, face2])
|
||||
];
|
||||
|
||||
solveAssembly(constraints);
|
||||
}
|
||||
|
||||
function faceParallelLegacy(ctx: ApplicationContext, faceSelection: string[]) {
|
||||
|
||||
const [face1, face2] = faceSelection.map(id => ctx.cadRegistry.find(id));
|
||||
|
||||
const stage = {};
|
||||
const objects = [
|
||||
faceWrapper(face1),
|
||||
faceWrapper(face2),
|
||||
csysWrapper(face1.shell.csys),
|
||||
csysWrapper(face2.shell.csys),
|
||||
];
|
||||
objects.forEach(o => o.stage = stage);
|
||||
stage.objects = objects;
|
||||
const algNumConstraint = new AlgNumConstraint(XConstraints3D.FaceParallel, objects);
|
||||
|
||||
const system = new AlgNumSubSystem(() => 0.001, val => val, stage);
|
||||
// __DEBUG__.AddNormal(face1.csys.origin, new Vector().set3(objects[0].normal.map(p => p.get())))
|
||||
// __DEBUG__.AddNormal(face2.csys.origin, new Vector().set3(objects[1].normal.map(p => p.get())))
|
||||
|
||||
system.startTransaction();
|
||||
system.addConstraint(algNumConstraint);
|
||||
system.prepare();
|
||||
system.solveFine();
|
||||
system.finishTransaction();
|
||||
|
||||
__DEBUG__.AddNormal(face1.csys.origin, new Vector().set3(objects[0].normal.map(p => p.get())))
|
||||
__DEBUG__.AddNormal(face2.csys.origin, new Vector().set3(objects[1].normal.map(p => p.get())))
|
||||
|
||||
|
||||
|
||||
function applyResults(shell, targetCsysParams, normal) {
|
||||
const [
|
||||
ox, oy, oz, ix, iy, iz, jx, jy, jz, kx, ky, kz
|
||||
] = targetCsysParams.map(p => p.get());
|
||||
|
||||
const targetCsys = new CSys(
|
||||
new Vector(ox, oy, oz),
|
||||
new Vector(ix, iy, iz),
|
||||
new Vector(jx, jy, jz),
|
||||
new Vector(kx, ky, kz),
|
||||
);
|
||||
|
||||
const basis = [
|
||||
new Vector(ix, iy, iz),
|
||||
new Vector(jx, jy, jz),
|
||||
new Vector(kx, ky, kz),
|
||||
];
|
||||
|
||||
// __DEBUG__.AddCSys(shell.csys);
|
||||
__DEBUG__.AddCSys(targetCsys);
|
||||
|
||||
const tr = shell.csys.inTransformation3x3;
|
||||
basis.forEach(r => tr._apply(r));
|
||||
|
||||
shell.location$.update(csys => {
|
||||
return targetCsys;
|
||||
});
|
||||
// shell.location$.mutate(csys => {
|
||||
// csys.x = basis[0];
|
||||
// csys.y = basis[1];
|
||||
// csys.z = basis[2];
|
||||
// csys.origin = new Vector(ox, oy, oz)._minus(shell.csys.origin);
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
applyResults(face1.shell, objects[2].params, new Vector().set3(objects[0].normal.map(p => p.get())));
|
||||
applyResults(face2.shell, objects[3].params, new Vector().set3(objects[1].normal.map(p => p.get())));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function rigidBodyLink3x3(csysParams, csys, vector) {
|
||||
const [ix, iy, iz, jx, jy, jz, kx, ky, kz] = csysParams;
|
||||
const [x, y, z] = vector;
|
||||
|
||||
// const [nStarX, nStarY, nStarZ] = csys.inTransformation3x3.apply3(vector.map(p => p.get()));
|
||||
const [nStarX, nStarY, nStarZ] = vector.map(p => p.get());
|
||||
// out.x = this.mxx * x + this.mxy * y + this.mxz * z + this.tx;
|
||||
// out.y = this.myx * x + this.myy * y + this.myz * z + this.ty;
|
||||
// out.z = this.mzx * x + this.mzy * y + this.mzz * z + this.tz;
|
||||
|
||||
return [
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(x, POW_1_FN)
|
||||
.monomial(nStarX)
|
||||
.term(ix, POW_1_FN)
|
||||
.monomial(nStarY)
|
||||
.term(jx, POW_1_FN)
|
||||
.monomial(nStarZ)
|
||||
.term(kx, POW_1_FN),
|
||||
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(y, POW_1_FN)
|
||||
.monomial(nStarX)
|
||||
.term(iy, POW_1_FN)
|
||||
.monomial(nStarY)
|
||||
.term(jy, POW_1_FN)
|
||||
.monomial(nStarZ)
|
||||
.term(ky, POW_1_FN),
|
||||
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(z, POW_1_FN)
|
||||
.monomial(nStarX)
|
||||
.term(iz, POW_1_FN)
|
||||
.monomial(nStarY)
|
||||
.term(jz, POW_1_FN)
|
||||
.monomial(nStarZ)
|
||||
.term(kz, POW_1_FN),
|
||||
|
||||
|
||||
new Polynomial(0)
|
||||
.monomial()
|
||||
.term(ix, POW_1_FN)
|
||||
.term(jx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iy, POW_1_FN)
|
||||
.term(jy, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iz, POW_1_FN)
|
||||
.term(jz, POW_1_FN),
|
||||
|
||||
new Polynomial(0)
|
||||
.monomial()
|
||||
.term(ix, POW_1_FN)
|
||||
.term(kx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iy, POW_1_FN)
|
||||
.term(ky, POW_1_FN)
|
||||
.monomial()
|
||||
.term(iz, POW_1_FN)
|
||||
.term(kz, POW_1_FN),
|
||||
|
||||
new Polynomial(0)
|
||||
.monomial()
|
||||
.term(jx, POW_1_FN)
|
||||
.term(kx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(jy, POW_1_FN)
|
||||
.term(ky, POW_1_FN)
|
||||
.monomial()
|
||||
.term(jz, POW_1_FN)
|
||||
.term(kz, POW_1_FN),
|
||||
|
||||
new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(ix, POW_2_FN)
|
||||
.monomial()
|
||||
.term(iy, POW_2_FN)
|
||||
.monomial()
|
||||
.term(iz, POW_2_FN),
|
||||
|
||||
new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(jx, POW_2_FN)
|
||||
.monomial()
|
||||
.term(jy, POW_2_FN)
|
||||
.monomial()
|
||||
.term(jz, POW_2_FN),
|
||||
|
||||
new Polynomial(-1)
|
||||
.monomial()
|
||||
.term(kx, POW_2_FN)
|
||||
.monomial()
|
||||
.term(ky, POW_2_FN)
|
||||
.monomial()
|
||||
.term(kz, POW_2_FN),
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import connect from 'ui/connect';
|
|||
import Fa from 'ui/components/Fa';
|
||||
import {toIdAndOverrides} from '../../actions/actionRef';
|
||||
import {isMenuAction} from '../menu/menuPlugin';
|
||||
import {combine} from 'lstream';
|
||||
import {menuAboveElementHint} from '../menu/menuUtils';
|
||||
import {useStream} from "../../../../../modules/ui/effects";
|
||||
import {ActionButtonBehavior} from "../../actions/ActionButtonBehavior";
|
||||
|
|
@ -44,11 +43,13 @@ const RightGroup = connect(streams => streams.ui.controlBars.right.map(actions =
|
|||
function ConnectedActionButton(props) {
|
||||
|
||||
const actionId = props.actionId;
|
||||
const stream = useStream(ctx => combine(ctx.streams.action.appearance[actionId], ctx.streams.action.state[actionId]));
|
||||
if (!stream) {
|
||||
|
||||
const actionAppearance = useStream(ctx => ctx.streams.action.appearance[actionId]);
|
||||
const actionState = useStream(ctx => ctx.streams.action.state[actionId]);
|
||||
|
||||
if (!actionAppearance || !actionState) {
|
||||
return null;
|
||||
}
|
||||
const [actionAppearance, actionState] = stream;
|
||||
|
||||
return <ActionButtonBehavior actionId={actionId}>
|
||||
{behaviourProps => <ActionButton {...behaviourProps} {...actionAppearance} {...actionState} {...props} />}
|
||||
|
|
|
|||
|
|
@ -67,11 +67,11 @@ function ActionButton({label, icon, icon96, icon32, cssIcons, symbol, size, noLa
|
|||
export function ConnectedActionButton(props) {
|
||||
|
||||
const actionId = props.actionId;
|
||||
const stream = useStream(ctx => combine(ctx.streams.action.appearance[actionId], ctx.streams.action.state[actionId]));
|
||||
if (!stream) {
|
||||
const actionAppearance = useStream(ctx => ctx.streams.action.appearance[actionId]);
|
||||
const actionState = useStream(ctx => ctx.streams.action.state[actionId]);
|
||||
if (!actionAppearance || !actionState) {
|
||||
return null;
|
||||
}
|
||||
const [actionAppearance, actionState] = stream;
|
||||
|
||||
return<ActionButtonBehavior actionId={actionId}>
|
||||
{behaviourProps => <ActionButton {...behaviourProps} {...actionAppearance} {...actionState} {...props} />}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ export default function UISystem({children, ...props}) {
|
|||
<MenuHolder/>
|
||||
<ActionInfo/>
|
||||
{children}
|
||||
<ContributedComponents/>
|
||||
<Scope><DocumentationWindow/></Scope>
|
||||
</div>
|
||||
</UISystemContext.Provider>;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import {ConstraintEditor} from "../../../sketcher/components/ConstraintEditor";
|
|||
import SketcherOperationWizard from "../../../sketcher/components/SketcherOperationWizard";
|
||||
import {ToastContainer} from "react-toastify";
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
import {ContributedComponents} from "./ContributedComponents";
|
||||
import {ModellerContextualActions} from "./ModellerContextualActions";
|
||||
|
||||
export default class View3d extends React.Component {
|
||||
|
||||
|
|
@ -56,6 +58,8 @@ export default class View3d extends React.Component {
|
|||
<div className={ls.wizardArea} >
|
||||
<WizardManager/>
|
||||
</div>
|
||||
<ContributedComponents/>
|
||||
<Scope><ModellerContextualActions /></Scope>
|
||||
</div>
|
||||
|
||||
<div className={ls.bottomStack}>
|
||||
|
|
|
|||
|
|
@ -57,11 +57,14 @@ const ConnectedActionMenu = connect((streams, props) =>
|
|||
export function ConnectedMenuItem(props) {
|
||||
|
||||
const actionId = props.actionId;
|
||||
const stream = useStream(ctx => combine(ctx.streams.action.appearance[actionId], ctx.streams.action.state[actionId]));
|
||||
if (!stream) {
|
||||
|
||||
const actionAppearance = useStream(ctx => ctx.streams.action.appearance[actionId]);
|
||||
const actionState = useStream(ctx => ctx.streams.action.state[actionId]);
|
||||
|
||||
|
||||
if (!actionAppearance || !actionState) {
|
||||
return null;
|
||||
}
|
||||
const [actionAppearance, actionState] = stream;
|
||||
|
||||
return <ActionButtonBehavior actionId={actionId}>
|
||||
{behaviourProps => <ActionMenuItem {...behaviourProps} {...actionAppearance} {...actionState} {...props} />}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import * as UIConfigPlugin from "../part/uiConfigPlugin";
|
|||
import * as DebugPlugin from "../debugPlugin";
|
||||
import * as ExpressionsPlugin from "../expressions/expressionsPlugin";
|
||||
import * as PartOperationsPlugin from "../part/partOperationsPlugin";
|
||||
|
||||
import * as LocationPlugin from "../location/locationPlugin";
|
||||
|
||||
export default function startApplication(callback) {
|
||||
|
||||
|
|
@ -75,6 +75,7 @@ export default function startApplication(callback) {
|
|||
UIConfigPlugin,
|
||||
DebugPlugin,
|
||||
PartOperationsPlugin,
|
||||
LocationPlugin,
|
||||
RemotePartsPlugin,
|
||||
ViewSyncPlugin,
|
||||
WizardSelectionPlugin
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {Matrix3} from '../../../math/l3space'
|
||||
import {Matrix3} from '../../../../../modules/math/l3space'
|
||||
import Vector from 'math/vector';
|
||||
import * as math from '../../../math/math'
|
||||
import {createShared} from '../../cad-utils'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {AXIS, IDENTITY_BASIS} from '../../../../math/l3space'
|
||||
import {AXIS, IDENTITY_BASIS} from '../../../../../../modules/math/l3space'
|
||||
import * as tk from '../../../../ui/toolkit.js'
|
||||
import {FACE_COLOR} from '../../../cad-utils'
|
||||
import {Wizard} from './wizard-commons'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as tk from '../../../../ui/toolkit.js'
|
|||
import * as workbench from '../workbench'
|
||||
import * as cad_utils from '../../../cad-utils'
|
||||
import Vector from 'math/vector';
|
||||
import {Matrix3, ORIGIN} from '../../../../math/l3space'
|
||||
import {Matrix3, ORIGIN} from '../../../../../../modules/math/l3space'
|
||||
import {OpWizard, IMAGINE_MATERIAL, BASE_MATERIAL} from './wizard-commons'
|
||||
|
||||
export function ExtrudeWizard(app, face, invert, initParams) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import {AXIS, IDENTITY_BASIS} from '../../../../math/l3space'
|
||||
import {AXIS, IDENTITY_BASIS} from '../../../../../../modules/math/l3space'
|
||||
import * as tk from '../../../../ui/toolkit.js'
|
||||
import {FACE_COLOR} from '../../../cad-utils'
|
||||
import {Wizard} from './wizard-commons'
|
||||
import {Matrix3} from '../../../../math/l3space'
|
||||
import {Matrix3} from '../../../../../../modules/math/l3space'
|
||||
|
||||
export function PlaneWizard(app, initParams) {
|
||||
Wizard.call(this, app.viewer, initParams);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as tk from '../../../../ui/toolkit.js'
|
|||
import * as workbench from '../workbench'
|
||||
import * as cad_utils from '../../../cad-utils'
|
||||
import Vector from 'math/vector';
|
||||
import {Matrix3, ORIGIN} from '../../../../math/l3space'
|
||||
import {Matrix3, ORIGIN} from '../../../../../../modules/math/l3space'
|
||||
import {revolveToTriangles} from '../revolve'
|
||||
import {OpWizard, IMAGINARY_SURFACE_MATERIAL, } from './wizard-commons'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {AXIS, IDENTITY_BASIS} from '../../../../math/l3space'
|
||||
import {AXIS, IDENTITY_BASIS} from '../../../../../../modules/math/l3space'
|
||||
import * as tk from '../../../../ui/toolkit.js'
|
||||
import {FACE_COLOR} from '../../../cad-utils'
|
||||
import {Wizard} from './wizard-commons'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {AXIS, IDENTITY_BASIS} from '../../../../math/l3space'
|
||||
import {AXIS, IDENTITY_BASIS} from '../../../../../../modules/math/l3space'
|
||||
import * as tk from '../../../../ui/toolkit.js'
|
||||
import {FACE_COLOR} from '../../../cad-utils'
|
||||
import {Wizard} from './wizard-commons'
|
||||
|
|
|
|||
116
web/app/cad/location/LocationDialog.tsx
Normal file
116
web/app/cad/location/LocationDialog.tsx
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import React, {useCallback, useContext} from 'react';
|
||||
import {useStreamWithUpdater} from "ui/effects";
|
||||
import {AppContext} from "../dom/components/AppContext";
|
||||
import {GenericWizard} from "ui/components/GenericWizard";
|
||||
import Field from "ui/components/controls/Field";
|
||||
import {Group} from "../craft/wizard/components/form/Form";
|
||||
import Label from "ui/components/controls/Label";
|
||||
import Folder from "ui/components/Folder";
|
||||
import {never} from "lstream";
|
||||
import NumberControl from "ui/components/controls/NumberControl";
|
||||
import {Location} from "../model/location";
|
||||
import {DEG_RAD} from "../../math/math";
|
||||
import CSys from "math/csys";
|
||||
|
||||
export function LocationDialog() {
|
||||
|
||||
const [req, setReq] = useStreamWithUpdater(ctx => ctx.locationService.editLocationRequest$);
|
||||
|
||||
|
||||
const [location, setLocation] = useStreamWithUpdater(() => req ? req.shell.location$ : never<CSys>());
|
||||
|
||||
const setX = useCallback(x => {
|
||||
location.origin.x = parseFloat(x);
|
||||
setLocation(location);
|
||||
}, [setLocation]);
|
||||
|
||||
const setY = useCallback(y => {
|
||||
location.origin.y = parseFloat(y);
|
||||
setLocation(location);
|
||||
}, [setLocation]);
|
||||
|
||||
const setZ = useCallback(z => {
|
||||
location.origin.z = parseFloat(z);
|
||||
setLocation(location);
|
||||
}, [setLocation]);
|
||||
//
|
||||
// const setAzimuth = useCallback(angle => {
|
||||
// location.rotationAxisAzimuth = parseFloat(angle) * DEG_RAD;
|
||||
// setLocation(location);
|
||||
// }, [setLocation]);
|
||||
//
|
||||
// const setInclination = useCallback(angle => {
|
||||
// location.rotationAxisInclination = parseFloat(angle) * DEG_RAD;
|
||||
// setLocation(location);
|
||||
// }, [setLocation]);
|
||||
//
|
||||
// const setAngle = useCallback(angle => {
|
||||
// location.rotationAxisAngle = parseFloat(angle) * DEG_RAD;
|
||||
// setLocation(location);
|
||||
// }, [setLocation]);
|
||||
|
||||
const ctx = useContext(AppContext);
|
||||
|
||||
if (!req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const revert = () => {
|
||||
// close();
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
setReq(null);
|
||||
};
|
||||
|
||||
const revertAndClose = () => {
|
||||
close();
|
||||
};
|
||||
|
||||
return <GenericWizard
|
||||
left={15}
|
||||
title='PART LOCATION'
|
||||
onClose={close}
|
||||
className='location-dialog'
|
||||
topicId='entity-location'
|
||||
infoText={null}
|
||||
onCancel={revertAndClose}
|
||||
onOK={close} >
|
||||
|
||||
<Folder title='Position'>
|
||||
<Group>
|
||||
<Field active={false} name='X'>
|
||||
<Label>X:</Label>
|
||||
<NumberControl onChange={setX} value={location.origin.x} />
|
||||
</Field>
|
||||
<Field active={false} name='Y'>
|
||||
<Label>Y:</Label>
|
||||
<NumberControl onChange={setY} value={location.origin.y} />
|
||||
</Field>
|
||||
<Field active={false} name='Z'>
|
||||
<Label>Z:</Label>
|
||||
<NumberControl onChange={setZ} value={location.origin.z} />
|
||||
</Field>
|
||||
</Group>
|
||||
</Folder>
|
||||
<Folder title='Rotation'>
|
||||
<Group>
|
||||
{/*<Field active={false} name='Azimuth'>*/}
|
||||
{/* <Label>Axis Azimuth:</Label>*/}
|
||||
{/* <NumberControl onChange={setAzimuth} value={location.rotationAxisAzimuth / DEG_RAD} />*/}
|
||||
{/*</Field>*/}
|
||||
{/*<Field active={false} name='Inclination'>*/}
|
||||
{/* <Label>Axis Inclination:</Label>*/}
|
||||
{/* <NumberControl onChange={setInclination} value={location.rotationAxisInclination / DEG_RAD} />*/}
|
||||
{/*</Field>*/}
|
||||
{/*<Field active={false} name='Angle'>*/}
|
||||
{/* <Label>Angle:</Label>*/}
|
||||
{/* <NumberControl onChange={setAngle} value={location.rotationAxisAngle / DEG_RAD} />*/}
|
||||
{/*</Field>*/}
|
||||
</Group>
|
||||
</Folder>
|
||||
|
||||
|
||||
</GenericWizard>
|
||||
|
||||
}
|
||||
44
web/app/cad/location/LocationPlugin.ts
Normal file
44
web/app/cad/location/LocationPlugin.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import {state, StateStream} from "lstream";
|
||||
import {ApplicationContext} from "context";
|
||||
import {MShell} from "../model/mshell";
|
||||
import {LocationDialog} from "./LocationDialog";
|
||||
|
||||
export function activate(ctx: ApplicationContext) {
|
||||
|
||||
ctx.domService.contributeComponent(LocationDialog);
|
||||
|
||||
const editLocationRequest$ = state(null);
|
||||
|
||||
ctx.locationService = {
|
||||
editLocationRequest$,
|
||||
|
||||
edit: shell => {
|
||||
editLocationRequest$.next({
|
||||
shell
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface EditLocationRequest {
|
||||
|
||||
shell: MShell;
|
||||
|
||||
}
|
||||
|
||||
export interface LocationService {
|
||||
|
||||
editLocationRequest$: StateStream<EditLocationRequest>;
|
||||
|
||||
edit(shell);
|
||||
|
||||
}
|
||||
|
||||
declare module 'context' {
|
||||
interface ApplicationContext {
|
||||
|
||||
locationService: LocationService;
|
||||
}
|
||||
}
|
||||
|
||||
24
web/app/cad/model/location.ts
Normal file
24
web/app/cad/model/location.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import Vector from "math/vector";
|
||||
import {Matrix3} from "math/l3space";
|
||||
|
||||
export class Location {
|
||||
|
||||
rotationAxisAzimuth: number = 0;
|
||||
rotationAxisInclination: number = 0;
|
||||
rotationAxisAngle: number = 0;
|
||||
|
||||
translation: Vector = new Vector();
|
||||
|
||||
__mx = new Matrix3();
|
||||
|
||||
toTransformationMatrix() {
|
||||
this.__mx.rotateWithSphericalAxis(
|
||||
this.rotationAxisAzimuth,
|
||||
this.rotationAxisInclination,
|
||||
this.rotationAxisAngle,
|
||||
this.translation
|
||||
);
|
||||
return this.__mx;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import {MObject, MObjectIdGenerator} from './mobject';
|
||||
import CSys from "../../math/csys";
|
||||
import CSys from "math/csys";
|
||||
import Vector from "math/vector";
|
||||
|
||||
export class MDatum extends MObject {
|
||||
|
|
@ -13,9 +13,9 @@ export class MDatum extends MObject {
|
|||
constructor(csys) {
|
||||
super(MDatum.TYPE, MObjectIdGenerator.next(MDatum.TYPE, 'D'));
|
||||
this.csys = csys;
|
||||
this.xAxis = new MDatumAxis(this.id + '/X', this.csys.origin, this.csys.x);
|
||||
this.yAxis = new MDatumAxis(this.id + '/Y', this.csys.origin, this.csys.y);
|
||||
this.zAxis = new MDatumAxis(this.id + '/Z', this.csys.origin, this.csys.z);
|
||||
this.xAxis = new MDatumAxis(this.id + '/X', this.csys.origin, this.csys.x, this);
|
||||
this.yAxis = new MDatumAxis(this.id + '/Y', this.csys.origin, this.csys.y, this);
|
||||
this.zAxis = new MDatumAxis(this.id + '/Z', this.csys.origin, this.csys.z, this);
|
||||
}
|
||||
|
||||
getAxisByLiteral(literal) {
|
||||
|
|
@ -33,6 +33,10 @@ export class MDatum extends MObject {
|
|||
this.yAxis.traverse(callback);
|
||||
this.zAxis.traverse(callback);
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class MDatumAxis extends MObject {
|
||||
|
|
@ -40,10 +44,16 @@ export class MDatumAxis extends MObject {
|
|||
static TYPE = 'datumAxis';
|
||||
origin: Vector;
|
||||
dir: Vector;
|
||||
holder: MObject;
|
||||
|
||||
constructor(id, origin, dir) {
|
||||
constructor(id, origin, dir, holder) {
|
||||
super(MDatumAxis.TYPE, id);
|
||||
this.origin = origin;
|
||||
this.dir = dir;
|
||||
this.holder = holder;
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return this.holder;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import {MObject} from './mobject';
|
||||
import {MBrepShell, MShell} from "./mshell";
|
||||
import {MBrepShell} from "./mshell";
|
||||
|
||||
export class MEdge extends MObject {
|
||||
|
||||
|
|
@ -25,4 +25,8 @@ export class MEdge extends MObject {
|
|||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return this.shell;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
import {MObject} from './mobject';
|
||||
import Vector from 'math/vector';
|
||||
import {BasisForPlane} from '../../math/l3space';
|
||||
import {BasisForPlane} from 'math/l3space';
|
||||
import {MSketchObject} from './msketchObject';
|
||||
import {EMPTY_ARRAY} from 'gems/iterables';
|
||||
import CSys from '../../math/csys';
|
||||
import CSys from 'math/csys';
|
||||
import {MSketchLoop} from './mloop';
|
||||
import {ProductionInfo} from './productionInfo';
|
||||
import {MBrepShell, MShell} from "./mshell";
|
||||
import {AssemblyUnitVectorNode} from "../assembly/assembly";
|
||||
|
||||
export class MFace extends MObject {
|
||||
|
||||
|
|
@ -18,6 +19,10 @@ export class MFace extends MObject {
|
|||
sketch: any;
|
||||
brepFace: any;
|
||||
|
||||
assemblyNodes: {
|
||||
normal: AssemblyUnitVectorNode
|
||||
};
|
||||
|
||||
private _csys: any;
|
||||
private w: number;
|
||||
private _basis: [Vector, Vector, Vector];
|
||||
|
|
@ -31,7 +36,10 @@ export class MFace extends MObject {
|
|||
this.surface = surface;
|
||||
this.sketchObjects = [];
|
||||
this.sketchLoops = [];
|
||||
this._csys = csys
|
||||
this._csys = csys;
|
||||
this.assemblyNodes = {
|
||||
normal: new AssemblyUnitVectorNode(this, () => this.normal())
|
||||
};
|
||||
}
|
||||
|
||||
normal() {
|
||||
|
|
@ -166,6 +174,10 @@ export class MFace extends MObject {
|
|||
this.sketchLoops.forEach(i => i.traverse(callback));
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return this.shell;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class MBrepFace extends MFace {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ export class MLoop extends MObject {
|
|||
super(MLoop.TYPE, id);
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class MSketchLoop extends MLoop {
|
||||
|
|
@ -24,5 +27,9 @@ export class MSketchLoop extends MLoop {
|
|||
this.contour = contour;
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return this.face;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
export abstract class MObject {
|
||||
|
||||
TYPE: string;
|
||||
|
||||
id: string;
|
||||
ext: any = {};
|
||||
|
||||
|
||||
constructor(TYPE, id) {
|
||||
this.TYPE = TYPE;
|
||||
this.id = id;
|
||||
|
|
@ -14,6 +13,16 @@ export abstract class MObject {
|
|||
traverse(callback: (obj: MObject) => void): void {
|
||||
callback(this);
|
||||
}
|
||||
|
||||
abstract get parent();
|
||||
|
||||
get root(): MObject {
|
||||
let obj = this;
|
||||
while (obj.parent) {
|
||||
obj = obj.parent;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
export const MObjectIdGenerator = {
|
||||
|
|
@ -50,3 +59,4 @@ export const MObjectIdGenerator = {
|
|||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,5 +16,8 @@ export class MOpenFaceShell extends MShell {
|
|||
get face() {
|
||||
return this.faces[0];
|
||||
}
|
||||
|
||||
|
||||
get parent() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import {MObject, MObjectIdGenerator} from './mobject';
|
||||
import {MBrepFace, MFace} from './mface';
|
||||
import {MBrepFace} from './mface';
|
||||
import {MEdge} from './medge';
|
||||
import {MVertex} from './mvertex';
|
||||
import CSys from '../../math/csys';
|
||||
import CSys from 'math/csys';
|
||||
import {Matrix3} from "math/l3space";
|
||||
import {state, StateStream} from "lstream";
|
||||
import {AssemblyCSysNode} from "../assembly/assembly";
|
||||
|
||||
export class MShell extends MObject {
|
||||
|
||||
|
|
@ -15,8 +18,20 @@ export class MShell extends MObject {
|
|||
edges = [];
|
||||
vertices = [];
|
||||
|
||||
location$: StateStream<CSys> = state(CSys.origin());
|
||||
locationMatrix$ = this.location$.map((csys: CSys) => csys.outTransformation).remember();
|
||||
|
||||
assemblyNodes: {
|
||||
location: AssemblyCSysNode
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super(MShell.TYPE, MObjectIdGenerator.next(MShell.TYPE, 'S'))
|
||||
super(MShell.TYPE, MObjectIdGenerator.next(MShell.TYPE, 'S'));
|
||||
// @ts-ignore
|
||||
this.assemblyNodes = {
|
||||
location: new AssemblyCSysNode( this, () => new Matrix3() )
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
traverse(callback: (obj: MObject) => void): void {
|
||||
|
|
@ -25,6 +40,10 @@ export class MShell extends MObject {
|
|||
this.edges.forEach(i => i.traverse(callback));
|
||||
this.vertices.forEach(i => i.traverse(callback));
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class MBrepShell extends MShell {
|
||||
|
|
|
|||
|
|
@ -15,4 +15,8 @@ export class MSketchObject extends MObject {
|
|||
this.construction = false;
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return this.face;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,4 +13,8 @@ export class MVertex extends MObject {
|
|||
this.brepVertex = brepVertex;
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return this.shell;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import {SelectionView} from "../dom/components/SelectionView";
|
|||
import {GrSelect} from "react-icons/gr";
|
||||
|
||||
export const STANDARD_MODE_HEADS_UP_TOOLBAR = ['DATUM_CREATE', 'PLANE', 'EditFace', 'EXTRUDE', 'CUT', 'REVOLVE', 'LOFT',
|
||||
'-', 'FILLET', '-', 'INTERSECTION', 'SUBTRACT', 'UNION', '-', 'IMPORT_PART'];
|
||||
'-', 'FILLET', '-', 'INTERSECTION', 'SUBTRACT', 'UNION', '-', 'IMPORT_PART', "IMPORT_STEP_FILE"];
|
||||
|
||||
export function activate({services, streams}) {
|
||||
streams.ui.controlBars.left.value = ['menu.file', 'menu.craft', 'menu.boolean', 'menu.primitives', 'menu.views', 'Donate', 'GitHub'];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {AXIS, Matrix3, ORIGIN} from '../math/l3space'
|
||||
import {AXIS, Matrix3, ORIGIN} from '../../../modules/math/l3space'
|
||||
import * as vec from 'math/vec'
|
||||
import Vector from 'math/vector';
|
||||
import BrepBuilder from '../brep/brep-builder'
|
||||
|
|
@ -9,7 +9,7 @@ import {surfaceIntersect} from '../brep/geom/intersection/surfaceSurface';
|
|||
import {closestToCurveParam} from '../brep/geom/curves/closestPoint';
|
||||
import NurbsSurface from '../brep/geom/surfaces/nurbsSurface';
|
||||
import DatumObject3D from './craft/datum/datumObject';
|
||||
import CSys from '../math/csys';
|
||||
import CSys from '../../../modules/math/csys';
|
||||
import {createOctreeFromSurface, sphereOctree, traverseOctree} from "../../../modules/voxels/octree";
|
||||
|
||||
export function runSandbox({bus, services, services: { viewer, cadScene, cadRegistry, exposure, exposure: {addShellOnScene} }}) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {AXIS} from '../../math/l3space'
|
||||
import {AXIS} from '../../../../modules/math/l3space'
|
||||
import {createArrow} from 'scene/objects/auxiliary';
|
||||
import Vector from 'math/vector';
|
||||
import {OnTopOfAll} from 'scene/materialMixins';
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ export function activate(context) {
|
|||
|
||||
domElement.addEventListener('mousedown', mousedown, false);
|
||||
domElement.addEventListener('mouseup', mouseup, false);
|
||||
domElement.addEventListener('dblclick', mousedblclick, false);
|
||||
|
||||
let mouseState = {
|
||||
startX: 0,
|
||||
|
|
@ -93,6 +94,10 @@ export function activate(context) {
|
|||
}
|
||||
}
|
||||
|
||||
function mousedblclick(e) {
|
||||
handleSolidPick(e);
|
||||
}
|
||||
|
||||
function setPickHandler(handler) {
|
||||
pickHandler = handler || defaultHandler;
|
||||
services.marker.clear();
|
||||
|
|
@ -136,8 +141,7 @@ export function activate(context) {
|
|||
function handleSolidPick(e) {
|
||||
let pickResults = services.viewer.raycast(e, services.cadScene.workGroup.children);
|
||||
traversePickResults(e, pickResults, PICK_KIND.FACE, (sketchFace) => {
|
||||
streams.selection.solid.next([sketchFace.solid]);
|
||||
services.viewer.render();
|
||||
context.locationService.edit(sketchFace.shell);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ function sceneSynchronizer({services: {cadScene, cadRegistry, viewer, wizard, ac
|
|||
if (model instanceof MOpenFaceShell) {
|
||||
modelView = new OpenFaceShellView(model);
|
||||
} else if (model instanceof MShell) {
|
||||
modelView = new ShellView(model);
|
||||
modelView = new ShellView(model, undefined, viewer);
|
||||
} else if (model instanceof MDatum) {
|
||||
modelView = new DatumView(model, viewer,
|
||||
wizard.open,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {Mesh} from 'three';
|
|||
|
||||
export class ShellView extends View {
|
||||
|
||||
constructor(shell, skin) {
|
||||
constructor(shell, skin, viewer) {
|
||||
super(shell);
|
||||
|
||||
this.material = createSolidMaterial(skin);
|
||||
|
|
@ -45,6 +45,15 @@ export class ShellView extends View {
|
|||
SceneGraph.addToGroup(this.edgeGroup, edgeView.rootGroup);
|
||||
this.edgeViews.push(edgeView);
|
||||
}
|
||||
|
||||
this.rootGroup.matrixAutoUpdate = false;
|
||||
|
||||
this.model.locationMatrix$.attach(loc => {
|
||||
loc.setToMatrix(this.rootGroup.matrix);
|
||||
this.rootGroup.matrixWorldNeedsUpdate = true;
|
||||
viewer.requestRender();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
mark(color) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {readBrep} from '../../../brep/io/brepIO';
|
||||
import {MBrepShell} from '../../model/mshell';
|
||||
import CSys from '../../../math/csys';
|
||||
import CSys from '../../../../../modules/math/csys';
|
||||
|
||||
export function readShellEntityFromJson(data, consumed, csys) {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Vector from 'math/vector';
|
||||
import {BasisForPlane} from '../../../math/l3space'
|
||||
import {BasisForPlane} from '../../../../../modules/math/l3space'
|
||||
import DPR from 'dpr'
|
||||
import {setAttribute} from "scene/objectData";
|
||||
import {genSolidId} from "../../craft/cadRegistryPlugin";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {DelegatingPanTool} from '../../sketcher/tools/pan';
|
||||
import {Matrix4} from 'three/src/math/Matrix4';
|
||||
import {ORIGIN} from '../../math/l3space';
|
||||
import {ORIGIN} from '../../../../modules/math/l3space';
|
||||
import {CAMERA_MODE} from '../scene/viewer';
|
||||
import DPR from 'dpr';
|
||||
import {SKETCHER_MODE_HEADS_UP_ACTIONS} from "./sketcherUIContrib";
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {LUT} from '../../math/bezier-cubic'
|
|||
import {distanceAB, isCCW, makeAngle0_360} from '../../math/math'
|
||||
import {normalizeCurveEnds} from '../../brep/geom/impl/nurbs-ext';
|
||||
import Vector from '../../../../modules/math/vector';
|
||||
import {AXIS, ORIGIN} from '../../math/l3space';
|
||||
import {AXIS, ORIGIN} from '../../../../modules/math/l3space';
|
||||
|
||||
const RESOLUTION = 20;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as sm from './sketchModel'
|
||||
import {Matrix3, AXIS, ORIGIN} from '../../math/l3space'
|
||||
import {Matrix3, AXIS, ORIGIN} from '../../../../modules/math/l3space'
|
||||
import Vector from 'math/vector';
|
||||
import {Graph} from '../../math/graph'
|
||||
import * as math from '../../math/math'
|
||||
|
|
|
|||
|
|
@ -1,277 +0,0 @@
|
|||
import Vector from 'math/vector';
|
||||
|
||||
const freeze = Object.freeze;
|
||||
|
||||
const ORIGIN = freeze(new Vector(0, 0, 0));
|
||||
|
||||
const AXIS = freeze({
|
||||
X : freeze(new Vector(1, 0, 0)),
|
||||
Y : freeze(new Vector(0, 1, 0)),
|
||||
Z : freeze(new Vector(0, 0, 1))
|
||||
});
|
||||
|
||||
const IDENTITY_BASIS = Object.freeze([AXIS.X, AXIS.Y, AXIS.Z]);
|
||||
|
||||
export const STANDARD_BASES = freeze({
|
||||
'XY': IDENTITY_BASIS,
|
||||
'XZ': [AXIS.X, AXIS.Z, AXIS.Y],
|
||||
'ZY': [AXIS.Z, AXIS.Y, AXIS.X]
|
||||
});
|
||||
|
||||
|
||||
class Matrix3 {
|
||||
constructor() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
apply = vector => this.__apply(vector, new Vector());
|
||||
}
|
||||
|
||||
Matrix3.prototype.reset = function() {
|
||||
this.mxx = 1; this.mxy = 0; this.mxz = 0; this.tx = 0;
|
||||
this.myx = 0; this.myy = 1; this.myz = 0; this.ty = 0;
|
||||
this.mzx = 0; this.mzy = 0; this.mzz = 1; this.tz = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.setBasis = function(basis) {
|
||||
var b = basis;
|
||||
this.mxx = b[0].x; this.mxy = b[1].x; this.mxz = b[2].x; this.tx = 0;
|
||||
this.myx = b[0].y; this.myy = b[1].y; this.myz = b[2].y; this.ty = 0;
|
||||
this.mzx = b[0].z; this.mzy = b[1].z; this.mzz = b[2].z; this.tz = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.setBasisAxises = function(x, y, z) {
|
||||
this.mxx = x.x; this.mxy = y.x; this.mxz = z.x; this.tx = 0;
|
||||
this.myx = x.y; this.myy = y.y; this.myz = z.y; this.ty = 0;
|
||||
this.mzx = x.z; this.mzy = y.z; this.mzz = z.z; this.tz = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.scale = function(dx, dy, dz) {
|
||||
this.mxx *= dx;
|
||||
this.myy *= dy;
|
||||
this.mzz *= dz;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.translate = function(dx, dy, dz) {
|
||||
this.tx += dx;
|
||||
this.ty += dy;
|
||||
this.tz += dz;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.set3 = function(
|
||||
mxx, mxy, mxz,
|
||||
myx, myy, myz,
|
||||
mzx, mzy, mzz
|
||||
) {
|
||||
this.mxx = mxx; this.mxy = mxy; this.mxz = mxz;
|
||||
this.myx = myx; this.myy = myy; this.myz = myz;
|
||||
this.mzx = mzx; this.mzy = mzy; this.mzz = mzz;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.set34 = function(
|
||||
mxx, mxy, mxz, tx,
|
||||
myx, myy, myz, ty,
|
||||
mzx, mzy, mzz, tz
|
||||
) {
|
||||
this.mxx = mxx; this.mxy = mxy; this.mxz = mxz; this.tx = tx;
|
||||
this.myx = myx; this.myy = myy; this.myz = myz; this.ty = ty;
|
||||
this.mzx = mzx; this.mzy = mzy; this.mzz = mzz; this.tz = tz;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.setMatrix = function(m) {
|
||||
this.mxx = m.mxx; this.mxy = m.mxy; this.mxz = m.mxz; this.tx = m.tx;
|
||||
this.myx = m.myx; this.myy = m.myy; this.myz = m.myz; this.ty = m.ty;
|
||||
this.mzx = m.mzx; this.mzy = m.mzy; this.mzz = m.mzz; this.tz = m.tz;
|
||||
return this;
|
||||
};
|
||||
|
||||
Matrix3.prototype.toArray = function() {
|
||||
return [
|
||||
[this.mxx, this.mxy, this.mxz, this.tx],
|
||||
[this.myx, this.myy, this.myz, this.ty],
|
||||
[this.mzx, this.mzy, this.mzz, this.tz]
|
||||
];
|
||||
};
|
||||
|
||||
Matrix3.prototype.invert = function() {
|
||||
return this.__invert(new Matrix3());
|
||||
};
|
||||
|
||||
Matrix3.prototype._invert = function() {
|
||||
return this.__invert(this);
|
||||
};
|
||||
|
||||
Matrix3.prototype.__invert = function(out) {
|
||||
|
||||
var det =
|
||||
this.mxx * (this.myy * this.mzz - this.mzy * this.myz) +
|
||||
this.mxy * (this.myz * this.mzx - this.mzz * this.myx) +
|
||||
this.mxz * (this.myx * this.mzy - this.mzx * this.myy);
|
||||
|
||||
if (det == 0.0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var cxx = this.myy * this.mzz - this.myz * this.mzy;
|
||||
var cyx = - this.myx * this.mzz + this.myz * this.mzx;
|
||||
var czx = this.myx * this.mzy - this.myy * this.mzx;
|
||||
var cxt = - this.mxy * (this.myz * this.tz - this.mzz * this.ty)
|
||||
- this.mxz * (this.ty * this.mzy - this.tz * this.myy)
|
||||
- this.tx * (this.myy * this.mzz - this.mzy * this.myz);
|
||||
var cxy = - this.mxy * this.mzz + this.mxz * this.mzy;
|
||||
var cyy = this.mxx * this.mzz - this.mxz * this.mzx;
|
||||
var czy = - this.mxx * this.mzy + this.mxy * this.mzx;
|
||||
var cyt = this.mxx * (this.myz * this.tz - this.mzz * this.ty)
|
||||
+ this.mxz * (this.ty * this.mzx - this.tz * this.myx)
|
||||
+ this.tx * (this.myx * this.mzz - this.mzx * this.myz);
|
||||
var cxz = this.mxy * this.myz - this.mxz * this.myy;
|
||||
var cyz = - this.mxx * this.myz + this.mxz * this.myx;
|
||||
var czz = this.mxx * this.myy - this.mxy * this.myx;
|
||||
var czt = - this.mxx * (this.myy * this.tz - this.mzy * this.ty)
|
||||
- this.mxy * (this.ty * this.mzx - this.tz * this.myx)
|
||||
- this.tx * (this.myx * this.mzy - this.mzx * this.myy);
|
||||
|
||||
out.mxx = cxx / det;
|
||||
out.mxy = cxy / det;
|
||||
out.mxz = cxz / det;
|
||||
out.tx = cxt / det;
|
||||
out.myx = cyx / det;
|
||||
out.myy = cyy / det;
|
||||
out.myz = cyz / det;
|
||||
out.ty = cyt / det;
|
||||
out.mzx = czx / det;
|
||||
out.mzy = czy / det;
|
||||
out.mzz = czz / det;
|
||||
out.tz = czt / det;
|
||||
return out;
|
||||
};
|
||||
|
||||
Matrix3.prototype.combine = function(transform, out) {
|
||||
var txx = transform.mxx;
|
||||
var txy = transform.mxy;
|
||||
var txz = transform.mxz;
|
||||
var ttx = transform.tx;
|
||||
var tyx = transform.myx;
|
||||
var tyy = transform.myy;
|
||||
var tyz = transform.myz;
|
||||
var tty = transform.ty;
|
||||
var tzx = transform.mzx;
|
||||
var tzy = transform.mzy;
|
||||
var tzz = transform.mzz;
|
||||
var ttz = transform.tz;
|
||||
|
||||
var m = out || new Matrix3();
|
||||
m.mxx = (this.mxx * txx + this.mxy * tyx + this.mxz * tzx);
|
||||
m.mxy = (this.mxx * txy + this.mxy * tyy + this.mxz * tzy);
|
||||
m.mxz = (this.mxx * txz + this.mxy * tyz + this.mxz * tzz);
|
||||
m.tx = (this.mxx * ttx + this.mxy * tty + this.mxz * ttz + this.tx);
|
||||
m.myx = (this.myx * txx + this.myy * tyx + this.myz * tzx);
|
||||
m.myy = (this.myx * txy + this.myy * tyy + this.myz * tzy);
|
||||
m.myz = (this.myx * txz + this.myy * tyz + this.myz * tzz);
|
||||
m.ty = (this.myx * ttx + this.myy * tty + this.myz * ttz + this.ty);
|
||||
m.mzx = (this.mzx * txx + this.mzy * tyx + this.mzz * tzx);
|
||||
m.mzy = (this.mzx * txy + this.mzy * tyy + this.mzz * tzy);
|
||||
m.mzz = (this.mzx * txz + this.mzy * tyz + this.mzz * tzz);
|
||||
m.tz = (this.mzx * ttx + this.mzy * tty + this.mzz * ttz + this.tz);
|
||||
|
||||
return m;
|
||||
};
|
||||
|
||||
Matrix3.prototype._apply = function(vector) {
|
||||
return this.__apply(vector, vector);
|
||||
};
|
||||
|
||||
Matrix3.prototype.__apply = function(vector, out) {
|
||||
let x = vector.x;
|
||||
let y = vector.y;
|
||||
let z = vector.z;
|
||||
out.x = this.mxx * x + this.mxy * y + this.mxz * z + this.tx;
|
||||
out.y = this.myx * x + this.myy * y + this.myz * z + this.ty;
|
||||
out.z = this.mzx * x + this.mzy * y + this.mzz * z + this.tz;
|
||||
return out;
|
||||
};
|
||||
|
||||
Matrix3.prototype.apply3 = function(data) {
|
||||
return this.__apply3(data, [])
|
||||
};
|
||||
|
||||
Matrix3.prototype._apply3 = function(data) {
|
||||
return this.__apply3(data, data);
|
||||
};
|
||||
|
||||
Matrix3.prototype.__apply3 = function([x, y, z], out) {
|
||||
out[0] = this.mxx * x + this.mxy * y + this.mxz * z + this.tx;
|
||||
out[1] = this.myx * x + this.myy * y + this.myz * z + this.ty;
|
||||
out[2] = this.mzx * x + this.mzy * y + this.mzz * z + this.tz;
|
||||
return out;
|
||||
};
|
||||
|
||||
Matrix3.prototype.rotate = function(angle, axis, pivot) {
|
||||
return Matrix3.rotateMatrix(angle, axis, pivot, this);
|
||||
};
|
||||
|
||||
Matrix3.rotateMatrix = function(angle, axis, pivot, matrix) {
|
||||
var sin = Math.sin(angle);
|
||||
var cos = Math.cos(angle);
|
||||
var axisX, axisY, axisZ;
|
||||
var m = matrix || new Matrix3();
|
||||
|
||||
if (axis === AXIS.X || axis === AXIS.Y || axis === AXIS.Z) {
|
||||
axisX = axis.x;
|
||||
axisY = axis.y;
|
||||
axisZ = axis.z;
|
||||
} else {
|
||||
// normalize
|
||||
var mag = axis.length();
|
||||
|
||||
if (mag == 0.0) {
|
||||
return m;
|
||||
} else {
|
||||
axisX = axis.x / mag;
|
||||
axisY = axis.y / mag;
|
||||
axisZ = axis.z / mag;
|
||||
}
|
||||
}
|
||||
|
||||
var px = pivot.x;
|
||||
var py = pivot.y;
|
||||
var pz = pivot.z;
|
||||
|
||||
m.mxx = cos + axisX * axisX * (1 - cos);
|
||||
m.mxy = axisX * axisY * (1 - cos) - axisZ * sin;
|
||||
m.mxz = axisX * axisZ * (1 - cos) + axisY * sin;
|
||||
|
||||
m.tx = px * (1 - m.mxx) - py * m.mxy - pz * m.mxz;
|
||||
|
||||
m.myx = axisY * axisX * (1 - cos) + axisZ * sin;
|
||||
m.myy = cos + axisY * axisY * (1 - cos);
|
||||
m.myz = axisY * axisZ * (1 - cos) - axisX * sin;
|
||||
m.ty = py * (1 - m.myy) - px * m.myx - pz * m.myz;
|
||||
|
||||
m.mzx = axisZ * axisX * (1 - cos) - axisY * sin;
|
||||
m.mzy = axisZ * axisY * (1 - cos) + axisX * sin;
|
||||
m.mzz = cos + axisZ * axisZ * (1 - cos);
|
||||
m.tz = pz * (1 - m.mzz) - px * m.mzx - py * m.mzy;
|
||||
return m;
|
||||
};
|
||||
|
||||
function BasisForPlane(normal, alignY = AXIS.Y, alignZ = AXIS.Z) {
|
||||
let alignPlane, x, y;
|
||||
if (Math.abs(normal.dot(alignY)) < 0.5) {
|
||||
alignPlane = normal.cross(alignY);
|
||||
} else {
|
||||
alignPlane = normal.cross(alignZ);
|
||||
}
|
||||
y = alignPlane.cross(normal);
|
||||
x = y.cross(normal);
|
||||
return [x, y, normal];
|
||||
}
|
||||
|
||||
export {Matrix3, ORIGIN, IDENTITY_BASIS, AXIS, BasisForPlane};
|
||||
|
|
@ -9,12 +9,13 @@ import {SketcherAppContext} from "./SketcherAppContext";
|
|||
export function SketchObjectExplorer() {
|
||||
|
||||
const [modification, setModification] = useState(0);
|
||||
const stream = useStream(ctx => combine(ctx.viewer.streams.objects, ctx.viewer.streams.selection));
|
||||
const objects = useStream(ctx => ctx.viewer.streams.objects);
|
||||
const selection = useStream(ctx.viewer.streams.selection);
|
||||
const ctx = useContext(SketcherAppContext);
|
||||
if (!stream) {
|
||||
|
||||
if (!objects || !selection) {
|
||||
return null
|
||||
}
|
||||
const [objects, selection] = stream;
|
||||
|
||||
const select = (obj, exclusive) => {
|
||||
let viewer = ctx.viewer;
|
||||
|
|
|
|||
|
|
@ -33,8 +33,15 @@ import {
|
|||
LengthAnnotation,
|
||||
RadiusLengthAnnotation
|
||||
} from "../shapes/annotations/angleAnnotation";
|
||||
import {ISolveStage, SolvableObject} from "./solvableObject";
|
||||
import {SketchObject} from "../shapes/sketch-object";
|
||||
import {IconType} from "react-icons";
|
||||
|
||||
export const ConstraintDefinitions = {
|
||||
export const ConstraintDefinitions
|
||||
// : {
|
||||
// [key: string]: ConstraintSchema
|
||||
// }
|
||||
= {
|
||||
|
||||
PCoincident : {
|
||||
id: 'PCoincident',
|
||||
|
|
@ -338,8 +345,8 @@ export const ConstraintDefinitions = {
|
|||
.monomial(-1);
|
||||
|
||||
|
||||
polynomials.push(ellipsePoly());
|
||||
polynomials.push(ellipsePoly());
|
||||
// polynomials.push(ellipsePoly());
|
||||
// polynomials.push(ellipsePoly());
|
||||
},
|
||||
|
||||
},
|
||||
|
|
@ -814,12 +821,12 @@ export const ConstraintDefinitions = {
|
|||
pt.visitParams(callback);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, [px, py], {x, y}) => {
|
||||
collectPolynomials: (polynomials, [px, py], {x, y}: ResolvedConstants) => {
|
||||
polynomials.push(new Polynomial(-x).monomial().term(px, POW_1_FN));
|
||||
polynomials.push(new Polynomial(-y).monomial().term(py, POW_1_FN));
|
||||
},
|
||||
|
||||
setConstantsFromGeometry: ([pt], constants) => {
|
||||
setConstantsFromGeometry: ([pt], constants: ConstantsDefinitions) => {
|
||||
constants.x = pt.x + '';
|
||||
constants.y = pt.y + '';
|
||||
}
|
||||
|
|
@ -940,11 +947,51 @@ const bezier3Polynomial = (p, t, p0, p1, p2, p3) => new Polynomial()
|
|||
.monomial(-1)
|
||||
.term(p, POW_1_FN);
|
||||
|
||||
|
||||
export type ResolvedConstants = { [p: string]: any };
|
||||
export type ConstantsDefinitions = { [p: string]: string };
|
||||
|
||||
export interface ConstraintSchema {
|
||||
|
||||
id: string;
|
||||
name: string,
|
||||
icon: IconType,
|
||||
constants?: {
|
||||
[name: string]: {
|
||||
readOnly?: boolean;
|
||||
type: string,
|
||||
description?: string,
|
||||
transform?: (string) => any,
|
||||
initialValue(objects: SolvableObject[]): any;
|
||||
}
|
||||
};
|
||||
|
||||
createAnnotations?: (objects: SolvableObject[], constraintInstance: AlgNumConstraint) => SketchObject[];
|
||||
|
||||
defineParamsScope: (object: SolvableObject[], cb: (param: Param) => void) => void;
|
||||
|
||||
collectPolynomials(polynomials: Polynomial[], params: Param[], resolvedConstants: ResolvedConstants, objects: SolvableObject[]): void;
|
||||
|
||||
setConstantsFromGeometry?: (object: SolvableObject[], resolvedConstants: ConstantsDefinitions) => void;
|
||||
|
||||
initialGuess?(params: Param[], resolvedConstants: ResolvedConstants): void;
|
||||
}
|
||||
|
||||
export class AlgNumConstraint {
|
||||
|
||||
static Counter = 0;
|
||||
|
||||
constructor(schema, objects, constants, internal = false) {
|
||||
id: string;
|
||||
objects: SolvableObject[];
|
||||
constants: ConstantsDefinitions;
|
||||
resolvedConstants: ResolvedConstants;
|
||||
internal: boolean;
|
||||
schema: ConstraintSchema;
|
||||
params: Param[];
|
||||
stage: ISolveStage;
|
||||
private annotations: SketchObject[];
|
||||
|
||||
constructor(schema: ConstraintSchema, objects: SolvableObject[], constants?: ConstantsDefinitions, internal?: boolean = false) {
|
||||
this.id = schema.id + ':' + (AlgNumConstraint.Counter ++); // only for debug purposes - not persisted
|
||||
this.objects = objects;
|
||||
this.constants = constants;
|
||||
|
|
@ -958,18 +1005,6 @@ export class AlgNumConstraint {
|
|||
this.schema.defineParamsScope(this.objects, p => this.params.push(p));
|
||||
}
|
||||
|
||||
this.modifier = this.schema.modify !== undefined;
|
||||
if (this.modifier) {
|
||||
this.referenceObjects = this.schema.referenceObjects(this.objects);
|
||||
this.managedObjects = this.schema.managedObjects(this.objects);
|
||||
this.managedObjects.forEach(o => {
|
||||
if (o.managedBy) {
|
||||
throw 'there can be only one managing modifier for an object';
|
||||
}
|
||||
o.managedBy = this;
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.internal && this.schema.createAnnotations) {
|
||||
this.annotations = this.schema.createAnnotations(this.objects, this);
|
||||
} else {
|
||||
|
|
@ -977,8 +1012,8 @@ export class AlgNumConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
collectPolynomials(polynomials) {
|
||||
this.schema.collectPolynomials(polynomials, this.params, this.resolvedConstants);
|
||||
collectPolynomials(polynomials: Polynomial[]) {
|
||||
this.schema.collectPolynomials(polynomials, this.params, this.resolvedConstants, this.objects);
|
||||
}
|
||||
|
||||
resolveConstants(expressionResolver) {
|
||||
|
|
@ -988,7 +1023,7 @@ export class AlgNumConstraint {
|
|||
}
|
||||
Object.keys(this.constants).map(name => {
|
||||
let def = this.schema.constants[name];
|
||||
let val = this.constants[name];
|
||||
let val: any = this.constants[name];
|
||||
val = expressionResolver(val);
|
||||
if (def.type === 'number') {
|
||||
val = parseFloat(val);
|
||||
|
|
@ -1071,4 +1106,3 @@ export class AlgNumConstraint {
|
|||
this.constants[key] = value + ''; // only string are allowed here
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2,8 +2,10 @@ import {prepare} from "./solver";
|
|||
import {eqEps} from "../../brep/geom/tolerance";
|
||||
import {Polynomial, POW_1_FN} from "./polynomial";
|
||||
import {compositeFn} from "gems/func";
|
||||
import {AlgNumConstraint} from "./ANConstraints";
|
||||
import {SolverParam} from "./solverParam";
|
||||
|
||||
const DEBUG = false;
|
||||
const DEBUG = true;
|
||||
|
||||
export class AlgNumSubSystem {
|
||||
|
||||
|
|
@ -34,6 +36,18 @@ export class AlgNumSubSystem {
|
|||
|
||||
stage = null;
|
||||
|
||||
dof: number = 0;
|
||||
|
||||
requiresHardSolve: boolean = false;
|
||||
|
||||
polynomialIsolations: Isolation[];
|
||||
|
||||
calcVisualLimit: () => number;
|
||||
|
||||
expressionResolver: (string) => any;
|
||||
|
||||
solveStatus: SolveStatus;
|
||||
|
||||
constructor(calcVisualLimit, expressionResolver, stage) {
|
||||
|
||||
this.calcVisualLimit = calcVisualLimit;
|
||||
|
|
@ -182,7 +196,7 @@ export class AlgNumSubSystem {
|
|||
});
|
||||
|
||||
if (DEBUG) {
|
||||
console.log('reducing system:');
|
||||
console.log('reducing system(of', this.polynomials.length, '):');
|
||||
this.polynomials.forEach(p => console.log(p.toString()));
|
||||
}
|
||||
|
||||
|
|
@ -502,6 +516,13 @@ export class AlgNumSubSystem {
|
|||
|
||||
|
||||
class Isolation {
|
||||
polynomials: Polynomial[];
|
||||
system: AlgNumSubSystem;
|
||||
beingSolvedParams: Set<SolverParam>;
|
||||
beingSolvedConstraints: Set<AlgNumConstraint>;
|
||||
dof: number;
|
||||
solveStatus: SolveStatus;
|
||||
numericalSolver: { system; diagnose; solveSystem; error; updateLock };
|
||||
|
||||
constructor(polynomials, system) {
|
||||
this.system = system;
|
||||
|
|
@ -605,3 +626,7 @@ class PolynomialResidual {
|
|||
|
||||
}
|
||||
|
||||
interface SolveStatus {
|
||||
success: boolean;
|
||||
error: number
|
||||
}
|
||||
12
web/app/sketcher/constr/solvableObject.ts
Normal file
12
web/app/sketcher/constr/solvableObject.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import {Param} from "../shapes/param";
|
||||
|
||||
export interface SolvableObject {
|
||||
|
||||
id: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ISolveStage {
|
||||
objects: Set<SolvableObject>;
|
||||
index: number;
|
||||
}
|
||||
|
|
@ -6,28 +6,6 @@ import {ConstantWrapper, EqualsTo} from './solverConstraints'
|
|||
import {dog_leg} from '../../math/optim'
|
||||
import {newVector} from 'math/vec';
|
||||
|
||||
/** @constructor */
|
||||
function Param(value, objectParam) {
|
||||
this.reset(value);
|
||||
this.objectParam = objectParam;
|
||||
}
|
||||
|
||||
Param.prototype.reset = function(value) {
|
||||
this.set(value);
|
||||
this.constant = false;
|
||||
this.j = -1;
|
||||
};
|
||||
|
||||
Param.prototype.set = function(value) {
|
||||
if (this.constant) return;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
Param.prototype.get = function() {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
Param.prototype.nop = function() {};
|
||||
|
||||
/** @constructor */
|
||||
function System(constraints) {
|
||||
|
|
@ -313,4 +291,4 @@ var solve_lm = function(sys, model, jacobian, rough) {
|
|||
};
|
||||
};
|
||||
|
||||
export {Param, prepare}
|
||||
export {prepare}
|
||||
35
web/app/sketcher/constr/solverParam.ts
Normal file
35
web/app/sketcher/constr/solverParam.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import {Param} from "../shapes/param";
|
||||
|
||||
export class SolverParam {
|
||||
|
||||
value: number;
|
||||
objectParam: Param;
|
||||
constant: boolean;
|
||||
|
||||
/**
|
||||
* Jacobian position
|
||||
*/
|
||||
j: number;
|
||||
|
||||
constructor(value, objectParam) {
|
||||
this.reset(value);
|
||||
this.objectParam = objectParam;
|
||||
}
|
||||
|
||||
reset(value) {
|
||||
this.set(value);
|
||||
this.constant = false;
|
||||
this.j = -1;
|
||||
};
|
||||
|
||||
set(value) {
|
||||
if (this.constant) return;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -3,6 +3,8 @@ import {AlgNumConstraint, ConstraintDefinitions} from "./constr/ANConstraints";
|
|||
import {AlgNumSubSystem} from "./constr/AlgNumSystem";
|
||||
import {state, stream} from 'lstream';
|
||||
import {toast} from "react-toastify";
|
||||
import {ISolveStage, SolvableObject} from "./constr/solvableObject";
|
||||
import {Viewer} from "./viewer2d";
|
||||
|
||||
export {Constraints, ParametricManager}
|
||||
|
||||
|
|
@ -31,6 +33,8 @@ class ParametricManager {
|
|||
$constantDefinition = state('');
|
||||
|
||||
groundStage = new SolveStage(this);
|
||||
viewer: Viewer;
|
||||
messageSink: (msg) => void;
|
||||
|
||||
constructor(viewer) {
|
||||
this.viewer = viewer;
|
||||
|
|
@ -240,7 +244,7 @@ class ParametricManager {
|
|||
});
|
||||
};
|
||||
|
||||
_removeObject = (obj, force) => {
|
||||
_removeObject = (obj, force?) => {
|
||||
if (obj.__disposed) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -398,10 +402,12 @@ class ParametricManager {
|
|||
}
|
||||
}
|
||||
|
||||
class SolveStage {
|
||||
class SolveStage implements ISolveStage{
|
||||
|
||||
generators = new Set();
|
||||
objects = new Set();
|
||||
objects = new Set<SolvableObject>();
|
||||
private parametricManager: ParametricManager;
|
||||
private algNumSystem: AlgNumSubSystem;
|
||||
|
||||
constructor(parametricManager) {
|
||||
this.parametricManager = parametricManager;
|
||||
|
|
@ -460,6 +466,7 @@ class SolveStage {
|
|||
solve(rough) {
|
||||
this.algNumSystem.solve(rough);
|
||||
this.generators.forEach(gen => {
|
||||
// @ts-ignore
|
||||
gen.regenerate(this.viewer);
|
||||
})
|
||||
}
|
||||
|
|
@ -1,15 +1,18 @@
|
|||
import {Generator} from "../id-generator";
|
||||
import {Param as SolverParam} from '../constr/solver';
|
||||
import {SolverParam} from "../constr/solverParam";
|
||||
|
||||
export class Param {
|
||||
|
||||
id: number;
|
||||
value: number;
|
||||
solverParam: any;
|
||||
solverParam: SolverParam;
|
||||
private readonly debugSymbol: string;
|
||||
normalizer: (number) => any;
|
||||
enforceVisualLimit: boolean = false;
|
||||
|
||||
//penalty function constraints
|
||||
constraints?: any[];
|
||||
|
||||
constructor(value, debugSymbol) {
|
||||
this.id = Generator.genID();
|
||||
this.value = value;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import {Styles} from "../styles";
|
|||
import {NoIcon} from "../icons/NoIcon";
|
||||
import {Layer, Viewer} from "../viewer2d";
|
||||
import {NOOP} from "gems/func";
|
||||
import {SolvableObject} from "../constr/solveObject";
|
||||
|
||||
export abstract class SketchObject extends Shape {
|
||||
export abstract class SketchObject extends Shape implements SolvableObject {
|
||||
|
||||
ref: string;
|
||||
id: string;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {BasisOrigin} from './shapes/basis-origin';
|
|||
import Vector from 'math/vector';
|
||||
|
||||
import * as draw_utils from './shapes/draw-utils';
|
||||
import {Matrix3} from '../math/l3space';
|
||||
import {Matrix3} from 'math/l3space';
|
||||
import sketcherStreams, {SketcherStreams} from './sketcherStreams';
|
||||
import {BBox, IO} from "./io";
|
||||
import {NOOP} from "../../../modules/gems/func";
|
||||
|
|
@ -358,13 +358,14 @@ export class Viewer {
|
|||
};
|
||||
|
||||
fit() {
|
||||
|
||||
let count = 0;
|
||||
const bbox = new BBox();
|
||||
this.accept(obj => {
|
||||
count ++;
|
||||
bbox.check(obj);
|
||||
return true;
|
||||
});
|
||||
if (!bbox.isValid()) {
|
||||
if (count < 2 || !bbox.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,5 +22,5 @@ CadError.KIND = {
|
|||
INVALID_PARAMS: 'INVALID_PARAMS'
|
||||
};
|
||||
|
||||
CadError.ALGORITMTHM_ERROR_KINDS = ['INTERNAL_ERROR', 'UNSUPPORTED_CASE', 'INVALID_INPUT'];
|
||||
CadError.ALGORITHM_ERROR_KINDS = ['INTERNAL_ERROR', 'UNSUPPORTED_CASE', 'INVALID_INPUT'];
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue