ode.pyx 131 KB

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