mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-08 01:13:27 +01:00
sketcher sub systems split
This commit is contained in:
parent
f325a875c1
commit
4713cc1fc8
38 changed files with 2063 additions and 1190 deletions
|
|
@ -56,6 +56,26 @@ export function addToListInMap(map, key, value) {
|
|||
list.push(value);
|
||||
}
|
||||
|
||||
export function addToSetInMap(map, key, value) {
|
||||
let set = map.get(key);
|
||||
if (!set) {
|
||||
set = new Set();
|
||||
map.set(key, set);
|
||||
}
|
||||
set.add(value);
|
||||
}
|
||||
|
||||
export function removeFromSetInMap(map, key, value) {
|
||||
let set = map.get(key);
|
||||
if (set) {
|
||||
set.delete(value);
|
||||
if (set.size === 0) {
|
||||
map.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function removeInPlace(arr, val) {
|
||||
let index = arr.indexOf(val);
|
||||
if (index !== -1) {
|
||||
|
|
|
|||
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -1153,6 +1153,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@dagrejs/graphlib": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.1.4.tgz",
|
||||
"integrity": "sha512-QCg9sL4uhjn468FDEsb/S9hS2xUZSrv/+dApb1Ze5VKO96pTXKNJZ6MGhIpgWkc1TVhbVGH9/7rq/Mf8/jWicw==",
|
||||
"requires": {
|
||||
"lodash": "^4.11.1"
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.7.11",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz",
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
"webpack-dev-server": "^3.1.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dagrejs/graphlib": "^2.1.4",
|
||||
"classnames": "2.2.5",
|
||||
"clipper-lib": "6.2.1",
|
||||
"diff-match-patch": "1.0.0",
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ function initializeSketcherApplication() {
|
|||
var constrList = new ui.List('constrs', {
|
||||
items : function() {
|
||||
var theItems = [];
|
||||
for (var j = 0; j < pm.subSystems.length; j++) {
|
||||
var sub = pm.subSystems[j];
|
||||
for (var j = 0; j < pm.system.subSystems.length; j++) {
|
||||
var sub = pm.system.subSystems[j];
|
||||
for (var i = 0; i < sub.constraints.length; ++i) {
|
||||
var constr = sub.constraints[i];
|
||||
if (constr.aux !== true && app.constraintFilter[constr.NAME] != true) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as utils from '../../utils/utils'
|
|||
import * as math from '../../math/math'
|
||||
import QR from '../../math/qr'
|
||||
import LMOptimizer from '../../math/lm'
|
||||
import {ConstantWrapper, EqualsTo} from './constraints'
|
||||
import {ConstantWrapper, EqualsTo} from './solverConstraints'
|
||||
import {dog_leg} from '../../math/optim'
|
||||
import {newVector} from '../../math/vec';
|
||||
|
||||
|
|
@ -17,8 +17,8 @@ Param.prototype.reset = function(value) {
|
|||
this.aux = false;
|
||||
};
|
||||
|
||||
Param.prototype.set = function(value) {
|
||||
if (this.aux) return;
|
||||
Param.prototype.set = function(value, force) {
|
||||
if (this.aux && !force) return;
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
|
|
@ -139,7 +139,9 @@ System.prototype.calcGrad = function(out) {
|
|||
var cParams = c.params;
|
||||
var grad = [];
|
||||
utils.fillArray(grad, 0, cParams.length, 0);
|
||||
for (var p = 0; p < cParams.length; p++) {
|
||||
c.gradient(grad);
|
||||
|
||||
for (var p = 0; p < cParams.length; p++) {
|
||||
var param = cParams[p];
|
||||
var j = param.j;
|
||||
out[j] += this.constraints[i].error() * grad[p]; // (10.4)
|
||||
|
|
|
|||
1091
web/app/sketcher/constraints.js
Normal file
1091
web/app/sketcher/constraints.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,7 @@ import Vector from 'math/vector';
|
|||
import exportTextData from 'gems/exportTextData';
|
||||
import NurbsCurve from '../brep/geom/curves/nurbsCurve';
|
||||
import {NurbsObject} from './shapes/nurbsObject';
|
||||
import {System} from './system';
|
||||
|
||||
const Types = {
|
||||
END_POINT : 'TCAD.TWO.EndPoint',
|
||||
|
|
@ -319,8 +320,8 @@ IO.prototype.cleanUpData = function() {
|
|||
}
|
||||
this.viewer.deselectAll();
|
||||
Generator.resetIDGenerator(0);
|
||||
if (this.viewer.parametricManager.subSystems.length != 0) {
|
||||
this.viewer.parametricManager.subSystems = [];
|
||||
if (this.viewer.parametricManager.system.subSystems.length !== 0) {
|
||||
this.viewer.parametricManager.system = new System();
|
||||
this.viewer.parametricManager.notify();
|
||||
}
|
||||
};
|
||||
|
|
@ -386,7 +387,7 @@ IO.prototype._serializeSketch = function() {
|
|||
}
|
||||
|
||||
var constrs = sketch['constraints'] = [];
|
||||
var subSystems = this.viewer.parametricManager.subSystems;
|
||||
var subSystems = this.viewer.parametricManager.system.subSystems;
|
||||
for (var j = 0; j < subSystems.length; j++) {
|
||||
var sub = subSystems[j];
|
||||
for (i = 0; i < sub.constraints.length; ++i) {
|
||||
|
|
|
|||
16
web/app/sketcher/mirror.js
Normal file
16
web/app/sketcher/mirror.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
function mirrorManager() {
|
||||
|
||||
let mirrors = [];
|
||||
|
||||
function add() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function mirrorTool() {
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -3,7 +3,7 @@ import * as math from '../../math/math';
|
|||
import Vector from 'math/vector';
|
||||
import {Ref} from './ref'
|
||||
import {Constraints} from '../parametric'
|
||||
import {SketchObject} from './sketch-object'
|
||||
import {pointIterator, SketchObject} from './sketch-object';
|
||||
|
||||
export class Arc extends SketchObject {
|
||||
|
||||
|
|
@ -20,14 +20,14 @@ export class Arc extends SketchObject {
|
|||
this.r.value = this.distanceA();
|
||||
this.r.obj = this;
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
this.a.collectParams(params);
|
||||
this.b.collectParams(params);
|
||||
this.c.collectParams(params);
|
||||
params.push(this.r);
|
||||
|
||||
visitParams(callback) {
|
||||
this.a.visitParams(callback);
|
||||
this.b.visitParams(callback);
|
||||
this.c.visitParams(callback);
|
||||
callback(this.r);
|
||||
}
|
||||
|
||||
|
||||
getReferencePoint() {
|
||||
return this.c;
|
||||
}
|
||||
|
|
@ -131,6 +131,12 @@ export class Arc extends SketchObject {
|
|||
copy() {
|
||||
return new Arc(this.a.copy(), this.b.copy(), this.c.copy());
|
||||
}
|
||||
|
||||
mirror(dest, mirroringFunc) {
|
||||
this.a.mirror(dest.b, mirroringFunc);
|
||||
this.b.mirror(dest.a, mirroringFunc);
|
||||
this.c.mirror(dest.c, mirroringFunc);
|
||||
}
|
||||
}
|
||||
|
||||
Arc.prototype._class = 'TCAD.TWO.Arc';
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ export class BezierCurve extends SketchObject {
|
|||
}
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
this.a.collectParams(params);
|
||||
this.b.collectParams(params);
|
||||
this.cp1.collectParams(params);
|
||||
this.cp2.collectParams(params);
|
||||
visitParams(callback) {
|
||||
this.a.visitParams(callback);
|
||||
this.b.visitParams(callback);
|
||||
this.cp1.visitParams(callback);
|
||||
this.cp2.visitParams(callback);
|
||||
}
|
||||
|
||||
normalDistance(aim, scale) {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ export class Circle extends SketchObject {
|
|||
this.r = new Ref(0);
|
||||
this.r.obj = this;
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
this.c.collectParams(params);
|
||||
params.push(this.r);
|
||||
|
||||
visitParams(callback) {
|
||||
this.c.visitParams(callback);
|
||||
callback(this.r);
|
||||
}
|
||||
|
||||
getReferencePoint() {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ class LinearDimension extends SketchObject {
|
|||
this.b = b;
|
||||
this.flip = false;
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
|
||||
visitParams(callback) {
|
||||
}
|
||||
|
||||
getReferencePoint() {
|
||||
|
|
@ -164,8 +164,8 @@ export class DiameterDimension extends SketchObject {
|
|||
this.obj = obj;
|
||||
this.angle = Math.PI / 4;
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
|
||||
visitParams(callback) {
|
||||
}
|
||||
|
||||
getReferencePoint() {
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ export class Ellipse extends SketchObject {
|
|||
}
|
||||
return recovered;
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
this.ep1.collectParams(params);
|
||||
this.ep2.collectParams(params);
|
||||
params.push(this.r);
|
||||
|
||||
visitParams(callback) {
|
||||
this.ep1.visitParams(callback);
|
||||
this.ep2.visitParams(callback);
|
||||
callback(this.r);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ export class NurbsObject extends SketchObject {
|
|||
this.bezierPieces = this.calcBezierPiecewise();
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
this.a.collectParams(params);
|
||||
this.b.collectParams(params);
|
||||
visitParams(callback) {
|
||||
this.a.visitParams(callback);
|
||||
this.b.visitParams(callback);
|
||||
}
|
||||
|
||||
normalDistance(aim) {
|
||||
|
|
|
|||
|
|
@ -13,25 +13,25 @@ export class EndPoint extends SketchObject {
|
|||
this._x = new Param(this, 'x');
|
||||
this._y = new Param(this, 'y');
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
params.push(this._x);
|
||||
params.push(this._y);
|
||||
|
||||
visitParams(callback) {
|
||||
callback(this._x);
|
||||
callback(this._y);
|
||||
}
|
||||
|
||||
|
||||
normalDistance(aim) {
|
||||
return aim.minus(new Vector(this.x, this.y)).length();
|
||||
}
|
||||
|
||||
|
||||
getReferencePoint() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
translateImpl(dx, dy) {
|
||||
this.x += dx;
|
||||
this.y += dy;
|
||||
}
|
||||
|
||||
|
||||
drawImpl(ctx, scale) {
|
||||
DrawPoint(ctx, this.x, this.y, 3, scale)
|
||||
}
|
||||
|
|
@ -48,14 +48,20 @@ export class EndPoint extends SketchObject {
|
|||
setFromArray(arr) {
|
||||
this.setXY(arr[0], arr[1]);
|
||||
}
|
||||
|
||||
|
||||
toVector() {
|
||||
return new Vector(this.x, this.y);
|
||||
}
|
||||
|
||||
|
||||
copy() {
|
||||
return new EndPoint(this.x, this.y);
|
||||
}
|
||||
|
||||
mirror(dest, mirroringFunc) {
|
||||
let {x, y} = mirroringFunc(this.x, this.y);
|
||||
dest.x = x;
|
||||
dest.y = y;
|
||||
}
|
||||
}
|
||||
EndPoint.prototype._class = 'TCAD.TWO.EndPoint';
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ export class Segment extends SketchObject {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
this.a.collectParams(params);
|
||||
this.b.collectParams(params);
|
||||
|
||||
visitParams(callback) {
|
||||
this.a.visitParams(callback);
|
||||
this.b.visitParams(callback);
|
||||
}
|
||||
|
||||
normalDistance(aim) {
|
||||
|
|
@ -72,6 +72,16 @@ export class Segment extends SketchObject {
|
|||
// ctx.restore();
|
||||
}
|
||||
|
||||
opposite(endPoint) {
|
||||
if (endPoint === this.a) {
|
||||
return this.b;
|
||||
} else if (endPoint === this.b) {
|
||||
return this.a;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
copy() {
|
||||
return new Segment(this.a.copy(), this.b.copy());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {Generator} from '../id-generator'
|
||||
import {Shape} from './shape'
|
||||
import {Types} from '../io';
|
||||
|
||||
export class SketchObject extends Shape {
|
||||
constructor() {
|
||||
|
|
@ -89,5 +90,47 @@ export class SketchObject extends Shape {
|
|||
copy() {
|
||||
throw 'method not implemented';
|
||||
}
|
||||
|
||||
mirror(dest, mirroringFunc) {
|
||||
|
||||
let sourcePoints = [];
|
||||
|
||||
pointIterator(this, o => {
|
||||
sourcePoints.push(o);
|
||||
});
|
||||
|
||||
let i = 0;
|
||||
pointIterator(dest, o => {
|
||||
sourcePoints[i++].mirror(o, mirroringFunc);
|
||||
});
|
||||
}
|
||||
|
||||
visitParams(callback) {
|
||||
throw 'method not implemented';
|
||||
}
|
||||
|
||||
collectParams(params) {
|
||||
this.visitParams(p => params.push(p));
|
||||
}
|
||||
|
||||
get effectiveLayer() {
|
||||
let shape = this;
|
||||
while (shape) {
|
||||
if (shape.layer) {
|
||||
return shape.layer;
|
||||
}
|
||||
shape = shape.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function pointIterator(shape, func) {
|
||||
shape.accept(o => {
|
||||
if (o._class === Types.END_POINT) {
|
||||
func(o);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ function App2D() {
|
|||
}
|
||||
checkForTerminalVisibility();
|
||||
|
||||
this.registerAction('new', "Create New Sketch", function () {
|
||||
app.newSketch();
|
||||
});
|
||||
|
||||
this.registerAction('terminal', "Open/Close Terminal Window", function () {
|
||||
app.commandsWin.toggle();
|
||||
checkForTerminalVisibility();
|
||||
|
|
@ -214,6 +218,10 @@ function App2D() {
|
|||
app.viewer.parametricManager.p2lDistance(app.viewer.selected, prompt);
|
||||
});
|
||||
|
||||
this.registerAction('mirrorConstraint', "Mirror Constraint", function () {
|
||||
app.viewer.parametricManager.mirror(app.viewer.selected);
|
||||
});
|
||||
|
||||
this.registerAction('P2PDistanceConstraint', "Distance Between two Points", function () {
|
||||
app.viewer.parametricManager.p2pDistance(app.viewer.selected, prompt);
|
||||
});
|
||||
|
|
@ -294,6 +302,10 @@ App2D.views = [
|
|||
{
|
||||
name: 'Constraints',
|
||||
icon: 'cogs'
|
||||
},
|
||||
{
|
||||
name: 'Mirroring',
|
||||
icon: 'mirror'
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ export const Styles = {
|
|||
strokeStyle : "#ffffff",
|
||||
fillStyle : "#000000"
|
||||
},
|
||||
|
||||
VIRTUAL: {
|
||||
lineWidth : 2,
|
||||
strokeStyle : "#ffffff88",
|
||||
fillStyle : "#00000088"
|
||||
},
|
||||
SERVICE : {
|
||||
lineWidth : 0.3,
|
||||
strokeStyle : "#ff0000",
|
||||
|
|
|
|||
290
web/app/sketcher/system.js
Normal file
290
web/app/sketcher/system.js
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
import {addToSetInMap, removeFromSetInMap, removeInPlace} from '../../../modules/gems/iterables';
|
||||
import {ParametricManager} from './parametric';
|
||||
|
||||
|
||||
let SUB_SYSTEM_ORDER = 0;
|
||||
|
||||
class SubSystem {
|
||||
constructor() {
|
||||
this.alg = 1;
|
||||
this.error = 0;
|
||||
this.reduce = false;
|
||||
this.constraints = [];
|
||||
this.dependencies = [];
|
||||
this.nativeParams = new Set();
|
||||
|
||||
this._internaOrder = SUB_SYSTEM_ORDER++;
|
||||
}
|
||||
|
||||
mergeWith(other) {
|
||||
other.constraints.forEach(c => this.constraints.push(c));
|
||||
other.dependencies.forEach(d => {
|
||||
if (this.dependencies.indexOf(d) === -1) {
|
||||
this.dependencies.push(d);
|
||||
}
|
||||
});
|
||||
other.nativeParams.forEach(p => this.nativeParams.add(p));
|
||||
}
|
||||
}
|
||||
|
||||
class Index {
|
||||
|
||||
constructor() {
|
||||
this.constraints = [];
|
||||
this.paramToConstraintsIndex = new Map();
|
||||
this.paramToConstraintsGraph = new Map();
|
||||
this.generatorConstraints = [];
|
||||
this.generatedParams = new Map();
|
||||
}
|
||||
|
||||
_reset() {
|
||||
this.constraints = [];
|
||||
this.paramToConstraintsIndex.clear();
|
||||
this.paramToConstraintsGraph.clear();
|
||||
this.generatorConstraints = [];
|
||||
this.generatedParams.clear();
|
||||
}
|
||||
|
||||
_pushConstraint(constr) {
|
||||
this.constraints.push(constr);
|
||||
visitParams(constr, true, p => addToSetInMap(this.paramToConstraintsGraph, p, constr));
|
||||
visitParams(constr, false, p => addToSetInMap(this.paramToConstraintsIndex, p, constr));
|
||||
if (constr.GENERATOR) {
|
||||
this.generatorConstraints.push(constr);
|
||||
constr.visitGeneratedParams(p => this.generatedParams.set(p, constr));
|
||||
}
|
||||
}
|
||||
|
||||
_popConstraint(constr) {
|
||||
|
||||
removeInPlace(this.constraints, constr);
|
||||
|
||||
visitParams(constr, true, p => removeFromSetInMap(this.paramToConstraintsGraph, p, constr));
|
||||
visitParams(constr, false, p => removeFromSetInMap(this.paramToConstraintsIndex, p, constr));
|
||||
|
||||
if (constr.GENERATOR) {
|
||||
removeInPlace(this.generatorConstraints, constr);
|
||||
constr.visitGeneratedParams(p => this.generatedParams.delete(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class System extends Index{
|
||||
constructor() {
|
||||
super();
|
||||
this.subSystems = [];
|
||||
this.constraintToSubSystem = new Map();
|
||||
this.paramToSubSystem = new Map();
|
||||
}
|
||||
|
||||
_reset() {
|
||||
super._reset();
|
||||
this.subSystems = [];
|
||||
this.constraintToSubSystem.clear();
|
||||
this.paramToSubSystem.clear();
|
||||
}
|
||||
|
||||
_collectDependenciesForSubSystemFromConstraint(subSystem, constr) {
|
||||
visitParams(constr, false, p => {
|
||||
let generator = this.generatedParams.get(p);
|
||||
if (generator) {
|
||||
let generatorSS = this.constraintToSubSystem.get(generator);
|
||||
if (generatorSS) {
|
||||
if (subSystem.dependencies.indexOf(generatorSS) === -1) {
|
||||
subSystem.dependencies.push(generatorSS);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_rebuildDependencies() {
|
||||
this.subSystems.forEach(ss => {
|
||||
if (ss.dependencies.length !== 0) {
|
||||
ss.dependencies = [];
|
||||
}
|
||||
});
|
||||
this.subSystems.forEach(subSystem => {
|
||||
subSystem.constraints.forEach(constr => {
|
||||
this._collectDependenciesForSubSystemFromConstraint(subSystem, constr);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_groupBySubsystems() {
|
||||
|
||||
if (this.subSystems.length !== 0) {
|
||||
this.subSystems = [];
|
||||
}
|
||||
this.constraintToSubSystem.clear();
|
||||
|
||||
const visited = new Set();
|
||||
this.constraints.forEach(constr => {
|
||||
if (visited.has(constr)) {
|
||||
return;
|
||||
}
|
||||
const subSystem = this.createSubSystem();
|
||||
|
||||
const stack = [constr];
|
||||
while (stack.length) {
|
||||
let workingConstr = stack.pop();
|
||||
if (visited.has(workingConstr)) {
|
||||
continue;
|
||||
}
|
||||
this._assignConstraint(workingConstr, subSystem);
|
||||
|
||||
visited.add(workingConstr);
|
||||
visitParams(workingConstr, true, p => {
|
||||
const constrs = this.paramToConstraintsGraph.get(p);
|
||||
if (constrs) {
|
||||
constrs.forEach(constrToAdvance => {
|
||||
if (constrToAdvance !== workingConstr) {
|
||||
stack.push(constrToAdvance);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
_rebuild() {
|
||||
this._groupBySubsystems();
|
||||
this._rebuildDependencies();
|
||||
}
|
||||
|
||||
_assignConstraint(constr, subSystem) {
|
||||
subSystem.constraints.push(constr);
|
||||
this.constraintToSubSystem.set(constr, subSystem);
|
||||
}
|
||||
|
||||
add(constr) {
|
||||
constr.id = "C_" + (COUNTER ++) ; //fixme
|
||||
let affectedSubsystems = new Set();
|
||||
let freeParams = [];
|
||||
|
||||
visitParams(constr, false, p => {
|
||||
|
||||
let subSystem = this.paramToSubSystem.get(p);
|
||||
|
||||
if (subSystem) {
|
||||
affectedSubsystems.add(subSystem);
|
||||
} else {
|
||||
if (!isAuxParam(p) && !this.generatedParams.has(p)) {
|
||||
freeParams.push(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
affectedSubsystems.forEach(ss => {
|
||||
ss.dependencies.forEach(d => affectedSubsystems.delete(d));
|
||||
});
|
||||
|
||||
let toMerge = Array.from(affectedSubsystems).sort((a, b) => a._internaOrder - b._internaOrder);
|
||||
let master;
|
||||
if (toMerge.length === 0 ) {
|
||||
console.error("system has circular dependencies");
|
||||
master = this.createSubSystem();
|
||||
} else {
|
||||
[master, ...toMerge] = toMerge;
|
||||
}
|
||||
|
||||
toMerge.forEach(s => {
|
||||
master.mergeWith(s);
|
||||
s.nativeParams.forEach(p => this.paramToSubSystem.set(p, master));
|
||||
removeInPlace(this.subSystems, s);
|
||||
});
|
||||
|
||||
freeParams.forEach(p => {
|
||||
master.nativeParams.add(p);
|
||||
this.paramToSubSystem.set(p, master)
|
||||
});
|
||||
|
||||
master.constraints.push(constr);
|
||||
this.constraintToSubSystem.set(constr, master);
|
||||
if (constr.GENERATOR) {
|
||||
let dependant = this.createSubSystem();
|
||||
dependant.dependencies.push(master);
|
||||
constr.visitGeneratedParams(p => {
|
||||
this.generatedParams.set(p, constr)
|
||||
this.paramToSubSystem.set(p, dependant);
|
||||
});
|
||||
}
|
||||
|
||||
this._pushConstraint(constr);
|
||||
|
||||
}
|
||||
|
||||
remove(constr) {
|
||||
removeInPlace(this.constraints, constr);
|
||||
this.setConstraints(this.constraints);
|
||||
}
|
||||
|
||||
setConstraints(constraints) {
|
||||
this._reset();
|
||||
constraints.forEach(c => this.add(c));
|
||||
}
|
||||
|
||||
subSystemsByParam(param, callback) {
|
||||
let constraints = this.paramToConstraintsIndex.get(param);
|
||||
if (constraints) {
|
||||
constraints.forEach(c => callback(this.constraintToSubSystem.get(c)));
|
||||
}
|
||||
}
|
||||
|
||||
traverse(callback, onCircular) {
|
||||
const visited = new Set();
|
||||
const loop = new Set();
|
||||
|
||||
function doVisit(subSystem) {
|
||||
if (loop.has(subSystem)) {
|
||||
onCircular(subSystem);
|
||||
return;
|
||||
}
|
||||
loop.add(subSystem);
|
||||
subSystem.dependencies.forEach(dep => {
|
||||
if (!visited.has(dep)) {
|
||||
doVisit(dep);
|
||||
}
|
||||
});
|
||||
|
||||
callback(subSystem);
|
||||
visited.add(subSystem);
|
||||
loop.delete(subSystem)
|
||||
}
|
||||
this.subSystems.forEach(doVisit);
|
||||
}
|
||||
|
||||
createSubSystem() {
|
||||
const subSystem = new SubSystem();
|
||||
this.subSystems.push(subSystem);
|
||||
return subSystem;
|
||||
}
|
||||
}
|
||||
|
||||
function visitParams(constraint, skipAux, callback) {
|
||||
if (skipAux) {
|
||||
let delegate = callback;
|
||||
callback = p => {
|
||||
if (!isAuxParam(p)) {
|
||||
delegate(p)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (constraint.visitParams) {
|
||||
constraint.visitParams(callback);
|
||||
} else {
|
||||
constraint.getSolveData().forEach(([, sParams]) => sParams.forEach(callback));
|
||||
}
|
||||
}
|
||||
|
||||
function isAuxParam(param) {
|
||||
return ParametricManager.isAux(param.obj, GOT_NOTHING);
|
||||
}
|
||||
|
||||
const GOT_NOTHING = {
|
||||
has: () => false
|
||||
};
|
||||
|
||||
let COUNTER = 0;
|
||||
|
|
@ -34,7 +34,6 @@ export class EditCircleTool extends Tool {
|
|||
solveRequest(rough) {
|
||||
this.solver = this.viewer.parametricManager.prepare([this.circle.r]);
|
||||
this.solver.solve(rough, 1);
|
||||
this.solver.sync();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ export class DragTool extends Tool {
|
|||
|
||||
solveRequest(rough) {
|
||||
this.solver.solve(rough, 1);
|
||||
this.solver.sync();
|
||||
|
||||
var paramsToUpdate = [];
|
||||
this.viewer.accept(function (obj) {
|
||||
|
|
@ -72,7 +71,6 @@ export class DragTool extends Tool {
|
|||
this.solver.updateParameter(paramsToUpdate[i]);
|
||||
}
|
||||
this.solver.solve(rough, 1);
|
||||
this.solver.sync();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,5 @@ export class EllipseTool extends Tool {
|
|||
solveRequest(rough) {
|
||||
this.solver = this.viewer.parametricManager.prepare([this.ellipse.r]);
|
||||
this.solver.solve(rough, 1);
|
||||
this.solver.sync();
|
||||
}
|
||||
}
|
||||
|
|
@ -67,11 +67,20 @@ export class FilletTool extends Tool {
|
|||
point1.parent.layer.add(arc);
|
||||
var pm = this.viewer.parametricManager;
|
||||
arc.stabilize(this.viewer);
|
||||
pm._add(new Constraints.Tangent( arc, point1.parent));
|
||||
pm._add(new Constraints.Tangent( arc, point2.parent));
|
||||
pm._add(new Constraints.Coincident( arc.a, point1));
|
||||
pm._add(new Constraints.Coincident( arc.b, point2));
|
||||
|
||||
pm._add(new Constraints.Fillet( point1, point2, arc));
|
||||
|
||||
this.viewer.validators.push(() => {
|
||||
function validOn(p, left) {
|
||||
let op = p.parent.opposite(p);
|
||||
let opV = op.toVector();
|
||||
let dir = p.toVector()._minus(opV)._normalize();
|
||||
let centerDir = arc.c.toVector()._minus(opV)._normalize();
|
||||
let z = centerDir.cross(dir).z;
|
||||
|
||||
return left ? z < 0.1 : z > -0.1;
|
||||
}
|
||||
return validOn(point1, true) && validOn(point2, false);
|
||||
});
|
||||
//function otherEnd(point) {
|
||||
// if (point.parent.a.id === point.id) {
|
||||
// return point.parent.b;
|
||||
|
|
@ -114,15 +123,18 @@ export class FilletTool extends Tool {
|
|||
}
|
||||
|
||||
getCandidate(e) {
|
||||
var picked = this.viewer.pick(e);
|
||||
|
||||
let preferSketchLayer = (a, b) => (a.effectiveLayer === b.effectiveLayer)? 0 : a.effectiveLayer.name === 'sketch' ? -1 : 1;
|
||||
|
||||
let picked = this.viewer.pick(e);
|
||||
if (picked.length > 0) {
|
||||
var res = fetch.sketchObjects(picked, true, ['TCAD.TWO.EndPoint']);
|
||||
let res = fetch.sketchObjects(picked, true, ['TCAD.TWO.EndPoint']);
|
||||
if (res == null) return null;
|
||||
var point1 = res[0];
|
||||
let point1 = res.sort(preferSketchLayer)[0];
|
||||
if (!FilletTool.isLine(point1.parent)) return;
|
||||
var line2 = null;
|
||||
for (var i = 0; i < point1.linked.length; i++) {
|
||||
var point2 = point1.linked[i];
|
||||
let linked = [...point1.linked].sort(preferSketchLayer);
|
||||
for (let i = 0; i < linked.length; i++) {
|
||||
let point2 = linked[i];
|
||||
if (FilletTool.isLine(point2.parent)) {
|
||||
return [point1, point2];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,9 +50,7 @@ export class ToolManager {
|
|||
} else if (e.keyCode === 46 || e.keyCode === 8) {
|
||||
let selection = viewer.selected.slice();
|
||||
viewer.deselectAll();
|
||||
for (let i = 0; i < selection.length; i++) {
|
||||
viewer.remove(selection[i]);
|
||||
}
|
||||
viewer.removeAll(selection);
|
||||
viewer.refresh();
|
||||
}
|
||||
}, false);
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ function Viewer(canvas, IO) {
|
|||
this.historyManager = new HistoryManager(this);
|
||||
this.transformation = null;
|
||||
this.screenToModelMatrix = null;
|
||||
this.validators = [];
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +119,11 @@ Viewer.prototype.addSegment = function(x1, y1, x2, y2, layer) {
|
|||
};
|
||||
|
||||
Viewer.prototype.remove = function(obj) {
|
||||
if (obj.layer != null) {
|
||||
if (obj.layer.remove(obj)) {
|
||||
this.parametricManager.removeConstraintsByObj(obj);
|
||||
}
|
||||
}
|
||||
this.removeAll([obj]);
|
||||
};
|
||||
|
||||
Viewer.prototype.removeAll = function(objects) {
|
||||
this.parametricManager.removeObjects(objects);
|
||||
};
|
||||
|
||||
Viewer.prototype.add = function(obj, layer) {
|
||||
|
|
@ -470,7 +471,8 @@ function Layer(name, style) {
|
|||
this.name = name;
|
||||
this.style = style;
|
||||
this.stylesByRoles = {
|
||||
'construction': Styles.CONSTRUCTION_OF_OBJECT
|
||||
'construction': Styles.CONSTRUCTION_OF_OBJECT,
|
||||
'virtual': Styles.VIRTUAL
|
||||
};
|
||||
this.objects = [];
|
||||
this.readOnly = false; // This is actually a mark for boundary layers coming from 3D
|
||||
|
|
|
|||
|
|
@ -45,8 +45,9 @@
|
|||
|
||||
<div id="dock" class="panel b-right scroll" style="float: left; width: 245px; height: 100%;"></div>
|
||||
<div id="right-toolbar" class="panel b-left scroll" style="width: 50px; float: right; height: 100%; ">
|
||||
<div style="width:50%; height: 2px"></div>
|
||||
<div style="width:50%; height: 2px"></div>
|
||||
<button class="btn rbtn act-coincident" style="background-image: url(img/coi.png);"></button>
|
||||
<button class="btn rbtn act-mirrorConstraint" style="background-image: url(img/coi.png);"></button>
|
||||
<button class="btn rbtn act-verticalConstraint" style="background-image: url(img/vert.png);"></button>
|
||||
<button class="btn rbtn act-horizontalConstraint" style="background-image: url(img/hor.png);"></button>
|
||||
<button class="btn rbtn act-parallelConstraint" style="background-image: url(img/par.png);"></button>
|
||||
|
|
|
|||
216
web/test/cases/solveSystems.js
Normal file
216
web/test/cases/solveSystems.js
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
import {assertEquals, assertFalse, assertTrue} from '../utils/asserts';
|
||||
import {NOOP} from '../../../modules/gems/func';
|
||||
|
||||
export const TEST_MODE = 'sketcherUI';
|
||||
|
||||
export function testEqualConstraints(env, ui) {
|
||||
|
||||
ui.addRectangle(10, 10, 100, 100);
|
||||
|
||||
assertEquals(4, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(4, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
export function testBuildGraphBasics(env, ui) {
|
||||
|
||||
const seg1 = ui.addSegment(10, 10, 10, 100);
|
||||
const seg2 = ui.addSegment(200, 10, 200, 100);
|
||||
ui.select([seg1, seg2]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
|
||||
|
||||
const seg3 = ui.addSegment(500, 10, 500, 100);
|
||||
const seg4 = ui.addSegment(700, 10, 700, 100);
|
||||
ui.select([seg3, seg4]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
assertEquals(2, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(2, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems[1].constraints.length);
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
export function testThreeConnectedConstraints(env, ui) {
|
||||
|
||||
const seg1 = ui.addSegment(10, 10, 10, 100);
|
||||
const seg2 = ui.addSegment(200, 10, 200, 100);
|
||||
ui.select([seg1, seg2]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
|
||||
|
||||
const seg3 = ui.addSegment(500, 10, 500, 100);
|
||||
const seg4 = ui.addSegment(700, 10, 700, 100);
|
||||
ui.select([seg3, seg4]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
assertEquals(2, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(2, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems[1].constraints.length);
|
||||
|
||||
ui.select([seg2, seg3]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(3, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(3, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
export function testIgnoreBoundaries(env, ui) {
|
||||
|
||||
const boundary = ui.addSegment(500, 10, 500, 100);
|
||||
boundary.aux = true;
|
||||
|
||||
const seg1 = ui.addSegment(100, 10, 100, 100);
|
||||
ui.select([seg1, boundary]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
const seg2 = ui.addSegment(700, 10, 700, 100);
|
||||
ui.select([seg1, boundary]);
|
||||
|
||||
ui.select([seg1, boundary]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(2, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(2, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
export function testMirroring(env, ui) {
|
||||
|
||||
const seg1 = ui.addSegment(10, 10, 10, 100);
|
||||
const seg2 = ui.addSegment(200, 10, 200, 100);
|
||||
|
||||
ui.select([seg2, seg1]);
|
||||
ui.runAction('mirrorConstraint');
|
||||
const seg3 = ui.viewer.parametricManager.system.constraints[0].reflectedObjects[0];
|
||||
const seg4 = ui.addSegment(600, 10, 600, 100);
|
||||
ui.select([seg4, seg3]);
|
||||
ui.runAction('mirrorConstraint');
|
||||
|
||||
let system = ui.viewer.parametricManager.system;
|
||||
let subSystems = ui.viewer.parametricManager.system.subSystems;
|
||||
assertEquals(3, subSystems.length);
|
||||
const subSystem0 = system.constraintToSubSystem.get(system.constraints[0]);
|
||||
const subSystem1 = system.constraintToSubSystem.get(system.constraints[1]);
|
||||
assertTrue( subSystem1.dependencies[0] === subSystem0, "Second subsystem depends on first one");
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
export function testCircularDependencies(env, ui) {
|
||||
|
||||
const seg1 = ui.addSegment(10, 10, 10, 100);
|
||||
const seg2 = ui.addSegment(200, 10, 200, 100);
|
||||
|
||||
ui.select([seg2, seg1]);
|
||||
ui.runAction('mirrorConstraint');
|
||||
const seg3 = ui.viewer.parametricManager.system.constraints[0].reflectedObjects[0];
|
||||
const seg4 = ui.addSegment(600, 10, 600, 100);
|
||||
ui.select([seg4, seg3]);
|
||||
ui.runAction('mirrorConstraint');
|
||||
|
||||
|
||||
let seg5 = ui.viewer.parametricManager.system.constraints[1].reflectedObjects[0];
|
||||
ui.select([seg5, seg1]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
let isCircular = false;
|
||||
ui.viewer.parametricManager.system.traverse(NOOP, () => isCircular = true);
|
||||
|
||||
assertEquals(2, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertTrue(isCircular, "System should contain circular depending subsystems");
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
|
||||
export function testSimpleRemove(env, ui) {
|
||||
|
||||
const seg1 = ui.addSegment(10, 10, 10, 100);
|
||||
const seg2 = ui.addSegment(200, 10, 200, 100);
|
||||
ui.select([seg1, seg2]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
const seg3 = ui.addSegment(500, 10, 500, 100);
|
||||
const seg4 = ui.addSegment(700, 10, 700, 100);
|
||||
ui.select([seg3, seg4]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
|
||||
ui.select([seg2, seg3]);
|
||||
ui.runAction('parallelConstraint');
|
||||
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(3, ui.viewer.parametricManager.system.constraints.length);
|
||||
assertEquals(3, ui.viewer.parametricManager.system.subSystems[0].constraints.length);
|
||||
|
||||
ui.select([]);
|
||||
ui.viewer.remove(seg1);
|
||||
|
||||
assertEquals(1, ui.viewer.parametricManager.system.subSystems.length);
|
||||
assertEquals(2, ui.viewer.parametricManager.system.constraints.length);
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
export function testMirroringRemove(env, ui) {
|
||||
|
||||
const seg1 = ui.addSegment(10, 10, 10, 100);
|
||||
const seg2 = ui.addSegment(200, 10, 200, 100);
|
||||
|
||||
ui.select([seg2, seg1]);
|
||||
ui.runAction('mirrorConstraint');
|
||||
const seg3 = ui.viewer.parametricManager.system.constraints[0].reflectedObjects[0];
|
||||
const seg4 = ui.addSegment(600, 10, 600, 100);
|
||||
ui.select([seg4, seg3]);
|
||||
ui.runAction('mirrorConstraint');
|
||||
|
||||
assertEquals(3, ui.viewer.parametricManager.system.subSystems.length);
|
||||
ui.viewer.remove(seg1);
|
||||
assertEquals(0, ui.viewer.parametricManager.system.subSystems.length);
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
||||
export function testDoubleAngle(env, ui) {
|
||||
|
||||
const seg1 = ui.addSegment(100, 100, 100, 200);
|
||||
const seg2 = ui.addSegment(100, 200, 200, 200);
|
||||
const seg3 = ui.addSegment(10, 10, 300, 10);
|
||||
|
||||
ui.select([seg3, seg2, seg1]);
|
||||
|
||||
ui.runAction('mirrorConstraint');
|
||||
|
||||
const [seg4, seg5] = ui.viewer.parametricManager.system.constraints[1].reflectedObjects;
|
||||
const seg6 = ui.addSegment(300, -200, 300, 300);
|
||||
|
||||
ui.select([seg6, seg5, seg4, seg2, seg1]);
|
||||
|
||||
ui.runAction('mirrorConstraint');
|
||||
|
||||
let isCircular = false;
|
||||
ui.viewer.parametricManager.system.traverse(NOOP, () => isCircular = true);
|
||||
|
||||
assertFalse(isCircular, "shouldn't be circular");
|
||||
|
||||
env.done();
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import * as test from './test';
|
||||
import modellerUISubject from './utils/subjects/modeller/modellerUISubject';
|
||||
import {createSketcherSubject} from './utils/subjects/modeller/sketcherUISubject';
|
||||
|
||||
export const modellerUI = func => env => {
|
||||
test.emptyModeller(env.test(win => {
|
||||
|
|
@ -8,3 +9,9 @@ export const modellerUI = func => env => {
|
|||
}));
|
||||
};
|
||||
|
||||
export const sketcherUI = func => env => {
|
||||
test.emptySketch(env.test((win, app) => {
|
||||
let subject = createSketcherSubject(app);
|
||||
func(env, subject);
|
||||
}));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<title></title>
|
||||
<script src="../static/test_runner.bundle.js"></script>
|
||||
<link rel="stylesheet" href="../lib/font-awesome/css/font-awesome.min.css?modeler">
|
||||
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
||||
</head>
|
||||
<body>
|
||||
<div id="control-bar" class="page-row">
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ body {
|
|||
width: 70%;
|
||||
height: 70%;
|
||||
background-color: #233930;
|
||||
//visibility: hidden;
|
||||
}
|
||||
|
||||
#test-list {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export default {
|
|||
SketcherSolver: [
|
||||
TestCase('constraints'),
|
||||
TestCase('parametric'),
|
||||
TestCase('solveSystems'),
|
||||
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
export function FailError(msg) {
|
||||
this.msg = msg;
|
||||
this.stack = (new Error()).stack;
|
||||
export function createFailError(msg) {
|
||||
let error = new Error(msg);
|
||||
error.assertionFail = true;
|
||||
return error;
|
||||
}
|
||||
|
||||
export class TestEnv {
|
||||
|
|
@ -27,7 +28,7 @@ export class TestEnv {
|
|||
this.failed = true;
|
||||
this.error = msg + (optionalMsg === undefined ? '' : ' ' + optionalMsg);
|
||||
this.done();
|
||||
throw new FailError(this.error);
|
||||
throw createFailError(this.error);
|
||||
}
|
||||
|
||||
terminateOnError(error) {
|
||||
|
|
@ -46,8 +47,7 @@ export class TestEnv {
|
|||
if (!env.finished) {
|
||||
env.terminateOnError(e);
|
||||
}
|
||||
console.error(e.stack);
|
||||
throw e;
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
import {FailError} from '../test';
|
||||
import {createFailError} from '../test';
|
||||
import sketchObjectGlobalId from '../../app/cad/sketch/sketchObjectGlobalId';
|
||||
|
||||
export function fail(msg, optionalMsg) {
|
||||
throw new FailError(msg + (optionalMsg === undefined ? '' : ' ' + optionalMsg));
|
||||
throw createFailError(msg + (optionalMsg === undefined ? '' : ' ' + optionalMsg));
|
||||
}
|
||||
|
||||
export function assertTrue(stmt, msg) {
|
||||
if (typeof stmt === 'string') {
|
||||
throw 'wrong assertion usage, mixed up arguments';
|
||||
}
|
||||
if (!stmt) {
|
||||
fail('assertTrue fails.', msg);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertEmpty(array, msg) {
|
||||
if (typeof stmt === 'string') {
|
||||
throw 'wrong assertion usage, mixed up arguments';
|
||||
}
|
||||
if (array.length !== 0) {
|
||||
fail('assertEmpty fails. Array length = ' + array.length, msg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,7 @@ export function toModelP(app, point) {
|
|||
}
|
||||
|
||||
export function getConstraints(app) {
|
||||
const subSystems = app.viewer.parametricManager.subSystems;
|
||||
if (subSystems.length == 0) {
|
||||
return [];
|
||||
}
|
||||
return subSystems[0].constraints;
|
||||
return app.viewer.parametricManager.system.constraints;
|
||||
}
|
||||
|
||||
export function click(app, point, attrs) {
|
||||
|
|
@ -170,10 +166,11 @@ export class TestSegment {
|
|||
}
|
||||
}
|
||||
|
||||
function modelToScreen(viewer, x, y) {
|
||||
|
||||
let modelToScreenMx = viewer.screenToModelMatrix.invert();
|
||||
[x, y] = modelToScreenMx.apply3([x, y, 0]);
|
||||
export function modelToScreen(viewer, x, y) {
|
||||
if (viewer.screenToModelMatrix) {
|
||||
let modelToScreenMx = viewer.screenToModelMatrix.invert();
|
||||
[x, y] = modelToScreenMx.apply3([x, y, 0]);
|
||||
}
|
||||
x /= viewer.retinaPxielRatio;
|
||||
y = (viewer.canvas.height - y) / viewer.retinaPxielRatio;
|
||||
return [x, y];
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import genSerpinski, {genSerpinskiImpl} from '../../../../app/utils/genSerpinski
|
|||
import {distance, distanceAB} from '../../../../app/math/math';
|
||||
|
||||
export function createSubjectFromInPlaceSketcher(ctx) {
|
||||
|
||||
let actions = {};
|
||||
for (const actionId of Object.keys(ctx.streams.action.state)) {
|
||||
if (actionId.startsWith('sketch')) {
|
||||
|
|
@ -15,19 +14,27 @@ export function createSubjectFromInPlaceSketcher(ctx) {
|
|||
actions.addBezierCurve = actions.addCubicBezierSpline;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const oldStyleSketcherApp = {
|
||||
viewer: ctx.services.sketcher.inPlaceEditor.viewer,
|
||||
actions
|
||||
};
|
||||
|
||||
return createSketcherSubject(oldStyleSketcherApp);
|
||||
}
|
||||
|
||||
const addSegment = sketcher_utils.addSegmentInModel.bind(this, oldStyleSketcherApp);
|
||||
const addArc = sketcher_utils.addArc.bind(this, oldStyleSketcherApp);
|
||||
const addCircle = sketcher_utils.addCircle.bind(this, oldStyleSketcherApp);
|
||||
const addEllipse = sketcher_utils.addEllipse.bind(this, oldStyleSketcherApp);
|
||||
const addEllipticalArc = sketcher_utils.addEllipticalArc.bind(this, oldStyleSketcherApp);
|
||||
const addBezier = sketcher_utils.addBezier.bind(this, oldStyleSketcherApp);
|
||||
const move = sketcher_utils.moveInModel.bind(this, oldStyleSketcherApp);
|
||||
export function createSketcherSubject(sketcherApp) {
|
||||
|
||||
const viewer = sketcherApp.viewer;
|
||||
viewer.parametricManager.messageSink = msg => console.log(msg);
|
||||
|
||||
const addSegment = sketcher_utils.addSegmentInModel.bind(this, sketcherApp);
|
||||
const addArc = sketcher_utils.addArc.bind(this, sketcherApp);
|
||||
const addCircle = sketcher_utils.addCircle.bind(this, sketcherApp);
|
||||
const addEllipse = sketcher_utils.addEllipse.bind(this, sketcherApp);
|
||||
const addEllipticalArc = sketcher_utils.addEllipticalArc.bind(this, sketcherApp);
|
||||
const addBezier = sketcher_utils.addBezier.bind(this, sketcherApp);
|
||||
const move = sketcher_utils.moveInModel.bind(this, sketcherApp);
|
||||
function addRectangle(x0, y0, x1, y1) {
|
||||
return [
|
||||
addSegment(x0, y0, x1, y0),
|
||||
|
|
@ -38,7 +45,7 @@ export function createSubjectFromInPlaceSketcher(ctx) {
|
|||
}
|
||||
|
||||
function addSerpinski(ax, ay, bx, by, depth) {
|
||||
genSerpinskiImpl(ctx.services.sketcher.inPlaceEditor.viewer, {x: ax, y: ay}, {x: bx, y: by}, depth);
|
||||
genSerpinskiImpl(viewer, {x: ax, y: ay}, {x: bx, y: by}, depth);
|
||||
let jointWidth = distance(ax, ay, bx, by) / (depth + 1) / 2;
|
||||
let dx = bx - ax;
|
||||
let dy = by - ay;
|
||||
|
|
@ -47,7 +54,7 @@ export function createSubjectFromInPlaceSketcher(ctx) {
|
|||
dy /= D;
|
||||
let ddx = -dy * jointWidth;
|
||||
let ddy = dx * jointWidth;
|
||||
genSerpinskiImpl(ctx.services.sketcher.inPlaceEditor.viewer, {x: bx-ddx, y: by-ddy}, {x: ax-ddx, y: ay-ddy}, depth);
|
||||
genSerpinskiImpl(viewer, {x: bx-ddx, y: by-ddy}, {x: ax-ddx, y: ay-ddy}, depth);
|
||||
addSegment(ax, ay, ax-ddx, ay-ddy);
|
||||
addSegment(bx, by, bx-ddx, by-ddy);
|
||||
}
|
||||
|
|
@ -62,7 +69,7 @@ export function createSubjectFromInPlaceSketcher(ctx) {
|
|||
}
|
||||
|
||||
function changeLayer(layerName) {
|
||||
ctx.services.sketcher.inPlaceEditor.viewer.setActiveLayerName(layerName);
|
||||
viewer.setActiveLayerName(layerName);
|
||||
}
|
||||
|
||||
function changeToConstructionLayer() {
|
||||
|
|
@ -73,9 +80,24 @@ export function createSubjectFromInPlaceSketcher(ctx) {
|
|||
changeLayer('sketch');
|
||||
}
|
||||
|
||||
function click(modelX, modelY, attrs) {
|
||||
let [x, y] = sketcher_utils.modelToScreen(viewer, modelX, modelY);
|
||||
sketcher_utils.clickXY(sketcherApp, x, y, attrs);
|
||||
}
|
||||
|
||||
function select(objects, inclusive) {
|
||||
sketcherApp.viewer.select(objects, !inclusive);
|
||||
}
|
||||
|
||||
function runAction(id) {
|
||||
sketcherApp.actions[id].action();
|
||||
}
|
||||
|
||||
return {
|
||||
addSegment, addRectangle, addArc, addCircle, addEllipse, addEllipticalArc, addSerpinski, addBezier, addPolygon,
|
||||
move, changeLayer, changeToConstructionLayer, changeToDefaultLayer
|
||||
move, changeLayer, changeToConstructionLayer, changeToDefaultLayer,
|
||||
click, select, runAction,
|
||||
viewer
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -31,6 +31,20 @@ module.exports = {
|
|||
extensions: ['.js', '.jsx'],
|
||||
modules: [MODULES, "node_modules"]
|
||||
},
|
||||
devServer: {
|
||||
hot: false,
|
||||
inline: false,
|
||||
before: function(app) {
|
||||
app.get('*.wasm', function(req, res) {
|
||||
res.sendFile(req.url, {
|
||||
root: path.join(__dirname, 'web'),
|
||||
headers: {
|
||||
'Content-Type': 'application/wasm'
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.(js|jsx)$/,
|
||||
|
|
@ -45,39 +59,25 @@ module.exports = {
|
|||
'less-loader',
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(less|css)$/,
|
||||
include: [MODULES, WEB_APP],
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
getLocalIdent: (context, localIdentName, localName) => generateCSSScopedName(localName, context.resourcePath),
|
||||
modules: true,
|
||||
url: false
|
||||
}
|
||||
},
|
||||
'less-loader'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
use: 'handlebars-loader?helperDirs[]=' + __dirname + '/web/app/ui/helpers'
|
||||
}]
|
||||
},
|
||||
devServer: {
|
||||
hot: false,
|
||||
inline: false,
|
||||
before: function(app) {
|
||||
app.get('*.wasm', function(req, res) {
|
||||
res.sendFile(req.url, {
|
||||
root: path.join(__dirname, 'web'),
|
||||
headers: {
|
||||
'Content-Type': 'application/wasm'
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
{
|
||||
test: /\.(less|css)$/,
|
||||
include: [MODULES, WEB_APP],
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
getLocalIdent: (context, localIdentName, localName) => generateCSSScopedName(localName, context.resourcePath),
|
||||
modules: true,
|
||||
url: false
|
||||
}
|
||||
},
|
||||
'less-loader'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
use: 'handlebars-loader?helperDirs[]=' + __dirname + '/web/app/ui/helpers'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue