#VRML V2.0 utf8

PROTO SuperRevolver
#
# works at least with SGI Cosmo Player 2.1.5, cc3dglut 4.3
#
# A VRML Proto to account the data of a SuperRevolver shape with scripting 
# (slow)
# Copyright (C) 2008 J. "MUFTI" Scheurich
#
# Developed from NodeNurbsSurface.cpp of the vrml97 editor dune 
# Copyright (C) 1999 Stephen F. White
#
# exampe use
#
# EXTERNPROTO SuperRevolver
#    [
#    exposedField SFFloat a 
#    exposedField SFFloat b 
#    exposedField SFFloat m 
#    exposedField SFFloat n1 
#    exposedField SFFloat n2 
#    exposedField SFFloat n3 
#    exposedField SFFloat border
#    exposedField SFFloat bottomBorder
#    exposedField SFInt32 superTessellation 
#    exposedField SFInt32 nurbsTessellation 
#    exposedField MFVec2f controlPoint   
#    exposedField MFFloat weight          
#    field        MFFloat knot           
#    field        SFInt32 order          
#    field        SFFloat creaseAngle 
#    field        SFBool  ccw
#    field        SFBool  solid
#    field        SFBool  pieceOfCake
#    ]
# [
# "SuperRevolverPROTO.wrl"
# ]
# 
# Transform 
#   {
#   children 
#     [
#     Shape 
#       {
#       appearance       Appearance 
#         {
#         material     Material 
#           {
#           }
#         }
#       geometry       SuperExtrusion 
#         {
#         a 1
#         b 1
#         m 3
#         n1 0.100000
#         n2 1.700000
#         n3 1.700000
#         controlPoint
#           [
#           0 0 0 
#           0.895434 0.871842 0 
#           0 2 0 
#           0.938359 2.971822 0 
#           -2.918766e-2 3.925251 0.251201 
#           ]
#         weight 
#           [
#           1 
#           1 
#           1 
#           1 
#           1 
#           ]
#         knot 
#           [
#           0 
#           0 
#           0 
#           1 
#           2 
#           3 
#           3 
#           3 
#           ]
#         }
#       }
#     ]
#   }
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see the file "COPYING" for details); if 
# not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
# Cambridge, MA 02139, USA.
#
   [
   exposedField SFFloat a 1
   exposedField SFFloat b 1
   exposedField SFFloat m 0
   exposedField SFFloat n1 1
   exposedField SFFloat n2 1
   exposedField SFFloat n3 1
   exposedField SFFloat border 3.14159265358979323846
   exposedField SFFloat bottomBorder -3.14159265358979323846
   exposedField SFInt32 superTessellation 0
   exposedField SFInt32 nurbsTessellation 0    # (-&infin;,&infin;)
   exposedField MFVec2f controlPoint    []     # (&infin;,&infin;)
   exposedField MFFloat weight          []     # (0,&infin;)
   field        MFFloat knot           []     # (-&infin;,&infin;)
   field        SFInt32 order          3      # [2,&infin;) 
   field        SFFloat creaseAngle 0.78539816339744830962
   field        SFBool  ccw FALSE
   field        SFBool  solid TRUE
   field        SFBool  pieceOfCake FALSE
   ]
{

    DEF IndexedFaceSet1 IndexedFaceSet 
      {
      coord DEF Coordinate1 Coordinate 
        {
        }
      creaseAngle IS creaseAngle
      solid IS solid
      ccw IS ccw
      convex FALSE
      }
    
    Switch 
      {
      choice 
        [
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF A_CONTAINER TextureTransform 
              {
              rotation IS a
              }
            }
          }
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF B_CONTAINER TextureTransform 
              {
              rotation IS b
              }
            }
          }
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF M_CONTAINER TextureTransform 
              {
              rotation IS m
              }
            }
          }
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF N1_CONTAINER TextureTransform 
              {
              rotation IS n1
              }
            }
          }
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF N2_CONTAINER TextureTransform 
              {
              rotation IS n2
              }
            }
          }
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF N3_CONTAINER TextureTransform 
              {
              rotation IS n3
              }
            }
          }
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF BORDER_CONTAINER TextureTransform 
              {
              rotation IS border
              }
            }
          }
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF BOTTOM_BORDER_CONTAINER TextureTransform 
              {
              rotation IS bottomBorder
              }
            }
          }
        Shape 
          {
          geometry IndexedFaceSet
            {
            texCoord DEF NURBS_CONTROLPOINT_CONTAINER 
              TextureCoordinate { point IS controlPoint } 
            }
          }
        DEF SUPER_TESSELLATION_CONTAINER Switch 
          {
          whichChoice IS superTessellation
          }
        DEF NURBS_WEIGHT_CONTAINER ScalarInterpolator
          {
          # same number of key and keyvalue....
          key IS weight
          keyValue IS weight
          }
        DEF NURBS_TESSELLATION_CONTAINER Switch 
          {
          whichChoice IS nurbsTessellation
          }
        ]
      }
       
    DEF Script1 Script 
      {
      eventOut MFVec3f vertices_out
      eventOut MFInt32 coordIndex_out

      field SFBool pieceOfCake IS pieceOfCake

      field MFVec3f vert []
      field MFInt32 ci []

      field SFFloat a 1
      field SFFloat b 1
      field SFFloat m 0
      field SFFloat n1 1
      field SFFloat n2 1
      field SFFloat n3 1

      field MFFloat r1 []
      field MFFloat c1 []
      field MFFloat s1 []

      eventIn SFFloat a_in
      eventIn SFFloat b_in
      eventIn SFFloat m_in
      eventIn SFFloat n1_in
      eventIn SFFloat n2_in
      eventIn SFFloat n3_in

      field SFFloat border 3.14159265358979323846
      eventIn SFFloat border_in
      field SFFloat bottomBorder 3.14159265358979323846
      eventIn SFFloat bottomBorder_in

      eventIn SFInt32 nurbsTessellation_in 
      field SFInt32 nurbsTessellation 0
      eventIn SFInt32 superTessellation_in 
      field SFInt32 superTessellation 0

      field SFNode aContainer USE A_CONTAINER
      field SFNode bContainer USE B_CONTAINER
      field SFNode mContainer USE M_CONTAINER
      field SFNode n1Container USE N1_CONTAINER
      field SFNode n2Container USE N2_CONTAINER
      field SFNode n3Container USE N3_CONTAINER

      field SFNode borderContainer USE BORDER_CONTAINER
      field SFNode bottomborderContainer USE BOTTOM_BORDER_CONTAINER

      field SFNode superTessContainer USE SUPER_TESSELLATION_CONTAINER
    
      field SFNode nurbsTessContainer USE NURBS_TESSELLATION_CONTAINER
    
      field SFNode controlPoint_container USE NURBS_CONTROLPOINT_CONTAINER
      eventIn MFVec2f controlPoint_in
      field MFVec3f controlPoint [] 

      field SFNode weight_container USE NURBS_WEIGHT_CONTAINER
      eventIn MFFloat weight_in
      field MFFloat weight []
    
      field MFFloat knot IS knot
      field SFInt32 order IS order
    
      field MFFloat weights []
      eventOut MFVec3f tess
      field MFVec2f tc []
    
      field MFFloat basis []
      field MFFloat deriv []
    
      field SFVec3f S 0 0 0
      field SFVec3f du 0 0 0
    
      field SFVec3f n 0 0 0
    
      field MFFloat left []
      field MFFloat right []
    
      field SFInt32 dimension 0

      url 
        [
        "javascript:
    
        function r(angle, a, b, m, n1, n2, n3)
           {
           var f;
           var c;
           var s;
           f=m*angle/4.0;
           c=Math.cos(f);
           s=Math.sin(f);
           return Math.pow(Math.pow(Math.abs(c/a),n2)+Math.pow(Math.abs(s/b),n3),-1.0/n1);
           }
    
        function account()
           {
           var superTess;
           var nurbsTess;
           var inc1;
           var angle1;
           var index;
           var cindex;
           var a1;
           var a2;
           var x;
           var y;
           var z;
           var sidesClosed;
           var closed;

           index = 0;
           cindex = 0;
           sidesClosed = false;

           superTess=(superTessellation==0)?17:superTessellation+1;
           nurbsTess=(nurbsTessellation==0)?17:nurbsTessellation+1;

           inc1=(border-bottomBorder)/(superTess-1);

           if (border!=(Math.PI/2.0))
              if (bottomBorder!=(-Math.PI/2.0))
                 if (pieceOfCake)
                    sidesClosed=true;

           low=bottomBorder;
           high=border;
           if (high<low) 
              {
              temp=high;
              high=low;
              low=temp;
              }
 
           angle1=bottomBorder;
           for (a1=0;a1<superTess;a1++)
              {
              r1[a1]=r(angle1,a,b,m,n1,n2,n3);
              c1[a1]=Math.cos(angle1);
              s1[a1]=Math.sin(angle1);
              angle1+=inc1;
              }


           for (a2 = 0; a2 < nurbsTess; a2++) 
              {
              for (a1 = 0; a1 < superTess; a1++) 
                 {
                 x = tess[a2].x * r1[a1] * c1[a1];
                 y = tess[a2].y;
                 z = tess[a2].x * r1[a1] * s1[a1];
                 vert[index].x = x;
                 vert[index].y = y;
                 vert[index].z = z;
                 index++;
                 n1 = a1 + 1;
                 closed = false;
                 if (n1 == superTess) 
                    {
                    n1 = 0;
                    if (sidesClosed)
                       closed = true;
                    }
                 n2 = a2 + 1;
                 if (n2 < nurbsTess) 
                    {
                    if (closed) 
                       {
                       ci[cindex++] = -1;
                       ci[cindex++] = -1;
                       ci[cindex++] = -1;
                       ci[cindex++] = -1;
                       ci[cindex++] = -1;
                       } 
                    else 
                       {
                       ci[cindex++] = a1 + n2 * superTess;
                       ci[cindex++] = n1 + n2 * superTess;
                       ci[cindex++] = n1 + a2 * superTess;
                       ci[cindex++] = a1 + a2 * superTess;
                       ci[cindex++] = -1;
                       }
                    }
                 }
              } 
           if (sidesClosed) 
              {
              var highest;
              var lowest;
              var lastIndex;
              var y;
              var i;

              highest = tess[tess.length - 1].y;
              lowest = tess[0].y;
              if (lowest > highest) 
                 {
                 highest = tess[0].y;
                 lowest = tess[tess.length - 1].y;
                 }
              lastIndex = cindex;
              for (i = 0; i < tess.length; i++)
                 {
                 y = tess[i].y;
                 if (y > highest)
                    y = highest;
                 if (y < lowest)
                    y = lowest;
                 vert[nurbsTess * superTess + i].x = 0;
                 vert[nurbsTess * superTess + i].y = y;
                 vert[nurbsTess * superTess + i].z = 0;
                 ci[cindex++] = nurbsTess * superTess + i;
              }
              for (i = 0; i < tess.length; i++) 
                 ci[cindex++] = superTess * i + (superTess - 1);
              ci[cindex++] = -1;
              for (i = tess.length - 1; i >= 0; i--) 
                 ci[cindex++] = nurbsTess * superTess + i;
              for (i = tess.length - 1; i >= 0; i--) 
                 ci[cindex++] = superTess * i;
              ci[cindex++] = -1;
              }
           coordIndex_out = ci;
           vertices_out = vert;
           }
    
         
        function findSpan(dimension, order, u, knots)
           {
           var low;
           var mid;
           var high;
           var n;
    
           n = dimension + order - 1;
    
           if (u >= knots[n]) 
              {
              return n - order;
              }
           low = order - 1;    high = n - order + 1;
    
           mid = (low + high) / 2;
    
           while (u < knots[mid] || u >= knots[mid+1]) 
              {
              if (u < knots[mid])
                 high = mid;
              else
                 low = mid;
              mid = (low+high)/2;
              }
           return Math.floor(mid);
           }
    
        function basisFuns(span, u, order, knots, basis, deriv)
           {
           var j;
           var saved;
           var dsaved;
           var r;
           var temp;
    
           basis[0] = 1.0;
           for (j = 1; j < order; j++) 
              {
              left[j] = u - knots[span+1-j];
              right[j] = knots[span+j]-u;
              saved = 0.0;
              dsaved = 0.0;
              for (r = 0; r < j; r++) 
                 {
                 temp = basis[r] / (right[r+1] + left[j-r]);
                 basis[r] = saved + right[r+1] * temp;
                 deriv[r] = dsaved - j * temp;
                 saved = left[j-r] * temp;
                 dsaved = j * temp;
                 }
              basis[j] = saved;
              deriv[j] = dsaved;
              }
           }
    
    
        function linePoint(weight,u,ind)
           {
           var i;
           var j;
    
           var span;
  
           var base;
   
           var index;
  
           var w;
           var dw;
    
           var gain;
           var dgain;
    
           span = findSpan(dimension, order, u, knot);
    
           basisFuns(span, u, order, knot, basis, deriv);
    
           base = span-order+1;
    
           index = base;
    
           S=new SFVec3f(0.0, 0.0, 0.0);
           du=new SFVec3f(0.0, 0.0, 0.0);
           dv=new SFVec3f(0.0, 0.0, 0.0);
           w = 0.0;
           dw = 0.0;
           for (i = 0; i < order; i++) 
              {
              gain = basis[i];
              dgain = deriv[i];
              S.x += controlPoint[index].x * gain;
              S.y += controlPoint[index].y * gain;
              S.z += controlPoint[index].z * gain;
              w += weight[index] * gain;
              du.x += controlPoint[index].x * dgain;
              du.y += controlPoint[index].y * dgain;
              du.z += controlPoint[index].z * dgain;
              dw += weight[index] * dgain;
              index++;
              }
           S.x = S.x / w;
           S.y = S.y / w;
           S.z = S.z / w;
           n.x = (du.x - S.x * dw) / w;
           n.y = (du.y - S.y * dw) / w;
           n.z = (du.z - S.z * dw) / w;
           return S;
           }
    
        function makeLine()
           {
           var size;
           var i;
           var j;
           var index;
           var u;
           var inv;
           var inc;
           var uTess;        
    
           var tess_inc;
    
           var u=0;
           index=0;
    
           weights = new MFFloat();
       
           dimension = controlPoint.length;
    
           if (dimension == 0) return;
    
           if (knot.length != order + dimension) 
              {
              print('no NurbsCurve: knot.length!=order+dimension');
              return;
              }
       
           if (weight.length == 0) 
              {
              weights = new MFFloat();
              for (i = 0; i < dimension; i++)
                  weights[i] = 1.0;
              } 
           else if (weight.length != dimension) 
              {
              print('no NurbsCurve: weight.length!=dimension');
              return;
              }
       
           uTess=nurbsTessellation;
    
           // from the orignal white_dune sources
           //       if (uTess <= 0) uTess = 32;
    
           // changed to increase performance
           if (uTess <= 0) uTess = 16;
    
           tess = new MFVec3f();
    
           size = (uTess + 1);
       
           inc = (knot[knot.length-1] - knot[0]) / uTess;
       
           index = 0;
           w = (weight.length == 0) ? weights : weight;
           for (i = 0, u = knot[0]; i <= uTess; i++) 
              {
              tess[index] = linePoint(w,u,index);
              index++;
              u += inc;
              }
           account();
           }
    
        function controlPoint_in(value, time)
           {
           for (i = 0; i < value.length; i++) 
              {
              controlPoint[i].x=value[i].x;
              controlPoint[i].y=value[i].y;
              }
           makeLine();
           }    
    
        function weight_in(value, time)
           {
           weight=value;
           makeLine();
           }
        
        function nurbsTessellation_in(value, time)
           {
           nurbsTessellation=value;
           makeLine();
           }
           
        function a_in(value)
           {
           a = value;
           account();
           }
      
        function b_in(value)
           {
           b = value;
           account();
           }
      
        function m_in(value)
           {
           m = value;
           account();
           }
  
        function n1_in(value)
           {
           n1 = value;
           account();
           }
  
        function n2_in(value)
           {
           n2 = value;
           account();
           }
      
        function n3_in(value)
           {
           n3 = value;
           account();
           }
  
        function border_in(value)
           {
           border = value;
           account();
           }
  
        function superTessellation_in(value)
           {
           superTessellation = value;
           account();
           }

        function initialize()
           {
           a=aContainer.rotation;
           b=bContainer.rotation;
           m=mContainer.rotation;
           n1=n1Container.rotation;
           n2=n2Container.rotation;
           n3=n3Container.rotation;
           border=borderContainer.rotation;
           border=bottomborderContainer.rotation;
           superTessellation=superTessContainer.whichChoice;

           nurbsTessellation=nurbsTessContainer.whichChoice;
           for (i = 0; i < controlPoint_container.point.length; i++) 
              {
              controlPoint[i].x=controlPoint_container.point[i].x;
              controlPoint[i].y=controlPoint_container.point[i].y;
              controlPoint[i].z=0;
              }
           weight=weight_container.key;
           makeLine();
           }
        "
        ]
     }

   ROUTE A_CONTAINER.rotation TO Script1.a_in
   ROUTE B_CONTAINER.rotation TO Script1.b_in
   ROUTE M_CONTAINER.rotation TO Script1.m_in
   ROUTE N1_CONTAINER.rotation TO Script1.n1_in
   ROUTE N2_CONTAINER.rotation TO Script1.n2_in
   ROUTE N3_CONTAINER.rotation TO Script1.n3_in
    
   ROUTE SUPER_TESSELLATION_CONTAINER.whichChoice TO Script1.superTessellation_in
   ROUTE NURBS_TESSELLATION_CONTAINER.whichChoice TO Script1.nurbsTessellation_in
    
   ROUTE NURBS_CONTROLPOINT_CONTAINER.point TO Script1.controlPoint_in
   ROUTE NURBS_WEIGHT_CONTAINER.keyValue TO Script1.weight_in

   ROUTE Script1.vertices_out TO Coordinate1.set_point
   ROUTE Script1.coordIndex_out TO IndexedFaceSet1.set_coordIndex
}

