Spiral Staircase Generator

From Second Life Wiki
Revision as of 17:07, 29 April 2008 by Meyermagic Salome (talk | contribs) (New page: {{LSL Header}} Rezzes a spiral staircase according to configuration parameters. [[Image:SpiralStaircase.jpg|thumb|A screenshot of a staircase generated by the Spiral Staircase Generator]...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Rezzes a spiral staircase according to configuration parameters.

A screenshot of a staircase generated by the Spiral Staircase Generator

.

Generator

Drop this in the generator prim, along with the step, banister, and baluster. <lsl> //////////////////////////////// // Spiral Staircase Generator // // By Meyermagic Salome // //////////////////////////////// // Staircase Configuration // float wh = 2.5; //Height of one wave (in meters) float wc = 4.0; //Full waves in staircase

float r_max = 10.0; //Radius maximum, (0.1 -> 10.0) float r_min = 7.5; //Radius minimum, (0.1 -> 10.0)

integer landing = 5;//Number of non-rising stairs at top of staircase (not included in wc)

//Step Configuration float s_h = 0.01; //Step height, (0.01 -> 0.99) float s_s = 0.2; //Vertical stair spacing, (0.01 -> 10.00)

float l_max = 1.0; //Maximum stair length, (0.01 -> 10.00) float l_min = 0.5; //Minimum stair length, (0.01 -> 10.00)

//Balustrade Configuration float bal_d = 0.05; //Baluster diameter, (0.001 -> 1.000) float bal_h = 0.5; //Height of baluster / height of banister, (0.01 -> 1.00)

float ban_d = 0.05; //Banister diameter, (0.001 -> 1.000) float ban_h = 2.0; //Banister height, (0.01 -> 10.00)

// Functions // string str_repeat(string src, integer count) {

   if(count > 0)
   {
       string output;
       integer i;
       for(i = 0; i < count; i++)
       {
           output += src;
       }
       return output;
   }
   else
   {
       return "";
   }

}

string pad_left(string str, string pad, integer len)//Left-pads string str to length len with character pas {

   return str_repeat(pad, len - llStringLength(str)) + str;

} list segment(vector a, vector b)//Returns the parameters for a cylinder connecting points a and b {//Based on http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryBezierCurveDemo

   vector mid = (a + b) / 2.0;
   vector localZ = b - a;
   float len = llVecMag(localZ);
   localZ = localZ / len;
   vector xAxis;
   if(localZ.x < localZ.y)
   {
       xAxis = <1.0, 0.0, 0.0>;
   }
   else
   {
       xAxis= <0.0, 1.0, 0.0>;
   }
   vector localX = xAxis - (localZ * xAxis) * localZ;
   localX = llVecNorm(localX);
   rotation rot = llAxes2Rot(localX, localZ % localX, localZ);
   return [len, mid, rot];

}

//Staircase-specific Functions float wave(integer i)//Return i as portion of full wave (2PI) {

   return PI * (float)i * s_s / wh;

} float radius(integer i)//Return the stair radius at step i {

   return llFabs(((llCos(wave(i)) + 1.0) * ((r_max - r_min) / 2)) + r_min);

} float len(integer i)//Returns the length of stair at step i {

   return llFabs(((llCos(wave(i)) + 1.0) * ((l_max - l_min) / 2)) + l_min);

} float rot(integer i)//Returns the rotation of stair at step i {

   return llAcos(1 - llPow(len(i), 2.0) / (2 * llPow(radius(i), 2)));

}

integer s_encode(integer i) {

   return (integer)("1" + pad_left((string)llRound(s_h * 100.0), "0", 2) + pad_left((string)llRound(radius(i) * 10.0), "0", 3) + pad_left((string)llRound(len(i) * 100.0), "0", 4));

} integer p_encode(float h) {

   return (integer)("1" + pad_left((string)llRound(bal_d * 1000.0), "0", 4) + pad_left((string)llRound(h * 1000.0), "0", 5));

} integer r_encode(float l) {

   return (integer)("1" + pad_left((string)llRound(ban_d * 1000.0), "0", 4) + pad_left((string)llRound(l * 1000.0), "0", 5));

}

default {

   touch_start(integer num_detected)
   {
       if(llDetectedKey(0) == llGetOwner())
       {
           integer i = 0;
           float t = 0.0;
           //Rez main rising steps
           for(i = 0; i < (integer)(wc * wh / s_s); ++i)
           {
               llSetPos(llGetPos() + <0, 0, s_s>);//I'll have it do this every ~10m when I get around to it
               float c_rot = rot(i);
               float c_radius = radius(i);
               float n_radius = radius(i + 1);
               vector m_pos = llGetPos();
               //Rez step
               llRezObject("Step",
                   m_pos + <llCos(t + c_rot / 2.0) * c_radius / 2.0, llSin(t + c_rot / 2.0) * c_radius / 2.0, 0>,
                   ZERO_VECTOR,
                   llEuler2Rot(<PI_BY_TWO, t + c_rot / 2.0 + 4.7123889, 0>),
                   s_encode(i));
               //Get balustrade data
               list b_data = segment(m_pos + <llCos(t) * c_radius, llSin(t) * c_radius, ban_h + (s_h / 2.0)>,
                   m_pos + <llCos(t + c_rot) * n_radius, llSin(t + c_rot) * n_radius, ban_h + (s_h / 2.0) + s_s>);
               if(i == (integer)(wc * wh / s_s) - 1)
               {
                   b_data = segment(m_pos + <llCos(t) * c_radius, llSin(t) * c_radius, ban_h + (s_h / 2.0)>,
                       m_pos + <llCos(t + c_rot) * n_radius, llSin(t + c_rot) * n_radius, ban_h + (s_h / 2.0)>);
               }
               vector b_pos = llList2Vector(b_data, 1);
               //Rez banister
               llRezObject("Banister",
                   b_pos,
                   ZERO_VECTOR,
                   llList2Rot(b_data, 2),
                   r_encode(llList2Float(b_data, 0)));
               //Rez baluster
               llRezObject("Baluster",
                   <b_pos.x, b_pos.y, m_pos.z + ((b_pos.z - m_pos.z) / 2.0) + (s_h / 2.0)>,
                   ZERO_VECTOR,
                   ZERO_ROTATION,
                   p_encode((b_pos.z - m_pos.z) * bal_h));
               //Increment rotation
               t += rot(i);
           }
           //Rez non-rising steps
           for(i = (integer)(wc * wh / s_s); i < (integer)(wc * wh / s_s) + landing; ++i)
           {
               float c_rot = rot(i);
               float c_radius = radius(i);
               float n_radius = radius(i + 1);
               vector m_pos = llGetPos();
               //Rez step
               llRezObject("Step",
                   m_pos + <llCos(t + c_rot / 2.0) * c_radius / 2.0, llSin(t + c_rot / 2.0) * c_radius / 2.0, 0>,
                   ZERO_VECTOR,
                   llEuler2Rot(<PI_BY_TWO, t + c_rot / 2.0 + 4.7123889, 0>),
                   s_encode(i));
               //Get balustrade data
               list b_data = segment(m_pos + <llCos(t) * c_radius, llSin(t) * c_radius, ban_h + (s_h / 2.0)>,
                   m_pos + <llCos(t + c_rot) * n_radius, llSin(t + c_rot) * n_radius, ban_h + (s_h / 2.0)>);
               vector b_pos = llList2Vector(b_data, 1);
               //Rez banister
               llRezObject("Banister",
                   b_pos,
                   ZERO_VECTOR,
                   llList2Rot(b_data, 2),
                   r_encode(llList2Float(b_data, 0)));
               //Rez baluster
               llRezObject("Baluster",
                   <b_pos.x, b_pos.y, m_pos.z + ((b_pos.z - m_pos.z) / 2.0) + (s_h / 2.0)>,
                   ZERO_VECTOR,
                   ZERO_ROTATION,
                   p_encode((b_pos.z - m_pos.z) * bal_h));
               //Increment rotation
               t += rot(i);
           }
       }
   }

} </lsl>

Conf_Step

Drop this in a prim named "Step". (Box with x-taper 1.0 is recommended).

<lsl> default {

   on_rez(integer s)
   {
       if(s != 0)
       {
           string d = (string)s;
           float y = ((float)llGetSubString(d, 1, 2)) / 100.0;//Height
           float z = ((float)llGetSubString(d, 3, 5)) / 10.0;//Radius
           float x = ((float)llGetSubString(d, 6, 9)) / 100.0;//Length
           llSetScale(<x, y, z>);
           llRemoveInventory(llGetScriptName());
       }
   }

} </lsl>

Conf_Banister

Drop this in a cylinder named "Banister".

<lsl> default {

   on_rez(integer s)
   {
       if(s != 0)
       {
           string d = (string)s;
           float z = ((float)llGetSubString(d, 5, 9)) / 1000.0;//Length
           float y = ((float)llGetSubString(d, 1, 4)) / 1000.0;//Diameter
           float x = y;
           llSetScale(<x, y, z>);
           llRemoveInventory(llGetScriptName());
       }
   }

} </lsl>

Conf_Baluster

Drop this in a cylinder named "Baluster".

<lsl> default {

   on_rez(integer s)
   {
       if(s != 0)
       {
           string d = (string)s;
           float z = ((float)llGetSubString(d, 5, 9)) / 1000.0;//Height
           float y = ((float)llGetSubString(d, 1, 4)) / 1000.0;//Diameter
           float x = y;
           llSetScale(<x, y, z>);
           llRemoveInventory(llGetScriptName());
       }
   }

} </lsl>