mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-27 10:55:56 +01:00
BREP datastructure / prism build / visualizator
This commit is contained in:
parent
a5407d10b8
commit
27bd6ded86
13 changed files with 369 additions and 0 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
99
web/app/brep/brep-builder.js
Normal file
99
web/app/brep/brep-builder.js
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
8
web/app/brep/geom/curve.js
Normal file
8
web/app/brep/geom/curve.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
export class Curve {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
9
web/app/brep/geom/impl/line.js
Normal file
9
web/app/brep/geom/impl/line.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import {Curve} from '../curve'
|
||||
|
||||
export class Line extends Curve {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
||||
24
web/app/brep/geom/impl/plane.js
Normal file
24
web/app/brep/geom/impl/plane.js
Normal 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];
|
||||
}
|
||||
}
|
||||
3
web/app/brep/geom/point.js
Normal file
3
web/app/brep/geom/point.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import Vector from '../../math/vector'
|
||||
|
||||
export const Point = Vector;
|
||||
8
web/app/brep/geom/surface.js
Normal file
8
web/app/brep/geom/surface.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
export class Surface {
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
26
web/app/brep/topo/Edge.js
Normal file
26
web/app/brep/topo/Edge.js
Normal 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
10
web/app/brep/topo/face.js
Normal 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
12
web/app/brep/topo/loop.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
export class Loop {
|
||||
|
||||
constructor() {
|
||||
this.face = null;
|
||||
this.halfEdges = [];
|
||||
}
|
||||
|
||||
asPolygon() {
|
||||
return this.halfEdges.map(e => e.vertexA.point);
|
||||
}
|
||||
}
|
||||
8
web/app/brep/topo/shell.js
Normal file
8
web/app/brep/topo/shell.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
export class Shell {
|
||||
|
||||
constructor() {
|
||||
this.faces = []
|
||||
}
|
||||
|
||||
}
|
||||
9
web/app/brep/topo/vertex.js
Normal file
9
web/app/brep/topo/vertex.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
export class Vertex {
|
||||
|
||||
constructor(point) {
|
||||
this.point = point;
|
||||
this.edges = [];
|
||||
}
|
||||
|
||||
}
|
||||
135
web/app/brep/viz/scene-solid.js
Normal file
135
web/app/brep/viz/scene-solid.js
Normal 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 )}
|
||||
Loading…
Reference in a new issue