support arcs in csg

This commit is contained in:
Val Erastov 2015-08-28 00:10:05 -07:00
parent 6f96b75cc6
commit 9f6aae0aa7
6 changed files with 273 additions and 89 deletions

View file

@ -63,7 +63,87 @@ TCAD.App.prototype.sketchFace = function() {
} else {
data = JSON.parse(savedFace);
}
data.boundary = polyFace.polygon.to2D();
data.boundary = {lines : [], arcs : []};
function sameSketchObject(a, b) {
if (a.sketchConnectionObject === undefined || b.sketchConnectionObject === undefined) {
return false;
}
return a.sketchConnectionObject.id === b.sketchConnectionObject.id;
}
var paths = [];
polyFace.polygon.collectPaths(paths);
var _2dTr = polyFace.polygon.get2DTransformation();
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
var shift = 0;
TCAD.utils.iteratePath(path, 0, function(a, b, ai, bi) {
shift = bi;
return sameSketchObject(a, b);
});
function addSegment(a, b) {
data.boundary.lines.push({
a : {x : a.x, y: a.y},
b : {x : b.x, y: b.y}
});
}
function addArc(arc) {
if (arc.length < 2) {
return;
}
var a = arc[0], b = arc[arc.length - 1];
if (arc.length == 2) {
addSegment(a, b);
return;
}
var mid = (arc.length / 2) >> 0;
var c = TCAD.math.circleFromPoints(arc[0], arc[mid], arc[arc.length-1]);
if (c == null) {
return;
}
if (!TCAD.geom.isCCW([arc[0], arc[mid], arc[arc.length-1]])) {
var t = a;
a = b;
b = t;
}
data.boundary.arcs.push({
a : {x : a.x, y: a.y},
b : {x : b.x, y: b.y},
c : {x : c.x, y : c.y}
});
}
var currSko = null;
var arc = null;
TCAD.utils.iteratePath(path, shift+1, function(a, b, ai, bi, iterNumber, path) {
var isArc = a.sketchConnectionObject !== undefined && a.sketchConnectionObject._class == 'TCAD.TWO.Arc';
var a2d = _2dTr.apply(a);
if (isArc) {
if (currSko !== a.sketchConnectionObject.id) {
currSko = a.sketchConnectionObject.id;
if (arc != null) {
arc.push(a2d);
addArc(arc);
}
arc = [];
}
arc.push(a2d);
if (iterNumber === path.length - 1) {
arc.push(_2dTr.apply(b));
addArc(arc);
}
} else {
if (arc != null) {
arc.push(a2d);
addArc(arc);
arc = null;
}
currSko = null;
addSegment(a2d, _2dTr.apply(b));
}
return true;
});
}
localStorage.setItem(faceStorageKey, JSON.stringify(data));
window.open("sketcher.html#" + faceStorageKey.substring(14), "Edit Sketch", "height=900,width=1200");

View file

@ -172,14 +172,18 @@ TCAD.utils.isPointInsidePolygon = function( inPt, inPolygon ) {
TCAD.utils.sketchToPolygons = function(geom) {
var dict = {};
var lines = geom.lines;
var lines = geom.connections;
function key(a) {
return a[0] + ":" + a[1];
return a.x + ":" + a.y;
}
function edgeKey(a, b) {
return key(a) + ":" + key(b);
}
var size = 0;
var points = [];
var edges = {};
function memDir(a, b) {
var ak = key(a);
var dirs = dict[ak];
@ -192,10 +196,11 @@ TCAD.utils.sketchToPolygons = function(geom) {
}
for (var i = 0; i < lines.length; i++) {
var a = lines[i].slice(0,2);
var b = lines[i].slice(2,4);
var a = lines[i].a;
var b = lines[i].b;
memDir(a, b);
memDir(b, a);
edges[edgeKey(a, b)] = lines[i];
}
var graph = {
@ -223,11 +228,18 @@ TCAD.utils.sketchToPolygons = function(geom) {
var polyPoints = [];
for (var pi = 0; pi < loop.length; ++pi) {
var point = loop[pi];
polyPoints.push(new TCAD.Vector(point[0], point[1], 0));
var next = loop[(pi + 1) % loop.length];
var edge = edges[edgeKey(point, next)];
if (edge === undefined) {
edge = edges[edgeKey(next, point)];
}
polyPoints.push(point);
point.sketchConnectionObject = edge.sketchObject;
}
if (polyPoints.length >= 3) {
polygons.push(new TCAD.Polygon(polyPoints));
var polygon = new TCAD.Polygon(polyPoints);
polygons.push(polygon);
} else {
console.warn("Points count < 3!");
}
@ -303,6 +315,7 @@ TCAD.geom.extrude = function(source, target) {
lidShell[p],
lidShell[i]
]);
face.csgInfo = {derivedFrom: source.shell[i].sketchConnectionObject};
poly.push(face);
}
return poly;
@ -418,11 +431,12 @@ TCAD.SketchFace.prototype.syncSketches = function(geom) {
var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(this.polygon.shell, normal));
//we lost depth or z off in 2d sketch, calculate it again
var depth = normal.dot(this.polygon.shell[0]);
for (i = 0; i < geom.lines.length; ++i) {
var l = geom.lines[i];
for (i = 0; i < geom.connections.length; ++i) {
var l = geom.connections[i];
var lg = new THREE.Geometry();
var a = _3dTransformation.apply(new TCAD.Vector(l[0], l[1], depth));
var b = _3dTransformation.apply(new TCAD.Vector(l[2], l[3], depth));
l.a.z = l.b.z = depth;
var a = _3dTransformation.apply(l.a);
var b = _3dTransformation.apply(l.b);
lg.vertices.push(a.plus(offVector).three());
lg.vertices.push(b.plus(offVector).three());
@ -489,11 +503,15 @@ TCAD.Polygon.prototype.shift = function(target) {
return new TCAD.Polygon(shell, holes, this.normal);
};
TCAD.Polygon.prototype.get2DTransformation = function() {
var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(this.shell, this.normal));
var _2dTransformation = _3dTransformation.invert();
return _2dTransformation;
};
TCAD.Polygon.prototype.to2D = function() {
var _3dTransformation = new TCAD.Matrix().setBasis(TCAD.geom.someBasis(this.shell, this.normal));
var _2dTransformation = _3dTransformation.invert();
var _2dTransformation = this.get2DTransformation();
var i, h;
var shell = [];
@ -510,6 +528,11 @@ TCAD.Polygon.prototype.to2D = function() {
return {shell: shell, holes: holes};
};
TCAD.Polygon.prototype.collectPaths = function(paths) {
paths.push(this.shell);
paths.push.apply(paths, this.holes);
};
TCAD.Polygon.prototype.triangulate = function() {
function triangulateShape( contour, holes ) {
@ -548,3 +571,14 @@ TCAD.Polygon.prototype.eachVertex = function(handler) {
TCAD.Sketch = function() {
this.group = new THREE.Object3D();
};
TCAD.utils.iteratePath = function(path, shift, callback) {
var p, q, n = path.length;
for (p = n - 1,q = 0;q < n; p = q++) {
var ai = (p + shift) % n;
var bi = (q + shift) % n;
if (!callback(path[ai], path[bi], ai, bi, q, path)) {
break
}
}
};

View file

@ -82,3 +82,19 @@ TCAD.math.rotateMatrix = function(angle, axis, pivot) {
m.tz = pz * (1 - m.mzz) - px * m.mzx - py * m.mzy;
return m;
};
TCAD.math.circleFromPoints = function(p1, p2, p3) {
var center = new TCAD.Vector();
var offset = p2.x*p2.x + p2.y*p2.y;
var bc = ( p1.x*p1.x + p1.y*p1.y - offset )/2.0;
var cd = (offset - p3.x*p3.x - p3.y*p3.y)/2.0;
var det = (p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x)* (p1.y - p2.y);
if (Math.abs(det) < TCAD.TOLERANCE) { return null; }
var idet = 1/det;
center.x = (bc * (p2.y - p3.y) - cd * (p1.y - p2.y)) * idet;
center.y = (cd * (p1.x - p2.x) - bc * (p2.x - p3.x)) * idet;
return center;
};

View file

@ -27,6 +27,10 @@ TCAD.Vector.prototype.setV = function(data) {
return this;
};
TCAD.Vector.prototype.asKey = function() {
return this.x + ":" + this.y + ":" + this.z
};
TCAD.Vector.prototype.multiply = function(scalar) {
return new TCAD.Vector(this.x * scalar, this.y * scalar, this.z * scalar);
};

View file

@ -213,50 +213,44 @@ TCAD.IO.prototype.updateBoundary = function (boundary) {
this.boundaryLayer.readOnly = true;
this.viewer.layers.splice(0, 0, this.boundaryLayer);
}
var edges = [];
var bbox = [Number.MAX_VALUE, Number.MAX_VALUE, - Number.MAX_VALUE, - Number.MAX_VALUE];
var flattenPolygon = function(points) {
var n = points.length;
for ( var p = n - 1, q = 0; q < n; p = q ++ ) {
edges.push([points[p].x, points[p].y, points[q].x, points[q].y]);
bbox[0] = Math.min(bbox[0], points[p].x);
bbox[1] = Math.min(bbox[1], points[p].y);
bbox[2] = Math.max(bbox[2], points[q].x);
bbox[3] = Math.max(bbox[3], points[q].y);
}
};
flattenPolygon(boundary.shell);
for (var i = 0; i < boundary.holes.length; ++i ) {
flattenPolygon(boundary.holes[i]);
}
// if (bbox[0] < Number.MAX_VALUE && bbox[1] < Number.MAX_VALUE && -bbox[2] < Number.MAX_VALUE && -bbox[3] < Number.MAX_VALUE) {
// this.viewer.showBounds(bbox[0], bbox[1], bbox[2], bbox[3])
// }
for (var l = 0; l < this.viewer.layers.length; ++l) {
var layer = this.viewer.layers[l];
for (var i = 0; i < layer.objects.length; ++i) {
var obj = layer.objects[i];
if (obj.edge !== undefined) {
var edge = edges[obj.edge];
if (edge !== undefined && edge != null) {
obj.a.x = edge[0];
obj.a.y = edge[1];
obj.b.x = edge[2];
obj.b.y = edge[3];
edges[obj.edge] = null;
}
}
}
}
for (var i = 0; i < edges.length; ++i ) {
var edge = edges[i];
if (edge != null) {
var seg = this.viewer.addSegment(edge[0], edge[1], edge[2], edge[3], this.boundaryLayer);
//for (var l = 0; l < this.viewer.layers.length; ++l) {
// var layer = this.viewer.layers[l];
// for (var i = 0; i < layer.objects.length; ++i) {
// var obj = layer.objects[i];
// if (obj.edge !== undefined) {
// var edge = edges[obj.edge];
// if (edge !== undefined && edge != null) {
// obj.a.x = edge[0];
// obj.a.y = edge[1];
// obj.b.x = edge[2];
// obj.b.y = edge[3];
// edges[obj.edge] = null;
// }
// }
// }
//}
var id, i = 0;
for (i = 0; i < boundary.lines.length; ++i, ++id) {
var edge = boundary.lines[i];
var seg = this.viewer.addSegment(edge.a.x, edge.a.y, edge.b.x, edge.b.y, this.boundaryLayer);
seg.accept(function(o){o.aux = true; return true;});
seg.edge = i;
seg.edge = id ++;
}
for (i = 0; i < boundary.arcs.length; ++i, ++id) {
var a = boundary.arcs[i];
var arc = new TCAD.TWO.Arc(
new TCAD.TWO.EndPoint(a.a.x, a.a.y),
new TCAD.TWO.EndPoint(a.b.x, a.b.y),
new TCAD.TWO.EndPoint(a.c.x, a.c.y)
);
this.boundaryLayer.objects.push(arc);
arc.accept(function(o){o.aux = true; return true;});
arc.edge = id ++;
}
};

View file

@ -1,25 +1,38 @@
TCAD.workbench = {};
TCAD.workbench.SketchConnection = function(a, b, sketchObject) {
this.a = a;
this.b = b;
this.sketchObject = sketchObject;
};
TCAD.workbench.readSketchGeom = function(sketch) {
var out = {lines : [], circles : [], arcs : []};
var out = {connections : []};
var id = 0;
if (sketch.layers !== undefined) {
for (var l = 0; l < sketch.layers.length; ++l) {
for (var i = 0; i < sketch.layers[l].data.length; ++i) {
var obj = sketch.layers[l].data[i];
if (obj.edge !== undefined) continue;
if (!!obj.aux) continue;
var a = new TCAD.Vector(obj.points[0][1][1], obj.points[0][2][1], 0);
var b = new TCAD.Vector(obj.points[1][1][1], obj.points[1][2][1], 0);
if (obj._class === 'TCAD.TWO.Segment') {
out.lines.push([
obj.points[0][1][1], obj.points[0][2][1], //x,y
obj.points[1][1][1], obj.points[1][2][1] //x,y
]);
} else if (obj._class === 'TCAD.TWO.Arc') {
out.lines.push.apply(out.lines, TCAD.workbench.integrate(
[obj.points[0][1][1], obj.points[0][2][1]],
[obj.points[1][1][1], obj.points[1][2][1]],
[obj.points[2][1][1], obj.points[2][2][1]],
20
out.connections.push(new TCAD.workbench.SketchConnection(
a, b, {_class : obj._class, id : id++}
));
} else if (obj._class === 'TCAD.TWO.Arc') {
var center = new TCAD.Vector(obj.points[2][1][1], obj.points[2][2][1], 0);
var approxArc = TCAD.workbench.approxArc(a, b, center, 20);
var data = {_class : obj._class, id : id++};
for (var j = 0; j < approxArc.length - 1; j++) {
var pa = approxArc[j];
var pb = approxArc[j+1];
out.connections.push(new TCAD.workbench.SketchConnection(
pa, pb, data
));
}
} else if (obj._class === 'TCAD.TWO.Circle') {
}
}
@ -28,13 +41,10 @@ TCAD.workbench.readSketchGeom = function(sketch) {
return out;
};
TCAD.workbench.integrate = function(_a, _b, _c, k) {
var ao = new TCAD.Vector(_a[0], _a[1], 0);
var bo = new TCAD.Vector(_b[0], _b[1], 0);
var c = new TCAD.Vector(_c[0], _c[1], 0);
TCAD.workbench.approxArc = function(ao, bo, c, k) {
var a = ao.minus(c);
var b = bo.minus(c);
var points = [[ao.x, ao.y]];
var points = [ao];
var abAngle = Math.atan2(b.y, b.x) - Math.atan2(a.y, a.x);
if (abAngle > Math.PI * 2) abAngle = Math.PI / 2 - abAngle;
if (abAngle < 0) abAngle = Math.PI * 2 + abAngle;
@ -44,21 +54,15 @@ TCAD.workbench.integrate = function(_a, _b, _c, k) {
var angle = Math.atan2(a.y, a.x) + step;
for (var i = 0; i < k - 2; ++i) {
points.push([c.x + r*Math.cos(angle), c.y + r*Math.sin(angle)]);
points.push(new TCAD.Vector(c.x + r*Math.cos(angle), c.y + r*Math.sin(angle)));
angle += step;
}
points.push([bo.x, bo.y]);
var lines = [];
for (var i = 0; i < points.length - 1; i++) {
var p1 = points[i];
var p2 = points[i + 1];
lines.push([p1[0], p1[1], p2[0], p2[1]]);
}
return lines;
points.push(bo);
return points;
};
TCAD.workbench.serializeSolid = function(solid) {
data = {};
var data = {};
data.faceCounter = TCAD.geom.FACE_COUNTER;
for (var fi = 0; fi < solid.faces.length; ++fi) {
var face = solid.faces[fi];
@ -129,9 +133,11 @@ TCAD.craft.getSketchedPolygons3D = function(app, face) {
vec.z = depth;
// var a = _3dTransformation.apply(new TCAD.Vector(poly2D[m][0], poly2D[m][1], depth));
var a = _3dTransformation.apply(vec);
shell.push(a)
a.sketchConnectionObject = vec.sketchConnectionObject;
shell.push(a);
}
sketchedPolygons.push(new TCAD.Polygon(shell));
var polygon = new TCAD.Polygon(shell);
sketchedPolygons.push(polygon);
}
return sketchedPolygons;
};
@ -195,7 +201,7 @@ TCAD.craft._mergeCSGPolygonsTest = function() {
console.log(paths);
};
TCAD.craft._mergeCSGPolygons = function (__cgsPolygons) {
TCAD.craft._mergeCSGPolygons = function (__cgsPolygons, allPoints) {
var pointToPoly = {};
var points = [];
var pkey = TCAD.craft.pkey;
@ -231,6 +237,7 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons) {
vertices: cp.vertices.map(function (cv) {
return vec(cv.pos)
}),
csgInfo : cp.shared.__tcad,
normal: vec(cp.plane.normal),
w: cp.plane.w
};
@ -243,12 +250,13 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons) {
for (var vi = 0; vi < poly.vertices.length; ++vi) {
var vert = poly.vertices[vi];
points.push(vert);
allPoints.push(vert);
}
}
var tol = 1E-6;
for (var i = 0; i < points.length; i++) {
var a = points[i];
for (var i = 0; i < allPoints.length; i++) {
var a = allPoints[i];
for (var j = i + 1; j < points.length; j++) {
var b = points[j];
if (
@ -508,6 +516,7 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons) {
visited[pnkey(pCurr, normal)] = true;
var foundNext = true;
var csgInfo;
while (foundNext) {
foundNext = false;
path.push(vec(pCurr));
@ -515,6 +524,7 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons) {
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;
@ -543,7 +553,8 @@ TCAD.craft._mergeCSGPolygons = function (__cgsPolygons) {
paths.push({
vertices : path,
normal : normal,
w : w
w : w,
csgInfo : csgInfo
});
}
}
@ -619,6 +630,7 @@ TCAD.craft._makeFromPolygons = function(polygons) {
}
var pid = poly.id;
var shared = new CSG.Polygon.Shared([pid, pid, pid, pid]);
shared.__tcad = poly.csgInfo;
var refs = poly.triangulate();
for ( var i = 0; i < refs.length; ++ i ) {
var a = refs[i][0] + off;
@ -639,6 +651,43 @@ TCAD.craft._makeFromPolygons = function(polygons) {
return csgPolygons;
};
TCAD.craft.recoverySketchInfo = function(polygons) {
var nonStructuralGons = [];
var sketchEdges = {};
function key(a, b) {return a.asKey() + ":" + b.asKey()}
for (var pi = 0; pi < polygons.length; pi++) {
var poly = polygons[pi];
var paths = [];
poly.collectPaths(paths);
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
if (poly.csgInfo !== undefined && poly.csgInfo.derivedFrom !== undefined) {
var n = path.length;
for (var p = n - 1, q = 0; q < n ; p = q++ ) {
sketchEdges[key(path[p], path[q])] = poly.csgInfo;
}
} else {
nonStructuralGons.push(path);
}
}
}
for (var i = 0; i < nonStructuralGons.length; i++) {
var path = nonStructuralGons[i];
var n = path.length;
for (var p = n - 1, q = 0; q < n ; p = q++ ) {
var csgInfo = sketchEdges[key(path[p], path[q])];
if (!csgInfo) {
csgInfo = sketchEdges[key(path[q], path[p])];
}
if (csgInfo) {
path[p].sketchConnectionObject = csgInfo.derivedFrom;
}
}
}
};
TCAD.craft.cut = function(app, face, faces, height) {
var sketchedPolygons = TCAD.craft.getSketchedPolygons3D(app, face);
@ -703,7 +752,8 @@ TCAD.craft.cut = function(app, face, faces, height) {
return {
vertices : path.vertices.map(function(v) {return tr.apply(v);}),
normal : path.normal,
w : path.w
w : path.w,
csgInfo : path.csgInfo
}
});
@ -782,15 +832,21 @@ TCAD.craft.cut = function(app, face, faces, height) {
byShared[tag].push(p);
}
var result = [];
var allPoints = [];
for (var tag in byShared) {
var merged = TCAD.craft._mergeCSGPolygons(byShared[tag]);
var merged = TCAD.craft._mergeCSGPolygons(byShared[tag], allPoints);
var sorted = sortPaths(merged);
result.push.apply(result, sorted.map(function(path) {
return new TCAD.Polygon(path.vertices, path.holes.map(function(path){return path.vertices}), path.normal);
var p = new TCAD.Polygon(path.vertices, path.holes.map(function (path) {
return path.vertices
}), path.normal);
p.csgInfo = path.csgInfo;
return p;
})
);
}
TCAD.craft.recoverySketchInfo(result);
return result;
};