mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-10 02:13:58 +01:00
214 lines
No EOL
6 KiB
JavaScript
214 lines
No EOL
6 KiB
JavaScript
import {HashTable} from '../../../utils/hashmap'
|
|
import {findOutline, reconstructSketchBounds, segmentsToPaths} from '../../craft/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;
|
|
} |