|
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<numX-1||c<numY-1/*/2*/);
|
boolean free = (r - numX / 2) * (r - numX / 2) + (c - numY / 2) * (c - numY / 2) > 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<numX; i++)
|
{
|
//gl.glVertex3f(handles[i].position.x, handles[i].position.y, handles[i].position.z);
|
//gl.glVertex3f(mesh[i][0].position.x, mesh[i][0].position.y, mesh[i][0].position.z);
|
}
|
|
for (int r = 0; r < numX; r++)
|
{
|
for (int c = 0; c < numY; c++)
|
{
|
if (time > 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<Force> allForces;
|
Vector<DynamicNode> allNodes;
|
Vector<DynamicNode> allHandles = new Vector<DynamicNode>();
|
Vector<cVector> handles = new Vector<cVector>();
|
Vector<Spring> allSprings;
|
|
cMatrix3x3 matrix = new cMatrix3x3(); // buffer
|
cMatrix3x3 matrixT = new cMatrix3x3(); // buffer
|
|
PhysicsController3D()
|
{
|
allForces = new Vector<Force>(8, 0);
|
allNodes = new Vector<DynamicNode>(8, 0);
|
allSprings = new Vector<Spring>(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<usedrep.VertexCount(); i++)
|
{
|
Vertex v = usedrep.GetVertex(i);
|
|
vect1.set(v);
|
LA.xformPos(vect1,toRoot,vect1);
|
|
handles.get(i).set(vect1);
|
}
|
}
|
|
Vector<DynamicNode> edges = new Vector<DynamicNode>();
|
Vector<Spring> folds = new Vector<Spring>();
|
|
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<edges.size(); k+=2)
|
{
|
double rest = 1;
|
if (unfold)
|
{
|
Spring s = folds.get(k/2);
|
|
a.set(edges.get(k).position);
|
b.set(edges.get(k+1).position);
|
|
double mindist = 1E10;
|
for (double t=-1; t<=2; t+=0.01)
|
{
|
temp.set(s.a.position);
|
temp2.set(s.b.position);
|
temp.mul(t);
|
temp2.mul(1-t);
|
temp.add(temp2);
|
|
temp2.set(a);
|
temp2.sub(temp);
|
|
double len = temp2.length();
|
|
temp2.set(b);
|
temp2.sub(temp);
|
|
len += temp2.length();
|
|
if (mindist > 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<Force> GetForces()
|
{
|
return null;
|
}
|
|
void computeForce(Vector<Force> forces)
|
{
|
}
|
|
void update(boolean damping)
|
{
|
}
|
|
void addForce(Force F)
|
{
|
}
|
}
|
|
class DynamicNode extends Node
|
{
|
|
Point3D velocity;
|
//double damping;
|
Vector<Force> myForces;
|
Vector<Spring> 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<Spring> springs; // sorted
|
//transient Spring first;
|
//transient Spring second;
|
transient cVector axis = new cVector();
|
transient Vector<Point3D> axis0 = new Vector<Point3D>();
|
//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<Force>(4, 0);
|
mySprings = new Vector<Spring>(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<Force>(4, 0);
|
mySprings = new Vector<Spring>(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<Force> GetForces()
|
{
|
return myForces;
|
}
|
|
void addForce(Force F)
|
{
|
myForces.add(F);
|
}
|
|
void addSpring(Spring F)
|
{
|
myForces.add(F);
|
mySprings.add(F);
|
}
|
|
void computeForce(Vector<Force> 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<springs.size()-1; i+=1)
|
{
|
first = springs.get(i);
|
second = springs.get((i+1)%springs.size());
|
|
if (first == second)
|
{
|
new Exception().printStackTrace();
|
System.exit(0);
|
}
|
|
temp.set(first.GetOther(this).position);
|
temp.sub(position);
|
temp.normalize();
|
|
a.set(second.GetOther(this).position);
|
a.sub(position);
|
a.normalize();
|
|
/*
|
e1.set(x.x-o.x, x.y-o.y, x.z-o.z);
|
e2.set(y.x-o.x, y.y-o.y, y.z-o.z);
|
|
e3.cross(e1, e2);
|
|
double sin = e3.length();
|
double cos = e1.dot(e2);
|
*/
|
|
b.cross(temp, a);
|
|
double sin = b.length();
|
double cos = temp.dot(a);
|
|
double angle = Math.atan2(sin, cos);
|
|
if (angle > 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<springs.size(); i+=1)
|
{
|
Spring first = springs.get(i);
|
Spring second = springs.get((i+1)%springs.size());
|
|
if (first == second)
|
{
|
new Exception().printStackTrace();
|
System.exit(0);
|
}
|
|
temp.set(first.GetOther(this).position);
|
temp.sub(position);
|
temp.normalize();
|
|
// double dot = normal.dot(temp);
|
// dir.set(normal);
|
// dir.mul(dot);
|
// temp.sub(dir);
|
|
a.set(second.GetOther(this).position);
|
a.sub(position);
|
a.normalize();
|
|
// dot = normal.dot(a);
|
// dir.set(normal);
|
// dir.mul(dot);
|
// a.sub(dir);
|
|
if (a.dot(temp) < -0.75)
|
continue; // opposite springs
|
|
dir.cross(temp, a);
|
dir.normalize();
|
|
if (true) // full normals
|
{
|
// FullNormal();
|
}
|
|
//if (normal.dot(temp2) < 0)
|
// continue;
|
|
b.cross(dir, temp);
|
b.normalize();
|
|
Point3D a0 = axis0.get(i);
|
|
temp.mul(a0.x);
|
b.mul(a0.y);
|
|
axis.set(temp.x+b.x, temp.y+b.y, temp.z+b.z);
|
//axis.normalize();
|
|
quat.set(axis, a0.z); // rotangle);
|
|
rotation.setRotation(quat);
|
|
if (reverse)
|
{
|
normal.mul(-1);
|
}
|
|
rotation.Transform(dir);
|
dir.normalize();
|
|
temp3.add(dir);
|
|
if (IsFastNormals())
|
break;
|
}
|
|
if (temp3.length2() > 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<Spring>();
|
|
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<Vertex> 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<Vertex> sortedcollider;
|
Vector<Double> parameters = new Vector<Double>(); // 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<Force> forces = new Vector<Force>(); // 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;
|
}
|
}
|
*/
|
}
|