ode.pyx 131 KB

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