moving plane(operation and wizard) to the new API / BREP Framework

This commit is contained in:
Val Erastov 2017-03-17 01:20:31 -07:00
parent 1efc6b4cff
commit 1ab5ad089b
11 changed files with 210 additions and 16 deletions

View file

@ -0,0 +1,50 @@
import {PreviewWizard, IMAGINARY_SURFACE_MATERIAL} from './preview-wizard'
import {CURRENT_SELECTION as S} from './wizard'
import {AXIS, IDENTITY_BASIS, STANDARD_BASES} from '../../../../math/l3space'
import Vector from '../../../../math/vector'
const METADATA = [
['orientation', 'choice', 'XY', {options: ['XY', 'XZ', 'ZY']}],
['parallelTo', 'face', S],
['depth', 'number', 0, {}]
];
export class PlaneWizard extends PreviewWizard {
constructor(app, initialState) {
super(app, 'PLANE', METADATA, initialState);
}
createPreviewObject(app, params) {
let face = null;
if (params.face) {
face = this.app.findFace(params.face);
}
let basis;
let depth = params.depth;
if (face == null) {
basis = STANDARD_BASES[params.orientation];
} else {
basis = face.basis();
depth += face.depth();
}
const w = 375, h = 375;
const a = new Vector(-w, -h, 0);
const b = new Vector( w, -h, 0);
const c = new Vector( w, h, 0);
const d = new Vector(-w, h, 0);
const plane = PreviewWizard.createMesh([[a, b, c], [a, c, d]])
const m = new THREE.Matrix4();
m.makeBasis.apply(m, basis);
const wVec = new THREE.Vector3(0, 0, depth);
wVec.applyMatrix4(m);
m.setPosition(wVec);
plane.geometry.applyMatrix(m);
plane.geometry.computeFaceNormals();
return plane;
}
}

View file

@ -1,4 +1,5 @@
import * as tk from '../../../../ui/toolkit'
import {camelCaseSplit} from '../../../../utils/utils'
export class Wizard {
@ -21,7 +22,7 @@ export class Wizard {
}
uiLabel(name) {
return name;
return camelCaseSplit(name).map(w => w.toLowerCase()).join(' ');
}
focus() {
@ -36,9 +37,9 @@ export class Wizard {
const name = def[0];
const type = def[1];
const defaultValue = def[2];
const params = def[3];
const params = def[3] || {};
const label = this.uiLabel(name);
const formItem = this.createFormField(name, label, type, params);
const formItem = this.createFormField(name, label, type, params, defaultValue);
formItem.setter(defaultValue);
tk.add(folder, formItem.ui);
this.formFields[name] = formItem;
@ -98,13 +99,20 @@ export class Wizard {
this.box.close();
}
createFormField(name, label, type, params) {
createFormField(name, label, type, params, initValue) {
if (type == 'number') {
const number = tk.config(new tk.Number(label, 0, params.step, params.round), params);
const number = tk.config(new tk.Number(label, initValue, params.step, params.round), params);
number.input.on('t-change', () => this.onUIChange(name));
return Field.fromInput(number, Field.TEXT_TO_NUMBER_COERCION);
} else if (type == 'choice') {
const ops = params.options;
const radio = new tk.InlineRadio(ops, ops, ops.indexOf(initValue));
radio.root.find('input[type=radio]').on('change', () => {
this.onUIChange(name);
});
return new Field(radio, () => radio.getValue(), (v) => radio.setValue(v));
} else if (type == 'face') {
const face = new tk.Text(label, '');
const face = new tk.Text(label, initValue);
face.input.on('change', () => this.onUIChange(name));
return Field.fromInput(face, undefined, (faceId) => {
if (faceId === CURRENT_SELECTION) {
@ -138,6 +146,4 @@ Field.fromInput = function (inputEl, getterCoercer, setterCoercer) {
return new Field(inputEl, () => getterCoercer(inputEl.input.val()), (value) => inputEl.input.val(setterCoercer(value)));
};
export const CURRENT_SELECTION = {};

View file

@ -1,6 +1,7 @@
import {MESH_OPERATIONS} from './mesh/workbench'
import {Extrude, Cut} from './brep/cut-extrude'
import {BREPSceneSolid} from '../scene/brep-scene-object'
import {PlaneSceneObject} from '../scene/plane-scene-object'
import {box} from '../../brep/brep-primitives'
export const CUT = {
@ -49,7 +50,10 @@ export const PLANE = {
label: 'Plane',
info: (p) => '(' + p.depth + ')',
action: (app, request) => {
return {
outdated: [],
created: [PlaneSceneObject.create(request)]
}
}
};

View file

@ -28,8 +28,7 @@ export class BREPSceneSolid extends SceneSolid {
this.sceneFaces.push(sceneFace);
for (let i = g.groupStart; i < g.groupEnd; i ++) {
const face = geom.faces[i];
sceneFace.meshFaces.push(face);
face.__TCAD_SceneFace = sceneFace;
sceneFace.registerMeshFace(face);
}
}
geom.mergeVertices();

View file

@ -0,0 +1,89 @@
import Vector from '../../math/vector'
import {STANDARD_BASES} from '../../math/l3space'
import {Plane} from '../../brep/geom/impl/plane'
import {SceneSolid, SceneFace} from './scene-object'
const INIT_WIDTH_H = 750 * 0.5;
const INIT_HEIGHT_H = 750 * 0.5;
export const INIT_BOUNDS = [
new Vector(-INIT_WIDTH_H, -INIT_HEIGHT_H, 0),
new Vector( INIT_WIDTH_H, -INIT_HEIGHT_H, 0),
new Vector( INIT_WIDTH_H, INIT_HEIGHT_H, 0),
new Vector(-INIT_WIDTH_H, INIT_HEIGHT_H, 0)
];
export class PlaneSceneObject extends SceneSolid {
constructor(plane, skin) {
super('PLANE', undefined, Object.assign({
side : THREE.DoubleSide,
transparent: true,
opacity: 0.5
}, skin));
this.plane = plane;
this.sceneFace = new PlaneSceneFace(this);
this.sceneFaces.push(this.sceneFace); // as part of the API
this.updateBounds(INIT_BOUNDS);
}
createGeometry() {
const geometry = new THREE.Geometry();
geometry.dynamic = true;
this.bounds.forEach(v => geometry.vertices.push(v.three()));
geometry.faces.push(new THREE.Face3(0, 1, 2));
geometry.faces.push(new THREE.Face3(0, 2, 3));
geometry.faces.forEach(f => this.sceneFace.registerMeshFace(f));
geometry.computeFaceNormals();
this.mesh = new THREE.Mesh(geometry, this.material);
this.cadGroup.add(this.mesh);
}
dropGeometry() {
if (this.mesh) {
this.cadGroup.remove( this.mesh );
this.mesh.geometry.dispose();
this.sceneFace.meshFaces = [];
}
}
updateBounds(bounds2d) {
this.dropGeometry();
const tr = this.plane.get3DTransformation();
this.bounds = bounds2d.map(v => tr.apply(v.plusXYZ(0, 0, this.plane.w)));
this.createGeometry();
}
static create(params, faceResolver) {
let face = null;
if (params.face) {
face = faceResolver(params.face);
}
let plane = null;
if (face == null) {
const normal = STANDARD_BASES[params.orientation][2];
plane = new Plane(normal, params.depth);
} else {
plane = new Plane(face.normal(), params.depth);
}
return new PlaneSceneObject(plane);
}
}
class PlaneSceneFace extends SceneFace {
constructor(scenePlane) {
super(scenePlane);
}
normal() {
return this.solid.plane.normal;
}
depth() {
return this.solid.plane.w;
}
getBounds() {
return [];
}
}

View file

@ -98,11 +98,15 @@ export class SceneFace {
createMeshFace(a, b, c) {
const face = new THREE.Face3(a, b, c);
this.meshFaces.push(face);
face.__TCAD_SceneFace = this;
this.registerMeshFace(face);
return face;
}
registerMeshFace(threeFace) {
this.meshFaces.push(threeFace);
threeFace.__TCAD_SceneFace = this;
}
syncSketches(geom) {
const normal = this.normal();
const offVector = new Vector();//normal.multiply(0); // disable it. use polygon offset feature of material

View file

@ -9,7 +9,7 @@ import Menu from '../menu/menu'
import {ExtrudeWizard, CutWizard} from '../craft/brep/wizards/cut-extrude'
import {RevolveWizard} from '../craft/mesh/wizards/revolve'
import {PlaneWizard} from '../craft/mesh/wizards/plane'
import {PlaneWizard} from '../craft/brep/wizards/plane'
import {BoxWizard} from '../craft/brep/wizards/box'
import {SphereWizard} from '../craft/mesh/wizards/sphere'
import {TransformWizard} from '../craft/mesh/wizards/transform'

View file

@ -10,6 +10,13 @@ var AXIS = {
var IDENTITY_BASIS = [AXIS.X, AXIS.Y, AXIS.Z];
export const STANDARD_BASES = {
'XY': IDENTITY_BASIS,
'XZ': [AXIS.X, AXIS.Z, AXIS.Y],
'ZY': [AXIS.Z, AXIS.Y, AXIS.X]
};
/** @constructor */
function Matrix3() {
this.reset();

View file

@ -74,6 +74,10 @@ Vector.prototype._minusXYZ = function(x, y, z) {
return this;
};
Vector.prototype.plusXYZ = function(x, y, z) {
return new Vector(this.x + x, this.y + y, this.z + z);
};
Vector.prototype.plus = function(vector) {
return new Vector(this.x + vector.x, this.y + vector.y, this.z + vector.z);
};

View file

@ -71,6 +71,11 @@ InlineRadio.prototype.getValue = function() {
return null;
};
InlineRadio.prototype.setValue = function(v) {
this.root.find('input[value='+v+']').prop('checked', true);
};
InlineRadio.COUNTER = 0;
export function propLayout(root, name, valueEl) {

View file

@ -40,3 +40,29 @@ export function swap(arr, i1, i2) {
arr[i1] = arr[i2];
arr[i2] = tmp;
}
export function camelCaseSplit(str) {
function isUpperCase(str) {
return str.toUpperCase() == str;
}
const words = [];
let word = '';
for (let i = 0; i < str.length; i++) {
const c = str.charAt(i);
if (c == '_' || c == '-') {
continue;
}
const dot = c === '.';
if ((dot || isUpperCase(c)) && word.length != 0) {
words.push(word);
word = '';
}
if (!dot) word += c;
}
if (word.length != 0){
words.push(word);
}
return words;
}