Unit-90 Chain Uncurling

JOR, 31Jan11

Linkage at heart of pop-up spinner

Rotate each link about previous one.  Need convention on dihedral angles.
Say linkage = Vertices[1],[2],...,[n].  Global
First create initial configuration.

FUZZ=0.00001;
FuzzEq0[x_]:=Abs[x]<FUZZ;
RadDeg=180./Pi;
DegRad=Pi/180.;
buff=1/2; (*Buffer around PlotRange: currently disabled.*)

Init[] initializes the chain to be coiled completely.
Note these are all global vars.
ShowIt[] fixes PlotRange so we can get a type of animation.
    PlotRange now disabled because it is not working correctly...

Init[]:=Module[{},
n=8;
V=Table[{},{i,1,n}];
V[[1]] = o={0,0,0};
θ=0;
For[i=2,i≤n,i++,
V[[i]] =V[[i-1]] + {Cos[θ],Sin[θ],0};
θ +=π/2;
];
Print["Init[] finished"];
];
Init[];

ShowIt[color_: Red]:=Module[{tt,n},
n=Length[V];
tt=MapThread[Text[#1,#2,{1,1}]&,{Range[n],V}];
g=Graphics3D[{
{color,Thick,Tube[V,0.02]},
tt
}
(*,PlotRange->{{-buff,1+buff},{-buff,1+buff},{-buff,n+buff}}*)
];Print[g];
];
ShowIt[];

CheckChain[] makes sure all the links remain unit length.  Not really needed in a perfect world...

CheckChain[V_]:=Module[{i,n,d},
n=Length[V];
For[i=2,i≤ n,i++,
d=EuclideanDistance[V[[i]],V[[i-1]]];
If[ !FuzzEq0[d-1.], Print["Error in CheckChain: d=",d]];
];
If[debug,Print["CheckChain: All links unit length!"]]
];
CheckAngles[V_]:=Module[{i,n,αlist={},δlist={}},
n=Length[V];
For[i=2,i<n,i++,
AppendTo[αlist,RadDeg*VectorAngle[V[[i]]-V[[i-1]],V[[i+1]]-V[[i]]]];
If[ !FuzzEq0[αlist[[-1]]-90.], Print["Error in CheckAngles: d=",d]];
];
If[debug,Print["Joint angles α:",N[αlist,1]]];
For[i=2,i<n-1,i++,
AppendTo[δlist,RadDeg*VectorAngle[V[[i]]-V[[i-1]],V[[i+2]]-V[[i+1]]]]
];
Print["Dihedral angles δ:",N[δlist,1]];
];

OpenUp1 by angle δ, evenodd=0/1 determines different behavior. This is just one step of the opening. Runs through all even or odd indexed joints, and opens each by δ, through the whole chain.

OpenUp1[δ_,evenodd_, color_:Red]:=Module[{rot,i,j,n,vprev,istart,δ1},
n=Length[V];
V=N[V];(* Must make numerical to avoid great complexities!*)
If[debug,Print["OpenUp1: n=",n," V=", V]];
(* It is the link from i to i+1 that is being rotated about prev *)
If[evenodd==0,istart=2,istart=1];
For[i=istart,i<n,i+=2,
If[debug,Print["Before: {i,V[[i]]}=",{i,N[V[[i]]]}]];
If[debug,ShowIt[color]];
(* Special handling for nonexistent prior link *)
If[i≥2,vprev=V[[i-1]],vprev={0,1,0}];
(*Logic here: beyond 1st rot need twice the angle*)
If[i < 3, δ1=δ,δ1=2 δ];
rot=RotationTransform[δ1,V[[i]] -vprev, V[[i]]];
For[j=i+1,j≤ n,j++,
V[[j]]=N[rot[V[[j]]]];
];
If[debug,Print["After i=",i," V=", V]];
CheckChain[V];
];
Print["OpenUp: finished"];
CheckAngles[V];
ShowIt[Purple]
];

Testing the code, little by little.

Init[];
δ=Pi/9;debug=False;
OpenUp1[δ,0,Red];
OpenUp1[δ,1,Blue];
OpenUp1[δ,0,Green];
OpenUp1[δ,1,Red];
OpenUp1[δ,0,Blue];
OpenUp1[δ,1,Green];

OpenUpFrames computes a δ from nframes that will open up the chain completely.
Vstore holds all the frames of V[].

OpenUpFrames[nframes_]:=Module[{i,δ},
Init[];
Vstore={};(*Global storage for vertices*)
δ=N[Pi/nframes];
Print["OpenUpFrames: δ=",δ RadDeg];
For[i=1,i≤nframes,i+=2,
Print["OpenUpFrames: frame=",i];
OpenUp1[δ,0];
AppendTo[Vstore,V];
Print["OpenUpFrames: frame=",i+1];
OpenUp1[δ,1];
AppendTo[Vstore,V];
];(*For*)
Print["OpenUpFrames: finished!"];
Print["Length[Vstore]=",Length[Vstore],"; Length of each V: n=",n];
];

OpenUpFrames[16]

Notes for Julia here.  
All the frames are stored in Vstore, one row per frame, each row on instance of the vertex vector V.  I think you should be able to Export[ Vstore ] and work from that.