jsketcher/web/app/3d/scene/mesh-scene-object.js
2017-01-17 01:57:40 -08:00

214 lines
No EOL
6.1 KiB
JavaScript

import {HashTable} from '../../utils/hashmap'
import Vector from '../../math/vector'
import Counters from '../counters'
import {findOutline, segmentsToPaths, reconstructSketchBounds} from '../craft/mesh/workbench'
import {Matrix3, AXIS} from '../../math/l3space'
import {arrFlatten1L, isCurveClass} from '../cad-utils'
import DPR from '../../utils/dpr'
import {SceneSolid, SceneFace} from './scene-object'
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;
}
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;
}