bump threejs version to 0.143.0

This commit is contained in:
Val Erastov 2022-08-06 22:00:44 -07:00
parent e6d5b7b509
commit 56ed53131a
29 changed files with 521 additions and 1393 deletions

View file

@ -58,15 +58,18 @@ function createDirectedCurve(points, arrowDir, arrowTipPos, color) {
obj.__tcad_debug_materials = [];
let material = new THREE.LineBasicMaterial({color, linewidth: 10});
let lg = new THREE.Geometry();
const vertices = [];
let edgeLength = 0;
for (let i = 1; i < points.length; ++i) {
let a = points[i - 1];
let b = points[i];
lg.vertices.push(a.three());
lg.vertices.push(b.three());
vertices.push(a.three());
vertices.push(b.three());
edgeLength += distanceAB3(a, b);
}
const lg = new THREE.BufferGeometry().setFromPoints( vertices );
obj.__tcad_debug_materials.push(material);
obj.add(new THREE.Line(lg, material));

View file

@ -1,41 +1,26 @@
import {BoxGeometry, Face3, Geometry, Vector3} from 'three';
import {BoxGeometry, BufferGeometry, BufferAttribute, Vector3} from 'three';
import {normalOfCCWSeq} from "cad/cad-utils";
export function createBoxGeometry(width, height, depth) {
return new BoxGeometry(width, height, depth);
}
export function createMeshGeometry(triangles) {
const geometry = new Geometry();
for (let tr of triangles) {
const a = geometry.vertices.length;
const b = a + 1;
const c = a + 2;
const face = new Face3(a, b, c);
tr.forEach(v => geometry.vertices.push(v.three()));
geometry.faces.push(face);
}
geometry.mergeVertices();
geometry.computeFaceNormals();
const vertices = [];
const normals = [];
triangles.forEach(tr => {
const normal = normalOfCCWSeq(tr);
tr.forEach(p => {
vertices.push(p.x, p.y, p.z);
normals.push(normal.x, normal.y, normal.z);
})
});
const geometry = new BufferGeometry();
geometry.setAttribute('position', new BufferAttribute( new Float32Array(vertices), 3 ) );
geometry.setAttribute('normal', new BufferAttribute( new Float32Array(normals), 3));
return geometry;
}
export function createSmoothMeshGeometryFromData(tessInfo) {
const geometry = new Geometry();
const vec = arr => new Vector3().fromArray(arr);
for (let [tr, normals] of tessInfo) {
if (!normals || normals.find(n => n[0] === null || n[1] === null || n[2] === null)) {
normals = undefined;
}
const a = geometry.vertices.length;
const b = a + 1;
const c = a + 2;
const face = new Face3(a, b, c, normals && normals.map(vec));
tr.forEach(v => geometry.vertices.push(vec(v)));
geometry.faces.push(face);
}
geometry.mergeVertices();
geometry.computeFaceNormals();
return geometry;
}

View file

@ -3,7 +3,7 @@ import {MeshPhongMaterial, LineBasicMaterial, FaceColors, DoubleSide} from 'thre
export function createTransparentPhongMaterial(color, opacity) {
return new MeshPhongMaterial({
vertexColors: FaceColors,
// vertexColors: FaceColors,
color,
transparent: true,
opacity: opacity,

View file

@ -1,21 +1,23 @@
export function setAttribute(obj, key, value) {
getData(obj)[key] = value;
getData(obj, true)[key] = value;
}
export function getAttribute(obj, key) {
return getData(obj)[key];
return getData(obj, false)[key];
}
export function unsetAttribute(obj, key) {
delete getData(obj)[key];
delete getData(obj, false)[key];
}
export function getData(obj) {
function getData(obj, create) {
let data = obj.__TCAD_CUSTOM_DATA;
if (data === undefined) {
data = {};
obj.__TCAD_CUSTOM_DATA = data;
if (create) {
obj.__TCAD_CUSTOM_DATA = data;
}
}
return data;
}

View file

@ -1,9 +1,6 @@
import DPR from 'dpr';
import {ArrowHelper, CylinderBufferGeometry, Mesh, MeshBasicMaterial, Object3D, Vector3} from 'three';
import {createMeshLineGeometry} from './meshLine';
import {Sphere} from 'three/src/math/Sphere';
import {Matrix4} from 'three/src/math/Matrix4';
import {Ray} from 'three/src/math/Ray';
export function createArrow(length, arrowLength, arrowHead, axis, color, opacity, materialMixins) {
let arrow = new ArrowHelper(new Vector3().copy(axis), new Vector3(0, 0, 0), length, color, arrowLength, arrowHead);

View file

@ -1,145 +0,0 @@
import {Face3, Geometry, Vector3} from 'three';
export default function facetedCube(size, w) {
let d = size * 0.5;
let l = d - w;
const v = (x,y,z) => new Vector3(x,y,z);
let geom = new Geometry();
//front
geom.vertices.push(v(-l, -l, d));
geom.vertices.push(v(l, -l, d));
geom.vertices.push(v(l, l, d));
geom.vertices.push(v(-l, l, d));
//top
geom.vertices.push(v(-l, d, l));
geom.vertices.push(v(l, d, l));
geom.vertices.push(v(l, d, -l));
geom.vertices.push(v(-l, d, -l));
//back
geom.vertices.push(v(-l, -l, -d));
geom.vertices.push(v(l, -l, -d));
geom.vertices.push(v(l, l, -d));
geom.vertices.push(v(-l, l, -d));
//bottom
geom.vertices.push(v(-l, -d, l));
geom.vertices.push(v(l, -d, l));
geom.vertices.push(v(l, -d, -l));
geom.vertices.push(v(-l, -d, -l));
//left
geom.vertices.push(v(-d, -l, -l));
geom.vertices.push(v(-d, -l, l));
geom.vertices.push(v(-d, l, l));
geom.vertices.push(v(-d, l, -l));
//right
geom.vertices.push(v(d, -l, -l));
geom.vertices.push(v(d, -l, l));
geom.vertices.push(v(d, l, l));
geom.vertices.push(v(d, l, -l));
//front
geom.faces.push( new Face3( 0, 1, 2 ) );
geom.faces.push( new Face3( 2, 3, 0 ) );
//top
geom.faces.push( new Face3( 4, 5, 6 ) );
geom.faces.push( new Face3( 6, 7, 4 ) );
//back
geom.faces.push( new Face3( 10, 9, 8) );
geom.faces.push( new Face3( 8, 11, 10 ) );
//bottom
geom.faces.push( new Face3( 14, 13, 12) );
geom.faces.push( new Face3( 12, 15, 14 ) );
//left
geom.faces.push( new Face3( 16, 17, 18 ) );
geom.faces.push( new Face3( 18, 19, 16 ) );
// right
geom.faces.push( new Face3( 22, 21, 20 ) );
geom.faces.push( new Face3( 20, 23, 22 ) );
//front-top
geom.faces.push( new Face3( 4, 3, 2) );
geom.faces.push( new Face3( 2, 5, 4 ) );
//top-back
geom.faces.push( new Face3( 7, 6, 10) );
geom.faces.push( new Face3( 10, 11, 7 ) );
// back-bottom
geom.faces.push( new Face3( 8, 9, 14) );
geom.faces.push( new Face3( 14, 15, 8 ) );
//bottom-left
geom.faces.push( new Face3( 15, 12, 17) );
geom.faces.push( new Face3( 17, 16, 15 ) );
//bottom-right
geom.faces.push( new Face3( 20, 21, 13) );
geom.faces.push( new Face3( 13, 14, 20 ) );
//top-right
geom.faces.push( new Face3( 6, 5, 22) );
geom.faces.push( new Face3( 22, 23, 6 ) );
//top-left
geom.faces.push( new Face3( 19, 18, 4) );
geom.faces.push( new Face3( 4, 7, 19 ) );
//front-left
geom.faces.push( new Face3( 18, 17, 0) );
geom.faces.push( new Face3( 0, 3, 18 ) );
//front-bottom
geom.faces.push( new Face3( 12, 13, 1) );
geom.faces.push( new Face3( 1, 0, 12 ) );
//right-back
geom.faces.push( new Face3( 9, 10, 23) );
geom.faces.push( new Face3( 23, 20, 9 ) );
//front-right
geom.faces.push( new Face3( 21, 22, 2) );
geom.faces.push( new Face3( 2, 1, 21 ) );
//back-left
geom.faces.push( new Face3( 16, 19, 11) );
geom.faces.push( new Face3( 11, 8, 16 ) );
//front-top-left
geom.faces.push( new Face3( 4, 18, 3 ) );
//front-top-right
geom.faces.push( new Face3( 2, 22, 5 ) );
//top-right-back
geom.faces.push( new Face3( 23, 10, 6 ) );
// top-left-back
geom.faces.push( new Face3( 7, 11, 19 ) );
// front-left-bottom
geom.faces.push( new Face3( 17, 12, 0 ) );
// front-right-bottom
geom.faces.push( new Face3( 1, 13, 21 ) );
// back-right-bottom
geom.faces.push( new Face3( 20, 14, 9 ) );
// back-left-bottom
geom.faces.push( new Face3( 8, 15, 16 ) );
geom.computeFaceNormals();
return geom;
}

View file

@ -1,10 +1,11 @@
import * as vec from 'math/vec';
import {Face3, Geometry, Vector3} from 'three';
import {BufferAttribute, BufferGeometry} from 'three';
import {perpendicularVector} from "geom/euclidean";
export function createMeshLineGeometry(points, width) {
const vThree = arr => new Vector3().fromArray(arr);
const geometry = new Geometry();
const geometry = new BufferGeometry();
const vertices = [];
const index = [];
let base = null;
for (let i = 1; i < points.length; i++) {
@ -24,9 +25,9 @@ export function createMeshLineGeometry(points, width) {
}
let lid = dirs.map(d => vec.add(b, d));
let off = geometry.vertices.length;
base.forEach(p => geometry.vertices.push(vThree(p)));
lid.forEach(p => geometry.vertices.push(vThree(p)));
let off = vertices.length;
base.forEach(p => vertices.push(...p));
lid.forEach(p => vertices.push(...p));
base = lid;
[
@ -38,8 +39,10 @@ export function createMeshLineGeometry(points, width) {
[5, 4, 0],
[1, 2, 6],
[6, 5, 1],
].forEach(([a, b, c]) => geometry.faces.push(new Face3(a + off, b + off, c + off)));
].forEach(([a, b, c]) => index.push(a + off, b + off, c + off));
}
geometry.computeFaceNormals();
geometry.setIndex( index );
geometry.setAttribute('position', new BufferAttribute( new Float32Array(vertices), 3));
geometry.computeVertexNormals();
return geometry;
}

View file

@ -1,140 +1,63 @@
import {Face3, FaceColors, Geometry, Mesh, MeshBasicMaterial, MeshPhongMaterial} from 'three';
import {advancePseudoFrenetFrame, frenetFrame, pseudoFrenetFrame} from 'geom/curves/frenetFrame';
import * as vec from 'math/vec';
import {viewScaleFactor} from '../scaleHelper';
import {arrToThree} from 'math/vectorAdapters';
import {getSceneSetup} from '../sceneSetup';
import calcFaceNormal from '../utils/calcFaceNormal';
import {BufferGeometry} from "three/src/core/BufferGeometry";
import {ORIGIN} from "math/vector";
import {LineGeometry} from 'three/examples/jsm/lines/LineGeometry';
import {LineMaterial} from 'three/examples/jsm/lines/LineMaterial';
import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2';
import {Vector2} from 'three';
import SceneSetUp from "scene/sceneSetup";
// import {BufferGeometry, BufferAttribute} from "three/src/core/BufferGeometry";
export default class ScalableLine extends Mesh {
export default class ScalableLine extends LineSegments2 {
constructor(tessellation, width, color, opacity, smooth, ambient, offset) {
super(createGeometry(tessellation, smooth), createMaterial(color, opacity, ambient, offset));
this.width = width;
this.morphTargetInfluences = [0];
constructor(sceneSetup, tessellation, width, color) {
super(createGeometry(tessellation), createMaterial(sceneSetup, color, width));
this.resolutionListenerDisposer = sceneSetup.viewportSizeUpdate$.attach(() => {
this.material.resolution = getResolution(sceneSetup)
});
}
updateMatrix() {
let sceneSetup = getSceneSetup(this);
if (!sceneSetup) {
return;
}
let modelSize = 1;
let modelSizePx = this.width;
let k = viewScaleFactor(sceneSetup, ORIGIN, modelSizePx, modelSize);
let morphDistance = k * modelSize / 2 - modelSize;
this.morphTargetInfluences[0] = morphDistance / morphBase;
super.updateMatrix();
}
dispose() {
this.geometry.dispose();
this.material.dispose();
this.resolutionListenerDisposer();
}
}
function createMaterial(color, opacity, ambient, offset) {
let materialParams = {
vertexColors: FaceColors,
morphTargets: true,
function getResolution(sceneSetup) {
return new Vector2(sceneSetup.container.clientWidth, sceneSetup.container.clientHeight);
}
function createMaterial(sceneSetup, color, width, opacity, ambient, offset) {
// let modelSize = 1;
// let modelSizePx = width;
// let k = viewScaleFactor(sceneSetup, ORIGIN, modelSizePx, modelSize);
return new LineMaterial( {
color,
};
if (offset) {
Object.assign(materialParams, {
polygonOffset: true,
polygonOffsetFactor: -2.0,
polygonOffsetUnits: -1.0,
});
}
if (!ambient) {
materialParams.shininess = 0;
}
if (opacity !== undefined) {
materialParams.transparent = true;
materialParams.opacity = opacity;
}
return ambient ? new MeshBasicMaterial(materialParams) : new MeshPhongMaterial(materialParams);
}
function createGeometry(tessellation, smooth) {
const width = 1;
const geometry = new Geometry();
const scaleTargets = [];
geometry.dynamic = true;
let tess = tessellation;
// let frames = [pseudoFrenetFrame(edge.curve.tangentAtPoint(new Vector().set3(tess[0])).data())];
let frames = [pseudoFrenetFrame(vec._normalize(vec.sub(tess[1], tess[0])))];
// let frames = [calcFrame(tess[0]) || pseudoFrenetFrame(edge.curve.tangentAtPoint(new Vector().set3(tess[0])).data())];
for (let i = 1; i < tess.length; i++) {
let a = tess[i - 1];
let b = tess[i];
let ab = vec._normalize(vec.sub(b, a));
let prevFrame = frames[i - 1];
let T = vec._normalize(vec.add(prevFrame[0], ab));
// frames.push(calcFrame(b) || advancePseudoFrenetFrame(prevFrame, T));
frames.push(advancePseudoFrenetFrame(prevFrame, T));
}
let axises = frames.map(([T, N, B]) => {
let dirs = [];
dirs[0] = N;
dirs[1] = B;
dirs[2] = vec.negate(dirs[0]);
dirs[3] = vec.negate(dirs[1]);
return dirs;
linewidth: width,
resolution: getResolution(sceneSetup),
// worldUnits: false,
// linewidth: 0.0031,//width,
// vertexColors: true,
// dashed: false,
// alphaToCoverage: true,
});
let normals = smooth ? [] : null;
axises.forEach((dirs, i) => {
dirs.forEach(dir => {
geometry.vertices.push(arrToThree(vec._add(vec.mul(dir, width), tess[i])));
scaleTargets.push(arrToThree(vec._add(vec.mul(dir, width + morphBase), tess[i])));
if (smooth) {
normals.push(arrToThree(dir));
}
});
});
for (let i = 0; i < tess.length - 1; i++) {
let off = 4 * i;
[
[0, 4, 3],
[3, 4, 7],
[2, 3, 7],
[7, 6, 2],
[0, 1, 5],
[5, 4, 0],
[1, 2, 6],
[6, 5, 1],
].forEach(([a, b, c]) => {
let vertexNormales = smooth ? [normals[a + off], normals[b + off], normals[c + off]] : undefined;
let face = new Face3(a + off, b + off, c + off, vertexNormales);
geometry.faces.push(face);
if (!smooth) {
calcFaceNormal(face, geometry.vertices);
}
});
}
let startNormal = arrToThree(frames[0][0]).negate();
geometry.faces.push(new Face3(2, 1, 0, startNormal));
geometry.faces.push(new Face3(0, 3, 2, startNormal));
let endNormal = arrToThree(frames[frames.length - 1][0]);
let n = frames.length * 4 - 1;
geometry.faces.push(new Face3(n - 2, n - 1, n, endNormal));
geometry.faces.push(new Face3(n, n - 3, n - 2, endNormal));
geometry.morphTargets.push({name: 'scaleTargets', vertices: scaleTargets});
return new BufferGeometry().fromGeometry(geometry);
//
// if (opacity !== undefined) {
// materialParams.transparent = true;
// materialParams.opacity = opacity;
// }
// return ambient ? new MeshBasicMaterial(materialParams) : new MeshPhongMaterial(materialParams);
}
const morphBase = 10;
function createGeometry(tessellation) {
const positions = [];
for ( let point of tessellation ) {
positions.push( ...point );
}
const geometry = new LineGeometry();
geometry.setPositions( positions );
return geometry;
}

View file

@ -201,6 +201,11 @@ export default class SceneSetUp {
createRaycaster(viewX, viewY) {
let raycaster = new Raycaster();
raycaster.params.Line.threshold = 12 * (this._zoomMeasure() * 0.8);
raycaster.params.Line2 = {
threshold: 20
};
let x = ( viewX / this.container.clientWidth ) * 2 - 1;
let y = - ( viewY / this.container.clientHeight ) * 2 + 1;

View file

@ -1,10 +1,7 @@
import {Vector3} from 'three';
export default function(face, vertices) {
export default function(vA, vB, vC) {
let ab = new Vector3();
let vA = vertices[ face.a ];
let vB = vertices[ face.b ];
let vC = vertices[ face.c ];
face.normal.subVectors( vC, vB );
ab.subVectors( vA, vB );
face.normal.cross( ab );

14
package-lock.json generated
View file

@ -29,7 +29,7 @@
"react-icons": "^4.4.0",
"react-toastify": "^5.5.0",
"sprintf": "0.1.5",
"three": "^0.118.3",
"three": "^0.143.0",
"xml2js": "^0.4.23"
},
"devDependencies": {
@ -14687,9 +14687,9 @@
"dev": true
},
"node_modules/three": {
"version": "0.118.3",
"resolved": "https://registry.npmjs.org/three/-/three-0.118.3.tgz",
"integrity": "sha512-ijECXrNzDkHieoeh2H69kgawTGH8DiamhR4uBN8jEM7VHSKvfTdEvOoHsA8Aq7dh7PHAxhlqBsN5arBI3KixSw=="
"version": "0.143.0",
"resolved": "https://registry.npmjs.org/three/-/three-0.143.0.tgz",
"integrity": "sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg=="
},
"node_modules/throttleit": {
"version": "1.0.0",
@ -28609,9 +28609,9 @@
"dev": true
},
"three": {
"version": "0.118.3",
"resolved": "https://registry.npmjs.org/three/-/three-0.118.3.tgz",
"integrity": "sha512-ijECXrNzDkHieoeh2H69kgawTGH8DiamhR4uBN8jEM7VHSKvfTdEvOoHsA8Aq7dh7PHAxhlqBsN5arBI3KixSw=="
"version": "0.143.0",
"resolved": "https://registry.npmjs.org/three/-/three-0.143.0.tgz",
"integrity": "sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg=="
},
"throttleit": {
"version": "1.0.0",

View file

@ -91,7 +91,7 @@
"react-icons": "^4.4.0",
"react-toastify": "^5.5.0",
"sprintf": "0.1.5",
"three": "^0.118.3",
"three": "^0.143.0",
"xml2js": "^0.4.23"
}
}

View file

@ -1,6 +1,5 @@
import Vector from 'math/vector';
import BBox from 'math/bbox'
import {MeshSceneSolid} from './scene/wrappers/meshSceneObject'
import {Matrix3x4} from 'math/matrix';
import {equal} from 'math/equality';
import {area, isCCW, isPointInsidePolygon} from "geom/euclidean";
@ -40,29 +39,6 @@ export function createBox(w, h, d) {
return extrude(square, normal, normal.multiply(d), 1);
}
export function createCSGBox(w, h, d) {
var csg = CSG.fromPolygons(createBox(w, h, d));
return createSolid(csg);
}
export function createSphere(radius) {
var csg = CSG.sphere({radius: radius, resolution: 48});
var shared = createShared();
shared.__tcad.csgInfo = {
derivedFrom : {
id : 0,
_class : 'TCAD.TWO.Circle'
}
};
for (var i = 0; i < csg.polygons.length; i++) {
var poly = csg.polygons[i];
poly.shared = shared;
}
var solid = createSolid(csg);
solid.cadGroup.remove(solid.wireframeGroup);
return solid;
}
export function checkPolygon(poly) {
if (poly.length < 3) {
throw new Error('Polygon should contain at least 3 point');
@ -92,9 +68,9 @@ export function createPoint0(x, y, z) {
" gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n"
+'\n}'
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(x, y, z));
const geometry = new THREE.BufferGeometry().setFromPoints( [new THREE.Vector3(x, y, z)] );
// geometry.vertices.push(new THREE.Vector3(x+.001, y+.001, z+.001));
// var line = new THREE.PointCloud(geometry, material);
@ -124,9 +100,12 @@ export function createLine(a, b, color) {
color: color,
linewidth: 1
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(a.x, a.y, a.z));
geometry.vertices.push(new THREE.Vector3(b.x, b.y, b.z));
const vertices = []
vertices.push(new THREE.Vector3(a.x, a.y, a.z));
vertices.push(new THREE.Vector3(b.x, b.y, b.z));
const geometry = new THREE.BufferGeometry().setFromPoints( vertices );
return new THREE.Line(geometry, material);
}
@ -142,10 +121,6 @@ export function createSolidMaterial() {
});
}
export function createSolid(csg, id) {
return new MeshSceneSolid(csg, undefined, id);
}
export function intercept(obj, methodName, aspect) {
var originFunc = obj[methodName];
obj[methodName] = function() {
@ -154,61 +129,6 @@ export function intercept(obj, methodName, aspect) {
}
}
export function createPlane(basis, depth) {
var initWidth = 1;
var boundingPolygon = [
new Vector(0, 0, 0),
new Vector(initWidth, 0, 0),
new Vector(initWidth, initWidth, 0),
new Vector(0, initWidth, 0)
];
var shared = createShared();
var material = createSolidMaterial();
material.transparent = true;
material.opacity = 0.5;
material.side = THREE.DoubleSide;
var tr = new Matrix3x4().setBasis(basis);
var currentBounds = new BBox();
var points = boundingPolygon.map(function(p) { p.z = depth; return tr._apply(p); });
var polygon = new CSG.Polygon(points.map(function(p){return new CSG.Vertex(csgVec(p))}), shared);
var plane = new MeshSceneSolid(CSG.fromPolygons([polygon]), 'PLANE');
plane.wireframeGroup.visible = false;
plane.mergeable = false;
function setBounds(bbox) {
currentBounds = bbox;
const poly = new CSG.Polygon(bbox.toPolygon().map(function(p){p.z = depth; return new CSG.Vertex(csgVec( tr._apply(p) ))}), shared);
plane.csg = CSG.fromPolygons([poly]);
plane.dropGeometry();
plane.createGeometry();
}
var bb = new BBox();
bb.checkBounds(-400, -400);
bb.checkBounds( 400, 400);
setBounds(bb);
var sketchFace = plane.sceneFaces[0];
intercept(sketchFace, 'syncSketches', function(invocation, args) {
var geom = args[0];
invocation(geom);
var bbox = new BBox();
var connections = geom.connections.concat(arrFlatten1L(geom.loops));
for (var i = 0; i < connections.length; ++i) {
var l = connections[i];
bbox.checkBounds(l.a.x, l.a.y);
bbox.checkBounds(l.b.x, l.b.y);
}
if (bbox.maxX > currentBounds.maxX || bbox.maxY > currentBounds.maxY || bbox.minX < currentBounds.minX || bbox.minY < currentBounds.minY) {
bbox.expand(50);
setBounds(bbox);
}
});
return plane;
}
export function fixCCW(path, normal) {
var _2DTransformation = new Matrix3x4().setBasis(someBasis(path, normal)).invert();
var path2D = [];
@ -300,63 +220,6 @@ export function calculateExtrudedLid(sourcePolygon, normal, direction, expansion
return lid;
}
export function extrude(source, sourceNormal, target, expansionFactor) {
var extrudeDistance = target.normalize().dot(sourceNormal);
if (extrudeDistance == 0) {
return [];
}
var negate = extrudeDistance < 0;
var poly = [null, null];
var lid = calculateExtrudedLid(source, sourceNormal, target, expansionFactor);
var bottom, top;
if (negate) {
bottom = lid;
top = source;
} else {
bottom = source;
top = lid;
}
var n = source.length;
for ( var p = n - 1, i = 0; i < n; p = i ++ ) {
var shared = createShared();
shared.__tcad.csgInfo = {derivedFrom: source[p].sketchConnectionObject};
var face = new CSG.Polygon([
new CSG.Vertex(csgVec(bottom[p])),
new CSG.Vertex(csgVec(bottom[i])),
new CSG.Vertex(csgVec(top[i])),
new CSG.Vertex(csgVec(top[p]))
], shared);
poly.push(face);
}
var bottomNormal, topNormal;
if (negate) {
lid.reverse();
bottomNormal = sourceNormal;
topNormal = sourceNormal.negate();
} else {
source = source.slice(0);
source.reverse();
bottomNormal = sourceNormal.negate();
topNormal = sourceNormal;
}
function vecToVertex(v) {
return new CSG.Vertex(csgVec(v));
}
var sourcePlane = new CSG.Plane(bottomNormal.csg(), bottomNormal.dot(source[0]));
var lidPlane = new CSG.Plane(topNormal.csg(), topNormal.dot(lid[0]));
poly[0] = new CSG.Polygon(source.map(vecToVertex), createShared(), sourcePlane);
poly[1] = new CSG.Polygon(lid.map(vecToVertex), createShared(), lidPlane);
return poly;
}
export function triangulate(path, normal) {
var _3dTransformation = new Matrix3x4().setBasis(someBasis2(normal));
var _2dTransformation = _3dTransformation.invert();
@ -370,13 +233,6 @@ export function triangulate(path, normal) {
// return THREE.Shape.utils.triangulateShape( f2d.shell, f2d.holes );
}
export function createShared() {
var id = Counters.shared ++;
var shared = new CSG.Polygon.Shared([id, id, id, id]);
shared.__tcad = {};
return shared;
}
export function isCurveClass(className) {
return false;
}

View file

@ -1,4 +1,4 @@
import {Geometry, Line, LineBasicMaterial, MeshBasicMaterial, Object3D, Vector3} from 'three';
import {BufferGeometry, Line, LineBasicMaterial, MeshBasicMaterial, Object3D, Vector3} from 'three';
import CSysObject3D from './csysObject';
@ -56,10 +56,10 @@ export default class DatumObject3D extends Object3D {
let ext = dir.multiply(this.viewer.sceneSetup.workingSphere);
const material = new LineBasicMaterial({color});
let geometry = new Geometry();
geometry.vertices.push(new Vector3().copy(this.csys.origin.minus(ext)));
geometry.vertices.push(new Vector3().copy(this.csys.origin.plus(ext)));
const geometry = new BufferGeometry().setFromPoints( [
new Vector3().copy(this.csys.origin.minus(ext)),
new Vector3().copy(this.csys.origin.plus(ext))
]);
let line = new Line(geometry, material);
this.add(line);

View file

@ -1,6 +1,5 @@
import {checkForSelectedFaces} from './actions/actionHelpers';
import {brepFaceToGeom, surfaceToThreeGeom} from './scene/wrappers/brepSceneObject';
import {createSolidMaterial} from './scene/wrappers/sceneObject';
import {brepFaceToGeom, createSolidMaterial, surfaceToThreeGeom, tessDataToGeom} from './scene/views/viewUtils';
import DPR from 'dpr';
import Vector from 'math/vector';
import * as vec from 'math/vec';
@ -10,7 +9,6 @@ import {toLoops} from 'brep/io/brepLoopsFormat';
import curveTess from 'geom/impl/curve/curve-tess';
import {LOG_FLAGS} from './logFlags';
import {state} from "lstream";
import {BufferGeometry, BufferAttribute, Float32BufferAttribute, Int32BufferAttribute} from 'three';
const BREP_DEBUG_WINDOW_VISIBLE$ = state(false);
@ -116,17 +114,20 @@ function addGlobalDebugActions({viewer, cadScene, cadRegistry}) {
},
AddVolume: (shell, color) => {
color = color || 0xffffff;
const geometry = new THREE.Geometry();
shell.faces.forEach(f => brepFaceToGeom(f, geometry));
triangulateToThree(shell, geometry);
const mesh = new THREE.Mesh(geometry, createSolidMaterial({
color,
transparent: true,
opacity: 0.3,
depthWrite: false,
depthTest: false
}));
debugVolumeGroup.add(mesh);
// const geometry = new THREE.Geometry();
shell.faces.forEach(f => {
const geometry = brepFaceToGeom(f,)
const mesh = new THREE.Mesh(geometry, createSolidMaterial({
color,
transparent: true,
opacity: 0.3,
depthWrite: false,
depthTest: false
}));
debugVolumeGroup.add(mesh);
});
// window.__DEBUG__.AddWireframe(shell, color);
viewer.render();
},
@ -134,19 +135,20 @@ function addGlobalDebugActions({viewer, cadScene, cadRegistry}) {
color = color || 0xffffff;
const visited = new Set();
for (let e of shell.edges) {
let lg = new THREE.Geometry();
lg.vertices.push(e.halfEdge1.vertexA.point.three());
lg.vertices.push(e.halfEdge2.vertexA.point.three());
const line = new THREE.Line(lg, new THREE.LineBasicMaterial({color, linewidth: 3/DPR}));
const vertices = []
vertices.push(e.halfEdge1.vertexA.point.three());
vertices.push(e.halfEdge2.vertexA.point.three());
const lg = new THREE.BufferGeometry().setFromPoints( vertices );
const line = new THREE.Line(lg, new THREE.LineBasicMaterial({color, linewidth: 3/DPR}));
debugVolumeGroup.add(line);
}
viewer.render();
},
AddParametricSurface: (srf, color) => {
color = color || 0xffffff;
const geometry = new THREE.Geometry();
surfaceToThreeGeom(srf, geometry);
geometry.computeFaceNormals();
const geometry = surfaceToThreeGeom(srf);
const mesh = new THREE.Mesh(geometry, createSolidMaterial({
color,
transparent: true,
@ -192,22 +194,8 @@ function addGlobalDebugActions({viewer, cadScene, cadRegistry}) {
AddTessDump: (triangles, color) => {
const vec = arr => new THREE.Vector3().fromArray(arr);
color = color || 0xffffff;
const geometry = new THREE.Geometry();
for (let i = 0; i < triangles.length; ++i) {
let off = geometry.vertices.length;
let tr = triangles[i], normales;
if (Array.isArray(tr[0][0])) {
normales = tr[1];
tr = tr[0];
if (normales.find(n => n[0] === null || n[1] === null || n[2] === null)) {
normales = undefined;
}
}
tr.forEach(p => geometry.vertices.push(vec(p)));
const face = new THREE.Face3(off, off + 1, off + 2, normales && normales.map(vec));
geometry.faces.push(face);
}
geometry.computeFaceNormals();
const geometry = tessDataToGeom(triangles);
const mesh = new THREE.Mesh(geometry, createSolidMaterial({
vertexColors: THREE.FaceColors,
color: 0xB0C4DE,
@ -282,9 +270,8 @@ function clearGroup(g) {
export function createLine(a, b, color) {
color = color || 0xFA8072;
const debugLineMaterial = new THREE.LineBasicMaterial({color, linewidth: 10});
const lg = new THREE.Geometry();
lg.vertices.push(a.three());
lg.vertices.push(b.three());
const vertices = [a.three(), b.three()];
const lg = new THREE.BufferGeometry().setFromPoints( vertices );
return new THREE.Line(lg, debugLineMaterial);
}

View file

@ -1,11 +1,12 @@
import stlExporter from './stl/stlExporter';
import {STLExporter} from './stl/stlExporter';
import exportTextData from 'gems/exportTextData';
export function activate(ctx) {
function toStlAsciiString() {
let views = ctx.services.cadRegistry.shells.map(mShell => mShell.ext.view).filter(m => !!m);
return stlExporter(views);
const exporter = new STLExporter();
const views = ctx.services.cadRegistry.shells.map(mShell => mShell.ext.view).filter(m => !!m);
return exporter.parse( views );
}
function stlAscii() {

View file

@ -289,8 +289,8 @@ export function traversePickResults(event, pickResults, kind, visitor) {
return false;
},
(pickResult) => {
if (mask.is(kind, PICK_KIND.LOOP) && !!pickResult.face) {
let faceV = getAttribute(pickResult.face, LOOP);
if (mask.is(kind, PICK_KIND.LOOP)) {
let faceV = getAttribute(pickResult.object, LOOP);
if (faceV) {
return !visitor(faceV.model, event, pickResult);
}
@ -298,8 +298,8 @@ export function traversePickResults(event, pickResults, kind, visitor) {
return false;
},
(pickResult) => {
if (mask.is(kind, PICK_KIND.FACE) && !!pickResult.face) {
let faceV = getAttribute(pickResult.face, FACE);
if (mask.is(kind, PICK_KIND.FACE)) {
let faceV = getAttribute(pickResult.object, FACE);
if (faceV) {
return !visitor(faceV.model, event, pickResult);
}

View file

@ -2,29 +2,31 @@ import {View} from './view';
import * as SceneGraph from 'scene/sceneGraph';
import {setAttribute} from 'scene/objectData';
import ScalableLine from 'scene/objects/scalableLine';
import {NULL_COLOR} from "cad/scene/views/faceView";
export class CurveBasedView extends View {
constructor(ctx, model, tessellation, visualWidth, markerWidth, color, defaultMarkColor, offset, markTable) {
constructor(ctx, model, tessellation, visualWidth, color, markTable) {
super(ctx, model, undefined, markTable);
this.rootGroup = SceneGraph.createGroup();
this.representation = new ScalableLine(tessellation, visualWidth, color, undefined, false, true, offset);
this.marker = new ScalableLine(tessellation, markerWidth, defaultMarkColor, undefined, false, true, offset);
this.picker = new ScalableLine(tessellation, 10, 0xFA8072, undefined, false, true, offset);
this.marker.visible = false;
this.picker.material.visible = false;
this.representation = new ScalableLine(ctx.viewer.sceneSetup, tessellation, visualWidth, color, undefined, false, true, false);
this.setColor(color);
// this.marker = new ScalableLine(tessellation, markerWidth, defaultMarkColor, undefined, false, true, offset);
// this.picker = new ScalableLine(tessellation, 10, 0xFA8072, undefined, false, true, offset);
// this.marker.visible = false;
// this.picker.material.visible = false;
setAttribute(this.representation, model.TYPE, this);
setAttribute(this.picker, model.TYPE, this);
// setAttribute(this.picker, model.TYPE, this);
this.rootGroup.add(this.representation);
this.rootGroup.add(this.marker);
this.rootGroup.add(this.picker);
this.picker.onMouseEnter = () => {
// this.rootGroup.add(this.marker);
// this.rootGroup.add(this.picker);
this.representation.onMouseEnter = () => {
if (!this.isDisposed) {
this.ctx.highlightService.highlight(this.model.id);
}
}
this.picker.onMouseLeave = () => {
this.representation.onMouseLeave = () => {
if (!this.isDisposed) {
this.ctx.highlightService.unHighlight(this.model.id);
}
@ -33,20 +35,21 @@ export class CurveBasedView extends View {
updateVisuals() {
const markColor = this.markColor;
if (!markColor) {
this.marker.visible = false;
this.representation.visible = true;
} else {
this.marker.material.color.set(markColor);
this.marker.visible = true;
this.representation.visible = false;
}
this.representation.material.color.set(this.markColor||this.color);
// if (this.markColor) {
//
// this.representation.material.color.set( new Color().set(this.markColor) );
// }
// this.representation.material.needsUpdate = true;
// this.representation.needsUpdate = true;
}
dispose() {
this.representation.dispose();
this.marker.dispose();
// this.marker.dispose();
super.dispose();
}
}

View file

@ -18,6 +18,6 @@ export class EdgeView extends CurveBasedView {
constructor(ctx, edge) {
let brepEdge = edge.brepEdge;
let tess = brepEdge.data.tessellation ? brepEdge.data.tessellation : brepEdge.curve.tessellateToData();
super(ctx, edge, tess, 2, 4, 0x2B3856, 0xc42720, false, MarkerTable);
super(ctx, edge, tess, 3, 0x000000, MarkerTable);
}
}

View file

@ -1,13 +1,12 @@
import {setAttribute} from 'scene/objectData';
import {brepFaceToGeom, tessDataToGeom} from '../wrappers/brepSceneObject';
import {FACE} from 'cad/model/entities';
import {brepFaceToGeom, tessDataToGeom} from './viewUtils';
import * as SceneGraph from 'scene/sceneGraph';
import {SketchObjectView} from './sketchObjectView';
import {View} from './view';
import {SketchLoopView} from './sketchLoopView';
import {createSolidMaterial} from "cad/scene/wrappers/sceneObject";
import {createSolidMaterial} from "cad/scene/views/viewUtils";
import {SketchMesh} from "cad/scene/views/shellView";
import {Geometry} from "three";
import {FACE} from "cad/model/entities";
import {setAttribute} from "scene/objectData";
export class SketchingView extends View {
@ -68,26 +67,18 @@ export class FaceView extends SketchingView {
constructor(ctx, face, parent, skin) {
super(ctx, face, parent);
const geom = new Geometry();
geom.dynamic = true;
this.geometry = geom;
let geom;
this.material = createSolidMaterial(skin);
this.meshFaces = [];
const off = geom.faces.length;
if (face.brepFace.data.tessellation) {
tessDataToGeom(face.brepFace.data.tessellation.data, geom)
geom = tessDataToGeom(face.brepFace.data.tessellation.data)
} else {
brepFaceToGeom(face.brepFace, geom);
geom = brepFaceToGeom(face.brepFace);
}
for (let i = off; i < geom.faces.length; i++) {
const meshFace = geom.faces[i];
this.meshFaces.push(meshFace);
setAttribute(meshFace, FACE, this);
}
geom.mergeVertices();
this.geometry = geom;
this.material = createSolidMaterial(skin);
this.mesh = new SketchMesh(geom, this.material);
setAttribute(this.mesh, FACE, this);
this.mesh.onMouseEnter = () => {
this.ctx.highlightService.highlight(this.model.id);
}
@ -114,5 +105,5 @@ export function setFacesColor(faces, color) {
}
}
export const NULL_COLOR = new THREE.Color(0xbfbfbf);
const NULL_COLOR = 0xbfbfbf;

View file

@ -3,6 +3,9 @@ import {FACE, SHELL} from 'cad/model/entities';
import {SketchingView} from './faceView';
import {View} from './view';
import {SketchMesh} from './shellView';
import {BufferAttribute, BufferGeometry} from 'three';
import * as vec from "math/vec";
import {normalOfCCWSeq} from "cad/cad-utils";
export class OpenFaceShellView extends View {
@ -27,7 +30,6 @@ export class OpenFaceView extends SketchingView {
constructor(ctx, mFace, parent) {
super(ctx, mFace, parent);
this.material = new THREE.MeshPhongMaterial({
vertexColors: THREE.FaceColors,
// color: 0xB0C4DE,
shininess: 0,
polygonOffset : true,
@ -48,14 +50,26 @@ export class OpenFaceView extends SketchingView {
}
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 => setAttribute(f, FACE, this));
geometry.computeFaceNormals();
const vertices = [];;
const normals = [];;
const normal = normalOfCCWSeq(this.bounds);
this.bounds.forEach((v, i) => {
vertices.push(v.x, v.y, v.z);
normals.push(normal.x, normal.y, normal.z);
});
const index = [
0, 1, 2,
0, 2, 3
];
const geometry = new BufferGeometry();
geometry.setAttribute('position', new BufferAttribute( new Float32Array(vertices), 3));
geometry.setAttribute('normal', new BufferAttribute( new Float32Array(normals), 3));
geometry.setIndex(index);
this.mesh = new SketchMesh(geometry, this.material);
setAttribute(this.mesh, FACE, this)
this.rootGroup.add(this.mesh);
this.mesh.onMouseEnter = () => {
this.ctx.highlightService.highlight(this.model.id);

View file

@ -1,12 +1,12 @@
import {MarkTracker, View} from './view';
import {View} from './view';
import * as SceneGraph from 'scene/sceneGraph';
import {tessellateLoopsOnSurface} from '../../tess/brep-tess';
import {createSolidMaterial} from '../wrappers/sceneObject';
import {DoubleSide, Geometry, Mesh} from 'three';
import {surfaceAndPolygonsToGeom} from '../wrappers/brepSceneObject';
import {TriangulatePolygons} from '../../tess/triangulation';
import {tessellateLoopsOnSurface} from 'cad/tess/brep-tess';
import {createSolidMaterial} from '../views/viewUtils';
import {DoubleSide, Mesh} from 'three';
import {surfaceAndPolygonsToGeom} from './viewUtils';
import {TriangulatePolygons} from 'cad/tess/triangulation';
import Vector from 'math/vector';
import {LOOP} from '../../model/entities';
import {LOOP} from 'cad/model/entities';
import {setAttribute} from 'scene/objectData';
const HIGHLIGHT_COLOR = 0xDBFFD9;
@ -32,19 +32,7 @@ export class SketchLoopView extends View {
super(ctx, mLoop, MarkerTable);
this.rootGroup = SceneGraph.createGroup();
const geometry = new Geometry();
geometry.dynamic = true;
this.mesh = new Mesh(geometry, createSolidMaterial({
// color: HIGHLIGHT_COLOR,
side: DoubleSide,
// transparent: true,
// depthTest: true,
// depthWrite: false,
polygonOffset: true,
polygonOffsetFactor: -1.0, // should less than offset of loop lines
polygonOffsetUnits: -1.0,
visible: false
}));
let surface = mLoop.face.surface;
let tess;
if (surface.simpleSurface && surface.simpleSurface.isPlane) {
@ -56,12 +44,21 @@ export class SketchLoopView extends View {
seg => seg.inverted);
}
surfaceAndPolygonsToGeom(surface, tess, this.mesh.geometry);
this.mesh.geometry.mergeVertices();
for (let i = 0; i < geometry.faces.length; i++) {
const meshFace = geometry.faces[i];
setAttribute(meshFace, LOOP, this);
}
const geometry = surfaceAndPolygonsToGeom(surface, tess);
this.mesh = new Mesh(geometry, createSolidMaterial({
// color: HIGHLIGHT_COLOR,
side: DoubleSide,
// transparent: true,
// depthTest: true,
// depthWrite: false,
polygonOffset: true,
polygonOffsetFactor: -1.0, // should less than offset of loop lines
polygonOffsetUnits: -1.0,
visible: false
}));
setAttribute(this.mesh, LOOP, this);
this.rootGroup.add(this.mesh);
this.mesh.onMouseEnter = () => {

View file

@ -5,8 +5,8 @@ export class SketchObjectView extends CurveBasedView {
constructor(ctx, mSketchObject, sketchToWorldTransformation) {
const color = mSketchObject.construction ? 0x964B00 : 0x0000FF;
const tess = mSketchObject.sketchPrimitive.tessellate(10).map(sketchToWorldTransformation.apply).map(v => v.data());
super(ctx, mSketchObject, tess, 3, 4, color, 0x49FFA5, true);
this.picker.onDblclick = () => {
super(ctx, mSketchObject, tess, 3, color);
this.representation.onDblclick = () => {
ctx.sketcherService.sketchFace(this.model.face);
}
}

View file

@ -0,0 +1,105 @@
import {BufferAttribute, BufferGeometry, DoubleSide} from "three";
import brepTess from '../../tess/brep-tess';
import tessellateSurface from 'geom/surfaces/surfaceTess';
import * as vec from 'math/vec';
export function createSolidMaterial(skin) {
return new THREE.MeshPhongMaterial(Object.assign({
// vertexColors: THREE.FaceColors,
color: 0xaeaeae,
shininess: 0,
polygonOffset : true,
polygonOffsetFactor : 1,
polygonOffsetUnits : 2,
side: DoubleSide,
}, skin));
}
const SMOOTH_RENDERING = true;
export function tessDataToGeom(tessellation) {
const vertices = [];
const normals3 = [];
for (let [tr, normales] of tessellation) {
tr.forEach(p => vertices.push(...p));
if (normales && SMOOTH_RENDERING) {
normales.forEach(n => normals3.push(...n));
} else {
const n = vec.normal3(tr);
normals3.push(...n, ...n, ...n);
}
}
const geometry = new BufferGeometry();
geometry.setAttribute('position', new BufferAttribute( new Float32Array(vertices), 3));
geometry.setAttribute('normal', new BufferAttribute( new Float32Array(normals3), 3));
return geometry;
}
export function brepFaceToGeom(brepFace) {
const polygons = brepTess(brepFace);
return surfaceAndPolygonsToGeom(brepFace.surface, polygons);
}
export function surfaceAndPolygonsToGeom(surface, polygons) {
const vertices = [];
const normals = [];
const index = [];
const isPlane = surface.simpleSurface && surface.simpleSurface.isPlane;
let planeNormal = isPlane ? surface.normalInMiddle().data() : null;
for (let p = 0; p < polygons.length; ++p) {
const off = vertices.length / 3;
const poly = polygons[p];
const vLength = poly.length;
if (vLength < 3) continue;
function pushVertex(vtx) {
vertices.push(vtx.x, vtx.y, vtx.z);
if (!isPlane) {
const normal = surface.normal(vtx);
normals.push(normal.x, normal.y, normal.z);
} else {
normals.push(...planeNormal);
}
}
const firstVertex = poly[0];
pushVertex(firstVertex)
for (let i = 2; i < vLength; i++) {
let pVert = poly[i - 1];
let iVert = poly[i];
pushVertex(pVert);
pushVertex(iVert);
const a = off;
const b = (i - 1) + off;
const c = i + off;
index.push(a, b, c);
}
//view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null);
}
const geometry = new BufferGeometry();
geometry.setAttribute('position', new BufferAttribute( new Float32Array(vertices), 3));
geometry.setAttribute('normal', new BufferAttribute( new Float32Array(normals), 3));
geometry.setIndex( index );
return geometry;
}
export function surfaceToThreeGeom(srf, geom) {
const off = geom.vertices.length;
const tess = tessellateSurface(srf);
tess.points.forEach(p => geom.vertices.push(new THREE.Vector3().fromArray(p)));
for (let faceIndices of tess.faces) {
const face = new THREE.Face3(faceIndices[0] + off, faceIndices[1] + off, faceIndices[2] + off);
geom.faces.push(face);
}
}

View file

@ -1,232 +0,0 @@
import Vector from 'math/vector';
import {SceneEdge, SceneFace, SceneSolid} from './sceneObject';
import brepTess from '../../tess/brep-tess';
import tessellateSurface from 'geom/surfaces/surfaceTess';
import {setAttribute} from 'scene/objectData';
import * as vec from 'math/vec';
import {perpendicularVector} from "geom/euclidean";
const SMOOTH_RENDERING = true;
export class BREPSceneSolid extends SceneSolid {
constructor(shell, type, skin) {
super(type, undefined, skin);
this.shell = shell;
this.externals = this.shell.data.externals;
this.createGeometry();
}
createGeometry() {
const geometry = new THREE.Geometry();
geometry.dynamic = true;
this.mesh = new THREE.Mesh(geometry, this.material);
this.cadGroup.add(this.mesh);
this.createFaces();
this.createEdges();
this.createVertices();
}
createFaces() {
const geom = this.mesh.geometry;
for (let brepFace of this.shell.faces) {
const sceneFace = new BREPSceneFace(brepFace, this);
this.sceneFaces.push(sceneFace);
let off = geom.faces.length;
if (brepFace.data.tessellation) {
tessDataToGeom(brepFace.data.tessellation.data, geom)
} else {
brepFaceToGeom(brepFace, geom);
}
for (let i = off; i < geom.faces.length; i++) {
sceneFace.registerMeshFace(geom.faces[i]);
}
}
geom.mergeVertices();
}
createEdges() {
for (let edge of this.shell.edges) {
this.createEdge(edge);
}
}
createEdge(edge) {
const doEdge = (edge, aux, width, color, opacity) => {
const geometry = new THREE.Geometry();
const scaleTargets = [];
geometry.dynamic = true;
let materialParams = {
color,
vertexColors: THREE.FaceColors,
shininess: 0,
visible: !aux,
morphTargets: true
};
if (opacity !== undefined) {
materialParams.transparent = true;
materialParams.opacity = opacity;
}
let tess = edge.data.tessellation ? edge.data.tessellation : edge.curve.tessellateToData();
let base = null;
for (let i = 1; i < tess.length; i++) {
let a = tess[i - 1];
let b = tess[i];
let ab = vec._normalize(vec.sub(b, a));
let dirs = [];
dirs[0] = perpendicularVector(ab);
dirs[1] = vec.cross(ab, dirs[0]);
dirs[2] = vec.negate(dirs[0]);
dirs[3] = vec.negate(dirs[1]);
dirs.forEach(d => vec._mul(d, width));
if (base === null) {
base = dirs.map(d => vec.add(a, d));
}
let lid = dirs.map(d => vec.add(b, d));
let off = geometry.vertices.length;
base.forEach(p => geometry.vertices.push(vThree(p)));
lid.forEach(p => geometry.vertices.push(vThree(p)));
function addScaleTargets(points, origin) {
points.forEach(p => scaleTargets.push(vThree(vec._add(vec._mul(vec.sub(p, origin), 10), origin))));
}
addScaleTargets(base, a);
addScaleTargets(lid, b);
base = lid;
[
[0, 4, 3],
[3, 4, 7],
[2, 3, 7],
[7, 6, 2],
[0, 1, 5],
[5, 4, 0],
[1, 2, 6],
[6, 5, 1],
].forEach(([a, b, c]) => geometry.faces.push(new THREE.Face3(a + off, b + off, c + off)));
}
geometry.morphTargets.push( { name: "scaleTargets", vertices: scaleTargets } );
geometry.computeFaceNormals();
let mesh = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial(materialParams));
this.wireframeGroup.add(mesh);
// mesh.morphTargetInfluences[ 0 ] = 0.2;
return mesh;
};
let sceneEdge = new SceneEdge(null, this);
sceneEdge.externals = edge.data.externals;
this.sceneEdges.push(sceneEdge);
let representation = doEdge(edge, false, 1, 0x2B3856);
let marker = doEdge(edge, true, 3, 0xFA8072, 0.8);
setAttribute(representation, 'edge', sceneEdge);
setAttribute(marker, 'edge', sceneEdge);
sceneEdge.representation = representation;
sceneEdge.marker = marker;
}
createVertices() {
}
}
class BREPSceneFace extends SceneFace {
constructor(brepFace, solid) {
super(solid, brepFace.id);
brepFace.id = this.id;
this.brepFace = brepFace;
this.externals = this.brepFace.data.externals;
}
normal() {
return this.brepFace.surface.normalInMiddle();
}
depth() {
return this.brepFace.surface.tangentPlaneInMiddle().w;
}
surface() {
return this.brepFace.surface;
}
getBounds() {
const bounds = [];
for (let loop of this.brepFace.loops) {
bounds.push(loop.asPolygon().map(p => new Vector().setV(p)));
}
return bounds;
}
}
export function tessDataToGeom(tessellation, geom) {
for (let [tr, normales] of tessellation) {
let off = geom.vertices.length;
tr.forEach(p => geom.vertices.push(vThree(p)));
if (normales && SMOOTH_RENDERING) {
normales = normales.map(vThree)
} else {
normales = vThree(vec.normal3(tr));
}
const face = new THREE.Face3(off, off + 1, off + 2, normales);
geom.faces.push(face);
}
}
export function brepFaceToGeom(brepFace, geom) {
const polygons = brepTess(brepFace);
return surfaceAndPolygonsToGeom(brepFace.surface, polygons, geom);
}
export function surfaceAndPolygonsToGeom(surface, polygons, geom) {
const isPlane = surface.simpleSurface && surface.simpleSurface.isPlane;
let normalOrNormals;
if (isPlane) {
normalOrNormals = surface.normalInMiddle().three();
}
for (let p = 0; p < polygons.length; ++p) {
const off = geom.vertices.length;
const poly = polygons[p];
const vLength = poly.length;
if (vLength < 3) continue;
const firstVertex = poly[0];
geom.vertices.push(firstVertex.three());
geom.vertices.push(poly[1].three());
for (let i = 2; i < vLength; i++) {
geom.vertices.push(poly[i].three());
const a = off;
const b = i - 1 + off;
const c = i + off;
if (!isPlane) {
normalOrNormals = [firstVertex, poly[i - 1], poly[i]].map(v => surface.normal(v));
}
const face = new THREE.Face3(a, b, c, normalOrNormals);
geom.faces.push(face);
}
//view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null);
}
}
export function surfaceToThreeGeom(srf, geom) {
const off = geom.vertices.length;
const tess = tessellateSurface(srf);
tess.points.forEach(p => geom.vertices.push(new THREE.Vector3().fromArray(p)));
for (let faceIndices of tess.faces) {
const face = new THREE.Face3(faceIndices[0] + off, faceIndices[1] + off, faceIndices[2] + off);
geom.faces.push(face);
}
}
const vThree = arr => new THREE.Vector3().fromArray(arr);

View file

@ -1,214 +0,0 @@
import {HashTable} from '../../../utils/hashmap'
//import {findOutline, reconstructSketchBounds, segmentsToPaths} from '../../legacy/mesh/workbench'
import {isCurveClass} from '../../cad-utils'
import {SceneFace, SceneSolid} from './sceneObject'
export class MeshSceneSolid extends SceneSolid {
constructor(csg, type, id) {
super(type, id);
csg = csg.reTesselated().canonicalized();
this.csg = csg;
this.createGeometry();
}
createGeometry() {
const geometry = new THREE.Geometry();
geometry.dynamic = true;
this.mesh = new THREE.Mesh(geometry, this.material);
this.cadGroup.add(this.mesh);
this.wires = HashTable.forEdge();
this.curvedSurfaces = {};
this.setupGeometry();
}
dropGeometry() {
this.cadGroup.remove( this.mesh );
this.mesh.geometry.dispose();
for(let i = this.wireframeGroup.children.length-1; i >=0 ; i--){
this.wireframeGroup.remove(this.wireframeGroup.children[i]);
}
}
setupGeometry() {
function threeV(v) {return new THREE.Vector3( v.x, v.y, v.z )}
var off = 0;
var groups = groupCSG(this.csg);
var geom = this.mesh.geometry;
for (var gIdx in groups) {
var group = groups[gIdx];
if (group.shared.__tcad === undefined) group.shared.__tcad = {};
var sceneFace = new MeshSceneFace(this, group);
this.sceneFaces.push(sceneFace);
for (var p = 0; p < group.polygons.length; ++p) {
var poly = group.polygons[p];
var vLength = poly.vertices.length;
if (vLength < 3) continue;
var firstVertex = poly.vertices[0];
geom.vertices.push(threeV(firstVertex.pos));
geom.vertices.push(threeV(poly.vertices[1].pos));
var normal = threeV(poly.plane.normal);
for (var i = 2; i < vLength; i++) {
geom.vertices.push(threeV(poly.vertices[i].pos));
var a = off;
var b = i - 1 + off;
var c = i + off;
const face = sceneFace.createMeshFace(a, b, c);
face.normal = normal;
face.materialIndex = gIdx;
geom.faces.push(face);
//face.color.set(new THREE.Color().setRGB( Math.random(), Math.random(), Math.random()));
}
//view.setFaceColor(sceneFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null);
off = geom.vertices.length;
}
this.collectCurvedSurface(sceneFace);
this.collectWires(sceneFace, group.polygons);
}
geom.mergeVertices();
this.processWires();
};
collectCurvedSurface(face) {
var derivedFrom = getDerivedFrom(face.csgGroup.shared);
if (derivedFrom === null || !isCurveClass(derivedFrom._class)) return;
var surfaces = this.curvedSurfaces[derivedFrom.id];
if (surfaces === undefined) {
surfaces = [];
this.curvedSurfaces[derivedFrom.id] = surfaces;
}
surfaces.push(face);
face.curvedSurfaces = surfaces;
}
collectWires(face, facePolygons) {
function contains(planes, plane) {
for (var j = 0; j < planes.length; j++) {
if (planes[j].equals(plane)) {
return true;
}
}
return false;
}
const outline = findOutline(facePolygons);
const paths = segmentsToPaths(outline);
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
var p, q, n = path.vertices.length;
for (q = 0, p = n - 1; q < n; p = q++) {
var edge = [path.vertices[p], path.vertices[q]];
var data = this.wires.get(edge);
if (data === null) {
data = {
sharedPlanes : [face.csgGroup.plane],
sharedFaces : [face]
};
this.wires.put(edge, data);
} else {
if (!contains(data.sharedPlanes, face.csgGroup.plane)) {
data.sharedPlanes.push(face.csgGroup.plane);
}
data.sharedFaces.push(face);
}
}
}
}
processWires() {
var solid = this;
this.wires.entries(function(edge, data) {
if (data.sharedPlanes.length > 1) {
var plane0 = data.sharedPlanes[0];
var plane1 = data.sharedPlanes[1];
var angle = Math.acos(plane0.normal.dot(plane1.normal));
if (angle < SMOOTH_LIMIT) {
return;
}
}
for (var i = 0; i < data.sharedFaces.length; ++i) {
for (var j = i + 1; j < data.sharedFaces.length; ++j) {
var face0 = data.sharedFaces[0];
var face1 = data.sharedFaces[1];
if (sameID(getDerivedID(face0.csgGroup.shared), getDerivedID(face1.csgGroup.shared))) {
return;
}
}
}
solid.addLineToScene(edge[0], edge[1]);
});
}
}
function groupCSG(csg) {
var csgPolygons = csg.toPolygons();
var groups = {};
for (var i = 0; i < csgPolygons.length; i++) {
var p = csgPolygons[i];
var tag = p.shared.getTag();
if (groups[tag] === undefined) {
groups[tag] = {
tag : tag,
polygons : [],
shared : p.shared,
plane : p.plane
};
}
groups[tag].polygons.push(p);
}
return groups;
}
const SMOOTH_LIMIT = 10 * Math.PI / 180;
class MeshSceneFace extends SceneFace {
constructor(solid, csgGroup) {
super(solid, csgGroup.shared.__tcad.faceId);
csgGroup.__face = this;
csgGroup.shared.__tcad.faceId = this.id;
this.csgGroup = csgGroup;
this.curvedSurfaces = null;
}
normal() {
return this.csgGroup.plane.normal;
}
depth() {
return this.csgGroup.plane.w;
}
surface() {
return this.csgGroup.plane;
}
getBounds() {
return reconstructSketchBounds(this.solid.csg, this);
}
}
function sameID(id1, id2) {
if (id1 === null || id2 === null) {
return false;
}
return id1 === id2;
}
function getDerivedID(shared) {
return shared.__tcad && !!shared.__tcad.csgInfo && !!shared.__tcad.csgInfo.derivedFrom ? shared.__tcad.csgInfo.derivedFrom.id : null;
}
function getDerivedFrom(shared) {
return shared.__tcad && !!shared.__tcad.csgInfo && !!shared.__tcad.csgInfo.derivedFrom ? shared.__tcad.csgInfo.derivedFrom : null;
}

View file

@ -1,80 +0,0 @@
import Vector from 'math/vector';
import {SceneFace, SceneSolid} from './sceneObject';
import {createBoundingSurfaceFrom2DPoints} from 'brep/brep-builder';
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.surface = createBoundingSurfaceFrom2DPoints([
new Vector(0,0,0), new Vector(0,100,0), new Vector(100,100,0), new Vector(100,0,0)
], 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));
this.createGeometry();
}
}
class PlaneSceneFace extends SceneFace {
constructor(scenePlane) {
super(scenePlane);
}
normal() {
return this.solid.plane.normal;
}
depth() {
return this.solid.plane.w;
}
surface() {
return this.solid.surface;
}
getBounds() {
return [];
}
}

View file

@ -1,198 +0,0 @@
import Vector from 'math/vector';
import DPR from 'dpr'
import {getAttribute, setAttribute} from "scene/objectData";
import {BasisForPlane} from 'math/basis';
import {DoubleSide} from "three";
//todo: rename to shell
export class SceneSolid {
ID = 0;
constructor(type, id, skin) {
this.tCadType = type || 'SHELL';
this.cadGroup = new THREE.Object3D();
setAttribute(this.cadGroup, 'shell', this);
this.tCadId = SceneSolid.ID++;
this.id = id === undefined ? this.tCadId : id; // to keep identity through the history
this.faceCounter = 0;
this.edgeCounter = 0;
this.wireframeGroup = new THREE.Object3D();
this.cadGroup.add(this.wireframeGroup);
this.mergeable = true;
this.sceneFaces = [];
this.sceneEdges = [];
this.sketch = null;
this.material = createSolidMaterial(skin);
}
addLineToScene(a, b) {
let lg = new THREE.Geometry();
lg.vertices.push(a);
lg.vertices.push(b);
let line = new THREE.Line(lg, WIREFRAME_MATERIAL);
this.wireframeGroup.add(line);
return line;
}
dispose() {
this.material.dispose();
this.mesh.geometry.dispose();
}
}
export function createSolidMaterial(skin) {
return new THREE.MeshPhongMaterial(Object.assign({
vertexColors: THREE.FaceColors,
color: 0xaeaeae,
shininess: 0,
polygonOffset : true,
polygonOffsetFactor : 1,
polygonOffsetUnits : 2,
side: DoubleSide,
}, skin));
}
const OFF_LINES_VECTOR = new Vector();//normal.multiply(0); // disable it. use polygon offset feature of material
export class SceneFace {
constructor(solid, propagatedId) {
if (propagatedId === undefined) {
this.id = solid.tCadId + ":" + (solid.faceCounter++);
} else {
this.id = propagatedId;
}
this.solid = solid;
this.meshFaces = [];
this.sketch3DGroup = null;
}
normal() {
throw 'not implemented';
}
depth() {
throw 'not implemented';
}
getBounds() {
throw 'not implemented';
}
surface() {
throw 'not implemented';
}
calcBasis() {
return BasisForPlane(this.normal());
};
basis() {
if (!this._basis) {
this._basis = this.calcBasis();
}
return this._basis;
}
createMeshFace(a, b, c, normales) {
const face = new THREE.Face3(a, b, c, normales);
this.registerMeshFace(face);
return face;
}
registerMeshFace(threeFace) {
this.meshFaces.push(threeFace);
setAttribute(threeFace, 'face', this);
}
updateSketch(sketch) {
this.sketch = sketch;
if (this.sketch !== null) {
this.syncSketch(this.sketch);
}
}
syncSketch(geom) {
if (this.sketch3DGroup !== null) {
for (let i = this.sketch3DGroup.children.length - 1; i >= 0; --i) {
this.sketch3DGroup.remove(this.sketch3DGroup.children[i]);
}
} else {
this.sketch3DGroup = new THREE.Object3D();
this.solid.cadGroup.add(this.sketch3DGroup);
}
let surface = this.surface();
const _3dTransformation = surface.tangentPlaneInMiddle().get3DTransformation();
const addSketchObjects = (sketchObjects, material, close) => {
for (let sketchObject of sketchObjects) {
let line = new THREE.Line(new THREE.Geometry(), material);
let sceneSketchObject = new SceneSketchObject(sketchObject, line);
setAttribute(line, 'sketchObject', sceneSketchObject);
const chunks = sketchObject.tessellate(10);
function addLine(p, q) {
const lg = line.geometry;
const a = _3dTransformation.apply(chunks[p]);
const b = _3dTransformation.apply(chunks[q]);
lg.vertices.push(a._plus(OFF_LINES_VECTOR).three());
lg.vertices.push(b._plus(OFF_LINES_VECTOR).three());
}
for (let q = 1; q < chunks.length; q ++) {
addLine(q - 1, q);
}
this.sketch3DGroup.add(line);
}
};
addSketchObjects(geom.constructionSegments, SKETCH_CONSTRUCTION_MATERIAL);
addSketchObjects(geom.connections, SKETCH_MATERIAL);
addSketchObjects(geom.loops, SKETCH_MATERIAL);
}
findById(sketchObjectId) {
for (let o of this.sketch3DGroup.children) {
let sceneSketchObject = getAttribute(o, 'sketchObject');
if (sceneSketchObject && sceneSketchObject.id === sketchObjectId) {
return sceneSketchObject;
}
}
}
getSketchObjectVerticesIn3D(sketchObjectId) {
const object = this.findById(sketchObjectId);
if (!object) {
return undefined;
}
return object.geometry.vertices;
}
}
export class SceneEdge {
constructor(curve, solid, representation, marker) {
this.id = solid.tCadId + ":" + (solid.edgeCounter++);
this.curve = curve;
this.solid = solid;
this.representation = representation;
this.marker = marker;
}
}
export class SceneSketchObject {
constructor(model, viewObject) {
this.id = model.id;
this.model = model;
this.viewObject = viewObject;
}
}
export const SKETCH_MATERIAL = new THREE.LineBasicMaterial({color: 0xFFFFFF, linewidth: 3/DPR});
export const SKETCH_CONSTRUCTION_MATERIAL = new THREE.LineBasicMaterial({color: 0x777777, linewidth: 2/DPR});
export const WIREFRAME_MATERIAL = new THREE.LineBasicMaterial({color: 0x2B3856, linewidth: 3/DPR});

View file

@ -1,76 +1,204 @@
// copied from THREE.JS three/examples/js/exporters/STLExporter and slightly modified
import {Mesh} from 'three';
/**
* @author kovacsv / http://kovacsv.hu/
* @author mrdoob / http://mrdoob.com/
* Usage:
* const exporter = new STLExporter();
*
* // second argument is a list of options
* const data = exporter.parse( mesh, { binary: true } );
*
*/
import {BufferGeometry, Geometry, Matrix3, Mesh, Vector3} from 'three';
export class STLExporter {
parse(shellViews, options = {}) {
const binary = options.binary !== undefined ? options.binary : false; //
const objects = [];
let triangles = 0;
let vector = new Vector3();
let normalMatrixWorld = new Matrix3();
shellViews.forEach(function (view) {
if (!view.faceViews) {
return;
}
export default function (shellViews) {
view.faceViews.forEach(faceView => {
const object = faceView.mesh;
if (object instanceof Mesh) {
const geometry = object.geometry;
let output = '';
if (geometry.isBufferGeometry !== true) {
shellViews.forEach(view => {
throw new Error('THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.');
}
const index = geometry.index;
const positionAttribute = geometry.getAttribute('position');
triangles += index !== null ? index.count / 3 : positionAttribute.count / 3;
objects.push({
object3d: object,
geometry: geometry,
modelId: view.model.id
});
}
});
});
let output;
let offset = 80; // skip header
if (binary === true) {
const bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4;
const arrayBuffer = new ArrayBuffer(bufferLength);
output = new DataView(arrayBuffer);
output.setUint32(offset, triangles, true);
offset += 4;
} else {
output = '';
output += 'solid exported\n';
if (!view.faceViews) {
return;
}
output += `solid ${view.model.id}\n`;
const vA = new THREE.Vector3();
const vB = new THREE.Vector3();
const vC = new THREE.Vector3();
const cb = new THREE.Vector3();
const ab = new THREE.Vector3();
const normal = new THREE.Vector3();
view.faceViews.forEach(faceView => {
const mesh = faceView.mesh;
if (mesh instanceof Mesh) {
for (let i = 0, il = objects.length; i < il; i++) {
let geometry = mesh.geometry;
let matrixWorld = mesh.matrixWorld;
const object = objects[i].object3d;
const geometry = objects[i].geometry;
const index = geometry.index;
const positionAttribute = geometry.getAttribute('position');
if (geometry instanceof BufferGeometry) {
if (index !== null) {
geometry = new Geometry().fromBufferGeometry(geometry);
// indexed geometry
for (let j = 0; j < index.count; j += 3) {
const a = index.getX(j + 0);
const b = index.getX(j + 1);
const c = index.getX(j + 2);
writeFace(a, b, c, positionAttribute, object);
}
if (geometry instanceof Geometry) {
} else {
let vertices = geometry.vertices;
let faces = geometry.faces;
// non-indexed geometry
for (let j = 0; j < positionAttribute.count; j += 3) {
normalMatrixWorld.getNormalMatrix(matrixWorld);
for (let i = 0, l = faces.length; i < l; i++) {
let face = faces[i];
vector.copy(face.normal).applyMatrix3(normalMatrixWorld).normalize();
output += '\tfacet normal ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n';
output += '\t\touter loop\n';
let indices = [face.a, face.b, face.c];
for (let j = 0; j < 3; j++) {
vector.copy(vertices[indices[j]]).applyMatrix4(matrixWorld);
output += '\t\t\tvertex ' + vector.x + ' ' + vector.y + ' ' + vector.z + '\n';
}
output += '\t\tendloop\n';
output += '\tendfacet\n';
}
const a = j + 0;
const b = j + 1;
const c = j + 2;
writeFace(a, b, c, positionAttribute, object);
}
}
})
output += `endsolid ${view.model.id}\n`;
});
}
if (binary === false) {
output += 'endsolid exported\n';
}
return output;
function writeFace(a, b, c, positionAttribute, object) {
vA.fromBufferAttribute(positionAttribute, a);
vB.fromBufferAttribute(positionAttribute, b);
vC.fromBufferAttribute(positionAttribute, c);
if (object.isSkinnedMesh === true) {
object.boneTransform(a, vA);
object.boneTransform(b, vB);
object.boneTransform(c, vC);
}
vA.applyMatrix4(object.matrixWorld);
vB.applyMatrix4(object.matrixWorld);
vC.applyMatrix4(object.matrixWorld);
writeNormal(vA, vB, vC);
writeVertex(vA);
writeVertex(vB);
writeVertex(vC);
if (binary === true) {
output.setUint16(offset, 0, true);
offset += 2;
} else {
output += '\t\tendloop\n';
output += '\tendfacet\n';
}
}
function writeNormal(vA, vB, vC) {
cb.subVectors(vC, vB);
ab.subVectors(vA, vB);
cb.cross(ab).normalize();
normal.copy(cb).normalize();
if (binary === true) {
output.setFloat32(offset, normal.x, true);
offset += 4;
output.setFloat32(offset, normal.y, true);
offset += 4;
output.setFloat32(offset, normal.z, true);
offset += 4;
} else {
output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
output += '\t\touter loop\n';
}
}
function writeVertex(vertex) {
if (binary === true) {
output.setFloat32(offset, vertex.x, true);
offset += 4;
output.setFloat32(offset, vertex.y, true);
offset += 4;
output.setFloat32(offset, vertex.z, true);
offset += 4;
} else {
output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
}
}
}
}
return output;
}