Blender  V2.59
KX_ConstraintActuator.cpp
Go to the documentation of this file.
00001 /*
00002  * Apply a constraint to a position or rotation value
00003  *
00004  * $Id: KX_ConstraintActuator.cpp 35171 2011-02-25 13:35:59Z jesterking $
00005  *
00006  * ***** BEGIN GPL LICENSE BLOCK *****
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software Foundation,
00020  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021  *
00022  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00023  * All rights reserved.
00024  *
00025  * The Original Code is: all of this file.
00026  *
00027  * Contributor(s): none yet.
00028  *
00029  * ***** END GPL LICENSE BLOCK *****
00030  */
00031 
00037 #include "SCA_IActuator.h"
00038 #include "KX_ConstraintActuator.h"
00039 #include "SCA_IObject.h"
00040 #include "MT_Point3.h"
00041 #include "MT_Matrix3x3.h"
00042 #include "KX_GameObject.h"
00043 #include "KX_RayCast.h"
00044 #include "KX_PythonInit.h" // KX_GetActiveScene
00045 
00046 #include <stdio.h>
00047 
00048 /* ------------------------------------------------------------------------- */
00049 /* Native functions                                                          */
00050 /* ------------------------------------------------------------------------- */
00051 
00052 KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, 
00053                                                                                          int posDampTime,
00054                                                                                          int rotDampTime,
00055                                                                                          float minBound,
00056                                                                                          float maxBound,
00057                                                                                          float refDir[3],
00058                                                                                          int locrotxyz,
00059                                                                                          int time,
00060                                                                                          int option,
00061                                                                                          char *property) :
00062         SCA_IActuator(gameobj, KX_ACT_CONSTRAINT),
00063         m_refDirVector(refDir),
00064         m_currentTime(0)
00065 {
00066         m_refDirection[0] = refDir[0];
00067         m_refDirection[1] = refDir[1];
00068         m_refDirection[2] = refDir[2];
00069         m_posDampTime = posDampTime;
00070         m_rotDampTime = rotDampTime;
00071         m_locrot   = locrotxyz;
00072         m_option = option;
00073         m_activeTime = time;
00074         if (property) {
00075                 m_property = property;
00076         } else {
00077                 m_property = "";
00078         }
00079         /* The units of bounds are determined by the type of constraint. To      */
00080         /* make the constraint application easier and more transparent later on, */
00081         /* I think converting the bounds to the applicable domain makes more     */
00082         /* sense.                                                                */
00083         switch (m_locrot) {
00084         case KX_ACT_CONSTRAINT_ORIX:
00085         case KX_ACT_CONSTRAINT_ORIY:
00086         case KX_ACT_CONSTRAINT_ORIZ:
00087                 {
00088                         MT_Scalar len = m_refDirVector.length();
00089                         if (MT_fuzzyZero(len)) {
00090                                 // missing a valid direction
00091                                 std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no valid reference direction!" << std::endl;
00092                                 m_locrot = KX_ACT_CONSTRAINT_NODEF;
00093                         } else {
00094                                 m_refDirection[0] /= len;
00095                                 m_refDirection[1] /= len;
00096                                 m_refDirection[2] /= len;
00097                                 m_refDirVector /= len;
00098                         }
00099                         m_minimumBound = cos(minBound);
00100                         m_maximumBound = cos(maxBound);
00101                         m_minimumSine = sin(minBound);
00102                         m_maximumSine = sin(maxBound);
00103                 }
00104                 break;
00105         default:
00106                 m_minimumBound = minBound;
00107                 m_maximumBound = maxBound;
00108                 m_minimumSine = 0.f;
00109                 m_maximumSine = 0.f;
00110                 break;
00111         }
00112 
00113 } /* End of constructor */
00114 
00115 KX_ConstraintActuator::~KX_ConstraintActuator()
00116 { 
00117         // there's nothing to be done here, really....
00118 } /* end of destructor */
00119 
00120 bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
00121 {
00122 
00123         m_hitObject = client->m_gameobject;
00124         
00125         bool bFound = false;
00126 
00127         if (m_property.IsEmpty())
00128         {
00129                 bFound = true;
00130         }
00131         else
00132         {
00133                 if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
00134                 {
00135                         if (client->m_auxilary_info)
00136                         {
00137                                 bFound = !strcmp(m_property.Ptr(), ((char*)client->m_auxilary_info));
00138                         }
00139                 }
00140                 else
00141                 {
00142                         bFound = m_hitObject->GetProperty(m_property) != NULL;
00143                 }
00144         }
00145         // update the hit status
00146         result->m_hitFound = bFound;
00147         // stop looking
00148         return true;
00149 }
00150 
00151 /* this function is used to pre-filter the object before casting the ray on them.
00152    This is useful for "X-Ray" option when we want to see "through" unwanted object.
00153  */
00154 bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client)
00155 {
00156         if (client->m_type > KX_ClientObjectInfo::ACTOR)
00157         {
00158                 // Unknown type of object, skip it.
00159                 // Should not occur as the sensor objects are filtered in RayTest()
00160                 printf("Invalid client type %d found in ray casting\n", client->m_type);
00161                 return false;
00162         }
00163         // no X-Ray function yet
00164         return true;
00165 }
00166 
00167 bool KX_ConstraintActuator::Update(double curtime, bool frame)
00168 {
00169 
00170         bool result = false;    
00171         bool bNegativeEvent = IsNegativeEvent();
00172         RemoveAllEvents();
00173 
00174         if (!bNegativeEvent) {
00175                 /* Constraint clamps the values to the specified range, with a sort of    */
00176                 /* low-pass filtered time response, if the damp time is unequal to 0.     */
00177 
00178                 /* Having to retrieve location/rotation and setting it afterwards may not */
00179                 /* be efficient enough... Somthing to look at later.                      */
00180                 KX_GameObject  *obj = (KX_GameObject*) GetParent();
00181                 MT_Point3    position = obj->NodeGetWorldPosition();
00182                 MT_Point3    newposition;
00183                 MT_Vector3   normal, direction, refDirection;
00184                 MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
00185                 MT_Scalar    filter, newdistance, cosangle;
00186                 int axis, sign;
00187 
00188                 if (m_posDampTime) {
00189                         filter = m_posDampTime/(1.0+m_posDampTime);
00190                 } else {
00191                         filter = 0.0;
00192                 }
00193                 switch (m_locrot) {
00194                 case KX_ACT_CONSTRAINT_ORIX:
00195                 case KX_ACT_CONSTRAINT_ORIY:
00196                 case KX_ACT_CONSTRAINT_ORIZ:
00197                         switch (m_locrot) {
00198                         case KX_ACT_CONSTRAINT_ORIX:
00199                                 direction[0] = rotation[0][0];
00200                                 direction[1] = rotation[1][0];
00201                                 direction[2] = rotation[2][0];
00202                                 axis = 0;
00203                                 break;
00204                         case KX_ACT_CONSTRAINT_ORIY:
00205                                 direction[0] = rotation[0][1];
00206                                 direction[1] = rotation[1][1];
00207                                 direction[2] = rotation[2][1];
00208                                 axis = 1;
00209                                 break;
00210                         default:
00211                                 direction[0] = rotation[0][2];
00212                                 direction[1] = rotation[1][2];
00213                                 direction[2] = rotation[2][2];
00214                                 axis = 2;
00215                                 break;
00216                         }
00217                         if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
00218                                 // reference direction needs to be evaluated
00219                                 // 1. get the cosine between current direction and target
00220                                 cosangle = direction.dot(m_refDirVector);
00221                                 if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
00222                                         // no change to do
00223                                         result = true;
00224                                         goto CHECK_TIME;
00225                                 }
00226                                 // 2. define a new reference direction
00227                                 //    compute local axis with reference direction as X and
00228                                 //    Y in direction X refDirection plane
00229                                 MT_Vector3 zaxis = m_refDirVector.cross(direction);
00230                                 if (MT_fuzzyZero2(zaxis.length2())) {
00231                                         // direction and refDirection are identical,
00232                                         // choose any other direction to define plane
00233                                         if (direction[0] < 0.9999)
00234                                                 zaxis = m_refDirVector.cross(MT_Vector3(1.0,0.0,0.0));
00235                                         else
00236                                                 zaxis = m_refDirVector.cross(MT_Vector3(0.0,1.0,0.0));
00237                                 }
00238                                 MT_Vector3 yaxis = zaxis.cross(m_refDirVector);
00239                                 yaxis.normalize();
00240                                 if (cosangle > m_minimumBound) {
00241                                         // angle is too close to reference direction,
00242                                         // choose a new reference that is exactly at minimum angle
00243                                         refDirection = m_minimumBound * m_refDirVector + m_minimumSine * yaxis;
00244                                 } else {
00245                                         // angle is too large, choose new reference direction at maximum angle
00246                                         refDirection = m_maximumBound * m_refDirVector + m_maximumSine * yaxis;
00247                                 }
00248                         } else {
00249                                 refDirection = m_refDirVector;
00250                         }
00251                         // apply damping on the direction
00252                         direction = filter*direction + (1.0-filter)*refDirection;
00253                         obj->AlignAxisToVect(direction, axis);
00254                         result = true;
00255                         goto CHECK_TIME;
00256                 case KX_ACT_CONSTRAINT_DIRPX:
00257                 case KX_ACT_CONSTRAINT_DIRPY:
00258                 case KX_ACT_CONSTRAINT_DIRPZ:
00259                 case KX_ACT_CONSTRAINT_DIRNX:
00260                 case KX_ACT_CONSTRAINT_DIRNY:
00261                 case KX_ACT_CONSTRAINT_DIRNZ:
00262                         switch (m_locrot) {
00263                         case KX_ACT_CONSTRAINT_DIRPX:
00264                                 normal[0] = rotation[0][0];
00265                                 normal[1] = rotation[1][0];
00266                                 normal[2] = rotation[2][0];
00267                                 axis = 0;               // axis according to KX_GameObject::AlignAxisToVect()
00268                                 sign = 0;               // X axis will be parrallel to direction of ray
00269                                 break;
00270                         case KX_ACT_CONSTRAINT_DIRPY:
00271                                 normal[0] = rotation[0][1];
00272                                 normal[1] = rotation[1][1];
00273                                 normal[2] = rotation[2][1];
00274                                 axis = 1;
00275                                 sign = 0;
00276                                 break;
00277                         case KX_ACT_CONSTRAINT_DIRPZ:
00278                                 normal[0] = rotation[0][2];
00279                                 normal[1] = rotation[1][2];
00280                                 normal[2] = rotation[2][2];
00281                                 axis = 2;
00282                                 sign = 0;
00283                                 break;
00284                         case KX_ACT_CONSTRAINT_DIRNX:
00285                                 normal[0] = -rotation[0][0];
00286                                 normal[1] = -rotation[1][0];
00287                                 normal[2] = -rotation[2][0];
00288                                 axis = 0;
00289                                 sign = 1;
00290                                 break;
00291                         case KX_ACT_CONSTRAINT_DIRNY:
00292                                 normal[0] = -rotation[0][1];
00293                                 normal[1] = -rotation[1][1];
00294                                 normal[2] = -rotation[2][1];
00295                                 axis = 1;
00296                                 sign = 1;
00297                                 break;
00298                         case KX_ACT_CONSTRAINT_DIRNZ:
00299                                 normal[0] = -rotation[0][2];
00300                                 normal[1] = -rotation[1][2];
00301                                 normal[2] = -rotation[2][2];
00302                                 axis = 2;
00303                                 sign = 1;
00304                                 break;
00305                         }
00306                         normal.normalize();
00307                         if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
00308                                 // direction of the ray is along the local axis
00309                                 direction = normal;
00310                         } else {
00311                                 switch (m_locrot) {
00312                                 case KX_ACT_CONSTRAINT_DIRPX:
00313                                         direction = MT_Vector3(1.0,0.0,0.0);
00314                                         break;
00315                                 case KX_ACT_CONSTRAINT_DIRPY:
00316                                         direction = MT_Vector3(0.0,1.0,0.0);
00317                                         break;
00318                                 case KX_ACT_CONSTRAINT_DIRPZ:
00319                                         direction = MT_Vector3(0.0,0.0,1.0);
00320                                         break;
00321                                 case KX_ACT_CONSTRAINT_DIRNX:
00322                                         direction = MT_Vector3(-1.0,0.0,0.0);
00323                                         break;
00324                                 case KX_ACT_CONSTRAINT_DIRNY:
00325                                         direction = MT_Vector3(0.0,-1.0,0.0);
00326                                         break;
00327                                 case KX_ACT_CONSTRAINT_DIRNZ:
00328                                         direction = MT_Vector3(0.0,0.0,-1.0);
00329                                         break;
00330                                 }
00331                         }
00332                         {
00333                                 MT_Point3 topoint = position + (m_maximumBound) * direction;
00334                                 PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment();
00335                                 KX_IPhysicsController *spc = obj->GetPhysicsController();
00336 
00337                                 if (!pe) {
00338                                         std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no physics environment!" << std::endl;
00339                                         goto CHECK_TIME;
00340                                 }        
00341                                 if (!spc) {
00342                                         // the object is not physical, we probably want to avoid hitting its own parent
00343                                         KX_GameObject *parent = obj->GetParent();
00344                                         if (parent) {
00345                                                 spc = parent->GetPhysicsController();
00346                                                 parent->Release();
00347                                         }
00348                                 }
00349                                 KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
00350                                 result = KX_RayCast::RayTest(pe, position, topoint, callback);
00351                                 if (result)     {
00352                                         MT_Vector3 newnormal = callback.m_hitNormal;
00353                                         // compute new position & orientation
00354                                         if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
00355                                                 // if none option is set, the actuator does nothing but detect ray 
00356                                                 // (works like a sensor)
00357                                                 goto CHECK_TIME;
00358                                         }
00359                                         if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
00360                                                 MT_Scalar rotFilter;
00361                                                 // apply damping on the direction
00362                                                 if (m_rotDampTime) {
00363                                                         rotFilter = m_rotDampTime/(1.0+m_rotDampTime);
00364                                                 } else {
00365                                                         rotFilter = filter;
00366                                                 }
00367                                                 newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal;
00368                                                 obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
00369                                                 if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
00370                                                         direction = newnormal;
00371                                                         direction.normalize();
00372                                                 }
00373                                         }
00374                                         if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
00375                                                 if (m_posDampTime) {
00376                                                         newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound;
00377                                                 } else {
00378                                                         newdistance = m_minimumBound;
00379                                                 }
00380                                                 // logically we should cancel the speed along the ray direction as we set the
00381                                                 // position along that axis
00382                                                 spc = obj->GetPhysicsController();
00383                                                 if (spc && spc->IsDyna()) {
00384                                                         MT_Vector3 linV = spc->GetLinearVelocity();
00385                                                         // cancel the projection along the ray direction
00386                                                         MT_Scalar fallspeed = linV.dot(direction);
00387                                                         if (!MT_fuzzyZero(fallspeed))
00388                                                                 spc->SetLinearVelocity(linV-fallspeed*direction,false);
00389                                                 }
00390                                         } else {
00391                                                 newdistance = (position-callback.m_hitPoint).length();
00392                                         }
00393                                         newposition = callback.m_hitPoint-newdistance*direction;
00394                                 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
00395                                         // no contact but still keep running
00396                                         result = true;
00397                                         goto CHECK_TIME;
00398                                 }
00399                         }
00400                         break; 
00401                 case KX_ACT_CONSTRAINT_FHPX:
00402                 case KX_ACT_CONSTRAINT_FHPY:
00403                 case KX_ACT_CONSTRAINT_FHPZ:
00404                 case KX_ACT_CONSTRAINT_FHNX:
00405                 case KX_ACT_CONSTRAINT_FHNY:
00406                 case KX_ACT_CONSTRAINT_FHNZ:
00407                         switch (m_locrot) {
00408                         case KX_ACT_CONSTRAINT_FHPX:
00409                                 normal[0] = -rotation[0][0];
00410                                 normal[1] = -rotation[1][0];
00411                                 normal[2] = -rotation[2][0];
00412                                 direction = MT_Vector3(1.0,0.0,0.0);
00413                                 break;
00414                         case KX_ACT_CONSTRAINT_FHPY:
00415                                 normal[0] = -rotation[0][1];
00416                                 normal[1] = -rotation[1][1];
00417                                 normal[2] = -rotation[2][1];
00418                                 direction = MT_Vector3(0.0,1.0,0.0);
00419                                 break;
00420                         case KX_ACT_CONSTRAINT_FHPZ:
00421                                 normal[0] = -rotation[0][2];
00422                                 normal[1] = -rotation[1][2];
00423                                 normal[2] = -rotation[2][2];
00424                                 direction = MT_Vector3(0.0,0.0,1.0);
00425                                 break;
00426                         case KX_ACT_CONSTRAINT_FHNX:
00427                                 normal[0] = rotation[0][0];
00428                                 normal[1] = rotation[1][0];
00429                                 normal[2] = rotation[2][0];
00430                                 direction = MT_Vector3(-1.0,0.0,0.0);
00431                                 break;
00432                         case KX_ACT_CONSTRAINT_FHNY:
00433                                 normal[0] = rotation[0][1];
00434                                 normal[1] = rotation[1][1];
00435                                 normal[2] = rotation[2][1];
00436                                 direction = MT_Vector3(0.0,-1.0,0.0);
00437                                 break;
00438                         case KX_ACT_CONSTRAINT_FHNZ:
00439                                 normal[0] = rotation[0][2];
00440                                 normal[1] = rotation[1][2];
00441                                 normal[2] = rotation[2][2];
00442                                 direction = MT_Vector3(0.0,0.0,-1.0);
00443                                 break;
00444                         }
00445                         normal.normalize();
00446                         {
00447                                 PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment();
00448                                 KX_IPhysicsController *spc = obj->GetPhysicsController();
00449 
00450                                 if (!pe) {
00451                                         std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no physics environment!" << std::endl;
00452                                         goto CHECK_TIME;
00453                                 }        
00454                                 if (!spc || !spc->IsDyna()) {
00455                                         // the object is not dynamic, it won't support setting speed
00456                                         goto CHECK_TIME;
00457                                 }
00458                                 m_hitObject = NULL;
00459                                 // distance of Fh area is stored in m_minimum
00460                                 MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
00461                                 KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
00462                                 result = KX_RayCast::RayTest(pe, position, topoint, callback);
00463                                 // we expect a hit object
00464                                 if (!m_hitObject)
00465                                         result = false;
00466                                 if (result)     
00467                                 {
00468                                         MT_Vector3 newnormal = callback.m_hitNormal;
00469                                         // compute new position & orientation
00470                                         MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius(); 
00471                                         // estimate the velocity of the hit point
00472                                         MT_Point3 relativeHitPoint;
00473                                         relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition());
00474                                         MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint);
00475                                         MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint;
00476                                         MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity);
00477                                         MT_Scalar springExtent = 1.0 - distance/m_minimumBound;
00478                                         // Fh force is stored in m_maximum
00479                                         MT_Scalar springForce = springExtent * m_maximumBound;
00480                                         // damping is stored in m_refDirection [0] = damping, [1] = rot damping
00481                                         MT_Scalar springDamp = relativeVelocityRay * m_refDirVector[0];
00482                                         MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction;
00483                                         if (m_option & KX_ACT_CONSTRAINT_NORMAL)
00484                                         {
00485                                                 newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction);
00486                                         }
00487                                         spc->SetLinearVelocity(newVelocity, false);
00488                                         if (m_option & KX_ACT_CONSTRAINT_DOROTFH)
00489                                         {
00490                                                 MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound;
00491                                                 MT_Vector3 angVelocity = spc->GetAngularVelocity();
00492                                                 // remove component that is parallel to normal
00493                                                 angVelocity -= angVelocity.dot(newnormal)*newnormal;
00494                                                 MT_Vector3 angDamp = angVelocity * ((m_refDirVector[1]>MT_EPSILON)?m_refDirVector[1]:m_refDirVector[0]);
00495                                                 spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false);
00496                                         }
00497                                 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
00498                                         // no contact but still keep running
00499                                         result = true;
00500                                 }
00501                                 // don't set the position with this constraint
00502                                 goto CHECK_TIME;
00503                         }
00504                         break; 
00505                 case KX_ACT_CONSTRAINT_LOCX:
00506                 case KX_ACT_CONSTRAINT_LOCY:
00507                 case KX_ACT_CONSTRAINT_LOCZ:
00508                         newposition = position = obj->GetSGNode()->GetLocalPosition();
00509                         switch (m_locrot) {
00510                         case KX_ACT_CONSTRAINT_LOCX:
00511                                 Clamp(newposition[0], m_minimumBound, m_maximumBound);
00512                                 break;
00513                         case KX_ACT_CONSTRAINT_LOCY:
00514                                 Clamp(newposition[1], m_minimumBound, m_maximumBound);
00515                                 break;
00516                         case KX_ACT_CONSTRAINT_LOCZ:
00517                                 Clamp(newposition[2], m_minimumBound, m_maximumBound);
00518                                 break;
00519                         }
00520                         result = true;
00521                         if (m_posDampTime) {
00522                                 newposition = filter*position + (1.0-filter)*newposition;
00523                         }
00524                         obj->NodeSetLocalPosition(newposition);
00525                         goto CHECK_TIME;
00526                 }
00527                 if (result) {
00528                         // set the new position but take into account parent if any
00529                         obj->NodeSetWorldPosition(newposition);
00530                 }
00531         CHECK_TIME:
00532                 if (result && m_activeTime > 0 ) {
00533                         if (++m_currentTime >= m_activeTime)
00534                                 result = false;
00535                 }
00536         }
00537         if (!result) {
00538                 m_currentTime = 0;
00539         }
00540         return result;
00541 } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime)   */
00542 
00543 void KX_ConstraintActuator::Clamp(MT_Scalar &var, 
00544                                                                   float min, 
00545                                                                   float max) {
00546         if (var < min) {
00547                 var = min;
00548         } else if (var > max) {
00549                 var = max;
00550         }
00551 }
00552 
00553 
00554 bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) 
00555 {
00556         bool res = false;
00557 
00558         if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
00559                 res = true;
00560         }
00561 
00562         return res;
00563 }
00564 
00565 #ifdef WITH_PYTHON
00566 
00567 /* ------------------------------------------------------------------------- */
00568 /* Python functions                                                          */
00569 /* ------------------------------------------------------------------------- */
00570 
00571 /* Integration hooks ------------------------------------------------------- */
00572 PyTypeObject KX_ConstraintActuator::Type = {
00573         PyVarObject_HEAD_INIT(NULL, 0)
00574         "KX_ConstraintActuator",
00575         sizeof(PyObjectPlus_Proxy),
00576         0,
00577         py_base_dealloc,
00578         0,
00579         0,
00580         0,
00581         0,
00582         py_base_repr,
00583         0,0,0,0,0,0,0,0,0,
00584         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00585         0,0,0,0,0,0,0,
00586         Methods,
00587         0,
00588         0,
00589         &SCA_IActuator::Type,
00590         0,0,0,0,0,0,
00591         py_base_new
00592 };
00593 
00594 PyMethodDef KX_ConstraintActuator::Methods[] = {
00595         {NULL,NULL} //Sentinel
00596 };
00597 
00598 PyAttributeDef KX_ConstraintActuator::Attributes[] = {
00599         KX_PYATTRIBUTE_INT_RW("damp",0,100,true,KX_ConstraintActuator,m_posDampTime),
00600         KX_PYATTRIBUTE_INT_RW("rotDamp",0,100,true,KX_ConstraintActuator,m_rotDampTime),
00601         KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK("direction",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_refDirection,3,pyattr_check_direction),
00602         KX_PYATTRIBUTE_INT_RW("option",0,0xFFFF,false,KX_ConstraintActuator,m_option),
00603         KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_ConstraintActuator,m_activeTime),
00604         KX_PYATTRIBUTE_STRING_RW("propName",0,32,true,KX_ConstraintActuator,m_property),
00605         KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound),
00606         KX_PYATTRIBUTE_FLOAT_RW("distance",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound),
00607         KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_maximumBound),
00608         KX_PYATTRIBUTE_FLOAT_RW("rayLength",0,2000.f,KX_ConstraintActuator,m_maximumBound),
00609         KX_PYATTRIBUTE_INT_RW("limit",KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF+1,KX_ConstraintActuator::KX_ACT_CONSTRAINT_MAX-1,false,KX_ConstraintActuator,m_locrot),
00610         { NULL }        //Sentinel
00611 };
00612 
00613 int KX_ConstraintActuator::pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
00614 {
00615         KX_ConstraintActuator* act = static_cast<KX_ConstraintActuator*>(self);
00616         MT_Vector3 dir(act->m_refDirection);
00617         MT_Scalar len = dir.length();
00618         if (MT_fuzzyZero(len)) {
00619                 PyErr_SetString(PyExc_ValueError, "actuator.direction = vec: KX_ConstraintActuator, invalid direction");
00620                 return 1;
00621         }
00622         act->m_refDirVector = dir/len;
00623         return 0;       
00624 }
00625 
00626 #endif
00627 
00628 /* eof */