e0b2efb3a255364b09b44645de3381cf9653694c
[blender.git] / source / gameengine / Ketsji / KX_ConstraintActuator.cpp
1 /**
2  * Apply a constraint to a position or rotation value
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include "SCA_IActuator.h"
33 #include "KX_ConstraintActuator.h"
34 #include "SCA_IObject.h"
35 #include "MT_Point3.h"
36 #include "MT_Matrix3x3.h"
37 #include "KX_GameObject.h"
38 #include "KX_RayCast.h"
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 /* ------------------------------------------------------------------------- */
45 /* Native functions                                                          */
46 /* ------------------------------------------------------------------------- */
47
48 KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, 
49                                                                                          int posDampTime,
50                                                                                          int rotDampTime,
51                                                                                          float minBound,
52                                                                                          float maxBound,
53                                                                                          float refDir[3],
54                                                                                          int locrotxyz,
55                                                                                          int time,
56                                                                                          int option,
57                                                                                          char *property,
58                                                                                          PyTypeObject* T) : 
59         m_refDirection(refDir),
60         m_currentTime(0),
61         SCA_IActuator(gameobj, T)
62 {
63         m_posDampTime = posDampTime;
64         m_rotDampTime = rotDampTime;
65         m_locrot   = locrotxyz;
66         m_option = option;
67         m_activeTime = time;
68         if (property) {
69                 strncpy(m_property, property, sizeof(m_property));
70                 m_property[sizeof(m_property)-1] = 0;
71         } else {
72                 m_property[0] = 0;
73         }
74         /* The units of bounds are determined by the type of constraint. To      */
75         /* make the constraint application easier and more transparent later on, */
76         /* I think converting the bounds to the applicable domain makes more     */
77         /* sense.                                                                */
78         switch (m_locrot) {
79         case KX_ACT_CONSTRAINT_ORIX:
80         case KX_ACT_CONSTRAINT_ORIY:
81         case KX_ACT_CONSTRAINT_ORIZ:
82                 {
83                         MT_Scalar len = m_refDirection.length();
84                         if (MT_fuzzyZero(len)) {
85                                 // missing a valid direction
86                                 std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no valid reference direction!" << std::endl;
87                                 m_locrot = KX_ACT_CONSTRAINT_NODEF;
88                         } else {
89                                 m_refDirection /= len;
90                         }
91                 }
92                 break;
93         default:
94                 m_minimumBound = minBound;
95                 m_maximumBound = maxBound;
96                 break;
97         }
98
99 } /* End of constructor */
100
101 KX_ConstraintActuator::~KX_ConstraintActuator()
102
103         // there's nothing to be done here, really....
104 } /* end of destructor */
105
106 bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
107 {
108
109         KX_GameObject* hitKXObj = client->m_gameobject;
110         
111         if (client->m_type > KX_ClientObjectInfo::ACTOR)
112         {
113                 // false hit
114                 return false;
115         }
116         bool bFound = false;
117
118         if (m_property[0] == 0)
119         {
120                 bFound = true;
121         }
122         else
123         {
124                 if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
125                 {
126                         if (client->m_auxilary_info)
127                         {
128                                 bFound = !strcmp(m_property, ((char*)client->m_auxilary_info));
129                         }
130                 }
131                 else
132                 {
133                         bFound = hitKXObj->GetProperty(m_property) != NULL;
134                 }
135         }
136
137         return bFound;
138 }
139
140 bool KX_ConstraintActuator::Update(double curtime, bool frame)
141 {
142
143         bool result = false;    
144         bool bNegativeEvent = IsNegativeEvent();
145         RemoveAllEvents();
146
147         if (!bNegativeEvent) {
148                 /* Constraint clamps the values to the specified range, with a sort of    */
149                 /* low-pass filtered time response, if the damp time is unequal to 0.     */
150
151                 /* Having to retrieve location/rotation and setting it afterwards may not */
152                 /* be efficient enough... Somthing to look at later.                      */
153                 KX_GameObject  *obj = (KX_GameObject*) GetParent();
154                 MT_Point3    position = obj->NodeGetWorldPosition();
155                 MT_Point3    newposition;
156                 MT_Vector3   direction;
157                 MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
158                 MT_Scalar    filter, newdistance;
159                 int axis, sign;
160
161                 if (m_posDampTime) {
162                         filter = m_posDampTime/(1.0+m_posDampTime);
163                 }
164                 switch (m_locrot) {
165                 case KX_ACT_CONSTRAINT_ORIX:
166                 case KX_ACT_CONSTRAINT_ORIY:
167                 case KX_ACT_CONSTRAINT_ORIZ:
168                         switch (m_locrot) {
169                         case KX_ACT_CONSTRAINT_ORIX:
170                                 direction[0] = rotation[0][0];
171                                 direction[1] = rotation[1][0];
172                                 direction[2] = rotation[2][0];
173                                 axis = 0;
174                                 break;
175                         case KX_ACT_CONSTRAINT_ORIY:
176                                 direction[0] = rotation[0][1];
177                                 direction[1] = rotation[1][1];
178                                 direction[2] = rotation[2][1];
179                                 axis = 1;
180                                 break;
181                         default:
182                                 direction[0] = rotation[0][2];
183                                 direction[1] = rotation[1][2];
184                                 direction[2] = rotation[2][2];
185                                 axis = 2;
186                                 break;
187                         }
188                         if (m_posDampTime) {
189                                 // apply damping on the direction
190                                 direction = filter*direction + (1.0-filter)*m_refDirection;
191                         } else {
192                                 direction = m_refDirection;
193                         }
194                         obj->AlignAxisToVect(direction, axis);
195                         result = true;
196                         goto CHECK_TIME;
197                 case KX_ACT_CONSTRAINT_DIRPX:
198                 case KX_ACT_CONSTRAINT_DIRPY:
199                 case KX_ACT_CONSTRAINT_DIRPZ:
200                 case KX_ACT_CONSTRAINT_DIRMX:
201                 case KX_ACT_CONSTRAINT_DIRMY:
202                 case KX_ACT_CONSTRAINT_DIRMZ:
203                         switch (m_locrot) {
204                         case KX_ACT_CONSTRAINT_DIRPX:
205                                 direction[0] = rotation[0][0];
206                                 direction[1] = rotation[1][0];
207                                 direction[2] = rotation[2][0];
208                                 axis = 0;               // axis according to KX_GameObject::AlignAxisToVect()
209                                 sign = 1;               // X axis will be anti parrallel to normal
210                                 break;
211                         case KX_ACT_CONSTRAINT_DIRPY:
212                                 direction[0] = rotation[0][1];
213                                 direction[1] = rotation[1][1];
214                                 direction[2] = rotation[2][1];
215                                 axis = 1;
216                                 sign = 1;
217                                 break;
218                         case KX_ACT_CONSTRAINT_DIRPZ:
219                                 direction[0] = rotation[0][2];
220                                 direction[1] = rotation[1][2];
221                                 direction[2] = rotation[2][2];
222                                 axis = 2;
223                                 sign = 1;
224                                 break;
225                         case KX_ACT_CONSTRAINT_DIRMX:
226                                 direction[0] = -rotation[0][0];
227                                 direction[1] = -rotation[1][0];
228                                 direction[2] = -rotation[2][0];
229                                 axis = 0;
230                                 sign = 0;
231                                 break;
232                         case KX_ACT_CONSTRAINT_DIRMY:
233                                 direction[0] = -rotation[0][1];
234                                 direction[1] = -rotation[1][1];
235                                 direction[2] = -rotation[2][1];
236                                 axis = 1;
237                                 sign = 0;
238                                 break;
239                         case KX_ACT_CONSTRAINT_DIRMZ:
240                                 direction[0] = -rotation[0][2];
241                                 direction[1] = -rotation[1][2];
242                                 direction[2] = -rotation[2][2];
243                                 axis = 2;
244                                 sign = 0;
245                                 break;
246                         }
247                         direction.normalize();
248                         {
249                                 MT_Point3 topoint = position + (m_maximumBound) * direction;
250                                 MT_Point3 resultpoint;
251                                 MT_Vector3 resultnormal;
252                                 PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
253                                 KX_IPhysicsController *spc = obj->GetPhysicsController();
254
255                                 if (!pe) {
256                                         std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no physics environment!" << std::endl;
257                                         goto CHECK_TIME;
258                                 }        
259                                 if (!spc) {
260                                         // the object is not physical, we probably want to avoid hitting its own parent
261                                         KX_GameObject *parent = obj->GetParent();
262                                         if (parent) {
263                                                 spc = parent->GetPhysicsController();
264                                                 parent->Release();
265                                         }
266                                 }
267                                 result = KX_RayCast::RayTest(spc, pe, position, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_ConstraintActuator>(this));
268
269                                 if (result)     {
270                                         // compute new position & orientation
271                                         if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
272                                                 // if none option is set, the actuator does nothing but detect ray 
273                                                 // (works like a sensor)
274                                                 goto CHECK_TIME;
275                                         }
276                                         if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
277                                                 // the new orientation must be so that the axis is parallel to normal
278                                                 if (sign)
279                                                         resultnormal = -resultnormal;
280                                                 // apply damping on the direction
281                                                 if (m_rotDampTime) {
282                                                         MT_Scalar rotFilter = 1.0/(1.0+m_rotDampTime);
283                                                         resultnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*resultnormal;
284                                                 } else if (m_posDampTime) {
285                                                         resultnormal = -filter*direction + (1.0-filter)*resultnormal;
286                                                 }
287                                                 obj->AlignAxisToVect(resultnormal, axis);
288                                                 direction = -resultnormal;
289                                         }
290                                         if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
291                                                 if (m_posDampTime) {
292                                                         newdistance = filter*(position-resultpoint).length()+(1.0-filter)*m_minimumBound;
293                                                 } else {
294                                                         newdistance = m_minimumBound;
295                                                 }
296                                         } else {
297                                                 newdistance = (position-resultpoint).length();
298                                         }
299                                         newposition = resultpoint-newdistance*direction;
300                                 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
301                                         // no contact but still keep running
302                                         result = true;
303                                         goto CHECK_TIME;
304                                 }
305                         }
306                         break; 
307                 case KX_ACT_CONSTRAINT_LOCX:
308                 case KX_ACT_CONSTRAINT_LOCY:
309                 case KX_ACT_CONSTRAINT_LOCZ:
310                         newposition = position;
311                         switch (m_locrot) {
312                         case KX_ACT_CONSTRAINT_LOCX:
313                                 Clamp(newposition[0], m_minimumBound, m_maximumBound);
314                                 break;
315                         case KX_ACT_CONSTRAINT_LOCY:
316                                 Clamp(newposition[1], m_minimumBound, m_maximumBound);
317                                 break;
318                         case KX_ACT_CONSTRAINT_LOCZ:
319                                 Clamp(newposition[2], m_minimumBound, m_maximumBound);
320                                 break;
321                         }
322                         result = true;
323                         if (m_posDampTime) {
324                                 newposition = filter*position + (1.0-filter)*newposition;
325                         }
326                         break;
327                 }
328                 if (result) {
329                         // set the new position but take into account parent if any
330                         obj->NodeSetWorldPosition(newposition);
331                 }
332         CHECK_TIME:
333                 if (result && m_activeTime > 0 ) {
334                         if (++m_currentTime >= m_activeTime)
335                                 result = false;
336                 }
337         }
338         if (!result) {
339                 m_currentTime = 0;
340         }
341         return result;
342 } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime)   */
343
344 void KX_ConstraintActuator::Clamp(MT_Scalar &var, 
345                                                                   float min, 
346                                                                   float max) {
347         if (var < min) {
348                 var = min;
349         } else if (var > max) {
350                 var = max;
351         }
352 }
353
354
355 bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) 
356 {
357         bool res = false;
358
359         if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
360                 res = true;
361         }
362
363         return res;
364 }
365
366 /* ------------------------------------------------------------------------- */
367 /* Python functions                                                          */
368 /* ------------------------------------------------------------------------- */
369
370 /* Integration hooks ------------------------------------------------------- */
371 PyTypeObject KX_ConstraintActuator::Type = {
372         PyObject_HEAD_INIT(&PyType_Type)
373         0,
374         "KX_ConstraintActuator",
375         sizeof(KX_ConstraintActuator),
376         0,
377         PyDestructor,
378         0,
379         __getattr,
380         __setattr,
381         0, //&MyPyCompare,
382         __repr,
383         0, //&cvalue_as_number,
384         0,
385         0,
386         0,
387         0
388 };
389
390 PyParentObject KX_ConstraintActuator::Parents[] = {
391         &KX_ConstraintActuator::Type,
392         &SCA_IActuator::Type,
393         &SCA_ILogicBrick::Type,
394         &CValue::Type,
395         NULL
396 };
397
398 PyMethodDef KX_ConstraintActuator::Methods[] = {
399         {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc},
400         {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_VARARGS, GetDamp_doc},
401         {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, SetRotDamp_doc},
402         {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_VARARGS, GetRotDamp_doc},
403         {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, SetDirection_doc},
404         {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_VARARGS, GetDirection_doc},
405         {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, SetOption_doc},
406         {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_VARARGS, GetOption_doc},
407         {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, SetTime_doc},
408         {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_VARARGS, GetTime_doc},
409         {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
410         {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
411         {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
412         {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc},
413         {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetDistance_doc},
414         {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetDistance_doc},
415         {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
416         {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc},
417         {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetRayLength_doc},
418         {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetRayLength_doc},
419         {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
420         {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc},
421         {NULL,NULL} //Sentinel
422 };
423
424 PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) {
425         _getattr_up(SCA_IActuator);
426 }
427
428 /* 2. setDamp                                                                */
429 char KX_ConstraintActuator::SetDamp_doc[] = 
430 "setDamp(duration)\n"
431 "\t- duration: integer\n"
432 "\tSets the time constant of the orientation and distance constraint.\n"
433 "\tIf the duration is negative, it is set to 0.\n";
434 PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, 
435                                                                                    PyObject* args, 
436                                                                                    PyObject* kwds) {
437         int dampArg;
438         if(!PyArg_ParseTuple(args, "i", &dampArg)) {
439                 return NULL;            
440         }
441         
442         m_posDampTime = dampArg;
443         if (m_posDampTime < 0) m_posDampTime = 0;
444
445         Py_Return;
446 }
447 /* 3. getDamp                                                                */
448 char KX_ConstraintActuator::GetDamp_doc[] = 
449 "getDamp()\n"
450 "\tReturns the damping parameter.\n";
451 PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self, 
452                                                                                    PyObject* args, 
453                                                                                    PyObject* kwds){
454         return PyInt_FromLong(m_posDampTime);
455 }
456
457 /* 2. setRotDamp                                                                */
458 char KX_ConstraintActuator::SetRotDamp_doc[] = 
459 "setRotDamp(duration)\n"
460 "\t- duration: integer\n"
461 "\tSets the time constant of the orientation constraint.\n"
462 "\tIf the duration is negative, it is set to 0.\n";
463 PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self, 
464                                                                                       PyObject* args, 
465                                                                                       PyObject* kwds) {
466         int dampArg;
467         if(!PyArg_ParseTuple(args, "i", &dampArg)) {
468                 return NULL;            
469         }
470         
471         m_rotDampTime = dampArg;
472         if (m_rotDampTime < 0) m_rotDampTime = 0;
473
474         Py_Return;
475 }
476 /* 3. getRotDamp                                                                */
477 char KX_ConstraintActuator::GetRotDamp_doc[] = 
478 "getRotDamp()\n"
479 "\tReturns the damping time for application of the constraint.\n";
480 PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self, 
481                                                                                       PyObject* args, 
482                                                                                       PyObject* kwds){
483         return PyInt_FromLong(m_rotDampTime);
484 }
485
486 /* 2. setDirection                                                                */
487 char KX_ConstraintActuator::SetDirection_doc[] = 
488 "setDirection(vector)\n"
489 "\t- vector: 3-tuple\n"
490 "\tSets the reference direction in world coordinate for the orientation constraint.\n";
491 PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self, 
492                                                                                         PyObject* args, 
493                                                                                         PyObject* kwds) {
494         float x, y, z;
495         MT_Scalar len;
496         MT_Vector3 dir;
497
498         if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) {
499                 return NULL;            
500         }
501         dir[0] = x;
502         dir[1] = y;
503         dir[2] = z;
504         len = dir.length();
505         if (MT_fuzzyZero(len)) {
506                 std::cout << "Invalid direction" << std::endl;
507                 return NULL;
508         }
509         m_refDirection = dir/len;
510
511         Py_Return;
512 }
513 /* 3. getDirection                                                                */
514 char KX_ConstraintActuator::GetDirection_doc[] = 
515 "getDirection()\n"
516 "\tReturns the reference direction of the orientation constraint as a 3-tuple.\n";
517 PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self, 
518                                                                                         PyObject* args, 
519                                                                                         PyObject* kwds){
520         PyObject *retVal = PyList_New(3);
521
522         PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0]));
523         PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1]));
524         PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2]));
525         return retVal;
526 }
527
528 /* 2. setOption                                                                */
529 char KX_ConstraintActuator::SetOption_doc[] = 
530 "setOption(option)\n"
531 "\t- option: integer\n"
532 "\tSets several options of the distance  constraint.\n"
533 "\tBinary combination of the following values:\n"
534 "\t\t 64 : Activate alignment to surface\n"
535 "\t\t128 : Detect material rather than property\n"
536 "\t\t256 : No deactivation if ray does not hit target\n"
537 "\t\t512 : Activate distance control\n";
538 PyObject* KX_ConstraintActuator::PySetOption(PyObject* self, 
539                                                                                      PyObject* args, 
540                                                                                      PyObject* kwds) {
541         int option;
542         if(!PyArg_ParseTuple(args, "i", &option)) {
543                 return NULL;            
544         }
545         
546         m_option = option;
547
548         Py_Return;
549 }
550 /* 3. getOption                                                              */
551 char KX_ConstraintActuator::GetOption_doc[] = 
552 "getOption()\n"
553 "\tReturns the option parameter.\n";
554 PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self, 
555                                                                                      PyObject* args, 
556                                                                                      PyObject* kwds){
557         return PyInt_FromLong(m_option);
558 }
559
560 /* 2. setTime                                                                */
561 char KX_ConstraintActuator::SetTime_doc[] = 
562 "setTime(duration)\n"
563 "\t- duration: integer\n"
564 "\tSets the activation time of the actuator.\n"
565 "\tThe actuator disables itself after this many frame.\n"
566 "\tIf set to 0 or negative, the actuator is not limited in time.\n";
567 PyObject* KX_ConstraintActuator::PySetTime(PyObject* self, 
568                                                                                    PyObject* args, 
569                                                                                    PyObject* kwds) {
570         int t;
571         if(!PyArg_ParseTuple(args, "i", &t)) {
572                 return NULL;            
573         }
574         
575         if (t < 0)
576                 t = 0;
577         m_activeTime = t;
578
579         Py_Return;
580 }
581 /* 3. getTime                                                                */
582 char KX_ConstraintActuator::GetTime_doc[] = 
583 "getTime()\n"
584 "\tReturns the time parameter.\n";
585 PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self, 
586                                                                                    PyObject* args, 
587                                                                                    PyObject* kwds){
588         return PyInt_FromLong(m_activeTime);
589 }
590
591 /* 2. setProperty                                                                */
592 char KX_ConstraintActuator::SetProperty_doc[] = 
593 "setProperty(property)\n"
594 "\t- property: string\n"
595 "\tSets the name of the property or material for the ray detection of the distance constraint.\n"
596 "\tIf empty, the ray will detect any collisioning object.\n";
597 PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self, 
598                                                                                        PyObject* args, 
599                                                                                        PyObject* kwds) {
600         char *property;
601         if (!PyArg_ParseTuple(args, "s", &property)) {
602                 return NULL;
603         }
604         if (property == NULL) {
605                 m_property[0] = 0;
606         } else {
607                 strncpy(m_property, property, sizeof(m_property));
608                 m_property[sizeof(m_property)-1] = 0;
609         }
610
611         Py_Return;
612 }
613 /* 3. getProperty                                                                */
614 char KX_ConstraintActuator::GetProperty_doc[] = 
615 "getProperty()\n"
616 "\tReturns the property parameter.\n";
617 PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self, 
618                                                                                        PyObject* args, 
619                                                                                        PyObject* kwds){
620         return PyString_FromString(m_property);
621 }
622
623 /* 4. setDistance                                                                 */
624 char KX_ConstraintActuator::SetDistance_doc[] = 
625 "setDistance(distance)\n"
626 "\t- distance: float\n"
627 "\tSets the target distance in distance constraint\n";
628 /* 4. setMin                                                                 */
629 char KX_ConstraintActuator::SetMin_doc[] = 
630 "setMin(lower_bound)\n"
631 "\t- lower_bound: float\n"
632 "\tSets the lower value of the interval to which the value\n"
633 "\tis clipped.\n";
634 PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, 
635                                                                                   PyObject* args, 
636                                                                                   PyObject* kwds) {
637         float minArg;
638         if(!PyArg_ParseTuple(args, "f", &minArg)) {
639                 return NULL;            
640         }
641
642         switch (m_locrot) {
643         default:
644                 m_minimumBound = minArg;
645                 break;
646         case KX_ACT_CONSTRAINT_ROTX:
647         case KX_ACT_CONSTRAINT_ROTY:
648         case KX_ACT_CONSTRAINT_ROTZ:
649                 m_minimumBound = MT_radians(minArg);
650                 break;
651         }
652
653         Py_Return;
654 }
655 /* 5. getDistance                                                                 */
656 char KX_ConstraintActuator::GetDistance_doc[] = 
657 "getDistance()\n"
658 "\tReturns the distance parameter \n";
659 /* 5. getMin                                                                 */
660 char KX_ConstraintActuator::GetMin_doc[] = 
661 "getMin()\n"
662 "\tReturns the lower value of the interval to which the value\n"
663 "\tis clipped.\n";
664 PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self, 
665                                                                                   PyObject* args, 
666                                                                                   PyObject* kwds) {
667         return PyFloat_FromDouble(m_minimumBound);
668 }
669
670 /* 6. setRayLength                                                                 */
671 char KX_ConstraintActuator::SetRayLength_doc[] = 
672 "setRayLength(length)\n"
673 "\t- length: float\n"
674 "\tSets the maximum ray length of the distance constraint\n";
675 /* 6. setMax                                                                 */
676 char KX_ConstraintActuator::SetMax_doc[] = 
677 "setMax(upper_bound)\n"
678 "\t- upper_bound: float\n"
679 "\tSets the upper value of the interval to which the value\n"
680 "\tis clipped.\n";
681 PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, 
682                                                                                   PyObject* args, 
683                                                                                   PyObject* kwds){
684         float maxArg;
685         if(!PyArg_ParseTuple(args, "f", &maxArg)) {
686                 return NULL;            
687         }
688
689         switch (m_locrot) {
690         default:
691                 m_maximumBound = maxArg;
692                 break;
693         case KX_ACT_CONSTRAINT_ROTX:
694         case KX_ACT_CONSTRAINT_ROTY:
695         case KX_ACT_CONSTRAINT_ROTZ:
696                 m_maximumBound = MT_radians(maxArg);
697                 break;
698         }
699
700         Py_Return;
701 }
702 /* 7. getRayLength                                                                 */
703 char KX_ConstraintActuator::GetRayLength_doc[] = 
704 "getRayLength()\n"
705 "\tReturns the length of the ray\n";
706 /* 7. getMax                                                                 */
707 char KX_ConstraintActuator::GetMax_doc[] = 
708 "getMax()\n"
709 "\tReturns the upper value of the interval to which the value\n"
710 "\tis clipped.\n";
711 PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self, 
712                                                                                   PyObject* args, 
713                                                                                   PyObject* kwds) {
714         return PyFloat_FromDouble(m_maximumBound);
715 }
716
717
718 /* This setter/getter probably for the constraint type                       */
719 /* 8. setLimit                                                               */
720 char KX_ConstraintActuator::SetLimit_doc[] = 
721 "setLimit(type)\n"
722 "\t- type: integer\n"
723 "\t  1  : LocX\n"
724 "\t  2  : LocY\n"
725 "\t  3  : LocZ\n"
726 "\t  7  : Distance along +X axis\n"
727 "\t  8  : Distance along +Y axis\n"
728 "\t  9  : Distance along +Z axis\n"
729 "\t  10 : Distance along -X axis\n"
730 "\t  11 : Distance along -Y axis\n"
731 "\t  12 : Distance along -Z axis\n"
732 "\t  13 : Align X axis\n"
733 "\t  14 : Align Y axis\n"
734 "\t  15 : Align Z axis\n"
735 "\tSets the type of constraint.\n";
736 PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, 
737                                                                                         PyObject* args, 
738                                                                                         PyObject* kwds) {
739         int locrotArg;
740         if(!PyArg_ParseTuple(args, "i", &locrotArg)) {
741                 return NULL;            
742         }
743         
744         if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg;
745
746         Py_Return;
747 }
748 /* 9. getLimit                                                               */
749 char KX_ConstraintActuator::GetLimit_doc[] = 
750 "getLimit()\n"
751 "\tReturns the type of constraint.\n";
752 PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self, 
753                                                                                         PyObject* args, 
754                                                                                         PyObject* kwds) {
755         return PyInt_FromLong(m_locrot);
756 }
757
758 /* eof */