mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-14 20:33:30 +01:00
bump threejs version to 0.143.0
This commit is contained in:
parent
e6d5b7b509
commit
56ed53131a
29 changed files with 521 additions and 1393 deletions
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
14
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
105
web/app/cad/scene/views/viewUtils.js
Normal file
105
web/app/cad/scene/views/viewUtils.js
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 [];
|
||||
}
|
||||
}
|
||||
|
|
@ -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});
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in a new issue