mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-16 05:23:19 +01:00
assembly infrastructure
This commit is contained in:
parent
4ddf018fc6
commit
931a05ac36
33 changed files with 885 additions and 545 deletions
23
modules/ui/components/Status.tsx
Normal file
23
modules/ui/components/Status.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import * as React from "react";
|
||||
import {BsCheckCircle, BsQuestionCircle} from "react-icons/bs";
|
||||
import {FaRegTimesCircle} from "react-icons/fa";
|
||||
|
||||
export function Status({success}: {
|
||||
success?: boolean
|
||||
}) {
|
||||
|
||||
if (success === true) {
|
||||
return <span><BsCheckCircle style={{
|
||||
color: 'green'
|
||||
}}/> success</span>
|
||||
} else if (success === false) {
|
||||
return <span><FaRegTimesCircle style={{
|
||||
color: 'red'
|
||||
}}/> fail</span>
|
||||
} else {
|
||||
return <span><BsQuestionCircle style={{
|
||||
color: 'orange'
|
||||
}}/> unknown</span>
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,3 +29,11 @@ pre {
|
|||
path {
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: @on-color-highlight-variant-red;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
color: @on-color-highlight-variant-yellow;
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
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";
|
||||
import {AssemblyCSysNode} from "./nodes/assemblyCSysNode";
|
||||
|
||||
export abstract class AssemblyNode implements SolvableObject {
|
||||
|
||||
|
|
@ -41,105 +39,3 @@ export abstract class AssemblyNode implements SolvableObject {
|
|||
|
||||
}
|
||||
|
||||
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])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
10
web/app/cad/assembly/assemblyConstraintDefinition.ts
Normal file
10
web/app/cad/assembly/assemblyConstraintDefinition.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import {ConstantsDefinitions} from "../../sketcher/constr/ANConstraints";
|
||||
|
||||
export interface AssemblyConstraintDefinition {
|
||||
|
||||
typeId: string;
|
||||
|
||||
objects: string[];
|
||||
|
||||
constants: ConstantsDefinitions
|
||||
}
|
||||
118
web/app/cad/assembly/assemblyPlugin.ts
Normal file
118
web/app/cad/assembly/assemblyPlugin.ts
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
import {ApplicationContext} from "context";
|
||||
import {ModellerContextualActions} from "./ui/ModellerContextualActions";
|
||||
import {state, StateStream} from "lstream";
|
||||
import {AssemblyConstraintDefinition} from "./assemblyConstraintDefinition";
|
||||
import {solveAssembly as solveAssemblyImpl} from "./assemblySolver";
|
||||
import {Constraints3D, createAssemblyConstraint} from "./constraints3d";
|
||||
import {SolveStatus} from "../../sketcher/constr/AlgNumSystem";
|
||||
import {ConstantsDefinitions} from "../../sketcher/constr/ANConstraints";
|
||||
import {AssemblyView} from "./ui/AssemblyView";
|
||||
import {IoMdConstruct} from "react-icons/io";
|
||||
|
||||
export function activate(ctx: ApplicationContext) {
|
||||
|
||||
const constraints$ = state<AssemblyConstraintDefinition[][]>([]);
|
||||
const status$ = state<SolveStatus>(null);
|
||||
|
||||
function getConstraints(): AssemblyConstraintDefinition[][] {
|
||||
return constraints$.value;
|
||||
}
|
||||
|
||||
function loadConstraints(inData: AssemblyConstraintDefinition[][]): void {
|
||||
constraints$.next(inData);
|
||||
}
|
||||
|
||||
function addConstraint(typeId: string, objects: string[], constants?: ConstantsDefinitions): void {
|
||||
constraints$.mutate(stages => {
|
||||
if (stages.length === 0) {
|
||||
stages.push([])
|
||||
}
|
||||
stages[stages.length - 1].push({
|
||||
typeId, objects, constants
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function removeConstraint(constr: AssemblyConstraintDefinition) {
|
||||
constraints$.mutate(stages => {
|
||||
for (let constrs of stages) {
|
||||
const index = constrs.indexOf(constr);
|
||||
if (index !== -1) {
|
||||
constrs.splice(index, 1);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function solveAssembly(): void {
|
||||
if (ctx.craftService.isEditingHistory()) {
|
||||
console.log('skipping assembly resolve request in the history mode');
|
||||
return;
|
||||
}
|
||||
|
||||
const stages = constraints$.value.map(stage => stage.map(constr => {
|
||||
const schema = Constraints3D[constr.typeId];
|
||||
if (!schema) {
|
||||
console.error('reference to nonexistent constraint ' + constr.typeId);
|
||||
return null;
|
||||
}
|
||||
const objects = [];
|
||||
for (const id of constr.objects) {
|
||||
const modelObject = ctx.cadRegistry.find(id);
|
||||
if (!modelObject) {
|
||||
console.warn('skipping constraint referring to nonexistent object ' + id);
|
||||
return null;
|
||||
}
|
||||
objects.push(modelObject);
|
||||
}
|
||||
return createAssemblyConstraint(schema, objects)
|
||||
} ).filter(x => x) );
|
||||
|
||||
const solveStatus = solveAssemblyImpl(stages);
|
||||
|
||||
status$.next(solveStatus);
|
||||
}
|
||||
|
||||
constraints$.attach(solveAssembly);
|
||||
|
||||
ctx.domService.contributeComponent(ModellerContextualActions);
|
||||
|
||||
ctx.services.ui.registerFloatView('assembly', AssemblyView, 'Assembly', IoMdConstruct);
|
||||
|
||||
ctx.craftService.modifications$.attach((modifications) => {
|
||||
//if we reach the end reevaluate locations
|
||||
if (modifications.pointer === modifications.history.length - 1) {
|
||||
solveAssembly();
|
||||
}
|
||||
});
|
||||
|
||||
ctx.assemblyService = {
|
||||
constraints$, getConstraints, loadConstraints, solveAssembly, addConstraint, removeConstraint, status$
|
||||
}
|
||||
}
|
||||
|
||||
export interface AssemblyService {
|
||||
|
||||
constraints$: StateStream<AssemblyConstraintDefinition[][]>;
|
||||
|
||||
status$: StateStream<SolveStatus>;
|
||||
|
||||
addConstraint(typeId: string, objects: string[], constants?: ConstantsDefinitions): void;
|
||||
|
||||
removeConstraint(constr: AssemblyConstraintDefinition): void;
|
||||
|
||||
solveAssembly(): void;
|
||||
|
||||
loadConstraints(constraints: AssemblyConstraintDefinition[][]);
|
||||
|
||||
getConstraints(): AssemblyConstraintDefinition[][];
|
||||
|
||||
}
|
||||
|
||||
declare module 'context' {
|
||||
interface ApplicationContext {
|
||||
|
||||
assemblyService: AssemblyService;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,17 +1,18 @@
|
|||
import {AlgNumConstraint} from "../../sketcher/constr/ANConstraints";
|
||||
import {AlgNumSubSystem} from "../../sketcher/constr/AlgNumSystem";
|
||||
import {AlgNumSubSystem, SolveStatus} from "../../sketcher/constr/AlgNumSystem";
|
||||
import Vector from "math/vector";
|
||||
import CSys from "math/csys";
|
||||
import {AssemblyCSysNode, AssemblyNode} from "./assembly";
|
||||
import {AssemblyNode} from "./assembly";
|
||||
import {ISolveStage} from "../../sketcher/constr/solvableObject";
|
||||
import {MObject} from "../model/mobject";
|
||||
import {MShell} from "../model/mshell";
|
||||
import {Constraints3D} from "./constraints3d";
|
||||
import {AssemblyCSysNode} from "./nodes/assemblyCSysNode";
|
||||
|
||||
export function solveAssembly(constraints: AlgNumConstraint[]) {
|
||||
export function solveAssembly(stages: AlgNumConstraint[][]): SolveStatus {
|
||||
|
||||
// temporary solve everything in one stage
|
||||
const constraints = [].concat(...stages);
|
||||
|
||||
const objects = new Set<AssemblyNode>();
|
||||
|
||||
constraints.forEach(c => c.objects.forEach(o => objects.add(o)));
|
||||
|
||||
const stage: ISolveStage = {
|
||||
|
|
@ -33,11 +34,8 @@ export function solveAssembly(constraints: AlgNumConstraint[]) {
|
|||
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));
|
||||
|
|
@ -60,17 +58,18 @@ export function solveAssembly(constraints: AlgNumConstraint[]) {
|
|||
}
|
||||
});
|
||||
|
||||
system.prepare();
|
||||
system.solveFine();
|
||||
system.finishTransaction();
|
||||
system.solveFine();
|
||||
|
||||
// __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);
|
||||
});
|
||||
if (system.solveStatus.success) {
|
||||
roots.forEach(root => {
|
||||
applyResults(root, root.assemblyNodes.location);
|
||||
});
|
||||
} else {
|
||||
console.log("Assembly system haven't been solved, locations won't be updated");
|
||||
}
|
||||
|
||||
return system.solveStatus;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ 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";
|
||||
import {AssemblyNode} from "./assembly";
|
||||
import {EndPoint} from "../../sketcher/shapes/point";
|
||||
import {Circle} from "../../sketcher/shapes/circle";
|
||||
import {Arc} from "../../sketcher/shapes/arc";
|
||||
|
||||
|
||||
export const Constraints3D = {
|
||||
|
||||
|
|
@ -47,13 +52,70 @@ export const Constraints3D = {
|
|||
|
||||
},
|
||||
|
||||
FaceToFace: {
|
||||
id: 'FaceToFace',
|
||||
name: 'Face To Face',
|
||||
icon: NoIcon,
|
||||
|
||||
selectionMatcher: {
|
||||
selector: 'matchAll',
|
||||
types: ['face'],
|
||||
minQuantity: 2
|
||||
},
|
||||
|
||||
defineAssemblyScope: ([face1, face2]) => {
|
||||
return [
|
||||
face1.assemblyNodes.plane,
|
||||
face2.assemblyNodes.plane,
|
||||
];
|
||||
},
|
||||
|
||||
defineParamsScope: ([plane1, plane2], cb) => {
|
||||
plane1.visitParams(cb);
|
||||
plane2.visitParams(cb);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params) => {
|
||||
|
||||
const [
|
||||
nx1, ny1, nz1, w1, nx2, ny2, nz2, w2
|
||||
] = 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)
|
||||
|
||||
);
|
||||
polynomials.push(
|
||||
new Polynomial()
|
||||
.monomial()
|
||||
.term(w1, POW_1_FN)
|
||||
.monomial()
|
||||
.term(w2, POW_1_FN)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
UnitVectorConsistency: {
|
||||
id: 'UnitVectorConsistency',
|
||||
name: 'UnitVectorConsistency',
|
||||
icon: NoIcon,
|
||||
|
||||
defineParamsScope: ([vec], cb) => {
|
||||
vec.visitParams(cb);
|
||||
//don't change to generic way it can a plane
|
||||
cb(vec.x);
|
||||
cb(vec.y);
|
||||
cb(vec.z);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params) => {
|
||||
|
|
@ -162,6 +224,80 @@ export const Constraints3D = {
|
|||
},
|
||||
},
|
||||
|
||||
RigidBodyPlaneLink: {
|
||||
id: 'RigidBodyPlaneLink',
|
||||
name: 'RigidBodyPlaneLink',
|
||||
icon: NoIcon,
|
||||
|
||||
defineParamsScope: ([csys, plane], cb) => {
|
||||
csys.visitParams(cb);
|
||||
plane.visitParams(cb);
|
||||
},
|
||||
|
||||
collectPolynomials: (polynomials, params, _, objects) => {
|
||||
const [csys, plane] = objects;
|
||||
|
||||
const n = plane.getNormal();
|
||||
const wStar = plane.getDepth();
|
||||
|
||||
const {x: xStar, y: yStar, z: zStar} = n.multiply(wStar);
|
||||
|
||||
const [ox, oy, oz, ix, iy, iz, jx, jy, jz, kx, ky, kz, x, y, z, w] = 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)
|
||||
.term(w, POW_1_FN)
|
||||
.monomial(xStar)
|
||||
.term(ix, POW_1_FN)
|
||||
.monomial(yStar)
|
||||
.term(jx, POW_1_FN)
|
||||
.monomial(zStar)
|
||||
.term(kx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(ox, POW_1_FN)
|
||||
);
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(y, POW_1_FN)
|
||||
.term(w, POW_1_FN)
|
||||
.monomial(xStar)
|
||||
.term(iy, POW_1_FN)
|
||||
.monomial(yStar)
|
||||
.term(jy, POW_1_FN)
|
||||
.monomial(zStar)
|
||||
.term(ky, POW_1_FN)
|
||||
.monomial()
|
||||
.term(oy, POW_1_FN)
|
||||
|
||||
);
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(z, POW_1_FN)
|
||||
.term(w, POW_1_FN)
|
||||
.monomial(xStar)
|
||||
.term(iz, POW_1_FN)
|
||||
.monomial(yStar)
|
||||
.term(jz, POW_1_FN)
|
||||
.monomial(zStar)
|
||||
.term(kz, POW_1_FN)
|
||||
.monomial()
|
||||
.term(oz, POW_1_FN)
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
RigidBodyLink3x3: {
|
||||
id: 'RigidBodyLink3x3',
|
||||
name: 'RigidBodyLink3x3',
|
||||
|
|
@ -231,18 +367,103 @@ export const Constraints3D = {
|
|||
}
|
||||
},
|
||||
|
||||
RigidBodyLink4x4: {
|
||||
id: 'RigidBodyLink4x4',
|
||||
name: 'RigidBodyLink4x4',
|
||||
icon: NoIcon,
|
||||
|
||||
defineParamsScope: ([csys, vec], cb) => {
|
||||
cb(csys.ox);
|
||||
cb(csys.oy);
|
||||
cb(csys.oz);
|
||||
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: xStar, y: yStar, z: zStar} = vec.getVector();
|
||||
|
||||
const [ox, oy, oz, 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(xStar)
|
||||
.term(ix, POW_1_FN)
|
||||
.monomial(yStar)
|
||||
.term(jx, POW_1_FN)
|
||||
.monomial(zStar)
|
||||
.term(kx, POW_1_FN)
|
||||
.monomial()
|
||||
.term(ox, POW_1_FN)
|
||||
|
||||
);
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(y, POW_1_FN)
|
||||
.monomial(xStar)
|
||||
.term(iy, POW_1_FN)
|
||||
.monomial(yStar)
|
||||
.term(jy, POW_1_FN)
|
||||
.monomial(zStar)
|
||||
.term(ky, POW_1_FN)
|
||||
.monomial()
|
||||
.term(oy, POW_1_FN)
|
||||
|
||||
|
||||
);
|
||||
|
||||
polynomials.push(
|
||||
new Polynomial(0)
|
||||
.monomial(-1)
|
||||
.term(z, POW_1_FN)
|
||||
.monomial(xStar)
|
||||
.term(iz, POW_1_FN)
|
||||
.monomial(yStar)
|
||||
.term(jz, POW_1_FN)
|
||||
.monomial(zStar)
|
||||
.term(kz, POW_1_FN)
|
||||
.monomial()
|
||||
.term(oz, POW_1_FN)
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
export interface AssemblyConstraintSchema extends ConstraintSchema {
|
||||
defineAssemblyScope: (objects: MObject[]) => SolvableObject[],
|
||||
selectionMatcher?: {
|
||||
selector: string,
|
||||
types: any[],
|
||||
minQuantity: number
|
||||
};
|
||||
defineAssemblyScope: (objects: MObject[]) => AssemblyNode[],
|
||||
}
|
||||
|
||||
|
||||
export function createAssemblyConstraint(schema: AssemblyConstraintSchema,
|
||||
objects: MObject[],
|
||||
constants?: ConstantsDefinitions,
|
||||
internal?: boolean = false) {
|
||||
internal: boolean = false) {
|
||||
|
||||
return new AlgNumConstraint(schema, schema.defineAssemblyScope(objects), constants, internal);
|
||||
}
|
||||
70
web/app/cad/assembly/nodes/assemblyCSysNode.ts
Normal file
70
web/app/cad/assembly/nodes/assemblyCSysNode.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import {Param} from "../../../sketcher/shapes/param";
|
||||
import {Matrix3} from "math/l3space";
|
||||
import {MObject} from "../../model/mobject";
|
||||
import {AlgNumConstraint} from "../../../sketcher/constr/ANConstraints";
|
||||
import {Constraints3D} from "../constraints3d";
|
||||
import {AssemblyNode} from "../assembly";
|
||||
|
||||
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])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
53
web/app/cad/assembly/nodes/assemblyPlaneNode.ts
Normal file
53
web/app/cad/assembly/nodes/assemblyPlaneNode.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import {Param} from "../../../sketcher/shapes/param";
|
||||
import Vector from "math/vector";
|
||||
import {MObject} from "../../model/mobject";
|
||||
import {AlgNumConstraint} from "../../../sketcher/constr/ANConstraints";
|
||||
import {Constraints3D} from "../constraints3d";
|
||||
import {AssemblyNode} from "../assembly";
|
||||
import {AssemblyCSysNode} from "./assemblyCSysNode";
|
||||
|
||||
export class AssemblyPlaneNode extends AssemblyNode {
|
||||
|
||||
x = new Param(0, 'X');
|
||||
y = new Param(0, 'Y');
|
||||
z = new Param(0, 'Z');
|
||||
w = new Param(0, 'W');
|
||||
getNormal: () => Vector;
|
||||
getDepth: () => number;
|
||||
|
||||
constructor(model: MObject, getNormal: () => Vector, getDepth: () => number) {
|
||||
super(model);
|
||||
this.getNormal = getNormal;
|
||||
this.getDepth = getDepth;
|
||||
}
|
||||
|
||||
visitParams(cb) {
|
||||
cb(this.x);
|
||||
cb(this.y);
|
||||
cb(this.z);
|
||||
cb(this.w);
|
||||
}
|
||||
|
||||
reset() {
|
||||
const {x, y, z} = this.getNormal();
|
||||
const w = this.getDepth();
|
||||
this.x.set(x);
|
||||
this.y.set(y);
|
||||
this.z.set(z);
|
||||
this.w.set(w);
|
||||
}
|
||||
|
||||
createConsistencyConstraints() {
|
||||
return [
|
||||
new AlgNumConstraint(Constraints3D.UnitVectorConsistency, [this])
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
createRigidBodyLink(body: AssemblyCSysNode) {
|
||||
return [
|
||||
new AlgNumConstraint(Constraints3D.RigidBodyPlaneLink, [body, this])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
33
web/app/cad/assembly/nodes/assemblyScalarNode.ts
Normal file
33
web/app/cad/assembly/nodes/assemblyScalarNode.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import {AssemblyNode} from "../assembly";
|
||||
import {Param} from "../../../sketcher/shapes/param";
|
||||
import {MObject} from "../../model/mobject";
|
||||
import {AlgNumConstraint} from "../../../sketcher/constr/ANConstraints";
|
||||
import {Constraints3D} from "../constraints3d";
|
||||
import {AssemblyCSysNode} from "./assemblyCSysNode";
|
||||
|
||||
export class AssemblyScalarNode extends AssemblyNode {
|
||||
|
||||
param: Param;
|
||||
getValue: () => number;
|
||||
|
||||
constructor(model: MObject, debugSymbol: string, getValue: () => number) {
|
||||
super(model);
|
||||
this.param = new Param(0, debugSymbol);
|
||||
this.getValue = getValue;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.param.set(this.getValue());
|
||||
}
|
||||
|
||||
visitParams(cb) {
|
||||
cb(this.param);
|
||||
}
|
||||
|
||||
createRigidBodyLink(body: AssemblyCSysNode) {
|
||||
return [
|
||||
// new AlgNumConstraint(Constraints3D.RigidTest, [body, this.model.assemblyNodes.normal, this])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
46
web/app/cad/assembly/nodes/assemblyUnitVectorNode.ts
Normal file
46
web/app/cad/assembly/nodes/assemblyUnitVectorNode.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import {Param} from "../../../sketcher/shapes/param";
|
||||
import Vector from "math/vector";
|
||||
import {MObject} from "../../model/mobject";
|
||||
import {AlgNumConstraint} from "../../../sketcher/constr/ANConstraints";
|
||||
import {Constraints3D} from "../constraints3d";
|
||||
import {AssemblyNode} from "../assembly";
|
||||
import {AssemblyCSysNode} from "./assemblyCSysNode";
|
||||
|
||||
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])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
40
web/app/cad/assembly/nodes/assemblyVectorNode.ts
Normal file
40
web/app/cad/assembly/nodes/assemblyVectorNode.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import {Param} from "../../../sketcher/shapes/param";
|
||||
import Vector from "math/vector";
|
||||
import {MObject} from "../../model/mobject";
|
||||
import {AlgNumConstraint} from "../../../sketcher/constr/ANConstraints";
|
||||
import {Constraints3D} from "../constraints3d";
|
||||
import {AssemblyNode} from "../assembly";
|
||||
import {AssemblyCSysNode} from "./assemblyCSysNode";
|
||||
|
||||
export class AssemblyVectorNode 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);
|
||||
}
|
||||
|
||||
createRigidBodyLink(body: AssemblyCSysNode) {
|
||||
return [
|
||||
new AlgNumConstraint(Constraints3D.RigidBodyLink4x4, [body, this])
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
91
web/app/cad/assembly/ui/AssemblyView.tsx
Normal file
91
web/app/cad/assembly/ui/AssemblyView.tsx
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import React, {useContext, useEffect} from 'react';
|
||||
import {useStream} from "ui/effects";
|
||||
import {Status} from "ui/components/Status";
|
||||
import Folder from "ui/components/Folder";
|
||||
import {Constraints3D} from "../constraints3d";
|
||||
import {AppContext} from "../../dom/components/AppContext";
|
||||
import cx from 'classnames';
|
||||
import {NoIcon} from "../../../sketcher/icons/NoIcon";
|
||||
import ls from "../../../sketcher/components/ConstraintExplorer.less";
|
||||
import Fa from "ui/components/Fa";
|
||||
import {AssemblyConstraintDefinition} from "../assemblyConstraintDefinition";
|
||||
import {ApplicationContext} from "context";
|
||||
|
||||
|
||||
export function AssemblyView() {
|
||||
|
||||
const ctx = useContext(AppContext);
|
||||
const constraints = useStream(ctx => ctx.assemblyService.constraints$);
|
||||
const status = useStream(ctx => ctx.assemblyService.status$);
|
||||
|
||||
|
||||
return <div>
|
||||
<div>
|
||||
Status: <Status success={status.success} />
|
||||
</div>
|
||||
{constraints.map((stage, i) => <Folder key={i} title={'Stage' + (i + 1)}>
|
||||
{stage.map((constr, j) => <AssemblyConstraintButton key={j} prefix={j + '.'} constraint={constr} />) }
|
||||
</Folder>)}
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
export function AssemblyConstraintButton({prefix='', constraint: c, ...props}: {
|
||||
prefix: string,
|
||||
constraint: AssemblyConstraintDefinition,
|
||||
props?: React.HTMLAttributes<HTMLDivElement>
|
||||
}) {
|
||||
|
||||
const ctx: ApplicationContext = useContext(AppContext);
|
||||
|
||||
const edit = (constraint) => {
|
||||
if (constraint.editable) {
|
||||
//...
|
||||
}
|
||||
};
|
||||
|
||||
const remove = constr => {
|
||||
ctx.assemblyService.removeConstraint(constr);
|
||||
};
|
||||
|
||||
const highlight = constr => {
|
||||
ctx.services.marker.clear();
|
||||
constr.objects.forEach(id => {
|
||||
const entity = ctx.cadRegistry.find(id);
|
||||
if (entity) {
|
||||
ctx.services.marker.markAdding(entity.TYPE, id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const withdraw = () => {
|
||||
ctx.services.marker.clear();
|
||||
};
|
||||
|
||||
useEffect(() => withdraw, [c]);
|
||||
|
||||
const schema = Constraints3D[c.typeId];
|
||||
if (schema === null) {
|
||||
return <div className='warning-text'>Invalid Constraint {c.typeId} </div>
|
||||
}
|
||||
|
||||
const entities = c.objects.map(ctx.cadRegistry.find);
|
||||
|
||||
const invalid = !!entities.find(x => !x);
|
||||
|
||||
const Icon = schema.icon || NoIcon;
|
||||
|
||||
return <div className={cx(ls.objectItem, invalid&&ls.conflicting)}
|
||||
onClick={() => schema.constants && edit(c)}
|
||||
onMouseEnter={() => highlight(c)}
|
||||
onMouseLeave={() => withdraw()}
|
||||
{...props}>
|
||||
<span className={ls.objectIcon}><Icon size={16} /></span>
|
||||
<span className={ls.objectTag}>
|
||||
{prefix} {schema.name}
|
||||
</span>
|
||||
<span className={ls.removeButton} onClick={() => remove(c)}><Fa icon='times'/></span>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
36
web/app/cad/assembly/ui/ModellerContextualActions.tsx
Normal file
36
web/app/cad/assembly/ui/ModellerContextualActions.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import React, {useContext} from 'react';
|
||||
import {AppContext} from "../../dom/components/AppContext";
|
||||
import {useStream} from "ui/effects";
|
||||
import {Dialog} from "ui/components/Dialog";
|
||||
import {AssemblyConstraintSchema, Constraints3D} from "../constraints3d";
|
||||
import {matchAvailableSubjects, MatchIndex, matchSelection} from "../../../sketcher/selectionMatcher";
|
||||
|
||||
export function ModellerContextualActions() {
|
||||
|
||||
const ctx = useContext(AppContext);
|
||||
|
||||
const selection: string[] = useStream(ctx => ctx.streams.selection.all);
|
||||
|
||||
if (!selection || selection.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const entities = selection.map(ctx.cadRegistry.find);
|
||||
|
||||
const allConstraints = Object.values(Constraints3D) as AssemblyConstraintSchema[];
|
||||
const availableConstraints = matchAvailableSubjects(entities, allConstraints) as AssemblyConstraintSchema[];
|
||||
|
||||
if (availableConstraints.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <Dialog initRight={50} title='AVAILABLE ACTIONS' onClose={() => {}}>
|
||||
{availableConstraints.map( schema => <button key={schema.id}
|
||||
onClick={() => {
|
||||
|
||||
const objects = matchSelection(schema.selectionMatcher, new MatchIndex(entities), false);
|
||||
ctx.assemblyService.addConstraint(schema.id, objects.map(o => o.id));
|
||||
|
||||
}}>{schema.name}</button> ) }
|
||||
</Dialog>;
|
||||
}
|
||||
|
|
@ -99,11 +99,16 @@ export function activate(ctx: CoreContext) {
|
|||
return runRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isEditingHistory() {
|
||||
const mods = this.modifications$.value;
|
||||
return mods && mods.pointer !== mods.history.length - 1;
|
||||
}
|
||||
|
||||
ctx.craftService = {
|
||||
modify, modifyInHistoryAndStep, reset, rebuild, runRequest, runPipeline,
|
||||
historyTravel: historyTravel(modifications$),
|
||||
modifications$, models$, update$
|
||||
modifications$, models$, update$, isEditingHistory
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
|
|
@ -256,7 +261,9 @@ interface CraftService {
|
|||
|
||||
runRequest(request: OperationRequest): Promise<OperationResult>;
|
||||
|
||||
runPipeline(history: OperationRequest[], beginIndex: number, endIndex: number): Promise<void>
|
||||
runPipeline(history: OperationRequest[], beginIndex: number, endIndex: number): Promise<void>;
|
||||
|
||||
isEditingHistory(): boolean;
|
||||
}
|
||||
|
||||
interface HistoryTravel {
|
||||
|
|
|
|||
|
|
@ -1,377 +0,0 @@
|
|||
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),
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
|
|
@ -20,7 +20,6 @@ import SketcherOperationWizard from "../../../sketcher/components/SketcherOperat
|
|||
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 {
|
||||
|
||||
|
|
@ -59,7 +58,6 @@ export default class View3d extends React.Component {
|
|||
<WizardManager/>
|
||||
</div>
|
||||
<ContributedComponents/>
|
||||
<Scope><ModellerContextualActions /></Scope>
|
||||
</div>
|
||||
|
||||
<div className={ls.bottomStack}>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import * as DebugPlugin from "../debugPlugin";
|
|||
import * as ExpressionsPlugin from "../expressions/expressionsPlugin";
|
||||
import * as PartOperationsPlugin from "../part/partOperationsPlugin";
|
||||
import * as LocationPlugin from "../location/locationPlugin";
|
||||
import * as AssemblyPlugin from "../assembly/assemblyPlugin";
|
||||
|
||||
export default function startApplication(callback) {
|
||||
|
||||
|
|
@ -76,6 +77,7 @@ export default function startApplication(callback) {
|
|||
DebugPlugin,
|
||||
PartOperationsPlugin,
|
||||
LocationPlugin,
|
||||
AssemblyPlugin,
|
||||
RemotePartsPlugin,
|
||||
ViewSyncPlugin,
|
||||
WizardSelectionPlugin
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ import CSys from 'math/csys';
|
|||
import {MSketchLoop} from './mloop';
|
||||
import {ProductionInfo} from './productionInfo';
|
||||
import {MBrepShell, MShell} from "./mshell";
|
||||
import {AssemblyUnitVectorNode} from "../assembly/assembly";
|
||||
import {AssemblyUnitVectorNode} from "../assembly/nodes/assemblyUnitVectorNode";
|
||||
import {AssemblyScalarNode} from "../assembly/nodes/assemblyScalarNode";
|
||||
import {AssemblyVectorNode} from "../assembly/nodes/assemblyVectorNode";
|
||||
import {AssemblyPlaneNode} from "../assembly/nodes/assemblyPlaneNode";
|
||||
|
||||
export class MFace extends MObject {
|
||||
|
||||
|
|
@ -20,7 +23,9 @@ export class MFace extends MObject {
|
|||
brepFace: any;
|
||||
|
||||
assemblyNodes: {
|
||||
normal: AssemblyUnitVectorNode
|
||||
// normal: AssemblyUnitVectorNode
|
||||
plane: AssemblyPlaneNode,
|
||||
// w: AssemblyScalarNode
|
||||
};
|
||||
|
||||
private _csys: any;
|
||||
|
|
@ -38,15 +43,17 @@ export class MFace extends MObject {
|
|||
this.sketchLoops = [];
|
||||
this._csys = csys;
|
||||
this.assemblyNodes = {
|
||||
normal: new AssemblyUnitVectorNode(this, () => this.normal())
|
||||
// normal: new AssemblyUnitVectorNode(this, () => this.normal()),
|
||||
// w: new AssemblyScalarNode(this, 'W', () => this.depth())
|
||||
plane: new AssemblyPlaneNode(this, () => this.normal(), () => this.depth())
|
||||
};
|
||||
}
|
||||
|
||||
normal() {
|
||||
normal(): Vector {
|
||||
return this.csys.z;
|
||||
}
|
||||
|
||||
depth() {
|
||||
depth(): number {
|
||||
this.evalCSys();
|
||||
return this.w;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {MVertex} from './mvertex';
|
|||
import CSys from 'math/csys';
|
||||
import {Matrix3} from "math/l3space";
|
||||
import {state, StateStream} from "lstream";
|
||||
import {AssemblyCSysNode} from "../assembly/assembly";
|
||||
import {AssemblyCSysNode} from "../assembly/nodes/assemblyCSysNode";
|
||||
|
||||
export class MShell extends MObject {
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import exportTextData from '../../../../modules/gems/exportTextData';
|
|||
import {SketchFormat_V3} from "../../sketcher/io";
|
||||
import {ApplicationContext} from "context";
|
||||
import {OperationRequest} from "../craft/craftPlugin";
|
||||
import {AssemblyConstraintDefinition} from "../assembly/assemblyConstraintDefinition";
|
||||
|
||||
export function activate(ctx: ApplicationContext) {
|
||||
|
||||
|
|
@ -202,6 +203,8 @@ export interface ProjectModel {
|
|||
|
||||
expressions: string
|
||||
|
||||
assembly?: AssemblyConstraintDefinition[][];
|
||||
|
||||
}
|
||||
|
||||
export interface ModelBundle {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@ export function initProjectService(ctx: CoreContext, id: string, hints: any) {
|
|||
function save() {
|
||||
let data = {
|
||||
history: ctx.craftService.modifications$.value.history,
|
||||
expressions: ctx.expressionService.script$.value
|
||||
expressions: ctx.expressionService.script$.value,
|
||||
|
||||
// @ts-ignore we deliberately don't uplift the type to the ApplicationContext in order to be able to use ProjectService in the headless mode
|
||||
assembly: ctx.assemblyService && ctx.assemblyService.getConstraints()
|
||||
};
|
||||
ctx.storageService.set(projectStorageKey(), JSON.stringify(data));
|
||||
}
|
||||
|
|
@ -65,6 +68,13 @@ export function initProjectService(ctx: CoreContext, id: string, hints: any) {
|
|||
if (data.history) {
|
||||
ctx.craftService.reset(data.history);
|
||||
}
|
||||
|
||||
// @ts-ignore we deliberately don't uplift the type to the ApplicationContext in order to be able to use ProjectService in the headless mode
|
||||
if (data.assembly && ctx.assemblyService) {
|
||||
// @ts-ignore
|
||||
ctx.assemblyService.loadConstraints(data.assembly);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function empty() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {state} from 'lstream';
|
|||
import {addToListInMap} from 'gems/iterables';
|
||||
import {EMPTY_ARRAY} from '../../../../modules/gems/iterables';
|
||||
import {DATUM, FACE, SHELL, SKETCH_OBJECT, EDGE, LOOP} from './entites';
|
||||
import {combine} from "../../../../modules/lstream";
|
||||
|
||||
export const SELECTABLE_ENTITIES = [FACE, EDGE, SKETCH_OBJECT, DATUM, SHELL];
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ export function defineStreams(ctx) {
|
|||
SELECTABLE_ENTITIES.forEach(entity => {
|
||||
ctx.streams.selection[entity] = state([]);
|
||||
});
|
||||
ctx.streams.selection.all = combine(...Object.values(ctx.streams.selection)).map(selection => [].concat(...selection)).throttle();
|
||||
}
|
||||
|
||||
export function activate(ctx) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import sketcherUIContrib from './sketcherUIContrib';
|
|||
import initReassignSketchMode from './reassignSketchMode';
|
||||
import {Viewer} from "../../sketcher/viewer2d";
|
||||
import {IO} from "../../sketcher/io";
|
||||
import {Generator} from "../../sketcher/id-generator";
|
||||
|
||||
export function defineStreams(ctx) {
|
||||
ctx.streams.sketcher = {
|
||||
|
|
@ -67,6 +68,7 @@ export function activate(ctx) {
|
|||
services.storage.set(ctx.projectService.sketchStorageKey(sketchId), viewer.io.serializeSketch({
|
||||
expressionsSignature: signature
|
||||
}));
|
||||
Generator.resetIDGenerator();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import constraintActions from "./constraintActions";
|
||||
import {getDescription, MatchIndex, matchSelection} from "../selectionMatcher";
|
||||
import {getDescription, matchAvailableSubjects, MatchIndex, matchSelection} from "../selectionMatcher";
|
||||
import {toast} from "react-toastify";
|
||||
import operationActions from "./operationActions";
|
||||
import constraintGlobalActions from "./constraintGlobalActions";
|
||||
|
|
@ -35,19 +35,7 @@ ALL_ACTIONS.forEach(a => index[a.id] = a);
|
|||
Object.freeze(index);
|
||||
|
||||
export function matchAvailableActions(selection) {
|
||||
|
||||
let matched = [];
|
||||
let matchIndex = new MatchIndex(selection);
|
||||
|
||||
if (selection.length) {
|
||||
for (let action of ALL_CONTEXTUAL_ACTIONS) {
|
||||
if (action.selectionMatcher && matchSelection(action.selectionMatcher, matchIndex, true)) {
|
||||
matched.push(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matched;
|
||||
return matchAvailableSubjects(selection, ALL_CONTEXTUAL_ACTIONS);
|
||||
}
|
||||
|
||||
export function getSketcherAction(actionId) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export function SketchObjectExplorer() {
|
|||
|
||||
const [modification, setModification] = useState(0);
|
||||
const objects = useStream(ctx => ctx.viewer.streams.objects);
|
||||
const selection = useStream(ctx.viewer.streams.selection);
|
||||
const selection = useStream(ctx => ctx.viewer.streams.selection);
|
||||
const ctx = useContext(SketcherAppContext);
|
||||
|
||||
if (!objects || !selection) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import {
|
|||
import {ISolveStage, SolvableObject} from "./solvableObject";
|
||||
import {SketchObject} from "../shapes/sketch-object";
|
||||
import {IconType} from "react-icons";
|
||||
import {ConstraintAnnotation} from "./constraintAnnotation";
|
||||
|
||||
export const ConstraintDefinitions
|
||||
// : {
|
||||
|
|
@ -966,7 +967,7 @@ export interface ConstraintSchema {
|
|||
}
|
||||
};
|
||||
|
||||
createAnnotations?: (objects: SolvableObject[], constraintInstance: AlgNumConstraint) => SketchObject[];
|
||||
createAnnotations?: (objects: SolvableObject[], constraintInstance: AlgNumConstraint) => ConstraintAnnotation<any>[];
|
||||
|
||||
defineParamsScope: (object: SolvableObject[], cb: (param: Param) => void) => void;
|
||||
|
||||
|
|
@ -989,9 +990,9 @@ export class AlgNumConstraint {
|
|||
schema: ConstraintSchema;
|
||||
params: Param[];
|
||||
stage: ISolveStage;
|
||||
private annotations: SketchObject[];
|
||||
annotations: ConstraintAnnotation<any>[];
|
||||
|
||||
constructor(schema: ConstraintSchema, objects: SolvableObject[], constants?: ConstantsDefinitions, internal?: boolean = false) {
|
||||
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;
|
||||
|
|
@ -1038,7 +1039,7 @@ export class AlgNumConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
write() {
|
||||
write(): ConstraintSerialization {
|
||||
return {
|
||||
typeId: this.schema.id,
|
||||
objects: this.objects.map(o => o.id),
|
||||
|
|
@ -1048,7 +1049,7 @@ export class AlgNumConstraint {
|
|||
}
|
||||
}
|
||||
|
||||
static read({typeId, objects, constants, annotations}, index) {
|
||||
static read({typeId, objects, constants, annotations}: ConstraintSerialization, index: {[key: string]: SolvableObject}) {
|
||||
const schema = ConstraintDefinitions[typeId];
|
||||
if (!schema) {
|
||||
throw "constraint schema " + typeId + " doesn't exist";
|
||||
|
|
@ -1106,3 +1107,12 @@ export class AlgNumConstraint {
|
|||
this.constants[key] = value + ''; // only string are allowed here
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface ConstraintSerialization {
|
||||
typeId: string;
|
||||
objects: string[];
|
||||
constants: ConstantsDefinitions;
|
||||
stage: number;
|
||||
annotations?: any
|
||||
}
|
||||
|
|
@ -626,7 +626,7 @@ class PolynomialResidual {
|
|||
|
||||
}
|
||||
|
||||
interface SolveStatus {
|
||||
export interface SolveStatus {
|
||||
success: boolean;
|
||||
error: number
|
||||
error: number;
|
||||
}
|
||||
6
web/app/sketcher/constr/constraintAnnotation.ts
Normal file
6
web/app/sketcher/constr/constraintAnnotation.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export interface ConstraintAnnotation<T> {
|
||||
|
||||
save(): T;
|
||||
|
||||
load(data: T);
|
||||
}
|
||||
|
|
@ -1,3 +1,20 @@
|
|||
|
||||
export function matchAvailableSubjects(selection, subjects) {
|
||||
|
||||
let matched = [];
|
||||
let matchIndex = new MatchIndex(selection);
|
||||
|
||||
if (selection.length) {
|
||||
for (let action of subjects) {
|
||||
if (action.selectionMatcher && matchSelection(action.selectionMatcher, matchIndex, true)) {
|
||||
matched.push(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
export function matchSelection(definition, matchIndex, fast) {
|
||||
const selection = matchIndex.selection;
|
||||
if (definition.selector === 'function') {
|
||||
|
|
@ -12,7 +29,7 @@ export function matchSelection(definition, matchIndex, fast) {
|
|||
|
||||
let hit = false;
|
||||
for (let constructor of types) {
|
||||
if (constructor.prototype._class === obj._class) {
|
||||
if (typeToString(constructor) === obj.TYPE) {
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -70,7 +87,7 @@ export function getDescription(definition) {
|
|||
}
|
||||
|
||||
function stringifyTypes(types, minQuantity) {
|
||||
return types.map(t => t.prototype.TYPE + (minQuantity > 1 ? 's' : '')).join(' or ');
|
||||
return types.map(t => typeToString(t) + (minQuantity > 1 ? 's' : '')).join(' or ');
|
||||
}
|
||||
|
||||
export class MatchIndex {
|
||||
|
|
@ -82,13 +99,13 @@ export class MatchIndex {
|
|||
constructor(selection) {
|
||||
this.selection = selection;
|
||||
selection.forEach(obj => {
|
||||
let info = this.typeMap.get(obj._class);
|
||||
let info = this.typeMap.get(obj.TYPE);
|
||||
if (!info) {
|
||||
info = {
|
||||
hits: 0,
|
||||
objects: []
|
||||
};
|
||||
this.typeMap.set(obj._class, info);
|
||||
this.typeMap.set(obj.TYPE, info);
|
||||
}
|
||||
info.objects.push(obj);
|
||||
})
|
||||
|
|
@ -102,7 +119,7 @@ export class MatchIndex {
|
|||
|
||||
mark(types, quantity) {
|
||||
for (let type of types) {
|
||||
const info = this.typeMap.get(type.prototype._class);
|
||||
const info = this.typeMap.get(typeToString(type));
|
||||
if (!info) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -123,4 +140,12 @@ export class MatchIndex {
|
|||
return this.selection.length === this.overallHits;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function typeToString(type) {
|
||||
if (typeof type === 'string') {
|
||||
return type;
|
||||
} else {
|
||||
return type.prototype.TYPE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
import {AngleBetweenDimension, DiameterDimension, LinearDimension} from "../dim";
|
||||
import {Styles} from "../../styles";
|
||||
import {ConstraintAnnotation} from "../../constr/constraintAnnotation";
|
||||
import {AlgNumConstraint} from "../../constr/ANConstraints";
|
||||
|
||||
export class AngleBetweenAnnotation extends AngleBetweenDimension {
|
||||
export class AngleBetweenAnnotation extends AngleBetweenDimension implements ConstraintAnnotation<{offset: number}> {
|
||||
|
||||
constraint: AlgNumConstraint;
|
||||
|
||||
constructor(a, b, constraint) {
|
||||
super(a, b);
|
||||
|
|
@ -27,7 +31,9 @@ AngleBetweenAnnotation.prototype.TYPE = 'AngleBetweenAnnotation';
|
|||
|
||||
AngleBetweenAnnotation.prototype._class = 'TCAD.TWO.AngleBetweenAnnotation';
|
||||
|
||||
export class AngleAbsoluteAnnotation extends AngleBetweenDimension {
|
||||
export class AngleAbsoluteAnnotation extends AngleBetweenDimension implements ConstraintAnnotation<{offset: number}> {
|
||||
|
||||
constraint: AlgNumConstraint;
|
||||
|
||||
constructor(segment, constraint) {
|
||||
super({
|
||||
|
|
@ -90,7 +96,9 @@ export class AngleAbsoluteAnnotation extends AngleBetweenDimension {
|
|||
AngleAbsoluteAnnotation.prototype._class = 'AngleAbsoluteAnnotation';
|
||||
|
||||
|
||||
export class LengthAnnotation extends LinearDimension {
|
||||
export class LengthAnnotation extends LinearDimension implements ConstraintAnnotation<{offset: number}> {
|
||||
|
||||
constraint: AlgNumConstraint;
|
||||
|
||||
constructor(segment, constraint) {
|
||||
super(segment.a, segment.b);
|
||||
|
|
@ -116,7 +124,9 @@ LengthAnnotation.prototype.TYPE = 'LengthAnnotation';
|
|||
|
||||
LengthAnnotation.prototype._class = 'TCAD.TWO.LengthAnnotation';
|
||||
|
||||
export class RadiusLengthAnnotation extends DiameterDimension {
|
||||
export class RadiusLengthAnnotation extends DiameterDimension implements ConstraintAnnotation<{angle: number}> {
|
||||
|
||||
constraint: AlgNumConstraint;
|
||||
|
||||
constructor(obj, constraint) {
|
||||
super(obj);
|
||||
|
|
@ -7,6 +7,7 @@ import {TextHelper} from "./textHelper";
|
|||
import {isInstanceOf} from "../actions/matchUtils";
|
||||
import {Arc} from "./arc";
|
||||
import {SketchObject} from "./sketch-object";
|
||||
import {ConstraintAnnotation} from "../constr/constraintAnnotation";
|
||||
|
||||
const ARROW_W_PX = 15;
|
||||
const ARROW_H_PX = 4;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {Styles} from './styles';
|
|||
import {Dimension} from "./shapes/dim";
|
||||
import {GroundObjectsGeneratorSchema} from "./generators/groundObjectsGenerator";
|
||||
import {SketchGenerator} from "./generators/sketchGenerator";
|
||||
import {Generator} from "./id-generator";
|
||||
|
||||
export class Viewer {
|
||||
|
||||
|
|
@ -136,6 +137,7 @@ export class Viewer {
|
|||
window.removeEventListener('resize', this.onWindowResize, false);
|
||||
this.canvas = null;
|
||||
this.toolManager.dispose();
|
||||
Generator.resetIDGenerator();
|
||||
};
|
||||
|
||||
isDisposed() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue