diff --git a/web/app/3d/hashmap.js b/web/app/3d/hashmap.js
new file mode 100644
index 00000000..116ee16b
--- /dev/null
+++ b/web/app/3d/hashmap.js
@@ -0,0 +1,160 @@
+TCAD.struct = {};
+
+TCAD.struct.HashTable = function(hashCodeF, equalsF) {
+ this.hashCodeF = hashCodeF;
+ this.equalsF = equalsF;
+ this.setTableSize(8);
+ this.size = 0;
+};
+
+TCAD.struct.HashTable.prototype.hash = function(key) {
+ return Math.abs(this.hashCodeF(key) % this.table.length);
+};
+
+TCAD.struct.HashTable.prototype.get = function(key) {
+ var entry = this._findEntry(key, this._findBucket(key));
+ if (entry == null) return null;
+ return entry[1];
+};
+
+TCAD.struct.HashTable.prototype.put = function(key, value) {
+ if (this.size >= 0.75 * this.table.length) {
+ this.rebuild();
+ }
+ this._put(key, value);
+};
+
+TCAD.struct.HashTable.prototype._findBucket = function(key) {
+ var hash = this.hash(key);
+ var bucket = this.table[hash];
+ if (bucket === null) {
+ bucket = [];
+ this.table[hash] = bucket;
+ }
+ return bucket;
+};
+
+TCAD.struct.HashTable.prototype._findEntry = function(key, bucket) {
+ for (var i = 0; i < bucket.length; i++) {
+ if (this.equalsF(bucket[i][0], key)) {
+ return bucket[i];
+ }
+ }
+ return null;
+};
+
+TCAD.struct.HashTable.prototype._put = function(key, value) {
+ var bucket = this._findBucket(key);
+ var entry = this._findEntry(key, bucket);
+ if (entry == null) {
+ bucket.push([key, value]);
+ } else {
+ entry[1] = value;
+ }
+ this.size++;
+};
+
+TCAD.struct.HashTable.prototype.rebuild = function() {
+ this.size = 0;
+ var oldTable = this.table;
+ this.setTableSize(this.table.length * 2);
+ for (var i = 0; i < oldTable.length; i++) {
+ var e = oldTable[i];
+ if (e != null) {
+ for (var j = 0; j < e.length; j++) {
+ var bucket = e[j];
+ this._put(bucket[0], bucket[1]);
+ }
+ }
+ }
+};
+
+TCAD.struct.HashTable.prototype.entries = function(callback) {
+ for (var i = 0; i < this.table.length; i++) {
+ var e = this.table[i];
+ if (e != null) {
+ for (var j = 0; j < e.length; j++) {
+ var bucket = e[j];
+ callback(bucket[0], bucket[1]);
+ }
+ }
+ }
+};
+
+TCAD.struct.HashTable.prototype.setTableSize = function(newSize) {
+ this.table = [];
+ for (var i = 0; i < newSize; i++) {
+ this.table[i] = null;
+ }
+};
+
+TCAD.struct.hashTable = {};
+
+TCAD.struct.hashTable.DoubleHelper = function() {
+ this.dv = new DataView(new ArrayBuffer(8));
+};
+
+TCAD.struct.hashTable.DoubleHelper.prototype.hash = function(v) {
+ this.dv.setFloat64(0, v);
+ return this.dv.getInt32(0) ^ this.dv.getInt32(4);
+};
+
+TCAD.struct.hashTable.vectorEquals = function(a, b) {
+ return a.x === b.x && a.y === b.y && a.z === b.z;
+};
+
+TCAD.struct.hashTable.forVector3d = function() {
+ var doubleHelper = new TCAD.struct.hashTable.DoubleHelper();
+ function hash(v) {
+ return doubleHelper.hash(v.x) ^ doubleHelper.hash(v.y) ^ doubleHelper.hash(v.z);
+ }
+ return new TCAD.struct.HashTable(hash, TCAD.struct.hashTable.vectorEquals);
+};
+
+TCAD.struct.hashTable.forEdge = function() {
+ var doubleHelper = new TCAD.struct.hashTable.DoubleHelper();
+ function hash(v) {
+ return doubleHelper.hash(v[0].x) ^ doubleHelper.hash(v[0].y) ^ doubleHelper.hash(v[0].z)
+ ^doubleHelper.hash(v[1].x) ^ doubleHelper.hash(v[1].y) ^ doubleHelper.hash(v[1].z);
+ }
+ function veq(a, b) {
+ return a.x === b.x && a.y === b.y && a.z === b.z;
+ }
+ function eq(e1, e2) {
+ var a1 = e1[0];
+ var b1 = e1[1];
+ var a2 = e2[0];
+ var b2 = e2[1];
+ return (veq(a1, a2) && veq(b1, b2)) || (veq(a1, b2) && veq(b1, a2));
+ }
+ return new TCAD.struct.HashTable(hash, eq);
+};
+
+TCAD.struct.hashTable.forVector2d = function() {
+ var doubleHelper = new TCAD.struct.hashTable.DoubleHelper();
+ function hash(v) {
+ return doubleHelper.hash(v.x) ^ doubleHelper.hash(v.y) ;
+ }
+ function eq(a, b) {
+ return a.x === b.x && a.y === b.y;
+ }
+ return new TCAD.struct.HashTable(hash, eq);
+};
+
+TCAD.struct.hashTable.forDoubleArray = function() {
+ var doubleHelper = new TCAD.struct.hashTable.DoubleHelper();
+ function hash(v) {
+ var hash = 0;
+ for (var i = 0; i < v.length; i++) {
+ hash ^= v[i];
+ }
+ return hash;
+ }
+ function eq(a, b) {
+ for (var i = 0; i < a.length; i++) {
+ if (a[i] !== b[i]) return false;
+ }
+ return true;
+ }
+ return new TCAD.struct.HashTable(hash, eq);
+};
diff --git a/web/app/workbench.js b/web/app/workbench.js
index 39807bf7..1f42c393 100644
--- a/web/app/workbench.js
+++ b/web/app/workbench.js
@@ -202,14 +202,8 @@ TCAD.craft._mergeCSGPolygonsTest = function() {
};
TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) {
- var pointToPoly = {};
- var points = [];
var pkey = TCAD.craft.pkey;
- function pnkey(point, normal) {
- return pkey(point) + ":" + pkey(normal);
- }
-
function vec(p) {
var v = new TCAD.Vector();
v.setV(p);
@@ -219,14 +213,6 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) {
// var tol = Math.round(1 / TCAD.TOLERANCE);
var tol = 1E6;
- function round(num) {
- return Math.round(num * tol) / tol;
- }
-
- function roundV(v) {
- return v.set(round(v.x), round(v.y), round(v.z));
- }
-
function prepare(__cgsPolygons) {
var counter = 0;
var polygons = __cgsPolygons.map(function (cp) {
@@ -284,12 +270,6 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) {
}
}
}
-
-// for (var i = 0; i < points.length; i++) {
-// roundV(points[i]);
-// }
-
- //polygons = polygons.filter(function(e){return e.normal.equals(new TCAD.Vector(-1,0,0)) });
return polygons;
}
@@ -325,12 +305,8 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) {
for (var gi = 0; gi < gons.length; gi++) {
var pointPoly = gons[gi];
if (poly.id === pointPoly.id) continue POLYGONS;
- if (pointPoly.normal.equals(poly.normal)) {
- hasNormal = true;
- }
}
- if (!hasNormal) continue;
-
+
var n = poly.vertices.length;
var add = [];
@@ -356,116 +332,11 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) {
return polygons;
}
- function triangulate(polygons) {
- var triangles = [];
- for (var ei = 0; ei < polygons.length; ++ei) {
- var poly = polygons[ei];
- var nvec = poly.normal;
- var refs = new TCAD.Polygon(poly.vertices, [], nvec).triangulate();
- for ( var i = 0; i < refs.length; ++ i ) {
- var a = refs[i][0];
- var b = refs[i][1];
- var c = refs[i][2];
- var triangle = {
- vertices : [
- poly.vertices[a],
- poly.vertices[b],
- poly.vertices[c]
- ],
- normal : poly.normal
- };
- triangles.push(triangle);
- }
- }
- return triangles;
- }
-
var polygons = prepare(__cgsPolygons);
polygons = mergeVertices(polygons);
- //polygons = triangulate(polygons);
-// return polygons;
+ //return polygons;
- var pi, vi, poly, key, vert;
- var pid = 0;
- for (pi = 0; pi < polygons.length; pi++) {
- poly = polygons[pi];
- poly.id = pi;
- for (vi = 0; vi < poly.vertices.length; vi++) {
- vert = poly.vertices[vi];
- key = pkey(vert);
- var pList = pointToPoly[key];
- if (pList === undefined) {
- pointToPoly[key] = [poly];
- points.push(vert);
- } else {
- pList.push(poly);
- }
- }
- }
- function getNeighbors(vertices, i) {
- var a = i - 1;
- var b = i + 1;
- if (a < 0) a = vertices.length - 1;
- if (b == vertices.length) b = 0;
- return [a, b];
- }
-
- function pointIdx(vertices, key) {
- for (var i = 0; i < vertices.length; i++) {
- var v = vertices[i];
- if (pkey(v) === key) {
- return i;
- }
- }
- return -1;
- }
-
- function getDirs(vertices, key) {
- var idx = pointIdx(vertices, key);
- if (idx != -1) {
- return getNeighbors(vertices, idx).map(function(i) { return vertices[i]; });
- }
- return null;
- }
-
- function sharesEdge(masterPolyId, v1, v2, key1, key2, normalKey) {
- var e1 = v2.minus(v1).normalize();
- var pp1 = pointToPoly[key1];
- function along(v) {
- var e = v.minus(v1).normalize();
- return e.equals(e1);
- }
- for (var ii = 0; ii < pp1.length; ii++) {
- var poly = pp1[ii];
- if (pkey(poly.normal) !== normalKey) {
- continue;
- }
- if (masterPolyId === poly.id) continue;
- var idx = pointIdx(poly.vertices, key1);
- if (idx != -1) {
- var neighbors = getNeighbors(poly.vertices, idx);
- if (along(poly.vertices[neighbors[0]]) ||
- along(poly.vertices[neighbors[1]])) {
- return true;
- }
- }
- }
- return false;
- }
-
- var paths = [];
- var path;
- var visited = {};
- function nextUnvisitedPolygon(p, key) {
- var polygons = pointToPoly[key];
- for (var pi = 0; pi < polygons.length; pi++) {
- var poly = polygons[pi];
- var nkey = pnkey(p, poly.normal);
- if (visited[nkey] === undefined) return poly;
- }
- return null;
- }
function deleteRedundantPoints(path) {
var n = path.length;
if (n < 3) return path;
@@ -494,72 +365,103 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) {
return path;
}
- var p, pCurr, keyCurr, keyPrev, keyStart, pStart;
- for (var i = 0; i < points.length; i++) {
- var point = points[i];
- key = pkey(point);
- var unvPoly = nextUnvisitedPolygon(point, key);
- if (unvPoly == null) {
- continue;
+ var edges = TCAD.struct.hashTable.forEdge();
+
+ for (var pi = 0; pi < polygons.length; pi++) {
+ var poly = polygons[pi];
+ var n = poly.vertices.length, p, q;
+ for (p = n - 1, q = 0; q < n; p = q ++) {
+ var a = poly.vertices[p];
+ var b = poly.vertices[q];
+
+ var edge = [a, b, poly];
+ var shares = edges.get(edge);
+ if (shares === null) {
+ shares = 0;
+ }
+ edges.put(edge, shares + 1);
}
- var normal = unvPoly.normal;
- var w = unvPoly.w;
- var normalKey = pkey(normal);
+ }
- pCurr = point;
- pStart = point;
- keyCurr = key;
- keyStart = key;
-
- path = [];
- keyPrev = null;
+ var veq = TCAD.struct.hashTable.vectorEquals;
- visited[pnkey(pCurr, normal)] = true;
- var foundNext = true;
- var csgInfo;
- while (foundNext) {
- foundNext = false;
- path.push(vec(pCurr));
- var gons = pointToPoly[keyCurr];
- POLY:
- for (pi = 0; pi < gons.length; pi++) {
- poly = gons[pi];
- csgInfo = poly.csgInfo;
- if (normalKey != pkey(poly.normal)) continue;
- var dirs = getDirs(poly.vertices, keyCurr);
- if (dirs == null) continue;
- for (vi = 0; vi < dirs.length; vi++) {
- p = dirs[vi];
- key = pkey(p);
-
- if (keyStart === key) continue;
- if (keyCurr === key) continue;
- if (keyPrev != null && keyPrev === key) continue;
- var nkey = pnkey(p, poly.normal);
- if (sharesEdge(poly.id, pCurr, p, keyCurr, key, normalKey)) continue;
- if (visited[nkey] !== undefined) continue;
- visited[nkey] = true;
+ var paths = [];
+ var csgDatas = [];
+ var index = TCAD.struct.hashTable.forVector3d();
- pCurr = p;
- keyPrev = keyCurr;
- keyCurr = key;
- foundNext = true;
- break POLY;
- }
+ function indexPoint(p, edge) {
+ var edges = index.get(p);
+ if (edges === null) {
+ edges = [];
+ index.put(p, edges);
+ }
+ edges.push(edge);
+ }
+
+ var edgesToProcess = [];
+ edges.entries(function(k, v) {
+ if (v === 1) {
+ indexPoint(k[0], k);
+ indexPoint(k[1], k);
+ k[3] = false;
+ edgesToProcess.push(k);
+ }
+ });
+
+ function nextPoint(p) {
+ var edges = index.get(p);
+ if (edges === null) return null;
+ for (var i = 0; i < edges.length; i++) {
+ var edge = edges[i]
+ if (edge[3]) continue;
+ var res = null;
+ if (veq(p, edge[0])) res = edge[1];
+ if (veq(p, edge[1])) res = edge[0];
+ if (res != null) {
+ edge[3] = true;
+ return res;
}
}
- path = deleteRedundantPoints(path);
+ return null;
+ }
+
+ for (var ei = 0; ei < edgesToProcess.length; ei++) {
+ var edge = edgesToProcess[ei];
+ if (edge[3]) {
+ continue;
+ }
+ edge[3] = true;
+ var path = [edge[0], edge[1]];
+ paths.push(path);
+ csgDatas.push(edge[2]);
+ var next = nextPoint(edge[1]);
+ while (next !== null) {
+ if (!veq(next, path[0])) {
+ path.push(next);
+ next = nextPoint(next);
+ } else {
+ next = null;
+ }
+ }
+ }
+
+
+
+ var filteredPaths = [];
+ for (var i = 0; i < paths.length; i++) {
+ var path = deleteRedundantPoints(paths[i]);
+ var csgData = csgDatas[i];
if (path.length > 2) {
- paths.push({
+ filteredPaths.push({
vertices : path,
- normal : normal,
- w : w,
- csgInfo : csgInfo
+ normal : csgData.normal,
+ w : csgData.w,
+ csgInfo : csgData.csgInfo
});
}
}
- return paths;
+ return filteredPaths;
};
diff --git a/web/index.html b/web/index.html
index e51a213a..32d18711 100644
--- a/web/index.html
+++ b/web/index.html
@@ -23,6 +23,7 @@
+