Switch to side-by-side view

--- a
+++ b/Tools/ModelUtilities/KinematicLimits/KinLimit_template.any
@@ -0,0 +1,223 @@
+/* 
+HOW TO USE:
+
+Add `#include "../path/to/KinLimitsDriver_template.any"` in the beginning
+of your main file. Then create the `KinLimitsDriver` class inside Main.
+
+In the following example we add a limit driver to `MyKinematicMeasure`, which limits the 
+measures between -1 and 1. 
+
+```
+#include "../path/to/KinLimits_template.any"
+
+Main = {
+
+  KinLimitsDriver limit_driver(
+      KinMeasure = ..path.to.MyKinematicMeasure
+   ) = {
+     LowerLimit = -1;
+     HighLimit = 1;
+   }; 
+      
+```
+
+The class supports the following settings:
+
+|-----------------------|--------------|------------------------------------------------------------------------------|
+| Variable              | Type         |  Default                    | Desciption                                     |
+|-----------------------|--------------|------------------------------------------------------------------------------|
+| LowerLimit            | AnyFloat     |  -                          | The low limit of the driver                    |
+| HighLimit             | AnyFloat     |  -                          | The high limit of the driver                   |
+| DriverPhaseIn         | AnyFloat     |  0.1*(HighLimit-LowerLimit) | How fast the limits driver ramps up.           |
+| HighLimitHard         | AnyFloat     |  HighLimit + DriverPhaseIn  | Low limit where the driver is fully ramped up  |
+| LowerLimitHard        | AnyFloat     |  LowerLimit - DriverPhaseIn | High limit where the driver is fully ramped up |
+| ErrorAtHardLimit      | AnyFloat     |  1                          | The kinematic error at the hard limits         |
+| ErrorAtLowerHardLimit | AnyFloat     |  ErrorAtHardLimit           | The kinematic error at the lower hard limit    |
+| ErrorAtLowerHardLimit | AnyFloat     |  ErrorAtHardLimit           | The kinematic error at the high hard limit     |
+| MeasureConversion     | AnyFloat     |  1                          | Constant factor applied to the measure         |
+|-----------------------|--------------|------------------------------------------------------------------------------| 
+
+
+*/
+
+
+/*
+The class uses the builtin smoothramp function, to create a AnyFunInterpol function 
+which is used by the AnyKinFunComb1 class. 
+
+The smoothramp function is essentially this c++ function. 
+This is just half a smoother step function which continues liniearly when it
+reaches it steepest value. See https://en.wikipedia.org/wiki/Smoothstep
+
+float smoothramp(float edge0, float edge1, float x)
+{
+    // Scale, and clamp x to 0..1 range
+    x = clamp((x - edge0)/(2*(edge1 - edge0)), 0.0, 0.5);
+    // Evaluate polynomial
+    if (x < 0.5) {
+      return x*x*x*(x*(x*6 - 15) + 10)
+    }
+    else {
+      return 2*x - 0.5
+    };
+};
+*/
+#ifndef KINLIMIT_TEMPLATE_ANY
+#define KINLIMIT_TEMPLATE_ANY
+
+
+// The smoothramp function is not available in AMS 6 and below. 
+// This just defines an equallent implementation directly in AnyScript.
+#define KIN_LIMIT_SMOOTHRAMP_ANYSCRIPT(edge0, edge1, val) iffun(gtfun(((val)-(edge0))/(2*((edge1)-(edge0))), 0.5), -0.5+2*(((val)-(edge0))/(2*((edge1)-(edge0)))),\
+                                                mult(iffun(ltfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.0), 0*(val), iffun(gtfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.5),0*(val)+0.5, ((val)-(edge0))/(2*((edge1)-(edge0)))))\
+                                               ,mult(iffun(ltfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.0), 0*(val), iffun(gtfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.5),0*(val)+0.5, ((val)-(edge0))/(2*((edge1)-(edge0)))))\
+                                               ,mult(iffun(ltfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.0), 0*(val), iffun(gtfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.5),0*(val)+0.5, ((val)-(edge0))/(2*((edge1)-(edge0)))))\
+                                               ,(mult(iffun(ltfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.0), 0*(val), iffun(gtfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.5),0*(val)+0.5, ((val)-(edge0))/(2*((edge1)-(edge0)))))\
+                                               ,(iffun(ltfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.0), 0*(val), iffun(gtfun(((val)-(edge0))/(2*((edge1)-(edge0))),0.5),0*(val)+0.5, ((val)-(edge0))/(2*((edge1)-(edge0)))))\
+                                                *6 - 15)) + 10) )))\
+                                               )
+                                               
+#if ANYBODY_V1 >= 7
+#define KIN_LIMIT_SMOOTHRAMP smoothramp
+#else
+#define KIN_LIMIT_SMOOTHRAMP KIN_LIMIT_SMOOTHRAMP_ANYSCRIPT
+#endif
+                                               
+
+
+
+
+#class_template KinLimitsDriver(AnyKinMeasure& KinMeasure, _DEBUG=0) {
+
+  
+#var AnyVar LowerLimit; 
+#var AnyVar HighLimit;
+
+AnyInt LowerHighCheck = assert(gteqfun(HighLimit, LowerLimit), "HighLimit must be greater than LowLimit: " + CompleteNameOf(ObjGetParent(1)));
+  
+#var AnyVar DriverPhaseIn = 0.01*(HighLimit - LowerLimit) ;
+#var AnyVar LowerLimitHard= LowerLimit - DriverPhaseIn ;
+#var AnyVar HighLimitHard= HighLimit + DriverPhaseIn ;
+
+#var AnyVar ErrorAtHardLimit = 1;
+#var AnyVar ErrorAtLowerHardLimit = ErrorAtHardLimit;
+#var AnyVar ErrorAtHighHardLimit = ErrorAtHardLimit;
+
+#var AnyVar MeasureConversion = 1;
+
+/// Generates an non-equisample abscissa axis for the data. 
+/// Most points are clustered around the transition zones.
+AnyFunInterpol AbscissaFunction = 
+{
+  AnyFloat LowPhaseIn = abs(.LowerLimit-.LowerLimitHard);
+  AnyFloat HighPhaseIn = abs(.HighLimit-.HighLimitHard);
+  AnyFloat TotalRange = abs(.LowerLimitHard-.HighLimitHard) + 0*.LowerHighCheck; // force calculation of LowerHighCheck before error in interpolation function.
+
+  #var Type = Bspline;
+  #var BsplineOrder = 8;
+       
+  #var AnyMatrix M = {
+                      {0, .LowerLimitHard-1e1*LowPhaseIn-1e1*TotalRange},
+                      {80, .LowerLimitHard-1e1*LowPhaseIn},
+                      {160,  .LowerLimitHard},
+                      {490, .LowerLimit},
+                      {510, .HighLimit},
+                      {840, .HighLimitHard},
+                      {920, .HighLimitHard+1e1*HighPhaseIn},
+                      {999, .HighLimitHard+1e1*HighPhaseIn+1e1*TotalRange}                    
+                    };  
+
+                    
+  T    = M'[0];
+  Data = {M'[1]};
+};
+
+
+
+AnyFunInterpol JointLimitErrorFunction= 
+{  
+  Type = Bspline;
+  T = .AbscissaFunction(1.0*iarr(0,999))' ;
+  Data = {.ErrorAtLowerHardLimit*KIN_LIMIT_SMOOTHRAMP(.LowerLimit, .LowerLimitHard, T) + 
+          .ErrorAtHighHardLimit*KIN_LIMIT_SMOOTHRAMP(.HighLimit, .HighLimitHard, T)} ;
+};
+
+#if _DEBUG
+AnyFunInterpol &FT = JointLimitErrorFunction;
+AnyFloat Test = {FT (-10.0), FT( -5.0), FT (0.0), FT (5.0), FT (10.0)}; 
+AnyFloat test_fullrange = JointLimitErrorFunction(1.0*iarr(ceil(min(AbscissaFunction.M'[1])),floor(max(AbscissaFunction.M'[1]))))';
+AnyFloat range = iarr(0, 1000-1)*(HighLimitHard-LowerLimitHard)/(1000-1)+LowerLimitHard
+AnyFloat test_range = JointLimitErrorFunction(range)';
+#endif
+
+
+AnyKinMeasureFunComb1 JointLimitMeasure = {
+  AnyKinMeasureLinComb ConvertedMeasure = {
+    AnyKinMeasure& ref = ..KinMeasure;
+    Coef  = {{..MeasureConversion }};
+    OutDim = 1;
+  };
+  Functions = {&.JointLimitErrorFunction};
+};
+
+AnyKinEqSimpleDriver JointLimitDriver = 
+{
+  AnyKinMeasureFunComb1 & ref = .JointLimitMeasure;
+  #var DriverPos = {0};
+  #var DriverVel = {0};
+  Reaction.Type = {Off};
+  CType = {Soft};
+  AnyFunConst ConstFun = 
+  { 
+    #var Value = {1};
+  };
+  #var WeightFun = {&ConstFun};      
+};
+
+
+};
+
+
+
+#if ANYBODY_NAME_MAINFILE  == "KinLimit_template"
+
+
+Main = 
+{
+
+AnyStringVar test = ANYBODY_NAME_MAINFILE;
+
+AnyKinStudy Test_study =
+{
+  Gravity = {0,0,0.0};
+  tStart = 0;
+  tEnd = 100;
+  AnyFloat Smoothramp_buitin = smoothramp(40, 60,t);
+  AnyFloat Smoothramp_anyscript = KIN_LIMIT_SMOOTHRAMP_ANYSCRIPT(40, 60,t);
+  AnyFloat diff = Smoothramp_buitin- Smoothramp_anyscript;
+  
+  
+  AnyFolder test = 
+  {
+    #define DIFFMAT(N) arrcat(zeros(1,N-1), eye(N-1)')' - arrcat(eye(N-1)', zeros(1,N-1))'
+    AnyMatrix diffmat = DIFFMAT(101);
+    
+    AnyFloat Vec = .tArray;
+    
+    AnyFloat smoothramp_builtin = smoothramp(40, 60, Vec);
+    AnyFloat smoothramp_anyscript = KIN_LIMIT_SMOOTHRAMP_ANYSCRIPT(40, 60,Vec);
+
+    AnyFloat smoothramp_builtin_diff = diffmat*smoothramp_builtin';
+    AnyFloat smoothramp_anyscript_diff = diffmat*smoothramp_anyscript';
+  
+  
+  
+  
+  };
+};
+
+};
+
+#endif
+#endif
+