ode.pyx 128 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401
  1. ######################################################################
  2. # Python Open Dynamics Engine Wrapper
  3. # Copyright (C) 2004 PyODE developers (see file AUTHORS)
  4. # All rights reserved.
  5. #
  6. # This library is free software; you can redistribute it and/or
  7. # modify it under the terms of EITHER:
  8. # (1) The GNU Lesser General Public License as published by the Free
  9. # Software Foundation; either version 2.1 of the License, or (at
  10. # your option) any later version. The text of the GNU Lesser
  11. # General Public License is included with this library in the
  12. # file LICENSE.
  13. # (2) The BSD-style license that is included with this library in
  14. # the file LICENSE-BSD.
  15. #
  16. # This library is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
  19. # LICENSE and LICENSE-BSD for more details.
  20. ######################################################################
  21. from ode cimport *
  22. paramLoStop = 0
  23. paramHiStop = 1
  24. paramVel = 2
  25. paramFMax = 3
  26. paramFudgeFactor = 4
  27. paramBounce = 5
  28. paramCFM = 6
  29. paramStopERP = 7
  30. paramStopCFM = 8
  31. paramSuspensionERP = 9
  32. paramSuspensionCFM = 10
  33. ParamLoStop = 0
  34. ParamHiStop = 1
  35. ParamVel = 2
  36. ParamFMax = 3
  37. ParamFudgeFactor = 4
  38. ParamBounce = 5
  39. ParamCFM = 6
  40. ParamStopERP = 7
  41. ParamStopCFM = 8
  42. ParamSuspensionERP = 9
  43. ParamSuspensionCFM = 10
  44. ParamLoStop2 = 256 + 0
  45. ParamHiStop2 = 256 + 1
  46. ParamVel2 = 256 + 2
  47. ParamFMax2 = 256 + 3
  48. ParamFudgeFactor2 = 256 + 4
  49. ParamBounce2 = 256 + 5
  50. ParamCFM2 = 256 + 6
  51. ParamStopERP2 = 256 + 7
  52. ParamStopCFM2 = 256 + 8
  53. ParamSuspensionERP2 = 256 + 9
  54. ParamSuspensionCFM2 = 256 + 10
  55. ParamLoStop3 = 512 + 0
  56. ParamHiStop3 = 512 + 1
  57. ParamVel3 = 512 + 2
  58. ParamFMax3 = 512 + 3
  59. ParamFudgeFactor3 = 512 + 4
  60. ParamBounce3 = 512 + 5
  61. ParamCFM3 = 512 + 6
  62. ParamStopERP3 = 512 + 7
  63. ParamStopCFM3 = 512 + 8
  64. ParamSuspensionERP3 = 512 + 9
  65. ParamSuspensionCFM3 = 512 + 10
  66. ParamGroup = 256
  67. ContactMu2 = 0x001
  68. ContactFDir1 = 0x002
  69. ContactBounce = 0x004
  70. ContactSoftERP = 0x008
  71. ContactSoftCFM = 0x010
  72. ContactMotion1 = 0x020
  73. ContactMotion2 = 0x040
  74. ContactSlip1 = 0x080
  75. ContactSlip2 = 0x100
  76. ContactApprox0 = 0x0000
  77. ContactApprox1_1 = 0x1000
  78. ContactApprox1_2 = 0x2000
  79. ContactApprox1 = 0x3000
  80. AMotorUser = dAMotorUser
  81. AMotorEuler = dAMotorEuler
  82. Infinity = dInfinity
  83. import weakref
  84. _geom_c2py_lut = weakref.WeakValueDictionary()
  85. cdef class Mass:
  86. """Mass parameters of a rigid body.
  87. This class stores mass parameters of a rigid body which can be
  88. accessed through the following attributes:
  89. - mass: The total mass of the body (float)
  90. - c: The center of gravity position in body frame (3-tuple of floats)
  91. - I: The 3x3 inertia tensor in body frame (3-tuple of 3-tuples)
  92. This class wraps the dMass structure from the C API.
  93. @ivar mass: The total mass of the body
  94. @ivar c: The center of gravity position in body frame (cx, cy, cz)
  95. @ivar I: The 3x3 inertia tensor in body frame ((I11, I12, I13), (I12, I22, I23), (I13, I23, I33))
  96. @type mass: float
  97. @type c: 3-tuple of floats
  98. @type I: 3-tuple of 3-tuples of floats
  99. """
  100. cdef dMass _mass
  101. def __cinit__(self):
  102. dMassSetZero(&self._mass)
  103. def setZero(self):
  104. """setZero()
  105. Set all the mass parameters to zero."""
  106. dMassSetZero(&self._mass)
  107. def setParameters(self, mass, cgx, cgy, cgz, I11, I22, I33, I12, I13, I23):
  108. """setParameters(mass, cgx, cgy, cgz, I11, I22, I33, I12, I13, I23)
  109. Set the mass parameters to the given values.
  110. @param mass: Total mass of the body.
  111. @param cgx: Center of gravity position in the body frame (x component).
  112. @param cgy: Center of gravity position in the body frame (y component).
  113. @param cgz: Center of gravity position in the body frame (z component).
  114. @param I11: Inertia tensor
  115. @param I22: Inertia tensor
  116. @param I33: Inertia tensor
  117. @param I12: Inertia tensor
  118. @param I13: Inertia tensor
  119. @param I23: Inertia tensor
  120. @type mass: float
  121. @type cgx: float
  122. @type cgy: float
  123. @type cgz: float
  124. @type I11: float
  125. @type I22: float
  126. @type I33: float
  127. @type I12: float
  128. @type I13: float
  129. @type I23: float
  130. """
  131. dMassSetParameters(&self._mass, mass, cgx, cgy, cgz,
  132. I11, I22, I33, I12, I13, I23)
  133. def setSphere(self, density, radius):
  134. """setSphere(density, radius)
  135. Set the mass parameters to represent a sphere of the given radius
  136. and density, with the center of mass at (0,0,0) relative to the body.
  137. @param density: The density of the sphere
  138. @param radius: The radius of the sphere
  139. @type density: float
  140. @type radius: float
  141. """
  142. dMassSetSphere(&self._mass, density, radius)
  143. def setSphereTotal(self, total_mass, radius):
  144. """setSphereTotal(total_mass, radius)
  145. Set the mass parameters to represent a sphere of the given radius
  146. and mass, with the center of mass at (0,0,0) relative to the body.
  147. @param total_mass: The total mass of the sphere
  148. @param radius: The radius of the sphere
  149. @type total_mass: float
  150. @type radius: float
  151. """
  152. dMassSetSphereTotal(&self._mass, total_mass, radius)
  153. def setCapsule(self, density, direction, radius, length):
  154. """setCapsule(density, direction, radius, length)
  155. Set the mass parameters to represent a capsule of the given parameters
  156. and density, with the center of mass at (0,0,0) relative to the body.
  157. The radius of the cylinder (and the spherical cap) is radius. The length
  158. of the cylinder (not counting the spherical cap) is length. The
  159. cylinder's long axis is oriented along the body's x, y or z axis
  160. according to the value of direction (1=x, 2=y, 3=z). The first function
  161. accepts the density of the object, the second accepts its total mass.
  162. @param density: The density of the capsule
  163. @param direction: The direction of the capsule's cylinder (1=x axis, 2=y axis, 3=z axis)
  164. @param radius: The radius of the capsule's cylinder
  165. @param length: The length of the capsule's cylinder (without the caps)
  166. @type density: float
  167. @type direction: int
  168. @type radius: float
  169. @type length: float
  170. """
  171. dMassSetCapsule(&self._mass, density, direction, radius, length)
  172. def setCapsuleTotal(self, total_mass, direction, radius, length):
  173. """setCapsuleTotal(total_mass, direction, radius, length)
  174. Set the mass parameters to represent a capsule of the given parameters
  175. and mass, with the center of mass at (0,0,0) relative to the body. The
  176. radius of the cylinder (and the spherical cap) is radius. The length of
  177. the cylinder (not counting the spherical cap) is length. The cylinder's
  178. long axis is oriented along the body's x, y or z axis according to the
  179. value of direction (1=x, 2=y, 3=z). The first function accepts the
  180. density of the object, the second accepts its total mass.
  181. @param total_mass: The total mass of the capsule
  182. @param direction: The direction of the capsule's cylinder (1=x axis, 2=y axis, 3=z axis)
  183. @param radius: The radius of the capsule's cylinder
  184. @param length: The length of the capsule's cylinder (without the caps)
  185. @type total_mass: float
  186. @type direction: int
  187. @type radius: float
  188. @type length: float
  189. """
  190. dMassSetCapsuleTotal(&self._mass, total_mass, direction,
  191. radius, length)
  192. def setCylinder(self, density, direction, r, h):
  193. """setCylinder(density, direction, r, h)
  194. Set the mass parameters to represent a flat-ended cylinder of
  195. the given parameters and density, with the center of mass at
  196. (0,0,0) relative to the body. The radius of the cylinder is r.
  197. The length of the cylinder is h. The cylinder's long axis is
  198. oriented along the body's x, y or z axis according to the value
  199. of direction (1=x, 2=y, 3=z).
  200. @param density: The density of the cylinder
  201. @param direction: The direction of the cylinder (1=x axis, 2=y axis, 3=z axis)
  202. @param r: The radius of the cylinder
  203. @param h: The length of the cylinder
  204. @type density: float
  205. @type direction: int
  206. @type r: float
  207. @type h: float
  208. """
  209. dMassSetCylinder(&self._mass, density, direction, r, h)
  210. def setCylinderTotal(self, total_mass, direction, r, h):
  211. """setCylinderTotal(total_mass, direction, r, h)
  212. Set the mass parameters to represent a flat-ended cylinder of
  213. the given parameters and mass, with the center of mass at
  214. (0,0,0) relative to the body. The radius of the cylinder is r.
  215. The length of the cylinder is h. The cylinder's long axis is
  216. oriented along the body's x, y or z axis according to the value
  217. of direction (1=x, 2=y, 3=z).
  218. @param total_mass: The total mass of the cylinder
  219. @param direction: The direction of the cylinder (1=x axis, 2=y axis, 3=z axis)
  220. @param r: The radius of the cylinder
  221. @param h: The length of the cylinder
  222. @type total_mass: float
  223. @type direction: int
  224. @type r: float
  225. @type h: float
  226. """
  227. dMassSetCylinderTotal(&self._mass, total_mass, direction, r, h)
  228. def setBox(self, density, lx, ly, lz):
  229. """setBox(density, lx, ly, lz)
  230. Set the mass parameters to represent a box of the given
  231. dimensions and density, with the center of mass at (0,0,0)
  232. relative to the body. The side lengths of the box along the x,
  233. y and z axes are lx, ly and lz.
  234. @param density: The density of the box
  235. @param lx: The length along the x axis
  236. @param ly: The length along the y axis
  237. @param lz: The length along the z axis
  238. @type density: float
  239. @type lx: float
  240. @type ly: float
  241. @type lz: float
  242. """
  243. dMassSetBox(&self._mass, density, lx, ly, lz)
  244. def setBoxTotal(self, total_mass, lx, ly, lz):
  245. """setBoxTotal(total_mass, lx, ly, lz)
  246. Set the mass parameters to represent a box of the given
  247. dimensions and mass, with the center of mass at (0,0,0)
  248. relative to the body. The side lengths of the box along the x,
  249. y and z axes are lx, ly and lz.
  250. @param total_mass: The total mass of the box
  251. @param lx: The length along the x axis
  252. @param ly: The length along the y axis
  253. @param lz: The length along the z axis
  254. @type total_mass: float
  255. @type lx: float
  256. @type ly: float
  257. @type lz: float
  258. """
  259. dMassSetBoxTotal(&self._mass, total_mass, lx, ly, lz)
  260. def adjust(self, newmass):
  261. """adjust(newmass)
  262. Adjust the total mass. Given mass parameters for some object,
  263. adjust them so the total mass is now newmass. This is useful
  264. when using the setXyz() methods to set the mass parameters for
  265. certain objects - they take the object density, not the total
  266. mass.
  267. @param newmass: The new total mass
  268. @type newmass: float
  269. """
  270. dMassAdjust(&self._mass, newmass)
  271. def translate(self, t):
  272. """translate(t)
  273. Adjust mass parameters. Given mass parameters for some object,
  274. adjust them to represent the object displaced by (x,y,z)
  275. relative to the body frame.
  276. @param t: Translation vector (x, y, z)
  277. @type t: 3-tuple of floats
  278. """
  279. dMassTranslate(&self._mass, t[0], t[1], t[2])
  280. # def rotate(self, R):
  281. # """
  282. # Given mass parameters for some object, adjust them to
  283. # represent the object rotated by R relative to the body frame.
  284. # """
  285. # pass
  286. def add(self, Mass b):
  287. """add(b)
  288. Add the mass b to the mass object. Masses can also be added using
  289. the + operator.
  290. @param b: The mass to add to this mass
  291. @type b: Mass
  292. """
  293. dMassAdd(&self._mass, &b._mass)
  294. def __getattr__(self, name):
  295. if name == "mass":
  296. return self._mass.mass
  297. elif name == "c":
  298. return self._mass.c[0], self._mass.c[1], self._mass.c[2]
  299. elif name == "I":
  300. return ((self._mass.I[0], self._mass.I[1], self._mass.I[2]),
  301. (self._mass.I[4], self._mass.I[5], self._mass.I[6]),
  302. (self._mass.I[8], self._mass.I[9], self._mass.I[10]))
  303. else:
  304. raise AttributeError("Mass object has no attribute '%s'" % name)
  305. def __setattr__(self, name, value):
  306. if name == "mass":
  307. self.adjust(value)
  308. elif name == "c":
  309. raise AttributeError("Use the setParameter() method to change c")
  310. elif name == "I":
  311. raise AttributeError("Use the setParameter() method to change I")
  312. else:
  313. raise AttributeError("Mass object has no attribute '%s" % name)
  314. def __add__(self, Mass b):
  315. self.add(b)
  316. return self
  317. def __str__(self):
  318. m = str(self._mass.mass)
  319. sc0 = str(self._mass.c[0])
  320. sc1 = str(self._mass.c[1])
  321. sc2 = str(self._mass.c[2])
  322. I11 = str(self._mass.I[0])
  323. I22 = str(self._mass.I[5])
  324. I33 = str(self._mass.I[10])
  325. I12 = str(self._mass.I[1])
  326. I13 = str(self._mass.I[2])
  327. I23 = str(self._mass.I[6])
  328. return ("Mass=%s\n"
  329. "Cg=(%s, %s, %s)\n"
  330. "I11=%s I22=%s I33=%s\n"
  331. "I12=%s I13=%s I23=%s" %
  332. (m, sc0, sc1, sc2, I11, I22, I33, I12, I13, I23))
  333. # return ("Mass=%s / "
  334. # "Cg=(%s, %s, %s) / "
  335. # "I11=%s I22=%s I33=%s "
  336. # "I12=%s I13=%s I23=%s" %
  337. # (m, sc0, sc1, sc2, I11, I22, I33, I12, I13, I23))
  338. cdef class Contact:
  339. """This class represents a contact between two bodies in one point.
  340. A Contact object stores all the input parameters for a ContactJoint.
  341. This class wraps the ODE dContact structure which has 3 components::
  342. struct dContact {
  343. dSurfaceParameters surface;
  344. dContactGeom geom;
  345. dVector3 fdir1;
  346. };
  347. This wrapper class provides methods to get and set the items of those
  348. structures.
  349. """
  350. cdef dContact _contact
  351. def __cinit__(self):
  352. self._contact.surface.mode = ContactBounce
  353. self._contact.surface.mu = dInfinity
  354. self._contact.surface.bounce = 0.1
  355. # getMode
  356. def getMode(self):
  357. """getMode() -> flags
  358. Return the contact flags.
  359. """
  360. return self._contact.surface.mode
  361. # setMode
  362. def setMode(self, flags):
  363. """setMode(flags)
  364. Set the contact flags. The argument m is a combination of the
  365. ContactXyz flags (ContactMu2, ContactBounce, ...).
  366. @param flags: Contact flags
  367. @type flags: int
  368. """
  369. self._contact.surface.mode = flags
  370. # getMu
  371. def getMu(self):
  372. """getMu() -> float
  373. Return the Coulomb friction coefficient.
  374. """
  375. return self._contact.surface.mu
  376. # setMu
  377. def setMu(self, mu):
  378. """setMu(mu)
  379. Set the Coulomb friction coefficient.
  380. @param mu: Coulomb friction coefficient (0..Infinity)
  381. @type mu: float
  382. """
  383. self._contact.surface.mu = mu
  384. # getMu2
  385. def getMu2(self):
  386. """getMu2() -> float
  387. Return the optional Coulomb friction coefficient for direction 2.
  388. """
  389. return self._contact.surface.mu2
  390. # setMu2
  391. def setMu2(self, mu):
  392. """setMu2(mu)
  393. Set the optional Coulomb friction coefficient for direction 2.
  394. @param mu: Coulomb friction coefficient (0..Infinity)
  395. @type mu: float
  396. """
  397. self._contact.surface.mu2 = mu
  398. # getBounce
  399. def getBounce(self):
  400. """getBounce() -> float
  401. Return the restitution parameter.
  402. """
  403. return self._contact.surface.bounce
  404. # setBounce
  405. def setBounce(self, b):
  406. """setBounce(b)
  407. @param b: Restitution parameter (0..1)
  408. @type b: float
  409. """
  410. self._contact.surface.bounce = b
  411. # getBounceVel
  412. def getBounceVel(self):
  413. """getBounceVel() -> float
  414. Return the minimum incoming velocity necessary for bounce.
  415. """
  416. return self._contact.surface.bounce_vel
  417. # setBounceVel
  418. def setBounceVel(self, bv):
  419. """setBounceVel(bv)
  420. Set the minimum incoming velocity necessary for bounce. Incoming
  421. velocities below this will effectively have a bounce parameter of 0.
  422. @param bv: Velocity
  423. @type bv: float
  424. """
  425. self._contact.surface.bounce_vel = bv
  426. # getSoftERP
  427. def getSoftERP(self):
  428. """getSoftERP() -> float
  429. Return the contact normal "softness" parameter.
  430. """
  431. return self._contact.surface.soft_erp
  432. # setSoftERP
  433. def setSoftERP(self, erp):
  434. """setSoftERP(erp)
  435. Set the contact normal "softness" parameter.
  436. @param erp: Softness parameter
  437. @type erp: float
  438. """
  439. self._contact.surface.soft_erp = erp
  440. # getSoftCFM
  441. def getSoftCFM(self):
  442. """getSoftCFM() -> float
  443. Return the contact normal "softness" parameter.
  444. """
  445. return self._contact.surface.soft_cfm
  446. # setSoftCFM
  447. def setSoftCFM(self, cfm):
  448. """setSoftCFM(cfm)
  449. Set the contact normal "softness" parameter.
  450. @param cfm: Softness parameter
  451. @type cfm: float
  452. """
  453. self._contact.surface.soft_cfm = cfm
  454. # getMotion1
  455. def getMotion1(self):
  456. """getMotion1() -> float
  457. Get the surface velocity in friction direction 1.
  458. """
  459. return self._contact.surface.motion1
  460. # setMotion1
  461. def setMotion1(self, m):
  462. """setMotion1(m)
  463. Set the surface velocity in friction direction 1.
  464. @param m: Surface velocity
  465. @type m: float
  466. """
  467. self._contact.surface.motion1 = m
  468. # getMotion2
  469. def getMotion2(self):
  470. """getMotion2() -> float
  471. Get the surface velocity in friction direction 2.
  472. """
  473. return self._contact.surface.motion2
  474. # setMotion2
  475. def setMotion2(self, m):
  476. """setMotion2(m)
  477. Set the surface velocity in friction direction 2.
  478. @param m: Surface velocity
  479. @type m: float
  480. """
  481. self._contact.surface.motion2 = m
  482. # getSlip1
  483. def getSlip1(self):
  484. """getSlip1() -> float
  485. Get the coefficient of force-dependent-slip (FDS) for friction
  486. direction 1.
  487. """
  488. return self._contact.surface.slip1
  489. # setSlip1
  490. def setSlip1(self, s):
  491. """setSlip1(s)
  492. Set the coefficient of force-dependent-slip (FDS) for friction
  493. direction 1.
  494. @param s: FDS coefficient
  495. @type s: float
  496. """
  497. self._contact.surface.slip1 = s
  498. # getSlip2
  499. def getSlip2(self):
  500. """getSlip2() -> float
  501. Get the coefficient of force-dependent-slip (FDS) for friction
  502. direction 2.
  503. """
  504. return self._contact.surface.slip2
  505. # setSlip2
  506. def setSlip2(self, s):
  507. """setSlip2(s)
  508. Set the coefficient of force-dependent-slip (FDS) for friction
  509. direction 1.
  510. @param s: FDS coefficient
  511. @type s: float
  512. """
  513. self._contact.surface.slip2 = s
  514. # getFDir1
  515. def getFDir1(self):
  516. """getFDir1() -> (x, y, z)
  517. Get the "first friction direction" vector that defines a direction
  518. along which frictional force is applied.
  519. """
  520. return (self._contact.fdir1[0],
  521. self._contact.fdir1[1],
  522. self._contact.fdir1[2])
  523. # setFDir1
  524. def setFDir1(self, fdir):
  525. """setFDir1(fdir)
  526. Set the "first friction direction" vector that defines a direction
  527. along which frictional force is applied. It must be of unit length
  528. and perpendicular to the contact normal (so it is typically
  529. tangential to the contact surface).
  530. @param fdir: Friction direction
  531. @type fdir: 3-sequence of floats
  532. """
  533. self._contact.fdir1[0] = fdir[0]
  534. self._contact.fdir1[1] = fdir[1]
  535. self._contact.fdir1[2] = fdir[2]
  536. # getContactGeomParams
  537. def getContactGeomParams(self):
  538. """getContactGeomParams() -> (pos, normal, depth, geom1, geom2)
  539. Get the ContactGeom structure of the contact.
  540. The return value is a tuple (pos, normal, depth, geom1, geom2)
  541. where pos and normal are 3-tuples of floats and depth is a single
  542. float. geom1 and geom2 are the Geom objects of the geoms in contact.
  543. """
  544. cdef long id1, id2
  545. pos = (self._contact.geom.pos[0],
  546. self._contact.geom.pos[1],
  547. self._contact.geom.pos[2])
  548. normal = (self._contact.geom.normal[0],
  549. self._contact.geom.normal[1],
  550. self._contact.geom.normal[2])
  551. depth = self._contact.geom.depth
  552. id1 = <long>self._contact.geom.g1
  553. id2 = <long>self._contact.geom.g2
  554. g1 = _geom_c2py_lut[id1]
  555. g2 = _geom_c2py_lut[id2]
  556. return pos, normal, depth, g1, g2
  557. # setContactGeomParams
  558. def setContactGeomParams(self, pos, normal, depth, g1=None, g2=None):
  559. """setContactGeomParams(pos, normal, depth, geom1=None, geom2=None)
  560. Set the ContactGeom structure of the contact.
  561. @param pos: Contact position, in global coordinates
  562. @type pos: 3-sequence of floats
  563. @param normal: Unit length normal vector
  564. @type normal: 3-sequence of floats
  565. @param depth: Depth to which the two bodies inter-penetrate
  566. @type depth: float
  567. @param geom1: Geometry object 1 that collided
  568. @type geom1: Geom
  569. @param geom2: Geometry object 2 that collided
  570. @type geom2: Geom
  571. """
  572. cdef long id
  573. self._contact.geom.pos[0] = pos[0]
  574. self._contact.geom.pos[1] = pos[1]
  575. self._contact.geom.pos[2] = pos[2]
  576. self._contact.geom.normal[0] = normal[0]
  577. self._contact.geom.normal[1] = normal[1]
  578. self._contact.geom.normal[2] = normal[2]
  579. self._contact.geom.depth = depth
  580. if g1 != None:
  581. id = g1._id()
  582. self._contact.geom.g1 = <dGeomID>id
  583. else:
  584. self._contact.geom.g1 = <dGeomID>0
  585. if g2 != None:
  586. id = g2._id()
  587. self._contact.geom.g2 = <dGeomID>id
  588. else:
  589. self._contact.geom.g2 = <dGeomID>0
  590. # World
  591. cdef class World:
  592. """Dynamics world.
  593. The world object is a container for rigid bodies and joints.
  594. Constructor::
  595. World()
  596. """
  597. cdef dWorldID wid
  598. def __cinit__(self):
  599. self.wid = dWorldCreate()
  600. def __dealloc__(self):
  601. if self.wid != NULL:
  602. dWorldDestroy(self.wid)
  603. # setGravity
  604. def setGravity(self, gravity):
  605. """setGravity(gravity)
  606. Set the world's global gravity vector.
  607. @param gravity: Gravity vector
  608. @type gravity: 3-sequence of floats
  609. """
  610. dWorldSetGravity(self.wid, gravity[0], gravity[1], gravity[2])
  611. # getGravity
  612. def getGravity(self):
  613. """getGravity() -> 3-tuple
  614. Return the world's global gravity vector as a 3-tuple of floats.
  615. """
  616. cdef dVector3 g
  617. dWorldGetGravity(self.wid, g)
  618. return g[0], g[1], g[2]
  619. # setERP
  620. def setERP(self, erp):
  621. """setERP(erp)
  622. Set the global ERP value, that controls how much error
  623. correction is performed in each time step. Typical values are
  624. in the range 0.1-0.8. The default is 0.2.
  625. @param erp: Global ERP value
  626. @type erp: float
  627. """
  628. dWorldSetERP(self.wid, erp)
  629. # getERP
  630. def getERP(self):
  631. """getERP() -> float
  632. Get the global ERP value, that controls how much error
  633. correction is performed in each time step. Typical values are
  634. in the range 0.1-0.8. The default is 0.2.
  635. """
  636. return dWorldGetERP(self.wid)
  637. # setCFM
  638. def setCFM(self, cfm):
  639. """setCFM(cfm)
  640. Set the global CFM (constraint force mixing) value. Typical
  641. values are in the range 10E-9 - 1. The default is 10E-5 if
  642. single precision is being used, or 10E-10 if double precision
  643. is being used.
  644. @param cfm: Constraint force mixing value
  645. @type cfm: float
  646. """
  647. dWorldSetCFM(self.wid, cfm)
  648. # getCFM
  649. def getCFM(self):
  650. """getCFM() -> float
  651. Get the global CFM (constraint force mixing) value. Typical
  652. values are in the range 10E-9 - 1. The default is 10E-5 if
  653. single precision is being used, or 10E-10 if double precision
  654. is being used.
  655. """
  656. return dWorldGetCFM(self.wid)
  657. # step
  658. def step(self, stepsize):
  659. """step(stepsize)
  660. Step the world. This uses a "big matrix" method that takes
  661. time on the order of O(m3) and memory on the order of O(m2), where m
  662. is the total number of constraint rows.
  663. For large systems this will use a lot of memory and can be
  664. very slow, but this is currently the most accurate method.
  665. @param stepsize: Time step
  666. @type stepsize: float
  667. """
  668. dWorldStep(self.wid, stepsize)
  669. # quickStep
  670. def quickStep(self, stepsize):
  671. """quickStep(stepsize)
  672. Step the world. This uses an iterative method that takes time
  673. on the order of O(m*N) and memory on the order of O(m), where m is
  674. the total number of constraint rows and N is the number of
  675. iterations.
  676. For large systems this is a lot faster than dWorldStep, but it
  677. is less accurate.
  678. @param stepsize: Time step
  679. @type stepsize: float
  680. """
  681. dWorldQuickStep(self.wid, stepsize)
  682. # setQuickStepNumIterations
  683. def setQuickStepNumIterations(self, num):
  684. """setQuickStepNumIterations(num)
  685. Set the number of iterations that the QuickStep method
  686. performs per step. More iterations will give a more accurate
  687. solution, but will take longer to compute. The default is 20
  688. iterations.
  689. @param num: Number of iterations
  690. @type num: int
  691. """
  692. dWorldSetQuickStepNumIterations(self.wid, num)
  693. # getQuickStepNumIterations
  694. def getQuickStepNumIterations(self):
  695. """getQuickStepNumIterations() -> int
  696. Get the number of iterations that the QuickStep method
  697. performs per step. More iterations will give a more accurate
  698. solution, but will take longer to compute. The default is 20
  699. iterations.
  700. """
  701. return dWorldGetQuickStepNumIterations(self.wid)
  702. # setQuickStepNumIterations
  703. def setContactMaxCorrectingVel(self, vel):
  704. """setContactMaxCorrectingVel(vel)
  705. Set the maximum correcting velocity that contacts are allowed
  706. to generate. The default value is infinity (i.e. no
  707. limit). Reducing this value can help prevent "popping" of
  708. deeply embedded objects.
  709. @param vel: Maximum correcting velocity
  710. @type vel: float
  711. """
  712. dWorldSetContactMaxCorrectingVel(self.wid, vel)
  713. # getQuickStepNumIterations
  714. def getContactMaxCorrectingVel(self):
  715. """getContactMaxCorrectingVel() -> float
  716. Get the maximum correcting velocity that contacts are allowed
  717. to generate. The default value is infinity (i.e. no
  718. limit). Reducing this value can help prevent "popping" of
  719. deeply embedded objects.
  720. """
  721. return dWorldGetContactMaxCorrectingVel(self.wid)
  722. # setContactSurfaceLayer
  723. def setContactSurfaceLayer(self, depth):
  724. """setContactSurfaceLayer(depth)
  725. Set the depth of the surface layer around all geometry
  726. objects. Contacts are allowed to sink into the surface layer
  727. up to the given depth before coming to rest. The default value
  728. is zero. Increasing this to some small value (e.g. 0.001) can
  729. help prevent jittering problems due to contacts being
  730. repeatedly made and broken.
  731. @param depth: Surface layer depth
  732. @type depth: float
  733. """
  734. dWorldSetContactSurfaceLayer(self.wid, depth)
  735. # getContactSurfaceLayer
  736. def getContactSurfaceLayer(self):
  737. """getContactSurfaceLayer()
  738. Get the depth of the surface layer around all geometry
  739. objects. Contacts are allowed to sink into the surface layer
  740. up to the given depth before coming to rest. The default value
  741. is zero. Increasing this to some small value (e.g. 0.001) can
  742. help prevent jittering problems due to contacts being
  743. repeatedly made and broken.
  744. """
  745. return dWorldGetContactSurfaceLayer(self.wid)
  746. # setAutoDisableFlag
  747. def setAutoDisableFlag(self, flag):
  748. """setAutoDisableFlag(flag)
  749. Set the default auto-disable flag for newly created bodies.
  750. @param flag: True = Do auto disable
  751. @type flag: bool
  752. """
  753. dWorldSetAutoDisableFlag(self.wid, flag)
  754. # getAutoDisableFlag
  755. def getAutoDisableFlag(self):
  756. """getAutoDisableFlag() -> bool
  757. Get the default auto-disable flag for newly created bodies.
  758. """
  759. return dWorldGetAutoDisableFlag(self.wid)
  760. # setAutoDisableLinearThreshold
  761. def setAutoDisableLinearThreshold(self, threshold):
  762. """setAutoDisableLinearThreshold(threshold)
  763. Set the default auto-disable linear threshold for newly created
  764. bodies.
  765. @param threshold: Linear threshold
  766. @type threshold: float
  767. """
  768. dWorldSetAutoDisableLinearThreshold(self.wid, threshold)
  769. # getAutoDisableLinearThreshold
  770. def getAutoDisableLinearThreshold(self):
  771. """getAutoDisableLinearThreshold() -> float
  772. Get the default auto-disable linear threshold for newly created
  773. bodies.
  774. """
  775. return dWorldGetAutoDisableLinearThreshold(self.wid)
  776. # setAutoDisableAngularThreshold
  777. def setAutoDisableAngularThreshold(self, threshold):
  778. """setAutoDisableAngularThreshold(threshold)
  779. Set the default auto-disable angular threshold for newly created
  780. bodies.
  781. @param threshold: Angular threshold
  782. @type threshold: float
  783. """
  784. dWorldSetAutoDisableAngularThreshold(self.wid, threshold)
  785. # getAutoDisableAngularThreshold
  786. def getAutoDisableAngularThreshold(self):
  787. """getAutoDisableAngularThreshold() -> float
  788. Get the default auto-disable angular threshold for newly created
  789. bodies.
  790. """
  791. return dWorldGetAutoDisableAngularThreshold(self.wid)
  792. # setAutoDisableSteps
  793. def setAutoDisableSteps(self, steps):
  794. """setAutoDisableSteps(steps)
  795. Set the default auto-disable steps for newly created bodies.
  796. @param steps: Auto disable steps
  797. @type steps: int
  798. """
  799. dWorldSetAutoDisableSteps(self.wid, steps)
  800. # getAutoDisableSteps
  801. def getAutoDisableSteps(self):
  802. """getAutoDisableSteps() -> int
  803. Get the default auto-disable steps for newly created bodies.
  804. """
  805. return dWorldGetAutoDisableSteps(self.wid)
  806. # setAutoDisableTime
  807. def setAutoDisableTime(self, time):
  808. """setAutoDisableTime(time)
  809. Set the default auto-disable time for newly created bodies.
  810. @param time: Auto disable time
  811. @type time: float
  812. """
  813. dWorldSetAutoDisableTime(self.wid, time)
  814. # getAutoDisableTime
  815. def getAutoDisableTime(self):
  816. """getAutoDisableTime() -> float
  817. Get the default auto-disable time for newly created bodies.
  818. """
  819. return dWorldGetAutoDisableTime(self.wid)
  820. # setLinearDamping
  821. def setLinearDamping(self, scale):
  822. """setLinearDamping(scale)
  823. Set the world's linear damping scale.
  824. @param scale The linear damping scale that is to be applied to bodies.
  825. Default is 0 (no damping). Should be in the interval [0, 1].
  826. @type scale: float
  827. """
  828. dWorldSetLinearDamping(self.wid, scale)
  829. # getLinearDamping
  830. def getLinearDamping(self):
  831. """getLinearDamping() -> float
  832. Get the world's linear damping scale.
  833. """
  834. return dWorldGetLinearDamping(self.wid)
  835. # setAngularDamping
  836. def setAngularDamping(self, scale):
  837. """setAngularDamping(scale)
  838. Set the world's angular damping scale.
  839. @param scale The angular damping scale that is to be applied to bodies.
  840. Default is 0 (no damping). Should be in the interval [0, 1].
  841. @type scale: float
  842. """
  843. dWorldSetAngularDamping(self.wid, scale)
  844. # getAngularDamping
  845. def getAngularDamping(self):
  846. """getAngularDamping() -> float
  847. Get the world's angular damping scale.
  848. """
  849. return dWorldGetAngularDamping(self.wid)
  850. # impulseToForce
  851. def impulseToForce(self, stepsize, impulse):
  852. """impulseToForce(stepsize, impulse) -> 3-tuple
  853. If you want to apply a linear or angular impulse to a rigid
  854. body, instead of a force or a torque, then you can use this
  855. function to convert the desired impulse into a force/torque
  856. vector before calling the dBodyAdd... function.
  857. @param stepsize: Time step
  858. @param impulse: Impulse vector
  859. @type stepsize: float
  860. @type impulse: 3-tuple of floats
  861. """
  862. cdef dVector3 force
  863. dWorldImpulseToForce(self.wid, stepsize,
  864. impulse[0], impulse[1], impulse[2], force)
  865. return force[0], force[1], force[2]
  866. # createBody
  867. # def createBody(self):
  868. # return Body(self)
  869. # createBallJoint
  870. # def createBallJoint(self, jointgroup=None):
  871. # return BallJoint(self, jointgroup)
  872. # createHingeJoint
  873. # def createHingeJoint(self, jointgroup=None):
  874. # return HingeJoint(self, jointgroup)
  875. # createHinge2Joint
  876. # def createHinge2Joint(self, jointgroup=None):
  877. # return Hinge2Joint(self, jointgroup)
  878. # createSliderJoint
  879. # def createSliderJoint(self, jointgroup=None):
  880. # return SliderJoint(self, jointgroup)
  881. # createFixedJoint
  882. # def createFixedJoint(self, jointgroup=None):
  883. # return FixedJoint(self, jointgroup)
  884. # createContactJoint
  885. # def createContactJoint(self, jointgroup, contact):
  886. # return ContactJoint(self, jointgroup, contact)
  887. # Body
  888. cdef class Body:
  889. """The rigid body class encapsulating the ODE body.
  890. This class represents a rigid body that has a location and orientation
  891. in space and that stores the mass properties of an object.
  892. When creating a Body object you have to pass the world it belongs to
  893. as argument to the constructor::
  894. >>> import ode
  895. >>> w = ode.World()
  896. >>> b = ode.Body(w)
  897. """
  898. cdef dBodyID bid
  899. # A reference to the world so that the world won't be destroyed while
  900. # there are still joints using it.
  901. cdef object world
  902. # A dictionary with user attributes
  903. # (set via __getattr__ and __setattr__)
  904. cdef object userattribs
  905. def __cinit__(self, World world not None):
  906. self.bid = dBodyCreate(world.wid)
  907. def __init__(self, World world not None):
  908. """Constructor.
  909. @param world: The world in which the body should be created.
  910. @type world: World
  911. """
  912. self.world = world
  913. self.userattribs = {}
  914. def __dealloc__(self):
  915. if self.bid != NULL:
  916. dBodyDestroy(self.bid)
  917. def __getattr__(self, name):
  918. try:
  919. return self.userattribs[name]
  920. except:
  921. raise AttributeError("Body object has no attribute '%s'" % name)
  922. def __setattr__(self, name, value):
  923. self.userattribs[name] = value
  924. def __delattr__(self, name):
  925. try:
  926. del self.userattribs[name]
  927. except:
  928. raise AttributeError("Body object has no attribute '%s'" % name)
  929. # setPosition
  930. def setPosition(self, pos):
  931. """setPosition(pos)
  932. Set the position of the body.
  933. @param pos: The new position
  934. @type pos: 3-sequence of floats
  935. """
  936. dBodySetPosition(self.bid, pos[0], pos[1], pos[2])
  937. # getPosition
  938. def getPosition(self):
  939. """getPosition() -> 3-tuple
  940. Return the current position of the body.
  941. """
  942. cdef dReal* p
  943. # The "const" in the original return value is cast away
  944. p = <dReal*>dBodyGetPosition(self.bid)
  945. return p[0], p[1], p[2]
  946. # setRotation
  947. def setRotation(self, R):
  948. """setRotation(R)
  949. Set the orientation of the body. The rotation matrix must be
  950. given as a sequence of 9 floats which are the elements of the
  951. matrix in row-major order.
  952. @param R: Rotation matrix
  953. @type R: 9-sequence of floats
  954. """
  955. cdef dMatrix3 m
  956. m[0] = R[0]
  957. m[1] = R[1]
  958. m[2] = R[2]
  959. m[3] = 0
  960. m[4] = R[3]
  961. m[5] = R[4]
  962. m[6] = R[5]
  963. m[7] = 0
  964. m[8] = R[6]
  965. m[9] = R[7]
  966. m[10] = R[8]
  967. m[11] = 0
  968. dBodySetRotation(self.bid, m)
  969. # getRotation
  970. def getRotation(self):
  971. """getRotation() -> 9-tuple
  972. Return the current rotation matrix as a tuple of 9 floats (row-major
  973. order).
  974. """
  975. cdef dReal* m
  976. # The "const" in the original return value is cast away
  977. m = <dReal*>dBodyGetRotation(self.bid)
  978. return m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]
  979. # getQuaternion
  980. def getQuaternion(self):
  981. """getQuaternion() -> 4-tuple
  982. Return the current rotation as a quaternion. The return value
  983. is a list of 4 floats.
  984. """
  985. cdef dReal* q
  986. q = <dReal*>dBodyGetQuaternion(self.bid)
  987. return q[0], q[1], q[2], q[3]
  988. # setQuaternion
  989. def setQuaternion(self, q):
  990. """setQuaternion(q)
  991. Set the orientation of the body. The quaternion must be given as a
  992. sequence of 4 floats.
  993. @param q: Quaternion
  994. @type q: 4-sequence of floats
  995. """
  996. cdef dQuaternion w
  997. w[0] = q[0]
  998. w[1] = q[1]
  999. w[2] = q[2]
  1000. w[3] = q[3]
  1001. dBodySetQuaternion(self.bid, w)
  1002. # setLinearVel
  1003. def setLinearVel(self, vel):
  1004. """setLinearVel(vel)
  1005. Set the linear velocity of the body.
  1006. @param vel: New velocity
  1007. @type vel: 3-sequence of floats
  1008. """
  1009. dBodySetLinearVel(self.bid, vel[0], vel[1], vel[2])
  1010. # getLinearVel
  1011. def getLinearVel(self):
  1012. """getLinearVel() -> 3-tuple
  1013. Get the current linear velocity of the body.
  1014. """
  1015. cdef dReal* p
  1016. # The "const" in the original return value is cast away
  1017. p = <dReal*>dBodyGetLinearVel(self.bid)
  1018. return p[0], p[1], p[2]
  1019. # setAngularVel
  1020. def setAngularVel(self, vel):
  1021. """setAngularVel(vel)
  1022. Set the angular velocity of the body.
  1023. @param vel: New angular velocity
  1024. @type vel: 3-sequence of floats
  1025. """
  1026. dBodySetAngularVel(self.bid, vel[0], vel[1], vel[2])
  1027. # getAngularVel
  1028. def getAngularVel(self):
  1029. """getAngularVel() -> 3-tuple
  1030. Get the current angular velocity of the body.
  1031. """
  1032. cdef dReal* p
  1033. # The "const" in the original return value is cast away
  1034. p = <dReal*>dBodyGetAngularVel(self.bid)
  1035. return p[0], p[1], p[2]
  1036. # setMass
  1037. def setMass(self, Mass mass):
  1038. """setMass(mass)
  1039. Set the mass properties of the body. The argument mass must be
  1040. an instance of a Mass object.
  1041. @param mass: Mass properties
  1042. @type mass: Mass
  1043. """
  1044. dBodySetMass(self.bid, &mass._mass)
  1045. # getMass
  1046. def getMass(self):
  1047. """getMass() -> mass
  1048. Return the mass properties as a Mass object.
  1049. """
  1050. cdef Mass m
  1051. m = Mass()
  1052. dBodyGetMass(self.bid, &m._mass)
  1053. return m
  1054. # addForce
  1055. def addForce(self, f):
  1056. """addForce(f)
  1057. Add an external force f given in absolute coordinates. The force
  1058. is applied at the center of mass.
  1059. @param f: Force
  1060. @type f: 3-sequence of floats
  1061. """
  1062. dBodyAddForce(self.bid, f[0], f[1], f[2])
  1063. # addTorque
  1064. def addTorque(self, t):
  1065. """addTorque(t)
  1066. Add an external torque t given in absolute coordinates.
  1067. @param t: Torque
  1068. @type t: 3-sequence of floats
  1069. """
  1070. dBodyAddTorque(self.bid, t[0], t[1], t[2])
  1071. # addRelForce
  1072. def addRelForce(self, f):
  1073. """addRelForce(f)
  1074. Add an external force f given in relative coordinates
  1075. (relative to the body's own frame of reference). The force
  1076. is applied at the center of mass.
  1077. @param f: Force
  1078. @type f: 3-sequence of floats
  1079. """
  1080. dBodyAddRelForce(self.bid, f[0], f[1], f[2])
  1081. # addRelTorque
  1082. def addRelTorque(self, t):
  1083. """addRelTorque(t)
  1084. Add an external torque t given in relative coordinates
  1085. (relative to the body's own frame of reference).
  1086. @param t: Torque
  1087. @type t: 3-sequence of floats
  1088. """
  1089. dBodyAddRelTorque(self.bid, t[0], t[1], t[2])
  1090. # addForceAtPos
  1091. def addForceAtPos(self, f, p):
  1092. """addForceAtPos(f, p)
  1093. Add an external force f at position p. Both arguments must be
  1094. given in absolute coordinates.
  1095. @param f: Force
  1096. @param p: Position
  1097. @type f: 3-sequence of floats
  1098. @type p: 3-sequence of floats
  1099. """
  1100. dBodyAddForceAtPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2])
  1101. # addForceAtRelPos
  1102. def addForceAtRelPos(self, f, p):
  1103. """addForceAtRelPos(f, p)
  1104. Add an external force f at position p. f is given in absolute
  1105. coordinates and p in absolute coordinates.
  1106. @param f: Force
  1107. @param p: Position
  1108. @type f: 3-sequence of floats
  1109. @type p: 3-sequence of floats
  1110. """
  1111. dBodyAddForceAtRelPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2])
  1112. # addRelForceAtPos
  1113. def addRelForceAtPos(self, f, p):
  1114. """addRelForceAtPos(f, p)
  1115. Add an external force f at position p. f is given in relative
  1116. coordinates and p in relative coordinates.
  1117. @param f: Force
  1118. @param p: Position
  1119. @type f: 3-sequence of floats
  1120. @type p: 3-sequence of floats
  1121. """
  1122. dBodyAddRelForceAtPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2])
  1123. # addRelForceAtRelPos
  1124. def addRelForceAtRelPos(self, f, p):
  1125. """addRelForceAtRelPos(f, p)
  1126. Add an external force f at position p. Both arguments must be
  1127. given in relative coordinates.
  1128. @param f: Force
  1129. @param p: Position
  1130. @type f: 3-sequence of floats
  1131. @type p: 3-sequence of floats
  1132. """
  1133. dBodyAddRelForceAtRelPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2])
  1134. # getForce
  1135. def getForce(self):
  1136. """getForce() -> 3-tuple
  1137. Return the current accumulated force.
  1138. """
  1139. cdef dReal* f
  1140. # The "const" in the original return value is cast away
  1141. f = <dReal*>dBodyGetForce(self.bid)
  1142. return f[0], f[1], f[2]
  1143. # getTorque
  1144. def getTorque(self):
  1145. """getTorque() -> 3-tuple
  1146. Return the current accumulated torque.
  1147. """
  1148. cdef dReal* f
  1149. # The "const" in the original return value is cast away
  1150. f = <dReal*>dBodyGetTorque(self.bid)
  1151. return f[0], f[1], f[2]
  1152. # setForce
  1153. def setForce(self, f):
  1154. """setForce(f)
  1155. Set the body force accumulation vector.
  1156. @param f: Force
  1157. @type f: 3-tuple of floats
  1158. """
  1159. dBodySetForce(self.bid, f[0], f[1], f[2])
  1160. # setTorque
  1161. def setTorque(self, t):
  1162. """setTorque(t)
  1163. Set the body torque accumulation vector.
  1164. @param t: Torque
  1165. @type t: 3-tuple of floats
  1166. """
  1167. dBodySetTorque(self.bid, t[0], t[1], t[2])
  1168. # getRelPointPos
  1169. def getRelPointPos(self, p):
  1170. """getRelPointPos(p) -> 3-tuple
  1171. Utility function that takes a point p on a body and returns
  1172. that point's position in global coordinates. The point p
  1173. must be given in body relative coordinates.
  1174. @param p: Body point (local coordinates)
  1175. @type p: 3-sequence of floats
  1176. """
  1177. cdef dVector3 res
  1178. dBodyGetRelPointPos(self.bid, p[0], p[1], p[2], res)
  1179. return res[0], res[1], res[2]
  1180. # getRelPointVel
  1181. def getRelPointVel(self, p):
  1182. """getRelPointVel(p) -> 3-tuple
  1183. Utility function that takes a point p on a body and returns
  1184. that point's velocity in global coordinates. The point p
  1185. must be given in body relative coordinates.
  1186. @param p: Body point (local coordinates)
  1187. @type p: 3-sequence of floats
  1188. """
  1189. cdef dVector3 res
  1190. dBodyGetRelPointVel(self.bid, p[0], p[1], p[2], res)
  1191. return res[0], res[1], res[2]
  1192. # getPointVel
  1193. def getPointVel(self, p):
  1194. """getPointVel(p) -> 3-tuple
  1195. Utility function that takes a point p on a body and returns
  1196. that point's velocity in global coordinates. The point p
  1197. must be given in global coordinates.
  1198. @param p: Body point (global coordinates)
  1199. @type p: 3-sequence of floats
  1200. """
  1201. cdef dVector3 res
  1202. dBodyGetPointVel(self.bid, p[0], p[1], p[2], res)
  1203. return res[0], res[1], res[2]
  1204. # getPosRelPoint
  1205. def getPosRelPoint(self, p):
  1206. """getPosRelPoint(p) -> 3-tuple
  1207. This is the inverse of getRelPointPos(). It takes a point p in
  1208. global coordinates and returns the point's position in
  1209. body-relative coordinates.
  1210. @param p: Body point (global coordinates)
  1211. @type p: 3-sequence of floats
  1212. """
  1213. cdef dVector3 res
  1214. dBodyGetPosRelPoint(self.bid, p[0], p[1], p[2], res)
  1215. return res[0], res[1], res[2]
  1216. # vectorToWorld
  1217. def vectorToWorld(self, v):
  1218. """vectorToWorld(v) -> 3-tuple
  1219. Given a vector v expressed in the body coordinate system, rotate
  1220. it to the world coordinate system.
  1221. @param v: Vector in body coordinate system
  1222. @type v: 3-sequence of floats
  1223. """
  1224. cdef dVector3 res
  1225. dBodyVectorToWorld(self.bid, v[0], v[1], v[2], res)
  1226. return res[0], res[1], res[2]
  1227. # vectorFromWorld
  1228. def vectorFromWorld(self, v):
  1229. """vectorFromWorld(v) -> 3-tuple
  1230. Given a vector v expressed in the world coordinate system, rotate
  1231. it to the body coordinate system.
  1232. @param v: Vector in world coordinate system
  1233. @type v: 3-sequence of floats
  1234. """
  1235. cdef dVector3 res
  1236. dBodyVectorFromWorld(self.bid, v[0], v[1], v[2], res)
  1237. return res[0], res[1], res[2]
  1238. # Enable
  1239. def enable(self):
  1240. """enable()
  1241. Manually enable a body.
  1242. """
  1243. dBodyEnable(self.bid)
  1244. # Disable
  1245. def disable(self):
  1246. """disable()
  1247. Manually disable a body. Note that a disabled body that is connected
  1248. through a joint to an enabled body will be automatically re-enabled
  1249. at the next simulation step.
  1250. """
  1251. dBodyDisable(self.bid)
  1252. # isEnabled
  1253. def isEnabled(self):
  1254. """isEnabled() -> bool
  1255. Check if a body is currently enabled.
  1256. """
  1257. return dBodyIsEnabled(self.bid)
  1258. # setFiniteRotationMode
  1259. def setFiniteRotationMode(self, mode):
  1260. """setFiniteRotationMode(mode)
  1261. This function controls the way a body's orientation is updated at
  1262. each time step. The mode argument can be:
  1263. - 0: An "infinitesimal" orientation update is used. This is
  1264. fast to compute, but it can occasionally cause inaccuracies
  1265. for bodies that are rotating at high speed, especially when
  1266. those bodies are joined to other bodies. This is the default
  1267. for every new body that is created.
  1268. - 1: A "finite" orientation update is used. This is more
  1269. costly to compute, but will be more accurate for high speed
  1270. rotations. Note however that high speed rotations can result
  1271. in many types of error in a simulation, and this mode will
  1272. only fix one of those sources of error.
  1273. @param mode: Rotation mode (0/1)
  1274. @type mode: int
  1275. """
  1276. dBodySetFiniteRotationMode(self.bid, mode)
  1277. # getFiniteRotationMode
  1278. def getFiniteRotationMode(self):
  1279. """getFiniteRotationMode() -> mode (0/1)
  1280. Return the current finite rotation mode of a body (0 or 1).
  1281. See setFiniteRotationMode().
  1282. """
  1283. return dBodyGetFiniteRotationMode(self.bid)
  1284. # setFiniteRotationAxis
  1285. def setFiniteRotationAxis(self, a):
  1286. """setFiniteRotationAxis(a)
  1287. Set the finite rotation axis of the body. This axis only has a
  1288. meaning when the finite rotation mode is set
  1289. (see setFiniteRotationMode()).
  1290. @param a: Axis
  1291. @type a: 3-sequence of floats
  1292. """
  1293. dBodySetFiniteRotationAxis(self.bid, a[0], a[1], a[2])
  1294. # getFiniteRotationAxis
  1295. def getFiniteRotationAxis(self):
  1296. """getFiniteRotationAxis() -> 3-tuple
  1297. Return the current finite rotation axis of the body.
  1298. """
  1299. cdef dVector3 p
  1300. # The "const" in the original return value is cast away
  1301. dBodyGetFiniteRotationAxis(self.bid, p)
  1302. return p[0], p[1], p[2]
  1303. # getNumJoints
  1304. def getNumJoints(self):
  1305. """getNumJoints() -> int
  1306. Return the number of joints that are attached to this body.
  1307. """
  1308. return dBodyGetNumJoints(self.bid)
  1309. # setGravityMode
  1310. def setGravityMode(self, mode):
  1311. """setGravityMode(mode)
  1312. Set whether the body is influenced by the world's gravity
  1313. or not. If mode is True it is, otherwise it isn't.
  1314. Newly created bodies are always influenced by the world's gravity.
  1315. @param mode: Gravity mode
  1316. @type mode: bool
  1317. """
  1318. dBodySetGravityMode(self.bid, mode)
  1319. # getGravityMode
  1320. def getGravityMode(self):
  1321. """getGravityMode() -> bool
  1322. Return True if the body is influenced by the world's gravity.
  1323. """
  1324. return dBodyGetGravityMode(self.bid)
  1325. def setDynamic(self):
  1326. """setDynamic()
  1327. Set a body to the (default) "dynamic" state, instead of "kinematic".
  1328. See setKinematic() for more information.
  1329. """
  1330. dBodySetDynamic(self.bid)
  1331. def setKinematic(self):
  1332. """setKinematic()
  1333. Set the kinematic state of the body (change it into a kinematic body)
  1334. Kinematic bodies behave as if they had infinite mass. This means they don't react
  1335. to any force (gravity, constraints or user-supplied); they simply follow
  1336. velocity to reach the next position. [from ODE wiki]
  1337. """
  1338. dBodySetKinematic(self.bid)
  1339. def isKinematic(self):
  1340. """isKinematic() -> bool
  1341. Return True if the body is kinematic (not influenced by other forces).
  1342. Kinematic bodies behave as if they had infinite mass. This means they don't react
  1343. to any force (gravity, constraints or user-supplied); they simply follow
  1344. velocity to reach the next position. [from ODE wiki]
  1345. """
  1346. return dBodyIsKinematic(self.bid)
  1347. def setMaxAngularSpeed(self, max_speed):
  1348. """setMaxAngularSpeed(max_speed)
  1349. You can also limit the maximum angular speed. In contrast to the damping
  1350. functions, the angular velocity is affected before the body is moved.
  1351. This means that it will introduce errors in joints that are forcing the
  1352. body to rotate too fast. Some bodies have naturally high angular
  1353. velocities (like cars' wheels), so you may want to give them a very high
  1354. (like the default, dInfinity) limit.
  1355. """
  1356. dBodySetMaxAngularSpeed(self.bid, max_speed)
  1357. # JointGroup
  1358. cdef class JointGroup:
  1359. """Joint group.
  1360. Constructor::
  1361. JointGroup()
  1362. """
  1363. # JointGroup ID
  1364. cdef dJointGroupID gid
  1365. # A list of Python joints that were added to the group
  1366. cdef object jointlist
  1367. def __cinit__(self):
  1368. self.gid = dJointGroupCreate(0)
  1369. def __init__(self):
  1370. self.jointlist = []
  1371. def __dealloc__(self):
  1372. if self.gid != NULL:
  1373. for j in self.jointlist:
  1374. j._destroyed()
  1375. dJointGroupDestroy(self.gid)
  1376. # empty
  1377. def empty(self):
  1378. """empty()
  1379. Destroy all joints in the group.
  1380. """
  1381. dJointGroupEmpty(self.gid)
  1382. for j in self.jointlist:
  1383. j._destroyed()
  1384. self.jointlist = []
  1385. def _addjoint(self, j):
  1386. """_addjoint(j)
  1387. Add a joint to the group. This is an internal method that is
  1388. called by the joints. The group has to know the Python
  1389. wrappers because it has to notify them when the group is
  1390. emptied (so that the ODE joints won't get destroyed
  1391. twice). The notification is done by calling _destroyed() on
  1392. the Python joints.
  1393. @param j: The joint to add
  1394. @type j: Joint
  1395. """
  1396. self.jointlist.append(j)
  1397. ######################################################################
  1398. # Joint
  1399. cdef class Joint:
  1400. """Base class for all joint classes."""
  1401. # Joint id as returned by dJointCreateXxx()
  1402. cdef dJointID jid
  1403. # A reference to the world so that the world won't be destroyed while
  1404. # there are still joints using it.
  1405. cdef object world
  1406. # The feedback buffer
  1407. cdef dJointFeedback* feedback
  1408. cdef object body1
  1409. cdef object body2
  1410. # A dictionary with user attributes
  1411. # (set via __getattr__ and __setattr__)
  1412. cdef object userattribs
  1413. def __cinit__(self, *a, **kw):
  1414. self.jid = NULL
  1415. self.world = None
  1416. self.feedback = NULL
  1417. self.body1 = None
  1418. self.body2 = None
  1419. self.userattribs = {}
  1420. def __init__(self, *a, **kw):
  1421. raise NotImplementedError("Joint base class can't be used directly")
  1422. def __dealloc__(self):
  1423. self.setFeedback(False)
  1424. if self.jid != NULL:
  1425. dJointDestroy(self.jid)
  1426. def __getattr__(self, name):
  1427. try:
  1428. return self.userattribs[name]
  1429. except:
  1430. raise AttributeError("Joint object has no attribute '%s'" % name)
  1431. def __setattr__(self, name, value):
  1432. self.userattribs[name] = value
  1433. def __delattr__(self, name):
  1434. try:
  1435. del self.userattribs[name]
  1436. except:
  1437. raise AttributeError("Joint object has no attribute '%s'" % name)
  1438. # _destroyed
  1439. def _destroyed(self):
  1440. """Notify the joint object about an external destruction of the ODE joint.
  1441. This method has to be called when the underlying ODE object
  1442. was destroyed by someone else (e.g. by a joint group). The Python
  1443. wrapper will then refrain from destroying it again.
  1444. """
  1445. self.jid = NULL
  1446. # enable
  1447. def enable(self):
  1448. """enable()
  1449. Enable the joint. Disabled joints are completely ignored during the
  1450. simulation. Disabled joints don't lose the already computed information
  1451. like anchors and axes.
  1452. """
  1453. dJointEnable(self.jid)
  1454. # disable
  1455. def disable(self):
  1456. """disable()
  1457. Disable the joint. Disabled joints are completely ignored during the
  1458. simulation. Disabled joints don't lose the already computed information
  1459. like anchors and axes.
  1460. """
  1461. dJointDisable(self.jid)
  1462. # isEnabled
  1463. def isEnabled(self):
  1464. """isEnabled() -> bool
  1465. Determine whether the joint is enabled. Disabled joints are completely
  1466. ignored during the simulation. Disabled joints don't lose the already
  1467. computed information like anchors and axes.
  1468. """
  1469. return dJointIsEnabled(self.jid)
  1470. # attach
  1471. def attach(self, Body body1, Body body2):
  1472. """attach(body1, body2)
  1473. Attach the joint to some new bodies. A body can be attached
  1474. to the environment by passing None as second body.
  1475. @param body1: First body
  1476. @param body2: Second body
  1477. @type body1: Body
  1478. @type body2: Body
  1479. """
  1480. cdef dBodyID id1, id2
  1481. if body1 == None:
  1482. id1 = NULL
  1483. else:
  1484. id1 = body1.bid
  1485. if body2 == None:
  1486. id2 = NULL
  1487. else:
  1488. id2 = body2.bid
  1489. self.body1 = body1
  1490. self.body2 = body2
  1491. dJointAttach(self.jid, id1, id2)
  1492. # getBody
  1493. def getBody(self, index):
  1494. """getBody(index) -> Body
  1495. Return the bodies that this joint connects. If index is 0 the
  1496. "first" body will be returned, corresponding to the body1
  1497. argument of the attach() method. If index is 1 the "second" body
  1498. will be returned, corresponding to the body2 argument of the
  1499. attach() method.
  1500. @param index: Bodx index (0 or 1).
  1501. @type index: int
  1502. """
  1503. if index == 0:
  1504. return self.body1
  1505. elif index == 1:
  1506. return self.body2
  1507. else:
  1508. raise IndexError()
  1509. # setFeedback
  1510. def setFeedback(self, flag=1):
  1511. """setFeedback(flag=True)
  1512. Create a feedback buffer. If flag is True then a buffer is
  1513. allocated and the forces/torques applied by the joint can
  1514. be read using the getFeedback() method. If flag is False the
  1515. buffer is released.
  1516. @param flag: Specifies whether a buffer should be created or released
  1517. @type flag: bool
  1518. """
  1519. if flag:
  1520. # Was there already a buffer allocated? then we're finished
  1521. if self.feedback != NULL:
  1522. return
  1523. # Allocate a buffer and pass it to ODE
  1524. self.feedback = <dJointFeedback*>malloc(sizeof(dJointFeedback))
  1525. if self.feedback == NULL:
  1526. raise MemoryError("can't allocate feedback buffer")
  1527. dJointSetFeedback(self.jid, self.feedback)
  1528. else:
  1529. if self.feedback != NULL:
  1530. # Free a previously allocated buffer
  1531. dJointSetFeedback(self.jid, NULL)
  1532. free(self.feedback)
  1533. self.feedback = NULL
  1534. # getFeedback
  1535. def getFeedback(self):
  1536. """getFeedback() -> (force1, torque1, force2, torque2)
  1537. Get the forces/torques applied by the joint. If feedback is
  1538. activated (i.e. setFeedback(True) was called) then this method
  1539. returns a tuple (force1, torque1, force2, torque2) with the
  1540. forces and torques applied to body 1 and body 2. The
  1541. forces/torques are given as 3-tuples.
  1542. If feedback is deactivated then the method always returns None.
  1543. """
  1544. cdef dJointFeedback* fb
  1545. fb = dJointGetFeedback(self.jid)
  1546. if fb == NULL:
  1547. return None
  1548. f1 = (fb.f1[0], fb.f1[1], fb.f1[2])
  1549. t1 = (fb.t1[0], fb.t1[1], fb.t1[2])
  1550. f2 = (fb.f2[0], fb.f2[1], fb.f2[2])
  1551. t2 = (fb.t2[0], fb.t2[1], fb.t2[2])
  1552. return f1, t1, f2, t2
  1553. ######################################################################
  1554. # BallJoint
  1555. cdef class BallJoint(Joint):
  1556. """Ball joint.
  1557. Constructor::
  1558. BallJoint(world, jointgroup=None)
  1559. """
  1560. def __cinit__(self, World world not None, jointgroup=None):
  1561. cdef JointGroup jg
  1562. cdef dJointGroupID jgid
  1563. jgid = NULL
  1564. if jointgroup != None:
  1565. jg = jointgroup
  1566. jgid = jg.gid
  1567. self.jid = dJointCreateBall(world.wid, jgid)
  1568. def __init__(self, World world not None, jointgroup=None):
  1569. self.world = world
  1570. if jointgroup != None:
  1571. jointgroup._addjoint(self)
  1572. # setAnchor
  1573. def setAnchor(self, pos):
  1574. """setAnchor(pos)
  1575. Set the joint anchor point which must be specified in world
  1576. coordinates.
  1577. @param pos: Anchor position
  1578. @type pos: 3-sequence of floats
  1579. """
  1580. dJointSetBallAnchor(self.jid, pos[0], pos[1], pos[2])
  1581. # getAnchor
  1582. def getAnchor(self):
  1583. """getAnchor() -> 3-tuple of floats
  1584. Get the joint anchor point, in world coordinates. This
  1585. returns the point on body 1. If the joint is perfectly
  1586. satisfied, this will be the same as the point on body 2.
  1587. """
  1588. cdef dVector3 p
  1589. dJointGetBallAnchor(self.jid, p)
  1590. return p[0], p[1], p[2]
  1591. # getAnchor2
  1592. def getAnchor2(self):
  1593. """getAnchor2() -> 3-tuple of floats
  1594. Get the joint anchor point, in world coordinates. This
  1595. returns the point on body 2. If the joint is perfectly
  1596. satisfied, this will be the same as the point on body 1.
  1597. """
  1598. cdef dVector3 p
  1599. dJointGetBallAnchor2(self.jid, p)
  1600. return p[0], p[1], p[2]
  1601. # setParam
  1602. def setParam(self, param, value):
  1603. pass
  1604. # getParam
  1605. def getParam(self, param):
  1606. return 0.0
  1607. # HingeJoint
  1608. cdef class HingeJoint(Joint):
  1609. """Hinge joint.
  1610. Constructor::
  1611. HingeJoint(world, jointgroup=None)
  1612. """
  1613. def __cinit__(self, World world not None, jointgroup=None):
  1614. cdef JointGroup jg
  1615. cdef dJointGroupID jgid
  1616. jgid = NULL
  1617. if jointgroup != None:
  1618. jg = jointgroup
  1619. jgid = jg.gid
  1620. self.jid = dJointCreateHinge(world.wid, jgid)
  1621. def __init__(self, World world not None, jointgroup=None):
  1622. self.world = world
  1623. if jointgroup != None:
  1624. jointgroup._addjoint(self)
  1625. # setAnchor
  1626. def setAnchor(self, pos):
  1627. """setAnchor(pos)
  1628. Set the hinge anchor which must be given in world coordinates.
  1629. @param pos: Anchor position
  1630. @type pos: 3-sequence of floats
  1631. """
  1632. dJointSetHingeAnchor(self.jid, pos[0], pos[1], pos[2])
  1633. # getAnchor
  1634. def getAnchor(self):
  1635. """getAnchor() -> 3-tuple of floats
  1636. Get the joint anchor point, in world coordinates. This returns
  1637. the point on body 1. If the joint is perfectly satisfied, this
  1638. will be the same as the point on body 2.
  1639. """
  1640. cdef dVector3 p
  1641. dJointGetHingeAnchor(self.jid, p)
  1642. return p[0], p[1], p[2]
  1643. # getAnchor2
  1644. def getAnchor2(self):
  1645. """getAnchor2() -> 3-tuple of floats
  1646. Get the joint anchor point, in world coordinates. This returns
  1647. the point on body 2. If the joint is perfectly satisfied, this
  1648. will be the same as the point on body 1.
  1649. """
  1650. cdef dVector3 p
  1651. dJointGetHingeAnchor2(self.jid, p)
  1652. return p[0], p[1], p[2]
  1653. # setAxis
  1654. def setAxis(self, axis):
  1655. """setAxis(axis)
  1656. Set the hinge axis.
  1657. @param axis: Hinge axis
  1658. @type axis: 3-sequence of floats
  1659. """
  1660. dJointSetHingeAxis(self.jid, axis[0], axis[1], axis[2])
  1661. # getAxis
  1662. def getAxis(self):
  1663. """getAxis() -> 3-tuple of floats
  1664. Get the hinge axis.
  1665. """
  1666. cdef dVector3 a
  1667. dJointGetHingeAxis(self.jid, a)
  1668. return a[0], a[1], a[2]
  1669. # getAngle
  1670. def getAngle(self):
  1671. """getAngle() -> float
  1672. Get the hinge angle. The angle is measured between the two
  1673. bodies, or between the body and the static environment. The
  1674. angle will be between -pi..pi.
  1675. When the hinge anchor or axis is set, the current position of
  1676. the attached bodies is examined and that position will be the
  1677. zero angle.
  1678. """
  1679. return dJointGetHingeAngle(self.jid)
  1680. # getAngleRate
  1681. def getAngleRate(self):
  1682. """getAngleRate() -> float
  1683. Get the time derivative of the angle.
  1684. """
  1685. return dJointGetHingeAngleRate(self.jid)
  1686. # addTorque
  1687. def addTorque(self, torque):
  1688. """addTorque(torque)
  1689. Applies the torque about the hinge axis.
  1690. @param torque: Torque magnitude
  1691. @type torque: float
  1692. """
  1693. dJointAddHingeTorque(self.jid, torque)
  1694. # setParam
  1695. def setParam(self, param, value):
  1696. """setParam(param, value)
  1697. Set limit/motor parameters for the joint.
  1698. param is one of ParamLoStop, ParamHiStop, ParamVel, ParamFMax,
  1699. ParamFudgeFactor, ParamBounce, ParamCFM, ParamStopERP, ParamStopCFM,
  1700. ParamSuspensionERP, ParamSuspensionCFM.
  1701. These parameter names can be optionally followed by a digit (2
  1702. or 3) to indicate the second or third set of parameters.
  1703. @param param: Selects the parameter to set
  1704. @param value: Parameter value
  1705. @type param: int
  1706. @type value: float
  1707. """
  1708. dJointSetHingeParam(self.jid, param, value)
  1709. # getParam
  1710. def getParam(self, param):
  1711. """getParam(param) -> float
  1712. Get limit/motor parameters for the joint.
  1713. param is one of ParamLoStop, ParamHiStop, ParamVel, ParamFMax,
  1714. ParamFudgeFactor, ParamBounce, ParamCFM, ParamStopERP, ParamStopCFM,
  1715. ParamSuspensionERP, ParamSuspensionCFM.
  1716. These parameter names can be optionally followed by a digit (2
  1717. or 3) to indicate the second or third set of parameters.
  1718. @param param: Selects the parameter to read
  1719. @type param: int
  1720. """
  1721. return dJointGetHingeParam(self.jid, param)
  1722. # SliderJoint
  1723. cdef class SliderJoint(Joint):
  1724. """Slider joint.
  1725. Constructor::
  1726. SlideJoint(world, jointgroup=None)
  1727. """
  1728. def __cinit__(self, World world not None, jointgroup=None):
  1729. cdef JointGroup jg
  1730. cdef dJointGroupID jgid
  1731. jgid = NULL
  1732. if jointgroup != None:
  1733. jg = jointgroup
  1734. jgid = jg.gid
  1735. self.jid = dJointCreateSlider(world.wid, jgid)
  1736. def __init__(self, World world not None, jointgroup=None):
  1737. self.world = world
  1738. if jointgroup != None:
  1739. jointgroup._addjoint(self)
  1740. # setAxis
  1741. def setAxis(self, axis):
  1742. """setAxis(axis)
  1743. Set the slider axis parameter.
  1744. @param axis: Slider axis
  1745. @type axis: 3-sequence of floats
  1746. """
  1747. dJointSetSliderAxis(self.jid, axis[0], axis[1], axis[2])
  1748. # getAxis
  1749. def getAxis(self):
  1750. """getAxis() -> 3-tuple of floats
  1751. Get the slider axis parameter.
  1752. """
  1753. cdef dVector3 a
  1754. dJointGetSliderAxis(self.jid, a)
  1755. return a[0], a[1], a[2]
  1756. # getPosition
  1757. def getPosition(self):
  1758. """getPosition() -> float
  1759. Get the slider linear position (i.e. the slider's "extension").
  1760. When the axis is set, the current position of the attached
  1761. bodies is examined and that position will be the zero
  1762. position.
  1763. """
  1764. return dJointGetSliderPosition(self.jid)
  1765. # getPositionRate
  1766. def getPositionRate(self):
  1767. """getPositionRate() -> float
  1768. Get the time derivative of the position.
  1769. """
  1770. return dJointGetSliderPositionRate(self.jid)
  1771. # addForce
  1772. def addForce(self, force):
  1773. """addForce(force)
  1774. Applies the given force in the slider's direction.
  1775. @param force: Force magnitude
  1776. @type force: float
  1777. """
  1778. dJointAddSliderForce(self.jid, force)
  1779. # setParam
  1780. def setParam(self, param, value):
  1781. dJointSetSliderParam(self.jid, param, value)
  1782. # getParam
  1783. def getParam(self, param):
  1784. return dJointGetSliderParam(self.jid, param)
  1785. # UniversalJoint
  1786. cdef class UniversalJoint(Joint):
  1787. """Universal joint.
  1788. Constructor::
  1789. UniversalJoint(world, jointgroup=None)
  1790. """
  1791. def __cinit__(self, World world not None, jointgroup=None):
  1792. cdef JointGroup jg
  1793. cdef dJointGroupID jgid
  1794. jgid = NULL
  1795. if jointgroup != None:
  1796. jg = jointgroup
  1797. jgid = jg.gid
  1798. self.jid = dJointCreateUniversal(world.wid, jgid)
  1799. def __init__(self, World world not None, jointgroup=None):
  1800. self.world = world
  1801. if jointgroup != None:
  1802. jointgroup._addjoint(self)
  1803. # setAnchor
  1804. def setAnchor(self, pos):
  1805. """setAnchor(pos)
  1806. Set the universal anchor.
  1807. @param pos: Anchor position
  1808. @type pos: 3-sequence of floats
  1809. """
  1810. dJointSetUniversalAnchor(self.jid, pos[0], pos[1], pos[2])
  1811. # getAnchor
  1812. def getAnchor(self):
  1813. """getAnchor() -> 3-tuple of floats
  1814. Get the joint anchor point, in world coordinates. This returns
  1815. the point on body 1. If the joint is perfectly satisfied, this
  1816. will be the same as the point on body 2.
  1817. """
  1818. cdef dVector3 p
  1819. dJointGetUniversalAnchor(self.jid, p)
  1820. return p[0], p[1], p[2]
  1821. # getAnchor2
  1822. def getAnchor2(self):
  1823. """getAnchor2() -> 3-tuple of floats
  1824. Get the joint anchor point, in world coordinates. This returns
  1825. the point on body 2. If the joint is perfectly satisfied, this
  1826. will be the same as the point on body 1.
  1827. """
  1828. cdef dVector3 p
  1829. dJointGetUniversalAnchor2(self.jid, p)
  1830. return p[0], p[1], p[2]
  1831. # setAxis1
  1832. def setAxis1(self, axis):
  1833. """setAxis1(axis)
  1834. Set the first universal axis. Axis 1 and axis 2 should be
  1835. perpendicular to each other.
  1836. @param axis: Joint axis
  1837. @type axis: 3-sequence of floats
  1838. """
  1839. dJointSetUniversalAxis1(self.jid, axis[0], axis[1], axis[2])
  1840. # getAxis1
  1841. def getAxis1(self):
  1842. """getAxis1() -> 3-tuple of floats
  1843. Get the first univeral axis.
  1844. """
  1845. cdef dVector3 a
  1846. dJointGetUniversalAxis1(self.jid, a)
  1847. return a[0], a[1], a[2]
  1848. # setAxis2
  1849. def setAxis2(self, axis):
  1850. """setAxis2(axis)
  1851. Set the second universal axis. Axis 1 and axis 2 should be
  1852. perpendicular to each other.
  1853. @param axis: Joint axis
  1854. @type axis: 3-sequence of floats
  1855. """
  1856. dJointSetUniversalAxis2(self.jid, axis[0], axis[1], axis[2])
  1857. # getAxis2
  1858. def getAxis2(self):
  1859. """getAxis2() -> 3-tuple of floats
  1860. Get the second univeral axis.
  1861. """
  1862. cdef dVector3 a
  1863. dJointGetUniversalAxis2(self.jid, a)
  1864. return a[0], a[1], a[2]
  1865. # addTorques
  1866. def addTorques(self, torque1, torque2):
  1867. """addTorques(torque1, torque2)
  1868. Applies torque1 about axis 1, and torque2 about axis 2.
  1869. @param torque1: Torque 1 magnitude
  1870. @param torque2: Torque 2 magnitude
  1871. @type torque1: float
  1872. @type torque2: float
  1873. """
  1874. dJointAddUniversalTorques(self.jid, torque1, torque2)
  1875. def getAngle1(self):
  1876. return dJointGetUniversalAngle1(self.jid)
  1877. def getAngle2(self):
  1878. return dJointGetUniversalAngle2(self.jid)
  1879. def getAngle1Rate(self):
  1880. return dJointGetUniversalAngle1Rate(self.jid)
  1881. def getAngle2Rate(self):
  1882. return dJointGetUniversalAngle2Rate(self.jid)
  1883. # setParam
  1884. def setParam(self, param, value):
  1885. dJointSetUniversalParam(self.jid, param, value)
  1886. # getParam
  1887. def getParam(self, param):
  1888. return dJointGetUniversalParam(self.jid, param)
  1889. # Hinge2Joint
  1890. cdef class Hinge2Joint(Joint):
  1891. """Hinge2 joint.
  1892. Constructor::
  1893. Hinge2Joint(world, jointgroup=None)
  1894. """
  1895. def __cinit__(self, World world not None, jointgroup=None):
  1896. cdef JointGroup jg
  1897. cdef dJointGroupID jgid
  1898. jgid = NULL
  1899. if jointgroup != None:
  1900. jg = jointgroup
  1901. jgid = jg.gid
  1902. self.jid = dJointCreateHinge2(world.wid, jgid)
  1903. def __init__(self, World world, jointgroup=None):
  1904. self.world = world
  1905. if jointgroup != None:
  1906. jointgroup._addjoint(self)
  1907. # setAnchor
  1908. def setAnchor(self, pos):
  1909. """setAnchor(pos)
  1910. Set the hinge-2 anchor.
  1911. @param pos: Anchor position
  1912. @type pos: 3-sequence of floats
  1913. """
  1914. dJointSetHinge2Anchor(self.jid, pos[0], pos[1], pos[2])
  1915. # getAnchor
  1916. def getAnchor(self):
  1917. """getAnchor() -> 3-tuple of floats
  1918. Get the joint anchor point, in world coordinates. This returns
  1919. the point on body 1. If the joint is perfectly satisfied, this
  1920. will be the same as the point on body 2.
  1921. """
  1922. cdef dVector3 p
  1923. dJointGetHinge2Anchor(self.jid, p)
  1924. return p[0], p[1], p[2]
  1925. # getAnchor2
  1926. def getAnchor2(self):
  1927. """getAnchor2() -> 3-tuple of floats
  1928. Get the joint anchor point, in world coordinates. This returns
  1929. the point on body 2. If the joint is perfectly satisfied, this
  1930. will be the same as the point on body 1.
  1931. """
  1932. cdef dVector3 p
  1933. dJointGetHinge2Anchor2(self.jid, p)
  1934. return p[0], p[1], p[2]
  1935. # setAxis1
  1936. def setAxis1(self, axis):
  1937. """setAxis1(axis)
  1938. Set the first hinge-2 axis. Axis 1 and axis 2 must not lie
  1939. along the same line.
  1940. @param axis: Joint axis
  1941. @type axis: 3-sequence of floats
  1942. """
  1943. dJointSetHinge2Axis1(self.jid, axis[0], axis[1], axis[2])
  1944. # getAxis1
  1945. def getAxis1(self):
  1946. """getAxis1() -> 3-tuple of floats
  1947. Get the first hinge-2 axis.
  1948. """
  1949. cdef dVector3 a
  1950. dJointGetHinge2Axis1(self.jid, a)
  1951. return a[0], a[1], a[2]
  1952. # setAxis2
  1953. def setAxis2(self, axis):
  1954. """setAxis2(axis)
  1955. Set the second hinge-2 axis. Axis 1 and axis 2 must not lie
  1956. along the same line.
  1957. @param axis: Joint axis
  1958. @type axis: 3-sequence of floats
  1959. """
  1960. dJointSetHinge2Axis2(self.jid, axis[0], axis[1], axis[2])
  1961. # getAxis2
  1962. def getAxis2(self):
  1963. """getAxis2() -> 3-tuple of floats
  1964. Get the second hinge-2 axis.
  1965. """
  1966. cdef dVector3 a
  1967. dJointGetHinge2Axis2(self.jid, a)
  1968. return a[0], a[1], a[2]
  1969. # getAngle
  1970. def getAngle1(self):
  1971. """getAngle1() -> float
  1972. Get the first hinge-2 angle (around axis 1).
  1973. When the anchor or axis is set, the current position of the
  1974. attached bodies is examined and that position will be the zero
  1975. angle.
  1976. """
  1977. return dJointGetHinge2Angle1(self.jid)
  1978. # getAngle1Rate
  1979. def getAngle1Rate(self):
  1980. """getAngle1Rate() -> float
  1981. Get the time derivative of the first hinge-2 angle.
  1982. """
  1983. return dJointGetHinge2Angle1Rate(self.jid)
  1984. # getAngle2Rate
  1985. def getAngle2Rate(self):
  1986. """getAngle2Rate() -> float
  1987. Get the time derivative of the second hinge-2 angle.
  1988. """
  1989. return dJointGetHinge2Angle2Rate(self.jid)
  1990. # addTorques
  1991. def addTorques(self, torque1, torque2):
  1992. """addTorques(torque1, torque2)
  1993. Applies torque1 about axis 1, and torque2 about axis 2.
  1994. @param torque1: Torque 1 magnitude
  1995. @param torque2: Torque 2 magnitude
  1996. @type torque1: float
  1997. @type torque2: float
  1998. """
  1999. dJointAddHinge2Torques(self.jid, torque1, torque2)
  2000. # setParam
  2001. def setParam(self, param, value):
  2002. dJointSetHinge2Param(self.jid, param, value)
  2003. # getParam
  2004. def getParam(self, param):
  2005. return dJointGetHinge2Param(self.jid, param)
  2006. # FixedJoint
  2007. cdef class FixedJoint(Joint):
  2008. """Fixed joint.
  2009. Constructor::
  2010. FixedJoint(world, jointgroup=None)
  2011. """
  2012. def __cinit__(self, World world not None, jointgroup=None):
  2013. cdef JointGroup jg
  2014. cdef dJointGroupID jgid
  2015. jgid = NULL
  2016. if jointgroup != None:
  2017. jg = jointgroup
  2018. jgid = jg.gid
  2019. self.jid = dJointCreateFixed(world.wid, jgid)
  2020. def __init__(self, World world not None, jointgroup=None):
  2021. self.world = world
  2022. if jointgroup != None:
  2023. jointgroup._addjoint(self)
  2024. # setFixed
  2025. def setFixed(self):
  2026. """setFixed()
  2027. Call this on the fixed joint after it has been attached to
  2028. remember the current desired relative offset and desired
  2029. relative rotation between the bodies.
  2030. """
  2031. dJointSetFixed(self.jid)
  2032. # ContactJoint
  2033. cdef class ContactJoint(Joint):
  2034. """Contact joint.
  2035. Constructor::
  2036. ContactJoint(world, jointgroup, contact)
  2037. """
  2038. def __cinit__(self, World world not None, jointgroup, Contact contact):
  2039. cdef JointGroup jg
  2040. cdef dJointGroupID jgid
  2041. jgid = NULL
  2042. if jointgroup != None:
  2043. jg = jointgroup
  2044. jgid = jg.gid
  2045. self.jid = dJointCreateContact(world.wid, jgid, &contact._contact)
  2046. def __init__(self, World world not None, jointgroup, Contact contact):
  2047. self.world = world
  2048. if jointgroup != None:
  2049. jointgroup._addjoint(self)
  2050. # AMotor
  2051. cdef class AMotor(Joint):
  2052. """AMotor joint.
  2053. Constructor::
  2054. AMotor(world, jointgroup=None)
  2055. """
  2056. def __cinit__(self, World world not None, jointgroup=None):
  2057. cdef JointGroup jg
  2058. cdef dJointGroupID jgid
  2059. jgid = NULL
  2060. if jointgroup != None:
  2061. jg = jointgroup
  2062. jgid = jg.gid
  2063. self.jid = dJointCreateAMotor(world.wid, jgid)
  2064. def __init__(self, World world not None, jointgroup=None):
  2065. self.world = world
  2066. if jointgroup != None:
  2067. jointgroup._addjoint(self)
  2068. # setMode
  2069. def setMode(self, mode):
  2070. """setMode(mode)
  2071. Set the angular motor mode. mode must be either AMotorUser or
  2072. AMotorEuler.
  2073. @param mode: Angular motor mode
  2074. @type mode: int
  2075. """
  2076. dJointSetAMotorMode(self.jid, mode)
  2077. # getMode
  2078. def getMode(self):
  2079. """getMode()
  2080. Return the angular motor mode (AMotorUser or AMotorEuler).
  2081. """
  2082. return dJointGetAMotorMode(self.jid)
  2083. # setNumAxes
  2084. def setNumAxes(self, int num):
  2085. """setNumAxes(num)
  2086. Set the number of angular axes that will be controlled by the AMotor.
  2087. num may be in the range from 0 to 3.
  2088. @param num: Number of axes (0-3)
  2089. @type num: int
  2090. """
  2091. dJointSetAMotorNumAxes(self.jid, num)
  2092. # getNumAxes
  2093. def getNumAxes(self):
  2094. """getNumAxes() -> int
  2095. Get the number of angular axes that are controlled by the AMotor.
  2096. """
  2097. return dJointGetAMotorNumAxes(self.jid)
  2098. # setAxis
  2099. def setAxis(self, int anum, int rel, axis):
  2100. """setAxis(anum, rel, axis)
  2101. Set an AMotor axis.
  2102. The anum argument selects the axis to change (0,1 or 2).
  2103. Each axis can have one of three "relative orientation" modes,
  2104. selected by rel:
  2105. 0: The axis is anchored to the global frame.
  2106. 1: The axis is anchored to the first body.
  2107. 2: The axis is anchored to the second body.
  2108. The axis vector is always specified in global coordinates
  2109. regardless of the setting of rel.
  2110. @param anum: Axis number
  2111. @param rel: Relative orientation mode
  2112. @param axis: Axis
  2113. @type anum: int
  2114. @type rel: int
  2115. @type axis: 3-sequence of floats
  2116. """
  2117. dJointSetAMotorAxis(self.jid, anum, rel, axis[0], axis[1], axis[2])
  2118. # getAxis
  2119. def getAxis(self, int anum):
  2120. """getAxis(anum)
  2121. Get an AMotor axis.
  2122. @param anum: Axis index (0-2)
  2123. @type anum: int
  2124. """
  2125. cdef dVector3 a
  2126. dJointGetAMotorAxis(self.jid, anum, a)
  2127. return a[0], a[1], a[2]
  2128. # getAxisRel
  2129. def getAxisRel(self, int anum):
  2130. """getAxisRel(anum) -> int
  2131. Get the relative mode of an axis.
  2132. @param anum: Axis index (0-2)
  2133. @type anum: int
  2134. """
  2135. return dJointGetAMotorAxisRel(self.jid, anum)
  2136. # setAngle
  2137. def setAngle(self, int anum, angle):
  2138. """setAngle(anum, angle)
  2139. Tell the AMotor what the current angle is along axis anum.
  2140. @param anum: Axis index
  2141. @param angle: Angle
  2142. @type anum: int
  2143. @type angle: float
  2144. """
  2145. dJointSetAMotorAngle(self.jid, anum, angle)
  2146. # getAngle
  2147. def getAngle(self, int anum):
  2148. """getAngle(anum) -> float
  2149. Return the current angle for axis anum.
  2150. @param anum: Axis index
  2151. @type anum: int
  2152. """
  2153. return dJointGetAMotorAngle(self.jid, anum)
  2154. # getAngleRate
  2155. def getAngleRate(self, int anum):
  2156. """getAngleRate(anum) -> float
  2157. Return the current angle rate for axis anum.
  2158. @param anum: Axis index
  2159. @type anum: int
  2160. """
  2161. return dJointGetAMotorAngleRate(self.jid, anum)
  2162. # addTorques
  2163. def addTorques(self, torque0, torque1, torque2):
  2164. """addTorques(torque0, torque1, torque2)
  2165. Applies torques about the AMotor's axes.
  2166. @param torque0: Torque 0 magnitude
  2167. @param torque1: Torque 1 magnitude
  2168. @param torque2: Torque 2 magnitude
  2169. @type torque0: float
  2170. @type torque1: float
  2171. @type torque2: float
  2172. """
  2173. dJointAddAMotorTorques(self.jid, torque0, torque1, torque2)
  2174. # setParam
  2175. def setParam(self, param, value):
  2176. dJointSetAMotorParam(self.jid, param, value)
  2177. # getParam
  2178. def getParam(self, param):
  2179. return dJointGetAMotorParam(self.jid, param)
  2180. # LMotor
  2181. cdef class LMotor(Joint):
  2182. """LMotor joint.
  2183. Constructor::
  2184. LMotor(world, jointgroup=None)
  2185. """
  2186. def __cinit__(self, World world not None, jointgroup=None):
  2187. cdef JointGroup jg
  2188. cdef dJointGroupID jgid
  2189. jgid = NULL
  2190. if jointgroup != None:
  2191. jg = jointgroup
  2192. jgid = jg.gid
  2193. self.jid = dJointCreateLMotor(world.wid, jgid)
  2194. def __init__(self, World world not None, jointgroup=None):
  2195. self.world = world
  2196. if jointgroup != None:
  2197. jointgroup._addjoint(self)
  2198. # setNumAxes
  2199. def setNumAxes(self, int num):
  2200. """setNumAxes(num)
  2201. Set the number of angular axes that will be controlled by the LMotor.
  2202. num may be in the range from 0 to 3.
  2203. @param num: Number of axes (0-3)
  2204. @type num: int
  2205. """
  2206. dJointSetLMotorNumAxes(self.jid, num)
  2207. # getNumAxes
  2208. def getNumAxes(self):
  2209. """getNumAxes() -> int
  2210. Get the number of angular axes that are controlled by the LMotor.
  2211. """
  2212. return dJointGetLMotorNumAxes(self.jid)
  2213. # setAxis
  2214. def setAxis(self, int anum, int rel, axis):
  2215. """setAxis(anum, rel, axis)
  2216. Set an LMotor axis.
  2217. The anum argument selects the axis to change (0,1 or 2).
  2218. Each axis can have one of three "relative orientation" modes,
  2219. selected by rel:
  2220. 0: The axis is anchored to the global frame.
  2221. 1: The axis is anchored to the first body.
  2222. 2: The axis is anchored to the second body.
  2223. @param anum: Axis number
  2224. @param rel: Relative orientation mode
  2225. @param axis: Axis
  2226. @type anum: int
  2227. @type rel: int
  2228. @type axis: 3-sequence of floats
  2229. """
  2230. dJointSetLMotorAxis(self.jid, anum, rel, axis[0], axis[1], axis[2])
  2231. # getAxis
  2232. def getAxis(self, int anum):
  2233. """getAxis(anum)
  2234. Get an LMotor axis.
  2235. @param anum: Axis index (0-2)
  2236. @type anum: int
  2237. """
  2238. cdef dVector3 a
  2239. dJointGetLMotorAxis(self.jid, anum, a)
  2240. return a[0], a[1], a[2]
  2241. # setParam
  2242. def setParam(self, param, value):
  2243. dJointSetLMotorParam(self.jid, param, value)
  2244. # getParam
  2245. def getParam(self, param):
  2246. return dJointGetLMotorParam(self.jid, param)
  2247. # Plane2DJoint
  2248. cdef class Plane2DJoint(Joint):
  2249. """Plane-2D Joint.
  2250. Constructor::
  2251. Plane2DJoint(world, jointgroup=None)
  2252. """
  2253. def __cinit__(self, World world not None, jointgroup=None):
  2254. cdef JointGroup jg
  2255. cdef dJointGroupID jgid
  2256. jgid = NULL
  2257. if jointgroup != None:
  2258. jg = jointgroup
  2259. jgid = jg.gid
  2260. self.jid = dJointCreatePlane2D(world.wid, jgid)
  2261. def __init__(self, World world not None, jointgroup=None):
  2262. self.world = world
  2263. if jointgroup != None:
  2264. jointgroup._addjoint(self)
  2265. def setXParam(self, param, value):
  2266. dJointSetPlane2DXParam(self.jid, param, value)
  2267. def setYParam(self, param, value):
  2268. dJointSetPlane2DYParam(self.jid, param, value)
  2269. def setAngleParam(self, param, value):
  2270. dJointSetPlane2DAngleParam(self.jid, param, value)
  2271. # Geom base class
  2272. cdef class GeomObject:
  2273. """This is the abstract base class for all geom objects.
  2274. """
  2275. # The id of the geom object as returned by dCreateXxxx()
  2276. cdef dGeomID gid
  2277. # The space in which the geom was placed (or None). This reference
  2278. # is kept so that the space won't be destroyed while there are still
  2279. # geoms around that might use it.
  2280. cdef object space
  2281. # The body that the geom was attached to (or None).
  2282. cdef object body
  2283. # A dictionary with user defined attributes
  2284. cdef object attribs
  2285. cdef object __weakref__
  2286. def __cinit__(self, *a, **kw):
  2287. self.gid = NULL
  2288. self.space = None
  2289. self.body = None
  2290. self.attribs = {}
  2291. def __init__(self, *a, **kw):
  2292. raise NotImplementedError(
  2293. "GeomObject base class can't be used directly")
  2294. def __dealloc__(self):
  2295. if self.gid != NULL:
  2296. dGeomDestroy(self.gid)
  2297. self.gid = NULL
  2298. def __getattr__(self, name):
  2299. if name in self.attribs:
  2300. return self.attribs[name]
  2301. else:
  2302. raise AttributeError("geom has no attribute '%s'" % name)
  2303. def __setattr__(self, name, val):
  2304. self.attribs[name] = val
  2305. def __delattr__(self, name):
  2306. if name in self.attribs:
  2307. del self.attribs[name]
  2308. else:
  2309. raise AttributeError("geom has no attribute '%s'" % name)
  2310. def _id(self):
  2311. """_id() -> int
  2312. Return the internal id of the geom (dGeomID) as returned by
  2313. the dCreateXyz() functions.
  2314. This method has to be overwritten in derived methods.
  2315. """
  2316. raise NotImplementedError("Bug: The _id() method is not implemented")
  2317. def placeable(self):
  2318. """placeable() -> bool
  2319. Returns True if the geom object is a placeable geom.
  2320. This method has to be overwritten in derived methods.
  2321. """
  2322. return False
  2323. def setBody(self, Body body):
  2324. """setBody(body)
  2325. Set the body associated with a placeable geom.
  2326. @param body: The Body object or None.
  2327. @type body: Body
  2328. """
  2329. if not self.placeable():
  2330. raise ValueError(
  2331. "Non-placeable geoms cannot have a body associated to them")
  2332. if body == None:
  2333. dGeomSetBody(self.gid, NULL)
  2334. else:
  2335. dGeomSetBody(self.gid, body.bid)
  2336. self.body = body
  2337. def getBody(self):
  2338. """getBody() -> Body
  2339. Get the body associated with this geom.
  2340. """
  2341. if not self.placeable():
  2342. return environment
  2343. return self.body
  2344. def setPosition(self, pos):
  2345. """setPosition(pos)
  2346. Set the position of the geom. If the geom is attached to a body,
  2347. the body's position will also be changed.
  2348. @param pos: Position
  2349. @type pos: 3-sequence of floats
  2350. """
  2351. if not self.placeable():
  2352. raise ValueError("Cannot set a position on non-placeable geoms")
  2353. dGeomSetPosition(self.gid, pos[0], pos[1], pos[2])
  2354. def getPosition(self):
  2355. """getPosition() -> 3-tuple
  2356. Get the current position of the geom. If the geom is attached to
  2357. a body the returned value is the body's position.
  2358. """
  2359. if not self.placeable():
  2360. raise ValueError("Non-placeable geoms do not have a position")
  2361. cdef dReal* p
  2362. p = <dReal*>dGeomGetPosition(self.gid)
  2363. return p[0], p[1], p[2]
  2364. def setRotation(self, R):
  2365. """setRotation(R)
  2366. Set the orientation of the geom. If the geom is attached to a body,
  2367. the body's orientation will also be changed.
  2368. @param R: Rotation matrix
  2369. @type R: 9-sequence of floats
  2370. """
  2371. if not self.placeable():
  2372. raise ValueError("Cannot set a rotation on non-placeable geoms")
  2373. cdef dMatrix3 m
  2374. m[0] = R[0]
  2375. m[1] = R[1]
  2376. m[2] = R[2]
  2377. m[3] = 0
  2378. m[4] = R[3]
  2379. m[5] = R[4]
  2380. m[6] = R[5]
  2381. m[7] = 0
  2382. m[8] = R[6]
  2383. m[9] = R[7]
  2384. m[10] = R[8]
  2385. m[11] = 0
  2386. dGeomSetRotation(self.gid, m)
  2387. def getRotation(self):
  2388. """getRotation() -> 9-tuple
  2389. Get the current orientation of the geom. If the geom is attached to
  2390. a body the returned value is the body's orientation.
  2391. """
  2392. if not self.placeable():
  2393. raise ValueError("Non-placeable geoms do not have a rotation")
  2394. cdef dReal* m
  2395. m = <dReal*>dGeomGetRotation(self.gid)
  2396. return [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]]
  2397. def getQuaternion(self):
  2398. """getQuaternion() -> (w,x,y,z)
  2399. Get the current orientation of the geom. If the geom is attached to
  2400. a body the returned value is the body's orientation.
  2401. """
  2402. if not self.placeable():
  2403. raise ValueError("Non-placeable geoms do not have an orientation")
  2404. cdef dQuaternion q
  2405. dGeomGetQuaternion(self.gid, q)
  2406. return q[0], q[1], q[2], q[3]
  2407. def setQuaternion(self, q):
  2408. """setQuaternion(q)
  2409. Set the orientation of the geom. If the geom is attached to a body,
  2410. the body's orientation will also be changed.
  2411. @param q: Quaternion (w,x,y,z)
  2412. @type q: 4-sequence of floats
  2413. """
  2414. if not self.placeable():
  2415. raise ValueError("Cannot set a quaternion on non-placeable geoms")
  2416. cdef dQuaternion cq
  2417. cq[0] = q[0]
  2418. cq[1] = q[1]
  2419. cq[2] = q[2]
  2420. cq[3] = q[3]
  2421. dGeomSetQuaternion(self.gid, cq)
  2422. def setOffsetPosition(self, pos):
  2423. """setOffsetPosition(pos)
  2424. Set the offset position of the geom. The geom must be attached to a
  2425. body. If the geom did not have an offset, it is automatically created.
  2426. This sets up an additional (local) transformation for the geom, since
  2427. geoms attached to a body share their global position and rotation.
  2428. @param pos: Position
  2429. @type pos: 3-sequence of floats
  2430. """
  2431. if self.body == None:
  2432. raise ValueError("Cannot set an offset position on a geom before "
  2433. "calling setBody")
  2434. dGeomSetOffsetPosition(self.gid, pos[0], pos[1], pos[2])
  2435. def getOffsetPosition(self):
  2436. """getOffsetPosition() -> 3-tuple
  2437. Get the offset position of the geom.
  2438. """
  2439. cdef dReal* p
  2440. p = <dReal*>dGeomGetOffsetPosition(self.gid)
  2441. return (p[0],p[1],p[2])
  2442. def setOffsetRotation(self, R):
  2443. """setOffsetRotation(R)
  2444. Set the offset rotation of the geom. The geom must be attached to a
  2445. body. If the geom did not have an offset, it is automatically created.
  2446. This sets up an additional (local) transformation for the geom, since
  2447. geoms attached to a body share their global position and rotation.
  2448. @param R: Rotation matrix
  2449. @type R: 9-sequence of floats
  2450. """
  2451. if self.body == None:
  2452. raise ValueError("Cannot set an offset rotation on a geom before "
  2453. "calling setBody")
  2454. cdef dMatrix3 m
  2455. m[0] = R[0]
  2456. m[1] = R[1]
  2457. m[2] = R[2]
  2458. m[3] = 0
  2459. m[4] = R[3]
  2460. m[5] = R[4]
  2461. m[6] = R[5]
  2462. m[7] = 0
  2463. m[8] = R[6]
  2464. m[9] = R[7]
  2465. m[10] = R[8]
  2466. m[11] = 0
  2467. dGeomSetOffsetRotation(self.gid, m)
  2468. def getOffsetRotation(self):
  2469. """getOffsetRotation() -> 9-tuple
  2470. Get the offset rotation of the geom.
  2471. """
  2472. cdef dReal* m
  2473. m = <dReal*>dGeomGetOffsetRotation(self.gid)
  2474. return [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]]
  2475. def clearOffset(self):
  2476. """clearOffset()
  2477. Disable the offset transform of the geom.
  2478. """
  2479. dGeomClearOffset(self.gid)
  2480. def getAABB(self):
  2481. """getAABB() -> 6-tuple
  2482. Return an axis aligned bounding box that surrounds the geom.
  2483. The return value is a 6-tuple (minx, maxx, miny, maxy, minz, maxz).
  2484. """
  2485. cdef dReal aabb[6]
  2486. dGeomGetAABB(self.gid, aabb)
  2487. return aabb[0], aabb[1], aabb[2], aabb[3], aabb[4], aabb[5]
  2488. def isSpace(self):
  2489. """isSpace() -> bool
  2490. Return 1 if the given geom is a space, or 0 if not."""
  2491. return dGeomIsSpace(self.gid)
  2492. def getSpace(self):
  2493. """getSpace() -> Space
  2494. Return the space that the given geometry is contained in,
  2495. or return None if it is not contained in any space."""
  2496. return self.space
  2497. def setCollideBits(self, bits):
  2498. """setCollideBits(bits)
  2499. Set the "collide" bitfields for this geom.
  2500. @param bits: Collide bit field
  2501. @type bits: int/long
  2502. """
  2503. dGeomSetCollideBits(self.gid, long(bits))
  2504. def setCategoryBits(self, bits):
  2505. """setCategoryBits(bits)
  2506. Set the "category" bitfields for this geom.
  2507. @param bits: Category bit field
  2508. @type bits: int/long
  2509. """
  2510. dGeomSetCategoryBits(self.gid, long(bits))
  2511. def getCollideBits(self):
  2512. """getCollideBits() -> long
  2513. Return the "collide" bitfields for this geom.
  2514. """
  2515. return dGeomGetCollideBits(self.gid)
  2516. def getCategoryBits(self):
  2517. """getCategoryBits() -> long
  2518. Return the "category" bitfields for this geom.
  2519. """
  2520. return dGeomGetCategoryBits(self.gid)
  2521. def enable(self):
  2522. """enable()
  2523. Enable the geom."""
  2524. dGeomEnable(self.gid)
  2525. def disable(self):
  2526. """disable()
  2527. Disable the geom."""
  2528. dGeomDisable(self.gid)
  2529. def isEnabled(self):
  2530. """isEnabled() -> bool
  2531. Return True if the geom is enabled."""
  2532. return dGeomIsEnabled(self.gid)
  2533. # _SpaceIterator
  2534. class _SpaceIterator:
  2535. """Iterates over the geoms inside a Space.
  2536. """
  2537. def __init__(self, space):
  2538. self.space = space
  2539. self.idx = 0
  2540. def __iter__(self):
  2541. return self
  2542. def next(self):
  2543. if self.idx >= self.space.getNumGeoms():
  2544. raise StopIteration
  2545. else:
  2546. res = self.space.getGeom(self.idx)
  2547. self.idx = self.idx + 1
  2548. return res
  2549. # SpaceBase
  2550. cdef class SpaceBase(GeomObject):
  2551. """Space class (container for geometry objects).
  2552. A Space object is a container for geometry objects which are used
  2553. to do collision detection.
  2554. The space does high level collision culling, which means that it
  2555. can identify which pairs of geometry objects are potentially
  2556. touching.
  2557. This Space class can be used for both, a SimpleSpace and a HashSpace
  2558. (see ODE documentation).
  2559. >>> space = Space(type=0) # Create a SimpleSpace
  2560. >>> space = Space(type=1) # Create a HashSpace
  2561. """
  2562. # The id of the space. Actually this is a copy of the value in self.gid
  2563. # (as the Space is derived from GeomObject) which can be used without
  2564. # casting whenever a *space* id is required.
  2565. cdef dSpaceID sid
  2566. # Dictionary with Geomobjects. Key is the ID (geom._id()) and the value
  2567. # is the geom object (Python wrapper). This is used in collide_callback()
  2568. # cdef object geom_dict
  2569. def __cinit__(self, *a, **kw):
  2570. pass
  2571. def __init__(self, *a, **kw):
  2572. raise NotImplementedError("The SpaceBase class can't be used directly")
  2573. def __dealloc__(self):
  2574. if self.gid != NULL:
  2575. dSpaceDestroy(self.sid)
  2576. self.sid = NULL
  2577. self.gid = NULL
  2578. # def _addgeom(self, geom):
  2579. # """Insert the geom object into the dictionary (internal method).
  2580. #
  2581. # This method has to called in the constructor of a geom object.
  2582. # """
  2583. # self.geom_dict[geom._id()]=geom
  2584. # def _id2geom(self, id):
  2585. # """Get the Python wrapper that corresponds to an ID.
  2586. #
  2587. # The ID is the integer value, as returned by geom._id().
  2588. # If the ID is unknown then None is returned.
  2589. # """
  2590. # if id in self.geom_dict:
  2591. # return self.geom_dict[id]
  2592. # else:
  2593. # return None
  2594. def _id(self):
  2595. cdef long id
  2596. id = <long>self.sid
  2597. return id
  2598. def __len__(self):
  2599. return self.getNumGeoms()
  2600. def __iter__(self):
  2601. return _SpaceIterator(self)
  2602. def add(self, GeomObject geom):
  2603. """add(geom)
  2604. Add a geom to a space. This does nothing if the geom is
  2605. already in the space.
  2606. @param geom: Geom object to add
  2607. @type geom: GeomObject
  2608. """
  2609. dSpaceAdd(self.sid, geom.gid)
  2610. def remove(self, GeomObject geom):
  2611. """remove(geom)
  2612. Remove a geom from a space.
  2613. @param geom: Geom object to remove
  2614. @type geom: GeomObject
  2615. """
  2616. dSpaceRemove(self.sid, geom.gid)
  2617. def query(self, GeomObject geom):
  2618. """query(geom) -> bool
  2619. Return True if the given geom is in the space.
  2620. @param geom: Geom object to check
  2621. @type geom: GeomObject
  2622. """
  2623. return dSpaceQuery(self.sid, geom.gid)
  2624. def getNumGeoms(self):
  2625. """getNumGeoms() -> int
  2626. Return the number of geoms contained within the space.
  2627. """
  2628. return dSpaceGetNumGeoms(self.sid)
  2629. def getGeom(self, int idx):
  2630. """getGeom(idx) -> GeomObject
  2631. Return the geom with the given index contained within the space.
  2632. @param idx: Geom index (0,1,...,getNumGeoms()-1)
  2633. @type idx: int
  2634. """
  2635. cdef dGeomID gid
  2636. # Check the index
  2637. if idx < 0 or idx >= dSpaceGetNumGeoms(self.sid):
  2638. raise IndexError("geom index out of range")
  2639. gid = dSpaceGetGeom(self.sid, idx)
  2640. if <long>gid not in _geom_c2py_lut:
  2641. raise RuntimeError(
  2642. "geom id cannot be translated to a Python object")
  2643. return _geom_c2py_lut[<long>gid]
  2644. def collide(self, arg, callback):
  2645. """collide(arg, callback)
  2646. Call a callback function one or more times, for all
  2647. potentially intersecting objects in the space. The callback
  2648. function takes 3 arguments:
  2649. def NearCallback(arg, geom1, geom2):
  2650. The arg parameter is just passed on to the callback function.
  2651. Its meaning is user defined. The geom1 and geom2 arguments are
  2652. the geometry objects that may be near each other. The callback
  2653. function can call the function collide() (not the Space
  2654. method) on geom1 and geom2, perhaps first determining
  2655. whether to collide them at all based on other information.
  2656. @param arg: A user argument that is passed to the callback function
  2657. @param callback: Callback function
  2658. @type callback: callable
  2659. """
  2660. cdef void* data
  2661. cdef object tup
  2662. tup = (callback, arg)
  2663. data = <void*>tup
  2664. dSpaceCollide(self.sid, data, collide_callback)
  2665. # Callback function for the dSpaceCollide() call in the Space.collide() method
  2666. # The data parameter is a tuple (Python-Callback, Arguments).
  2667. # The function calls a Python callback function with 3 arguments:
  2668. # def callback(UserArg, Geom1, Geom2)
  2669. # Geom1 and Geom2 are instances of GeomXyz classes.
  2670. cdef void collide_callback(void* data, dGeomID o1, dGeomID o2):
  2671. cdef object tup
  2672. # cdef Space space
  2673. cdef long id1, id2
  2674. # if (dGeomGetBody(o1)==dGeomGetBody(o2)):
  2675. # return
  2676. tup = <object>data
  2677. callback, arg = tup
  2678. id1 = <long>o1
  2679. id2 = <long>o2
  2680. g1 = _geom_c2py_lut[id1]
  2681. g2 = _geom_c2py_lut[id2]
  2682. callback(arg, g1, g2)
  2683. # SimpleSpace
  2684. cdef class SimpleSpace(SpaceBase):
  2685. """Simple space.
  2686. This does not do any collision culling - it simply checks every
  2687. possible pair of geoms for intersection, and reports the pairs
  2688. whose AABBs overlap. The time required to do intersection testing
  2689. for n objects is O(n**2). This should not be used for large numbers
  2690. of objects, but it can be the preferred algorithm for a small
  2691. number of objects. This is also useful for debugging potential
  2692. problems with the collision system.
  2693. """
  2694. def __cinit__(self, space=None):
  2695. cdef SpaceBase sp
  2696. cdef dSpaceID parentid
  2697. parentid = NULL
  2698. if space != None:
  2699. sp = space
  2700. parentid = sp.sid
  2701. self.sid = dSimpleSpaceCreate(parentid)
  2702. # Copy the ID
  2703. self.gid = <dGeomID>self.sid
  2704. dSpaceSetCleanup(self.sid, 0)
  2705. _geom_c2py_lut[<long>self.sid] = self
  2706. def __init__(self, space=None):
  2707. pass
  2708. # HashSpace
  2709. cdef class HashSpace(SpaceBase):
  2710. """Multi-resolution hash table space.
  2711. This uses an internal data structure that records how each geom
  2712. overlaps cells in one of several three dimensional grids. Each
  2713. grid has cubical cells of side lengths 2**i, where i is an integer
  2714. that ranges from a minimum to a maximum value. The time required
  2715. to do intersection testing for n objects is O(n) (as long as those
  2716. objects are not clustered together too closely), as each object
  2717. can be quickly paired with the objects around it.
  2718. """
  2719. def __cinit__(self, space=None):
  2720. cdef SpaceBase sp
  2721. cdef dSpaceID parentid
  2722. parentid = NULL
  2723. if space != None:
  2724. sp = space
  2725. parentid = sp.sid
  2726. self.sid = dHashSpaceCreate(parentid)
  2727. # Copy the ID
  2728. self.gid = <dGeomID>self.sid
  2729. dSpaceSetCleanup(self.sid, 0)
  2730. _geom_c2py_lut[<long>self.sid] = self
  2731. def __init__(self, space=None):
  2732. pass
  2733. def setLevels(self, int minlevel, int maxlevel):
  2734. """setLevels(minlevel, maxlevel)
  2735. Sets the size of the smallest and largest cell used in the
  2736. hash table. The actual size will be 2^minlevel and 2^maxlevel
  2737. respectively.
  2738. """
  2739. if minlevel > maxlevel:
  2740. raise ValueError(
  2741. "minlevel (%d) must be less than or equal to maxlevel (%d)" %
  2742. (minlevel, maxlevel))
  2743. dHashSpaceSetLevels(self.sid, minlevel, maxlevel)
  2744. def getLevels(self):
  2745. """getLevels() -> (minlevel, maxlevel)
  2746. Gets the size of the smallest and largest cell used in the
  2747. hash table. The actual size is 2^minlevel and 2^maxlevel
  2748. respectively.
  2749. """
  2750. cdef int minlevel
  2751. cdef int maxlevel
  2752. dHashSpaceGetLevels(self.sid, &minlevel, &maxlevel)
  2753. return minlevel, maxlevel
  2754. # QuadTreeSpace
  2755. cdef class QuadTreeSpace(SpaceBase):
  2756. """Quadtree space.
  2757. This uses a pre-allocated hierarchical grid-based AABB tree to
  2758. quickly cull collision checks. It's exceptionally quick for large
  2759. amounts of objects in landscape-shaped worlds. The amount of
  2760. memory used is 4**depth * 32 bytes.
  2761. Currently getGeom() is not implemented for the quadtree space.
  2762. """
  2763. def __cinit__(self, center, extents, depth, space=None):
  2764. cdef SpaceBase sp
  2765. cdef dSpaceID parentid
  2766. cdef dVector3 c
  2767. cdef dVector3 e
  2768. parentid = NULL
  2769. if space != None:
  2770. sp = space
  2771. parentid = sp.sid
  2772. c[0] = center[0]
  2773. c[1] = center[1]
  2774. c[2] = center[2]
  2775. e[0] = extents[0]
  2776. e[1] = extents[1]
  2777. e[2] = extents[2]
  2778. self.sid = dQuadTreeSpaceCreate(parentid, c, e, depth)
  2779. # Copy the ID
  2780. self.gid = <dGeomID>self.sid
  2781. dSpaceSetCleanup(self.sid, 0)
  2782. _geom_c2py_lut[<long>self.sid] = self
  2783. def __init__(self, center, extents, depth, space=None):
  2784. pass
  2785. def Space(space_type=0):
  2786. """Space factory function.
  2787. Depending on the type argument this function either returns a
  2788. SimpleSpace (space_type=0) or a HashSpace (space_type=1).
  2789. This function is provided to remain compatible with previous
  2790. versions of PyODE where there was only one Space class.
  2791. >>> space = Space(space_type=0) # Create a SimpleSpace
  2792. >>> space = Space(space_type=1) # Create a HashSpace
  2793. """
  2794. if space_type == 0:
  2795. return SimpleSpace()
  2796. elif space_type == 1:
  2797. return HashSpace()
  2798. else:
  2799. raise ValueError("Unknown space type (%d)" % space_type)
  2800. # GeomSphere
  2801. cdef class GeomSphere(GeomObject):
  2802. """Sphere geometry.
  2803. This class represents a sphere centered at the origin.
  2804. Constructor::
  2805. GeomSphere(space=None, radius=1.0)
  2806. """
  2807. def __cinit__(self, space=None, radius=1.0):
  2808. cdef SpaceBase sp
  2809. cdef dSpaceID sid
  2810. sid = NULL
  2811. if space != None:
  2812. sp = space
  2813. sid = sp.sid
  2814. self.gid = dCreateSphere(sid, radius)
  2815. # if space != None:
  2816. # space._addgeom(self)
  2817. _geom_c2py_lut[<long>self.gid] = self
  2818. def __init__(self, space=None, radius=1.0):
  2819. self.space = space
  2820. self.body = None
  2821. def placeable(self):
  2822. return True
  2823. def _id(self):
  2824. cdef long id
  2825. id = <long>self.gid
  2826. return id
  2827. def setRadius(self, radius):
  2828. """setRadius(radius)
  2829. Set the radius of the sphere.
  2830. @param radius: New radius
  2831. @type radius: float
  2832. """
  2833. dGeomSphereSetRadius(self.gid, radius)
  2834. def getRadius(self):
  2835. """getRadius() -> float
  2836. Return the radius of the sphere.
  2837. """
  2838. return dGeomSphereGetRadius(self.gid)
  2839. def pointDepth(self, p):
  2840. """pointDepth(p) -> float
  2841. Return the depth of the point p in the sphere. Points inside
  2842. the geom will have positive depth, points outside it will have
  2843. negative depth, and points on the surface will have zero
  2844. depth.
  2845. @param p: Point
  2846. @type p: 3-sequence of floats
  2847. """
  2848. return dGeomSpherePointDepth(self.gid, p[0], p[1], p[2])
  2849. # GeomBox
  2850. cdef class GeomBox(GeomObject):
  2851. """Box geometry.
  2852. This class represents a box centered at the origin.
  2853. Constructor::
  2854. GeomBox(space=None, lengths=(1.0, 1.0, 1.0))
  2855. """
  2856. def __cinit__(self, space=None, lengths=(1.0, 1.0, 1.0)):
  2857. cdef SpaceBase sp
  2858. cdef dSpaceID sid
  2859. sid = NULL
  2860. if space != None:
  2861. sp = space
  2862. sid = sp.sid
  2863. self.gid = dCreateBox(sid, lengths[0], lengths[1], lengths[2])
  2864. # if space != None:
  2865. # space._addgeom(self)
  2866. _geom_c2py_lut[<long>self.gid] = self
  2867. def __init__(self, space=None, lengths=(1.0, 1.0, 1.0)):
  2868. self.space = space
  2869. self.body = None
  2870. def placeable(self):
  2871. return True
  2872. def _id(self):
  2873. cdef long id
  2874. id = <long>self.gid
  2875. return id
  2876. def setLengths(self, lengths):
  2877. dGeomBoxSetLengths(self.gid, lengths[0], lengths[1], lengths[2])
  2878. def getLengths(self):
  2879. cdef dVector3 res
  2880. dGeomBoxGetLengths(self.gid, res)
  2881. return res[0], res[1], res[2]
  2882. def pointDepth(self, p):
  2883. """pointDepth(p) -> float
  2884. Return the depth of the point p in the box. Points inside the
  2885. geom will have positive depth, points outside it will have
  2886. negative depth, and points on the surface will have zero
  2887. depth.
  2888. @param p: Point
  2889. @type p: 3-sequence of floats
  2890. """
  2891. return dGeomBoxPointDepth(self.gid, p[0], p[1], p[2])
  2892. # GeomPlane
  2893. cdef class GeomPlane(GeomObject):
  2894. """Plane geometry.
  2895. This class represents an infinite plane. The plane equation is:
  2896. n.x*x + n.y*y + n.z*z = dist
  2897. This object can't be attached to a body.
  2898. If you call getBody() on this object it always returns ode.environment.
  2899. Constructor::
  2900. GeomPlane(space=None, normal=(0,0,1), dist=0)
  2901. """
  2902. def __cinit__(self, space=None, normal=(0, 0, 1), dist=0):
  2903. cdef SpaceBase sp
  2904. cdef dSpaceID sid
  2905. sid = NULL
  2906. if space != None:
  2907. sp = space
  2908. sid = sp.sid
  2909. self.gid = dCreatePlane(sid, normal[0], normal[1], normal[2], dist)
  2910. # if space != None:
  2911. # space._addgeom(self)
  2912. _geom_c2py_lut[<long>self.gid] = self
  2913. def __init__(self, space=None, normal=(0, 0, 1), dist=0):
  2914. self.space = space
  2915. def _id(self):
  2916. cdef long id
  2917. id = <long>self.gid
  2918. return id
  2919. def setParams(self, normal, dist):
  2920. dGeomPlaneSetParams(self.gid, normal[0], normal[1], normal[2], dist)
  2921. def getParams(self):
  2922. cdef dVector4 res
  2923. dGeomPlaneGetParams(self.gid, res)
  2924. return ((res[0], res[1], res[2]), res[3])
  2925. def pointDepth(self, p):
  2926. """pointDepth(p) -> float
  2927. Return the depth of the point p in the plane. Points inside the
  2928. geom will have positive depth, points outside it will have
  2929. negative depth, and points on the surface will have zero
  2930. depth.
  2931. @param p: Point
  2932. @type p: 3-sequence of floats
  2933. """
  2934. return dGeomPlanePointDepth(self.gid, p[0], p[1], p[2])
  2935. # GeomCapsule
  2936. cdef class GeomCapsule(GeomObject):
  2937. """Capped cylinder geometry.
  2938. This class represents a capped cylinder aligned along the local Z axis
  2939. and centered at the origin.
  2940. Constructor::
  2941. GeomCapsule(space=None, radius=0.5, length=1.0)
  2942. The length parameter does not include the caps.
  2943. """
  2944. def __cinit__(self, space=None, radius=0.5, length=1.0):
  2945. cdef SpaceBase sp
  2946. cdef dSpaceID sid
  2947. sid = NULL
  2948. if space != None:
  2949. sp = space
  2950. sid = sp.sid
  2951. self.gid = dCreateCapsule(sid, radius, length)
  2952. # if space != None:
  2953. # space._addgeom(self)
  2954. _geom_c2py_lut[<long>self.gid] = self
  2955. def __init__(self, space=None, radius=0.5, length=1.0):
  2956. self.space = space
  2957. self.body = None
  2958. def placeable(self):
  2959. return True
  2960. def _id(self):
  2961. cdef long id
  2962. id = <long>self.gid
  2963. return id
  2964. def setParams(self, radius, length):
  2965. dGeomCapsuleSetParams(self.gid, radius, length)
  2966. def getParams(self):
  2967. cdef dReal radius, length
  2968. dGeomCapsuleGetParams(self.gid, &radius, &length)
  2969. return radius, length
  2970. def pointDepth(self, p):
  2971. """pointDepth(p) -> float
  2972. Return the depth of the point p in the cylinder. Points inside the
  2973. geom will have positive depth, points outside it will have
  2974. negative depth, and points on the surface will have zero
  2975. depth.
  2976. @param p: Point
  2977. @type p: 3-sequence of floats
  2978. """
  2979. return dGeomCapsulePointDepth(self.gid, p[0], p[1], p[2])
  2980. GeomCCylinder = GeomCapsule # backwards compatibility
  2981. # GeomCylinder
  2982. cdef class GeomCylinder(GeomObject):
  2983. """Plain cylinder geometry.
  2984. This class represents an uncapped cylinder aligned along the local Z axis
  2985. and centered at the origin.
  2986. Constructor::
  2987. GeomCylinder(space=None, radius=0.5, length=1.0)
  2988. """
  2989. def __cinit__(self, space=None, radius=0.5, length=1.0):
  2990. cdef SpaceBase sp
  2991. cdef dSpaceID sid
  2992. sid = NULL
  2993. if space != None:
  2994. sp = space
  2995. sid = sp.sid
  2996. self.gid = dCreateCylinder(sid, radius, length)
  2997. # if space != None:
  2998. # space._addgeom(self)
  2999. _geom_c2py_lut[<long>self.gid] = self
  3000. def __init__(self, space=None, radius=0.5, length=1.0):
  3001. self.space = space
  3002. self.body = None
  3003. def placeable(self):
  3004. return True
  3005. def _id(self):
  3006. cdef long id
  3007. id = <long>self.gid
  3008. return id
  3009. def setParams(self, radius, length):
  3010. dGeomCylinderSetParams(self.gid, radius, length)
  3011. def getParams(self):
  3012. cdef dReal radius, length
  3013. dGeomCylinderGetParams(self.gid, &radius, &length)
  3014. return radius, length
  3015. ## dGeomCylinderPointDepth not implemented upstream in ODE 0.7
  3016. # GeomRay
  3017. cdef class GeomRay(GeomObject):
  3018. """Ray object.
  3019. A ray is different from all the other geom classes in that it does
  3020. not represent a solid object. It is an infinitely thin line that
  3021. starts from the geom's position and extends in the direction of
  3022. the geom's local Z-axis.
  3023. Constructor::
  3024. GeomRay(space=None, rlen=1.0)
  3025. """
  3026. def __cinit__(self, space=None, rlen=1.0):
  3027. cdef SpaceBase sp
  3028. cdef dSpaceID sid
  3029. sid = NULL
  3030. if space != None:
  3031. sp = space
  3032. sid = sp.sid
  3033. self.gid = dCreateRay(sid, rlen)
  3034. # if space != None:
  3035. # space._addgeom(self)
  3036. _geom_c2py_lut[<long>self.gid] = self
  3037. def __init__(self, space=None, rlen=1.0):
  3038. self.space = space
  3039. self.body = None
  3040. def _id(self):
  3041. cdef long id
  3042. id = <long>self.gid
  3043. return id
  3044. def placeable(self):
  3045. return True
  3046. def setLength(self, rlen):
  3047. '''setLength(rlen)
  3048. Set length of the ray.
  3049. @param rlen: length of the ray
  3050. @type rlen: float'''
  3051. dGeomRaySetLength(self.gid, rlen)
  3052. def getLength(self):
  3053. '''getLength() -> length
  3054. Get the length of the ray.
  3055. @returns: length of the ray (float)'''
  3056. return dGeomRayGetLength(self.gid)
  3057. def set(self, p, u):
  3058. '''set(p, u)
  3059. Set the position and rotation of a ray.
  3060. @param p: position
  3061. @type p: 3-sequence of floats
  3062. @param u: rotation
  3063. @type u: 3-sequence of floats'''
  3064. dGeomRaySet(self.gid, p[0], p[1], p[2], u[0], u[1], u[2])
  3065. def get(self):
  3066. '''get() -> ((p[0], p[1], p[2]), (u[0], u[1], u[2]))
  3067. Return the position and rotation as a pair of
  3068. tuples.
  3069. @returns: position and rotation'''
  3070. cdef dVector3 start
  3071. cdef dVector3 dir
  3072. dGeomRayGet(self.gid, start, dir)
  3073. return (start[0], start[1], start[2]), (dir[0], dir[1], dir[2])
  3074. # GeomTransform
  3075. cdef class GeomTransform(GeomObject):
  3076. """GeomTransform.
  3077. A geometry transform "T" is a geom that encapsulates another geom
  3078. "E", allowing E to be positioned and rotated arbitrarily with
  3079. respect to its point of reference.
  3080. Constructor::
  3081. GeomTransform(space=None)
  3082. """
  3083. cdef object geom
  3084. def __cinit__(self, space=None):
  3085. cdef SpaceBase sp
  3086. cdef dSpaceID sid
  3087. sid = NULL
  3088. if space != None:
  3089. sp = space
  3090. sid = sp.sid
  3091. self.gid = dCreateGeomTransform(sid)
  3092. # Set cleanup mode to 0 as a contained geom will be deleted
  3093. # by its Python wrapper class
  3094. dGeomTransformSetCleanup(self.gid, 0)
  3095. # if space != None:
  3096. # space._addgeom(self)
  3097. _geom_c2py_lut[<long>self.gid] = self
  3098. def __init__(self, space=None):
  3099. self.space = space
  3100. self.body = None
  3101. self.geom = None
  3102. self.attribs = {}
  3103. def placeable(self):
  3104. return True
  3105. def _id(self):
  3106. cdef long id
  3107. id = <long>self.gid
  3108. return id
  3109. def setGeom(self, GeomObject geom not None):
  3110. """setGeom(geom)
  3111. Set the geom that the geometry transform encapsulates.
  3112. A ValueError exception is thrown if a) the geom is not placeable,
  3113. b) the geom was already inserted into a space or c) the geom is
  3114. already associated with a body.
  3115. @param geom: Geom object to encapsulate
  3116. @type geom: GeomObject
  3117. """
  3118. cdef long id
  3119. if not geom.placeable():
  3120. raise ValueError(
  3121. "Only placeable geoms can be encapsulated by a GeomTransform")
  3122. if dGeomGetSpace(geom.gid) != <dSpaceID>0:
  3123. raise ValueError(
  3124. "The encapsulated geom was already inserted into a space")
  3125. if dGeomGetBody(geom.gid) != <dBodyID>0:
  3126. raise ValueError(
  3127. "The encapsulated geom is already associated with a body")
  3128. id = geom._id()
  3129. dGeomTransformSetGeom(self.gid, <dGeomID>id)
  3130. self.geom = geom
  3131. def getGeom(self):
  3132. """getGeom() -> GeomObject
  3133. Get the geom that the geometry transform encapsulates.
  3134. """
  3135. return self.geom
  3136. def setInfo(self, int mode):
  3137. """setInfo(mode)
  3138. Set the "information" mode of the geometry transform.
  3139. With mode 0, when a transform object is collided with another
  3140. object, the geom field of the ContactGeom structure is set to the
  3141. geom that is encapsulated by the transform object.
  3142. With mode 1, the geom field of the ContactGeom structure is set
  3143. to the transform object itself.
  3144. @param mode: Information mode (0 or 1)
  3145. @type mode: int
  3146. """
  3147. if mode < 0 or mode > 1:
  3148. raise ValueError(
  3149. "Invalid information mode (%d). Must be either 0 or 1." % mode)
  3150. dGeomTransformSetInfo(self.gid, mode)
  3151. def getInfo(self):
  3152. """getInfo() -> int
  3153. Get the "information" mode of the geometry transform (0 or 1).
  3154. With mode 0, when a transform object is collided with another
  3155. object, the geom field of the ContactGeom structure is set to the
  3156. geom that is encapsulated by the transform object.
  3157. With mode 1, the geom field of the ContactGeom structure is set
  3158. to the transform object itself.
  3159. """
  3160. return dGeomTransformGetInfo(self.gid)
  3161. ######################################################################
  3162. cdef class TriMeshData:
  3163. """This class stores the mesh data.
  3164. """
  3165. cdef dTriMeshDataID tmdid
  3166. cdef dReal* vertex_buffer
  3167. cdef int* face_buffer
  3168. def __cinit__(self):
  3169. self.tmdid = dGeomTriMeshDataCreate()
  3170. self.vertex_buffer = NULL
  3171. self.face_buffer = NULL
  3172. def __dealloc__(self):
  3173. if self.tmdid != NULL:
  3174. dGeomTriMeshDataDestroy(self.tmdid)
  3175. if self.vertex_buffer != NULL:
  3176. free(self.vertex_buffer)
  3177. if self.face_buffer != NULL:
  3178. free(self.face_buffer)
  3179. def build(self, verts, faces):
  3180. """build(verts, faces)
  3181. @param verts: Vertices
  3182. @type verts: Sequence of 3-sequences of floats
  3183. @param faces: Face definitions (three indices per face)
  3184. @type faces: Sequence of 3-sequences of ints
  3185. """
  3186. cdef int numverts
  3187. cdef int numfaces
  3188. cdef dReal* vp
  3189. cdef int* fp
  3190. cdef int a, b, c
  3191. numverts = len(verts)
  3192. numfaces = len(faces)
  3193. # Allocate the vertex and face buffer
  3194. self.vertex_buffer = <dReal*>malloc(numverts * 4 * sizeof(dReal))
  3195. self.face_buffer = <int*>malloc(numfaces * 3 * sizeof(int))
  3196. # Fill the vertex buffer
  3197. vp = self.vertex_buffer
  3198. for v in verts:
  3199. vp[0] = v[0]
  3200. vp[1] = v[1]
  3201. vp[2] = v[2]
  3202. vp[3] = 0
  3203. vp = vp + 4
  3204. # Fill the face buffer
  3205. fp = self.face_buffer
  3206. for f in faces:
  3207. a = f[0]
  3208. b = f[1]
  3209. c = f[2]
  3210. if (a < 0 or b < 0 or c < 0 or a >= numverts or b >= numverts or c >= numverts):
  3211. raise ValueError("Vertex index out of range")
  3212. fp[0] = a
  3213. fp[1] = b
  3214. fp[2] = c
  3215. fp = fp + 3
  3216. # Pass the data to ODE
  3217. dGeomTriMeshDataBuildSimple(self.tmdid, self.vertex_buffer, numverts,
  3218. self.face_buffer, numfaces * 3)
  3219. ######################################################################
  3220. # GeomTriMesh
  3221. cdef class GeomTriMesh(GeomObject):
  3222. """TriMesh object.
  3223. To construct the trimesh geom you need a TriMeshData object that
  3224. stores the actual mesh. This object has to be passed as first
  3225. argument to the constructor.
  3226. Constructor::
  3227. GeomTriMesh(data, space=None)
  3228. """
  3229. # Keep a reference to the data
  3230. cdef TriMeshData data
  3231. def __cinit__(self, TriMeshData data not None, space=None):
  3232. cdef SpaceBase sp
  3233. cdef dSpaceID sid
  3234. self.data = data
  3235. sid = NULL
  3236. if space != None:
  3237. sp = space
  3238. sid = sp.sid
  3239. self.gid = dCreateTriMesh(sid, data.tmdid, NULL, NULL, NULL)
  3240. _geom_c2py_lut[<long>self.gid] = self
  3241. def __init__(self, TriMeshData data not None, space=None):
  3242. self.space = space
  3243. self.body = None
  3244. def placeable(self):
  3245. return True
  3246. def _id(self):
  3247. cdef long id
  3248. id = <long>self.gid
  3249. return id
  3250. def clearTCCache(self):
  3251. """clearTCCache()
  3252. Clears the internal temporal coherence caches.
  3253. """
  3254. dGeomTriMeshClearTCCache(self.gid)
  3255. def getTriangle(self, int idx):
  3256. """getTriangle(idx) -> (v0, v1, v2)
  3257. @param idx: Triangle index
  3258. @type idx: int
  3259. """
  3260. cdef dVector3 v0, v1, v2
  3261. cdef dVector3* vp0
  3262. cdef dVector3* vp1
  3263. cdef dVector3* vp2
  3264. vp0 = <dVector3*>v0
  3265. vp1 = <dVector3*>v1
  3266. vp2 = <dVector3*>v2
  3267. dGeomTriMeshGetTriangle(self.gid, idx, vp0, vp1, vp2)
  3268. return ((v0[0], v0[1], v0[2]),
  3269. (v1[0], v1[1], v1[2]),
  3270. (v2[0], v2[1], v2[2]))
  3271. def getTriangleCount(self):
  3272. """getTriangleCount() -> n
  3273. Returns the number of triangles in the TriMesh."""
  3274. return dGeomTriMeshGetTriangleCount(self.gid)
  3275. ######################################################################
  3276. def collide(geom1, geom2):
  3277. """collide(geom1, geom2) -> contacts
  3278. Generate contact information for two objects.
  3279. Given two geometry objects that potentially touch (geom1 and geom2),
  3280. generate contact information for them. Internally, this just calls
  3281. the correct class-specific collision functions for geom1 and geom2.
  3282. [flags specifies how contacts should be generated if the objects
  3283. touch. Currently the lower 16 bits of flags specifies the maximum
  3284. number of contact points to generate. If this number is zero, this
  3285. function just pretends that it is one - in other words you can not
  3286. ask for zero contacts. All other bits in flags must be zero. In
  3287. the future the other bits may be used to select other contact
  3288. generation strategies.]
  3289. If the objects touch, this returns a list of Contact objects,
  3290. otherwise it returns an empty list.
  3291. @param geom1: First Geom
  3292. @type geom1: GeomObject
  3293. @param geom2: Second Geom
  3294. @type geom2: GeomObject
  3295. @returns: Returns a list of Contact objects.
  3296. """
  3297. cdef dContactGeom c[150]
  3298. cdef long id1
  3299. cdef long id2
  3300. cdef int i, n
  3301. cdef Contact cont
  3302. id1 = geom1._id()
  3303. id2 = geom2._id()
  3304. n = dCollide(<dGeomID>id1, <dGeomID>id2, 150, c, sizeof(dContactGeom))
  3305. res = []
  3306. i = 0
  3307. while i < n:
  3308. cont = Contact()
  3309. cont._contact.geom = c[i]
  3310. res.append(cont)
  3311. i = i + 1
  3312. return res
  3313. def collide2(geom1, geom2, arg, callback):
  3314. """collide2(geom1, geom2, arg, callback)
  3315. Calls the callback for all potentially intersecting pairs that contain
  3316. one geom from geom1 and one geom from geom2.
  3317. @param geom1: First Geom
  3318. @type geom1: GeomObject
  3319. @param geom2: Second Geom
  3320. @type geom2: GeomObject
  3321. @param arg: A user argument that is passed to the callback function
  3322. @param callback: Callback function
  3323. @type callback: callable
  3324. """
  3325. cdef void* data
  3326. cdef object tup
  3327. cdef long id1
  3328. cdef long id2
  3329. id1 = geom1._id()
  3330. id2 = geom2._id()
  3331. tup = (callback, arg)
  3332. data = <void*>tup
  3333. # collide_callback is defined in space.pyx
  3334. dSpaceCollide2(<dGeomID>id1, <dGeomID>id2, data, collide_callback)
  3335. def areConnected(Body body1, Body body2):
  3336. """areConnected(body1, body2) -> bool
  3337. Return True if the two bodies are connected together by a joint,
  3338. otherwise return False.
  3339. @param body1: First body
  3340. @type body1: Body
  3341. @param body2: Second body
  3342. @type body2: Body
  3343. @returns: True if the bodies are connected
  3344. """
  3345. if body1 is environment:
  3346. return False
  3347. if body2 is environment:
  3348. return False
  3349. return bool(dAreConnected(<dBodyID> body1.bid, <dBodyID> body2.bid))
  3350. def CloseODE():
  3351. """CloseODE()
  3352. Deallocate some extra memory used by ODE that can not be deallocated
  3353. using the normal destroy functions.
  3354. """
  3355. dCloseODE()
  3356. def InitODE():
  3357. '''InitODE()
  3358. Initialize some ODE internals. This will be called for you when you
  3359. "import ode", but you should call this again if you CloseODE().'''
  3360. dInitODE()
  3361. #environment = Body(None)
  3362. environment = None
  3363. InitODE()