assembly infrastructure

This commit is contained in:
Val Erastov (xibyte) 2020-06-20 21:53:23 -07:00
parent 06682ab003
commit 4ddf018fc6
85 changed files with 1951 additions and 504 deletions

View file

@ -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>

View file

@ -6,6 +6,9 @@ export class NeverStream extends StreamBase {
attach(observer) {
return NOOP;
}
next(value) {
}
}
NeverStream.INSTANCE = new NeverStream();

View file

@ -31,22 +31,24 @@ export default class CSys {
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 mx;
}
return this._outTr;
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) {
@ -66,6 +68,15 @@ export default class CSys {
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
View 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};

View 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;
}
}

View file

@ -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) {

View file

@ -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';

View file

@ -1,7 +1,6 @@
@import "~ui/styles/theme.less";
.root {
background-color: @bg-color-2;
}
.title {

View 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>
}

View file

@ -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} />;
}

View file

@ -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}/>;

View file

@ -1,26 +1,22 @@
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 {
export default function NumberControl(props) {
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} />
}
let {onChange, onFocus, value} = props;
onChange = e => {
this.props.onChange(e.target.value);
const onChangeFromTarget = e => {
onChange(e.target.value);
};
onWheel = (e) => {
let {baseStep, round, min, max, onChange, accelerator} = this.props;
let delta = e.deltaY;
const attachWheelListener = useCallback((input) => {
if (!input) {
return;
}
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;
@ -34,13 +30,24 @@ export default class NumberControl extends React.Component {
if (round !== 0) {
val = val.toFixed(round);
}
this.input.value = val;
input.value = val;
onChange(val);
// e.preventDefault();
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,

View file

@ -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
}

View file

@ -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;

View file

@ -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';

View file

@ -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;

View file

@ -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";

View file

@ -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 {

View file

@ -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";

View 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])
];
}
}

View 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);
// });
}

View 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);
}

View file

@ -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;

View file

@ -57,8 +57,12 @@ export function activate(ctx: ApplicationContext) {
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[];

View file

@ -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'

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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';

View file

@ -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);

View file

@ -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) {

View file

@ -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';

View file

@ -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';

View file

@ -1,4 +1,4 @@
import CSys from '../../../math/csys';
import CSys from '../../../../../modules/math/csys';
import {MDatum} from '../../model/mdatum';
import spatialCurveOpSchema from './spatialCurveOpSchema';

View file

@ -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,33 +54,19 @@ 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>
</>}>
<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>
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>}
@ -90,8 +74,11 @@ export default class Wizard extends React.Component {
{error.userMessage && <div className={ls.userErrorMessage}>{error.userMessage}</div>}
{!error.userMessage && <div>internal error processing operation, check the log</div>}
</div>}
</Stack>
</Window>;
>
<FormContext.Provider value={formContext}>
<Form/>
</FormContext.Provider>
</GenericWizard>;
}
onKeyDown = e => {

View file

@ -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;

View 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),
]
}

View file

@ -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} />}

View file

@ -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} />}

View file

@ -31,7 +31,6 @@ export default function UISystem({children, ...props}) {
<MenuHolder/>
<ActionInfo/>
{children}
<ContributedComponents/>
<Scope><DocumentationWindow/></Scope>
</div>
</UISystemContext.Provider>;

View file

@ -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}>

View file

@ -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} />}

View file

@ -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

View file

@ -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'

View file

@ -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'

View file

@ -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) {

View file

@ -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);

View file

@ -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'

View file

@ -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'

View file

@ -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'

View 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>
}

View 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;
}
}

View 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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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;
}
}

View file

@ -1,4 +1,3 @@
export abstract class MObject {
TYPE: string;
@ -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 = {
}
};

View file

@ -17,4 +17,7 @@ export class MOpenFaceShell extends MShell {
return this.faces[0];
}
get parent() {
return null;
}
}

View file

@ -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 {

View file

@ -15,4 +15,8 @@ export class MSketchObject extends MObject {
this.construction = false;
}
get parent() {
return this.face;
}
}

View file

@ -13,4 +13,8 @@ export class MVertex extends MObject {
this.brepVertex = brepVertex;
}
get parent() {
return this.shell;
}
}

View file

@ -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'];

View file

@ -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} }}) {

View file

@ -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';

View file

@ -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;
});
}

View file

@ -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,

View file

@ -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) {

View file

@ -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) {

View file

@ -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";

View file

@ -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";

View file

@ -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;

View file

@ -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'

View file

@ -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};

View file

@ -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;

View file

@ -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
}
}

View file

@ -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
}

View file

@ -0,0 +1,12 @@
import {Param} from "../shapes/param";
export interface SolvableObject {
id: string;
}
export interface ISolveStage {
objects: Set<SolvableObject>;
index: number;
}

View file

@ -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}

View 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;
}
}

View file

@ -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);
})
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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'];