Commit 109d726a authored by amandaghassaei's avatar amandaghassaei
Browse files

working on a rigid solver

parent 2a9f4cde
......@@ -388,6 +388,7 @@
<script type="text/javascript" src="js/3dUI.js"></script>
<script type="text/javascript" src="js/staticSolver.js"></script>
<script type="text/javascript" src="js/dynamic/dynamicSolver.js"></script>
<script type="text/javascript" src="js/rigidSolver.js"></script>
<script type="text/javascript" src="js/pattern.js"></script>
<script type="text/javascript" src="js/saveSTL.js"></script>
<script type="text/javascript" src="js/saveFOLD.js"></script>
......@@ -508,6 +509,10 @@
<input name="simType" value="static" data-toggle="radio" class="custom-radio" type="radio"><span class="icons"><span class="icon-unchecked"></span><span class="icon-checked"></span></span>
Compliant Static Simulation <a class="about floatRight" href="#" id="aboutStaticSim"><span class="fui-question-circle"></span></a>
</label>
<label class="radio">
<input name="simType" value="rigid" data-toggle="radio" class="custom-radio" type="radio"><span class="icons"><span class="icon-unchecked"></span><span class="icon-checked"></span></span>
Rigid Static Simulation <a class="about floatRight" href="#" id="aboutRigidSim"><span class="fui-question-circle"></span></a>
</label>
</div><br/>
<label class="checkbox" for="userInteractionEnabled">
<input id="userInteractionEnabled" data-toggle="checkbox" class="custom-checkbox layersSelector" type="checkbox"><span class="icons"><span class="icon-unchecked"></span><span class="icon-checked"></span></span>
......@@ -937,6 +942,20 @@
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="modal fade" id="aboutRigidSimModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-med">
<div class="modal-content">
<div class="modal-body">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<p><b>Rigid Static Simulation</b><br/><br/>
....
</p>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="modal fade" id="aboutAxialStrainModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-med">
<div class="modal-content">
......
......@@ -123,12 +123,8 @@ function initControls(globals){
setRadio("simType", globals.simType, function(val){
if (val == "static"){
globals.staticSolver.syncNodesAndEdges();
} else if (val == "dynamic"){
globals.dynamicSolver.syncNodesAndEdges();
}
globals.simType = val;
globals.needsSync = true;
});
setSliderInput("#axialStiffness", globals.axialStiffness, 10, 40, 1, function(val){
......@@ -252,6 +248,9 @@ function initControls(globals){
setLink("#aboutStaticSim", function(){
$("#aboutStaticSimModal").modal("show");
});
setLink("#aboutRigidSim", function(){
$("#aboutRigidSimModal").modal("show");
});
setLink("#aboutAxialStrain", function(){
$("#aboutAxialStrainModal").modal("show");
});
......
......@@ -38,7 +38,7 @@ function initDynamicSolver(globals){
faces = globals.model.getFaces();
creases = globals.model.getCreases();
globals.model.sync();
// globals.model.sync();
positions = globals.model.getPositionsArray();
colors = globals.model.getColorsArray();
......@@ -64,49 +64,45 @@ function initDynamicSolver(globals){
}
function solve(_numSteps){
if (globals.shouldSyncWithModel){
syncNodesAndEdges();
globals.shouldSyncWithModel = false;
} else {
if (globals.forceHasChanged) {
updateExternalForces();
globals.forceHasChanged = false;
}
if (globals.fixedHasChanged) {
updateFixed();
globals.fixedHasChanged = false;
}
if (globals.nodePositionHasChanged) {
updateLastPosition();
globals.nodePositionHasChanged = false;
}
if (globals.creaseMaterialHasChanged) {
updateCreasesMeta();
globals.creaseMaterialHasChanged = false;
}
if (globals.materialHasChanged) {
updateMaterials();
globals.materialHasChanged = false;
}
if (globals.shouldChangeCreasePercent) {
setCreasePercent(globals.creasePercent);
globals.shouldChangeCreasePercent = false;
}
// if (globals.shouldZeroDynamicVelocity){
// globals.gpuMath.step("zeroTexture", [], "u_velocity");
// globals.gpuMath.step("zeroTexture", [], "u_lastVelocity");
// globals.shouldZeroDynamicVelocity = false;
// }
if (globals.shouldCenterGeo){
var avgPosition = getAvgPosition();
globals.gpuMath.setProgram("centerTexture");
globals.gpuMath.setUniformForProgram("centerTexture", "u_center", [avgPosition.x, avgPosition.y, avgPosition.z], "3f");
globals.gpuMath.step("centerTexture", ["u_lastPosition"], "u_position");
globals.gpuMath.swapTextures("u_position", "u_lastPosition");
globals.gpuMath.step("zeroTexture", [], "u_lastVelocity");
globals.gpuMath.step("zeroTexture", [], "u_velocity");
globals.shouldCenterGeo = false;
}
if (globals.forceHasChanged) {
updateExternalForces();
globals.forceHasChanged = false;
}
if (globals.fixedHasChanged) {
updateFixed();
globals.fixedHasChanged = false;
}
if (globals.nodePositionHasChanged) {
updateLastPosition();
globals.nodePositionHasChanged = false;
}
if (globals.creaseMaterialHasChanged) {
updateCreasesMeta();
globals.creaseMaterialHasChanged = false;
}
if (globals.materialHasChanged) {
updateMaterials();
globals.materialHasChanged = false;
}
if (globals.shouldChangeCreasePercent) {
setCreasePercent(globals.creasePercent);
globals.shouldChangeCreasePercent = false;
}
// if (globals.shouldZeroDynamicVelocity){
// globals.gpuMath.step("zeroTexture", [], "u_velocity");
// globals.gpuMath.step("zeroTexture", [], "u_lastVelocity");
// globals.shouldZeroDynamicVelocity = false;
// }
if (globals.shouldCenterGeo){
var avgPosition = getAvgPosition();
globals.gpuMath.setProgram("centerTexture");
globals.gpuMath.setUniformForProgram("centerTexture", "u_center", [avgPosition.x, avgPosition.y, avgPosition.z], "3f");
globals.gpuMath.step("centerTexture", ["u_lastPosition"], "u_position");
globals.gpuMath.swapTextures("u_position", "u_lastPosition");
globals.gpuMath.step("zeroTexture", [], "u_lastVelocity");
globals.gpuMath.step("zeroTexture", [], "u_velocity");
globals.shouldCenterGeo = false;
}
if (_numSteps == undefined) _numSteps = globals.numSteps;
......
......@@ -29,10 +29,10 @@ function initGlobals(){
creaseMaterialHasChanged: false,
shouldResetDynamicSim: false,
shouldChangeCreasePercent: false,
shouldSyncWithModel: false,
nodePositionHasChanged: false,
shouldZeroDynamicVelocity: false,
shouldCenterGeo: false,
needsSync: false,
//3d vis
simType: "dynamic",
......
......@@ -16,6 +16,7 @@ $(function() {
globals.model = initModel(globals);
globals.staticSolver = initStaticSolver(globals);
globals.dynamicSolver = initDynamicSolver(globals);
globals.rigidSolver = initRigidSolver(globals);
globals.pattern = initPattern(globals);
globals.vive = initViveInterface(globals);
$(".demo[data-url='Tessellations/waterbomb.svg']").click();
......
......@@ -98,55 +98,6 @@ function initModel(globals){
return colors;
}
// nodes.push(new Node(new THREE.Vector3(0,0,0), nodes.length));
// nodes.push(new Node(new THREE.Vector3(0,0,10), nodes.length));
// nodes.push(new Node(new THREE.Vector3(10,0,0), nodes.length));
// nodes.push(new Node(new THREE.Vector3(0,0,-10), nodes.length));
// nodes.push(new Node(new THREE.Vector3(10,0,-10), nodes.length));
// nodes.push(new Node(new THREE.Vector3(-10,0,0), nodes.length));
// nodes[0].setFixed(true);
// nodes[1].setFixed(true);
// nodes[2].setFixed(true);
// edges.push(new Beam([nodes[1], nodes[0]]));
// edges.push(new Beam([nodes[1], nodes[2]]));
// edges.push(new Beam([nodes[2], nodes[0]]));
// edges.push(new Beam([nodes[3], nodes[0]]));
// edges.push(new Beam([nodes[3], nodes[2]]));
// edges.push(new Beam([nodes[3], nodes[4]]));
// edges.push(new Beam([nodes[2], nodes[4]]));
// edges.push(new Beam([nodes[4], nodes[0]]));
// edges.push(new Beam([nodes[4], nodes[1]]));
// edges.push(new Beam([nodes[3], nodes[4]]));
// faces.push(new THREE.Face3(0,1,2));
// faces.push(new THREE.Face3(0,2,3));
// faces.push(new THREE.Face3(4,3,2));
// faces.push(new THREE.Face3(4,1,0));
// faces.push(new THREE.Face3(3,4,0));
// creases.push(new Crease(edges[2], 0, 1, Math.PI, 1, nodes[1], nodes[3], 0));
// creases.push(new Crease(edges[4], 2, 1, -Math.PI, 1, nodes[4], nodes[0], 1));
// creases.push(new Crease(edges[5], 3, 2, -Math.PI, 1, nodes[3], nodes[1], 1));
// creases.push(new Crease(edges[0], 3, 0, Math.PI, 1, nodes[4], nodes[2], 2));
// var _allNodeObject3Ds = [];
// _.each(nodes, function(node){
// var obj3D = node.getObject3D();
// _allNodeObject3Ds.push(obj3D);
// globals.threeView.sceneAddModel(obj3D);
// });
// allNodeObject3Ds = _allNodeObject3Ds;
// _.each(edges, function(edge){
// globals.threeView.sceneAddModel(edge.getObject3D());
// });
function pause(){
globals.threeView.pauseSimulation();
}
......@@ -156,12 +107,23 @@ function initModel(globals){
}
function reset(){
getSolver().reset();
var solver = getSolver();
if (globals.needsSync){
solver.syncNodesAndEdges();
globals.needsSync = false;
}
solver.reset();
setGeoUpdates();
}
function step(numSteps){
getSolver().solve(numSteps);
var solver = getSolver();
if (globals.needsSync){
solver.syncNodesAndEdges();
globals.needsSync = false;
}
solver.solve(numSteps);
geometry.attributes.position.needsUpdate = true;
setGeoUpdates();
}
......@@ -179,9 +141,7 @@ function initModel(globals){
function startSolver(){
globals.threeView.startAnimation(function(){
if (!inited) return;
getSolver().solve();
geometry.attributes.position.needsUpdate = true;
setGeoUpdates();
step();
});
}
......@@ -203,9 +163,9 @@ function initModel(globals){
for (var i=0;i<_vertices.length;i++){
_nodes.push(new Node(_vertices[i].clone(), _nodes.length));
}
// _nodes[_faces[0].a].setFixed(true);
// _nodes[_faces[0].b].setFixed(true);
// _nodes[_faces[0].c].setFixed(true);
// _nodes[_faces[0][0]].setFixed(true);
// _nodes[_faces[0][1]].setFixed(true);
// _nodes[_faces[0][2]].setFixed(true);
var _edges = [];
for (var i=0;i<_allEdges.length;i++) {
......@@ -257,7 +217,6 @@ function initModel(globals){
globals.threeView.sceneAddModel(object3D);
globals.threeView.sceneAddModel(object3D2);
globals.shouldSyncWithModel = true;
inited = true;
updateEdgeVisibility();
updateMeshVisibility();
......@@ -271,14 +230,15 @@ function initModel(globals){
}
if (!globals.threeView.running()) {
getSolver().syncNodesAndEdges();
sync();
}
globals.needsSync = true;
}
function getSolver(){
if (globals.simType == "dynamic") return globals.dynamicSolver;
return globals.staticSolver;
else if (globals.simType == "static") return globals.staticSolver;
return globals.rigidSolver;
}
function sync(){
......
......@@ -164,6 +164,11 @@ Node.prototype.render = function(position){
this.object3D.position.set(position.x, position.y, position.z);//todo need this?
return position;
};
Node.prototype.renderDelta = function(delta){
// if (this.fixed) return;
this.object3D.position.add(delta);
return this.object3D.position;
};
Node.prototype.renderChange = function(change){
this.object3D.position.add(change);
......
......@@ -717,6 +717,7 @@ function initPattern(globals){
if (!containsInnerCrease) {
polygons.splice(i,1);
polygonEdges.splice(i,1);
break;//todo only remove once
}
}
......
/**
* Created by amandaghassaei on 5/26/17.
*/
function initRigidSolver(){
var nodes;
var edges;
var faces;
var creases;
var positions;
var C, F;
function syncNodesAndEdges(){
nodes = globals.model.getNodes();
edges = globals.model.getEdges();
faces = globals.model.getFaces();
creases = globals.model.getCreases();
positions = globals.model.getPositionsArray();
setUpParams();
}
function solve(){
updateMatrices();
solveStep();
}
function reset(){
}
// function pinv(A) { //for linearly ind rows
// var AT = numeric.transpose(A);
// return numeric.dot(AT, numeric.inv(numeric.dot(AT,A)));
// }
function pinv(A) {
//http://www.numericjs.com/workshop.php?link=b923cdeb84e188a11b44e3e82e44897b3b7da1d6640ddb46ab7330a6625f8e19
var z = numeric.svd(A), foo = z.S[0];
var U = z.U, S = z.S, V = z.V;
var m = A.length, n = A[0].length, tol = Math.max(m,n)*numeric.epsilon*foo,M = S.length;
var i,Sinv = new Array(M);
for(i=M-1;i!==-1;i--) { if(S[i]>tol) Sinv[i] = 1/S[i]; else Sinv[i] = 0; }
return numeric.dot(numeric.dot(V,numeric.diag(Sinv)),numeric.transpose(U))
}
function solveStep(){
//todo add external forces
var X = numeric.dot(numeric.sub(numeric.identity(3*nodes.length),
numeric.dot(numeric.transpose(pinv(numeric.transpose(C))), C)), F);//todo valid psuedoinv?
// var sum = new THREE.Vector3();
// for (var i=0;i<_F.length;i+=3){
// sum.x += _F[i];
// sum.y += _F[i+1];
// sum.z += _F[i+2];
// }
// console.log(sum);
console.log(X);
render(X);
}
function render(X){
for (var i=0;i<nodes.length;i++){
var nodePosition = new THREE.Vector3(X[3*i], X[3*i+1], X[3*i+2]);
var nexPos = nodes[i].renderDelta(nodePosition);
positions[3*i] = nexPos.x;
positions[3*i+1] = nexPos.y;
positions[3*i+2] = nexPos.z;
}
for (var i=0;i<edges.length;i++){
edges[i].render();
}
}
function initEmptyArray(dim1, dim2, dim3){
if (dim2 === undefined) dim2 = 0;
if (dim3 === undefined) dim3 = 0;
var array = [];
for (var i=0;i<dim1;i++){
if (dim2 == 0) array.push(0);
else array.push([]);
for (var j=0;j<dim2;j++){
if (dim3 == 0) array[i].push(0);
else array[i].push([]);
for (var k=0;k<dim3;k++){
array[i][j].push(0);
}
}
}
return array;
}
function setUpParams(){
//C = (edges + creases) x 3nodes
//disp = 1 x 3nodes
C = initEmptyArray(edges.length, 3*nodes.length);//todo change size
F = initEmptyArray(3*nodes.length);
// for (var i=0;i<nodes.length;i++){
// F[3*i] = 0;
// F[3*i+1] = 0;
// F[3*i+2] = 0;
// }
}
function updateMatrices(){
var numNodes = nodes.length;
var numEdges = edges.length;
F = initEmptyArray(3*numNodes);
for (var j=0;j<numEdges;j++){
var edge = edges[j];
var _nodes = edge.nodes;
var edgeVector0 = edge.getVector(_nodes[0]);
var length = edge.getOriginalLength();
var diff = edgeVector0.length() - length;
var rxnForceScale = globals.axialStiffness*diff/length;
edgeVector0.normalize();
var i = _nodes[0].getIndex();
C[j][3*i] = edgeVector0.x;
C[j][3*i+1] = edgeVector0.y;
C[j][3*i+2] = edgeVector0.z;
F[3*i] -= edgeVector0.x*rxnForceScale;
F[3*i+1] -= edgeVector0.y*rxnForceScale;
F[3*i+2] -= edgeVector0.z*rxnForceScale;
i = _nodes[1].getIndex();
C[j][3*i] = -edgeVector0.x;
C[j][3*i+1] = -edgeVector0.y;
C[j][3*i+2] = -edgeVector0.z;
F[3*i] += edgeVector0.x*rxnForceScale;
F[3*i+1] += edgeVector0.y*rxnForceScale;
F[3*i+2] += edgeVector0.z*rxnForceScale;
}
var geometry = globals.model.getGeometry();
var indices = geometry.index.array;
var normals = [];
//compute all normals
var cb = new THREE.Vector3(), ab = new THREE.Vector3();
for (var j=0;j<indices.length;j+=3){
var index = 3*indices[j];
var vA = new THREE.Vector3(positions[index], positions[index+1], positions[index+2]);
index = 3*indices[j+1];
var vB = new THREE.Vector3(positions[index], positions[index+1], positions[index+2]);
index = 3*indices[j+2];
var vC = new THREE.Vector3(positions[index], positions[index+1], positions[index+2]);
cb.subVectors( vC, vB );
ab.subVectors( vA, vB );
cb.cross( ab );
cb.normalize();
normals.push(cb.clone());
}
for (var j=0;j<numFreeCreases;j++){
var crease = creases[freeCreasesMapping[j]];
var normal1 = normals[crease.face1Index];
var normal2 = normals[crease.face2Index];
var dotNormals = normal1.dot(normal2);
if (dotNormals < -1.0) dotNormals = -1.0;
else if (dotNormals > 1.0) dotNormals = 1.0;
var creaseVector = crease.getVector().normalize();
//https://math.stackexchange.com/questions/47059/how-do-i-calculate-a-dihedral-angle-given-cartesian-coordinates
var theta = Math.atan2((normal1.clone().cross(creaseVector)).dot(normal2), dotNormals);
var diff = theta - globals.creasePercent*crease.targetTheta;
var rxnForceScale = crease.getK()*diff;
var partial1, partial2;
if (!crease.node1.fixed){
var i = indicesMapping.indexOf(crease.node1.getIndex());
var dist = crease.getLengthToNode1();
var partial1 = normal1.clone().divideScalar(dist);
// C[j+numFreeEdges][3*i] = partial1.x;
// C[j+numFreeEdges][3*i+1] = partial1.y;
// C[j+numFreeEdges][3*i+2] = partial1.z;
F[3*i] -= partial1.x*rxnForceScale;
F[3*i+1] -= partial1.y*rxnForceScale;
F[3*i+2] -= partial1.z*rxnForceScale;
}
if (!crease.node2.fixed){
var i = indicesMapping.indexOf(crease.node2.getIndex());
var dist = crease.getLengthToNode2();
var partial2 = normal2.clone().divideScalar(dist);
// C[j+numFreeEdges][3*i] = partial2.x;
// C[j+numFreeEdges][3*i+1] = partial2.y;
// C[j+numFreeEdges][3*i+2] = partial2.z;
F[3*i] -= partial2.x*rxnForceScale;
F[3*i+1] -= partial2.y*rxnForceScale;
F[3*i+2] -= partial2.z*rxnForceScale;
}
var creaseNodes = crease.edge.nodes;
for (var k=0;k<creaseNodes.length;k++){
var node = creaseNodes[k];
if (node.fixed) continue;
var i = indicesMapping.indexOf(node.getIndex());
// C[j+numFreeEdges][3*i] = -(partial1.x+partial2.x)/2;
// C[j+numFreeEdges][3*i+1] = -(partial1.y+partial2.y)/2;
// C[j+numFreeEdges][3*i+2] = -(partial1.z+partial2.z)/2;
F[3*i] += (partial1.x+partial2.x)/2*rxnForceScale;
F[3*i+1] += (partial1.y+partial2.y)/2*rxnForceScale;
F[3*i+2] += (partial1.z+partial2.z)/2*rxnForceScale;
}
}
}
return {
syncNodesAndEdges: syncNodesAndEdges,
solve:solve,
reset:reset
}
}
\ No newline at end of file
......@@ -34,6 +34,11 @@ function initStaticSolver(){
function reset(){
}
function pinv(A) { //for linearly ind rows
var AT = numeric.transpose(A);
return numeric.dot(AT, numeric.inv(numeric.dot(AT,A)));
}
function solveStep(){
console.log("static solve");
// if (fixedIndicesMapping.length == 0){//no boundary conditions
......@@ -47,9 +52,14 @@ function initStaticSolver(){
for (var i=0;i<_F.length;i++) {
_F[i] += F_rxn[i];
}
var X = numeric.dot(numeric.inv(Ctrans_Q_C), _F);
console.log(_F);
var X = numeric.solve(Ctrans_Q_C, _F);
// var sum = new THREE.Vector3();
// for (var i=0;i<_F.length;i+=3){
// sum.x += _F[i];
// sum.y += _F[i+1];
// sum.z += _F[i+2];
// }
// console.log(sum);
render(X);
}
......@@ -59,7 +69,7 @@ function initStaticSolver(){
for (var i=0;i<numVerticesFree;i++){
var index = indicesMapping[i];
var nodePosition = new THREE.Vector3(X[3*i], X[3*i+1], X[3*i+2]);
var nexPos = nodes[index].render(nodePosition);
var nexPos = nodes[index].renderDelta(nodePosition);
positions[3*index] = nexPos.x;
positions[3*index+1] = nexPos.y;
positions[3*index+2] = nexPos.z;
......@@ -98,6 +108,7 @@ function initStaticSolver(){
function updateMatrices(){
calcCsAndRxns();
Ctrans = numeric.transpose(C);
// console.log(Q);
Ctrans_Q = numeric.dot(Ctrans, Q);
Ctrans_Q_C = numeric.dot(Ctrans_Q, C);
}
......@@ -201,65 +212,64 @@ function initStaticSolver(){
}
for (var j=0;j<