Each chain is moving is independently, the first segment completely random, the next ones restricted by segment distance and step length. Segment distance and step length have a random variation.
Each chain is created with an angle restriction between segments (low angle expandend chain, high angle compact chain).
Coil[] coil;
int boxsize = 500;
float camangle = 90; //camera angle
float angle = 90; //maximum anlge between coil[j].segments, the larger the more flexible
int snumber = 75; //number of coil[j].segments in coil
int cnumber = 5; // number of coils
int sdistance = 10; //distance between coil[j].segments
float segdistdev = 0.5; //deviation from possible sdistance (0.1 = 10%)
float stepdev = 0.5; // deviation from possible speed/speed (0.1 = 10%)
int speed = 10; //movement speed
void setup(){
size(900, 700, P3D);
coil = new Coil[cnumber];
for (int j=0; j < coil.length; j++){
coil[j] = new Coil(sdistance, snumber, speed);
}
}
void draw(){
background(129,200,273);
lights();
translate(450,350,0);
rotateY(camangle);
noFill();
stroke(0);
box(boxsize);
println("Start: Check");
for (int j=0; j < coil.length; j++){
for (int i = 1; i < coil[j].segments.length; i++){
PVector point0 = new PVector();
PVector point1 = new PVector();
point0 = coil[j].segments[i-1].location.copy();
point1= coil[j].segments[i].location.copy();
//check that segments are within box; while instead of if to cover cases with coordinates larger than boxsize/2
while (point0.x > boxsize/2){ point0.x -=boxsize; }
while (point0.x < -boxsize/2){ point0.x +=boxsize; }
while (point0.y > boxsize/2){ point0.y -=boxsize; }
while (point0.y < -boxsize/2){ point0.y +=boxsize; }
while (point0.z > boxsize/2){ point0.z -=boxsize; }
while (point0.z < -boxsize/2){ point0.z +=boxsize; }
while (point1.x > boxsize/2){ point1.x -=boxsize; }
while (point1.x < -boxsize/2){ point1.x +=boxsize; }
while (point1.y > boxsize/2){ point1.y -=boxsize; }
while (point1.y < -boxsize/2){ point1.y +=boxsize; }
while (point1.z > boxsize/2){ point1.z -=boxsize; }
while (point1.z < -boxsize/2){ point1.z +=boxsize; }
//check if points are on opposite ends of box, then no line is drawn, 2*sdistance to accommodate deviation
if (abs(point1.x - point0.x) < 2*sdistance && abs(point1.y - point0.y) < 2*sdistance && abs(point1.z - point0.z) < 2*sdistance*sdistance){
strokeWeight(5);
line(point0.x,point0.y, point0.z, point1.x, point1.y, point1.z);
strokeWeight(1);
}
}
}
if(mousePressed == true){
camangle += 0.1;
}
for (int j=0; j < coil.length; j++){
for (int i=0; i < coil[j].segments.length; i++){
println("Start Movement: Check");
PVector alastnew = new PVector(); //axis of last to new segment
PVector teststep = new PVector(); //temporary step to check conditions for Segment 0 step
PVector testaxis = new PVector(); //temporary axis to check conditions for Segment 0 step
float taxislength = 0;
float seg1step = 0; //actual step length calculated
float seg1distance = 0;
PVector seg0 = new PVector();
PVector segment0 = new PVector();
PVector segment1 = new PVector();
if (i == 0){
//random step for first segment
segment0 = coil[j].segments[0].location.copy();
segment1 = coil[j].segments[1].location.copy();
while (abs(taxislength) < sdistance || abs(taxislength) > sdistance+speed) {
seg0 = PVector.random3D();
float step1 = speed*random(1-stepdev,1+stepdev);
seg0.setMag(step1);
PVector.add(segment0,seg0,teststep);
PVector.sub(teststep,segment1,testaxis);
taxislength = testaxis.mag();
}
segment0 = teststep.copy(); //1st segment updated
coil[j].segments[0].location = segment0.copy();
} else {
segment0 = coil[j].segments[i-1].location.copy();
segment1 = coil[j].segments[i].location.copy();
PVector.sub(segment0,segment1,alastnew);
float axislength = alastnew.mag();
while (seg1step < abs(axislength-seg1distance) || seg1step > abs(axislength+seg1distance)){
seg1distance = sdistance*random(1-segdistdev,1+segdistdev);
seg1step=speed*random(1-stepdev,1+stepdev);
}
println("Movement calculation completed for segment", i);
println(frameRate);
segment1 = movement(segment0,segment1,seg1distance,seg1step);
coil[j].segments[i].location = segment1.copy();
}
}
}
}
class Coil{
Segments[] segments;
int csdistance;
int csnumber;
int cspeed;
float crgcounter = 0;
float cRg = 0;
Coil(int sdistance_ , int snumber_ , int speed_){
csdistance = sdistance_;
csnumber = snumber_;
cspeed = speed_;
segments = new Segments[csnumber];
startcond();
println(segments[0].location, segments[snumber-1].location);
}
void startcond(){
//create starting point for coil
PVector loc; //starting vector
PVector loc_old = new PVector(); //preceding vector
float test = 0; //angle test
loc = new PVector (map(random(1),0,1,-boxsize/4,boxsize/4),map(random(1),0,1,-boxsize/4,boxsize/4),map(random(1),0,1,-boxsize/4,boxsize/4));
segments[0] = new Segments(loc);
loc_old = loc.copy();
//create random segments
for (int i = 1; i < segments.length; i++){
PVector loc2 = loc_old;
while (degrees(test) > angle || degrees(test)==0 || loc2 == loc_old){
loc2=PVector.random3D();
test = PVector.angleBetween(loc2,loc_old);
}
loc2 = loc2.setMag(csdistance);
loc_old=loc2.copy();
loc2 = loc2.add(segments[i-1].location);
segments[i] = new Segments(loc2);
println(i, degrees(test), loc2);
}
}
}
PVector movement(PVector lastseg, PVector newseg, float segdistance, float step){
PVector out = new PVector();
PVector axis = new PVector();
PVector proj = new PVector();
float cradius; //radius of intersect circle
//axis vector through circle center
PVector.sub(lastseg,newseg,axis);
//vector to projection point of axis, which is middle point of circle
float projection = (step*step - segdistance*segdistance + axis.magSq())/ (2*axis.mag());
proj = axis.copy();
proj.setMag(projection);
proj.add(newseg);
//radius of intersect circle
cradius = sqrt(step*step - projection*projection);
//Identify axis coordinate with smallest absolute value to create perpendicular vector
float ax = abs(axis.x);
float ay = abs(axis.y);
float az = abs(axis.z);
PVector b = new PVector();
if (ax <= ay && ax <= az){
b = new PVector(1,0,0);
} else if (ax > ay && ay <= az){
b = new PVector(0,1,0);
} else {
b = new PVector(0,0,1);
}
//create vectors in plane with intersect circle
PVector iv = new PVector();
PVector.cross(axis,b,iv);
PVector jv = new PVector();
PVector.cross(axis, iv, jv);
iv.normalize();
jv.normalize();
PVector c2 = new PVector();
PVector c3 = new PVector();
PVector p = new PVector();
float cang = random(TWO_PI);
PVector.mult(iv, cos(cang), c2);
c2.mult(cradius);
PVector.mult(jv, sin(cang), c3);
c3.mult(cradius);
p.add(proj);
p.add(c2);
p.add(c3);
out = p.copy();
return out;
}
class Segments{
PVector location;
Segments(PVector location_){
location = location_;
}
}