mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-14 20:33:30 +01:00
csg experiment
This commit is contained in:
parent
8aff55f2b4
commit
07cc007e20
2 changed files with 201 additions and 68 deletions
|
|
@ -18,8 +18,23 @@ TCAD.utils.createSquare = function(width) {
|
|||
TCAD.utils.createBox = function(width) {
|
||||
var square = TCAD.utils.createSquare(width);
|
||||
var rot = TCAD.math.rotateMatrix(3/4, TCAD.math.AXIS.Z, TCAD.math.ORIGIN);
|
||||
square.eachVertex(function(path, i) { rot._apply(path[i]) } )
|
||||
return TCAD.geom.extrude(square, square.normal.multiply(width));
|
||||
square.eachVertex(function(path, i) { rot._apply(path[i]) } );
|
||||
var polygons = TCAD.geom.extrude(square, square.normal.multiply(width));
|
||||
return TCAD.utils.createSolidMesh(TCAD.utils.toCsgGroups(polygons));
|
||||
};
|
||||
|
||||
TCAD.utils.toCsgGroups = function(polygons) {
|
||||
var groups = [];
|
||||
for (var i = 0; i < polygons.length; i++) {
|
||||
var p = polygons[i];
|
||||
if (p.holes.length === 0) {
|
||||
groups.push( new TCAD.CSGGroup([new TCAD.SimplePolygon(p.shell, p.normal)], p.normal) );
|
||||
} else {
|
||||
// TODO: triangulation needed
|
||||
groups.push( new TCAD.CSGGroup([new TCAD.SimplePolygon(p.shell, p.normal)], p.normal) );
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
};
|
||||
|
||||
TCAD.utils.checkPolygon = function(poly) {
|
||||
|
|
@ -79,7 +94,7 @@ TCAD.utils.createLine = function (a, b, color) {
|
|||
return new THREE.Segment(geometry, material);
|
||||
};
|
||||
|
||||
TCAD.utils.createSolidMesh = function(faces) {
|
||||
TCAD.utils.createSolidMesh = function(csgGroups) {
|
||||
var material = new THREE.MeshPhongMaterial({
|
||||
vertexColors: THREE.FaceColors,
|
||||
color: TCAD.view.FACE_COLOR,
|
||||
|
|
@ -89,7 +104,7 @@ TCAD.utils.createSolidMesh = function(faces) {
|
|||
polygonOffsetUnits : 1
|
||||
|
||||
});
|
||||
var geometry = new TCAD.Solid(faces, material);
|
||||
var geometry = new TCAD.Solid(csgGroups, material);
|
||||
return geometry.meshObject;
|
||||
};
|
||||
|
||||
|
|
@ -328,16 +343,79 @@ TCAD.geom.extrude = function(source, target) {
|
|||
|
||||
TCAD.geom.SOLID_COUNTER = 0;
|
||||
|
||||
TCAD.SimplePolygon = function(vertices, normal) {
|
||||
this.vertices = vertices;
|
||||
this.normal = normal;
|
||||
};
|
||||
|
||||
TCAD.SimplePolygon.prototype.triangulate = function() {
|
||||
var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(this.vertices, this.normal));
|
||||
var _2dTransformation = _3dTransformation.invert();
|
||||
var i;
|
||||
var shell = [];
|
||||
for (i = 0; i < this.vertices.length; ++i) {
|
||||
shell[i] = _2dTransformation.apply(this.vertices[i]);
|
||||
}
|
||||
//
|
||||
//for (i = 0; i < shell.length; ++i) {
|
||||
// shell[i] = shell[i].three();
|
||||
//}
|
||||
|
||||
var myTriangulator = new PNLTRI.Triangulator();
|
||||
return myTriangulator.triangulate_polygon( [ shell ] );
|
||||
// return THREE.Shape.utils.triangulateShape( f2d.shell, f2d.holes );
|
||||
};
|
||||
|
||||
TCAD.GROUPS_COUNTER = 0;
|
||||
|
||||
TCAD.CSGGroup = function(simplePolygons, normal, w) {
|
||||
this.id = TCAD.GROUPS_COUNTER ++;
|
||||
this.polygons = simplePolygons;
|
||||
this.normal = normal;
|
||||
this.w = w || normal.dot(this.polygons[0].vertices[0]);
|
||||
};
|
||||
|
||||
TCAD.CSGGroup.prototype.basis = function() {
|
||||
return TCAD.geom.someBasis(this.polygons[0].vertices, this.normal);
|
||||
};
|
||||
|
||||
TCAD.CSGGroup.prototype.toCSGPolygons = function() {
|
||||
function csgVec(v) {
|
||||
return new CSG.Vector3D(v.x, v.y, v.z);
|
||||
}
|
||||
var csgPolygons = [];
|
||||
var pid = this.id;
|
||||
var shared = new CSG.Polygon.Shared([pid, pid, pid, pid]);
|
||||
shared.__tcad = {
|
||||
csgInfo : this.csgInfo,
|
||||
face : this.__face
|
||||
};
|
||||
var plane = CSG.Plane.fromObject(this);
|
||||
var vertices = [];
|
||||
for (var pi = 0; pi < this.polygons.length; ++pi) {
|
||||
var poly = this.polygons[pi];
|
||||
for (var vi = 0; vi < poly.vertices.length; vi++) {
|
||||
var v = poly.vertices[vi];
|
||||
vertices.push(new CSG.Vertex(csgVec(v)));
|
||||
}
|
||||
csgPolygons.push(new CSG.Polygon(vertices, shared, plane));
|
||||
}
|
||||
return csgPolygons;
|
||||
};
|
||||
|
||||
/** @constructor */
|
||||
TCAD.Solid = function(polygons, material) {
|
||||
TCAD.Solid = function(csgPolygonGroups, material) {
|
||||
THREE.Geometry.call( this );
|
||||
this.dynamic = true; //true by default
|
||||
|
||||
|
||||
this.meshObject = new THREE.Mesh(this, material);
|
||||
|
||||
this.id = TCAD.geom.SOLID_COUNTER ++;
|
||||
this.tCadId = TCAD.geom.SOLID_COUNTER ++;
|
||||
this.faceCounter = 0;
|
||||
|
||||
this.wireframeGroup = new THREE.Object3D();
|
||||
this.meshObject.add(this.wireframeGroup);
|
||||
|
||||
this.polyFaces = [];
|
||||
var scope = this;
|
||||
function pushVertices(vertices) {
|
||||
|
|
@ -347,52 +425,50 @@ TCAD.Solid = function(polygons, material) {
|
|||
}
|
||||
|
||||
var off = 0;
|
||||
for (var p = 0; p < polygons.length; ++ p) {
|
||||
var poly = polygons[p];
|
||||
try {
|
||||
var faces = poly.triangulate();
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
continue;
|
||||
}
|
||||
pushVertices(poly.shell);
|
||||
for ( var h = 0; h < poly.holes.length; ++ h ) {
|
||||
pushVertices(poly.holes[ h ]);
|
||||
}
|
||||
var polyFace = new TCAD.SketchFace(this, poly);
|
||||
for (var gIdx = 0; gIdx < csgPolygonGroups.length; ++ gIdx) {
|
||||
var group = csgPolygonGroups[gIdx];
|
||||
var polyFace = new TCAD.SketchFace(this, group);
|
||||
this.polyFaces.push(polyFace);
|
||||
|
||||
for ( var i = 0; i < faces.length; ++ i ) {
|
||||
|
||||
var a = faces[i][0] + off;
|
||||
var b = faces[i][1] + off;
|
||||
var c = faces[i][2] + off;
|
||||
|
||||
var fNormal = TCAD.geom.normalOfCCWSeqTHREE([
|
||||
this.vertices[a], this.vertices[b], this.vertices[c]]);
|
||||
|
||||
if (!TCAD.utils.vectorsEqual(fNormal, poly.normal)) {
|
||||
console.log("ASSERT");
|
||||
var _a = a;
|
||||
a = c;
|
||||
c = _a;
|
||||
for (var p = 0; p < group.polygons.length; ++p) {
|
||||
var poly = group.polygons[p];
|
||||
try {
|
||||
var faces = poly.triangulate();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
continue;
|
||||
}
|
||||
|
||||
var face = new THREE.Face3( a, b, c );
|
||||
polyFace.faces.push(face);
|
||||
face.__TCAD_polyFace = polyFace;
|
||||
face.normal = poly.normal.three();
|
||||
face.materialIndex = p;
|
||||
this.faces.push( face );
|
||||
}
|
||||
off = this.vertices.length;
|
||||
}
|
||||
pushVertices(poly.vertices);
|
||||
|
||||
for (var i = 0; i < faces.length; ++i) {
|
||||
|
||||
var a = faces[i][0] + off;
|
||||
var b = faces[i][1] + off;
|
||||
var c = faces[i][2] + off;
|
||||
|
||||
var fNormal = TCAD.geom.normalOfCCWSeqTHREE([
|
||||
this.vertices[a], this.vertices[b], this.vertices[c]]);
|
||||
|
||||
if (!TCAD.utils.vectorsEqual(fNormal, poly.normal)) {
|
||||
console.log("ASSERT");
|
||||
var _a = a;
|
||||
a = c;
|
||||
c = _a;
|
||||
}
|
||||
|
||||
var face = new THREE.Face3(a, b, c);
|
||||
polyFace.faces.push(face);
|
||||
face.__TCAD_polyFace = polyFace;
|
||||
face.normal = poly.normal.three();
|
||||
face.materialIndex = gIdx;
|
||||
this.faces.push(face);
|
||||
}
|
||||
off = this.vertices.length;
|
||||
}
|
||||
}
|
||||
this.mergeVertices();
|
||||
|
||||
this.wireframeGroup = new THREE.Object3D();
|
||||
this.meshObject.add(this.wireframeGroup);
|
||||
this.makeWireframe(polygons);
|
||||
//this.makeWireframe(polygons);
|
||||
};
|
||||
|
||||
if (typeof THREE !== "undefined") {
|
||||
|
|
@ -428,11 +504,11 @@ TCAD.Solid.prototype.makeWireframe = function(polygons) {
|
|||
};
|
||||
|
||||
/** @constructor */
|
||||
TCAD.SketchFace = function(solid, poly) {
|
||||
var proto = poly.__face;
|
||||
poly.__face = this;
|
||||
TCAD.SketchFace = function(solid, csgGroup) {
|
||||
var proto = csgGroup.__face;
|
||||
csgGroup.__face = this;
|
||||
if (proto === undefined) {
|
||||
this.id = solid.id + ":" + (solid.faceCounter++);
|
||||
this.id = solid.tCadId + ":" + (solid.faceCounter++);
|
||||
this.sketchGeom = null;
|
||||
} else {
|
||||
this.id = proto.id;
|
||||
|
|
@ -440,7 +516,7 @@ TCAD.SketchFace = function(solid, poly) {
|
|||
}
|
||||
|
||||
this.solid = solid;
|
||||
this.polygon = poly;
|
||||
this.csgGroup = csgGroup;
|
||||
this.faces = [];
|
||||
this.sketch3DGroup = null;
|
||||
|
||||
|
|
@ -458,7 +534,7 @@ if (typeof THREE !== "undefined") {
|
|||
|
||||
TCAD.SketchFace.prototype.syncSketches = function(geom) {
|
||||
var i;
|
||||
var normal = this.polygon.normal;
|
||||
var normal = this.csgGroup.normal;
|
||||
var offVector = normal.multiply(0); // disable it. use polygon offset feature of material
|
||||
|
||||
if (this.sketch3DGroup != null) {
|
||||
|
|
@ -470,9 +546,9 @@ TCAD.SketchFace.prototype.syncSketches = function(geom) {
|
|||
this.solid.meshObject.add(this.sketch3DGroup);
|
||||
}
|
||||
|
||||
var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(this.polygon.shell, normal));
|
||||
var _3dTransformation = new TCAD.Matrix().setBasis(this.csgGroup.basis());
|
||||
//we lost depth or z off in 2d sketch, calculate it again
|
||||
var depth = normal.dot(this.polygon.shell[0]);
|
||||
var depth = normal.dot(this.csgGroup.polygons[0].vertices[0]);
|
||||
for (i = 0; i < geom.connections.length; ++i) {
|
||||
var l = geom.connections[i];
|
||||
var lg = new THREE.Geometry();
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ TCAD.craft.getSketchedPolygons3D = function(app, face) {
|
|||
var geom = TCAD.workbench.readSketchGeom(JSON.parse(savedFace));
|
||||
var polygons2D = TCAD.utils.sketchToPolygons(geom);
|
||||
|
||||
var normal = face.polygon.normal;
|
||||
var normal = face.csgGroup.normal;
|
||||
var depth = null;
|
||||
var sketchedPolygons = [];
|
||||
for (var i = 0; i < polygons2D.length; i++) {
|
||||
|
|
@ -90,9 +90,9 @@ TCAD.craft.getSketchedPolygons3D = function(app, face) {
|
|||
if (poly2D.shell.length < 3) continue;
|
||||
|
||||
if (depth == null) {
|
||||
var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(face.polygon.shell, normal));
|
||||
var _3dTransformation = new TCAD.Matrix().setBasis(face.csgGroup.basis());
|
||||
//we lost depth or z off in 2d sketch, calculate it again
|
||||
depth = normal.dot(face.polygon.shell[0]);
|
||||
depth = normal.dot(face.csgGroup.polygons[0].vertices[0]);
|
||||
}
|
||||
|
||||
var shell = [];
|
||||
|
|
@ -707,27 +707,84 @@ TCAD.craft.collectFaces = function(solids) {
|
|||
return faces;
|
||||
};
|
||||
|
||||
TCAD.craft.collectCSGPolygons = function(faces) {
|
||||
var out = [];
|
||||
for (var fi = 0; fi < faces.length; fi++) {
|
||||
var face = faces[fi];
|
||||
TCAD.utils.addAll(out, face.csgGroup.toCSGPolygons());
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
TCAD.craft.toGroups = function(csgPolygons) {
|
||||
|
||||
function vec(p) {
|
||||
var v = new TCAD.Vector();
|
||||
v.setV(p);
|
||||
return v;
|
||||
}
|
||||
|
||||
var byShared = {};
|
||||
var infos = {};
|
||||
for (var i = 0; i < csgPolygons.length; i++) {
|
||||
var p = csgPolygons[i];
|
||||
var tag = p.shared.getTag();
|
||||
infos[tag] = p.shared;
|
||||
if (byShared[tag] === undefined) byShared[tag] = [];
|
||||
byShared[tag].push(p);
|
||||
}
|
||||
var result = [];
|
||||
for (var tag in byShared) {
|
||||
var groupedPolygons = byShared[tag];
|
||||
if (groupedPolygons.length === 0) continue;
|
||||
var plane = groupedPolygons[0].plane;
|
||||
var normal = vec(plane.normal);
|
||||
|
||||
var simplePolygons = groupedPolygons.map(function (p) {
|
||||
|
||||
var vertices = p.vertices.map(function (v) {
|
||||
return vec(v.pos);
|
||||
});
|
||||
return new TCAD.SimplePolygon(vertices, normal);
|
||||
});
|
||||
var csgGroup = new TCAD.CSGGroup(simplePolygons, normal, plane.w);
|
||||
var tcadShared = infos[tag].__tcad;
|
||||
if (tcadShared !== undefined) {
|
||||
csgGroup.csgInfo = tcadShared.csgInfo;
|
||||
csgGroup.__face = tcadShared.face;
|
||||
}
|
||||
result.push(csgGroup);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
TCAD.craft.cut = function(app, request) {
|
||||
var face = request.face;
|
||||
var sketchedPolygons = TCAD.craft.getSketchedPolygons3D(app, face);
|
||||
if (sketchedPolygons == null) return null;
|
||||
|
||||
//face.polygon.__face = undefined;
|
||||
var work;
|
||||
if (!!request.solids[0].__cached_csg) {
|
||||
work = request.solids[0].__cached_csg;
|
||||
} else {
|
||||
var faces = TCAD.craft.collectFaces(request.solids);
|
||||
work = CSG.fromPolygons(TCAD.craft.collectCSGPolygons(faces));
|
||||
}
|
||||
|
||||
var faces = TCAD.craft.collectFaces(request.solids);
|
||||
|
||||
var normal = face.polygon.normal;
|
||||
var normal = face.csgGroup.normal;
|
||||
var cutter = [];
|
||||
for (var i = 0; i < sketchedPolygons.length; i++) {
|
||||
var extruded = TCAD.geom.extrude(sketchedPolygons[i], normal.multiply( - request.depth));
|
||||
cutter = cutter.concat(TCAD.craft._makeFromPolygons(extruded));
|
||||
}
|
||||
|
||||
var work = TCAD.craft._makeFromPolygons(faces.map(function(f){ return f.polygon }));
|
||||
|
||||
var cut = CSG.fromPolygons(work).subtract(CSG.fromPolygons(cutter));
|
||||
var cut = work.subtract(CSG.fromPolygons(cutter));
|
||||
|
||||
return TCAD.craft.reconstruct(cut);
|
||||
var solid = TCAD.utils.createSolidMesh(TCAD.craft.toGroups(cut.polygons)).geometry;
|
||||
//solid.__cached_csg = cut;
|
||||
return solid;
|
||||
};
|
||||
|
||||
TCAD.Craft = function(app) {
|
||||
|
|
@ -760,14 +817,14 @@ TCAD.Craft.prototype.modify = function(request) {
|
|||
if (!op) return;
|
||||
|
||||
var detachedRequest = TCAD.craft.detach(request);
|
||||
var newFaces = op(this.app, request);
|
||||
var newGroups = op(this.app, request);
|
||||
|
||||
if (newFaces == null) return;
|
||||
if (newGroups == null) return;
|
||||
for (var i = 0; i < request.solids.length; i++) {
|
||||
var solid = request.solids[i];
|
||||
this.app.viewer.scene.remove( solid.meshObject );
|
||||
}
|
||||
this.app.viewer.scene.add(TCAD.utils.createSolidMesh(newFaces));
|
||||
this.app.viewer.scene.add(newGroups.meshObject);
|
||||
this.history.push(detachedRequest);
|
||||
this.app.bus.notify('craft');
|
||||
//REMOVE IT
|
||||
|
|
@ -780,6 +837,6 @@ TCAD.craft.OPS = {
|
|||
CUT : TCAD.craft.cut,
|
||||
PAD : TCAD.craft.extrude,
|
||||
BOX : function(app, request) {
|
||||
return TCAD.utils.createBox(request.size);
|
||||
return TCAD.utils.createBox(request.size).geometry;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue