2
0

ode.pyx 127 KB

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