import javax.media.opengl.GL; import java.util.Vector; public class cSpring extends //Composite // Object3D { static final long serialVersionUID = 338243130295214239L; // -158963378355317467L; boolean IsStatic() { return !(live && (Globals.isLIVE() || CameraPane.waslive)); } void Revert() { setup(); // redo the full geometry merge. if (support != null) linkVerticesThis(support); transientrep = bRep; bRep = null; InitPhysics(); } void Reset() { RefreshPositions(); if (Phys == null) // || spring.IsAutoFreeze()) InitPhysics(); RefreshNormals(); Phys.Reset(); } void Step() { if (Phys == null) // || spring.IsAutoFreeze()) InitPhysics(); Phys.update(); } void Freeze() { if (transientrep == null) Revert(); FreezeCopy(); RefreshPositions(); InitPhysics(); } void FreezeCopy() { } void RefreshPositions() { } void RefreshNormals() { } transient PhysicsController3D Phys; transient DynamicNode[][] mesh; transient DynamicNode[][] mesh2; //DynamicNode[][] centers; transient DynamicNode[] handles; Gravity G; Wind W; // single wind or list of forces (avoidance, etc) Force C; // Speed manager (collision) // boolean live = true; boolean thick = false; boolean singlelayer = true; boolean showsprings = false; // serial // stiffness double K = 4f; // timestep double timestep = 1; double normalpush = 0; // 1; static float H0 = 1E1f; // aucune importance... // mass double M = 1; // force strength cut-off double limit = 10000000; double solidity = 100000; // height = 40; double restlengthFactor = 1f; // restlength factor for mesh double thefloor = -1000; // -10000; static double THEFLOOR = -10000; double friction = 1; double elastic = 1; double damping = 0.2; double powdamping; // cache double cachedamping = -1; // cache double distortion = 1; // 0.01f; // was eps = 0.01f; double slowness = 5; int numX = 32; // 200; int numY = 32; // 4; int neighbors = 2; static int counter = 0; int timeout = 10000000; int time = 0; int framecount = 0; // This is not used, so we save 32 1-bit options static final int EPSEQUAL = 1; static final int SHOWINFO = 2; static final int SOLID = 4; static final int SOFT = 8; static final int FOLD = 16; static final int AUTOFREEZE = 32; static final int UNFOLD = 64; static final int FASTNORMALS = 128; static final int NORMALIZE = 256; static final int UPDATEHANDLES = 512; static final int POSEMESH = 1024; static final int LINKUV = 2048; int id = SOLID | LINKUV; // | SOFT; boolean IsPoseMesh() { return (id & POSEMESH) != 0; } boolean IsEpsEqual() { return (id & EPSEQUAL) != 0; } boolean IsLinkUV() { return (id & LINKUV) != 0; } boolean IsSolid() { return (id & SOLID) != 0; } boolean IsSoft() { return (id & SOFT) != 0; } boolean ShowInfo() { return (id & SHOWINFO) != 0; } boolean IsFold() { return (id & FOLD) != 0; } boolean IsUnfold() { return (id & UNFOLD) != 0; } boolean IsAutoFreeze() { return (id & AUTOFREEZE) != 0; } boolean IsFastNormals() { return (id & FASTNORMALS) != 0; } boolean IsNormalize() { return (id & NORMALIZE) != 0; } boolean IsUpdateHandles() { return (id & UPDATEHANDLES) != 0; } void SetEpsEqual(boolean x) { if (x) id |= EPSEQUAL; else id &= ~EPSEQUAL; } void SetLinkUV(boolean x) { if (x) id |= LINKUV; else id &= ~LINKUV; } void SetPoseMesh(boolean x) { if (x) id |= POSEMESH; else id &= ~POSEMESH; } void SetSolid(boolean x) { if (x) id |= SOLID; else id &= ~SOLID; } void SetSoft(boolean x) { if (x) id |= SOFT; else id &= ~SOFT; } void SetShowInfo(boolean x) { if (x) id |= SHOWINFO; else id &= ~SHOWINFO; } void SetFold(boolean x) { if (x) id |= FOLD; else id &= ~FOLD; } void SetUnfold(boolean x) { if (x) id |= UNFOLD; else id &= ~UNFOLD; } void SetAutoFreeze(boolean x) { if (x) id |= AUTOFREEZE; else id &= ~AUTOFREEZE; } void SetFastNormals(boolean x) { if (x) id |= FASTNORMALS; else id &= ~FASTNORMALS; } void SetNormalize(boolean x) { if (x) id |= NORMALIZE; else id &= ~NORMALIZE; } void SetUpdateHandles(boolean x) { if (x) id |= UPDATEHANDLES; else id &= ~UPDATEHANDLES; } boolean resetdelta = false; cSpring() { this("Spring"); } cSpring(String name) { super(name); // id = counter++; G = new Gravity(0); // .3f); //Wind w = new Wind(10f, 0.f, 1); W = new ActingForces(); // includes default Wind //W.AddForce(w); C = new Collision(THEFLOOR); //setup(); } Point3D zero = new Point3D(); Point3D X = new Point3D(1, 0, 0); Point3D Y = new Point3D(0, 1, 0); Point3D Z = new Point3D(0, 0, 1); Point3D a = new Point3D(); Point3D b = new Point3D(); Object3D deepCopy() { cSpring e = new cSpring(); deepCopySelf(e); return e; } void createEditWindow(GroupEditor callee, boolean newWindow) { if (newWindow) { objectUI = new cSpringEditor(this, deepCopy(), callee); } else { objectUI = new cSpringEditor(this, callee); } editWindow = objectUI.GetEditor(); } void ResetDelta() { resetdelta = true; } void setup() { InitPhysics(); } void InitPhysics() { Phys = new PhysicsController3D(); mesh = new DynamicNode[numX][numY]; if (thick) { mesh2 = new DynamicNode[numX][numY]; } else { mesh2 = null; } //centers = new DynamicNode[numX-1][numY-1]; handles = new DynamicNode[numX]; time = 0; //Create Nodes for (int r = 0; r < numX; r++) { for (int c = 0; c < numY; c++) { //mesh[r][c] = new DynamicNode(-(double)(c+r/10.0f)/numY, ((double)r+c/10.0f+5)/numY, (double)c/numY, 1.0f/(numX*numY), 0); // .01f); // 1f); //boolean free = (r 10 * 10; mesh[r][c] = new DynamicNode(-2 * c, /*2*r+*/ height + Math.random() * 0.001, 2 * r, free ? -M : -Float.MAX_VALUE, 0.01f); // 1f); if (thick) { mesh2[r][c] = new DynamicNode(-2 * c, /*2*r+*/ restlengthFactor + height + Math.random() * 0.001, 2 * r/*-thickness*/, -M, 0.01f); } // 1f); mesh[r][c].addForce(W); mesh[r][c].addForce(G); //mesh[r][c].addForce(C); Phys.addNode(mesh[r][c]); if (thick) { mesh2[r][c].addForce(W); mesh2[r][c].addForce(G); Phys.addNode(mesh2[r][c]); } } } ////Phys.addForce(G); ////Phys.addForce(W); Phys.addForce(C); //Create Handles for (int r = 0; r < numX; r++) { //handles[r] = new DynamicNode(0, ((double)r+5)/numY, 0, Float.MAX_VALUE, 0); //handles[r] = new DynamicNode(0, ((double)2*r+2), 0, Float.MAX_VALUE, 0); //Phys.addNode(handles[r]); } //connect mesh // structural if (thick) { for (int i = 1; i < 2; i++) { for (int r = 0; r < numX; r++) { for (int c = 0; c < numY - i; c++) { new Spring(mesh[r][c], mesh[r][c + i], K * 1, 1); if (thick) { new Spring(mesh2[r][c], mesh2[r][c + i], K * 1, 1); } } } for (int r = 0; r < numX - i; r++) { for (int c = 0; c < numY; c++) { new Spring(mesh[r][c], mesh[r + i][c], K * 1, 1); if (thick) { new Spring(mesh2[r][c], mesh2[r + i][c], K * 1, 1); } } } } } /* // flexion for (int r = 0; r < numX; r++) { for (int c = 0; c < numY - 2; c++) { new Spring(mesh[r][c], mesh[r][c + 2], K*1, 1); if(thick) new Spring(mesh2[r][c], mesh2[r][c + 2], K*1, 1); } } for (int r = 0; r < numX - 2; r++) { for (int c = 0; c < numY; c++) { new Spring(mesh[r][c], mesh[r + 2][c], K*1, 1); if(thick) new Spring(mesh2[r][c], mesh2[r + 2][c], K*1, 1); } } */ // center /* for (int r = 0; r < numX-1; r++) { for (int c = 0; c < numY-1; c++) { centers[r][c] = new DynamicNode(-2*c-1, 2*r+3, 2*r, 10f, 0.01f); //centers[r][c].addForce(W); centers[r][c].addForce(G); Phys.addNode(centers[r][c]); new Spring(centers[r][c], mesh[r][c], K*1, 1f); new Spring(centers[r][c], mesh[r+1][c], K*1, 1f); new Spring(centers[r][c], mesh[r][c+1], K*1, 1f); new Spring(centers[r][c], mesh[r+1][c+1], K*1, 1f); new Spring(centers[r][c], mesh2[r][c], K*1, 1f); new Spring(centers[r][c], mesh2[r+1][c], K*1, 1f); new Spring(centers[r][c], mesh2[r][c+1], K*1, 1f); new Spring(centers[r][c], mesh2[r+1][c+1], K*1, 1f); //new Spring(mesh[0][r], mesh[numX-1][r], K*1, 0.1f); } } */ // structural II if (thick) { for (int r = 0; r < numX; r++) { for (int c = 0; c < numY; c++) { new Spring(mesh[r][c], mesh2[r][c], K * 1, 1f); } } } // shear for (int i = 0; i <= neighbors; i++) { for (int j = 0; j <= neighbors; j++) { for (int r = 0; r < numX; r++) { for (int c = 0; c < numY - j; c++) { if (i == 0 && j == 0) { continue; } //new Spring(mesh2[r][c], mesh2[r + 1][c + 1], K/1, 1); //new Spring(mesh2[r + 1][c], mesh2[r][c + 1], K/1, 1); if (r - i >= 0) { if (thick) { new Spring(mesh[r][c], mesh2[r - i][c + j], K * 1, 1); new Spring(mesh[r - i][c], mesh2[r][c + j], K * 1, 1); new Spring(mesh[r][c + j], mesh2[r - i][c], K * 1, 1); new Spring(mesh[r - i][c + j], mesh2[r][c], K * 1, 1); } else { new Spring(mesh[r][c], mesh[r - i][c + j], K / 1, 1); new Spring(mesh[r - i][c], mesh[r][c + j], K / 1, 1); } } if (r + i < numX) { if (thick) { new Spring(mesh[r][c], mesh2[r + i][c + j], K * 1, 1); new Spring(mesh[r + i][c], mesh2[r][c + j], K * 1, 1); new Spring(mesh[r][c + j], mesh2[r + i][c], K * 1, 1); new Spring(mesh[r + i][c + j], mesh2[r][c], K * 1, 1); } else { new Spring(mesh[r][c], mesh[r + i][c + j], K / 1, 1); new Spring(mesh[r + i][c], mesh[r][c + j], K / 1, 1); } } } } } } //connect handles //for (int r = 0; r < numX; r++) int r = numX - 1; { //new Spring(mesh[r][0], handles[r], K, 0.5f); //new Spring(mesh[r/*/10*/][0], handles[0*r/10], K, 1); //0.5f); //new Spring(mesh[(numX - 1) - r/*/10*/][0], handles[(numX - 1) - 0*r/10], K*1, 1); //0.5f); } } // serial lost void DrawNode0(iCameraPane display) { super.DrawNode(display, null, false); } void DrawNode/*notused*/(iCameraPane display, Object3D /*Composite*/ root, boolean selected) { // assert displaylist == -1; // if (!(live && display.LIVE && display.drawMode == CameraPane.DEFAULT)) // return; // if (live && display.LIVE && display.drawMode == display.DEFAULT) // { // //System.out.println("UPDATE"); // Phys.update(); //// Phys.update(); //// Phys.update(); //// Phys.update(); // } //new Exception().printStackTrace(); GL gl = display.GetGL0(); // getGL(); //gl.glDisable(GL.GL_LIGHTING); if (display.DrawMode() == display.SHADOW) { gl.glDisable(gl.GL_CULL_FACE); } for (int i = 0; i < 2; i++) { Node[][] mesh = this.mesh; if (i == 1) { if (!singlelayer && mesh2 != null) { mesh = this.mesh2; } else { continue; } } //System.out.println("MESH = " + mesh); for (int x = 1; x < numX - 1; x++) { for (int y = 1; y < numY - 1; y++) { a.set(mesh[x][y + 1].position); a.sub(mesh[x][y].position); b.set(mesh[x + 1][y].position); b.sub(mesh[x][y].position); mesh[x][y].normal.cross(a, b); mesh[x][y].normal.normalize(); a.set(mesh[x][y - 1].position); a.sub(mesh[x][y].position); b.set(mesh[x - 1][y].position); b.sub(mesh[x][y].position); temp.cross(a, b); temp.normalize(); mesh[x][y].normal.add(temp); a.set(mesh[x - 1][y].position); a.sub(mesh[x][y].position); b.set(mesh[x][y + 1].position); b.sub(mesh[x][y].position); temp.cross(a, b); temp.normalize(); mesh[x][y].normal.add(temp); a.set(mesh[x + 1][y].position); a.sub(mesh[x][y].position); b.set(mesh[x][y - 1].position); b.sub(mesh[x][y].position); temp.cross(a, b); temp.normalize(); mesh[x][y].normal.add(temp); mesh[x][y].normal.normalize(); } } for (int x = 0; x < numX; x++) { mesh[x][0].normal.set(mesh[x][1].normal); mesh[x][numY - 1].normal.set(mesh[x][numY - 2].normal); } for (int y = 0; y < numY; y++) { mesh[0][y].normal.set(mesh[1][y].normal); mesh[numX - 1][y].normal.set(mesh[numX - 2][y].normal); } //if (i==1) // continue; /**/ gl.glBegin(GL.GL_LINES); //for (int i=0; i timeout) { mesh[r][c].mass = M; } if (thick && !singlelayer && mesh2 != null) { gl.glVertex3f((float) mesh[r][c].position.x, (float) mesh[r][c].position.y, (float) mesh[r][c].position.z); gl.glVertex3f((float) mesh2[r][c].position.x, (float) mesh2[r][c].position.y, (float) mesh2[r][c].position.z); } } } /* for (int r = 0; r < numX-1; r++) { for (int c = 0; c < numY-1; c++) { gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh[r][c].position.x, mesh[r][c].position.y, mesh[r][c].position.z); gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh2[r][c].position.x, mesh2[r][c].position.y, mesh2[r][c].position.z); gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh[r+1][c].position.x, mesh[r+1][c].position.y, mesh[r+1][c].position.z); gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh2[r+1][c].position.x, mesh2[r+1][c].position.y, mesh2[r+1][c].position.z); gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh[r][c+1].position.x, mesh[r][c+1].position.y, mesh[r][c+1].position.z); gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh2[r][c+1].position.x, mesh2[r][c+1].position.y, mesh2[r][c+1].position.z); gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh[r+1][c+1].position.x, mesh[r+1][c+1].position.y, mesh[r+1][c+1].position.z); gl.glVertex3f(centers[r][c].position.x, centers[r][c].position.y, centers[r][c].position.z); gl.glVertex3f(mesh2[r+1][c+1].position.x, mesh2[r+1][c+1].position.y, mesh2[r+1][c+1].position.z); } } */ gl.glEnd(); /**/ //gl.glBegin(GL.GL_QUADS); Node n; for (int x = 1; x < numX; x++) { gl.glBegin(GL.GL_QUAD_STRIP); int y = 1; n = mesh[x][y - 1]; gl.glColor4f(n.color.r, n.color.g, n.color.b, n.color.a); gl.glNormal3f((float) n.normal.x, (float) n.normal.y, (float) n.normal.z); gl.glTexCoord2f((float) n.texcoord.x, (float) n.texcoord.y); gl.glVertex3f((float) n.position.x, (float) Math.max(n.position.y, THEFLOOR + distortion), (float) n.position.z); n = mesh[x - 1][y - 1]; gl.glColor4f(n.color.r, n.color.g, n.color.b, n.color.a); gl.glNormal3f((float) n.normal.x, (float) n.normal.y, (float) n.normal.z); gl.glTexCoord2f((float) n.texcoord.x, (float) n.texcoord.y); gl.glVertex3f((float) n.position.x, (float) Math.max(n.position.y, THEFLOOR + distortion), (float) n.position.z); for (y = 2; y < numY; y++) { n = mesh[x][y]; gl.glColor4f(n.color.r, n.color.g, n.color.b, n.color.a); gl.glNormal3f((float) n.normal.x, (float) n.normal.y, (float) n.normal.z); gl.glTexCoord2f((float) n.texcoord.x, (float) n.texcoord.y); gl.glVertex3f((float) n.position.x, (float) Math.max(n.position.y, THEFLOOR + distortion), (float) n.position.z); n = mesh[x - 1][y]; gl.glColor4f(n.color.r, n.color.g, n.color.b, n.color.a); gl.glNormal3f((float) n.normal.x, (float) n.normal.y, (float) n.normal.z); gl.glTexCoord2f((float) n.texcoord.x, (float) n.texcoord.y); gl.glVertex3f((float) n.position.x, (float) Math.max(n.position.y, THEFLOOR + distortion), (float) n.position.z); } gl.glEnd(); } } //gl.glEnd(); /**/ gl.glDisable(GL.GL_LIGHTING); gl.glColor3f(1, 1, 1); gl.glBegin(GL.GL_LINES); if (showsprings) { for (int s = 0; s < Phys.allSprings.size(); s++) { Spring spring = Phys.allSprings.get(s); gl.glVertex3f((float) spring.a.position.x, (float) spring.a.position.y, (float) spring.a.position.z); gl.glVertex3f((float) spring.b.position.x, (float) spring.b.position.y, (float) spring.b.position.z); } } gl.glEnd(); gl.glEnable(GL.GL_LIGHTING); /**/ if (display.BackFaceCullMode()) { gl.glEnable(gl.GL_CULL_FACE); } // aout 2013?? if (displaylist > 0) // != -1) // { // CameraPane.RemoveList(displaylist); // } // // displaylist = 0; // june 2013 -1; //System.out.println("DRAW " + display.drawMode); if (live && Globals.isLIVE() && display.DrawMode() == display.DEFAULT) { //System.out.println("UPDATE"); Phys.update(); // Phys.update(); // Phys.update(); // Phys.update(); } } Object3D pose = null; Object3D posegroup = null; int poseid = 0; double distanceclosest = 0; double maxrestlength = 0; class PhysicsController3D // implements java.io.Serializable { transient Point3D reference = new Point3D(); Vector allForces; Vector allNodes; Vector allHandles = new Vector(); Vector handles = new Vector(); Vector allSprings; cMatrix3x3 matrix = new cMatrix3x3(); // buffer cMatrix3x3 matrixT = new cMatrix3x3(); // buffer PhysicsController3D() { allForces = new Vector(8, 0); allNodes = new Vector(8, 0); allSprings = new Vector(8, 0); } void Reset() { for (int i = 0; i < allNodes.size(); i++) { allNodes.get(i).deltaV.set(zero); allNodes.get(i).lastDeltaV.set(zero); allNodes.get(i).velocity.set(zero); } } void update() { if (CameraPane.jitter == 0) // first frame of antialiasing { ResetHandles(); useN1 ^= true; framecount++; time++; double[][] toRoot = GlobalTransformInv(); // toParent matrix.matrix[0][0] = toRoot[0][0]; matrix.matrix[0][1] = toRoot[0][1]; matrix.matrix[0][2] = toRoot[0][2]; matrix.matrix[1][0] = toRoot[1][0]; matrix.matrix[1][1] = toRoot[1][1]; matrix.matrix[1][2] = toRoot[1][2]; matrix.matrix[2][0] = toRoot[2][0]; matrix.matrix[2][1] = toRoot[2][1]; matrix.matrix[2][2] = toRoot[2][2]; //matrixT.matrix[0][0] = toRoot[0][0]; //matrixT.matrix[1][0] = toRoot[0][1]; //matrixT.matrix[2][0] = toRoot[0][2]; //matrixT.matrix[0][1] = toRoot[1][0]; //matrixT.matrix[1][1] = toRoot[1][1]; //matrixT.matrix[2][1] = toRoot[1][2]; //matrixT.matrix[0][2] = toRoot[2][0]; //matrixT.matrix[1][2] = toRoot[2][1]; //matrixT.matrix[2][2] = toRoot[2][2]; for (int j = 0; j < allHandles.size(); j++) { Node handle = allHandles.get(j); handle.position.set(handles.get(j)); temp.set(handle.position); // System.out.println(reference); // temp.sub(reference); // matrix.Transform(temp); // temp.add(reference); handle.position.x = temp.x; // + toRoot[3][0]; handle.position.y = temp.y; // + toRoot[3][1]; handle.position.z = temp.z; // + toRoot[3][2]; } distanceclosest = Double.MAX_VALUE; for (int i = 0; i < allNodes.size(); i++) { temp.set(allNodes.get(i).position); temp.sub(Phys.reference); double distance = temp.length(); if (distance == 0) distance = 0; if (distanceclosest > distance) distanceclosest = distance; } maxrestlength = -Double.MAX_VALUE; for (int i = 0; i < allSprings.size(); i++) { double distance = allSprings.get(i).restLength; if (maxrestlength < distance) maxrestlength = distance; } for (int i = 0; i < allNodes.size(); i++) //for (int i = allNodes.size(); --i>=0;) { if (resetdelta) { allNodes.get(i).deltaV.set(zero); } allNodes.get(i).computeForce(allNodes.get(i).GetForces()); } for (int i = 0; i < allNodes.size(); i++) { DynamicNode d = allNodes.get(i); d.updateOther(); d.updateSpring(); // if (i == 0) // System.out.println("V = " + d.velocity); // if (CameraPane.CURRENTANTIALIAS > 0) // { // if (cachedamping != damping) // { // powdamping = Math.pow(damping,1.0/CameraPane.ACSIZE); // cachedamping = damping; // } // d.velocity.mul(powdamping); // } // else if (CameraPane.jitter == 0) { //System.err.println("Damping = " + damping); d.velocity.mul(damping); } } resetdelta = false; /**/ for (int j = 0; j < allNodes.size(); j++) { allNodes.get(j).computeForce(allForces); } for (int j = 0; j < allNodes.size(); j++) { allNodes.get(j).updateSpeed(); } } for (int j = 0; j < allNodes.size(); j++) { allNodes.get(j).updatePosition(); } /**/ if (CameraPane.jitter == 0) { for (int j = 0; j < allNodes.size(); j++) { allNodes.get(j).lastDeltaV.set(allNodes.get(j).deltaV); //allNodes[j].lastForce.set(allNodes[j].netForce); allNodes.get(j).computeNormal(); } } } void ResetClosestPoints() { for (int i = 0; i < allNodes.size(); i++) { DynamicNode dn = allNodes.get(i); dn.linked = false; dn.closestpoint = null; } } void SetPose(Object3D obj) { if (obj == null) { pose = null; posegroup = null; return; } if (obj == posegroup && IsPoseMesh()) { poseid += Math.random()*posegroup.size(); poseid %= posegroup.size(); } if (obj.size() == 0) // instanceof cSpring) { pose = obj; posegroup = null; } else { posegroup = obj; pose = posegroup.get(poseid); } } int posecount = 0; void ResetHandles() { if (pose == null || handles.size() == 0) return; double sn = 5; if (slowness != 0) sn = slowness; if (posegroup != null && posecount++ > sn*((CameraPane.AntialiasingEnabled())?CameraPane.ACSIZE:1)) { posecount = 0; SetPose(posegroup); } if (posegroup != null) { pose = posegroup.get(poseid); // for UI } if (//handles == null || pose == null || pose.transientrep == null) { pose.RevertMeshes(); } BoundaryRep usedrep = pose.transientrep; if (usedrep == null) usedrep = pose.bRep; if(handles.size() != usedrep.VertexCount()) { System.out.println("INCOMPATIBLE SIZES " + handles.size() + " VS " + usedrep.VertexCount()); System.out.println("this = " + name + " VS pose = " + pose); new Exception().printStackTrace(); return; } assert(handles.size() == usedrep.VertexCount()); Object3D keepparent = pose.parent; pose.parent = null; double[][] toRoot = pose.GlobalTransformInv(); pose.parent = keepparent; for (int i=0; i edges = new Vector(); Vector folds = new Vector(); void ClearSprings() { /**/ for (int i = 0; i < allNodes.size(); i++) { DynamicNode dn = allNodes.get(i); // for (int j = 0; j < dn.mySprings.size(); j++) // { // Spring f = dn.mySprings.get(j); // // dn.mySprings.remove(f); // j -= 1; // } for (int j = 0; j < dn.myForces.size(); j++) { Force f = dn.myForces.get(j); if (f instanceof Spring) { dn.myForces.remove(f); j -= 1; } } } /**/ allSprings.clear(); } // doesn't work? void InitUnfolds() // boolean clearsprings) { // if (clearsprings) // ClearSprings(); for (int i = 0; i < allNodes.size(); i++) { DynamicNode dn = allNodes.get(i); temp.set(zero); if (dn.springs == null || dn.springs.size() < 3) continue; for (int j = 0; j < dn.springs.size(); j++) { Spring s = dn.springs.get(j); DynamicNode other = s.GetOther(dn); temp2.set(other.position); temp.add(temp2); } temp.mul(1.0/dn.springs.size()); DynamicNode newnode = new DynamicNode(temp.x,temp.y,temp.z,M,0); addNode(newnode); for (int j = 0; j < dn.springs.size(); j++) { Spring s = dn.springs.get(j); DynamicNode other = s.GetOther(dn); temp.set(other.position); temp.sub(dn.position); temp2.set(other.position); temp2.sub(newnode.position); new Spring(newnode,other,K,temp.length()/temp2.length()); } new Spring(newnode,dn,1*K,0); } } void InitFolds(boolean unfold) //, boolean clearsprings) { edges.clear(); folds.clear(); for (int i = 0; i < allSprings.size(); i++) { Spring s = allSprings.get(i); DynamicNode first = null; DynamicNode second = null; boolean broken = false; for (int j = 0; j < s.a.mySprings.size(); j++) { Spring f1 = s.a.mySprings.get(j); // if (!(f1 instanceof Spring)) // continue; Spring s1 = (Spring) f1; if (s1.isHandle) // restLength == 0) continue; DynamicNode n1 = s1.GetOther(s.a); for (int k = 0; k < s.b.mySprings.size(); k++) { Spring f2 = s.b.mySprings.get(k); // if (!(f2 instanceof Spring)) // continue; Spring s2 = (Spring) f2; if (s2.isHandle) // s2.restLength == 0) continue; DynamicNode n2 = s2.GetOther(s.b); if (n1 == n2) { if (first == null) first = n1; else second = n1; //broken = true; break; } } //if (broken) // break; } if (second != null) { folds.add(s); edges.add(first); edges.add(second); } if (edges.size()%2 != 0) { new Exception().printStackTrace(); System.exit(0); } } // if (clearsprings) // ClearSprings(); for (int k=0; k len) { temp3.set(temp); mindist = len; } } assert(mindist > 0); /* DynamicNode midpoint = new DynamicNode(temp3.x,temp3.y,temp3.z,0,0); addNode(midpoint); new Spring(edges.get(k),midpoint, 1*K, 1); new Spring(edges.get(k+1),midpoint, 1*K, 1); new Spring(s.a,midpoint, 1*K, 1); new Spring(s.b,midpoint, 1*K, 1); temp2.set(a); temp2.sub(temp3); double len = temp2.length(); temp.set(a); temp2.set(b); double t = len/mindist; temp.mul(1-t); temp2.mul(t); temp.add(temp2); DynamicNode other = new DynamicNode(temp.x,temp.y,temp.z,0,0); addNode(other); temp2.set(temp); temp2.sub(a); if (temp2.length() > 0) new Spring(edges.get(k),other, 1*K, len/temp2.length()); temp2.set(temp); temp2.sub(b); if (temp2.length() > 0) new Spring(edges.get(k+1),other, 1*K, (mindist-len)/temp2.length()); temp2.set(temp3); temp2.sub(temp); if (temp2.length() > 0) new Spring(midpoint,other, 1*K, 0); */ temp2.set(a); temp2.sub(b); if (temp2.length() != 0) rest = mindist/temp2.length(); //rest = 1/rest; //assert(rest >= 1); } new Spring(edges.get(k), edges.get(k+1), 1*K, rest,0,true); } edges.clear(); folds.clear(); } void InitNormals() { int i = 0; for (int j = 0; j < allNodes.size(); j++) { allNodes.get(j).initNormalRotation(); // allNodes.get(j).DetectBoundary(); } } void addNode(DynamicNode N) { allNodes.add(N); } void addHandle(DynamicNode N) { allNodes.add(N); allHandles.add(N); handles.add(new cVector(N.position)); } void addForce(Force F) { allForces.add(F); } } class Node implements java.io.Serializable { /*Point3D*/ cVector position; // serial. castable to Vertex Point3D normal; // = new Point3D(); Point3D texcoord; // = new Point3D(); double mass; cColor color; Node(cVector pos) // , cVector norm) //, cVector texcoord) { position = pos; normal = new Point3D(); // norm.x, norm.y, norm.z); //normal.set(norm); //this.texcoord.set(texcoord); mass = 1; // not M; color = new cColor(1, 1, 1); } Node(double x, double y, double z) { this(x, y, z, 1); } Node(double x, double y, double z, double m) { position = new /*Point3D*/ cVector(x, y, z); normal = new Point3D(); texcoord = new Point3D(); if (m < 0) { texcoord.x = (float) (x / numY / 2); texcoord.y = (float) (z / numX / 2); mass = -m; } else { texcoord.x = (float) (x / numY / 2); texcoord.y = (float) (y / numX / 2); mass = m; } color = new cColor(1, 1, 1); // (float)Math.random(), (float)Math.random(), (float)Math.random()); } Vector GetForces() { return null; } void computeForce(Vector forces) { } void update(boolean damping) { } void addForce(Force F) { } } class DynamicNode extends Node { Point3D velocity; //double damping; Vector myForces; Vector mySprings; Point3D springForce; Point3D otherForce; Point3D externalForce; Point3D deltaV = new Point3D(); Point3D lastDeltaV = new Point3D(); transient cMatrix3x3 rotation = new cMatrix3x3(); transient cQuat quat = new cQuat(); transient Vector springs; // sorted //transient Spring first; //transient Spring second; transient cVector axis = new cVector(); transient Vector axis0 = new Vector(); //transient double rotangle; // Z of axis transient boolean reverse = false; transient boolean linked = false; transient Vertex closestpoint = null; //Point3D lastForce = new Point3D(); // serial DynamicNode(cVector pos) { super(pos); // if (counter++%10 == 0) // mass = 0; myForces = new Vector(4, 0); mySprings = new Vector(4, 0); springForce = new Point3D(); otherForce = new Point3D(); externalForce = new Point3D(); velocity = new Point3D(); // (0,-1,0); } DynamicNode(double x, double y, double z, double m, double d) { super(x, y, z, m); myForces = new Vector(4, 0); mySprings = new Vector(4, 0); springForce = new Point3D(); otherForce = new Point3D(); externalForce = new Point3D(); velocity = new Point3D(); //0,m==-Float.MAX_VALUE?0:-0.1,0); // damping = d; } Vector GetForces() { return myForces; } void addForce(Force F) { myForces.add(F); } void addSpring(Spring F) { myForces.add(F); mySprings.add(F); } void computeForce(Vector forces) { //System.out.println("compute = " + this); springForce.x = springForce.y = springForce.z = 0; // ?? otherForce.x = otherForce.y = otherForce.z = 0; externalForce.x = externalForce.y = externalForce.z = 0; //if (CameraPane.jitter > 0) // return; // continue at constant speed for (int i = forces.size(); --i >= 0;) { Force f = forces.get(i); if (f instanceof Collision) { externalForce.add(f.forceOn(this)); } else { if (true) // f instanceof Spring && ((Spring)f).a.mass != 0 && ((Spring)f).b.mass != 0) { springForce.add(f.forceOn(this)); } else { otherForce.add(f.forceOn(this)); } } } if (Double.isNaN(springForce.y)) { springForce.x = springForce.y = springForce.z = 0; } } void DetectBoundary() { Spring first = null; Spring second = null; double suma = 0; if (springs != null && springs.size() > 2) { for (int i=0; i Math.PI*0.75) { mass = 0; return; } suma += angle; } if (suma < 1.25 * Math.PI) // BOUNDARY mass = 0; } else mass = 0; } void FullNormal() { temp2.set(zero); for (int i = mySprings.size(); --i >= 0;) { Spring f = mySprings.get(i); //if (f instanceof Spring) { Spring s = (Spring) f; a.set(s.GetOther(this).position); a.sub(position); if (a.length2() == 0) continue; a.normalize(); for (int j = mySprings.size(); --j >= 0;) { if (j == i) continue; Force f2 = mySprings.get(j); if (f2 instanceof Spring) { Spring s2 = (Spring) f2; b.set(s2.GetOther(this).position); b.sub(position); if (b.length2() == 0) continue; b.normalize(); dir.cross(a, b); // dir.normalize(); if (dir.dot(normal) < 0) dir.mul(-1); temp2.add(dir); } } } } normal.set(temp2); normal.normalize(); } void computeNormal() { if (mySprings.size() <= 1 || springs == null || springs.size() <= 2) return; /* Spring f = springs.get(springs.size()-1); Spring l = springs.get(0); temp.set(f.GetOther(this).position); temp.sub(position); temp.normalize(); a.set(l.GetOther(this).position); a.sub(position); temp2.cross(temp, a); temp2.normalize(); */ temp3.set(zero); //if (temp2.dot(normal) < 0 || springs.size() < 4) // mass = Float.MAX_VALUE; //else if (springs.size() > 1) for (int i=0; i 0) normal.set(temp3); normal.normalize(); // Phys.matrix.Transform(normal); if (position instanceof Vertex && ((Vertex)position).norm != null) ((Vertex)position).norm.set(normal.x,normal.y,normal.z); } void initNormalRotation() { axis0.clear(); if (mySprings.size() <= 1) return; Spring first = null; Spring second = null; for (int i = mySprings.size(); --i >= 0;) { Force f = mySprings.get(i); // if (!(f instanceof Spring)) // continue; first = (Spring) f; temp.set(first.GetOther(this).position); temp.sub(position); // if (temp.length2() == 0) if (first.isHandle) // first.restLength == 0) continue; temp.normalize(); break; } if (first == null) return; Spring veryfirst = first; springs = new Vector(); while (second != veryfirst) { // if (springs.indexOf(first) == 0) // loop done // break; double dot; dot = normal.dot(temp); dir.set(normal); dir.mul(dot); temp.sub(dir); temp.normalize(); Spring best = null; double maxcos = -1; double minang = 10; for (int j = mySprings.size(); --j >= 0;) { Spring f2 = mySprings.get(j); if (f2 == first) continue; // if (!(f2 instanceof Spring)) // continue; Spring s2 = (Spring) f2; if (s2.isHandle) // s2.restLength == 0) continue; a.set(s2.GetOther(this).position); a.sub(position); // a.normalize(); dot = normal.dot(a); dir.set(normal); dir.mul(dot); a.sub(dir); a.normalize(); b.cross(temp, a); // b.normalize(); double sin = normal.dot(b); /* if (sin <= 0) continue; */ /** if (maxsin > dot) continue; maxsin = dot; /**/ dot = /*Math.abs*/(temp.dot(a)); double angle = Math.atan2(sin,dot); if (angle < 0) angle += 2*Math.PI; if (minang < angle) continue; minang = angle; /* if (maxcos > dot) continue; maxcos = dot; /**/ best = s2; } // if (maxcos == -1) // return; if (minang == 10) { System.out.println("NONE!!"); return; } if (minang > Math.PI*5/6) { // System.out.println("BOUNDARY!"); // break; } second = best; a.set(first.GetOther(this).position); a.sub(position); a.normalize(); temp.set(second.GetOther(this).position); temp.sub(position); temp.normalize(); dir.cross(a, temp); dir.normalize(); if (springs.contains(first)) // size() > 100) { System.out.println("LOOP!!"); return; } springs.add(first); //springs.add(second); first = second; /* if (first == null) return; if (true) // Full normal { temp3.set(normal); // real normal.set(dir); // FullNormal(); dir.set(normal); normal.set(temp3); } */ b.cross(dir, a); // temp); temp2.cross(dir, normal); temp2.normalize(); Point3D a0 = new Point3D(); a0.x = (float) temp2.dot(a); a0.y = (float) temp2.dot(b); a0.z = 0; // == a.dot(dir); axis0.add(a0); dot = dir.dot(normal); /* if (false) // dot < 0) { reverse = true; dot = -dot; axis0.x = -axis0.x; axis0.y = -axis0.y; } */ //rotangle a0.z = (float) Math.acos(dot); //rotation = new cMatrix3x3(dir, normal); } } void updatePosition() { double factor = timestep; // 1; // factor *= factor; // may 2014 if (factor == 0) factor = 1; if (CameraPane.AntialiasingEnabled()) factor /= CameraPane.ACSIZE; position.x += velocity.x*H0 * factor; position.y += velocity.y*H0 * factor; position.z += velocity.z*H0 * factor; } void updateOther() { double factor = timestep; // 1; //if (factor == 0) factor = 1; // if (CameraPane.AntialiasingEnabled()) // factor /= CameraPane.ACSIZE; deltaV.x = otherForce.x * H0 * factor; deltaV.y = otherForce.y * H0 * factor; deltaV.z = otherForce.z * H0 * factor; velocity.x += deltaV.x; velocity.y += deltaV.y; velocity.z += deltaV.z; factor = timestep; // 1; // factor *= factor; // may 2014 position.x += velocity.x*H0 * factor; position.y += velocity.y*H0 * factor; position.z += velocity.z*H0 * factor; } void updateSpeed() { double factor = timestep; // 1; //if (factor == 0) factor = 1; // if (CameraPane.AntialiasingEnabled()) // factor /= CameraPane.ACSIZE; position.x -= velocity.x * H0 * factor; position.y -= velocity.y * H0 * factor; position.z -= velocity.z * H0 * factor; /* temp.set(velocity); temp.sub(deltaV); velocity.y = -velocity.y; */ velocity.set(externalForce); //position.add(velocity); position.x += velocity.x * H0 * factor; position.y += velocity.y * H0 * factor; position.z += velocity.z * H0 * factor; // COLLISION if (/*velocity.y == 0 &&*/position.y < THEFLOOR) { position.y = THEFLOOR; } //velocity.y = 0; // new /* deltaV.y = -deltaV.y; internalForce.set(deltaV); internalForce.mul(mass); */ //internalForce.set(zero); //deltaV.set(velocity); //deltaV.sub(temp); //deltaV.set(zero); deltaV.x = deltaV.y = deltaV.z = 0; } void updateSpring() { if (!IsUpdateHandles() && mass == 0) return; //System.out.println("update = " + this); /* if (dodamping) { // Damping double damp = damping; //double damp = (double) (2*Math.sqrt(mass*K)); double vl = velocity.length(); if (false) // vl > 0) { temp.set(velocity); temp.mul(mass); temp.add(netForce); damp = temp.length() / vl; } netForce.x -= damp * velocity.x; netForce.y -= damp * velocity.y; netForce.z -= damp * velocity.z; } */ double KH0H0 = (K+solidity) * H0 * H0; if (true) // implicit) { //deltaV.set(internalForce); //deltaV.mul(H); deltaV.x = springForce.x * H0; deltaV.y = springForce.y * H0; deltaV.z = springForce.z * H0; double n = 0; for (int i = myForces.size(); --i >= 0;) { Force f = myForces.get(i); if (!(f instanceof Spring)) { continue; } Spring s = (Spring) f; DynamicNode b = s.GetOther(this); if (b.mass == Float.MAX_VALUE) continue; // if (b.mass == 0) // continue; // if (s.nbcopies == 1) // s.nbcopies += 0; // if (s.nbcopies == 100) // s.nbcopies += 0; n += s.nbcopies; double bl = b.springForce.length2(); if (bl > 0) { /* temp.set(b.lastDeltaV); double dv = temp.length2(); temp.set(b.internalForce); temp.mul(K * H * H * (double) Math.sqrt(dv / bl)); deltaV.add(temp); */ double k = KH0H0 * (double) Math.sqrt(b.lastDeltaV.length2() / bl); deltaV.x += k * b.springForce.x; deltaV.y += k * b.springForce.y; deltaV.z += k * b.springForce.z; } } //assert (n == myForces.length); if (n != 0) // n = 1; // mechante patch { //deltaV.mul(1 / (mass + K * H * H * n)); double k = 1 / (mass + KH0H0 * n); deltaV.x *= k; deltaV.y *= k; deltaV.z *= k; } // NEW NEW // deltaV.mul(damping); // if (CameraPane.CURRENTANTIALIAS > 0) // deltaV.mul(1.0/CameraPane.ACSIZE); //temp.set(velocity); //temp.add(deltaV); //temp.mul(-(1 - 1/(1+damping*velocity.length2()))); //velocity.add(temp); //velocity.add(deltaV); velocity.x += deltaV.x; velocity.y += deltaV.y; velocity.z += deltaV.z; //temp.set(velocity); //temp.mul(H); //position.add(temp); // position.x += velocity.x*H0/CameraPane.ACSIZE; // position.y += velocity.y*H0/CameraPane.ACSIZE; // position.z += velocity.z*H0/CameraPane.ACSIZE; // NEW //System.out.println("damp = " + Math.exp(-damping)); //System.out.println("DAMPING = " + damping); // velocity.mul(damping); // //internalForce.set(zero); } else { // Collision if (true) // externalForce.length2() > 0) { //assert false; //System.out.println("COLLISION = " + externalForce); //position.sub(velocity); position.x -= velocity.x * H0; position.y -= velocity.y * H0; position.z -= velocity.z * H0; /* temp.set(velocity); temp.sub(deltaV); velocity.y = -velocity.y; */ velocity.set(externalForce); //position.add(velocity); position.x += velocity.x * H0; position.y += velocity.y * H0; position.z += velocity.z * H0; // COLLISION if (/*velocity.y == 0 &&*/position.y < THEFLOOR) { position.y = THEFLOOR; } //velocity.y = 0; // new /* deltaV.y = -deltaV.y; internalForce.set(deltaV); internalForce.mul(mass); */ //internalForce.set(zero); //deltaV.set(velocity); //deltaV.sub(temp); //deltaV.set(zero); deltaV.x = deltaV.y = deltaV.z = 0; } } // internalForce.x = internalForce.y = internalForce.z = 0; //velocity.x *= damping; //velocity.y *= damping; //velocity.z *= damping; //velocity.set(zero); //if (!dodamping) /* double force = netForce.length(); System.out.print("magnitude = " + force + "; FORCE = " + netForce); netForce.mul((double)(Math.atan(force*force*force)/(Math.PI/2))); System.out.println("; FORCE = " + netForce); velocity.sub(netForce); */ //System.out.println(" ---> " + this); } public String toString() { return "P = " + position.toString() + "; V = " + velocity.toString() + "; F = " + springForce.toString(); } } static Point3D temp = new Point3D(); static Point3D temp2 = new Point3D(); static Point3D temp3 = new Point3D(); static class Point3D implements java.io.Serializable { static final long serialVersionUID = 5950846180423399081L; double x, y, z; Point3D() { x = 0; y = 0; z = 0; } Point3D(float u, float v, float w) { set(u,v,w); } void set(float u, float v, float w) { x = u; y = v; z = w; } void set(Point3D p) { x = p.x; y = p.y; z = p.z; } void set(cVector p) { x = (float)p.x; y = (float)p.y; z = (float)p.z; } void add(Point3D p) { x += p.x; y += p.y; z += p.z; } void add(cVector p) { x += p.x; y += p.y; z += p.z; } void sub(Point3D p) { x -= p.x; y -= p.y; z -= p.z; } void sub(cVector p) { x -= p.x; y -= p.y; z -= p.z; } double dot(Point3D p) { return x * p.x + y * p.y + z * p.z; } double dot(double u, double v, double w) { return x * u + y * v + z * w; } void mul(double f) { x *= f; y *= f; z *= f; } void normalize() { double l = length2(); if (l == 0) return; if (l == 1) return; l = Math.sqrt(l); x /= l; y /= l; z /= l; } void cross(Point3D a, Point3D b) { double x = a.y * b.z - a.z * b.y; double y = a.z * b.x - a.x * b.z; double z = a.x * b.y - a.y * b.x; this.x = x; this.y = y; this.z = z; } double length() { return (double) Math.sqrt(length2()); } double length2() { return x * x + y * y + z * z; } public String toString() { return "[" + x + ", " + y + ", " + z + "]"; } } abstract class Force implements java.io.Serializable { abstract Point3D forceOn(DynamicNode N); } Point3D force = new Point3D(); Point3D dir = new Point3D(); static cVector vect1 = new cVector(); static cVector vect2 = new cVector(); static cVector vect3 = new cVector(); static cVector vect4 = new cVector(); cSpring This() { return this; } Object3D avoider; void ResetGlobalTransform() { // if (avoider instanceof cMesh && ((cMesh)avoider).live) // toRoot = null; // else toRoot = avoider.GlobalTransform(); } transient double[][] toRoot; // = new double[4][4]; Vertex ClosestPoint(Vector collider, DynamicNode N, int startindex, int endindex, int sortaxis) { if (startindex == endindex) return null; if (startindex+1 == endindex) return collider.get(startindex); // log N: /* int mid = (startindex + endindex)/2; Vertex ref = sortedcollider.get(mid); boolean test = false; switch (sortaxis) { case 0: test = N.position.x < ref.x; break; case 1: test = N.position.y < ref.y; break; case 2: test = N.position.z < ref.z; break; } sortaxis += 1; sortaxis %= 3; if (test) { Vertex cp1 = ClosestPoint(sortedcollider, N,startindex,mid,sortaxis); temp.set(N.position); temp.sub(cp1); temp2.set(N.position); temp2.sub(ref); if (temp.length2() > temp2.length2()) { Vertex cp2 = ClosestPoint(sortedcollider, N,mid,endindex,sortaxis); temp2.set(N.position); temp2.sub(cp2); if (temp.length2() < temp2.length2()) { return cp1; } else { return cp2; } } else { return cp1; } } else { Vertex cp2 = ClosestPoint(sortedcollider, N,mid,endindex,sortaxis); temp.set(N.position); temp.sub(cp2); temp2.set(N.position); temp2.sub(ref); if (temp.length2() > temp2.length2()) { Vertex cp1 = ClosestPoint(sortedcollider, N,startindex,mid,sortaxis); temp2.set(N.position); temp2.sub(cp1); if (temp.length2() < temp2.length2()) { return cp2; } else { return cp1; } } else { return cp2; } } */ // N^2 double mindist2 = Double.MAX_VALUE; Vertex cp = null; for (int i=collider.size(); --i>=0;) { // Why? 3 dec 2018 if (collider.get(i).norm.dot(((Vertex)N.position).norm) < 0.5) continue; temp.set(N.position); vect1.set(collider.get(i)); LA.xformPos(vect1,toRoot,vect1); //avoider.TransformToWorld(vect1, vect1); temp.sub(vect1); if (mindist2 > temp.length2()) { mindist2 = temp.length2(); cp = collider.get(i); } } return mindist2 < 1 ? cp : null; } class Avoider extends Force { static final long serialVersionUID = -8657094699711594990L; Avoider() { } Avoider(Object3D col) { SetAvoider(col); } void Avoidance(DynamicNode N) { temp.set(N.position); if (avoider != This()) { temp2.set(N.closestpoint.norm); temp2.mul(0.001); temp.sub(temp2); // push outside because of mesh artifacts } vect1.set(N.closestpoint); LA.xformPos(vect1,toRoot,vect1); //avoider.TransformToWorld(vect1, vect1); temp.sub(vect1); double distance = Math.sqrt(temp.length2()); if (distance < 0.01) { temp2.set(N.closestpoint.norm); double dot = temp2.dot(temp); if (dot > 0) dot = 0; // normal pushing temp.set(N.closestpoint.norm); if (IsAutoFreeze()) dot = -dot; temp.mul(normalpush/*/distance*/*-dot/Math.sqrt(distance)); force.add(temp); } } void Attraction(DynamicNode N) { temp.set(N.position); if (avoider != This()) { temp2.set(N.closestpoint.norm); temp2.mul(0.001); temp.sub(temp2); // push outside because of mesh artifacts } vect1.set(N.closestpoint); LA.xformPos(vect1,toRoot,vect1); //avoider.TransformToWorld(vect1, vect1); temp.sub(vect1); double distance = Math.sqrt(temp.length2()); //if (distance < 0.01) { temp2.set(N.closestpoint.norm); double dot = temp2.dot(temp); // if (dot > 0) // dot = 0; // normal pushing temp.set(N.closestpoint.norm); // if (IsAutoFreeze()) // dot = -dot; temp.mul(normalpush/*/distance*/ * -dot * distance); force.add(temp); } } void SetParameter(int index, double value) { parameters.setElementAt(new Double(value), index); } void SetAvoider(Object3D col) { avoider = col; } //Vector sortedcollider; Vector parameters = new Vector(); // serial issue Point3D forceOn(DynamicNode N) { force.x = 0; force.y = 0; force.z = 0; if (avoider.transientrep == null) avoider.Revert(); if (avoider.transientrep == null || avoider.transientrep.VertexCount() == 0 || avoider.transientrep.trimmed) return force; ResetGlobalTransform(); if (!N.linked) { //avoider.bRep.GetVertex(0); // "sort" ResetGlobalTransform(); N.closestpoint = ClosestPoint(avoider.transientrep.vertices, N, 0,avoider.transientrep.vertices.size(), 0); N.linked = true; } if (avoider == This()) { // good but must freeze the order first... not really... // if (cp.index < ((Vertex)N.position).index) // return force; } if (normalpush != 0) // && cp == null /*???*/) // speed == 0) { if (N.closestpoint == null) return force; //Avoidance(N); Attraction(N); } if (parameters.size() > 0) force.mul(parameters.get(0).doubleValue()); return force; } public String toString() { return avoider.toString(); } } class ActingForces extends Wind // Serialization issue { static final long serialVersionUID = -7125529831578437864L; Vector forces = new Vector(); // external forces (not entangled) transient Point3D totalforce = new Point3D(); ActingForces() { super(10f, 0.f, 1); } Point3D forceOn(DynamicNode N) { if (totalforce == null) totalforce = new Point3D(); totalforce.set(0,0,0); if (forces.size() == 0) totalforce.set(super.forceOn(N)); for (int i=forces.size(); --i>=0;) { totalforce.add(forces.get(i).forceOn(N)); } force.set(totalforce); return force; } void AddForce(Force f) { forces.add(f); } void RemoveForce(Force f) { forces.remove(f); } public String toString() { return forces.toString(); } } class Wind extends Force { static final long serialVersionUID = -1275614874116975270L; double wind; double speed; double lift; Wind() { // Serialization issues } void AddForce(Force f) { assert(false); } void RemoveForce(Force f) { assert(false); } ///// Wind(double viscosity, double velocity, double lift) { wind = viscosity; speed = velocity; this.lift = lift; } Point3D forceOn(DynamicNode N) { force.x = 0; force.y = 0; force.z = 0; if (normalpush != 0) // speed == 0) // Now normal force { // temp.set(N.position); // temp.sub(Phys.reference); double distance = 1; // temp.length2(); // normal pushing temp.set(N.normal); temp.mul(normalpush/distance); force.add(temp); } if (false) // wind == 0) { //force.set(zero); force.set(N.velocity); force.mul(-Math.exp(-1 / damping)); return force; } double mass = N.mass; if (mass == Float.MAX_VALUE || mass == 0) { return force; } else { // mass = M; } // ??? /* balloon */ if (wind == 0 && speed != 0) { temp.set(N.position); temp.sub(Phys.reference); double distance = temp.length(); temp.x /= distance; temp.y /= distance; temp.z /= distance; // distance -= distanceclosest; double factor = speed; temp2.set(N.normal); temp3.set(N.velocity); // if (false) // Math.abs(temp2.dot(temp)) > 0.5) // distance != 0) // { // //distance = 1000; // factor = 0; // } // else // { // temp2.set(temp); // //distance = 0; // return force; // distance *= distance; // distance *= distance; // distance *= distance; // } factor /= (distance+1); // solidity); // /distance; // *distance; if (IsAutoFreeze()) // BLOW ? { // blow double dot = temp2.dot(temp); if (dot < 0) { dot = 0; // "assert" } temp.mul(dot); force.x += temp.x*factor; force.y += temp.y*factor; force.z += temp.z*factor; } else { double dot = temp2.dot(temp); //double dot2 = temp3.dot(temp); //if (dot < 0) // dot = 0; //temp2.mul(dot*(1-dot)/2); //temp.add(N2.normal); //temp.normalize(); double weight = 1; // dot*(1-dot)/2; // Math.exp(-dot2); // -dot); if (false) // N.springs != null && N.springs.size() > 0) { Spring first = N.springs.get(0); a.set(first.a.position); b.set(first.b.position); a.sub(b); double deform = Math.abs(a.length()/first.restLength) - 1; if (deform > 0) weight *= Math.exp(-deform); } //if (weight > 0) // weight = -weight; if (dot < -0.2) { //weight *= -(1 + dot); // balloon weight *= -(1 - Math.sqrt(-dot)); temp2.mul(weight); } else { //temp2.set(temp); weight *= 1; // - dot; temp2.mul(weight); } force.x += temp2.x*factor; force.y += temp2.y*factor; force.z += temp2.z*factor; } // return force; } if (wind == 0) return force; temp.set(N.velocity); double s = speed; //System.out.println("Speed = " + speed); /* if ((time%100) == (framecount%100)) s *= //Math.cos(time/123.0 + framecount*154); // 2; // Math.random()-0.5; */ /* double push = force.dot(N.normal); if (push != 0) push /= force.length(); push = 1; // - push; //temp.set(N.normal); temp.set(N.position); temp.sub(Phys.reference); temp.normalize(); temp.mul(push*s); */ // force.set(temp); //// force.sub(temp); // temp.x -= s; // may 2014 temp.y -= s; // may 2014 temp.z -= s; // //force.y -= s; boolean wasnull = false; if (N.normal.length2() == 0) { //System.out.println("was null = " + wasnull); wasnull = true; N.normal.set(temp); N.normal.mul(-1); if (N.normal.length2() != 0) { N.normal.normalize(); } //a.set(zero); } else { // lift a.cross(temp, N.normal); } // drag //a.set(N.normal); //b.cross(N.normal, a); double factor = 0; double fdotN = /*-chien?*/temp.dot(N.normal); // -force.length() double f = temp.length(); if (f > 0) { factor = Math.abs(fdotN / f); } if (f > 1) { factor = 1; } // speed^2 / 2 //f = f*f/2; // drag // temp.set(N.normal); // test temp.mul(-mass * wind * fdotN); // factor); //force.mul(fdotN<0?1:-1); if (!wasnull && a.length2() > 0) // && force.dot(force) > 0)// && fdotN < 0) { //System.out.println("A = " + a); a.normalize(); //b.mul(1 - 4*(factor-0.5)*(factor-0.5)); //a.mul(Math.sin(Math.acos(factor)*2)); a.mul(Sinacos(factor)); //a.mul(1 - factor); //a.mul(Math.sqrt(1 - factor*factor)); //System.out.println("--> F = " + factor); //System.out.println("--> A = " + a); a.mul(lift * wind * mass * f); a.mul(fdotN < 0 ? -1 : 1); //if (Math.random() > 0.5) // a.mul(-1); //temp.set(force); //temp.mul(-b.dot(temp)/temp.length()); //b.sub(temp); temp.add(a); } if (wasnull) { N.normal.set(zero); } force.add(temp); return force; } } static int TABLESAC = 1024; static double[] tablesac = new double[TABLESAC]; static { for (int i = 0; i < TABLESAC; i++) { tablesac[i] = -1; } } static double Sinacos(double factor) { if (factor > 1) { // System.out.println("factor = " + factor); factor = 1; } int index = (int) (factor * (TABLESAC - 1)); if (tablesac[index] == -1) { tablesac[index] = Math.sin(Math.acos(factor) * 2); assert tablesac[index] != -1; } return tablesac[index]; } class Collision extends Force { double floor; // not used Collision(double a) { // floor = a; } Point3D forceOn(DynamicNode N) { force.set(N.velocity); // global if (N.position.y < THEFLOOR && N.velocity.y < 0) { //System.out.print("Y = " + N.position.y); //System.out.println("; VY = " + N.velocity.y); // force == new velocity force.x *= 1 - friction; force.y = 0; // doesn't really work... (float) (Math.abs(-N.velocity.y) * elastic); //force.y = floor - N.position.y; force.z *= 1 - friction; } //else // ??? // force.set(zero); // local //force.y = ((N.position.y < floor)&&(N.velocity.y<0))?-(2*N.velocity.y)*mass:0; //if(force.y != 0) // System.out.println("POS = " + N.position); if (time % 100 == 0 && time < 300) { //N.position.y += Math.random(); //System.out.println("POS = " + N.position); } return force; } } class Gravity extends Force { public double acceleration; Gravity(double a) { acceleration = a; } Point3D forceOn(DynamicNode N) { double mass = N.mass; if (mass == Float.MAX_VALUE) { mass = 0; } else { // mass = M; } // ??? if (avoider != null) { if (avoider.transientrep == null) avoider.Revert(); if (avoider.transientrep == null || avoider.transientrep.VertexCount() == 0 || avoider.transientrep.trimmed) return force; ResetGlobalTransform(); if (!N.linked) { //avoider.bRep.GetVertex(0); // "sort" //ResetGlobalTransform(); N.closestpoint = ClosestPoint(avoider.transientrep.vertices, N, 0,avoider.transientrep.vertices.size(), 0); N.linked = true; } if (N.closestpoint != null) { temp.set(N.position); vect1.set(N.closestpoint); LA.xformPos(vect1,toRoot,vect1); temp.sub(vect1); temp2.set(N.closestpoint.norm); double dot = temp2.dot(temp); if (dot < 0) mass = Float.NaN; } } force.x = 0; force.y = (float) (-acceleration * mass); force.z = 0; // -acceleration * mass * 1000 * Math.cos(time/234.0 + framecount*100); // (Math.random()*2 - 1); // return force; } } static boolean useN1; class Spring extends Force { double restLength; //double stiffness; // watch serial DynamicNode a, b; int nbcopies; float deform; boolean isHandle; Spring(DynamicNode n1, DynamicNode n2, double k, double l) { this(n1,n2,k,l,0, false); } Spring(DynamicNode n1, DynamicNode n2, double k, double l, float deformation, boolean handle) { a = n1; b = n2; if (n1.mass != Float.MAX_VALUE) { if (handle) n1.addForce(this); else n1.addSpring(this); } if (n2.mass != Float.MAX_VALUE) { if (handle) n2.addForce(this); else n2.addSpring(this); } //stiffness = k; temp.set(n2.position); temp.sub(n1.position); restLength = 1 * temp.length(); nbcopies = (int) Math.floor(k); // /K); Phys.allSprings.add(this); deform = deformation; isHandle = handle; } DynamicNode GetOther(DynamicNode N) { if (N == a) { return b; } else { return a; } } Point3D forceOn(DynamicNode N1) { force.x = 0; force.y = 0; force.z = 0; DynamicNode N2 = a; //useN1 ^= true; // useless if (N1 == a) { // if (useN1) N2 = b; // else // return force; } // else // if (useN1) // return force; double dx = N2.position.x - N1.position.x; double dy = N2.position.y - N1.position.y; double dz = N2.position.z - N1.position.z; if (false) // N2.mass != 0) { double dot = N1.normal.x * dx + N1.normal.y * dy + N1.normal.z * dz; dx -= dot*N1.normal.x; dy -= dot*N1.normal.y; dz -= dot*N1.normal.z; } double displacement = (double) Math.sqrt(dx*dx + dy*dy + dz*dz); if (N2.color.a == 0) { return force; } if (displacement == 0) // .00001) { //Yeesh... this is tricky... return force; } //assert(stiffness <= 1); double rlf = restlengthFactor; if (isHandle) rlf = 1; double magnitude = // /*N1.color.a * N2.color.a * */ 1 / (1 /*+ damping*/) * /*-*/(displacement - rlf*restLength); // Math.pow(restLength,elastic)); // WATCH OUT magnitude /= displacement; /** if ( //N1.damping == 0 && !isHandle && // N2.mass != 0 && magnitude < 0) magnitude = 0; /**/ if (nbcopies == 1) nbcopies += 0; if (nbcopies == 100) nbcopies += 0; if (false) // id > 0) { //if (magnitude < 0) // magnitude = 0; /**/ dx /= displacement; dy /= displacement; dz /= displacement; displacement /= restLength; int sign = 1; if (displacement < 1) { displacement = 1 / displacement; sign = -1; } displacement -= 1; magnitude = sign * K * (double) Math.pow(displacement, id); /**/ } if (N1.color.a != 0 && // Math.abs(magnitude) > limit) // || Math.abs(magnitude /* * displacement */) > limit) { //System.out.println("BREAK: " + magnitude + "; displacement = " + displacement + "; dx = " + dx + "; dy = " + dy + "; dz = " + dz); magnitude /= Math.abs(magnitude); magnitude *= limit; N1.color.a = 0; N2.color.a = 0; } else { //N1.color.a = 1; //N2.color.a = 1; } //if (magnitude > 0) // magnitude /= 10; double damp = 0; magnitude *= nbcopies; //if (IsNormalize()) // magnitude /= Math.sqrt(displacement); if (isHandle) { // double factor = 1; //if (CameraPane.CURRENTANTIALIAS > 0) // factor = 1.0/CameraPane.ACSIZE; magnitude /= //displacement * distortion; Math.pow(displacement, distortion); // * factor; } if (false) // isHandle) { double K = Math.exp(-displacement*normalpush); magnitude /= (displacement*(1-K) + K); } // if (magnitude > 0) // magnitude = Math.sqrt(magnitude); // else // magnitude = -Math.sqrt(-magnitude); if (N2.mass == Float.MAX_VALUE) { new Exception().printStackTrace(); System.exit(0); magnitude *= solidity; // * K; /** damp = 2*Math.sqrt(N1.mass*magnitude/displacement); double V = N1.velocity.dot(dx,dy,dz)/displacement; if (V != 0) { double limitdamp = Math.abs((V*N1.mass/H + magnitude)/V); if (damp < limitdamp) damp = limitdamp; } /**/ if (magnitude > 1/(H0*H0)) magnitude = 1/(H0*H0); } else { if (isHandle) // N2.mass == 0) { // rest length == 0 //System.err.println("solidity = " + solidity); magnitude *= solidity; //if (N1.velocity.dot(dx,dy,dz) < 0) // magnitude /= displacement; //if (magnitude > displacement) // magnitude = displacement; } else magnitude *= K; } // test squared // magnitude *= displacement * magnitude / K; // magnitude *= displacement * magnitude / K; force.x = (float) (dx * magnitude - damp*N1.velocity.x); force.y = (float) (dy * magnitude - damp*N1.velocity.y); force.z = (float) (dz * magnitude - damp*N1.velocity.z); // reduce oscillations... but unstable due to normals /** if (!isHandle) // N2.mass != 0) { temp.set(N1.normal); //temp.add(N2.normal); //temp.normalize(); double dot = force.dot(temp); // /2; force.x -= dot * temp.x; force.y -= dot * temp.y; force.z -= dot * temp.z; } /**/ /* temp.set(N2.velocity); temp.sub(N1.velocity); temp.mul(K); force.add(temp); */ if (magnitude > 0) // ok { restLength = deform*displacement + (1 - deform)*restLength; // double permanent = 0; // // if (restLength < maxrestlength/2) // { // permanent = 0; // Math.pow(restLength/maxrestlength,6); // restLength = (1-permanent)*displacement + permanent*restLength; // } // else // { // permanent = (restLength - maxrestlength/2)/(maxrestlength/2); // restLength = permanent*maxrestlength/2 + (1 - permanent)*restLength; // } } return force; } /* void draw() { beginShape(LINES); vertex(a.position.x, a.position.y, a.position.z); vertex(b.position.x, b.position.y, b.position.z); endShape(); } */ } /* class Fold extends Force { double restAngle; DynamicNode a, b, c; Fold(DynamicNode n1, DynamicNode n2, DynamicNode n3) { a = n1; b = n2; c = n3; n1.addForce(this); n2.addForce(this); n3.addForce(this); double dx = n2.position.x - n1.position.x; //double dy = N2.position.y - N1.position.y; double dz = n2.position.z - n1.position.z; restAngle = (double) Math.sqrt(dx * dx + dz * dz); } Point3D forceOn(DynamicNode N1) { DynamicNode N2 = a; if (N1 == N2) { N2 = b; } double dx = N2.position.x - N1.position.x; //double dy = N2.position.y - N1.position.y; double dz = N2.position.z - N1.position.z; double displacement = (double) Math.sqrt(dx * dx + dz * dz); force.x = 0; force.y = 0; force.z = 0; if (N2.color.a == 0) { return force; } if (displacement == 0) { //Yeesh... this is tricky... return force; } //assert(stiffness <= 1); double magnitude = K / 1 * (displacement - restAngle); magnitude /= displacement; if (N1.color.a != 0 && // Math.abs(magnitude) > limit) // || Math.abs(magnitude * displacement) > limit) { //System.out.println("BREAK: " + magnitude + "; displacement = " + displacement + "; dx = " + dx + "; dy = " + dy + "; dz = " + dz); magnitude /= Math.abs(magnitude); magnitude *= limit; N1.color.a = 0; N2.color.a = 0; } else { //N1.color.a = 1; //N2.color.a = 1; } force.x = dx * magnitude; //force.y = dy * magnitude; force.z = dz * magnitude; return force; } } */ }