//Rick's Chain Maker
//Copyright 2008 Richard Swika
//http://home.comcast.net/~chainmaker
//email:chainmaker@comcast.net
//Revision: 1.3.1
//Link Properties; adjust these to vary the size and proportions of
each link to suit your needs
//#declare LinkLength =
1.45; //The
length of a single link (outside diameter)
//#declare LinkRadius =
0.5; //The
outside radius of the link's curved section
//#declare WireRadius =
0.15; //The radius of
the wire used to make each ink
//Chain Frame Properties; adjust these to control the number of corners
and number of links in the final chain frame
//#declare CornerCount =
4; //How
many corners to put in the frame; 3 or more please!!!
//#declare CornerLinkCount = 3;
//How many links to put on the corners of the frame (0 for pointy
corners)
//#declare StraightLinkCountEven = 4; //How many links to put in the
even straight sections of the frame
//#declare StraightLinkCountOdd = 4; //How many links to put in
the odd straight sections of the frame
//Special effects
//#declare InitialTwist =
0; //The starting
twist angle of the chain;
//most useful at 90, 45 and -45 (all angles are in degrees)
//#declare TwistDelta =
90; //How much each
link twists when added to the chain
//most useful at 0 and 90
//very interesting effects at 30, 45, 60 and others
//#declare Zoom =
1;
//In rare cases you may want to change the zoom level
//#declare Exposure =
1;
//You can also play with the exposure level to bring out more detail
//#declare TotalInterior = 360;
//Total Interior Angle of all corners; set to 720 and CornerCount to 5
for a star
///Don't change anything below this line unless you know what you are
doing!!
#include "transforms.inc"
#include "math.inc"
//Calcuated constants
#declare CylL = LinkLength-(LinkRadius*2);
#declare LinkCount =
CornerCount*CornerLinkCount+int((1+CornerCount)/2)*StraightLinkCountEven+int(CornerCount/2)*StraightLinkCountOdd;
#if ((StraightLinkCountOdd>0) & (StraightLinkCountEven>0))
#declare CornerRotation =
TotalInterior/(CornerCount*(CornerLinkCount+1.0));
#else
#if (StraightLinkCountOdd+StraightLinkCountEven)
#declare CornerRotation =
TotalInterior/(CornerCount*(CornerLinkCount+0.5));
#else
#declare CornerRotation = TotalInterior/(CornerCount*(CornerLinkCount));
#end
#end
#declare LinkCurve = difference {
torus {LinkRadius-WireRadius,WireRadius sturm}
plane {-x,0}
rotate 90*x
}
#declare LinkSeg = cylinder {
<0, 0, 0>, <CylL, 0, 0>, WireRadius
}
#declare TestLink = union {
object {
cylinder {<-LinkRadius+WireRadius, 0,
0>, <CylL+LinkRadius-WireRadius, 0, 0>, WireRadius}
translate z*(LinkRadius-WireRadius)
}
object {
cylinder {<-LinkRadius+WireRadius, 0,
0>, <CylL+LinkRadius-WireRadius, 0, 0>, WireRadius}
translate -z*(LinkRadius-WireRadius)
}
}
#declare Link = union {
object {LinkCurve}
object {
LinkCurve
rotate y*180
translate x*CylL
}
object {
LinkSeg
translate y*(LinkRadius-WireRadius)
}
object {
LinkSeg
translate -y*(LinkRadius-WireRadius)
}
}
//Functions to determine which feature of the frame is being generated
as a function of the Section number
#declare OnCorner=function(Section) {odd(Section)};
#declare OnOddStraight=function(Section)
{odd(int(Section/2))*even(Section)};
#declare OnEvenStraight=function(Section)
{even(int(Section/2))*even(Section)};
//Macro to steer chain growth by moduling DeltaRotation; modify this to
generate different shapes
#macro SteerChain(Section)
#debug concat(" Section=",str(Section,3,0),"
SubIndex=",str(SubIndex,3,0),
"OnEvenStraight",str(OnEvenStraight(Section),3,0),
" OnOddStraight=",str(OnOddStraight(Section),3,0),"\n")
#declare DeltaRotation = 0;
#if (OnEvenStraight(Section))
#if (SubIndex >=
StraightLinkCountEven)
#declare Section = Section +
1;
#declare DeltaRotation =
CornerRotation;
#declare SubIndex = 0;
#if (CornerLinkCount=0)
#declare Section
= Section + 1;
#end
#end
#else #if (OnOddStraight(Section))
#if (SubIndex >= StraightLinkCountOdd)
#declare Section = Section +
1;
#declare DeltaRotation =
CornerRotation;
#declare SubIndex = 0;
#if (CornerLinkCount=0)
#declare Section
= Section + 1;
#end
#end
#else //Am on corner
#declare DeltaRotation = CornerRotation;
//Make corner
#if (SubIndex >= CornerLinkCount)
#declare Section = Section +
1;
#declare SubIndex = 0;
#if (OnEvenStraight(Section))
#if
(StraightLinkCountEven=0)
#declare Section = Section + 1;
#end
#else #if
(OnOddStraight(Section))
#if
(StraightLinkCountOdd=0)
#declare Section = Section + 1;
#end
#end
#end
#end
#end
#end
#end
#declare ChainFrame = union {
#declare Index = 0;
#if (StraightLinkCountEven=0)
#declare Section = 1;
#else
#declare Section = 0;
#end
#declare SubIndex = 0;
#declare AttachPt = <0,0,0>;
#declare Rotation = 0;
#declare DeltaRotation = 0;
#declare MinExtent = <0,0,0>;
#declare MaxExtent = <0,0,0>;
//Generate each link of the chain
#while(Index < LinkCount)
#declare Twist = InitialTwist + TwistDelta*Index;
//Amount of Twist is directly related to Link Index
//Adjust the pivot point of the link for a natural
appearance, such that
//vertical links rotate about torus minor radius
center, and
//horizontal links rotate about the torus major
radius center
#declare PivotAdjust
=(LinkRadius-WireRadius)*abs(sin(radians(Twist)));
// #debug
concat("Twist=",str(InitialTwist+TwistDelta*Index,5,0),"
PivotAdjust=",str(PivotAdjust,5,3),"\n")
// cylinder {AttachPt,AttachPt-z*LinkRadius*.99,
LinkRadius-2*WireRadius} //Identifies attachment point location during
development
//Generate the link, orient and position it
object {Link rotate x*(InitialTwist +
TwistDelta*Index) //Apply twist
translate
x*PivotAdjust
//Apply pivot point adjustment
rotate
z*Rotation
//Curve around frame
translate
AttachPt
//Move to Attachment Point
}
#declare Index = Index + 1;
#declare SubIndex = SubIndex + 1;
//Calculate where the attachment point has moved as
a result of the above transformation
#declare
AttachPt=AttachPt+vtransform(x*(CylL+2*PivotAdjust),transform{rotate
z*Rotation});
SteerChain(Section) //Steer chain by modulating
DeltaRotation of next link to be generated; 0 for straight section, etc.
//Advance Attachment Point
#declare Rotation = Rotation + DeltaRotation; //This
will be the total rotation of the next link to be generated
// #debug
concat("DeltaRotation=",str(DeltaRotation,4,0),"
Index=",str(Index,3,0)," SubIndex=",str(SubIndex,3,0),"\n")
//Find extent, for autotracking and autozoom
#declare MinExtent =
<min(MinExtent.x,AttachPt.x),min(MinExtent.y,AttachPt.y),0>;
#declare MaxExtent =
<max(MaxExtent.x,AttachPt.x),max(MaxExtent.y,AttachPt.y),max(MaxExtent.z,AttachPt.y)>;
#end
// rotate x*45 //For debugging, useful to see frame from a
different angle
}
#declare DepthRig = union {
plane {z, -0.000001} //Nudge toward black
ChainFrame
pigment {
gradient z
color_map {
[0 rgb 0]
[0.5 rgb 1]
[1 rgb 0]
}
scale <1,1,2*LinkRadius/Exposure>
}
finish {ambient 1 diffuse 0}
}
#declare CLOC = <0.0, 0.0, -10.0>;
camera
{
orthographic
location CLOC
direction 1*z
right x*image_width/image_height
look_at <0.0, 0.0, 0.0>
}
object { // scene
#debug concat("MinExtent =
<",str(MinExtent.x,2,0),",",str(MinExtent.y,2,0),",",str(MinExtent.z,2,0),">","\n")
#debug concat("MaxExtent =
<",str(MaxExtent.x,2,0),",",str(MaxExtent.y,2,0),",",str(MaxExtent.z,2,0),">","\n")
#declare ScreenScale =
Zoom/(1.1+max(MaxExtent.x-MinExtent.x,MaxExtent.y-MinExtent.y));
//Apply autotracking and autozooming
DepthRig translate
<-(MaxExtent.x+MinExtent.x)/2,-(MaxExtent.y+MinExtent.y)/2,0>
scale <ScreenScale,ScreenScale,ScreenScale>
}
//Rick's Chain Maker
//Copyright 2008 Richard Swika
//http://home.comcast.net/~chainmaker