#VRML V2.0 utf8

PROTO NurbsCurveAnimator
#
# works at least with 
#
# A VRML Proto to account the data for a PositionInterpolator and a 
# OrientationInterpolator from NurbsCurve data by scripting 
# (slow)
# Copyright (C) 2006 J. "MUFTI" Scheurich
#
# Developed from NodeNurbsSurface.cpp of the vrml97 editor dune 
# Copyright (C) 1999 Stephen F. White
#
# exampe use
#
# EXTERNPROTO NurbsCurveAnimator
#    [
#    eventIn      SFFloat    set_fraction
#    eventOut     SFVec3f    positionValue_changed
#    eventOut     SFRotation rotationValue_changed
#    eventOut     SFFloat    currentSpeedFraction
#    exposedField SFFloat    currentSpeedMultiplikator
#    exposedField SFVec3f    upAxis
#    exposedField SFNode     controlPoint    
#    exposedField SFInt32    tessellation 
#    exposedField MFFloat    weight          
#    field        MFFloat    knot           
#    field        SFInt32    order          
#    field        SFBool     closed
#    ]
# [
# "NurbsCurveAnimatorPROTO.wrl"
# ]
# 
# NurbsCurveAnimator 
#   {
#   tessellation 32
#   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.
#
   [
   eventIn      SFFloat    set_fraction
   eventOut     SFVec3f    positionValue_changed
   eventOut     SFRotation rotationValue_changed
   eventOut     SFFloat    currentSpeedFraction
   exposedField SFFloat    currentSpeedMultiplikator
   exposedField SFVec3f    upAxis
   exposedField SFNode     controlPoint    
   exposedField SFInt32    tessellation 
   exposedField MFFloat    weight          
   field        MFFloat    knot           
   field        SFInt32    order          
   field        SFBool     closed
   exposedField SFBool     showWay
   ]
{
    Switch 
      {
      choice 
        [
        Shape 
          {
          appearance       Appearance 
            {
            textureTransform DEF SPEED_MULTIPLICATOR_CONTAINER TextureTransform 
              {
              rotation IS currentSpeedMultiplikator
              }
            }
          }
        ]
      }
    
    Switch 
      {
      choice 
        [
        Shape 
          {
          geometry DEF NURBS_CONTROLPOINT_CONTAINER PointSet 
	    {
            coord IS controlPoint
	    }
          }
        ]
      }
       
    DEF TESSELLATION_CONTAINER Switch 
      {
      whichChoice IS tessellation
      }
    
    DEF NURBS_WEIGHT_CONTAINER ScalarInterpolator
      {
      # same number of key and keyvalue....
      key IS weight
      keyValue IS weight
      }


    
ROUTE SUPER_TESSELLATION_CONTAINER.whichChoice TO Script1.superTessellation_in
    
ROUTE Script1.crossSection_out TO Extrusion1.set_crossSection

Switch 
  {
  choice 
    [
    Shape 
      {
      geometry PointSet 
	{
        coord DEF NURBS_CONTROLPOINT_CONTAINER 
              Coordinate { point IS controlPoint } 
	}
      }
    DEF NURBS_TESSELLATION_CONTAINER Switch 
      {
      whichChoice IS spineTessellation
      }
    Shape 
      {
      geometry IndexedFaceSet 
	{
        texCoord DEF SCALE_CONTAINER 
              TextureCoordinate { point IS scale } 
	}
      }
    ]
  }

DEF NURBS_SCRIPT Script 
  {
  directOutput TRUE  

  field SFNode controlPoint_container USE NURBS_CONTROLPOINT_CONTAINER
  eventIn MFVec3f controlPoint_in
  eventOut MFVec3f controlPoint_out 
  field MFVec3f controlPoint [] 

  field SFNode tessellation_container USE NURBS_TESSELLATION_CONTAINER
  eventIn SFInt32 tessellation_in 
  eventOut SFInt32 tessellation_out 
  field SFInt32 Tessellation 0

  field SFNode weight_container USE NURBS_WEIGHT_CONTAINER
  eventIn MFFloat weight_in
  eventOut MFFloat weight_out
  field MFFloat weight []

  field MFFloat knot IS knot
  field SFInt32 order IS order

  field MFFloat weights []
  field MFVec3f tess []
  eventOut MFVec3f position_keyValue
  eventOut MFRotation rotation_keyValue
  
  field MFFloat w []
  field MFVec2f tc []

  field MFFloat basis []
  field MFFloat deriv []

  field SFVec3f S 0 0 0
  field SFVec3f u 0 0 0

  field SFVec3f n 0 0 0

  field MFFloat left []
  field MFFloat right []

  field SFInt32 dimension 0

      eventIn SFFloat currentSpeedMultiplikator_in
      field SFFloat currentSpeedMultiplikator 1
      field SFNode currentSpeedMultiplikatorContainer USE SPEED_MULTIPLIKATOR_CONTAINER

      eventIn SFInt32 tessellation_in 
      field SFInt32 tessellation 0
      field SFNode tesselationContainer USE TESSELLATION_CONTAINER
      url 
        [
        "javascript:

     function currentSpeedMultiplikator_in(value)
        {
        currentSpeedMultiplikator = value;
        }

     function tessellation_in(value)
        {
        tessellation = value;
        account();
        }

    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 scale_next_index;
       var tess_inc;
       var scale_inc;
       var scale_diff_x;
       var scale_diff_y;

       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=tessellation;

// 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++, u += inc) {
   	   tess[index] = linePoint(w,u,index);
   	   index++;
       }
       for (i = 0; i < index; i++)
           position_keyValue[i] = tess[index];
    }

    function initialize()
       {
       controlPoint=controlPoint_container.point;
       weight=weight_container.key;
       tessellation=tessellation_container.whichChoice;
       scale=scale_container.point;
       makeLine();
       }

    function controlPoint_in(value, time)
       {
       controlPoint=value;
       controlPoint_out=value;
       makeLine();
       }    

    function weight_in(value, time)
       {
       weight=value;
       weight_out=value;
       makeLine();
       }
    
    function tessellation_in(value, time)
       {
       tessellation=value;
       tessellation_out=value;
       makeLine();
       }

    function scale_in(value, time)
       {
       scale=value;
       makeLine();
       }
    "
   ]
   }

   ROUTE NURBS_CONTROLPOINT_CONTAINER.coord TO Script1.controlPoint_container_in
   ROUTE SPEED_MULTIPLIKATOR_CONTAINER.rotation TO Script1.currentSpeedMultiplikator_in

   ROUTE NURBS_CONTROLPOINT_CONTAINER.point TO NURBS_SCRIPT.controlPoint_in
   ROUTE NURBS_WEIGHT_CONTAINER.keyValue TO NURBS_SCRIPT.weight_in
   ROUTE NURBS_TESSELLATION_CONTAINER.whichChoice TO NURBS_SCRIPT.tessellation_in

   ROUTE NURBS_SCRIPT.controlPoint_container_out TO NURBS_CONTROLPOINT_CONTAINER.coord
   ROUTE NURBS_SCRIPT.currentSpeedMultiplikator_out TO SPEED_MULTIPLIKATOR_CONTAINER.rotation 


   ROUTE NURBS_SCRIPT.controlPoint_out TO NURBS_CONTROLPOINT_CONTAINER.point
   ROUTE NURBS_SCRIPT.weight_out TO NURBS_WEIGHT_CONTAINER.keyValue
   ROUTE NURBS_SCRIPT.tessellation_out TO NURBS_TESSELLATION_CONTAINER.whichChoice

   ROUTE NURBS_SCRIPT.tess TO Extrusion1.set_spine
   ROUTE NURBS_SCRIPT.scale_out TO Extrusion1.set_scale
}

