2 * Apply a constraint to a position or rotation value
6 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
22 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23 * All rights reserved.
25 * The Original Code is: all of this file.
27 * Contributor(s): none yet.
29 * ***** END GPL LICENSE BLOCK *****
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"
45 /* ------------------------------------------------------------------------- */
46 /* Native functions */
47 /* ------------------------------------------------------------------------- */
49 KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj,
60 SCA_IActuator(gameobj, T),
61 m_refDirVector(refDir),
64 m_refDirection[0] = refDir[0];
65 m_refDirection[1] = refDir[1];
66 m_refDirection[2] = refDir[2];
67 m_posDampTime = posDampTime;
68 m_rotDampTime = rotDampTime;
73 m_property = property;
77 /* The units of bounds are determined by the type of constraint. To */
78 /* make the constraint application easier and more transparent later on, */
79 /* I think converting the bounds to the applicable domain makes more */
82 case KX_ACT_CONSTRAINT_ORIX:
83 case KX_ACT_CONSTRAINT_ORIY:
84 case KX_ACT_CONSTRAINT_ORIZ:
86 MT_Scalar len = m_refDirVector.length();
87 if (MT_fuzzyZero(len)) {
88 // missing a valid direction
89 std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no valid reference direction!" << std::endl;
90 m_locrot = KX_ACT_CONSTRAINT_NODEF;
92 m_refDirection[0] /= len;
93 m_refDirection[1] /= len;
94 m_refDirection[2] /= len;
95 m_refDirVector /= len;
97 m_minimumBound = cos(minBound);
98 m_maximumBound = cos(maxBound);
99 m_minimumSine = sin(minBound);
100 m_maximumSine = sin(maxBound);
104 m_minimumBound = minBound;
105 m_maximumBound = maxBound;
111 } /* End of constructor */
113 KX_ConstraintActuator::~KX_ConstraintActuator()
115 // there's nothing to be done here, really....
116 } /* end of destructor */
118 bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
121 m_hitObject = client->m_gameobject;
125 if (m_property.IsEmpty())
131 if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
133 if (client->m_auxilary_info)
135 bFound = !strcmp(m_property.Ptr(), ((char*)client->m_auxilary_info));
140 bFound = m_hitObject->GetProperty(m_property) != NULL;
143 // update the hit status
144 result->m_hitFound = bFound;
149 /* this function is used to pre-filter the object before casting the ray on them.
150 This is useful for "X-Ray" option when we want to see "through" unwanted object.
152 bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client)
154 if (client->m_type > KX_ClientObjectInfo::ACTOR)
156 // Unknown type of object, skip it.
157 // Should not occur as the sensor objects are filtered in RayTest()
158 printf("Invalid client type %d found in ray casting\n", client->m_type);
161 // no X-Ray function yet
165 bool KX_ConstraintActuator::Update(double curtime, bool frame)
169 bool bNegativeEvent = IsNegativeEvent();
172 if (!bNegativeEvent) {
173 /* Constraint clamps the values to the specified range, with a sort of */
174 /* low-pass filtered time response, if the damp time is unequal to 0. */
176 /* Having to retrieve location/rotation and setting it afterwards may not */
177 /* be efficient enough... Somthing to look at later. */
178 KX_GameObject *obj = (KX_GameObject*) GetParent();
179 MT_Point3 position = obj->NodeGetWorldPosition();
180 MT_Point3 newposition;
181 MT_Vector3 normal, direction, refDirection;
182 MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
183 MT_Scalar filter, newdistance, cosangle;
187 filter = m_posDampTime/(1.0+m_posDampTime);
192 case KX_ACT_CONSTRAINT_ORIX:
193 case KX_ACT_CONSTRAINT_ORIY:
194 case KX_ACT_CONSTRAINT_ORIZ:
196 case KX_ACT_CONSTRAINT_ORIX:
197 direction[0] = rotation[0][0];
198 direction[1] = rotation[1][0];
199 direction[2] = rotation[2][0];
202 case KX_ACT_CONSTRAINT_ORIY:
203 direction[0] = rotation[0][1];
204 direction[1] = rotation[1][1];
205 direction[2] = rotation[2][1];
209 direction[0] = rotation[0][2];
210 direction[1] = rotation[1][2];
211 direction[2] = rotation[2][2];
215 if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
216 // reference direction needs to be evaluated
217 // 1. get the cosine between current direction and target
218 cosangle = direction.dot(m_refDirVector);
219 if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
224 // 2. define a new reference direction
225 // compute local axis with reference direction as X and
226 // Y in direction X refDirection plane
227 MT_Vector3 zaxis = m_refDirVector.cross(direction);
228 if (MT_fuzzyZero2(zaxis.length2())) {
229 // direction and refDirection are identical,
230 // choose any other direction to define plane
231 if (direction[0] < 0.9999)
232 zaxis = m_refDirVector.cross(MT_Vector3(1.0,0.0,0.0));
234 zaxis = m_refDirVector.cross(MT_Vector3(0.0,1.0,0.0));
236 MT_Vector3 yaxis = zaxis.cross(m_refDirVector);
238 if (cosangle > m_minimumBound) {
239 // angle is too close to reference direction,
240 // choose a new reference that is exactly at minimum angle
241 refDirection = m_minimumBound * m_refDirVector + m_minimumSine * yaxis;
243 // angle is too large, choose new reference direction at maximum angle
244 refDirection = m_maximumBound * m_refDirVector + m_maximumSine * yaxis;
247 refDirection = m_refDirVector;
249 // apply damping on the direction
250 direction = filter*direction + (1.0-filter)*refDirection;
251 obj->AlignAxisToVect(direction, axis);
254 case KX_ACT_CONSTRAINT_DIRPX:
255 case KX_ACT_CONSTRAINT_DIRPY:
256 case KX_ACT_CONSTRAINT_DIRPZ:
257 case KX_ACT_CONSTRAINT_DIRNX:
258 case KX_ACT_CONSTRAINT_DIRNY:
259 case KX_ACT_CONSTRAINT_DIRNZ:
261 case KX_ACT_CONSTRAINT_DIRPX:
262 normal[0] = rotation[0][0];
263 normal[1] = rotation[1][0];
264 normal[2] = rotation[2][0];
265 axis = 0; // axis according to KX_GameObject::AlignAxisToVect()
266 sign = 0; // X axis will be parrallel to direction of ray
268 case KX_ACT_CONSTRAINT_DIRPY:
269 normal[0] = rotation[0][1];
270 normal[1] = rotation[1][1];
271 normal[2] = rotation[2][1];
275 case KX_ACT_CONSTRAINT_DIRPZ:
276 normal[0] = rotation[0][2];
277 normal[1] = rotation[1][2];
278 normal[2] = rotation[2][2];
282 case KX_ACT_CONSTRAINT_DIRNX:
283 normal[0] = -rotation[0][0];
284 normal[1] = -rotation[1][0];
285 normal[2] = -rotation[2][0];
289 case KX_ACT_CONSTRAINT_DIRNY:
290 normal[0] = -rotation[0][1];
291 normal[1] = -rotation[1][1];
292 normal[2] = -rotation[2][1];
296 case KX_ACT_CONSTRAINT_DIRNZ:
297 normal[0] = -rotation[0][2];
298 normal[1] = -rotation[1][2];
299 normal[2] = -rotation[2][2];
305 if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
306 // direction of the ray is along the local axis
310 case KX_ACT_CONSTRAINT_DIRPX:
311 direction = MT_Vector3(1.0,0.0,0.0);
313 case KX_ACT_CONSTRAINT_DIRPY:
314 direction = MT_Vector3(0.0,1.0,0.0);
316 case KX_ACT_CONSTRAINT_DIRPZ:
317 direction = MT_Vector3(0.0,0.0,1.0);
319 case KX_ACT_CONSTRAINT_DIRNX:
320 direction = MT_Vector3(-1.0,0.0,0.0);
322 case KX_ACT_CONSTRAINT_DIRNY:
323 direction = MT_Vector3(0.0,-1.0,0.0);
325 case KX_ACT_CONSTRAINT_DIRNZ:
326 direction = MT_Vector3(0.0,0.0,-1.0);
331 MT_Point3 topoint = position + (m_maximumBound) * direction;
332 PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
333 KX_IPhysicsController *spc = obj->GetPhysicsController();
336 std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl;
340 // the object is not physical, we probably want to avoid hitting its own parent
341 KX_GameObject *parent = obj->GetParent();
343 spc = parent->GetPhysicsController();
347 KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
348 result = KX_RayCast::RayTest(pe, position, topoint, callback);
350 MT_Vector3 newnormal = callback.m_hitNormal;
351 // compute new position & orientation
352 if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
353 // if none option is set, the actuator does nothing but detect ray
354 // (works like a sensor)
357 if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
359 // apply damping on the direction
361 rotFilter = m_rotDampTime/(1.0+m_rotDampTime);
365 newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal;
366 obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
367 if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
368 direction = newnormal;
369 direction.normalize();
372 if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
374 newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound;
376 newdistance = m_minimumBound;
378 // logically we should cancel the speed along the ray direction as we set the
379 // position along that axis
380 spc = obj->GetPhysicsController();
381 if (spc && spc->IsDyna()) {
382 MT_Vector3 linV = spc->GetLinearVelocity();
383 // cancel the projection along the ray direction
384 MT_Scalar fallspeed = linV.dot(direction);
385 if (!MT_fuzzyZero(fallspeed))
386 spc->SetLinearVelocity(linV-fallspeed*direction,false);
389 newdistance = (position-callback.m_hitPoint).length();
391 newposition = callback.m_hitPoint-newdistance*direction;
392 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
393 // no contact but still keep running
399 case KX_ACT_CONSTRAINT_FHPX:
400 case KX_ACT_CONSTRAINT_FHPY:
401 case KX_ACT_CONSTRAINT_FHPZ:
402 case KX_ACT_CONSTRAINT_FHNX:
403 case KX_ACT_CONSTRAINT_FHNY:
404 case KX_ACT_CONSTRAINT_FHNZ:
406 case KX_ACT_CONSTRAINT_FHPX:
407 normal[0] = -rotation[0][0];
408 normal[1] = -rotation[1][0];
409 normal[2] = -rotation[2][0];
410 direction = MT_Vector3(1.0,0.0,0.0);
412 case KX_ACT_CONSTRAINT_FHPY:
413 normal[0] = -rotation[0][1];
414 normal[1] = -rotation[1][1];
415 normal[2] = -rotation[2][1];
416 direction = MT_Vector3(0.0,1.0,0.0);
418 case KX_ACT_CONSTRAINT_FHPZ:
419 normal[0] = -rotation[0][2];
420 normal[1] = -rotation[1][2];
421 normal[2] = -rotation[2][2];
422 direction = MT_Vector3(0.0,0.0,1.0);
424 case KX_ACT_CONSTRAINT_FHNX:
425 normal[0] = rotation[0][0];
426 normal[1] = rotation[1][0];
427 normal[2] = rotation[2][0];
428 direction = MT_Vector3(-1.0,0.0,0.0);
430 case KX_ACT_CONSTRAINT_FHNY:
431 normal[0] = rotation[0][1];
432 normal[1] = rotation[1][1];
433 normal[2] = rotation[2][1];
434 direction = MT_Vector3(0.0,-1.0,0.0);
436 case KX_ACT_CONSTRAINT_FHNZ:
437 normal[0] = rotation[0][2];
438 normal[1] = rotation[1][2];
439 normal[2] = rotation[2][2];
440 direction = MT_Vector3(0.0,0.0,-1.0);
445 PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
446 KX_IPhysicsController *spc = obj->GetPhysicsController();
449 std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl;
452 if (!spc || !spc->IsDyna()) {
453 // the object is not dynamic, it won't support setting speed
457 // distance of Fh area is stored in m_minimum
458 MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
459 KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
460 result = KX_RayCast::RayTest(pe, position, topoint, callback);
461 // we expect a hit object
466 MT_Vector3 newnormal = callback.m_hitNormal;
467 // compute new position & orientation
468 MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius();
469 // estimate the velocity of the hit point
470 MT_Point3 relativeHitPoint;
471 relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition());
472 MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint);
473 MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint;
474 MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity);
475 MT_Scalar springExtent = 1.0 - distance/m_minimumBound;
476 // Fh force is stored in m_maximum
477 MT_Scalar springForce = springExtent * m_maximumBound;
478 // damping is stored in m_refDirection [0] = damping, [1] = rot damping
479 MT_Scalar springDamp = relativeVelocityRay * m_refDirVector[0];
480 MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction;
481 if (m_option & KX_ACT_CONSTRAINT_NORMAL)
483 newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction);
485 spc->SetLinearVelocity(newVelocity, false);
486 if (m_option & KX_ACT_CONSTRAINT_DOROTFH)
488 MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound;
489 MT_Vector3 angVelocity = spc->GetAngularVelocity();
490 // remove component that is parallel to normal
491 angVelocity -= angVelocity.dot(newnormal)*newnormal;
492 MT_Vector3 angDamp = angVelocity * ((m_refDirVector[1]>MT_EPSILON)?m_refDirVector[1]:m_refDirVector[0]);
493 spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false);
495 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
496 // no contact but still keep running
499 // don't set the position with this constraint
503 case KX_ACT_CONSTRAINT_LOCX:
504 case KX_ACT_CONSTRAINT_LOCY:
505 case KX_ACT_CONSTRAINT_LOCZ:
506 newposition = position = obj->GetSGNode()->GetLocalPosition();
508 case KX_ACT_CONSTRAINT_LOCX:
509 Clamp(newposition[0], m_minimumBound, m_maximumBound);
511 case KX_ACT_CONSTRAINT_LOCY:
512 Clamp(newposition[1], m_minimumBound, m_maximumBound);
514 case KX_ACT_CONSTRAINT_LOCZ:
515 Clamp(newposition[2], m_minimumBound, m_maximumBound);
520 newposition = filter*position + (1.0-filter)*newposition;
522 obj->NodeSetLocalPosition(newposition);
526 // set the new position but take into account parent if any
527 obj->NodeSetWorldPosition(newposition);
530 if (result && m_activeTime > 0 ) {
531 if (++m_currentTime >= m_activeTime)
539 } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */
541 void KX_ConstraintActuator::Clamp(MT_Scalar &var,
546 } else if (var > max) {
552 bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m)
556 if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
563 /* ------------------------------------------------------------------------- */
564 /* Python functions */
565 /* ------------------------------------------------------------------------- */
567 /* Integration hooks ------------------------------------------------------- */
568 PyTypeObject KX_ConstraintActuator::Type = {
569 PyObject_HEAD_INIT(NULL)
571 "KX_ConstraintActuator",
572 sizeof(KX_ConstraintActuator),
587 PyParentObject KX_ConstraintActuator::Parents[] = {
588 &KX_ConstraintActuator::Type,
589 &SCA_IActuator::Type,
590 &SCA_ILogicBrick::Type,
595 PyMethodDef KX_ConstraintActuator::Methods[] = {
597 {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, (PY_METHODCHAR)SetDamp_doc},
598 {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, (PY_METHODCHAR)GetDamp_doc},
599 {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, (PY_METHODCHAR)SetRotDamp_doc},
600 {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, (PY_METHODCHAR)GetRotDamp_doc},
601 {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, (PY_METHODCHAR)SetDirection_doc},
602 {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, (PY_METHODCHAR)GetDirection_doc},
603 {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, (PY_METHODCHAR)SetOption_doc},
604 {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, (PY_METHODCHAR)GetOption_doc},
605 {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc},
606 {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc},
607 {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
608 {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc},
609 {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc},
610 {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc},
611 {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetDistance_doc},
612 {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetDistance_doc},
613 {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc},
614 {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc},
615 {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetRayLength_doc},
616 {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetRayLength_doc},
617 {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, (PY_METHODCHAR)SetLimit_doc},
618 {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, (PY_METHODCHAR)GetLimit_doc},
620 {NULL,NULL} //Sentinel
623 PyAttributeDef KX_ConstraintActuator::Attributes[] = {
624 KX_PYATTRIBUTE_INT_RW("damp",0,100,true,KX_ConstraintActuator,m_posDampTime),
625 KX_PYATTRIBUTE_INT_RW("rotDamp",0,100,true,KX_ConstraintActuator,m_rotDampTime),
626 KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK("direction",-MAXFLOAT,MAXFLOAT,KX_ConstraintActuator,m_refDirection,3,pyattr_check_direction),
627 KX_PYATTRIBUTE_INT_RW("option",0,0xFFFF,false,KX_ConstraintActuator,m_option),
628 KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_ConstraintActuator,m_activeTime),
629 KX_PYATTRIBUTE_STRING_RW("property",0,32,true,KX_ConstraintActuator,m_property),
630 KX_PYATTRIBUTE_FLOAT_RW("min",-MAXFLOAT,MAXFLOAT,KX_ConstraintActuator,m_minimumBound),
631 KX_PYATTRIBUTE_FLOAT_RW("distance",-MAXFLOAT,MAXFLOAT,KX_ConstraintActuator,m_minimumBound),
632 KX_PYATTRIBUTE_FLOAT_RW("max",-MAXFLOAT,MAXFLOAT,KX_ConstraintActuator,m_maximumBound),
633 KX_PYATTRIBUTE_FLOAT_RW("rayLength",0,2000.f,KX_ConstraintActuator,m_maximumBound),
634 KX_PYATTRIBUTE_INT_RW("limit",KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF+1,KX_ConstraintActuator::KX_ACT_CONSTRAINT_MAX-1,false,KX_ConstraintActuator,m_locrot),
638 PyObject* KX_ConstraintActuator::py_getattro(PyObject *attr)
640 py_getattro_up(SCA_IActuator);
643 int KX_ConstraintActuator::py_setattro(PyObject *attr, PyObject* value)
645 py_setattro_up(SCA_IActuator);
649 int KX_ConstraintActuator::pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
651 KX_ConstraintActuator* act = static_cast<KX_ConstraintActuator*>(self);
652 MT_Vector3 dir(act->m_refDirection);
653 MT_Scalar len = dir.length();
654 if (MT_fuzzyZero(len)) {
655 PyErr_SetString(PyExc_ValueError, "Invalid direction");
658 act->m_refDirVector = dir/len;
663 const char KX_ConstraintActuator::SetDamp_doc[] =
664 "setDamp(duration)\n"
665 "\t- duration: integer\n"
666 "\tSets the time constant of the orientation and distance constraint.\n"
667 "\tIf the duration is negative, it is set to 0.\n";
668 PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self,
671 ShowDeprecationWarning("setDamp()", "the damp property");
673 if(!PyArg_ParseTuple(args, "i", &dampArg)) {
677 m_posDampTime = dampArg;
678 if (m_posDampTime < 0) m_posDampTime = 0;
683 const char KX_ConstraintActuator::GetDamp_doc[] =
685 "\tReturns the damping parameter.\n";
686 PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){
687 ShowDeprecationWarning("getDamp()", "the damp property");
688 return PyInt_FromLong(m_posDampTime);
692 const char KX_ConstraintActuator::SetRotDamp_doc[] =
693 "setRotDamp(duration)\n"
694 "\t- duration: integer\n"
695 "\tSets the time constant of the orientation constraint.\n"
696 "\tIf the duration is negative, it is set to 0.\n";
697 PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self,
700 ShowDeprecationWarning("setRotDamp()", "the rotDamp property");
702 if(!PyArg_ParseTuple(args, "i", &dampArg)) {
706 m_rotDampTime = dampArg;
707 if (m_rotDampTime < 0) m_rotDampTime = 0;
712 const char KX_ConstraintActuator::GetRotDamp_doc[] =
714 "\tReturns the damping time for application of the constraint.\n";
715 PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){
716 ShowDeprecationWarning("getRotDamp()", "the rotDamp property");
717 return PyInt_FromLong(m_rotDampTime);
720 /* 2. setDirection */
721 const char KX_ConstraintActuator::SetDirection_doc[] =
722 "setDirection(vector)\n"
723 "\t- vector: 3-tuple\n"
724 "\tSets the reference direction in world coordinate for the orientation constraint.\n";
725 PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self,
728 ShowDeprecationWarning("setDirection()", "the direction property");
733 if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) {
740 if (MT_fuzzyZero(len)) {
741 std::cout << "Invalid direction" << std::endl;
744 m_refDirVector = dir/len;
745 m_refDirection[0] = x/len;
746 m_refDirection[1] = y/len;
747 m_refDirection[2] = z/len;
751 /* 3. getDirection */
752 const char KX_ConstraintActuator::GetDirection_doc[] =
754 "\tReturns the reference direction of the orientation constraint as a 3-tuple.\n";
755 PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){
756 ShowDeprecationWarning("getDirection()", "the direction property");
757 PyObject *retVal = PyList_New(3);
759 PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0]));
760 PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1]));
761 PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2]));
766 const char KX_ConstraintActuator::SetOption_doc[] =
767 "setOption(option)\n"
768 "\t- option: integer\n"
769 "\tSets several options of the distance constraint.\n"
770 "\tBinary combination of the following values:\n"
771 "\t\t 64 : Activate alignment to surface\n"
772 "\t\t128 : Detect material rather than property\n"
773 "\t\t256 : No deactivation if ray does not hit target\n"
774 "\t\t512 : Activate distance control\n";
775 PyObject* KX_ConstraintActuator::PySetOption(PyObject* self,
778 ShowDeprecationWarning("setOption()", "the option property");
780 if(!PyArg_ParseTuple(args, "i", &option)) {
789 const char KX_ConstraintActuator::GetOption_doc[] =
791 "\tReturns the option parameter.\n";
792 PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){
793 ShowDeprecationWarning("getOption()", "the option property");
794 return PyInt_FromLong(m_option);
798 const char KX_ConstraintActuator::SetTime_doc[] =
799 "setTime(duration)\n"
800 "\t- duration: integer\n"
801 "\tSets the activation time of the actuator.\n"
802 "\tThe actuator disables itself after this many frame.\n"
803 "\tIf set to 0 or negative, the actuator is not limited in time.\n";
804 PyObject* KX_ConstraintActuator::PySetTime(PyObject* self,
807 ShowDeprecationWarning("setTime()", "the time property");
809 if(!PyArg_ParseTuple(args, "i", &t)) {
820 const char KX_ConstraintActuator::GetTime_doc[] =
822 "\tReturns the time parameter.\n";
823 PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){
824 ShowDeprecationWarning("getTime()", "the time property");
825 return PyInt_FromLong(m_activeTime);
829 const char KX_ConstraintActuator::SetProperty_doc[] =
830 "setProperty(property)\n"
831 "\t- property: string\n"
832 "\tSets the name of the property or material for the ray detection of the distance constraint.\n"
833 "\tIf empty, the ray will detect any collisioning object.\n";
834 PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self,
837 ShowDeprecationWarning("setProperty()", "the 'property' property");
839 if (!PyArg_ParseTuple(args, "s", &property)) {
842 if (property == NULL) {
845 m_property = property;
851 const char KX_ConstraintActuator::GetProperty_doc[] =
853 "\tReturns the property parameter.\n";
854 PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){
855 ShowDeprecationWarning("getProperty()", "the 'property' property");
856 return PyString_FromString(m_property.Ptr());
860 const char KX_ConstraintActuator::SetDistance_doc[] =
861 "setDistance(distance)\n"
862 "\t- distance: float\n"
863 "\tSets the target distance in distance constraint\n";
865 const char KX_ConstraintActuator::SetMin_doc[] =
866 "setMin(lower_bound)\n"
867 "\t- lower_bound: float\n"
868 "\tSets the lower value of the interval to which the value\n"
870 PyObject* KX_ConstraintActuator::PySetMin(PyObject* self,
873 ShowDeprecationWarning("setMin() or setDistance()", "the min or distance property");
875 if(!PyArg_ParseTuple(args, "f", &minArg)) {
881 m_minimumBound = minArg;
883 case KX_ACT_CONSTRAINT_ROTX:
884 case KX_ACT_CONSTRAINT_ROTY:
885 case KX_ACT_CONSTRAINT_ROTZ:
886 m_minimumBound = MT_radians(minArg);
893 const char KX_ConstraintActuator::GetDistance_doc[] =
895 "\tReturns the distance parameter \n";
897 const char KX_ConstraintActuator::GetMin_doc[] =
899 "\tReturns the lower value of the interval to which the value\n"
901 PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self) {
902 ShowDeprecationWarning("getMin() or getDistance()", "the min or distance property");
903 return PyFloat_FromDouble(m_minimumBound);
906 /* 6. setRayLength */
907 const char KX_ConstraintActuator::SetRayLength_doc[] =
908 "setRayLength(length)\n"
909 "\t- length: float\n"
910 "\tSets the maximum ray length of the distance constraint\n";
912 const char KX_ConstraintActuator::SetMax_doc[] =
913 "setMax(upper_bound)\n"
914 "\t- upper_bound: float\n"
915 "\tSets the upper value of the interval to which the value\n"
917 PyObject* KX_ConstraintActuator::PySetMax(PyObject* self,
920 ShowDeprecationWarning("setMax() or setRayLength()", "the max or rayLength property");
922 if(!PyArg_ParseTuple(args, "f", &maxArg)) {
928 m_maximumBound = maxArg;
930 case KX_ACT_CONSTRAINT_ROTX:
931 case KX_ACT_CONSTRAINT_ROTY:
932 case KX_ACT_CONSTRAINT_ROTZ:
933 m_maximumBound = MT_radians(maxArg);
939 /* 7. getRayLength */
940 const char KX_ConstraintActuator::GetRayLength_doc[] =
942 "\tReturns the length of the ray\n";
944 const char KX_ConstraintActuator::GetMax_doc[] =
946 "\tReturns the upper value of the interval to which the value\n"
948 PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self) {
949 ShowDeprecationWarning("getMax() or getRayLength()", "the max or rayLength property");
950 return PyFloat_FromDouble(m_maximumBound);
954 /* This setter/getter probably for the constraint type */
956 const char KX_ConstraintActuator::SetLimit_doc[] =
958 "\t- type: integer\n"
962 "\t 7 : Distance along +X axis\n"
963 "\t 8 : Distance along +Y axis\n"
964 "\t 9 : Distance along +Z axis\n"
965 "\t 10 : Distance along -X axis\n"
966 "\t 11 : Distance along -Y axis\n"
967 "\t 12 : Distance along -Z axis\n"
968 "\t 13 : Align X axis\n"
969 "\t 14 : Align Y axis\n"
970 "\t 15 : Align Z axis\n"
971 "\tSets the type of constraint.\n";
972 PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self,
975 ShowDeprecationWarning("setLimit()", "the limit property");
977 if(!PyArg_ParseTuple(args, "i", &locrotArg)) {
981 if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg;
986 const char KX_ConstraintActuator::GetLimit_doc[] =
988 "\tReturns the type of constraint.\n";
989 PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self) {
990 ShowDeprecationWarning("setLimit()", "the limit property");
991 return PyInt_FromLong(m_locrot);