approach to modifiers

This commit is contained in:
Val Erastov (xibyte) 2020-01-30 21:23:38 -08:00
parent 79bbe7a4c3
commit d52d3a565d
19 changed files with 239 additions and 126 deletions

View file

@ -2,7 +2,7 @@ import {AlgNumConstraint, ConstraintDefinitions} from "../constr/ANConstraints";
import {EndPoint} from "../shapes/point";
import {Circle} from "../shapes/circle";
import {Segment} from "../shapes/segment";
import {matchAll, matchTypes, sortSelectionByType} from "./matchUtils";
import {isInstanceOf, matchAll, matchTypes, sortSelectionByType} from "./matchUtils";
import constraints from "../../../test/cases/constraints";
export default [
@ -18,11 +18,11 @@ export default [
const [first, ...others] = viewer.selected;
let pm = viewer.parametricManager;
for (let obj of others) {
pm.algnNumSystem.addConstraint(
pm._add(
new AlgNumConstraint(ConstraintDefinitions.PCoincident, [first, obj])
);
}
pm.refresh();
pm.commit();
}
},
@ -39,8 +39,7 @@ export default [
const constraint = new AlgNumConstraint(ConstraintDefinitions.TangentLC, [line, circle]);
constraint.initConstants();
const pm = viewer.parametricManager;
pm.algnNumSystem.addConstraint(constraint);
pm.refresh();
pm.add(constraint);
}
},
@ -54,7 +53,7 @@ export default [
const {viewer} = ctx;
const [pt, line] = sortSelectionByType(viewer.selected);
let pm = viewer.parametricManager;
pm.algnNumSystem.addConstraint(new AlgNumConstraint(ConstraintDefinitions.PointOnLine, [pt, line]));
pm.add(new AlgNumConstraint(ConstraintDefinitions.PointOnLine, [pt, line]));
}
},
@ -73,11 +72,11 @@ export default [
editConstraint(ctx, firstConstr, () => {
const pm = viewer.parametricManager;
pm.algnNumSystem.addConstraint(firstConstr);
pm._add(firstConstr);
for (let i = 1; i < viewer.selected.length; ++i) {
pm.algnNumSystem.addConstraint(new AlgNumConstraint(ConstraintDefinitions.Angle, [viewer.selected[i]], {...firstConstr.constants}));
pm._add(new AlgNumConstraint(ConstraintDefinitions.Angle, [viewer.selected[i]], {...firstConstr.constants}));
}
pm.refresh();
pm.commit();
});
}
},
@ -97,12 +96,12 @@ export default [
editConstraint(ctx, firstConstr, () => {
const pm = viewer.parametricManager;
pm.algnNumSystem.addConstraint(firstConstr);
pm._add(firstConstr);
for (let i = 2; i < viewer.selected.length; ++i) {
pm.algnNumSystem.addConstraint(new AlgNumConstraint(ConstraintDefinitions.Angle,
pm._add(new AlgNumConstraint(ConstraintDefinitions.Angle,
[viewer.selected[i-1], viewer.selected[i]], {...firstConstr.constants}));
}
pm.refresh();
pm.commit();
});
}
},
@ -122,11 +121,11 @@ export default [
editConstraint(ctx, firstConstr, () => {
const pm = viewer.parametricManager;
pm.algnNumSystem.addConstraint(firstConstr);
pm._add(firstConstr);
for (let other of others) {
pm.algnNumSystem.addConstraint(new AlgNumConstraint(ConstraintDefinitions.SegmentLength, [other], {...firstConstr.constants}));
pm._add(new AlgNumConstraint(ConstraintDefinitions.SegmentLength, [other], {...firstConstr.constants}));
}
pm.refresh();
pm.commit();
});
}
},
@ -143,7 +142,35 @@ export default [
const constr = new AlgNumConstraint(ConstraintDefinitions.LockPoint, [point]);
constr.initConstants();
editConstraint(ctx, constr, () => viewer.parametricManager.addAlgNum(constr));
editConstraint(ctx, constr, () => viewer.parametricManager.add(constr));
}
},
{
shortName: 'Mirror',
description: 'Mirror Objects',
selectionMatcher: selection => isInstanceOf(selection[0], Segment) && selection.length > 1,
invoke: ctx => {
const {viewer} = ctx;
const objects = viewer.selected;
const managedObjects = [];
for (let i = 1; i < objects.length; i++) {
let obj = objects[i];
const copy = obj.copy();
obj.layer.add(copy);
managedObjects.push(copy);
}
ConstraintDefinitions.Mirror.modify(objects, managedObjects);
// const constr = new AlgNumConstraint(ConstraintDefinitions.Mirror, [...objects, ...managedObjects]);
// viewer.parametricManager.addModifier(constr);
}
}

View file

@ -0,0 +1,19 @@
import {isInstanceOf} from "./matchUtils";
import {Generator} from "../id-generator";
export default [
{
shortName: 'Mirror',
description: 'Mirror Objects',
selectionMatcher: selection => isInstanceOf(selection[0]) && selection.length > 1,
invoke: ctx => {
const {viewer} = ctx;
viewer.parametricManager.addGenerator(new Generator(GeneratorDefinitions.Mirror, [...viewer.selected]));
}
},
];

View file

@ -33,6 +33,10 @@ export function matchTypes(selection) {
return si === selection.length && i === arguments.length;
}
export function isInstanceOf(obj, shapeConstructor) {
return obj._class === shapeConstructor.prototype._class;
}
export function sortSelectionByType(selection) {
return [...selection].sort((a, b) => a._class.localeCompare(b._class))
}

View file

@ -38,8 +38,8 @@ export function ConstraintList() {
return constraints.map((c, i) => {
const conflicting = viewer.parametricManager.algnNumSystem.conflicting.has(c);
const redundant = viewer.parametricManager.algnNumSystem.redundant.has(c);
const conflicting = false; //viewer.parametricManager.algNumSystem.conflicting.has(c);
const redundant = false; //viewer.parametricManager.algNumSystem.redundant.has(c);
return <div key={c.id} className={cx(ls.objectItem, conflicting&&ls.conflicting, redundant&&ls.redundant)}
onClick={() => viewer.parametricManager.updateConstraintConstants(c)}

View file

@ -3,6 +3,8 @@ import {indexById} from "../../../../modules/gems/iterables";
import {DEG_RAD, distanceAB} from "../../math/math";
import {COS_FN, Polynomial, POW_1_FN, POW_2_FN, SIN_FN} from "./polynomial";
import {Types} from "../io";
import {Constraints} from "../constraints";
import Vector from "../../../../modules/math/vector";
export const ConstraintDefinitions = indexById([
@ -273,6 +275,36 @@ export const ConstraintDefinitions = indexById([
polynomials.push(new Polynomial(-x).monomial().term(px, POW_1_FN));
polynomials.push(new Polynomial(-y).monomial().term(py, POW_1_FN));
},
},
{
id: 'Mirror',
name: 'Mirror Objects',
modify: (referenceObjects, managedObjects) => {
const reflectionLine = referenceObjects[0];
const dir = new Vector();
dir.set(-(reflectionLine.b.y - reflectionLine.a.y), reflectionLine.b.x - reflectionLine.a.x, 0)._normalize();
for (let i = 0; i < managedObjects.length; i++) {
let origin = reflectionLine.a.toVector();
const pointMirroring = (x, y) => {
let pt = new Vector(x, y, 0);
let proj = dir.dot(pt.minus(origin));
return dir.multiply(- proj * 2)._plus(pt);
};
referenceObjects[i+1].mirror(managedObjects[i], pointMirroring);
}
},
referenceObjects: objects => objects.slice(0, (objects.length >> 1) + 1),
managedObjects: objects => objects.slice((objects.length + 1) >> 1)
}
]);
@ -289,8 +321,26 @@ export class AlgNumConstraint {
this.internal = false;
this.schema = schema;
this.params = [];
this.schema.defineParamsScope(this.objects, p => this.params.push(p));
// this.paramSet = new Set(this.params);
if (this.schema.defineParamsScope) {
this.schema.defineParamsScope(this.objects, p => this.params.push(p));
}
this.modifier = this.schema.modify !== undefined;
if (this.modifier) {
this.referenceObjects = this.schema.referenceObjects(this.objects);
this.managedObjects = this.schema.managedObjects(this.objects);
this.managedObjects.forEach(o => {
if (o.managedBy) {
throw 'there can be only one managing modifier for an object';
}
o.managedBy = this;
});
}
}
modify() {
this.resolveConstants();
this.schema.modify(this.referenceObjects, this.managedObjects, this.resolvedConstants);
}
collectPolynomials(polynomials) {

View file

@ -1,32 +1,18 @@
import {createByConstraintName} from "./solverConstraints";
import {Param, prepare} from "./solver";
import {findConstructionCluster} from "./constructions";
import {GCCircle, GCPoint} from "./constractibles";
import {eqEps, eqTol} from "../../brep/geom/tolerance";
import {prepare} from "./solver";
import {eqEps} from "../../brep/geom/tolerance";
import {Polynomial, POW_1_FN} from "./polynomial";
import {compositeFn, NOOP} from "../../../../modules/gems/func";
import {sq} from "../../math/math";
import {compositeFn} from "gems/func";
export class AlgNumSubSystem {
generator = NOOP;//new BoundaryObjectsGenerator();
modifiers = [];
allConstraints = [];
ownParams = new Set();
readOnlyParams = new Set();
generatedParams = new Set();
paramToIsolation = new Map();
eliminatedParams = new Map();
// generators = [];
subSystems = []; //subsystems are generated by generators only
polynomials = [];
substitutedParams = [];
polyToConstr = new Map();
@ -36,9 +22,7 @@ export class AlgNumSubSystem {
snapshot = new Map();
constructor(generator = NOOP) {
this.generator = generator;
constructor() {
this.solveStatus = {
error: 0,
@ -47,7 +31,6 @@ export class AlgNumSubSystem {
}
get fullyConstrained() {
return this.dof === 0;
}
@ -62,11 +45,6 @@ export class AlgNumSubSystem {
addConstraint(constraint, _ancestorParams) {
if (this.canBeAdded(constraint.params)) {
// this.constraints.push(constraint);
// this.constraints
}
this.makeSnapshot();
this.allConstraints.push(constraint);
@ -233,6 +211,8 @@ export class AlgNumSubSystem {
prepare() {
this.isDirty = false;
this.reset();
this.evaluatePolynomials();
@ -325,7 +305,9 @@ export class AlgNumSubSystem {
solve(rough) {
this.generator();
// this.modifiers.forEach(m => m.modify());
// this.prepare();
this.polynomialIsolations.forEach(iso => {
iso.solve(rough);
@ -381,17 +363,6 @@ export class AlgNumSubSystem {
});
}
canBeAdded(subjectParams, ancestorParams) {
for (let p of subjectParams) {
if (!this.ownParams.has(p) && (!ancestorParams || !ancestorParams.has(p))) {
return false;
}
}
return true;
}
}

View file

@ -100,7 +100,7 @@ IO.prototype._loadSketch = function(sketch) {
if (!!ioLayer.style) layer.style = ioLayer.style;
layer.readOnly = !!ioLayer.readOnly;
var layerData = ioLayer['data'];
for (i = 0; i < layerData.length; ++i) {
for (let i = 0; i < layerData.length; ++i) {
var obj = layerData[i];
var skobj = null;
var _class = obj['_class'];
@ -194,7 +194,7 @@ IO.prototype._loadSketch = function(sketch) {
}
}
for (i = 0; i < this.viewer.dimLayer.objects.length; ++i) {
for (let i = 0; i < this.viewer.dimLayer.objects.length; ++i) {
obj = this.viewer.dimLayer.objects[i];
if (obj._class === T.DIM || obj._class === T.HDIM || obj._class === T.VDIM) {
obj.a = index[obj.a];
@ -212,15 +212,14 @@ IO.prototype._loadSketch = function(sketch) {
this.linkEndPoints(boundaryLayer.objects);
}
var sketchConstraints = sketch['constraints'];
let sketchConstraints = sketch['constraints'];
if (sketchConstraints !== undefined) {
for (var i = 0; i < sketchConstraints.length; ++i) {
for (let i = 0; i < sketchConstraints.length; ++i) {
try {
if (version > 1) {
this.viewer.parametricManager.algnNumSystem.addConstraint(AlgNumConstraint.read(sketchConstraints[i], index));
this.viewer.parametricManager._add(AlgNumConstraint.read(sketchConstraints[i], index));
} else {
const c = this.parseConstr(sketchConstraints[i], index);
this.viewer.parametricManager._add(c);
console.error("old format - need an upgrade");
}
} catch (msg) {
console.info("Skipping. " + msg);
@ -228,7 +227,7 @@ IO.prototype._loadSketch = function(sketch) {
}
this.viewer.parametricManager.notify();
}
var constants = sketch['constants'];
let constants = sketch['constants'];
if (constants !== undefined) {
this.viewer.params.constantDefinition = constants;
}
@ -333,10 +332,10 @@ IO.prototype.cleanUpData = function() {
}
this.viewer.deselectAll();
Generator.resetIDGenerator(0);
if (this.viewer.parametricManager.algnNumSystem.allConstraints.length !== 0) {
this.viewer.parametricManager.reset();
this.viewer.parametricManager.notify();
}
this.viewer.parametricManager.reset();
this.viewer.parametricManager.notify();
};
IO.prototype._serializeSketch = function(metadata) {
@ -400,7 +399,7 @@ IO.prototype._serializeSketch = function(metadata) {
}
sketch.constraints = [];
const systemConstraints = this.viewer.parametricManager.algnNumSystem.allConstraints;
const systemConstraints = this.viewer.parametricManager.allConstraints;
for (let sc of systemConstraints) {
if (!sc.internal) {
sketch.constraints.push(sc.write());

View file

@ -1,16 +0,0 @@
function mirrorManager() {
let mirrors = [];
function add() {
}
}
function mirrorTool() {
}

View file

@ -2,24 +2,30 @@ import {askNumber} from '../utils/utils';
import {Constraints} from './constraints';
import {AlgNumConstraint, ConstraintDefinitions} from "./constr/ANConstraints";
import {AlgNumSubSystem} from "./constr/AlgNumSystem";
import {stream} from "../../../modules/lstream";
import {state, stream} from "../../../modules/lstream";
export {Constraints, ParametricManager}
class ParametricManager {
algnNumSystem;
constantTable = {};
externalConstantResolver = null;
$constraints = stream().remember([]);
solveSystems;
$update = stream();
$constraints = this.$update.map(layers => layers.reduce((all, layer) => {
layer.allConstraints.forEach(c => all.push(c));
layer.modifiers.forEach(c => all.push(c));
return all
}, []).sort((c1, c2) => c1.id - c2.id)).remember([]);
constructor(viewer) {
this.viewer = viewer;
this.reset();
this.viewer.params.define('constantDefinition', null);
this.viewer.params.subscribe('constantDefinition', 'parametricManager', this.onConstantsExternalChange, this)();
this.constantResolver = this.createConstantResolver();
@ -27,12 +33,12 @@ class ParametricManager {
}
reset() {
this.algnNumSystem = new AlgNumSubSystem();
get allConstraints() {
return this.$constraints.value;
}
get subSystems() {
return this.system.subSystems;
reset() {
this.solveSystems = [new AlgNumSubSystem()];
}
addAlgNum(constr) {
@ -81,7 +87,7 @@ class ParametricManager {
onConstantsExternalChange(constantDefinition) {
this.rebuildConstantTable(constantDefinition);
this.refresh();
// this.refresh();
};
defineNewConstant(name, value) {
@ -111,24 +117,50 @@ class ParametricManager {
this.viewer.parametricManager.refresh();
};
notify(event) {
this.$constraints.next(this.algnNumSystem.allConstraints);
notify() {
this.$update.next(this.solveSystems);
};
refresh() {
console.log("calling non existent method");
};
_add(constr) {
this.viewer.historyManager.checkpoint();
this.algnNumSystem.addConstraint(constr);
commit() {
this.notify();
this.viewer.refresh();
};
getPlacementLayerIndex(objects) {
for (let i = this.solveSystems.length - 1; i >= 0; --i) {
const system = this.solveSystems[i];
for (let o of objects) {
if (o.solveSystem === system) {
return i;
}
}
}
return 0;
}
_add(constr) {
if (constr.modifier) {
throw 'use addModifier instead';
}
let system = this.solveSystems[this.getPlacementLayerIndex(constr.objects)];
for (let o of constr.objects) {
if (!o.solveSystem) {
o.solveSystem = system;
}
}
system.addConstraint(constr);
};
add(constr) {
this.viewer.historyManager.checkpoint();
this.algnNumSystem.addConstraint(constr);
this._add(constr);
this.notify();
this.viewer.refresh();
};
@ -136,7 +168,7 @@ class ParametricManager {
addAll(constrs) {
this.viewer.historyManager.checkpoint();
for (let i = 0; i < constrs.length; i++) {
this.algnNumSystem.addConstraint(constrs[i]);
this._add(constrs[i]);
}
this.notify();
this.viewer.refresh();
@ -144,7 +176,7 @@ class ParametricManager {
remove(constr) {
this.viewer.historyManager.checkpoint();
this.algnNumSystem.removeConstraint(constr);
// this.algNumSystem.removeConstraint(constr);
this.refresh();
};
@ -154,7 +186,7 @@ class ParametricManager {
let toRemove = new Set();
objects.forEach(obj => obj.visitParams(p => {
this.algnNumSystem.allConstraints.forEach(c => {
this.algNumSystem.allConstraints.forEach(c => {
c.objects.forEach(o => {
})
@ -190,6 +222,34 @@ class ParametricManager {
this.removeObjects(dependants);
}
};
prepare() {
this.solveSystems.forEach(system => system.prepare());
}
solve(rough) {
this.solveSystems.forEach(system => system.solve(rough));
}
addModifier(modifier) {
modifier.managedObjects.forEach(o => {
if (o.solveSystem) {
throw 'adding modifiers to already constrained objects isn not supported yet';
}
});
this.viewer.historyManager.checkpoint();
let index = this.getPlacementLayerIndex(modifier.referenceObjects) + 1;
if (index === this.solveSystems.length) {
this.solveSystems.push(new AlgNumSubSystem());
}
const solveSystem = this.solveSystems[index];
solveSystem.modifiers.push(modifier);
modifier.managedObjects.forEach(go => go.solveSystem = solveSystem);
this.notify();
this.viewer.refresh();
}
}

View file

@ -141,4 +141,3 @@ export class Arc extends SketchObject {
}
Arc.prototype._class = 'TCAD.TWO.Arc';
Arc.prototype.TYPE = 'ARC';

View file

@ -79,6 +79,5 @@ export class BezierCurve extends SketchObject {
}
}
BezierCurve.prototype._class = 'TCAD.TWO.BezierCurve';
BezierCurve.prototype.TYPE = 'BEZIER';
const RECOVER_LENGTH = 100;

View file

@ -38,7 +38,12 @@ export class Circle extends SketchObject {
normalDistance(aim) {
return Math.abs(math.distance(aim.x, aim.y, this.c.x, this.c.y) - this.r.get());
}
copy() {
const circle = new Circle(this.c.copy());
circle.r.set(this.r.get());
return circle;
}
}
Circle.prototype._class = 'TCAD.TWO.Circle';
Circle.prototype.TYPE = 'CIRCLE';

View file

@ -93,7 +93,6 @@ export class Ellipse extends SketchObject {
}
}
Ellipse.prototype._class = 'TCAD.TWO.Ellipse';
Ellipse.prototype.TYPE = 'ELLIPSE';
const sq = (a) => a * a;
const RECOVER_LENGTH = 100;

View file

@ -90,4 +90,3 @@ export class NurbsObject extends SketchObject {
}
NurbsObject.prototype._class = 'TCAD.TWO.NurbsObject';
NurbsObject.prototype.TYPE = 'NURBS';

View file

@ -83,5 +83,4 @@ export class EndPoint extends SketchObject {
}
EndPoint.prototype._class = 'TCAD.TWO.EndPoint';
EndPoint.prototype.TYPE = 'POINT';

View file

@ -154,5 +154,3 @@ export class Segment extends SketchObject {
}
Segment.prototype._class = 'TCAD.TWO.Segment';
Segment.prototype.TYPE = 'SEGMENT';

View file

@ -7,12 +7,13 @@ export class SketchObject extends Shape {
constructor() {
super();
this.id = Generator.genID();
this.aux = false;
this.marked = null;
this.children = [];
this.linked = [];
this.layer = null;
this.fullyConstrained = false;
this.managedBy = null;
this.solveSystem = null;
}
normalDistance(aim, scale) {

View file

@ -32,8 +32,8 @@ export class EditCircleTool extends Tool {
}
solveRequest(rough) {
this.solver = this.viewer.parametricManager.prepare([this.circle.r]);
this.solver.solve(rough, 1);
// this.viewer.parametricManager.prepare([this.circle.r]);
this.viewer.parametricManager.solve(rough);
}
mouseup(e) {

View file

@ -25,7 +25,7 @@ export class DragTool extends Tool {
this.obj.translate(dx, dy);
(this.obj.parent || this.obj).syncGeometry();
if (!Tool.dumbMode(e)) {
this.viewer.parametricManager.algnNumSystem.solve(true);
this.viewer.parametricManager.solve(true);
}
this.viewer.refresh();
}
@ -35,12 +35,12 @@ export class DragTool extends Tool {
this.origin.y = e.offsetY;
this.viewer.screenToModel2(e.offsetX, e.offsetY, this._point);
this.viewer.parametricManager.algnNumSystem.prepare();
this.viewer.parametricManager.prepare();
}
mouseup(e) {
this.viewer.parametricManager.algnNumSystem.solve(false);
this.viewer.parametricManager.solve(false);
this.viewer.refresh();
this.viewer.toolManager.releaseControl();
var traveled = math.distance(this.origin.x, this.origin.y, e.offsetX, e.offsetY);