/*************************************************************************
        SPIDER'S WEB INCLUDE FILE FOR PERSISTENCE OF VISION 3.x
**************************************************************************

Created by Chris Colefax, 25 September 1997
Updated 18 July 1998: updated for POV-Ray 3.1

OVERVIEW: Creates a spider's web composed of thin threads arranged
in a spokes and concentric circles pattern.

USAGE: To create the default spider's web, just include this file
inside an object statement, eg:

   object {#include "SPWeb.inc"}

This creates a web 10 units in radius, that lies in the XY plane.
To modify the web, insert the desired option declarations before
including the file (see below for a complete list of options), eg:

   object {#declare web_type = 3;
           #declare web_radius = 3;
           #declare thread_thickness = .1;
           #include "SPWeb.inc"}

To transform the web, add the desired modifications after including the
file, eg:

   object {#include "SPWeb.inc"
           scale .5 rotate <-45, -45, 0>
           clipped_by {box {<-3, -3, -3>, <3, 3, 3>}}
           texture {pigment {rgbt <1, 1, 1, .5>}}
           translate <-10, 20, 30>}

To create multiple webs, you can either include the file (as above)
multiple times (this will produce a different web each time), or declare
the object and reuse it in the standard way, eg:

   #declare SpiderWeb = object {#include "SPWeb.inc"}
      object {SpiderWeb translate <45, -10, 20>}
      object {SpiderWeb scale .5}

Note that declaring the object in this way requires less parsing time,
but produces identical webs.

OPTIONS: The following is a list of options (see above for usage) and
their default values.

 -- OPTION ------- DEFAULT -- DESCRIPTION ---------------------------
  web_type              2     Sets the style of the web circles
                                 (choose from 1, 2, or 3)
  web_radius           10     Sets the overall radius of the web
  web_spokes_count      8     Sets the number of spokes in the web
  web_circles_count     4     Sets the number of circles in the web
  web_circles_radius    8     Sets the overall radius of the web circles
  thread_thickness      0.05  Sets the thickness of the web thread
  thread_tightness      0.5   Sets the tightness of the web circles
  web_seed              0     Sets the random seed used to create the web
  web_spokes_turb       0.3   Sets the randomness of the web spokes
  web_circles_turb      0.5   Sets the randomness of the web circles

Setting web_type to 1 gives web circles composed of straight threads
(this is the quickest to parse and render).  Settings web_type to 2
gives web circles composed of threads that curve towards the centre
of the web, while setting web_type to 3 makes the threads hang
downwards.  The amount of curvature for web types 2 and 3 can be
controlled using the thread_tightness option (note that very small
values, eg. < 0.1, will not work well for the thread_tightness option).

*************************************************************************/

// CHECK VARIABLES AND ASSIGN DEFAULTS
// ***********************************
   #declare _SW_tempver = version; #version 3.0;
   #ifndef (web_type) #declare web_type = 2; #end
   #ifndef (web_radius) #declare web_radius = 10; #end
   #ifndef (web_spokes_count) #declare web_spokes_count = 8; #end
   #ifndef (web_circles_count) #declare web_circles_count = 4; #end
   #ifndef (web_circles_radius) #declare web_circles_radius = web_radius * .8; #end
   #ifndef (thread_thickness) #declare thread_thickness = .05; #end
   #ifndef (thread_tightness) #declare thread_tightness = .5; #end
   #ifndef (web_seed) #declare web_seed = 0; #end
   #ifndef (web_spokes_turb) #declare web_spokes_turb = .3; #end
   #ifndef (web_circles_turb) #declare web_circles_turb = .5; #end

// CREATE WEB AS CSG UNION
// ***********************
   #declare _SW_rand = seed(web_seed);
   union {

// CREATE WEB SPOKES
// *****************
   #declare _SW_spokeint = 360 / web_spokes_count;
   #declare _SW_rot = 0; #while (_SW_rot < 360)
      cylinder {<0, 0, 0>, y * web_radius, thread_thickness
         rotate z * (_SW_rot + ((rand(_SW_rand) - .5) * web_spokes_turb * _SW_spokeint))
         }
   #declare _SW_rot = _SW_rot + _SW_spokeint; #end

// CREATE WEB CIRCLES
// ******************
   #declare _SW_rand2 = seed(web_seed);
   #declare _SW_circleint = web_circles_radius / web_circles_count;
   #declare _SW_circlerad = _SW_circleint; #while (_SW_circlerad <= web_circles_radius)
      #declare _SW_rand = seed(web_seed);
      #declare _SW_spoke0rot = (_SW_rot + ((rand(_SW_rand) - .5) * web_spokes_turb * _SW_spokeint));
      #declare _SW_point0 = y * (_SW_circlerad + ((rand(_SW_rand2) - .5) * web_circles_turb * _SW_circleint));
      #declare _SW_point0 = vrotate(_SW_point0, z * _SW_spoke0rot);

      #declare _SW_spoke1rot = _SW_spoke0rot #declare _SW_point1 = _SW_point0;
      #declare _SW_rot = _SW_spokeint; #while (_SW_rot < 360)
         #declare _SW_spoke2rot = (_SW_rot + ((rand(_SW_rand) - .5) * web_spokes_turb * _SW_spokeint));
         #declare _SW_point2 = y * (_SW_circlerad + ((rand(_SW_rand2) - .5) * web_circles_turb * _SW_circleint));
         #declare _SW_point2 = vrotate(_SW_point2, z * _SW_spoke2rot);

// USE CYLINDERS FOR WEB TYPE 1
// ****************************
         #if (web_type = 1)
            cylinder {_SW_point1, _SW_point2, thread_thickness}

// USE CLIPPED TORII FOR WEB TYPES 2 AND 3
// ***************************************
         #else
            #declare _SW_normal = vnormalize(vcross(_SW_point2 - _SW_point1, z));
            #if (web_type = 3) #if (_SW_normal.y < 0) #declare _SW_normal = -_SW_normal; #end #end
            #declare _SW_midpoint = (_SW_point1 + _SW_point2) / 2;
            #declare _SW_centre = _SW_midpoint + (_SW_normal * vlength(_SW_point2 - _SW_point1) * thread_tightness * 2);
            torus {vlength(_SW_centre - _SW_point1), thread_thickness
               rotate x * 90 translate _SW_centre
               clipped_by {sphere {_SW_midpoint, vlength(_SW_point1 - _SW_midpoint)}}
               }
         #end
         #declare _SW_spoke1rot = _SW_spoke2rot;
         #declare _SW_point1 = _SW_point2;
      #declare _SW_rot = _SW_rot + _SW_spokeint; #end

// CLOSE WEB CIRCLES
// *****************
      #declare _SW_point2 = _SW_point0;
      #if (web_type = 1) cylinder {_SW_point1, _SW_point2, thread_thickness}
      #else #declare _SW_normal = vnormalize(vcross(_SW_point2 - _SW_point1, z));
         #if (web_type = 3) #if (_SW_normal.y < 0) #declare _SW_normal = -_SW_normal; #end #end
         #declare _SW_midpoint = (_SW_point1 + _SW_point2) / 2;
         #declare _SW_centre = _SW_midpoint + (_SW_normal * vlength(_SW_point2 - _SW_point1) * thread_tightness * 2);
         torus {vlength(_SW_centre - _SW_point1), thread_thickness
            rotate x * 90 translate _SW_centre
            clipped_by {sphere {_SW_midpoint, vlength(_SW_point1 - _SW_midpoint)}}
            } #end
   #declare _SW_circlerad = _SW_circlerad + _SW_circleint; #end

// DEFAULT TEXTURE FOR WEB
// ***********************
   texture {pigment {rgb <1, 1, 1>} finish {phong .2 phong_size 10}}}

// REDECLARE NEW WEB_SEED AND RESET VERSION
// ****************************************
   #declare web_seed = rand(_SW_rand) * 1e6;
   #version _SW_tempver;
