mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-15 21:05:22 +01:00
232 lines
6.6 KiB
JavaScript
232 lines
6.6 KiB
JavaScript
import Vector from 'math/vector';
|
|
import {SceneEdge, SceneFace, SceneSolid} from './sceneObject';
|
|
import brepTess from '../../tess/brep-tess';
|
|
import tessellateSurface from '../../../brep/geom/surfaces/surfaceTess';
|
|
import {setAttribute} from '../../../../../modules/scene/objectData';
|
|
import * as vec from 'math/vec';
|
|
import {perpendicularVector} from '../../../math/math';
|
|
|
|
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.tesselation) {
|
|
tessDataToGeom(brepFace.data.tesselation.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.tesselation ? edge.data.tesselation : 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);
|