mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 08:25:19 +01:00
second approach to face merging
This commit is contained in:
parent
e8e27493f0
commit
6fb0e58483
4 changed files with 2269 additions and 6 deletions
|
|
@ -121,6 +121,52 @@ TCAD.utils.equal = function(v1, v2) {
|
|||
return TCAD.utils.areEqual(v1, v2, TCAD.TOLERANCE);
|
||||
};
|
||||
|
||||
|
||||
TCAD.utils.isPointInsidePolygon = function( inPt, inPolygon ) {
|
||||
var EPSILON = TCAD.TOLERANCE;
|
||||
|
||||
var polyLen = inPolygon.length;
|
||||
|
||||
// inPt on polygon contour => immediate success or
|
||||
// toggling of inside/outside at every single! intersection point of an edge
|
||||
// with the horizontal line through inPt, left of inPt
|
||||
// not counting lowerY endpoints of edges and whole edges on that line
|
||||
var inside = false;
|
||||
for( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
|
||||
var edgeLowPt = inPolygon[ p ];
|
||||
var edgeHighPt = inPolygon[ q ];
|
||||
|
||||
var edgeDx = edgeHighPt.x - edgeLowPt.x;
|
||||
var edgeDy = edgeHighPt.y - edgeLowPt.y;
|
||||
|
||||
if ( Math.abs(edgeDy) > EPSILON ) { // not parallel
|
||||
if ( edgeDy < 0 ) {
|
||||
edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
|
||||
edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
|
||||
}
|
||||
if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
|
||||
|
||||
if ( inPt.y == edgeLowPt.y ) {
|
||||
if ( inPt.x == edgeLowPt.x ) return true; // inPt is on contour ?
|
||||
// continue; // no intersection or edgeLowPt => doesn't count !!!
|
||||
} else {
|
||||
var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);
|
||||
if ( perpEdge == 0 ) return true; // inPt is on contour ?
|
||||
if ( perpEdge < 0 ) continue;
|
||||
inside = ! inside; // true intersection left of inPt
|
||||
}
|
||||
} else { // parallel or colinear
|
||||
if ( inPt.y != edgeLowPt.y ) continue; // parallel
|
||||
// egde lies on the same horizontal line as inPt
|
||||
if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
|
||||
( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
|
||||
// continue;
|
||||
}
|
||||
}
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
TCAD.utils.sketchToPolygons = function(geom) {
|
||||
|
||||
var dict = {};
|
||||
|
|
@ -282,7 +328,7 @@ TCAD.Solid = function(polygons, material) {
|
|||
continue;
|
||||
}
|
||||
pushVertices(poly.shell);
|
||||
for ( var h = 0; h < poly.holes; ++ h ) {
|
||||
for ( var h = 0; h < poly.holes.length; ++ h ) {
|
||||
pushVertices(poly.holes[ h ]);
|
||||
}
|
||||
var polyFace = new TCAD.SketchFace(this, poly);
|
||||
|
|
@ -392,6 +438,13 @@ TCAD.Polygon = function(shell, holes, normal) {
|
|||
normal = TCAD.geom.normalOfCCWSeq(shell);
|
||||
} else {
|
||||
shell = TCAD.utils.fixCCW(shell, normal);
|
||||
if (holes.length > 0) {
|
||||
var neg = normal.negate();
|
||||
for (var h = 0; h < holes.length; ++h) {
|
||||
holes[h] = TCAD.utils.fixCCW(holes[h], neg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.normal = normal;
|
||||
|
|
@ -448,6 +501,11 @@ TCAD.Polygon.prototype.to2D = function() {
|
|||
|
||||
TCAD.Polygon.prototype.triangulate = function() {
|
||||
|
||||
function triangulateShape( contour, holes ) {
|
||||
var myTriangulator = new PNLTRI.Triangulator();
|
||||
return myTriangulator.triangulate_polygon( [ contour ].concat(holes) );
|
||||
}
|
||||
|
||||
var i, h;
|
||||
var f2d = this.to2D();
|
||||
|
||||
|
|
@ -459,7 +517,8 @@ TCAD.Polygon.prototype.triangulate = function() {
|
|||
f2d.holes[h][i] = f2d.holes[h][i].three();
|
||||
}
|
||||
}
|
||||
return THREE.Shape.utils.triangulateShape( f2d.shell, f2d.holes );
|
||||
return triangulateShape( f2d.shell, f2d.holes );
|
||||
// return THREE.Shape.utils.triangulateShape( f2d.shell, f2d.holes );
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -415,14 +415,121 @@ TCAD.craft.cut = function(app, face, faces, height) {
|
|||
var cut = CSG.fromPolygons(work).subtract(CSG.fromPolygons(cutter));
|
||||
|
||||
face.polygon.__face = undefined;
|
||||
return TCAD.craft._mergeCSGPolygons(cut.polygons).map(function(path) {
|
||||
return new TCAD.Polygon(path.vertices, [], path.normal);
|
||||
});
|
||||
|
||||
function sortPaths() {
|
||||
function pInP(p1, p2) {
|
||||
var notEqPoints = [];
|
||||
|
||||
for (var i = 0; i < p1.length; ++i) {
|
||||
var v1 = p1[i];
|
||||
for (var j = 0; j < p2.length; ++j) {
|
||||
var v2 = p2[j];
|
||||
if (!v1.equals(v2)) {
|
||||
notEqPoints.push(v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (notEqPoints.length == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < notEqPoints.length; ++i) {
|
||||
var v = notEqPoints[i];
|
||||
if (!TCAD.utils.isPointInsidePolygon(v, p2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function sortPaths(paths3D) {
|
||||
|
||||
paths = paths3D.map(function(path) {
|
||||
return {
|
||||
vertices : new TCAD.Polygon(path.vertices, [], path.normal).to2D().shell,
|
||||
normal : path.normal
|
||||
}
|
||||
});
|
||||
|
||||
var index = [];
|
||||
for (var pi = 0; pi < paths.length; ++pi) {
|
||||
index[pi] = [];
|
||||
paths3D[pi].holes = [];
|
||||
}
|
||||
|
||||
for (var pi = 0; pi < paths.length; ++pi) {
|
||||
var path = paths[pi];
|
||||
depth = path.vertices[0].dot(path.normal);
|
||||
for (var piTest = 0; piTest < paths.length; ++piTest) {
|
||||
var pathTest = paths[piTest];
|
||||
if (piTest === pi) continue;
|
||||
if (!pathTest.normal.equals(path.normal)) continue;
|
||||
depthTest = pathTest.vertices[0].dot(pathTest.normal);
|
||||
if (!TCAD.utils.equal(depthTest, depth)) continue;
|
||||
|
||||
if (pInP(pathTest.vertices, path.vertices)) {
|
||||
index[piTest].push(pi);
|
||||
}
|
||||
}
|
||||
}
|
||||
function collect(master, level) {
|
||||
var success = false;
|
||||
for (var i = 0; i < index.length; ++i) {
|
||||
var masters = index[i];
|
||||
if (level != masters.length) continue;
|
||||
for (var j = 0; j < masters.length; ++j) {
|
||||
var m = masters[j];
|
||||
if (m === master) {
|
||||
paths3D[m].holes.push(paths3D[i])
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
for (var success = true, level = 1;
|
||||
level < paths3D.length && success;
|
||||
level ++, success = false) {
|
||||
|
||||
for (var i = 0; i < index.length; ++i) {
|
||||
var masters = index[i];
|
||||
if (masters.length == level - 1) {
|
||||
if (collect(i, level)) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function separate(path, separated) {
|
||||
separated.push(path);
|
||||
for (var i = 0; i < path.holes.length; ++i) {
|
||||
var hole = path.holes[i];
|
||||
for (var j = 0; j < hole.holes.length; ++j) {
|
||||
var inner = hole.holes[j];
|
||||
separate(inner, separated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var separated = [];
|
||||
for (var i = 0; i < index.length; ++i) {
|
||||
var masters = index[i];
|
||||
if (masters.length == 0) {
|
||||
separate(paths3D[i], separated);
|
||||
}
|
||||
}
|
||||
return separated;
|
||||
}
|
||||
|
||||
var merged = TCAD.craft._mergeCSGPolygons(cut.polygons);
|
||||
var sorted = sortPaths(merged);
|
||||
return sorted.map(function(path) {
|
||||
return new TCAD.Polygon(path.vertices, path.holes.map(function(path){return path.vertices}), path.normal);
|
||||
});
|
||||
|
||||
// return cut.polygons.map(function(e) {
|
||||
// return new TCAD.Polygon(e.vertices.map(
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
<script src="lib/three/OrbitControls.js"></script>
|
||||
<script src="lib/dat.gui.min.js"></script>
|
||||
<script src="lib/csg.js"></script>
|
||||
<script src="lib/pnltri.js"></script>
|
||||
<script src="app/main.js"></script>
|
||||
<script src="app/ctrl.js"></script>
|
||||
<script src="app/viewer.js"></script>
|
||||
|
|
|
|||
2096
web/lib/pnltri.js
Normal file
2096
web/lib/pnltri.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue