BREP datastructure / prism build / visualizator

This commit is contained in:
Val Erastov 2017-01-06 02:34:42 -08:00
parent a5407d10b8
commit 27bd6ded86
13 changed files with 369 additions and 0 deletions

View file

@ -16,6 +16,9 @@ import {AddDebugSupport} from './debug'
import {init as initSample} from './sample'
import '../../css/app3d.less'
import * as BREPBuilder from '../brep/brep-builder'
import {SceneSolid} from '../brep/viz/scene-solid'
function App() {
this.id = this.processHints();
this.bus = new Bus();
@ -63,8 +66,23 @@ function App() {
}
app._refreshSketches();
});
this.BREPTest();
}
App.prototype.BREPTest = function() {
const box = BREPBuilder.createPrism([
BREPBuilder.point(-250, -250, 250),
BREPBuilder.point(250, -250, 250),
BREPBuilder.point(250, 250, 250),
BREPBuilder.point(-250, 250, 250),
], 500);
const sceneSolid = new SceneSolid(box);
this.viewer.workGroup.add(sceneSolid.cadGroup);
this.viewer.render()
};
App.prototype.processHints = function() {
let id = window.location.hash.substring(1);
if (!id) {

View file

@ -0,0 +1,99 @@
import {Shell} from './topo/shell'
import {Vertex} from './topo/vertex'
import {Loop} from './topo/loop'
import {Face} from './topo/face'
import {HalfEdge, Edge} from './topo/edge'
import {Line} from './geom/impl/line'
import {Plane} from './geom/impl/plane'
import {Point} from './geom/point'
import * as cad_utils from '../3d/cad-utils'
export function createPrism(basePoints, height) {
const normal = cad_utils.normalOfCCWSeq(basePoints);
const baseLoop = createPlaneLoop(basePoints.map(p => new Vertex(p)));
const baseFace = createPlaneFace(normal, baseLoop);
const lidNormal = normal.multiply(-1);
const offVector = lidNormal.multiply(height);
const lidPoints = basePoints.map(p => p.plus(offVector));
const lidLoop = createPlaneLoop(lidPoints.map(p => new Vertex(p)));
const lidFace = createPlaneFace(lidNormal, lidLoop);
const shell = new Shell();
for (let i = 0; i < baseLoop.halfEdges.length; i++) {
const baseHalfEdge = baseLoop.halfEdges[i];
const lidHalfEdge = lidLoop.halfEdges[i];
const wallLoop = createPlaneLoop([baseHalfEdge.vertexA, baseHalfEdge.vertexB, lidHalfEdge.vertexB, lidHalfEdge.vertexA]);
const baseEdge = new Edge(new Line());
linkHalfEdges(baseEdge, baseHalfEdge, wallLoop.halfEdges[0]);
const lidEdge = new Edge(new Line());
linkHalfEdges(lidEdge, lidHalfEdge, wallLoop.halfEdges[2]);
const wallNormal = cad_utils.normalOfCCWSeq([baseHalfEdge.vertexA.point, baseHalfEdge.vertexB.point, lidHalfEdge.vertexB.point]);
const wallFace = createPlaneFace(wallNormal, wallLoop);
shell.faces.push(wallFace);
}
iterateSegments(shell.faces, (a, b) => {
linkHalfEdges(new Edge(new Line()), a.outerLoop.halfEdges[1], b.outerLoop.halfEdges[3]);
});
shell.faces.push(baseFace, lidFace);
return shell;
}
function createPlaneFace(normal, loop) {
const w = loop.halfEdges[0].vertexA.point.dot(normal);
const plane = new Plane(normal, w);
const face = new Face(plane);
face.outerLoop = loop;
return face;
}
export function linkHalfEdges(edge, halfEdge1, halfEdge2) {
halfEdge1.edge = edge;
halfEdge2.edge = edge;
edge.halfEdge1 = halfEdge1;
edge.halfEdge2 = halfEdge2;
halfEdge1.vertexA.edges.push(edge);
halfEdge1.vertexB.edges.push(edge);
}
export function createPlaneLoop(vertices) {
const loop = new Loop();
iterateSegments(vertices, (a, b) => {
const halfEdge = new HalfEdge();
halfEdge.loop = loop;
halfEdge.vertexA = a;
halfEdge.vertexB = b;
loop.halfEdges.push(halfEdge);
});
iterateSegments(loop.halfEdges, (prev, next) => {
prev.next = next;
next.prev = prev;
});
return loop;
}
export function point(x, y, z) {
return new Point(x, y, z);
}
export function iterateSegments(items, callback) {
let length = items.length;
for (let i = 0; i < length; i++) {
let j = (i + 1) % length;
callback(items[i], items[j], i, j);
}
}

View file

@ -0,0 +1,8 @@
export class Curve {
constructor() {
}
}

View file

@ -0,0 +1,9 @@
import {Curve} from '../curve'
export class Line extends Curve {
constructor() {
super();
}
}

View file

@ -0,0 +1,24 @@
import {Surface} from '../surface'
import {AXIS} from '../../../math/l3space'
export class Plane extends Surface {
constructor(normal, w) {
super();
this.normal = normal;
this.w = w;
}
calculateBasis() {
const normal = this.normal;
let alignPlane, x, y;
if (Math.abs(normal.dot(AXIS.Y)) < 0.5) {
alignPlane = normal.cross(AXIS.Y);
} else {
alignPlane = normal.cross(AXIS.Z);
}
y = alignPlane.cross(normal);
x = y.cross(normal);
return [x, y, normal];
}
}

View file

@ -0,0 +1,3 @@
import Vector from '../../math/vector'
export const Point = Vector;

View file

@ -0,0 +1,8 @@
export class Surface {
constructor() {
}
}

26
web/app/brep/topo/Edge.js Normal file
View file

@ -0,0 +1,26 @@
export class Edge {
constructor(curve) {
this.curve = curve;
this.halfEdge1 = null;
this.halfEdge2 = null;
}
}
export class HalfEdge {
constructor() {
this.edge = null;
this.vertexA = null;
this.vertexB = null;
this.loop = null;
this.next = null;
this.prev = null;
}
twin() {
return this.edge.halfEdge1 == this ? this.edge.halfEdge2 : this.edge.halfEdge1;
}
}

10
web/app/brep/topo/face.js Normal file
View file

@ -0,0 +1,10 @@
export class Face {
constructor(surface) {
this.surface = surface;
this.outerLoop = null;
this.innerLoops = [];
}
}

12
web/app/brep/topo/loop.js Normal file
View file

@ -0,0 +1,12 @@
export class Loop {
constructor() {
this.face = null;
this.halfEdges = [];
}
asPolygon() {
return this.halfEdges.map(e => e.vertexA.point);
}
}

View file

@ -0,0 +1,8 @@
export class Shell {
constructor() {
this.faces = []
}
}

View file

@ -0,0 +1,9 @@
export class Vertex {
constructor(point) {
this.point = point;
this.edges = [];
}
}

View file

@ -0,0 +1,135 @@
import Vector from '../../math/vector'
import {Triangulate} from '../../3d/triangulation'
export class SceneSolid {
constructor(shell) {
this.shell = shell;
this.cadGroup = new THREE.Object3D();
this.cadGroup.__tcad_solid = this;
this.wireframeGroup = new THREE.Object3D();
this.cadGroup.add(this.wireframeGroup);
const geometry = new THREE.Geometry();
geometry.dynamic = true;
this.mesh = new THREE.Mesh(geometry, createSolidMaterial());
this.cadGroup.add(this.mesh);
this.polyFaces = [];
this.createFaces();
this.createEdges();
this.createVertices();
}
createFaces() {
let off = 0;
let gIdx = 0;
const geom = this.mesh.geometry;
for (let brepFace of this.shell.faces) {
const polyFace = new SceneFace(brepFace);
this.polyFaces.push(polyFace);
const polygons = triangulate(brepFace);
for (let p = 0; p < polygons.length; ++p) {
const poly = polygons[p];
const vLength = poly.length;
if (vLength < 3) continue;
const firstVertex = poly[0];
geom.vertices.push(threeV(firstVertex));
geom.vertices.push(threeV(poly[1]));
const normal = threeV(brepFace.surface.normal);
for (let i = 2; i < vLength; i++) {
geom.vertices.push(threeV(poly[i]));
const a = off;
const b = i - 1 + off;
const c = i + off;
const face = new THREE.Face3(a, b, c);
polyFace.faces.push(face);
face.__TCAD_polyFace = polyFace;
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(polyFace, utils.isSmoothPiece(group.shared) ? 0xFF0000 : null);
off = geom.vertices.length;
}
}
geom.mergeVertices();
}
createEdges() {
const visited = new Set();
for (let face of this.shell.faces) {
for (let halfEdge of face.outerLoop.halfEdges) {
if (!visited.has(halfEdge.edge)) {
visited.add(halfEdge.edge);
this.addLineToScene(halfEdge.vertexA.point, halfEdge.vertexB.point, halfEdge.edge);
}
}
}
}
createVertices() {
}
addLineToScene(a, b, edge) {
const lg = new THREE.Geometry();
lg.vertices.push(a);
lg.vertices.push(b);
const line = new THREE.Line(lg, WIREFRAME_MATERIAL);
line.__TCAD_edge = edge;
this.wireframeGroup.add(line);
};
}
const WIREFRAME_MATERIAL = new THREE.LineBasicMaterial({color: 0xff0000, linewidth: 10});
class SceneFace {
constructor(brepFace) {
this.brepFace = brepFace;
this.faces = [];
}
}
function triangulate(face) {
function csgVert(data) {
return new Vector(data[0], data[1], data[2]);
}
function data(v) {
return [v.x, v.y, v.z];
}
var triangled = [];
const polygons = [face.outerLoop.asPolygon()];
for (let poly of polygons) {
let vertices = Triangulate([poly.map(v => data(v))], data(face.surface.normal));
for (let i = 0; i < vertices.length; i += 3 ) {
var a = csgVert(vertices[i]);
var b = csgVert(vertices[i + 1]);
var c = csgVert(vertices[i + 2]);
triangled.push([a, b, c]);
}
}
return triangled;
}
function createSolidMaterial() {
return new THREE.MeshPhongMaterial({
vertexColors: THREE.FaceColors,
color: 0xB0C4DE,
shininess: 0,
polygonOffset : true,
polygonOffsetFactor : 1,
polygonOffsetUnits : 2,
side : THREE.DoubleSide
});
}
function threeV(v) {return new THREE.Vector3( v.x, v.y, v.z )}