python-box2d-2.0.2+svn20100109.244/0000755000000000000000000000000011414467240014500 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/setup.py0000644000000000000000000000634611151077147016224 0ustar rootroot#!/usr/bin/env python """ Setup script for pyBox2D distribution. For installation instructions, see INSTALL. Basic install steps: setup.py build If that worked, then: setup.py install """ import os from glob import glob try: from setuptools import (setup, Extension) print 'Using setuptools.' except: from distutils.core import (setup, Extension) print 'Setuptools not found; falling back on distutils.' # release version number box2d_version = '2.0.2' release_number = 1 # create the version string version_str = "%sb%s" % (box2d_version, str(release_number)) def write_init(): # read in the license header license_header = open(os.path.join('Box2D', 'pybox2d_license_header.txt')).read() # create the source code for the file init_source = [ "", "from Box2D import *", "__version__ = '%s'" % version_str, "__version_info__ = (%s,%d)" % (box2d_version.replace('.', ','), release_number), ] # and create the __init__ file with the appropriate version string f=open('__init__.py', 'w') f.write(license_header) f.write( '\n'.join(init_source) ) f.close() source_paths = [ 'Box2D/Dynamics/', 'Box2D/Dynamics/Contacts/', 'Box2D/Dynamics/Controllers/', 'Box2D/Dynamics/Joints/', 'Box2D/Common/', 'Box2D/Collision/', 'Box2D/Collision/Shapes/', ] # glob all of the paths and then flatten the list into one box2d_source_files = ['Box2D/Box2D.i'] + \ sum( [glob(os.path.join(path, "*.cpp")) for path in source_paths], []) # arguments to pass to SWIG. for old versions of SWIG, -O (optimize) might not be present. swig_arguments = '-c++ -IBox2D -O -includeall -ignoremissing -w201 -outdir .' pybox2d_extension = \ Extension('Box2D._Box2D', box2d_source_files, extra_compile_args=['-I.'], language='c++') LONG_DESCRIPTION = \ """ 2D physics library Box2D %s for usage in Python. After installing please be sure to try out the testbed demos. They require either pygame or pyglet and are available on the homepage. pybox2d homepage: http://pybox2d.googlecode.com Box2D's homepage: http://www.box2d.org """ % (box2d_version,) CLASSIFIERS = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: zlib/libpng License", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX", "Programming Language :: Python", "Games :: Physics Libraries" ] write_init() setup_dict = dict( name = "Box2D", version = version_str, author = "Ken Lauer", author_email = "sirkne at gmail dot com", description = "Python Box2D", license = "zlib", url ="http://pybox2d.googlecode.com/", long_description = LONG_DESCRIPTION, classifiers = CLASSIFIERS, packages = ['Box2D'], package_dir = {'Box2D': '.'}, options = { 'build_ext': { 'swig_opts' : swig_arguments } }, ext_modules = [ pybox2d_extension ] ) # run the actual setup from distutils setup( **setup_dict ) python-box2d-2.0.2+svn20100109.244/README0000644000000000000000000000266111151113531015352 0ustar rootrootpyBox2D Python Box2D Bindings -- 2D Physics Library http://pybox2d.googlecode.com/ What is it? ----------- pyBox2D is a 2D physics library for your games and simulation. It's based on the Box2D library, written in C++. It supports several shape types (circle, polygon, thin line segments), quite a few joint types (revolute, prismatic, etc.), and even controllers (buoyancy, gravity, etc.). Getting Started --------------- For building instructions, see INSTALL or the wiki on the homepage. Once installed, check out the testbed demos to see what pyBox2D can do (located in testbed/ ). Then read the manual located on the Box2D wiki, here: http://www.box2d.org/wiki/index.php?title=Python_Manual A possibly outdated local copy is included in this distribution in docs/ . For more information on some caveats and key differences between the C++ version of Box2D, please see: http://www.box2d.org/wiki/index.php?title=Box2D_with_Python On the wiki, you will also find more useful things of varying quality. Epydoc output for pyBox2D: http://pybox2d.googlecode.com/svn/epydoc/html/index.html It's by no means perfect, but it can come in handy. Bugs ---- Please submit any bugs that you find to: http://code.google.com/p/pybox2d/issues/list Contact ------- You can contact the team on the Box2D forums: http://www.box2d.org/forum/ or by e-mail: sirkne at gmail com python-box2d-2.0.2+svn20100109.244/testbed/0000755000000000000000000000000011414467240016132 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/test_Pulleys.py0000644000000000000000000000525511136402204021175 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Pulleys (Framework): name="Pulleys" joint1=None _pickle_vars=['joint1'] def __init__(self): super(Pulleys, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) a = 2.0 b = 4.0 y = 16.0 L = 12.0 sd=box2d.b2PolygonDef() sd.SetAsBox(a, b) sd.density = 5.0 bd=box2d.b2BodyDef() bd.position = (-10.0, y) body1 = self.world.CreateBody(bd) body1.CreateShape(sd) body1.SetMassFromShapes() bd.position = (10.0, y) body2 = self.world.CreateBody(bd) body2.CreateShape(sd) body2.SetMassFromShapes() pulleyDef=box2d.b2PulleyJointDef() anchor1 =(-10.0, y + b) anchor2 =( 10.0, y + b) groundAnchor1=(-10.0, y + b + L) groundAnchor2=( 10.0, y + b + L) pulleyDef.Initialize(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, 2.0) self.joint1 = self.world.CreateJoint(pulleyDef).getAsType() def Step(self, settings): super(Pulleys, self).Step(settings) if not self.joint1: return ratio = self.joint1.GetRatio() L = self.joint1.GetLength1() + ratio * self.joint1.GetLength2() self.DrawStringCR("L1 + %.2f * L2 = %.2f" % (ratio, L)) if __name__=="__main__": main(Pulleys) python-box2d-2.0.2+svn20100109.244/testbed/test_MotorsAndLimits.py0000644000000000000000000001110011136402204022612 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class MotorsAndLimits (Framework): name="MotorsAndLimits" joint1=None joint2=None joint3=None _pickle_vars = ['joint1', 'joint2', 'joint3'] def __init__(self): super(MotorsAndLimits, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(2.0, 0.5) sd.density = 5.0 sd.friction = 0.05 bd=box2d.b2BodyDef() rjd=box2d.b2RevoluteJointDef() prevBody=ground y = 8.0 bd.position = (3.0, y) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() rjd.Initialize(prevBody, body, (0.0, y)) rjd.motorSpeed = 1.0 * box2d.b2_pi rjd.maxMotorTorque = 10000.0 rjd.enableMotor = True self.joint1 = self.world.CreateJoint(rjd).getAsType() prevBody = body bd.position = (9.0, y) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() rjd.Initialize(prevBody, body, (6.0, y)) rjd.motorSpeed = 0.5 * box2d.b2_pi rjd.maxMotorTorque = 2000.0 rjd.enableMotor = True rjd.lowerAngle = - 0.5 * box2d.b2_pi rjd.upperAngle = 0.5 * box2d.b2_pi rjd.enableLimit = True self.joint2 = self.world.CreateJoint(rjd).getAsType() bd.position = (-10.0, 10.0) bd.angle = 0.5 * box2d.b2_pi body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() pjd=box2d.b2PrismaticJointDef() pjd.Initialize(ground, body, (-10.0, 10.0), (1.0, 0.0)) pjd.motorSpeed = 10.0 pjd.maxMotorForce = 1000.0 pjd.enableMotor = True pjd.lowerTranslation = 0.0 pjd.upperTranslation = 20.0 pjd.enableLimit = True self.joint3 = self.world.CreateJoint(pjd).getAsType() def Keyboard(self, key): if not self.joint1 or not self.joint2 or not self.joint3: return if key==K_l: self.joint2.EnableLimit(not self.joint2.IsLimitEnabled()) self.joint3.EnableLimit(not self.joint3.IsLimitEnabled()) self.joint2.GetBody1().WakeUp() self.joint3.GetBody2().WakeUp() elif key==K_m: self.joint1.EnableMotor(not self.joint1.IsMotorEnabled()) self.joint2.EnableMotor(not self.joint2.IsMotorEnabled()) self.joint3.EnableMotor(not self.joint3.IsMotorEnabled()) self.joint2.GetBody1().WakeUp() self.joint3.GetBody2().WakeUp() elif key==K_p: self.joint3.GetBody2().WakeUp() self.joint3.SetMotorSpeed(-self.joint3.GetMotorSpeed()) def Step(self, settings): self.DrawStringCR("Keys: (l) limits, (m) motors, (p) prismatic speed") if self.joint1 and self.joint2 and self.joint3: torque1 = self.joint1.GetMotorTorque() torque2 = self.joint2.GetMotorTorque() force3 = self.joint3.GetMotorForce() self.DrawStringCR("Motor Torque = %.0f, %.0f : Motor Force = %.0f" % (torque1,torque2, force3)) super(MotorsAndLimits, self).Step(settings) if __name__=="__main__": main(MotorsAndLimits) python-box2d-2.0.2+svn20100109.244/testbed/test_DynamicEdges.py0000644000000000000000000002145611135461416022106 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class DynamicEdges (Framework): name="DynamicEdges" def __init__(self): super(DynamicEdges, self).__init__() bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) body = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) body.CreateShape(sd) sd1=box2d.b2CircleDef() sd1.radius = 0.5 sd1.localPosition = (-0.5, 0.5) sd1.density = 2.0 sd2=box2d.b2CircleDef() sd2.radius = 0.5 sd2.localPosition = (0.5, 0.5) sd2.density = 0.0 # massless for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x + 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() sd1=box2d.b2PolygonDef() sd1.SetAsBox(0.25, 0.5) sd1.density = 2.0 sd2=box2d.b2PolygonDef() sd2.SetAsBox(0.25, 0.5, (0.0, -0.5), 0.5 * box2d.b2_pi) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x - 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() xf1=box2d.b2XForm() xf1.R.Set(0.3524 * box2d.b2_pi) xf1.position = box2d.b2Mul(xf1.R, (1.0, 0.0)) sd1=box2d.b2PolygonDef() sd1.vertexCount = 3 sd1.setVertex(0, box2d.b2Mul(xf1, (-1.0, 0.0))) sd1.setVertex(1, box2d.b2Mul(xf1, (1.0, 0.0))) sd1.setVertex(2, box2d.b2Mul(xf1, (0.0, 0.5))) sd1.density = 2.0 xf2=box2d.b2XForm() xf2.R.Set(-0.3524 * box2d.b2_pi) xf2.position = box2d.b2Mul(xf2.R, (-1.0, 0.0)) sd2=box2d.b2PolygonDef() sd2.vertexCount = 3 sd2.setVertex(0, box2d.b2Mul(xf2, (-1.0, 0.0))) sd2.setVertex(1, box2d.b2Mul(xf2, (1.0, 0.0))) sd2.setVertex(2, box2d.b2Mul(xf2, (0.0, 0.5))) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x, 2.05 + 2.5 * i) bd.angle = 0.0 body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() sd_bottom=box2d.b2PolygonDef() sd_bottom.SetAsBox( 1.5, 0.15 ) sd_bottom.density = 4.0 sd_left=box2d.b2PolygonDef() sd_left.SetAsBox(0.15, 2.7, (-1.45, 2.35), 0.2) sd_left.density = 4.0 sd_right=box2d.b2PolygonDef() sd_right.SetAsBox(0.15, 2.7, (1.45, 2.35), -0.2) sd_right.density = 4.0 bd=box2d.b2BodyDef() bd.position = ( 0.0, 2.0 ) body = self.world.CreateBody(bd) body.CreateShape(sd_bottom) body.CreateShape(sd_left) body.CreateShape(sd_right) body.SetMassFromShapes() loop1=[ (0.063134534,8.3695248), (0.94701801,9.3165428), (0.0,9.0640047), (-0.12626907,10.326695), (1.4520943,11.77879), (2.2728432,10.137292), (2.3991123,11.147444), (3.5986685,10.958041), (3.9143411,7.3593722), (4.1668793,9.4428119), (5.4295699,9.3165428), (6.2503189,8.3063903), (6.6922606,10.137292), (4.9876282,9.8216191), (4.7350901,10.958041), (7.2604714,11.652521), (10.732871,11.147444), (10.480333,10.642368), (10.732871,9.8216191), (11.55362,9.4428119), (12.374369,9.3796773), (13.005714,9.8216191), (13.195118,10.38983), (13.005714,10.768637), (12.626907,10.894906), (12.753176,11.526252), (13.573925,11.715655), (14.836616,11.399982), (16.351844,10.768637), (17.867073,11.399982), (17.803939,10.263561), (17.361997,8.3063903), (17.803939,8.1801212), (18.056477,9.5059464), (18.182746,11.336848), (18.561553,11.210579), (18.561553,9.6322155), (18.561553,7.7381795), (18.687822,5.5284708), (19.382302,5.6547398), (19.066629,8.1801212), (19.003495,10.263561), (19.066629,11.463117), (19.887378,11.841924), (20.708127,11.273713), (21.0238,10.011023), (20.708127,7.2962377), (21.086934,6.2860852), (21.150069,3.7607038), (20.392455,2.5611476), (18.624688,2.5611476), (20.771262,2.1192059), (20.771262,0.22516988), (18.624688,-0.2799064), (13.826463,0.16203534), (14.015867,1.7403987), (13.195118,2.1823404), (12.626907,1.5509951), (12.879445,0.85651522), (12.626907,0.35143895), (10.543467,1.298457), (11.490485,3.9501074), (13.889598,3.6344347), (13.889598,2.9399549), (14.584077,3.8869729), (11.932427,5.2127981), (9.7227183,4.0132419), (10.796005,3.5081657), (9.7858528,3.2556275), (10.796005,2.4980131), (7.9549513,1.7403987), (9.6595837,1.424726), (9.217642,0.66711162), (8.270624,-0.090502792), (7.0079333,0.85651522), (6.1240498,-0.15363733), (6.1240498,3.192493), (5.6821081,2.4348786), (4.9876282,2.1192059), (4.1037447,1.8666678), (3.0304576,1.8666678), (2.0834396,2.245475), (1.6414979,2.6242822), (1.3258252,3.5081657), (1.2626907,0.47770802), (0.63134534,0.035766276), (0.063134534,0.9827842), ] loop2 = [ (8.270624,6.1598161), (8.270624,5.3390672), (8.7757003,5.086529), (9.4701801,5.5284708), (9.217642,6.033547), (8.7757003,6.412354), ] b2Loop1 = [(loop[0] + 10.0, loop[1]+1.0) for loop in loop1] b2Loop2 = [(loop[0] - 10.0, loop[1]) for loop in loop2] b2Loop1.reverse() bd=box2d.b2BodyDef() bd.position = ( 0.0, 0.0 ) body = self.world.CreateBody(bd) weight=box2d.b2CircleDef() weight.filter.maskBits = 0 weight.density = 4.0 weight.radius = 0.5 weight.localPosition = (8.9, 5.75) body.CreateShape(weight) edgeDef=box2d.b2EdgeChainDef() edgeDef.setVertices(b2Loop2) body.CreateShape(edgeDef) body.SetMassFromShapes() body = self.world.CreateBody(bd) weight.radius = 5.0 weight.localPosition = (20.5, 7.0) body.CreateShape(weight) edgeDef.setVertices(b2Loop1) body.CreateShape(edgeDef) body.SetMassFromShapes() if __name__=="__main__": main(DynamicEdges) python-box2d-2.0.2+svn20100109.244/testbed/pgu/0000755000000000000000000000000011414467240016725 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/0000755000000000000000000000000011414467240017511 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/button.py0000644000000000000000000002356711130023047021377 0ustar rootroot""" """ from pygame.locals import * from const import * import widget, surface import basic class _button(widget.Widget): def __init__(self,**params): widget.Widget.__init__(self,**params) self.state = 0 def event(self,e): if e.type == ENTER: self.repaint() elif e.type == EXIT: self.repaint() elif e.type == FOCUS: self.repaint() elif e.type == BLUR: self.repaint() elif e.type == KEYDOWN: if e.key == K_SPACE or e.key == K_RETURN: self.state = 1 self.repaint() elif e.type == MOUSEBUTTONDOWN: self.state = 1 self.repaint() elif e.type == KEYUP: if self.state == 1: sub = pygame.event.Event(CLICK,{'pos':(0,0),'button':1}) #self.send(sub.type,sub) self._event(sub) self.state = 0 self.repaint() elif e.type == MOUSEBUTTONUP: self.state = 0 self.repaint() elif e.type == CLICK: self.click() self.pcls = "" if self.state == 0 and self.container.myhover is self: self.pcls = "hover" if self.state == 1 and self.container.myhover is self: self.pcls = "down" def click(self): pass class Button(_button): """A button, buttons can be clicked, they are usually used to set up callbacks.
Button(value=None)
value
either a widget or a string
Example w = gui.Button("Click Me") w.connect(gui.CLICK,fnc,value) """ def __init__(self,value=None,**params): params.setdefault('cls','button') _button.__init__(self,**params) self.value = value def __setattr__(self,k,v): if k == 'value' and type(v) == str: v = basic.Label(v,cls=self.cls+".label") _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and v != None: pass if k == 'value' and _v != NOATTR and _v != None and _v != v: self.send(CHANGE) self.chsize() def resize(self,width=None,height=None): self.value.rect.x,self.value.rect.y = 0,0 self.value.rect.w,self.value.rect.h = self.value.resize(width,height) return self.value.rect.w,self.value.rect.h # # self.value._resize() # self.rect.w,self.rect.h = self.value.rect_margin.w,self.value.rect_margin.h # # if self.style.width: self.rect.w = max(self.rect.w,self.style.width) # if self.style.height: self.rect.w = max(self.rect.w,self.style.height) # # xt,xr,xb,xl = self.value.getspacing() # # self.value._resize(self.rect.w-(xl+xr),self.rect.h-(xt+xb)) # def paint(self,s): self.value.pcls = self.pcls self.value.paint(surface.subsurface(s,self.value.rect)) class Switch(_button): """A switch can have two states, True or False.
Switch(value=False)
value
initial value, (True, False)
Example w = gui.Switch(True) w.connect(gui.CHANGE,fnc,value) """ def __init__(self,value=False,**params): params.setdefault('cls','switch') _button.__init__(self,**params) self.value = value img = self.style.off self.style.width = img.get_width() self.style.height = img.get_height() def paint(self,s): #self.pcls = "" #if self.container.myhover is self: self.pcls = "hover" if self.value: img = self.style.on else: img = self.style.off s.blit(img,(0,0)) def __setattr__(self,k,v): _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() def click(self): self.value = not self.value class Checkbox(_button): """Within a Group of Checkbox widgets several may be selected at a time.
Checkbox(group,value=None)
group
a gui.Group for the Checkbox to belong to
value
the value
Example g = gui.Group(name='colors',value=['r','b']) t = gui.Table() t.tr() t.td(gui.Label('Red')) t.td(gui.Checkbox(g,'r')) t.tr() t.td(gui.Label('Green')) t.td(gui.Checkbox(g,'g')) t.tr() t.td(gui.Label('Blue')) t.td(gui.Checkbox(g,'b')) """ def __init__(self,group,value=None,**params): params.setdefault('cls','checkbox') _button.__init__(self,**params) self.group = group self.group.add(self) if self.group.value == None: self.group.value = [] self.value = value img = self.style.off self.style.width = img.get_width() self.style.height = img.get_height() def paint(self,s): #self.pcls = "" #if self.container.myhover is self: self.pcls = "hover" if self.value in self.group.value: img = self.style.on else: img = self.style.off s.blit(img,(0,0)) def click(self): if self.value in self.group.value: self.group.value.remove(self.value) else: self.group.value.append(self.value) self.group._change() class Radio(_button): """Within a Group of Radio widgets only one may be selected at a time.
Radio(group,value=None)
group
a gui.Group for the Radio to belong to
value
the value
Example g = gui.Group(name='colors',value='g') t = gui.Table() t.tr() t.td(gui.Label('Red')) t.td(gui.Radio(g,'r')) t.tr() t.td(gui.Label('Green')) t.td(gui.Radio(g,'g')) t.tr() t.td(gui.Label('Blue')) t.td(gui.Radio(g,'b')) """ def __init__(self,group=None,value=None,**params): params.setdefault('cls','radio') _button.__init__(self,**params) self.group = group self.group.add(self) self.value = value img = self.style.off self.style.width = img.get_width() self.style.height = img.get_height() def paint(self,s): #self.pcls = "" #if self.container.myhover is self: self.pcls = "hover" if self.group.value == self.value: img = self.style.on else: img = self.style.off s.blit(img,(0,0)) def click(self): self.group.value = self.value class Tool(_button): """Within a Group of Tool widgets only one may be selected at a time.
Tool(group,widget=None,value=None)
group
a gui.Group for the Tool to belong to
widget
a widget to appear on the Tool (similar to a Button)
value
the value
Example g = gui.Group(name='colors',value='g') t = gui.Table() t.tr() t.td(gui.Tool(g,'Red','r')) t.tr() t.td(gui.Tool(g,'Green','g')) t.tr() t.td(gui.Tool(g,'Blue','b')) """ def __init__(self,group,widget=None,value=None,**params): #TODO widget= could conflict with module widget params.setdefault('cls','tool') _button.__init__(self,**params) self.group = group self.group.add(self) self.value = value if widget: self.setwidget(widget) if self.group.value == self.value: self.pcls = "down" def setwidget(self,w): self.widget = w def resize(self,width=None,height=None): self.widget.rect.w,self.widget.rect.h = self.widget.resize() #self.widget._resize() #self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h return self.widget.rect.w,self.widget.rect.h def event(self,e): _button.event(self,e) if self.group.value == self.value: self.pcls = "down" def paint(self,s): if self.group.value == self.value: self.pcls = "down" self.widget.paint(surface.subsurface(s,self.widget.rect)) def click(self): self.group.value = self.value for w in self.group.widgets: if w != self: w.pcls = "" class Icon(_button): """TODO - might be deprecated """ def __init__(self,cls,**params): params['cls'] = cls _button.__init__(self,**params) s = self.style.image self.style.width = s.get_width() self.style.height = s.get_height() self.state = 0 def paint(self,s): #self.pcls = "" #if self.state == 0 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "hover" #if self.state == 1 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "down" s.blit(self.style.image,(0,0)) class Link(_button): """A link, links can be clicked, they are usually used to set up callbacks. Basically the same as the button widget, just text only with a different cls. Made for convenience.
Link(value=None)
value
a string
Example w = gui.Link("Click Me") w.connect(gui.CLICK,fnc,value) """ def __init__(self,value,**params): params.setdefault('focusable',True) params.setdefault('cls','link') _button.__init__(self,**params) self.value = value self.font = self.style.font self.style.width, self.style.height = self.font.size(self.value) def paint(self,s): s.blit(self.font.render(self.value, 1, self.style.color),(0,0)) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/misc.py0000644000000000000000000000220711130023047021003 0ustar rootrootfrom const import * import widget import app class ProgressBar(widget.Widget): """A progress bar.
ProgressBar(value,min,max)
value
starting value
min
minimum value rendered on the screen (usually 0)
max
maximum value
Example w = gui.ProgressBar(0,0,100) w.value = 25 """ def __init__(self,value,min,max,**params): params.setdefault('cls','progressbar') widget.Widget.__init__(self,**params) self.min,self.max,self.value = min,max,value def paint(self,s): r = pygame.rect.Rect(0,0,self.rect.w,self.rect.h) r.w = r.w*(self.value-self.min)/(self.max-self.min) self.bar = r app.App.app.theme.render(s,self.style.bar,r) def __setattr__(self,k,v): if k == 'value': v = int(v) v = max(v,self.min) v = min(v,self.max) _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint()python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/style.py0000644000000000000000000000264011130023047021211 0ustar rootroot""" """ class Style: """The class used by widget for the widget.style

This object is used mainly as a dictionary, accessed via widget.style.attr, as opposed to widget.style['attr']. It automatically grabs information from the theme via value = theme.get(widget.cls,widget.pcls,attr).

""" def __init__(self,o,dict): self.obj = o for k,v in dict.items(): self.__dict__[k]=v self._cache = {} def __getattr__(self,k): key = self.obj.cls,self.obj.pcls,k if key not in self._cache: #import app #self._cache[key] = app.App.app.theme.get(self.obj.cls, self.obj.pcls, k) self._cache[key] = Style_get(self.obj.cls,self.obj.pcls,k) v = self._cache[key] if k in ( 'border_top','border_right','border_bottom','border_left', 'padding_top','padding_right','padding_bottom','padding_left', 'margin_top','margin_right','margin_bottom','margin_left', 'align','valign','width','height', ): self.__dict__[k] = v return v def __setattr__(self,k,v): self.__dict__[k] = v Style_cache = {} def Style_get(cls,pcls,k): key = cls,pcls,k if key not in Style_cache: import app Style_cache[key] = app.App.app.theme.get(cls,pcls,k) return Style_cache[key] python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/select.py0000644000000000000000000001344311130023047021333 0ustar rootroot""" """ from const import * import table import basic, button class Select(table.Table): """A select input.
Select(value=None)
value
initial value
Example w = Select(value="goats") w.add("Cats","cats") w.add("Goats","goats") w.add("Dogs","Dogs") w.value = 'dogs' #changes the value from goats to dogs """ def __init__(self,value=None,**params): params.setdefault('cls','select') table.Table.__init__(self,**params) self.top_selected = button.Button(cls=self.cls+".selected") table.Table.add(self,self.top_selected) #,hexpand=1,vexpand=1)#,0,0) self.top_selected.value = basic.Label(" ",cls=self.cls+".option.label") self.top_arrow = button.Button(basic.Image(self.style.arrow),cls=self.cls+".arrow") table.Table.add(self,self.top_arrow) #,hexpand=1,vexpand=1) #,1,0) self.options = table.Table() #style={'border':3}) self.options_first = None self.options.tr() self.spacer_top = basic.Spacer(0,0) self.options.add(self.spacer_top) self.options.tr() self._options = table.Table(cls=self.cls+".options") self.options.add(self._options) self.options.tr() self.spacer_bottom = basic.Spacer(0,0) self.options.add(self.spacer_bottom) self.options.connect(BLUR,self._close,None) self.spacer_top.connect(CLICK,self._close,None) self.spacer_bottom.connect(CLICK,self._close,None) self.values = [] self.value = value def resize(self,width=None,height=None): max_w,max_h = 0,0 for w in self._options.widgets: w.rect.w,w.rect.h = w.resize() max_w,max_h = max(max_w,w.rect.w),max(max_h,w.rect.h) #xt,xr,xb,xl = self.top_selected.getspacing() self.top_selected.style.width = max_w #+ xl + xr self.top_selected.style.height = max_h #+ xt + xb self.top_arrow.connect(CLICK,self._open,None) self.top_selected.connect(CLICK,self._open,None) w,h = table.Table.resize(self,width,height) self.spacer_top.style.width, self.spacer_top.style.height = w,h self.spacer_bottom.style.width, self.spacer_bottom.style.height = w,h self._options.style.width = w #HACK: sort of, but not a big one.. self._options.resize() return w,h def _open(self,value): sh = self.rect.h #spacer height opts = self.options self.spacer_top.style.height = 0 self.spacer_bottom.style.height = 0 opts.rect.w, opts.rect.h = opts.resize() h = opts.rect.h y = self.rect.y c = self.container while hasattr(c,'container'): y += c.rect.y if c.container == None: break c = c.container if y + sh + h <= c.rect.h: #down self.spacer_top.style.height = sh dy = self.rect.y else: #up self.spacer_bottom.style.height = sh dy = self.rect.y - h opts.rect.w, opts.rect.h = opts.resize() self.container.open(opts,self.rect.x,dy) self.options_first.focus() def _close(self,value): # print 'my close!' self.options.close() self.top_selected.focus() # self.blur() # self.focus() # print self.container.myfocus == self def _setvalue(self,value): self.value = value._value if hasattr(self,'container'): #self.chsize() #HACK: improper use of resize() #self.resize() #to recenter the new value, etc. pass # #self._resize() self._close(None) #self.repaint() #this will happen anyways def __setattr__(self,k,v): mywidget = None if k == 'value': for w in self.values: if w._value == v: mywidget = w _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() if k == 'value': if not mywidget: mywidget = basic.Label(" ",cls=self.cls+".option.label") self.top_selected.value = mywidget def add(self,w,value=None): """Add a widget, value item to the Select.
Select.add(widget,value=None)
widget
Widget or string to represent the item
value
value for this item
Example w = Select() w.add("Goat") #adds a Label w.add("Goat","goat") #adds a Label with the value goat w.add(gui.Label("Cuzco"),"goat") #adds a Label with value goat """ if type(w) == str: w = basic.Label(w,cls=self.cls+".option.label") w.style.align = -1 b = button.Button(w,cls=self.cls+".option") b.connect(CLICK,self._setvalue,w) #b = w #w.cls = self.cls+".option" #w.cls = self.cls+".option" self._options.tr() self._options.add(b) #,align=-1) if self.options_first == None: self.options_first = b #self._options.td(b, align=-1, cls=self.cls+".option") #self._options.td(_List_Item(w,value=value),align=-1) if value != None: w._value = value else: w._value = w if self.value == w._value: self.top_selected.value = w self.values.append(w) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/area.py0000644000000000000000000003677011130023047020774 0ustar rootroot""" """ import os from const import * import surface import container, table import group import basic, button, slider class SlideBox(container.Container): """A scrollable area with no scrollbars.
SlideBox(widget,width,height)
widget
widget to be able to scroll around
width, height
size of scrollable area
Example c = SlideBox(w,100,100) c.offset = (10,10) c.repaint() """ def __init__(self, widget, width, height, **params): params.setdefault('width', width) params.setdefault('height', height) container.Container.__init__(self, **params) self.offset = [0, 0] self.widget = widget def __setattr__(self,k,v): if k == 'widget': if hasattr(self,'widget'): self.remove(self.widget) self.add(v,0,0) self.__dict__[k] = v def paint(self, s): #if not hasattr(self,'surface'): self.surface = pygame.Surface((self.max_rect.w,self.max_rect.h),0,s) #self.surface.fill((0,0,0,0)) import app app.App.app.theme.render(self.surface,self.style.background,pygame.Rect(0,0,self.max_rect.w,self.max_rect.h)) self.bkgr = pygame.Surface((s.get_width(),s.get_height()),0,s) self.bkgr.blit(s,(0,0)) container.Container.paint(self,self.surface) s.blit(self.surface,(-self.offset[0],-self.offset[1])) self._offset = self.offset[:] return def paint_for_when_pygame_supports_other_tricks(self,s): #this would be ideal if pygame had support for it! #and if pgu also had a paint(self,s,rect) method to paint small parts sr = (self.offset[0],self.offset[1],self.max_rect.w,self.max_rect.h) cr = (-self.offset[0],-self.offset[1],s.get_width(),s.get_height()) s2 = s.subsurface(sr) s2.set_clip(cr) container.Container.paint(self,s2) def proxy_paint(self, s): container.Container.paint(self, surface.ProxySurface(parent=None, rect=self.max_rect, real_surface=s, offset=self.offset)) def update(self, s): rects = container.Container.update(self,self.surface) rets = [] s_rect = pygame.Rect(0,0,s.get_width(),s.get_height()) if self.offset == self._offset: for r in rects: r2 = r.move((-self.offset[0],-self.offset[1])) if r2.colliderect(s_rect): s.blit(self.surface.subsurface(r),r2) rets.append(r2) else: s.blit(self.bkgr,(0,0)) sub = pygame.Rect(self.offset[0],self.offset[1],min(s.get_width(),self.max_rect.w-self.offset[0]),min(s.get_height(),self.max_rect.h-self.offset[1])) # print sub # print self.surface.get_width(),self.surface.get_height() # print s.get_width(),s.get_height() # print self.offset # print self.style.width,self.style.height s.blit(self.surface.subsurface(sub),(0,0)) rets.append(s_rect) self._offset = self.offset[:] return rets def proxy_update(self, s): rects = container.Container.update(self, surface.ProxySurface(parent=None, rect=self.max_rect, real_surface=s, offset=self.offset)) result = [] for r in rects: result.append(pygame.Rect(r).move(self.offset)) return result def resize(self, width=None, height=None): container.Container.resize(self) self.max_rect = pygame.Rect(self.widget.rect) #self.max_rect.w = max(self.max_rect.w,self.style.width) #self.max_rect.h = max(self.max_rect.h,self.style.height) return self.style.width,self.style.height #self.rect = pygame.Rect(self.rect[0], self.rect[1], self.style.width, self.style.height) def event(self, e): if e.type in [MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION]: pos = (e.pos[0] + self.offset[0], e.pos[1] + self.offset[1]) if self.max_rect.collidepoint(pos): e_params = {'pos': pos } if e.type == MOUSEMOTION: e_params['buttons'] = e.buttons e_params['rel'] = e.rel else: e_params['button'] = e.button e = pygame.event.Event(e.type, e_params) container.Container.event(self, e) #class SlideBox(Area): # def __init__(self,*args,**params): # print 'gui.SlideBox','Scheduled to be renamed to Area.' # Area.__init__(self,*args,**params) class ScrollArea(table.Table): """A scrollable area with scrollbars.
ScrollArea(widget,width,height,hscrollbar=True)
widget
widget to be able to scroll around
width, height
size of scrollable area. Set either to 0 to default to size of widget.
hscrollbar
set to False if you do not wish to have a horizontal scrollbar
vscrollbar
set to False if you do not wish to have a vertical scrollbar
step
set to how far clicks on the icons will step
""" def __init__(self, widget, width=0, height=0, hscrollbar=True, vscrollbar=True,step=24, **params): w= widget params.setdefault('cls', 'scrollarea') table.Table.__init__(self, width=width,height=height,**params) self.sbox = SlideBox(w, width=width, height=height, cls=self.cls+".content") self.widget = w self.vscrollbar = vscrollbar self.hscrollbar = hscrollbar self.step = step def __setattr__(self,k,v): if k == 'widget': self.sbox.widget = v self.__dict__[k] = v def resize(self,width=None,height=None): widget = self.widget box = self.sbox #self.clear() table.Table.clear(self) #print 'resize',self,self._rows self.tr() self.td(box) widget.rect.w, widget.rect.h = widget.resize() my_width,my_height = self.style.width,self.style.height if not my_width: my_width = widget.rect.w self.hscrollbar = False if not my_height: my_height = widget.rect.h self.vscrollbar = False box.style.width,box.style.height = my_width,my_height #self.style.width,self.style.height box.rect.w,box.rect.h = box.resize() #print widget.rect #print box.rect #r = table.Table.resize(self,width,height) #print r #return r #print box.offset # #this old code automatically adds in a scrollbar if needed # #but it doesn't always work # self.vscrollbar = None # if widget.rect.h > box.rect.h: # self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step) # self.td(self.vscrollbar) # self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None) # # vs = self.vscrollbar # vs.rect.w,vs.rect.h = vs.resize() # box.style.width = self.style.width - vs.rect.w # # # self.hscrollbar = None # if widget.rect.w > box.rect.w: # self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step) # self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None) # self.tr() # self.td(self.hscrollbar) # # hs = self.hscrollbar # hs.rect.w,hs.rect.h = hs.resize() # box.style.height = self.style.height - hs.rect.h import app xt,xr,xb,xl = app.App.app.theme.getspacing(box) if self.vscrollbar: self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step) self.td(self.vscrollbar) self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None) vs = self.vscrollbar vs.rect.w,vs.rect.h = vs.resize() if self.style.width: box.style.width = self.style.width - (vs.rect.w + xl+xr) if self.hscrollbar: self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step) self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None) self.tr() self.td(self.hscrollbar) hs = self.hscrollbar hs.rect.w,hs.rect.h = hs.resize() if self.style.height: box.style.height = self.style.height - (hs.rect.h + xt + xb) if self.hscrollbar: hs = self.hscrollbar hs.min = 0 hs.max = widget.rect.w - box.style.width hs.style.width = box.style.width hs.size = hs.style.width * box.style.width / max(1,widget.rect.w) else: box.offset[0] = 0 if self.vscrollbar: vs = self.vscrollbar vs.min = 0 vs.max = widget.rect.h - box.style.height vs.style.height = box.style.height vs.size = vs.style.height * box.style.height / max(1,widget.rect.h) else: box.offset[1] = 0 #print self.style.width,box.style.width, hs.style.width r = table.Table.resize(self,width,height) return r def x_resize(self, width=None, height=None): w,h = table.Table.resize(self, width, height) if self.hscrollbar: if self.widget.rect.w <= self.sbox.rect.w: self.hscrollbar.size = self.hscrollbar.style.width else: self.hscrollbar.size = max(20,self.hscrollbar.style.width * self.sbox.rect.w / self.widget.rect.w) self._hscrollbar_changed(None) if self.widget.rect.h <= self.sbox.rect.h: self.vscrollbar.size = self.vscrollbar.style.height else: self.vscrollbar.size = max(20,self.vscrollbar.style.height * self.sbox.rect.h / self.widget.rect.h) self._vscrollbar_changed(None) return w,h def _vscrollbar_changed(self, xxx): #y = (self.widget.rect.h - self.sbox.rect.h) * self.vscrollbar.value / 1000 #if y >= 0: self.sbox.offset[1] = -y self.sbox.offset[1] = self.vscrollbar.value self.sbox.reupdate() def _hscrollbar_changed(self, xxx): #x = (self.widget.rect.w - self.sbox.rect.w) * self.hscrollbar.value / 1000 #if x >= 0: self.sbox.offset[0] = -x self.sbox.offset[0] = self.hscrollbar.value self.sbox.reupdate() def set_vertical_scroll(self, percents): #if not self.vscrollbar: return if not hasattr(self.vscrollbar,'value'): return self.vscrollbar.value = percents #min(max(percents*10, 0), 1000) self._vscrollbar_changed(None) def set_horizontal_scroll(self, percents): #if not self.hscrollbar: return if not hasattr(self.hscrollbar,'value'): return self.hscrollbar.value = percents #min(max(percents*10, 0), 1000) self._hscrollbar_changed(None) class _List_Item(button._button): def __init__(self,label=None,image=None,value=None,**params): #TODO label= could conflict with the module label #param image: an imagez.Image object (optional) #param text: a string object params.setdefault('cls','list.item') button._button.__init__(self,**params) self.group = None self.value = value #(self, value) self.widget = None if type(label) == str: label = basic.Label(label, cls=self.cls+".label") if image and label: self.widget = container.Container() self.widget.add(image, 0, 0) #HACK: improper use of .resize() image.rect.w,image.rect.h = image.resize() self.widget.add(label, image.rect.w, 0) elif image: self.widget = image elif label: self.widget = label self.pcls = "" def resize(self,width=None,height=None): self.widget.rect.w,self.widget.rect.h = self.widget.resize() return self.widget.rect.w,self.widget.rect.h # self.widget._resize() # self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h def event(self,e): button._button.event(self,e) if self.group.value == self.value: self.pcls = "down" def paint(self,s): if self.group.value == self.value: self.pcls = "down" self.widget.paint(surface.subsurface(s,self.widget.rect)) def click(self): self.group.value = self.value for w in self.group.widgets: if w != self: w.pcls = "" class List(ScrollArea): """A list of items in an area.

This widget can be a form element, it has a value set to whatever item is selected.

List(width,height)
""" def _change(self, value): self.value = self.group.value self.send(CHANGE) def __init__(self, width, height, **params): params.setdefault('cls', 'list') self.table = table.Table(width=width) ScrollArea.__init__(self, self.table, width, height,hscrollbar=False ,**params) self.items = [] g = group.Group() self.group = g g.connect(CHANGE,self._change,None) self.value = self.group.value = None self.add = self._add self.remove = self._remove def clear(self): """Clear the list.
List.clear()
""" self.items = [] self.group = group.Group() self.group.connect(CHANGE,self._change,None) self.table.clear() self.set_vertical_scroll(0) self.blur(self.myfocus) def _docs(self): #HACK: nasty hack to get the docs in "my way" def add(self, label, image=None, value=None): """Add an item to the list.
List.add(label,image=None,value=None)
label
a label for the item
image
an image for the item
value
a value for the item
""" def remove(self,value): """Remove an item from the list.
List.remove(value)
value
a value of an item to remove from the list
""" def _add(self, label, image = None, value=None): item = _List_Item(label,image=image,value=value) self.table.tr() self.table.add(item) self.items.append(item) item.group = self.group item.group.add(item) def _remove(self, item): for i in self.items: if i.value == item: item = i if item not in self.items: return item.blur() self.items.remove(item) self.group.widgets.remove(item) self.table.remove_row(item.style.row) #class List(ListArea): # def __init__(self,*args,**params): # print 'gui.List','Scheduled to be renamed to ListArea. API may also be changed in the future.' # ListArea.__init__(self,*args,**params) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/input.py0000644000000000000000000001151211130023047021206 0ustar rootroot""" """ import pygame from pygame.locals import * from const import * import widget class Input(widget.Widget): """A single line text input.
Input(value="",size=20)
value
initial text
size
size for the text box, in characters
Example w = Input(value="Cuzco the Goat",size=20) w = Input("Marbles") """ def __init__(self,value="",size=20,**params): params.setdefault('cls','input') widget.Widget.__init__(self,**params) self.value = value self.pos = len(str(value)) self.vpos = 0 self.font = self.style.font w,h = self.font.size("e"*size) if not self.style.height: self.style.height = h if not self.style.width: self.style.width = w #self.style.height = max(self.style.height,h) #self.style.width = max(self.style.width,w) #self.rect.w=w+self.style.padding_left+self.style.padding_right; #self.rect.h=h+self.style.padding_top+self.style.padding_bottom; def paint(self,s): r = pygame.Rect(0,0,self.rect.w,self.rect.h) cs = 2 #NOTE: should be in a style w,h = self.font.size(self.value[0:self.pos]) x = w-self.vpos if x < 0: self.vpos -= -x if x+cs > s.get_width(): self.vpos += x+cs-s.get_width() s.blit(self.font.render(self.value, 1, self.style.color),(-self.vpos,0)) if self.container.myfocus is self: w,h = self.font.size(self.value[0:self.pos]) r.x = w-self.vpos r.w = cs r.h = h s.fill(self.style.color,r) def _setvalue(self,v): self.__dict__['value'] = v self.send(CHANGE) def event(self,e): used = None if e.type == KEYDOWN: if e.key == K_BACKSPACE: if self.pos: self._setvalue(self.value[:self.pos-1] + self.value[self.pos:]) self.pos -= 1 elif e.key == K_DELETE: if len(self.value) > self.pos: self._setvalue(self.value[:self.pos] + self.value[self.pos+1:]) elif e.key == K_HOME: self.pos = 0 elif e.key == K_END: self.pos = len(self.value) elif e.key == K_LEFT: if self.pos > 0: self.pos -= 1 used = True elif e.key == K_RIGHT: if self.pos < len(self.value): self.pos += 1 used = True elif e.key == K_RETURN: self.next() elif e.key == K_TAB: pass else: #c = str(e.unicode) try: c = (e.unicode).encode('latin-1') if c: self._setvalue(self.value[:self.pos] + c + self.value[self.pos:]) self.pos += 1 except: #ignore weird characters pass self.repaint() elif e.type == FOCUS: self.repaint() elif e.type == BLUR: self.repaint() self.pcls = "" if self.container.myfocus is self: self.pcls = "focus" return used def __setattr__(self,k,v): if k == 'value': if v == None: v = '' v = str(v) self.pos = len(v) _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() class Password(Input): """A password input, text is *-ed out.
Password(value="",size=20)
value
initial text
size
size for the text box, in characters
Example w = Password(value="password",size=20) w = Password("53[r3+") """ def paint(self,s): hidden="*" show=len(self.value)*hidden #print "self.value:",self.value if self.pos == None: self.pos = len(self.value) r = pygame.Rect(0,0,self.rect.w,self.rect.h) cs = 2 #NOTE: should be in a style w,h = self.font.size(show) x = w-self.vpos if x < 0: self.vpos -= -x if x+cs > s.get_width(): self.vpos += x+cs-s.get_width() s.blit(self.font.render(show, 1, self.style.color),(-self.vpos,0)) if self.container.myfocus is self: #w,h = self.font.size(self.value[0:self.pos]) w,h = self.font.size(show[0:self.pos]) r.x = w-self.vpos r.w = cs r.h = h s.fill(self.style.color,r) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/basic.py0000644000000000000000000000543611130023047021140 0ustar rootroot"""These widgets are all grouped together because they are non-interactive widgets. """ import pygame from const import * import widget class Spacer(widget.Widget): """A invisible space.
Spacer(width,height)
""" def __init__(self,width,height,**params): params.setdefault('focusable',False) widget.Widget.__init__(self,width=width,height=height,**params) class Color(widget.Widget): """A block of color.

The color can be changed at run-time.

Color(value=None)
Example c = Color() c.value = (255,0,0) c.value = (0,255,0) """ def __init__(self,value=None,**params): params.setdefault('focusable',False) if value != None: params['value']=value widget.Widget.__init__(self,**params) def paint(self,s): if hasattr(self,'value'): s.fill(self.value) def __setattr__(self,k,v): if k == 'value' and type(v) == str: v = pygame.Color(v) _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() class Label(widget.Widget): """A text label.
Label(value)
value
text to be displayed
Example w = Label(value="I own a rubber chicken!") w = Label("3 rubber chickens") """ def __init__(self,value,**params): params.setdefault('focusable',False) params.setdefault('cls','label') widget.Widget.__init__(self,**params) self.value = value self.font = self.style.font self.style.width, self.style.height = self.font.size(self.value) def paint(self,s): s.blit(self.font.render(self.value, 1, self.style.color),(0,0)) class Image(widget.Widget): """An image.
Image(value)
value
a file name or a pygame.Surface
""" def __init__(self,value,**params): params.setdefault('focusable',False) widget.Widget.__init__(self,**params) if type(value) == str: value = pygame.image.load(value) ow,oh = iw,ih = value.get_width(),value.get_height() sw,sh = self.style.width,self.style.height if sw and not sh: iw,ih = sw,ih*sw/iw elif sh and not sw: iw,ih = iw*sh/ih,sh elif sw and sh: iw,ih = sw,sh if (ow,oh) != (iw,ih): value = pygame.transform.scale(value,(iw,ih)) self.style.width,self.style.height = iw,ih self.value = value def paint(self,s): s.blit(self.value,(0,0))python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/const.py0000644000000000000000000000136511130023047021202 0ustar rootroot"""Constants.

Event Types

from pygame

QUIT
MOUSEBUTTONDOWN
MOUSEBUTTONUP
MOUSEMOTION
KEYDOWN

gui specific

ENTER
EXIT
BLUR
FOCUS
CLICK
CHANGE
OPEN
CLOSE
INIT
Other
NOATTR
""" import pygame from pygame.locals import QUIT, MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION, KEYDOWN, USEREVENT ENTER = pygame.locals.USEREVENT + 0 EXIT = pygame.locals.USEREVENT + 1 BLUR = pygame.locals.USEREVENT + 2 FOCUS = pygame.locals.USEREVENT + 3 CLICK = pygame.locals.USEREVENT + 4 CHANGE = pygame.locals.USEREVENT + 5 OPEN = pygame.locals.USEREVENT + 6 CLOSE = pygame.locals.USEREVENT + 7 INIT = 'init' class NOATTR: passpython-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/menus.py0000644000000000000000000000661611130023047021207 0ustar rootroot""" """ from const import * import table import basic, button class _Menu_Options(table.Table): def __init__(self,menu,**params): table.Table.__init__(self,**params) self.menu = menu def event(self,e): handled = False arect = self.get_abs_rect() if e.type == MOUSEMOTION: abspos = e.pos[0]+arect.x,e.pos[1]+arect.y for w in self.menu.container.widgets: if not w is self.menu: mrect = w.get_abs_rect() if mrect.collidepoint(abspos): self.menu._close(None) w._open(None) handled = True if not handled: table.Table.event(self,e) class _Menu(button.Button): def __init__(self,parent,widget=None,**params): #TODO widget= could conflict with module widget params.setdefault('cls','menu') button.Button.__init__(self,widget,**params) self.parent = parent self._cls = self.cls self.options = _Menu_Options(self, cls=self.cls+".options") self.connect(CLICK,self._open,None) self.pos = 0 def _open(self,value): self.parent.value = self self.pcls = 'down' self.repaint() self.container.open(self.options,self.rect.x,self.rect.bottom) self.options.connect(BLUR,self._pass,None) self.options.blur(self.options.myfocus) self.options.connect(BLUR,self._close,None) self.options.focus() self.repaint() def _pass(self,value): pass def _close(self,value): self.pcls = '' self.parent.value = None self.repaint() self.options.close() def _value(self,value): self._close(None) if value['fnc'] != None: value['fnc'](value['value']) def event(self,e): button.Button.event(self,e) if self.parent.value == self: self.pcls = 'down' def add(self,w,fnc=None,value=None): w.style.align = -1 b = button.Button(w,cls=self.cls+".option") b.connect(CLICK,self._value,{'fnc':fnc,'value':value}) self.options.tr() self.options.add(b) return b class Menus(table.Table): """A drop down menu bar.
Menus(data)
data
Menu data, a list of (path,fnc,value), see example below
Example data = [ ('File/Save',fnc_save,None), ('File/New',fnc_new,None), ('Edit/Copy',fnc_copy,None), ('Edit/Cut',fnc_cut,None), ('Help/About',fnc_help,help_about_content), ('Help/Reference',fnc_help,help_reference_content), ] w = Menus(data) """ def __init__(self,data,menu_cls='menu',**params): params.setdefault('cls','menus') table.Table.__init__(self,**params) self.value = None n,m,mt = 0,None,None for path,cmd,value in data: parts = path.split("/") if parts[0] != mt: mt = parts[0] m = _Menu(self,basic.Label(mt,cls=menu_cls+".label"),cls=menu_cls) self.add(m,n,0) n += 1 m.add(basic.Label(parts[1],cls=m.cls+".option.label"),cmd,value) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/keysym.py0000644000000000000000000000415311130023047021373 0ustar rootroot""" """ import pygame from pygame.locals import * from const import * import widget class Keysym(widget.Widget): """A keysym input.

This widget records the keysym of the key pressed while this widget is in focus.

Keysym(value=None)
value
initial keysym, see pygame keysyms
Example w = Input(value=pygame.locals.K_g) w = Input(pygame.locals.K_g) w = Input() """ def __init__(self,value=None,**params): params.setdefault('cls','keysym') widget.Widget.__init__(self,**params) self.value = value self.font = self.style.font w,h = self.font.size("Right Super") #"Right Shift") self.style.width,self.style.height = w,h #self.rect.w=w+self.style.padding_left+self.style.padding_right #self.rect.h=h+self.style.padding_top+self.style.padding_bottom def event(self,e): used = None if e.type == FOCUS or e.type == BLUR: self.repaint() elif e.type == KEYDOWN: if e.key != K_TAB: self.value = e.key self.repaint() self.send(CHANGE) used = True self.next() self.pcls = "" if self.container.myfocus is self: self.pcls = "focus" return used def paint(self,s): r = pygame.rect.Rect(0,0,self.rect.w,self.rect.h) #render_box(s,self.style.background,r) if self.value == None: return name = "" for p in pygame.key.name(self.value).split(): name += p.capitalize()+" " #r.x = self.style.padding_left; #r.y = self.style.padding_bottom; s.blit(self.style.font.render(name, 1, self.style.color), r) def __setattr__(self,k,v): if k == 'value' and v != None: v = int(v) _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/widget.py0000644000000000000000000002447411130023047021345 0ustar rootroot""" """ import pygame import style class Widget: """Template object - base for all widgets.
Widget(**params)

A number of optional params may be passed to the Widget initializer.

decorate
defaults to True. If true, will call theme.decorate(self) to allow the theme a chance to decorate the widget.
style
a dict of style parameters.
x, y, width, height
position and size parameters, passed along to style
align, valign
alignment parameters, passed along to style
font, color, background
other common parameters that are passed along to style
cls
class name as used by Theme
name
name of widget as used by Form. If set, will call form.add(self,name) to add the widget to the most recently created Form.
focusable
True if this widget can receive focus via Tab, etc. Defaults to True.
disabled
True of this widget is disabled. Defaults to False.
value
initial value
Example - Creating your own Widget

This example shows which methods are template methods.

class Draw(gui.Widget): def paint(self,s): #paint the pygame.Surface return def update(self,s): #update the pygame.Surface and return the update rects return [pygame.Rect(0,0,self.rect.w,self.rect.h)] def event(self,e): #handle the pygame.Event return def resize(self,width=None,height=None): #return the width and height of this widget return 256,256 """ def __init__(self,**params): #object.Object.__init__(self) self.connects = {} params.setdefault('decorate',True) params.setdefault('style',{}) params.setdefault('focusable',True) params.setdefault('disabled',False) self.focusable = params['focusable'] self.disabled = params['disabled'] self.rect = pygame.Rect(params.get('x',0),params.get('y',0),params.get('width',0),params.get('height',0)) s = params['style'] #some of this is a bit "theme-ish" but it is very handy, so these #things don't have to be put directly into the style. for att in ('align','valign','x','y','width','height','color','font','background'): if att in params: s[att] = params[att] self.style = style.Style(self,s) self.cls = 'default' if 'cls' in params: self.cls = params['cls'] if 'name' in params: import form self.name = params['name'] if hasattr(form.Form,'form') and form.Form.form != None: form.Form.form.add(self) self.form = form.Form.form if 'value' in params: self.value = params['value'] self.pcls = "" if params['decorate'] != False: import app if not hasattr(app.App,'app'): print 'gui.widget: creating an App' app.App.app = app.App() app.App.app.theme.decorate(self,params['decorate']) def focus(self): """Focus this Widget.
Widget.focus()
""" if getattr(self,'container',None) != None: if self.container.myfocus != self: ## by Gal Koren self.container.focus(self) def blur(self): """Blur this Widget.
Widget.blur()
""" if getattr(self,'container',None) != None: self.container.blur(self) def open(self): """Open this Widget as a modal dialog.
Widget.open()
""" if getattr(self,'container',None) != None: self.container.open(self) def close(self): """Close this Widget (if it is a modal dialog.)
Widget.close()
""" if getattr(self,'container',None) != None: self.container.close(self) def resize(self,width=None,height=None): """Template method - return the size and width of this widget.

Responsible for also resizing all sub-widgets.

Widget.resize(width,height): return width,height
width
suggested width
height
suggested height

If not overridden, will return self.style.width, self.style.height

""" return self.style.width, self.style.height def chsize(self): """Change the size of this widget.

Calling this method will cause a resize on all the widgets, including this one.

Widget.chsize()
""" if not hasattr(self,'_painted'): return if not hasattr(self,'container'): return import app if hasattr(app.App,'app'): if app.App.app._chsize: return app.App.app.chsize() return #if hasattr(app.App,'app'): # w,h = self.rect.w,self.rect.h # w2,h2 = self.resize() # if w2 != w or h2 != h: # app.App.app.chsize() # else: # self.repaint() def update(self,s): """Template method - update the surface
Widget.update(s): return list of pygame.Rect(s)
s
pygame.Surface to update

return - a list of the updated areas as pygame.Rect(s).

""" return def paint(self,s): """Template method - paint the surface
Widget.paint(s)
s
pygame.Surface to paint
""" return def repaint(self): """Request a repaint of this Widget.
Widget.repaint()
""" if getattr(self,'container',None) != None: self.container.repaint(self) def repaintall(self): """Request a repaint of all Widgets.
Widget.repaintall()
""" if getattr(self,'container',None) != None: self.container.repaintall() def reupdate(self): """Request a reupdate of this Widget
Widget.reupdate()
""" if getattr(self,'container',None) != None: self.container.reupdate(self) def next(self): """Pass focus to next Widget.

Widget order determined by the order they were added to their container.

Widget.next()
""" if getattr(self,'container',None) != None: self.container.next(self) def previous(self): """Pass focus to previous Widget.

Widget order determined by the order they were added to their container.

Widget.previous()
""" if getattr(self,'container',None) != None: self.container.previous(self) def get_abs_rect(self): """Get the absolute rect of this widget on the App screen
Widget.get_abs_rect(): return pygame.Rect
""" x, y = self.rect.x , self.rect.y x += self._rect_content.x y += self._rect_content.y c = getattr(self,'container',None) while c: x += c.rect.x y += c.rect.y if hasattr(c,'_rect_content'): x += c._rect_content.x y += c._rect_content.y c = getattr(c,'container',None) return pygame.Rect(x, y, self.rect.w, self.rect.h) def connect(self,code,fnc,*values): """Connect a event code to a callback function.

There may only be one callback per event code.

Object.connect(code,fnc,value)
code
event type [[gui-const]]
fnc
callback function
*values
values to pass to callback. Please note that callbacks may also have "magicaly" parameters. Such as:
_event
receive the event
_code
receive the event code
_widget
receive the sending widget
Example def onclick(value): print 'click',value w = Button("PGU!") w.connect(gui.CLICK,onclick,'PGU Button Clicked') """ self.connects[code] = {'fnc':fnc,'values':values} def send(self,code,event=None): """Send a code, event callback trigger.
Object.send(code,event=None)
code
event code
event
event
""" if code in self.connects: con = self.connects[code] #con['fnc'](*con['values']) fnc = con['fnc'] values = list(con['values']) nargs = fnc.func_code.co_argcount names = list(fnc.func_code.co_varnames)[:nargs] if hasattr(fnc,'im_class'): names.pop(0) args = [] magic = {'_event':event,'_code':code,'_widget':self} for name in names: if name in magic.keys(): args.append(magic[name]) elif len(values): args.append(values.pop(0)) else: break args.extend(values) fnc(*args) def _event(self,e): if self.disabled: return self.send(e.type,e) return self.event(e) # return # import app # if hasattr(app.App,'app'): # app.App.app.events.append((self,e)) def event(self,e): """Template method - called when an event is passed to this object.

Please note that if you use an event, returning the value True will stop parent containers from also using the event. (For example, if your widget handles TABs or arrow keys, and you don't want those to also alter the focus.)

e
event
""" return python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/group.py0000644000000000000000000000216711130023047021211 0ustar rootroot""" """ from const import * import widget class Group(widget.Widget): """An object for grouping together Form elements.
Group(name=None,value=None)
name
name as used in the Form
value
values that are currently selected in the group

See [[gui-button]] for several examples.

When the value changes, an gui.CHANGE event is sent. Although note, that when the value is a list, it may have to be sent by hand via g.send(gui.CHANGE)

""" def __init__(self,name=None,value=None): widget.Widget.__init__(self,name=name,value=value) self.widgets = [] def add(self,w): """Add a widget to this group.
Group.add(w)
""" self.widgets.append(w) def __setattr__(self,k,v): _v = self.__dict__.get(k,NOATTR) self.__dict__[k] = v if k == 'value' and _v != NOATTR and _v != v: self._change() def _change(self): self.send(CHANGE) for w in self.widgets: w.repaint() python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/container.py0000644000000000000000000003544711130023047022046 0ustar rootroot""" """ import pygame from pygame.locals import * from const import * import widget, surface class Container(widget.Widget): """The base container widget, can be used as a template as well as stand alone.
Container()
""" def __init__(self,**params): widget.Widget.__init__(self,**params) self.myfocus = None self.mywindow = None self.myhover = None #self.background = 0 self.widgets = [] self.windows = [] self.toupdate = {} self.topaint = {} def update(self,s): updates = [] if self.myfocus: self.toupdate[self.myfocus] = self.myfocus for w in self.topaint: if w is self.mywindow: continue else: sub = surface.subsurface(s,w.rect) sub.blit(w._container_bkgr,(0,0)) w.paint(sub) updates.append(pygame.rect.Rect(w.rect)) for w in self.toupdate: if w is self.mywindow: continue else: us = w.update(surface.subsurface(s,w.rect)) if us: for u in us: updates.append(pygame.rect.Rect(u.x + w.rect.x,u.y+w.rect.y,u.w,u.h)) for w in self.topaint: if w is self.mywindow: w.paint(self.top_surface(s,w)) updates.append(pygame.rect.Rect(w.rect)) else: continue for w in self.toupdate: if w is self.mywindow: us = w.update(self.top_surface(s,w)) else: continue if us: for u in us: updates.append(pygame.rect.Rect(u.x + w.rect.x,u.y+w.rect.y,u.w,u.h)) self.topaint = {} self.toupdate = {} return updates def repaint(self,w=None): if not w: return widget.Widget.repaint(self) self.topaint[w] = w self.reupdate() def reupdate(self,w=None): if not w: return widget.Widget.reupdate(self) self.toupdate[w] = w self.reupdate() def paint(self,s): self.toupdate = {} self.topaint = {} for w in self.widgets: ok = False try: sub = surface.subsurface(s,w.rect) ok = True except: print 'container.paint(): %s not in %s'%(w.__class__.__name__,self.__class__.__name__) print s.get_width(),s.get_height(),w.rect ok = False if ok: if not (hasattr(w,'_container_bkgr') and w._container_bkgr.get_width() == sub.get_width() and w._container_bkgr.get_height() == sub.get_height()): w._container_bkgr = sub.copy() w._container_bkgr.fill((0,0,0,0)) w._container_bkgr.blit(sub,(0,0)) w.paint(sub) for w in self.windows: w.paint(self.top_surface(s,w)) def top_surface(self,s,w): x,y = s.get_abs_offset() s = s.get_abs_parent() return surface.subsurface(s,(x+w.rect.x,y+w.rect.y,w.rect.w,w.rect.h)) def event(self,e): used = False if self.mywindow and e.type == MOUSEBUTTONDOWN: w = self.mywindow if self.myfocus is w: if not w.rect.collidepoint(e.pos): self.blur(w) if not self.myfocus: if w.rect.collidepoint(e.pos): self.focus(w) if not self.mywindow: #### by Gal Koren ## ## if e.type == FOCUS: if e.type == FOCUS and not self.myfocus: #self.first() pass elif e.type == EXIT: if self.myhover: self.exit(self.myhover) elif e.type == BLUR: if self.myfocus: self.blur(self.myfocus) elif e.type == MOUSEBUTTONDOWN: h = None for w in self.widgets: if not w.disabled: #focusable not considered, since that is only for tabs if w.rect.collidepoint(e.pos): h = w if self.myfocus is not w: self.focus(w) if not h and self.myfocus: self.blur(self.myfocus) elif e.type == MOUSEMOTION: if 1 in e.buttons: if self.myfocus: ws = [self.myfocus] else: ws = [] else: ws = self.widgets h = None for w in ws: if w.rect.collidepoint(e.pos): h = w if self.myhover is not w: self.enter(w) if not h and self.myhover: self.exit(self.myhover) w = self.myhover if w and w is not self.myfocus: sub = pygame.event.Event(e.type,{ 'buttons':e.buttons, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y), 'rel':e.rel}) used = w._event(sub) w = self.myfocus if w: sub = e if e.type == MOUSEBUTTONUP or e.type == MOUSEBUTTONDOWN: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y)}) used = w._event(sub) elif e.type == CLICK and self.myhover is w: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y)}) used = w._event(sub) elif e.type == CLICK: #a dead click pass elif e.type == MOUSEMOTION: sub = pygame.event.Event(e.type,{ 'buttons':e.buttons, 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y), 'rel':e.rel}) used = w._event(sub) else: used = w._event(sub) if not used: if e.type is KEYDOWN: if e.key is K_TAB and self.myfocus: if (e.mod&KMOD_SHIFT) == 0: self.myfocus.next() else: self.myfocus.previous() return True elif e.key == K_UP: self._move_focus(0,-1) return True elif e.key == K_RIGHT: self._move_focus(1,0) return True elif e.key == K_DOWN: self._move_focus(0,1) return True elif e.key == K_LEFT: self._move_focus(-1,0) return True return used def _move_focus(self,dx_,dy_): myfocus = self.myfocus if not self.myfocus: return from pgu.gui import App widgets = self._get_widgets(App.app) #if myfocus not in widgets: return #widgets.remove(myfocus) if myfocus in widgets: widgets.remove(myfocus) rect = myfocus.get_abs_rect() fx,fy = rect.centerx,rect.centery def sign(v): if v < 0: return -1 if v > 0: return 1 return 0 dist = [] for w in widgets: wrect = w.get_abs_rect() wx,wy = wrect.centerx,wrect.centery dx,dy = wx-fx,wy-fy if dx_ > 0 and wrect.left < rect.right: continue if dx_ < 0 and wrect.right > rect.left: continue if dy_ > 0 and wrect.top < rect.bottom: continue if dy_ < 0 and wrect.bottom > rect.top: continue dist.append((dx*dx+dy*dy,w)) if not len(dist): return dist.sort() d,w = dist.pop(0) w.focus() def _get_widgets(self,c): widgets = [] if c.mywindow: widgets.extend(self._get_widgets(c.mywindow)) else: for w in c.widgets: if isinstance(w,Container): widgets.extend(self._get_widgets(w)) elif not w.disabled and w.focusable: widgets.append(w) return widgets def remove(self,w): """Remove a widget from the container.
Container.remove(w)
""" self.blur(w) self.widgets.remove(w) #self.repaint() self.chsize() def add(self,w,x,y): """Add a widget to the container.
Container.add(w,x,y)
x, y
position of the widget
""" w.style.x = x w.style.y = y w.container = self #NOTE: this might fix it, sort of... #but the thing is, we don't really want to resize #something if it is going to get resized again later #for no reason... #w.rect.x,w.rect.y = w.style.x,w.style.y #w.rect.w, w.rect.h = w.resize() self.widgets.append(w) self.chsize() def open(self,w=None,x=None,y=None): from app import App #HACK: I import it here to prevent circular importing if not w: if (not hasattr(self,'container') or not self.container) and self is not App.app: self.container = App.app #print 'top level open' return widget.Widget.open(self) if self.container: if x != None: return self.container.open(w,self.rect.x+x,self.rect.y+y) return self.container.open(w) w.container = self if w.rect.w == 0 or w.rect.h == 0: #this might be okay, not sure if needed. #_chsize = App.app._chsize #HACK: we don't want this resize to trigger a chsize. w.rect.w,w.rect.h = w.resize() #App.app._chsize = _chsize if x == None or y == None: #auto center the window #w.style.x,w.style.y = 0,0 w.rect.x = (self.rect.w-w.rect.w)/2 w.rect.y = (self.rect.h-w.rect.h)/2 #w.resize() #w._resize(self.rect.w,self.rect.h) else: #show it where we want it w.rect.x = x w.rect.y = y #w._resize() self.windows.append(w) self.mywindow = w self.focus(w) self.repaint(w) w.send(OPEN) def close(self,w=None): if not w: return widget.Widget.close(self) if self.container: #make sure we're in the App return self.container.close(w) if self.myfocus is w: self.blur(w) if w not in self.windows: return #no need to remove it twice! happens. self.windows.remove(w) self.mywindow = None if self.windows: self.mywindow = self.windows[-1] self.focus(self.mywindow) if not self.mywindow: self.myfocus = self.widget #HACK: should be done fancier, i think.. if not self.myhover: self.enter(self.widget) self.repaintall() w.send(CLOSE) def focus(self,w=None): widget.Widget.focus(self) ### by Gal koren # if not w: # return widget.Widget.focus(self) if not w: return if self.myfocus: self.blur(self.myfocus) if self.myhover is not w: self.enter(w) self.myfocus = w w._event(pygame.event.Event(FOCUS)) #print self.myfocus,self.myfocus.__class__.__name__ def blur(self,w=None): if not w: return widget.Widget.blur(self) if self.myfocus is w: if self.myhover is w: self.exit(w) self.myfocus = None w._event(pygame.event.Event(BLUR)) def enter(self,w): if self.myhover: self.exit(self.myhover) self.myhover = w w._event(pygame.event.Event(ENTER)) def exit(self,w): if self.myhover and self.myhover is w: self.myhover = None w._event(pygame.event.Event(EXIT)) # def first(self): # for w in self.widgets: # if w.focusable: # self.focus(w) # return # if self.container: self.container.next(self) # def next(self,w): # if w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... # # for w in self.widgets[self.widgets.index(w)+1:]: # if w.focusable: # self.focus(w) # return # if self.container: return self.container.next(self) def _next(self,orig=None): start = 0 if orig in self.widgets: start = self.widgets.index(orig)+1 for w in self.widgets[start:]: if not w.disabled and w.focusable: if isinstance(w,Container): if w._next(): return True else: self.focus(w) return True return False def _previous(self,orig=None): end = len(self.widgets) if orig in self.widgets: end = self.widgets.index(orig) ws = self.widgets[:end] ws.reverse() for w in ws: if not w.disabled and w.focusable: if isinstance(w,Container): if w._previous(): return True else: self.focus(w) return True return False def next(self,w=None): if w != None and w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... if self._next(w): return True if self.container: return self.container.next(self) def previous(self,w=None): if w != None and w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... if self._previous(w): return True if self.container: return self.container.previous(self) def resize(self,width=None,height=None): #r = self.rect #r.w,r.h = 0,0 ww,hh = 0,0 if self.style.width: ww = self.style.width if self.style.height: hh = self.style.height for w in self.widgets: #w.rect.w,w.rect.h = 0,0 w.rect.x,w.rect.y = w.style.x,w.style.y w.rect.w, w.rect.h = w.resize() #w._resize() ww = max(ww,w.rect.right) hh = max(hh,w.rect.bottom) return ww,hh python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/slider.py0000644000000000000000000002307311130023047021336 0ustar rootroot"""All sliders and scroll bar widgets have the same parameters.
Slider(value,min,max,size)
value
initial value
min
minimum value
max
maximum value
size
size of bar in pixels
""" import pygame from pygame.locals import * from const import * import widget import app import table import basic _SLIDER_HORIZONTAL = 0 _SLIDER_VERTICAL = 1 class _slider(widget.Widget): def __init__(self,value,orient,min,max,size,step=1,**params): params.setdefault('cls','slider') widget.Widget.__init__(self,**params) self.min,self.max,self.value,self.orient,self.size,self.step = min,max,value,orient,size,step def paint(self,s): self.value = self.value r = pygame.rect.Rect(0,0,self.style.width,self.style.height) if self.orient == _SLIDER_HORIZONTAL: r.x = (self.value-self.min) * (r.w-self.size) / max(1,self.max-self.min); r.w = self.size; else: r.y = (self.value-self.min) * (r.h-self.size) / max(1,self.max-self.min); r.h = self.size; self.bar = r app.App.app.theme.render(s,self.style.bar,r) def event(self,e): used = None r = pygame.rect.Rect(0,0,self.style.width,self.style.height) adj = 0 if e.type == ENTER: self.repaint() elif e.type == EXIT: self.repaint() elif e.type == MOUSEBUTTONDOWN: if self.bar.collidepoint(e.pos): self.grab = e.pos[0],e.pos[1] self.grab_value = self.value else: x,y,adj = e.pos[0],e.pos[1],1 self.grab = None self.repaint() elif e.type == MOUSEBUTTONUP: #x,y,adj = e.pos[0],e.pos[1],1 self.repaint() elif e.type == MOUSEMOTION: if 1 in e.buttons and self.container.myfocus is self: if self.grab != None: rel = e.pos[0]-self.grab[0],e.pos[1]-self.grab[1] if self.orient == _SLIDER_HORIZONTAL: d = (r.w - self.size) if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[0] / d) else: d = (r.h - self.size) if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[1] / d) else: x,y,adj = e.pos[0],e.pos[1],1 elif e.type is KEYDOWN: if self.orient == _SLIDER_HORIZONTAL and e.key == K_LEFT: self.value -= self.step used = True elif self.orient == _SLIDER_HORIZONTAL and e.key == K_RIGHT: self.value += self.step used = True elif self.orient == _SLIDER_VERTICAL and e.key == K_UP: self.value -= self.step used = True elif self.orient == _SLIDER_VERTICAL and e.key == K_DOWN: self.value += self.step used = True if adj: if self.orient == _SLIDER_HORIZONTAL: d = self.size/2 - (r.w/(self.max-self.min+1))/2 self.value = (x-d) * (self.max-self.min) / (r.w-self.size+1) + self.min else: d = self.size/2 - (r.h/(self.max-self.min+1))/2 self.value = (y-d) * (self.max-self.min) / (r.h-self.size+1) + self.min self.pcls = "" if self.container.myhover is self: self.pcls = "hover" if (self.container.myfocus is self and 1 in pygame.mouse.get_pressed()): self.pcls = "down" return used def __setattr__(self,k,v): if k == 'value': v = int(v) v = max(v,self.min) v = min(v,self.max) _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.send(CHANGE) self.repaint() if hasattr(self,'size'): sz = min(self.size,max(self.style.width,self.style.height)) sz = max(sz,min(self.style.width,self.style.height)) self.__dict__['size'] = sz if hasattr(self,'max') and hasattr(self,'min'): if self.max < self.min: self.max = self.min class VSlider(_slider): """A verticle slider.
VSlider(value,min,max,size)
""" def __init__(self,value,min,max,size,step=1,**params): params.setdefault('cls','vslider') _slider.__init__(self,value,_SLIDER_VERTICAL,min,max,size,step,**params) class HSlider(_slider): """A horizontal slider.
HSlider(value,min,max,size)
""" def __init__(self,value,min,max,size,step=1,**params): params.setdefault('cls','hslider') _slider.__init__(self,value,_SLIDER_HORIZONTAL,min,max,size,step,**params) class HScrollBar(table.Table): """A horizontal scroll bar.
HScrollBar(value,min,max,size,step=1)
""" def __init__(self,value,min,max,size,step=1,**params): params.setdefault('cls','hscrollbar') table.Table.__init__(self,**params) self.slider = _slider(value,_SLIDER_HORIZONTAL,min,max,size,step=step,cls=self.cls+'.slider') self.minus = basic.Image(self.style.minus) self.minus.connect(MOUSEBUTTONDOWN,self._click,-1) self.slider.connect(CHANGE,self.send,CHANGE) self.minus2 = basic.Image(self.style.minus) self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1) self.plus = basic.Image(self.style.plus) self.plus.connect(MOUSEBUTTONDOWN,self._click,1) self.size = size def _click(self,value): self.slider.value += self.slider.step*value def resize(self,width=None,height=None): self.clear() self.tr() w = self.style.width h = self.slider.style.height ww = 0 if w > (h*2 + self.minus.style.width+self.plus.style.width): self.td(self.minus) ww += self.minus.style.width self.td(self.slider) if w > (h*2 + self.minus.style.width+self.minus2.style.width+self.plus.style.width): self.td(self.minus2) ww += self.minus2.style.width if w > (h*2 + self.minus.style.width+self.plus.style.width): self.td(self.plus) ww += self.plus.style.width #HACK: handle theme sizing properly from app import App xt,xr,xb,xl = App.app.theme.getspacing(self.slider) ww += xr+xl self.slider.style.width = self.style.width - ww setattr(self.slider,'size',self.size * self.slider.style.width / max(1,self.style.width)) return table.Table.resize(self,width,height) def __setattr__(self,k,v): if k in ('min','max','value','step'): return setattr(self.slider,k,v) self.__dict__[k]=v def __getattr__(self,k): if k in ('min','max','value','step'): return getattr(self.slider,k) return table.Table.__getattr__(self,k) #self.__dict__[k] class VScrollBar(table.Table): """A vertical scroll bar.
VScrollBar(value,min,max,size,step=1)
""" def __init__(self,value,min,max,size,step=1,**params): params.setdefault('cls','vscrollbar') table.Table.__init__(self,**params) self.minus = basic.Image(self.style.minus) self.minus.connect(MOUSEBUTTONDOWN,self._click,-1) self.minus2 = basic.Image(self.style.minus) self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1) self.plus = basic.Image(self.style.plus) self.plus.connect(MOUSEBUTTONDOWN,self._click,1) self.slider = _slider(value,_SLIDER_VERTICAL,min,max,size,step=step,cls=self.cls+'.slider') self.slider.connect(CHANGE,self.send,CHANGE) self.size = size def _click(self,value): self.slider.value += self.slider.step*value def resize(self,width=None,height=None): self.clear() h = self.style.height w = self.slider.style.width hh = 0 if h > (w*2 + self.minus.style.height+self.plus.style.height): self.tr() self.td(self.minus) hh += self.minus.style.height self.tr() self.td(self.slider) if h > (w*2 + self.minus.style.height+self.minus2.style.height+self.plus.style.height): self.tr() self.td(self.minus2) hh += self.minus2.style.height if h > (w*2 + self.minus.style.height+self.plus.style.height): self.tr() self.td(self.plus) hh += self.plus.style.height #HACK: handle theme sizing properly from app import App xt,xr,xb,xl = App.app.theme.getspacing(self.slider) hh += xt+xb self.slider.style.height = self.style.height - hh setattr(self.slider,'size',self.size * self.slider.style.height / max(1,self.style.height)) return table.Table.resize(self,width,height) def __setattr__(self,k,v): if k in ('min','max','value','step'): return setattr(self.slider,k,v) self.__dict__[k]=v def __getattr__(self,k): if k in ('min','max','value','step'): return getattr(self.slider,k) return table.Table.__getattr__(self,k) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/form.py0000644000000000000000000000371111130023047021014 0ustar rootroot""" """ import widget class Form(widget.Widget): """A form that automatically will contain all named widgets.

After a form is created, all named widget that are subsequently created are added to that form. You may use dict style access to access named widgets.

Form()
Example f = gui.Form() w = gui.Input("Phil",name="firstname") w = gui.Input("Hassey",name="lastname") print f.results() print '' print f.items() print '' print f['firstname'].value print f['lastname'].value """ def __init__(self): widget.Widget.__init__(self,decorate=False) self._elist = [] self._emap = {} self._dirty = 0 Form.form = self def add(self,e,name=None,value=None): if name != None: e.name = name if value != None: e.value = value self._elist.append(e) self._dirty = 1 def _clean(self): for e in self._elist[:]: if not hasattr(e,'name') or e.name == None: self._elist.remove(e) self._emap = {} for e in self._elist: self._emap[e.name] = e self._dirty = 0 def __getitem__(self,k): if self._dirty: self._clean() return self._emap[k] def __contains__(self,k): if self._dirty: self._clean() if k in self._emap: return True return False def results(self): """Return a dict of name => values.
Form.results(): return dict
""" if self._dirty: self._clean() r = {} for e in self._elist: r[e.name] = e.value return r def items(self): """Return a list of name, value keys.
Form.items(): return list
""" return self.results().items() #def start(self): # Object.start(self,-1) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/readme.txt0000644000000000000000000000014411130023047021472 0ustar rootrootThis is the GUI module from Phil's pyGame Utilities: http://www.imitationpickles.org/pgu/wiki/indexpython-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/document.py0000644000000000000000000000577111130023047021677 0ustar rootroot""" """ import pygame import container import layout class _document_widget: def __init__(self,w,align=None): #w.rect.w,w.rect.h = w.resize() #self.rect = w.rect self.widget = w if align != None: self.align = align class Document(container.Container): """A document container contains many widgets strung together in a document format. (How informative!)
Document()
""" def __init__(self,**params): params.setdefault('cls','document') container.Container.__init__(self,**params) self.layout = layout.Layout(pygame.Rect(0,0,self.rect.w,self.rect.h)) def add(self,e,align=None): """Add a widget.
Document.add(e,align=None)
e
widget
align
alignment (None,-1,0,1)
""" dw = _document_widget(e,align) self.layout.add(dw) e.container = self e._c_dw = dw self.widgets.append(e) self.chsize() def remove(self,e): self.layout._widgets.remove(e._c_dw) self.widgets.remove(e) self.chsize() def block(self,align): """Start a new block.
Document.block(align)
align
alignment of block (-1,0,1)
""" self.layout.add(align) def space(self,e): """Add a spacer.
Document.space(e)
e
a (w,h) size for the spacer
""" self.layout.add(e) def br(self,height): """Add a line break.
Document.br(height)
height
height of line break
""" self.layout.add((0,height)) def resize(self,width=None,height=None): if self.style.width: width = self.style.width if self.style.height: height = self.style.height for w in self.widgets: w.rect.w,w.rect.h = w.resize() if (width != None and w.rect.w > width) or (height != None and w.rect.h > height): w.rect.w,w.rect.h = w.resize(width,height) dw = w._c_dw dw.rect = pygame.Rect(0,0,w.rect.w,w.rect.h) if width == None: width = 65535 self.layout.rect = pygame.Rect(0,0,width,0) self.layout.resize() _max_w = 0 for w in self.widgets: #xt,xl,xb,xr = w.getspacing() dw = w._c_dw w.style.x,w.style.y,w.rect.w,w.rect.h = dw.rect.x,dw.rect.y,dw.rect.w,dw.rect.h #w.resize() w.rect.x,w.rect.y = w.style.x,w.style.y _max_w = max(_max_w,w.rect.right) #self.rect.w = _max_w #self.layout.rect.w #self.rect.h = self.layout.rect.h #print 'document',_max_w,self.layout.rect.h return _max_w,self.layout.rect.h python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/dialog.py0000644000000000000000000001161711130023047021314 0ustar rootroot""" """ import os from const import * import table, area import basic, input, button class Dialog(table.Table): """A dialog window with a title bar and an "close" button on the bar.
Dialog(title,main)
title
title widget, usually a label
main
main widget, usually a container
Example title = gui.Label("My Title") main = gui.Container() #add stuff to the container... d = gui.Dialog(title,main) d.open() """ def __init__(self,title,main,**params): params.setdefault('cls','dialog') table.Table.__init__(self,**params) self.tr() self.td(title,align=-1,cls=self.cls+'.bar') clos = button.Icon(self.cls+".bar.close") clos.connect(CLICK,self.close,None) self.td(clos,align=1,cls=self.cls+'.bar') self.tr() self.td(main,colspan=2,cls=self.cls+".main") # self.tr() # # # t = table.Table(cls=self.cls+".bar") # t.tr() # t.td(title) # clos = button.Icon(self.cls+".bar.close") # t.td(clos,align=1) # clos.connect(CLICK,self.close,None) # self.add(t,0,0) # # main.rect.w,main.rect.h = main.resize() # clos.rect.w,clos.rect.h = clos.resize() # title.container.style.width = main.rect.w - clos.rect.w # # self.tr() # self.td(main,cls=self.cls+".main") # class FileDialog(Dialog): """A file picker dialog window.
FileDialog()

Some optional parameters:

title_txt
title text
button_txt
button text
path
initial path
""" def __init__(self, title_txt="File Browser", button_txt="Okay", cls="dialog", path=None): cls1 = 'filedialog' if not path: self.curdir = os.getcwd() else: self.curdir = path import app self.dir_img = basic.Image(app.App.app.theme.get(cls1+'.folder', '', 'image')) td_style = {'padding_left': 4, 'padding_right': 4, 'padding_top': 2, 'padding_bottom': 2} self.title = basic.Label(title_txt, cls=cls+".title.label") self.body = table.Table() self.list = area.List(width=350, height=150) self.input_dir = input.Input() self.input_file = input.Input() self._list_dir_() self.button_ok = button.Button(button_txt) self.body.tr() self.body.td(basic.Label("Folder"), style=td_style, align=-1) self.body.td(self.input_dir, style=td_style) self.body.tr() self.body.td(self.list, colspan=3, style=td_style) self.list.connect(CHANGE, self._item_select_changed_, None) self.button_ok.connect(CLICK, self._button_okay_clicked_, None) self.body.tr() self.body.td(basic.Label("File"), style=td_style, align=-1) self.body.td(self.input_file, style=td_style) self.body.td(self.button_ok, style=td_style) self.value = None Dialog.__init__(self, self.title, self.body) def _list_dir_(self): self.input_dir.value = self.curdir self.input_dir.pos = len(self.curdir) self.input_dir.vpos = 0 dirs = [] files = [] try: for i in os.listdir(self.curdir): if os.path.isdir(os.path.join(self.curdir, i)): dirs.append(i) else: files.append(i) except: self.input_file.value = "Opps! no access" #if '..' not in dirs: dirs.append('..') dirs.sort() dirs = ['..'] + dirs files.sort() for i in dirs: #item = ListItem(image=self.dir_img, text=i, value=i) self.list.add(i,image=self.dir_img,value=i) for i in files: #item = ListItem(image=None, text=i, value=i) self.list.add(i,value=i) #self.list.resize() self.list.set_vertical_scroll(0) #self.list.repaintall() def _item_select_changed_(self, arg): self.input_file.value = self.list.value fname = os.path.abspath(os.path.join(self.curdir, self.input_file.value)) if os.path.isdir(fname): self.input_file.value = "" self.curdir = fname self.list.clear() self._list_dir_() def _button_okay_clicked_(self, arg): if self.input_dir.value != self.curdir: if os.path.isdir(self.input_dir.value): self.input_file.value = "" self.curdir = os.path.abspath(self.input_dir.value) self.list.clear() self._list_dir_() else: self.value = os.path.join(self.curdir, self.input_file.value) self.send(CHANGE) self.close()python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/app.py0000644000000000000000000001406411130023047020634 0ustar rootroot""" """ import pygame from pygame.locals import * import container from const import * class App(container.Container): """The top-level widget for an application.
App(theme=None)
theme
an instance of a Theme, optional as it will use the default Theme class.
Basic Example app = gui.App() app.run(widget=widget,screen=screen) Integrated Example app = gui.App() gui.init(widget=widget) while 1: for e in pygame.event.get(): app.event(e) app.update(screen) """ def __init__(self,theme=None,**params): App.app = self if theme == None: from theme import Theme theme = Theme() self.theme = theme params['decorate'] = 'app' container.Container.__init__(self,**params) self._quit = False self.widget = None self._chsize = False self._repaint = False self.screen = None self.container = None self.events = [] def resize(self): screen = self.screen w = self.widget wsize = 0 #5 cases #input screen is already set use its size if screen: self.screen = screen width,height = screen.get_width(),screen.get_height() #display.screen elif pygame.display.get_surface(): screen = pygame.display.get_surface() self.screen = screen width,height = screen.get_width(),screen.get_height() #app has width,height elif self.style.width != 0 and self.style.height != 0: screen = pygame.display.set_mode((self.style.width,self.style.height),SWSURFACE) self.screen = screen width,height = screen.get_width(),screen.get_height() #widget has width,height, or its own size.. else: wsize = 1 width,height = w.rect.w,w.rect.h = w.resize() #w._resize() screen = pygame.display.set_mode((width,height),SWSURFACE) self.screen = screen #use screen to set up size of this widget self.style.width,self.style.height = width,height self.rect.w,self.rect.h = width,height self.rect.x,self.rect.y = 0,0 w.rect.x,w.rect.y = 0,0 w.rect.w,w.rect.h = w.resize(width,height) for w in self.windows: w.rect.w,w.rect.h = w.resize() self._chsize = False def init(self,widget=None,screen=None): #TODO widget= could conflict with module widget """Initialize the application.
App.init(widget=None,screen=None)
widget
main widget
screen
pygame.Surface to render to
""" App.app = self if widget: self.widget = widget if screen: self.screen = screen self.resize() w = self.widget self.widgets = [] self.widgets.append(w) w.container = self self.focus(w) pygame.key.set_repeat(500,30) self._repaint = True self._quit = False self.send(INIT) def event(self,e): """Pass an event to the main widget.
App.event(e)
e
event
""" App.app = self #NOTE: might want to deal with ACTIVEEVENT in the future. self.send(e.type,e) container.Container.event(self,e) if e.type == MOUSEBUTTONUP: if e.button not in (4,5): #ignore mouse wheel sub = pygame.event.Event(CLICK,{ 'button':e.button, 'pos':e.pos}) self.send(sub.type,sub) container.Container.event(self,sub) def loop(self): App.app = self s = self.screen for e in pygame.event.get(): if not (e.type == QUIT and self.mywindow): self.event(e) us = self.update(s) pygame.display.update(us) def paint(self,screen): self.screen = screen if self._chsize: self.resize() self._chsize = False if hasattr(self,'background'): self.background.paint(screen) container.Container.paint(self,screen) def update(self,screen): """Update the screen.
screen
pygame surface
""" self.screen = screen if self._chsize: self.resize() self._chsize = False if self._repaint: self.paint(screen) self._repaint = False return [pygame.Rect(0,0,screen.get_width(),screen.get_height())] else: us = container.Container.update(self,screen) return us def run(self,widget=None,screen=None): """Run an application.

Automatically calls App.init and then forever loops App.event and App.update

widget
main widget
screen
pygame.Surface to render to
""" self.init(widget,screen) while not self._quit: self.loop() pygame.time.wait(10) def reupdate(self,w=None): pass def repaint(self,w=None): self._repaint = True def repaintall(self): self._repaint = True def chsize(self): self._chsize = True self._repaint = True def quit(self,value=None): self._quit = True class Desktop(App): """Create an App using the desktop theme class.
Desktop()
""" def __init__(self,**params): params.setdefault('cls','desktop') App.__init__(self,**params)python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/layout.py0000644000000000000000000001164311130023047021371 0ustar rootroot"""document layout engine.""" class Layout: """the document layout engine .widgets -- elements are kept in this list. read-only, use add to add items to it. """ def __init__(self,rect=None): """initialize the object with the size of the box.""" self._widgets = [] self.rect = rect def add(self,e): """add a document element to the layout. a document element may be - a tuple (w,h) if it is a whitespace element - a tuple (0,h) if it is a linebreak element - an integer -1,0,1 if it is a command to start a new block of elements that are aligned either left,center, or right. - an object with a .rect (for size) -- such as a word element - an object with a .rect (for size) and .align -- such as an image element """ self._widgets.append(e) def resize(self): """resize the layout this method recalculates the position of all document elements after they have been added to the document. .rect.x,y will be updated for all objects. """ self.init() self.widgets = [] for e in self._widgets: if type(e) is tuple and e[0] != 0: self.do_space(e) elif type(e) is tuple and e[0] == 0: self.do_br(e[1]) elif type(e) is int: self.do_block(align=e) elif hasattr(e,'align'): self.do_align(e) else: self.do_item(e) self.line() self.rect.h = max(self.y,self.left_bottom,self.right_bottom) def init(self): self.x,self.y = self.rect.x,self.rect.y self.left = self.rect.left self.right = self.rect.right self.left_bottom = 0 self.right_bottom = 0 self.y = self.rect.y self.x = self.rect.x self.h = 0 self.items = [] self.align = -1 def getleft(self): if self.y > self.left_bottom: self.left = self.rect.left return self.left def getright(self): if self.y > self.right_bottom: self.right = self.rect.right return self.right def do_br(self,h): self.line() self.h = h def do_block(self,align=-1): self.line() self.align = align def do_align(self,e): align = e.align ox,oy,oh = self.x,self.y,self.h w,h = e.rect.w,e.rect.h if align == 0: self.line() self.x = self.rect.left + (self.rect.width-w)/2 self.fit = 0 elif align == -1: self.line() self.y = max(self.left_bottom,self.y + self.h) self.h = 0 self.x = self.rect.left elif align == 1: self.line() self.y = max(self.right_bottom,self.y + self.h) self.h = 0 self.x = self.rect.left + (self.rect.width-w) e.rect.x,e.rect.y = self.x,self.y self.x = self.x + w self.y = self.y if align == 0: self.h = max(self.h,h) self.y = self.y + self.h self.x = self.getleft() self.h = 0 elif align == -1: self.left = self.x self.left_bottom = self.y + h self.x,self.y,self.h = ox + w,oy,oh elif align == 1: self.right = self.x - w self.right_bottom = self.y + h self.x,self.y,self.h = ox,oy,oh self.widgets.append(e) def do_space(self,e): w,h = e if self.x+w >= self.getright(): self.line() else: self.items.append(e) self.h = max(self.h,h) self.x += w def do_item(self,e): w,h = e.rect.w,e.rect.h if self.x+w >= self.getright(): self.line() self.items.append(e) self.h = max(self.h,h) self.x += w def line(self): x1 = self.getleft() x2 = self.getright() align = self.align y = self.y if len(self.items) != 0 and type(self.items[-1]) == tuple: del self.items[-1] w = 0 for e in self.items: if type(e) == tuple: w += e[0] else: w += e.rect.w if align == -1: x = x1 elif align == 0: x = x1 + ((x2-x1)-w)/2 self.fit = 0 elif align == 1: x = x2 - w for e in self.items: if type(e) == tuple: x += e[0] else: e.rect.x,e.rect.y = x,y self.widgets.append(e) x += e.rect.w self.items = [] self.y = self.y + self.h self.x = self.getleft() self.h = 0 # vim: set filetype=python sts=4 sw=4 noet si : python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/surface.py0000644000000000000000000001202311130023047021475 0ustar rootroot""" """ import pygame def subsurface(s,r): """Return the subsurface of a surface, with some help, checks.
subsurface(s,r): return surface
""" r = pygame.Rect(r) if r.x < 0 or r.y < 0: raise "gui.subsurface: %d %d %s"%(s.get_width(),s.get_height(),r) w,h = s.get_width(),s.get_height() if r.right > w: r.w -= r.right-w if r.bottom > h: r.h -= r.bottom-h return s.subsurface(r) class ProxySurface: """ A surface-like object which smartly handle out-of-area blitting.
ProxySurface(parent, rect, real_surface=None, offset=(0, 0))

only one of parent and real_surface should be supplied (non None)

parent
a ProxySurface object
real_surface
a pygame Surface object
Variables
mysubsurface
a real and valid pygame.Surface object to be used for blitting.
x, y
if the proxy surface is lefter or higher than the parent, x, y hold the diffs.
offset
an optional feature which let you scroll the whole blitted content.
""" def __init__(self, parent, rect, real_surface, offset=(0, 0)): self.offset = offset self.x = self.y = 0 if rect[0] < 0: self.x = rect[0] if rect[1] < 0: self.y = rect[1] self.real_surface = real_surface if real_surface == None: self.mysubsurface = parent.mysubsurface.subsurface(parent.mysubsurface.get_rect().clip(rect)) else: self.mysubsurface = real_surface.subsurface(real_surface.get_rect().clip(rect)) rect[0], rect[1] = 0, 0 self.rect = rect def blit(self, s, pos, rect=None): if rect == None: rect = s.get_rect() pos = (pos[0] + self.offset[0] + self.x, pos[1] + self.offset[1] + self.y) self.mysubsurface.blit(s, pos, rect) def subsurface(self, rect): return ProxySurface(self, pygame.Rect(rect).move(self.offset[0] + self.x, self.offset[1] + self.y),self.real_surface) def fill(self, color, rect=None): if rect != None: self.mysubsurface.fill(color, rect) else: self.mysubsurface.fill(color) def get_rect(self): return self.rect def get_width(self): return self.rect[2] def get_height(self): return self.rect[3] def get_abs_offset(): return self.rect[:2] def get_abs_parent(): return self.mysubsurface.get_abs_parent() def set_clip(self, rect=None): if rect == None: self.mysubsurface.set_clip() else: rect = [rect[0] + self.offset[0] + self.x, rect[1] + self.offset[0] + self.y, rect[2], rect[3]] self.mysubsurface.set_clip(rect) class xProxySurface: """ A surface-like object which smartly handle out-of-area blitting.
ProxySurface(parent, rect, real_surface=None, offset=(0, 0))

only one of parent and real_surface should be supplied (non None)

parent
a ProxySurface object
real_surface
a pygame Surface object
Variables
mysubsurface
a real and valid pygame.Surface object to be used for blitting.
x, y
if the proxy surface is lefter or higher than the parent, x, y hold the diffs.
offset
an optional feature which let you scroll the whole blitted content.
""" def __init__(self, parent, rect, real_surface, offset=(0, 0)): self.offset = offset self.x = self.y = 0 if rect[0] < 0: self.x = rect[0] if rect[1] < 0: self.y = rect[1] self.real_surface = real_surface if real_surface == None: self.mysubsurface = parent.mysubsurface.subsurface(parent.mysubsurface.get_rect().clip(rect)) else: self.mysubsurface = real_surface.subsurface(real_surface.get_rect().clip(rect)) rect[0], rect[1] = 0, 0 self.rect = rect def blit(self, s, pos, rect=None): if rect == None: rect = s.get_rect() pos = (pos[0] + self.offset[0] + self.x, pos[1] + self.offset[1] + self.y) self.mysubsurface.blit(s, pos, rect) def subsurface(self, rect): return ProxySurface(self, pygame.Rect(rect).move(self.offset[0] + self.x, self.offset[1] + self.y),self.real_surface) def fill(self, color, rect=None): if rect != None: self.mysubsurface.fill(color, rect) else: self.mysubsurface.fill(color) def get_rect(self): return self.rect def get_width(self): return self.rect[2] def get_height(self): return self.rect[3] def get_abs_offset(): return self.rect[:2] def get_abs_parent(): return self.mysubsurface.get_abs_parent() def set_clip(self, rect=None): if rect == None: self.mysubsurface.set_clip() else: rect = [rect[0] + self.offset[0] + self.x, rect[1] + self.offset[0] + self.y, rect[2], rect[3]] self.mysubsurface.set_clip(rect) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/theme.py0000644000000000000000000003743211130023047021162 0ustar rootroot""" """ import os, re import pygame from const import * import surface def _list_themes(dir): d = {} for entry in os.listdir(dir): if os.path.exists(os.path.join(dir, entry, 'config.txt')): d[entry] = os.path.join(dir, entry) return d class Theme: """Theme interface.

If you wish to create your own theme, create a class with this interface, and pass it to gui.App via gui.App(theme=MyTheme()).

Default Theme
Theme(dirs='default')
dirs
Name of the theme dir to load a theme from. May be an absolute path to a theme, if pgu is not installed, or if you created your own theme. May include several dirs in a list if data is spread across several themes.
Example theme = gui.Theme("default") theme = gui.Theme(["mytheme","mytheme2"]) """ def __init__(self,dirs='default'): self.config = {} self.dict = {} self._loaded = [] self.cache = {} self._preload(dirs) pygame.font.init() def _preload(self,ds): if not isinstance(ds, list): ds = [ds] for d in ds: if d not in self._loaded: self._load(d) self._loaded.append(d) def _load(self, name): #theme_dir = themes[name] #try to load the local dir, or absolute path dnames = [name] #if the package isn't installed and people are just #trying out the scripts or examples dnames.append(os.path.join(os.path.dirname(__file__),"..","..","data","themes",name)) #if the package is installed, and the package is installed #in /usr/lib/python2.3/site-packages/pgu/ #or c:\python23\lib\site-packages\pgu\ #the data is in ... lib/../share/ ... dnames.append(os.path.join(os.path.dirname(__file__),"..","..","..","..","share","pgu","themes",name)) dnames.append(os.path.join(os.path.dirname(__file__),"..","..","..","..","..","share","pgu","themes",name)) for dname in dnames: if os.path.isdir(dname): break if not os.path.isdir(dname): raise 'could not find theme '+name fname = os.path.join(dname,"config.txt") if os.path.isfile(fname): try: f = open(fname) for line in f.readlines(): vals = line.strip().split() if len(vals) < 3: continue cls = vals[0] del vals[0] pcls = "" if cls.find(":")>=0: cls,pcls = cls.split(":") attr = vals[0] del vals[0] self.config[cls+":"+pcls+" "+attr] = (dname, vals) finally: f.close() fname = os.path.join(dname,"style.ini") if os.path.isfile(fname): import ConfigParser cfg = ConfigParser.ConfigParser() f = open(fname,'r') cfg.readfp(f) for section in cfg.sections(): cls = section pcls = '' if cls.find(":")>=0: cls,pcls = cls.split(":") for attr in cfg.options(section): vals = cfg.get(section,attr).strip().split() self.config[cls+':'+pcls+' '+attr] = (dname,vals) is_image = re.compile('\.(gif|jpg|bmp|png|tga)$', re.I) def _get(self,key): if not key in self.config: return if key in self.dict: return self.dict[key] dvals = self.config[key] dname, vals = dvals #theme_dir = themes[name] v0 = vals[0] if v0[0] == '#': v = pygame.color.Color(v0) elif v0.endswith(".ttf") or v0.endswith(".TTF"): v = pygame.font.Font(os.path.join(dname, v0),int(vals[1])) elif self.is_image.search(v0) is not None: v = pygame.image.load(os.path.join(dname, v0)) else: try: v = int(v0) except: v = pygame.font.SysFont(v0, int(vals[1])) self.dict[key] = v return v def get(self,cls,pcls,attr): """Interface method -- get the value of a style attribute.
Theme.get(cls,pcls,attr): return value
cls
class, for example "checkbox", "button", etc.
pcls
pseudo class, for example "hover", "down", etc.
attr
attribute, for example "image", "background", "font", "color", etc.

returns the value of the attribute.

This method is called from [[gui-style]].

""" if not self._loaded: self._preload("default") o = cls+":"+pcls+" "+attr #if not hasattr(self,'_count'): # self._count = {} #if o not in self._count: self._count[o] = 0 #self._count[o] += 1 if o in self.cache: return self.cache[o] v = self._get(cls+":"+pcls+" "+attr) if v: self.cache[o] = v return v pcls = "" v = self._get(cls+":"+pcls+" "+attr) if v: self.cache[o] = v return v cls = "default" v = self._get(cls+":"+pcls+" "+attr) if v: self.cache[o] = v return v v = 0 self.cache[o] = v return v def box(self,w,s): style = w.style c = (0,0,0) if style.border_color != 0: c = style.border_color w,h = s.get_width(),s.get_height() s.fill(c,(0,0,w,style.border_top)) s.fill(c,(0,h-style.border_bottom,w,style.border_bottom)) s.fill(c,(0,0,style.border_left,h)) s.fill(c,(w-style.border_right,0,style.border_right,h)) def getspacing(self,w): # return the top, right, bottom, left spacing around the widget if not hasattr(w,'_spacing'): #HACK: assume spacing doesn't change re pcls s = w.style xt = s.margin_top+s.border_top+s.padding_top xr = s.padding_right+s.border_right+s.margin_right xb = s.padding_bottom+s.border_bottom+s.margin_bottom xl = s.margin_left+s.border_left+s.padding_left w._spacing = xt,xr,xb,xl return w._spacing def resize(self,w,m): def func(width=None,height=None): #ww,hh = m(width,height) ow,oh = width,height s = w.style pt,pr,pb,pl = s.padding_top,s.padding_right,s.padding_bottom,s.padding_left bt,br,bb,bl = s.border_top,s.border_right,s.border_bottom,s.border_left mt,mr,mb,ml = s.margin_top,s.margin_right,s.margin_bottom,s.margin_left xt = pt+bt+mt xr = pr+br+mr xb = pb+bb+mb xl = pl+bl+ml ttw = xl+xr tth = xt+xb ww,hh = None,None if width != None: ww = width-ttw if height != None: hh = height-tth ww,hh = m(ww,hh) rect = pygame.Rect(0 + xl, 0 + xt, ww, hh) w._rect_content = rect #pygame.Rect(0 + xl, 0 + xt, width, height) #r = rect if width == None: width = ww if height == None: height = hh #if the widget hasn't respected the style.width, #style height, we'll add in the space for it... width = max(width-ttw,ww,w.style.width) height = max(height-tth,hh,w.style.height) #width = max(ww,w.style.width-tw) #height = max(hh,w.style.height-th) r = pygame.Rect(rect.x,rect.y,width,height) w._rect_padding = pygame.Rect(r.x-pl,r.y-pt,r.w+pl+pr,r.h+pt+pb) r = w._rect_padding w._rect_border = pygame.Rect(r.x-bl,r.y-bt,r.w+bl+br,r.h+bt+bb) r = w._rect_border w._rect_margin = pygame.Rect(r.x-ml,r.y-mt,r.w+ml+mr,r.h+mt+mb) #align it within it's zone of power. dx = width-rect.w dy = height-rect.h #rect.x += (1)*dx/2 #rect.y += (1)*dy/2 rect.x += (w.style.align+1)*dx/2 rect.y += (w.style.valign+1)*dy/2 #print w,ow, w._rect_margin.w, ttw return w._rect_margin.w,w._rect_margin.h return func def paint(self,w,m): def func(s): # if w.disabled: # if not hasattr(w,'_disabled_bkgr'): # w._disabled_bkgr = s.convert() # orig = s # s = w._disabled_bkgr.convert() # if not hasattr(w,'_theme_paint_bkgr'): # w._theme_paint_bkgr = s.convert() # else: # s.blit(w._theme_paint_bkgr,(0,0)) # # if w.disabled: # orig = s # s = w._theme_paint_bkgr.convert() if w.disabled: if not (hasattr(w,'_theme_bkgr') and w._theme_bkgr.get_width() == s.get_width() and w._theme_bkgr.get_height() == s.get_height()): w._theme_bkgr = s.copy() orig = s s = w._theme_bkgr s.fill((0,0,0,0)) s.blit(orig,(0,0)) if hasattr(w,'background'): w.background.paint(surface.subsurface(s,w._rect_border)) self.box(w,surface.subsurface(s,w._rect_border)) r = m(surface.subsurface(s,w._rect_content)) if w.disabled: s.set_alpha(128) orig.blit(s,(0,0)) # if w.disabled: # orig.blit(w._disabled_bkgr,(0,0)) # s.set_alpha(128) # orig.blit(s,(0,0)) w._painted = True return r return func def event(self,w,m): def func(e): rect = w._rect_content if e.type == MOUSEBUTTONUP or e.type == MOUSEBUTTONDOWN: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y)}) elif e.type == CLICK: sub = pygame.event.Event(e.type,{ 'button':e.button, 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y)}) elif e.type == MOUSEMOTION: sub = pygame.event.Event(e.type,{ 'buttons':e.buttons, 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y), 'rel':e.rel}) else: sub = e r = m(sub) return r return func def update(self,w,m): def func(s): if w.disabled: return [] r = m(surface.subsurface(s,w._rect_content)) if type(r) == list: dx,dy = w._rect_content.topleft for rr in r: rr.x,rr.y = rr.x+dx,rr.y+dy return r return func def open(self,w,m): def func(widget=None,x=None,y=None): if not hasattr(w,'_rect_content'): w.rect.w,w.rect.h = w.resize() #HACK: so that container.open won't resize again! rect = w._rect_content ##print w.__class__.__name__, rect if x != None: x += rect.x if y != None: y += rect.y return m(widget,x,y) return func #def open(self,w,m): # def func(widget=None): # return m(widget) # return func def decorate(self,widget,level): """Interface method -- decorate a widget.

The theme system is given the opportunity to decorate a widget methods at the end of the Widget initializer.

Theme.decorate(widget,level)
widget
the widget to be decorated
level
the amount of decoration to do, False for none, True for normal amount, 'app' for special treatment of App objects.
""" w = widget if level == False: return if type(w.style.background) != int: w.background = Background(w,self) if level == 'app': return for k,v in w.style.__dict__.items(): if k in ('border','margin','padding'): for kk in ('top','bottom','left','right'): setattr(w.style,'%s_%s'%(k,kk),v) w.paint = self.paint(w,w.paint) w.event = self.event(w,w.event) w.update = self.update(w,w.update) w.resize = self.resize(w,w.resize) w.open = self.open(w,w.open) def render(self,s,box,r): """Interface method - render a special widget feature.
Theme.render(s,box,r)
s
pygame.Surface
box
box data, a value returned from Theme.get, typically a pygame.Surface
r
pygame.Rect with the size that the box data should be rendered
""" if box == 0: return if not isinstance(box,pygame.Surface): s.fill(box,r) return x,y,w,h=r.x,r.y,r.w,r.h ww,hh=box.get_width()/3,box.get_height()/3 xx,yy=x+w,y+h src = pygame.rect.Rect(0,0,ww,hh) dest = pygame.rect.Rect(0,0,ww,hh) s.set_clip(pygame.Rect(x+ww,y+hh,w-ww*2,h-hh*2)) src.x,src.y = ww,hh for dest.y in xrange(y+hh,yy-hh,hh): for dest.x in xrange(x+ww,xx-ww,ww): s.blit(box,dest,src) s.set_clip(pygame.Rect(x+ww,y,w-ww*3,hh)) src.x,src.y,dest.y = ww,0,y for dest.x in xrange(x+ww,xx-ww*2,ww): s.blit(box,dest,src) dest.x = xx-ww*2 s.set_clip(pygame.Rect(x+ww,y,w-ww*2,hh)) s.blit(box,dest,src) s.set_clip(pygame.Rect(x+ww,yy-hh,w-ww*3,hh)) src.x,src.y,dest.y = ww,hh*2,yy-hh for dest.x in xrange(x+ww,xx-ww*2,ww): s.blit(box,dest,src) dest.x = xx-ww*2 s.set_clip(pygame.Rect(x+ww,yy-hh,w-ww*2,hh)) s.blit(box,dest,src) s.set_clip(pygame.Rect(x,y+hh,xx,h-hh*3)) src.y,src.x,dest.x = hh,0,x for dest.y in xrange(y+hh,yy-hh*2,hh): s.blit(box,dest,src) dest.y = yy-hh*2 s.set_clip(pygame.Rect(x,y+hh,xx,h-hh*2)) s.blit(box,dest,src) s.set_clip(pygame.Rect(xx-ww,y+hh,xx,h-hh*3)) src.y,src.x,dest.x=hh,ww*2,xx-ww for dest.y in xrange(y+hh,yy-hh*2,hh): s.blit(box,dest,src) dest.y = yy-hh*2 s.set_clip(pygame.Rect(xx-ww,y+hh,xx,h-hh*2)) s.blit(box,dest,src) s.set_clip() src.x,src.y,dest.x,dest.y = 0,0,x,y s.blit(box,dest,src) src.x,src.y,dest.x,dest.y = ww*2,0,xx-ww,y s.blit(box,dest,src) src.x,src.y,dest.x,dest.y = 0,hh*2,x,yy-hh s.blit(box,dest,src) src.x,src.y,dest.x,dest.y = ww*2,hh*2,xx-ww,yy-hh s.blit(box,dest,src) import pygame import widget class Background(widget.Widget): def __init__(self,value,theme,**params): params['decorate'] = False widget.Widget.__init__(self,**params) self.value = value self.theme = theme def paint(self,s): r = pygame.Rect(0,0,s.get_width(),s.get_height()) v = self.value.style.background if not isinstance(v,pygame.Surface): s.fill(v) else: self.theme.render(s,v,r) python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/table.py0000644000000000000000000003074111130023047021143 0ustar rootroot""" """ from const import * import container class Table(container.Container): """A table style container.

If you know HTML, this should all work roughly how you would expect. If you are not familiar with HTML, please read Tables in HTML Documents. Pay attention to TABLE, TR, TD related parts of the document.

Table()
Example t = gui.Table() t.tr() t.td(gui.Label("First Name"), align=-1) t.td(gui.Input()) t.tr() t.td(gui.Label("Last Name"), align=-1) t.td(gui.Input()) """ def __init__(self, **params): params.setdefault('cls','table') container.Container.__init__(self, **params) self._rows = [] self._curRow = 0 self._trok = False def getRows(self): return len(self._rows) def getColumns(self): if self._rows: return len(self._rows[0]) else: return 0 def remove_row(self, n): #NOTE: won't work in all cases. if n >= self.getRows(): print "Trying to remove a nonexistant row:", n, "there are only", self.getRows(), "rows" return for cell in self._rows[n]: if isinstance(cell, dict) and cell["widget"] in self.widgets: #print 'removing widget' self.widgets.remove(cell["widget"]) del self._rows[n] #print "got here" for w in self.widgets: if w.style.row > n: w.style.row -= 1 if self._curRow >= n: self._curRow -= 1 #self.rect.w, self.rect.h = self.resize() #self.repaint() self.chsize() def clear(self): self._rows = [] self._curRow = 0 self._trok = False self.widgets = [] self.chsize() #print 'clear',self,self._rows def _addRow(self): self._rows.append([None for x in xrange(self.getColumns())]) def tr(self): """Start on the next row.""" if not self._trok: self._trok = True return self._curRow += 1 if self.getRows() <= self._curRow: self._addRow() def _addColumn(self): if not self._rows: self._addRow() for row in self._rows: row.append(None) def _setCell(self, w, col, row, colspan=1, rowspan=1): #make room for the widget by adding columns and rows while self.getColumns() < col + colspan: self._addColumn() while self.getRows() < row + rowspan: self._addRow() #print w.__class__.__name__,col,row,colspan,rowspan #actual widget setting and modification stuff w.container = self w.style.row = row #HACK - to work with gal's list w.style.col = col #HACK - to work with gal's list self._rows[row][col] = {"widget":w, "colspan":colspan, "rowspan":rowspan} self.widgets.append(self._rows[row][col]["widget"]) #set the spanned columns #for acell in xrange(col + 1, col + colspan): # self._rows[row][acell] = True #set the spanned rows and the columns on them #for arow in xrange(row + 1, row + rowspan): # for acell in xrange(col, col + colspan): #incorrect? # self._rows[arow][acell] = True for arow in xrange(row, row + rowspan): for acell in xrange(col, col + colspan): #incorrect? if row != arow or col != acell: self._rows[arow][acell] = True def td(self, w, col=None, row=None, colspan=1, rowspan=1, **params): """Add a widget to a table after wrapping it in a TD container.
Table.td(w,col=None,row=None,colspan=1,rowspan=1,**params)
w
widget
col
column
row
row
colspan
colspan
rowspan
rowspan
align
horizontal alignment (-1,0,1)
valign
vertical alignment (-1,0,1)
params
other params for the TD container, style information, etc
""" Table.add(self,_Table_td(w, **params), col=col, row=row, colspan=colspan, rowspan=rowspan) def add(self, w, col=None, row=None, colspan=1, rowspan=1): """Add a widget directly into the table, without wrapping it in a TD container.
Table.add(w,col=None,row=None,colspan=1,rowspan=1)

See Table.td for an explanation of the parameters.

""" self._trok = True #if no row was specifically specified, set it to the current row if row is None: row = self._curRow #print row #if its going to be a new row, have it be on the first column if row >= self.getRows(): col = 0 #try to find an open cell for the widget if col is None: for cell in xrange(self.getColumns()): if col is None and not self._rows[row][cell]: col = cell break #otherwise put the widget in a new column if col is None: col = self.getColumns() self._setCell(w, col, row, colspan=colspan, rowspan=rowspan) self.chsize() return def remove(self,w): if hasattr(w,'_table_td'): w = w._table_td row,col = w.style.row,w.style.col cell = self._rows[row][col] colspan,rowspan = cell['colspan'],cell['rowspan'] for arow in xrange(row , row + rowspan): for acell in xrange(col, col + colspan): #incorrect? self._rows[arow][acell] = False self.widgets.remove(w) self.chsize() def resize(self, width=None, height=None): #if 1 or self.getRows() == 82: #print '' #print 'resize',self.getRows(),self.getColumns(),width,height #import inspect #for obj,fname,line,fnc,code,n in inspect.stack()[9:20]: # print fname,line,':',fnc,code[0].strip() #resize the widgets to their smallest size for w in self.widgets: w.rect.w, w.rect.h = w.resize() #calculate row heights and column widths rowsizes = [0 for y in xrange(self.getRows())] columnsizes = [0 for x in xrange(self.getColumns())] for row in xrange(self.getRows()): for cell in xrange(self.getColumns()): if self._rows[row][cell] and self._rows[row][cell] is not True: if not self._rows[row][cell]["colspan"] > 1: columnsizes[cell] = max(columnsizes[cell], self._rows[row][cell]["widget"].rect.w) if not self._rows[row][cell]["rowspan"] > 1: rowsizes[row] = max(rowsizes[row], self._rows[row][cell]["widget"].rect.h) #distribute extra space if necessary for wide colspanning/rowspanning for row in xrange(self.getRows()): for cell in xrange(self.getColumns()): if self._rows[row][cell] and self._rows[row][cell] is not True: if self._rows[row][cell]["colspan"] > 1: columns = xrange(cell, cell + self._rows[row][cell]["colspan"]) totalwidth = 0 for acol in columns: totalwidth += columnsizes[acol] if totalwidth < self._rows[row][cell]["widget"].rect.w: for acol in columns: columnsizes[acol] += _table_div(self._rows[row][cell]["widget"].rect.w - totalwidth, self._rows[row][cell]["colspan"],acol) if self._rows[row][cell]["rowspan"] > 1: rows = xrange(row, row + self._rows[row][cell]["rowspan"]) totalheight = 0 for arow in rows: totalheight += rowsizes[arow] if totalheight < self._rows[row][cell]["widget"].rect.h: for arow in rows: rowsizes[arow] += _table_div(self._rows[row][cell]["widget"].rect.h - totalheight, self._rows[row][cell]["rowspan"],arow) #make everything fill out to self.style.width, self.style.heigh, not exact, but pretty close... w, h = sum(columnsizes), sum(rowsizes) if w > 0 and w < self.style.width and len(columnsizes): d = (self.style.width - w) for n in xrange(0, len(columnsizes)): v = columnsizes[n] columnsizes[n] += v * d / w if h > 0 and h < self.style.height and len(rowsizes): d = (self.style.height - h) / len(rowsizes) for n in xrange(0, len(rowsizes)): v = rowsizes[n] rowsizes[n] += v * d / h #set the widget's position by calculating their row/column x/y offset cellpositions = [[[sum(columnsizes[0:cell]), sum(rowsizes[0:row])] for cell in xrange(self.getColumns())] for row in xrange(self.getRows())] for row in xrange(self.getRows()): for cell in xrange(self.getColumns()): if self._rows[row][cell] and self._rows[row][cell] is not True: x, y = cellpositions[row][cell] w = sum(columnsizes[cell:cell+self._rows[row][cell]["colspan"]]) h = sum(rowsizes[row:row+self._rows[row][cell]["rowspan"]]) widget = self._rows[row][cell]["widget"] widget.rect.x = x widget.rect.y = y if 1 and (w,h) != (widget.rect.w,widget.rect.h): # if h > 20: # print widget.widget.__class__.__name__, (widget.rect.w,widget.rect.h),'=>',(w,h) widget.rect.w, widget.rect.h = widget.resize(w, h) #print self._rows[row][cell]["widget"].rect #print columnsizes #print sum(columnsizes) #size = sum(columnsizes), sum(rowsizes); print size #return the tables final size return sum(columnsizes),sum(rowsizes) def _table_div(a,b,c): v,r = a/b, a%b if r != 0 and (c%b) self.style.width) or (self.style.height!=0 and w.rect.h > self.style.height): # ww,hh = None,None # if self.style.width: ww = self.style.width # if self.style.height: hh = self.style.height # w.rect.w,w.rect.h = w.resize(ww,hh) #in the case that the widget is too big, we try to resize it if (width != None and width < w.rect.w) or (height != None and height < w.rect.h): w.rect.w,w.rect.h = w.resize(width,height) width = max(width,w.rect.w,self.style.width) #,self.style.cell_width) height = max(height,w.rect.h,self.style.height) #,self.style.cell_height) dx = width-w.rect.w dy = height-w.rect.h w.rect.x = (self.style.align+1)*dx/2 w.rect.y = (self.style.valign+1)*dy/2 return width,height python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/deprecated.py0000644000000000000000000000444711130023047022160 0ustar rootrootimport pygame from const import * import table import group import button, basic def action_open(value): print 'gui.action_open',"Scheduled to be deprecated." value.setdefault('x',None) value.setdefault('y',None) value['container'].open(value['window'],value['x'],value['y']) def action_setvalue(value): print 'gui.action_setvalue',"Scheduled to be deprecated." a,b = value b.value = a.value def action_quit(value): print 'gui.action_quit',"Scheduled to be deprecated." value.quit() def action_exec(value): print 'gui.action_exec',"Scheduled to be deprecated." exec(value['script'],globals(),value['dict']) class Toolbox(table.Table): def __setattr__(self,k,v): _v = self.__dict__.get(k,NOATTR) self.__dict__[k]=v if k == 'value' and _v != NOATTR and _v != v: self.group.value = v for w in self.group.widgets: if w.value != v: w.pcls = "" else: w.pcls = "down" self.repaint() def _change(self,value): self.value = self.group.value self.send(CHANGE) def __init__(self,data,cols=0,rows=0,tool_cls='tool',value=None,**params): print 'gui.Toolbox','Scheduled to be deprecated.' params.setdefault('cls','toolbox') table.Table.__init__(self,**params) if cols == 0 and rows == 0: cols = len(data) if cols != 0 and rows != 0: rows = 0 self.tools = {} _value = value g = group.Group() self.group = g g.connect(CHANGE,self._change,None) self.group.value = _value x,y,p,s = 0,0,None,1 for ico,value in data: #from __init__ import theme import app img = app.App.app.theme.get(tool_cls+"."+ico,"","image") if img: i = basic.Image(img) else: i = basic.Label(ico,cls=tool_cls+".label") p = button.Tool(g,i,value,cls=tool_cls) self.tools[ico] = p #p.style.hexpand = 1 #p.style.vexpand = 1 self.add(p,x,y) s = 0 if cols != 0: x += 1 if cols != 0 and x == cols: x,y = 0,y+1 if rows != 0: y += 1 if rows != 0 and y == rows: x,y = x+1,0 python-box2d-2.0.2+svn20100109.244/testbed/pgu/gui/__init__.py0000644000000000000000000000150511130023047021607 0ustar rootrootimport pygame from pygame.locals import * from theme import Theme from style import Style from widget import Widget from surface import subsurface, ProxySurface from const import * from container import Container from app import App, Desktop from table import Table from document import Document #html from area import SlideBox, ScrollArea, List from form import Form from group import Group from basic import Spacer, Color, Label, Image from button import Icon, Button, Switch, Checkbox, Radio, Tool, Link from input import Input, Password from keysym import Keysym from slider import VSlider, HSlider, VScrollBar, HScrollBar from select import Select from misc import ProgressBar from menus import Menus from dialog import Dialog, FileDialog from deprecated import Toolbox, action_open, action_setvalue, action_quit, action_execpython-box2d-2.0.2+svn20100109.244/testbed/pgu/__init__.py0000644000000000000000000000015111130023047021017 0ustar rootroot"""Phil's pyGame Utilities """ __version__ = '0.10.6' # vim: set filetype=python sts=4 sw=4 noet si : python-box2d-2.0.2+svn20100109.244/testbed/test_Dominos.py0000644000000000000000000001241611135471136021156 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Dominos (Framework): name="Dominos" def __init__(self): super(Dominos, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) b1 = self.world.CreateBody(bd) b1.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(6.0, 0.25) bd=box2d.b2BodyDef() bd.position = (-1.5, 10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.1, 1.0) sd.density = 20.0 sd.friction = 0.1 for i in range(10): bd=box2d.b2BodyDef() bd.position = (-6.0 + 1.0 * i, 11.25) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() sd=box2d.b2PolygonDef() sd.SetAsBox(7.0, 0.25, (0,0), 0.3) bd=box2d.b2BodyDef() bd.position = (1.0, 6.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.25, 1.5) bd=box2d.b2BodyDef() bd.position = (-7.0, 4.0) b2 = self.world.CreateBody(bd) b2.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(6.0, 0.125) sd.density = 10.0 bd=box2d.b2BodyDef() bd.position = (-0.9, 1.0) bd.angle = -0.15 b3 = self.world.CreateBody(bd) b3.CreateShape(sd) b3.SetMassFromShapes() jd=box2d.b2RevoluteJointDef() anchor=(-2.0, 1.0) jd.Initialize(b1, b3, anchor) jd.collideConnected = True self.world.CreateJoint(jd).getAsType() sd=box2d.b2PolygonDef() sd.SetAsBox(0.25, 0.25) sd.density = 10.0 bd=box2d.b2BodyDef() bd.position = (-10.0, 15.0) b4 = self.world.CreateBody(bd) b4.CreateShape(sd) b4.SetMassFromShapes() anchor = (-7.0, 15.0) jd.Initialize(b2, b4, anchor) self.world.CreateJoint(jd).getAsType() bd=box2d.b2BodyDef() bd.position = (6.5, 3.0) b5 = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.density = 10.0 sd.friction = 0.1 sd.SetAsBox(1.0, 0.1, (0.0, -0.9), 0.0) b5.CreateShape(sd) sd.SetAsBox(0.1, 1.0, (-0.9, 0.0), 0.0) b5.CreateShape(sd) sd.SetAsBox(0.1, 1.0, (0.9, 0.0), 0.0) b5.CreateShape(sd) b5.SetMassFromShapes() anchor = (6.0, 2.0) jd.Initialize(b1, b5, anchor) self.world.CreateJoint(jd).getAsType() sd=box2d.b2PolygonDef() sd.SetAsBox(1.0, 0.1) sd.density = 30.0 sd.friction = 0.2 bd=box2d.b2BodyDef() bd.position = (6.5, 4.1) b6 = self.world.CreateBody(bd) b6.CreateShape(sd) b6.SetMassFromShapes() anchor = (7.5, 4.0) jd.Initialize(b5, b6, anchor) self.world.CreateJoint(jd).getAsType() sd=box2d.b2PolygonDef() sd.SetAsBox(0.1, 1.0) sd.density = 10.0 bd=box2d.b2BodyDef() bd.position = (7.4, 1.0) b7 = self.world.CreateBody(bd) b7.CreateShape(sd) b7.SetMassFromShapes() djd=box2d.b2DistanceJointDef() djd.body1 = b3 djd.body2 = b7 djd.localAnchor1 = (6.0, 0.0) djd.localAnchor2 = (0.0, -1.0) d = djd.body2.GetWorldPoint(djd.localAnchor2) - djd.body1.GetWorldPoint(djd.localAnchor1) djd.length = d.Length() self.world.CreateJoint(djd).getAsType() sd=box2d.b2CircleDef() sd.radius = 0.2 sd.density = 10.0 for i in range(4): bd=box2d.b2BodyDef() bd.position = (5.9 + 2.0 * sd.radius * i, 2.4) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() if __name__=="__main__": main(Dominos) python-box2d-2.0.2+svn20100109.244/testbed/test_empty.py0000644000000000000000000000577011136402204020700 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Empty(Framework): """You can use this class as an outline for your tests. """ name = "Empty" # Name of the class to display _pickle_vars=[] # variables to pickle (save/load). e.g., ['name', 'var1', 'var2'] def __init__(self): """ Initialize all of your objects here. Be sure to call the Framework's initializer first. """ super(Empty, self).__init__() # Initialize all of the objects def Keyboard(self, key): """ The key is from pygame.locals.K_* (e.g., if key == K_z: ... ) If you are using the pyglet backend, you should be able to use the same K_[a-z], see pyglet_keymapper.py """ pass def Step(self, settings): """Called upon every step. You should always call -> super(Your_Test_Class, self).Step(settings) at the beginning or end of your function. If placed at the beginning, it will cause the actual physics step to happen first. If placed at the end, it will cause the physics step to happen after your code. """ super(Empty, self).Step(settings) # do stuff # Placed after the physics step, it will draw on top of physics objects self.DrawStringCR("*** Base your own testbeds on me! ***") def ShapeDestroyed(self, shape): """ Callback indicating 'shape' has been destroyed. """ pass def JointDestroyed(self, joint): """ The joint passed in was removed. """ pass #def BoundaryViolated(self, body): # """ # The body went out of the world's extents. # """ # See pygame_main's implementation of BoundaryViolated for more information # about pickling and general stability. if __name__=="__main__": main(Empty) python-box2d-2.0.2+svn20100109.244/testbed/test_Biped.py0000644000000000000000000006040411135461416020571 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * global k_scale k_scale = 3.0 class Test_Biped(Framework): name = "Biped" biped = None _pickle_vars=[] def __init__(self): super(Test_Biped, self).__init__() k_restitution = 1.4 bd=box2d.b2BodyDef() bd.position = (0.0, 20.0) body = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.density = 0.0 sd.restitution = k_restitution sd.SetAsBox(0.1, 10.0, (-10.0, 0.0), 0.0) body.CreateShape(sd) sd.SetAsBox(0.1, 10.0, (10.0, 0.0), 0.0) body.CreateShape(sd) sd.SetAsBox(0.1, 10.0, (0.0, -10.0), 0.5 * box2d.b2_pi) body.CreateShape(sd) sd.SetAsBox(0.1, 10.0, (0.0, 10.0), -0.5 * box2d.b2_pi) body.CreateShape(sd) self.biped = Biped(self.world, box2d.b2Vec2(0.0, 20.0)) for i in range(8): bd=box2d.b2BodyDef() bd.position = (5.0, 20.0 + i) bd.isBullet = True body = self.world.CreateBody(bd) body.SetLinearVelocity(box2d.b2Vec2(0.0, -100.0)) body.SetAngularVelocity(box2d.b2Random(-50.0, 50.0)) sd=box2d.b2CircleDef() sd.radius = 0.25 sd.density = 15.0 sd.restitution = k_restitution body.CreateShape(sd) body.SetMassFromShapes() class Biped(object): world = None LFoot=None RFoot=None LCalf=None RCalf=None LThigh=None RThigh=None Pelvis=None Stomach=None Chest=None Neck=None Head=None LUpperArm=None RUpperArm=None LForearm=None RForearm=None LHand=None RHand=None LAnkle=None RAnkle=None LKnee=None RKnee=None LHip=None RHip=None LowerAbs=None UpperAbs=None LowerNeck=None UpperNeck=None LShoulder=None RShoulder=None LElbow=None RElbow=None LWrist=None RWrist=None def __init__(self, world, position): self.world = world bdef = BipedDef() bd=box2d.b2BodyDef() # create body parts bd = bdef.LFootDef bd.position += position self.LFoot = self.world.CreateBody(bd) self.LFoot.CreateShape(bdef.LFootPoly) self.LFoot.SetMassFromShapes() bd = bdef.RFootDef bd.position += position self.RFoot = self.world.CreateBody(bd) self.RFoot.CreateShape(bdef.RFootPoly) self.RFoot.SetMassFromShapes() bd = bdef.LCalfDef bd.position += position self.LCalf = self.world.CreateBody(bd) self.LCalf.CreateShape(bdef.LCalfPoly) self.LCalf.SetMassFromShapes() bd = bdef.RCalfDef bd.position += position self.RCalf = self.world.CreateBody(bd) self.RCalf.CreateShape(bdef.RCalfPoly) self.RCalf.SetMassFromShapes() bd = bdef.LThighDef bd.position += position self.LThigh = self.world.CreateBody(bd) self.LThigh.CreateShape(bdef.LThighPoly) self.LThigh.SetMassFromShapes() bd = bdef.RThighDef bd.position += position self.RThigh = self.world.CreateBody(bd) self.RThigh.CreateShape(bdef.RThighPoly) self.RThigh.SetMassFromShapes() bd = bdef.PelvisDef bd.position += position self.Pelvis = self.world.CreateBody(bd) self.Pelvis.CreateShape(bdef.PelvisPoly) self.Pelvis.SetMassFromShapes() bd = bdef.StomachDef bd.position += position self.Stomach = self.world.CreateBody(bd) self.Stomach.CreateShape(bdef.StomachPoly) self.Stomach.SetMassFromShapes() bd = bdef.ChestDef bd.position += position self.Chest = self.world.CreateBody(bd) self.Chest.CreateShape(bdef.ChestPoly) self.Chest.SetMassFromShapes() bd = bdef.NeckDef bd.position += position self.Neck = self.world.CreateBody(bd) self.Neck.CreateShape(bdef.NeckPoly) self.Neck.SetMassFromShapes() bd = bdef.HeadDef bd.position += position self.Head = self.world.CreateBody(bd) self.Head.CreateShape(bdef.HeadCirc) self.Head.SetMassFromShapes() bd = bdef.LUpperArmDef bd.position += position self.LUpperArm = self.world.CreateBody(bd) self.LUpperArm.CreateShape(bdef.LUpperArmPoly) self.LUpperArm.SetMassFromShapes() bd = bdef.RUpperArmDef bd.position += position self.RUpperArm = self.world.CreateBody(bd) self.RUpperArm.CreateShape(bdef.RUpperArmPoly) self.RUpperArm.SetMassFromShapes() bd = bdef.LForearmDef bd.position += position self.LForearm = self.world.CreateBody(bd) self.LForearm.CreateShape(bdef.LForearmPoly) self.LForearm.SetMassFromShapes() bd = bdef.RForearmDef bd.position += position self.RForearm = self.world.CreateBody(bd) self.RForearm.CreateShape(bdef.RForearmPoly) self.RForearm.SetMassFromShapes() bd = bdef.LHandDef bd.position += position self.LHand = self.world.CreateBody(bd) self.LHand.CreateShape(bdef.LHandPoly) self.LHand.SetMassFromShapes() bd = bdef.RHandDef bd.position += position self.RHand = self.world.CreateBody(bd) self.RHand.CreateShape(bdef.RHandPoly) self.RHand.SetMassFromShapes() # link body parts bdef.LAnkleDef.body1 = self.LFoot bdef.LAnkleDef.body2 = self.LCalf bdef.RAnkleDef.body1 = self.RFoot bdef.RAnkleDef.body2 = self.RCalf bdef.LKneeDef.body1 = self.LCalf bdef.LKneeDef.body2 = self.LThigh bdef.RKneeDef.body1 = self.RCalf bdef.RKneeDef.body2 = self.RThigh bdef.LHipDef.body1 = self.LThigh bdef.LHipDef.body2 = self.Pelvis bdef.RHipDef.body1 = self.RThigh bdef.RHipDef.body2 = self.Pelvis bdef.LowerAbsDef.body1 = self.Pelvis bdef.LowerAbsDef.body2 = self.Stomach bdef.UpperAbsDef.body1 = self.Stomach bdef.UpperAbsDef.body2 = self.Chest bdef.LowerNeckDef.body1 = self.Chest bdef.LowerNeckDef.body2 = self.Neck bdef.UpperNeckDef.body1 = self.Chest bdef.UpperNeckDef.body2 = self.Head bdef.LShoulderDef.body1 = self.Chest bdef.LShoulderDef.body2 = self.LUpperArm bdef.RShoulderDef.body1 = self.Chest bdef.RShoulderDef.body2 = self.RUpperArm bdef.LElbowDef.body1 = self.LForearm bdef.LElbowDef.body2 = self.LUpperArm bdef.RElbowDef.body1 = self.RForearm bdef.RElbowDef.body2 = self.RUpperArm bdef.LWristDef.body1 = self.LHand bdef.LWristDef.body2 = self.LForearm bdef.RWristDef.body1 = self.RHand bdef.RWristDef.body2 = self.RForearm # create joints self.LAnkle = self.world.CreateJoint(bdef.LAnkleDef).getAsType() self.RAnkle = self.world.CreateJoint(bdef.RAnkleDef).getAsType() self.LKnee = self.world.CreateJoint(bdef.LKneeDef).getAsType() self.RKnee = self.world.CreateJoint(bdef.RKneeDef).getAsType() self.LHip = self.world.CreateJoint(bdef.LHipDef).getAsType() self.RHip = self.world.CreateJoint(bdef.RHipDef).getAsType() self.LowerAbs = self.world.CreateJoint(bdef.LowerAbsDef).getAsType() self.UpperAbs = self.world.CreateJoint(bdef.UpperAbsDef).getAsType() self.LowerNeck = self.world.CreateJoint(bdef.LowerNeckDef).getAsType() self.UpperNeck = self.world.CreateJoint(bdef.UpperNeckDef).getAsType() self.LShoulder = self.world.CreateJoint(bdef.LShoulderDef).getAsType() self.RShoulder = self.world.CreateJoint(bdef.RShoulderDef).getAsType() self.LElbow = self.world.CreateJoint(bdef.LElbowDef).getAsType() self.RElbow = self.world.CreateJoint(bdef.RElbowDef).getAsType() self.LWrist = self.world.CreateJoint(bdef.LWristDef).getAsType() self.RWrist = self.world.CreateJoint(bdef.RWristDef).getAsType() class BipedDef(object): # BodyDefs LFootDef=box2d.b2BodyDef() RFootDef=box2d.b2BodyDef() LCalfDef=box2d.b2BodyDef() RCalfDef=box2d.b2BodyDef() LThighDef=box2d.b2BodyDef() RThighDef=box2d.b2BodyDef() PelvisDef=box2d.b2BodyDef() StomachDef=box2d.b2BodyDef() ChestDef=box2d.b2BodyDef() NeckDef=box2d.b2BodyDef() HeadDef=box2d.b2BodyDef() LUpperArmDef=box2d.b2BodyDef() RUpperArmDef=box2d.b2BodyDef() LForearmDef=box2d.b2BodyDef() RForearmDef=box2d.b2BodyDef() LHandDef=box2d.b2BodyDef() RHandDef=box2d.b2BodyDef() # Polygons LFootPoly=box2d.b2PolygonDef() RFootPoly=box2d.b2PolygonDef() LCalfPoly=box2d.b2PolygonDef() RCalfPoly=box2d.b2PolygonDef() LThighPoly=box2d.b2PolygonDef() RThighPoly=box2d.b2PolygonDef() PelvisPoly=box2d.b2PolygonDef() StomachPoly=box2d.b2PolygonDef() ChestPoly=box2d.b2PolygonDef() NeckPoly=box2d.b2PolygonDef() LUpperArmPoly=box2d.b2PolygonDef() RUpperArmPoly=box2d.b2PolygonDef() LForearmPoly=box2d.b2PolygonDef() RForearmPoly=box2d.b2PolygonDef() LHandPoly=box2d.b2PolygonDef() RHandPoly=box2d.b2PolygonDef() # Circles HeadCirc=box2d.b2CircleDef() # Revolute Joints LAnkleDef=box2d.b2RevoluteJointDef() RAnkleDef=box2d.b2RevoluteJointDef() LKneeDef=box2d.b2RevoluteJointDef() RKneeDef=box2d.b2RevoluteJointDef() LHipDef=box2d.b2RevoluteJointDef() RHipDef=box2d.b2RevoluteJointDef() LowerAbsDef=box2d.b2RevoluteJointDef() UpperAbsDef=box2d.b2RevoluteJointDef() LowerNeckDef=box2d.b2RevoluteJointDef() UpperNeckDef=box2d.b2RevoluteJointDef() LShoulderDef=box2d.b2RevoluteJointDef() RShoulderDef=box2d.b2RevoluteJointDef() LElbowDef=box2d.b2RevoluteJointDef() RElbowDef=box2d.b2RevoluteJointDef() LWristDef=box2d.b2RevoluteJointDef() RWristDef=box2d.b2RevoluteJointDef() count = 0 def __init__(self): # So much cleaner in Python than C++ :) self.iter_polys = ( self.LFootPoly, self.RFootPoly, self.LCalfPoly, self.RCalfPoly, self.LThighPoly, self.RThighPoly, self.PelvisPoly, self.StomachPoly, self.ChestPoly, self.NeckPoly, self.LUpperArmPoly, self.RUpperArmPoly, self.LForearmPoly, self.RForearmPoly, self.LHandPoly, self.RHandPoly , self.HeadCirc ) self.iter_defs = ( self.LFootDef, self.RFootDef, self.LCalfDef, self.RCalfDef, self.LThighDef, self.RThighDef, self.PelvisDef, self.StomachDef, self.ChestDef, self.NeckDef, self.HeadDef, self.LUpperArmDef, self.RUpperArmDef, self.LForearmDef, self.RForearmDef, self.LHandDef, self.RHandDef ) self.iter_joints=( self.LAnkleDef, self.RAnkleDef, self.LKneeDef, self.RKneeDef, self.LHipDef, self.RHipDef, self.LowerAbsDef, self.UpperAbsDef, self.LowerNeckDef, self.UpperNeckDef, self.LShoulderDef, self.RShoulderDef, self.LElbowDef, self.RElbowDef, self.LWristDef, self.RWristDef ) self.SetMotorTorque(2.0) self.SetMotorSpeed(0.0) self.SetDensity(20.0) self.SetRestitution(0.0) self.SetLinearDamping(0.0) self.SetAngularDamping(0.005) self.count -= 1 self.SetGroupIndex(self.count) self.EnableMotor() self.EnableLimit() self.DefaultVertices() self.DefaultPositions() self.DefaultJoints() self.LFootPoly.friction = self.RFootPoly.friction = 0.85 def IsFast(self, b): pass def SetGroupIndex(self, i): for o in self.iter_polys: o.filter.groupIndex = i def SetLinearDamping(self, f): for d in self.iter_defs: d.linearDamping = f def SetAngularDamping(self, f): for d in self.iter_defs: d.angularDamping = f def SetMotorTorque(self, f): for j in self.iter_joints: j.maxMotorTorque = f def SetMotorSpeed(self, f): for j in self.iter_joints: j.motorSpeed = f def SetDensity(self, f): for o in self.iter_polys: o.density = f def SetRestitution(self, f): for o in self.iter_polys: o.restitution = f def EnableLimit(self): self.SetLimit(True) def DisableLimit(self): self.SetLimit(False) def SetLimit(self, b): for j in self.iter_joints: j.enableLimit = b def EnableMotor(self): self.SetMotor(True) def DisableMotor(self): self.SetMotor(False) def SetMotor(self, b): for j in self.iter_joints: j.enableMotor = b def DefaultVertices(self): global k_scale # feet for poly in (self.LFootPoly, self.RFootPoly): poly.setVertices([ k_scale * box2d.b2Vec2(.033,.143), k_scale * box2d.b2Vec2(.023,.033), k_scale * box2d.b2Vec2(.267,.035), k_scale * box2d.b2Vec2(.265,.065), k_scale * box2d.b2Vec2(.117,.143)]) # calves for poly in (self.LCalfPoly, self.RCalfPoly): poly.setVertices([ k_scale * box2d.b2Vec2(.089,.016), k_scale * box2d.b2Vec2(.178,.016), k_scale * box2d.b2Vec2(.205,.417), k_scale * box2d.b2Vec2(.095,.417)]) # thighs for poly in (self.LThighPoly, self.RThighPoly): poly.setVertices([ k_scale * box2d.b2Vec2(.137,.032), k_scale * box2d.b2Vec2(.243,.032), k_scale * box2d.b2Vec2(.318,.343), k_scale * box2d.b2Vec2(.142,.343)]) # pelvis self.PelvisPoly.setVertices([ k_scale * box2d.b2Vec2(.105,.051), k_scale * box2d.b2Vec2(.277,.053), k_scale * box2d.b2Vec2(.320,.233), k_scale * box2d.b2Vec2(.112,.233), k_scale * box2d.b2Vec2(.067,.152)]) # stomach self.StomachPoly.setVertices([ k_scale * box2d.b2Vec2(.088,.043), k_scale * box2d.b2Vec2(.284,.043), k_scale * box2d.b2Vec2(.295,.231), k_scale * box2d.b2Vec2(.100,.231)]) # chest self.ChestPoly.setVertices([ k_scale * box2d.b2Vec2(.091,.042), k_scale * box2d.b2Vec2(.283,.042), k_scale * box2d.b2Vec2(.177,.289), k_scale * box2d.b2Vec2(.065,.289)]) # head self.HeadCirc.radius = k_scale * .115 # neck self.NeckPoly.setVertices([ k_scale * box2d.b2Vec2(.038,.054), k_scale * box2d.b2Vec2(.149,.054), k_scale * box2d.b2Vec2(.154,.102), k_scale * box2d.b2Vec2(.054,.113)]) # upper arms for poly in (self.LUpperArmPoly, self.RUpperArmPoly): poly.setVertices([ k_scale * box2d.b2Vec2(.092,.059), k_scale * box2d.b2Vec2(.159,.059), k_scale * box2d.b2Vec2(.169,.335), k_scale * box2d.b2Vec2(.078,.335), k_scale * box2d.b2Vec2(.064,.248)]) # forearms for poly in (self.LForearmPoly, self.RForearmPoly): poly.setVertices([ k_scale * box2d.b2Vec2(.082,.054), k_scale * box2d.b2Vec2(.138,.054), k_scale * box2d.b2Vec2(.149,.296), k_scale * box2d.b2Vec2(.088,.296)]) # hands for poly in (self.LHandPoly, self.RHandPoly): poly.setVertices([ k_scale * box2d.b2Vec2(.066,.031), k_scale * box2d.b2Vec2(.123,.020), k_scale * box2d.b2Vec2(.160,.127), k_scale * box2d.b2Vec2(.127,.178), k_scale * box2d.b2Vec2(.074,.178)]) def DefaultJoints(self): global k_scale #b.LAnkleDef.body1 = LFoot #b.LAnkleDef.body2 = LCalf #b.self.RAnkleDef.body1 = self.RFoot #b.self.RAnkleDef.body2 = self.RCalf # ankles anchor = k_scale * box2d.b2Vec2(-.045,-.75) self.LAnkleDef.localAnchor1 = self.RAnkleDef.localAnchor1 = anchor - self.LFootDef.position self.LAnkleDef.localAnchor2 = self.RAnkleDef.localAnchor2 = anchor - self.LCalfDef.position self.LAnkleDef.referenceAngle = self.RAnkleDef.referenceAngle = 0.0 self.LAnkleDef.lowerAngle = self.RAnkleDef.lowerAngle = -0.523598776 self.LAnkleDef.upperAngle = self.RAnkleDef.upperAngle = 0.523598776 #b.self.LKneeDef.body1 = self.LCalf #b.self.LKneeDef.body2 = self.LThigh #b.self.RKneeDef.body1 = self.RCalf #b.self.RKneeDef.body2 = self.RThigh # knees anchor = k_scale * box2d.b2Vec2(-.030,-.355) self.LKneeDef.localAnchor1 = self.RKneeDef.localAnchor1 = anchor - self.LCalfDef.position self.LKneeDef.localAnchor2 = self.RKneeDef.localAnchor2 = anchor - self.LThighDef.position self.LKneeDef.referenceAngle = self.RKneeDef.referenceAngle = 0.0 self.LKneeDef.lowerAngle = self.RKneeDef.lowerAngle = 0 self.LKneeDef.upperAngle = self.RKneeDef.upperAngle = 2.61799388 #b.self.LHipDef.body1 = self.LThigh #b.self.LHipDef.body2 = Pelvis #b.self.RHipDef.body1 = self.RThigh #b.self.RHipDef.body2 = Pelvis # hips anchor = k_scale * box2d.b2Vec2(.005,-.045) self.LHipDef.localAnchor1 = self.RHipDef.localAnchor1 = anchor - self.LThighDef.position self.LHipDef.localAnchor2 = self.RHipDef.localAnchor2 = anchor - self.PelvisDef.position self.LHipDef.referenceAngle = self.RHipDef.referenceAngle = 0.0 self.LHipDef.lowerAngle = self.RHipDef.lowerAngle = -2.26892803 self.LHipDef.upperAngle = self.RHipDef.upperAngle = 0 #b.self.LowerAbsDef.body1 = Pelvis #b.self.LowerAbsDef.body2 = Stomach # lower abs anchor = k_scale * box2d.b2Vec2(.035,.135) self.LowerAbsDef.localAnchor1 = anchor - self.PelvisDef.position self.LowerAbsDef.localAnchor2 = anchor - self.StomachDef.position self.LowerAbsDef.referenceAngle = 0.0 self.LowerAbsDef.lowerAngle = -0.523598776 self.LowerAbsDef.upperAngle = 0.523598776 #b.UpperAbsDef.body1 = Stomach #b.UpperAbsDef.body2 = Chest # upper abs anchor = k_scale * box2d.b2Vec2(.045,.320) self.UpperAbsDef.localAnchor1 = anchor - self.StomachDef.position self.UpperAbsDef.localAnchor2 = anchor - self.ChestDef.position self.UpperAbsDef.referenceAngle = 0.0 self.UpperAbsDef.lowerAngle = -0.523598776 self.UpperAbsDef.upperAngle = 0.174532925 #b.self.LowerNeckDef.body1 = Chest #b.self.LowerNeckDef.body2 = Neck # lower neck anchor = k_scale * box2d.b2Vec2(-.015,.575) self.LowerNeckDef.localAnchor1 = anchor - self.ChestDef.position self.LowerNeckDef.localAnchor2 = anchor - self.NeckDef.position self.LowerNeckDef.referenceAngle = 0.0 self.LowerNeckDef.lowerAngle = -0.174532925 self.LowerNeckDef.upperAngle = 0.174532925 #b.self.UpperNeckDef.body1 = Chest #b.self.UpperNeckDef.body2 = Head # upper neck anchor = k_scale * box2d.b2Vec2(-.005,.630) self.UpperNeckDef.localAnchor1 = anchor - self.ChestDef.position self.UpperNeckDef.localAnchor2 = anchor - self.HeadDef.position self.UpperNeckDef.referenceAngle = 0.0 self.UpperNeckDef.lowerAngle = -0.610865238 self.UpperNeckDef.upperAngle = 0.785398163 #b.self.LShoulderDef.body1 = Chest #b.self.LShoulderDef.body2 = self.LUpperArm #b.self.RShoulderDef.body1 = Chest #b.self.RShoulderDef.body2 = self.RUpperArm # shoulders anchor = k_scale * box2d.b2Vec2(-.015,.545) self.LShoulderDef.localAnchor1 = self.RShoulderDef.localAnchor1 = anchor - self.ChestDef.position self.LShoulderDef.localAnchor2 = self.RShoulderDef.localAnchor2 = anchor - self.LUpperArmDef.position self.LShoulderDef.referenceAngle = self.RShoulderDef.referenceAngle = 0.0 self.LShoulderDef.lowerAngle = self.RShoulderDef.lowerAngle = -1.04719755 self.LShoulderDef.upperAngle = self.RShoulderDef.upperAngle = 3.14159265 #b.self.LElbowDef.body1 = self.LForearm #b.self.LElbowDef.body2 = self.LUpperArm #b.self.RElbowDef.body1 = self.RForearm #b.self.RElbowDef.body2 = self.RUpperArm # elbows anchor = k_scale * box2d.b2Vec2(-.005,.290) self.LElbowDef.localAnchor1 = self.RElbowDef.localAnchor1 = anchor - self.LForearmDef.position self.LElbowDef.localAnchor2 = self.RElbowDef.localAnchor2 = anchor - self.LUpperArmDef.position self.LElbowDef.referenceAngle = self.RElbowDef.referenceAngle = 0.0 self.LElbowDef.lowerAngle = self.RElbowDef.lowerAngle = -2.7925268 self.LElbowDef.upperAngle = self.RElbowDef.upperAngle = 0 #b.self.LWristDef.body1 = self.LHand #b.self.LWristDef.body2 = self.LForearm #b.self.RWristDef.body1 = self.RHand #b.self.RWristDef.body2 = self.RForearm # wrists anchor = k_scale * box2d.b2Vec2(-.010,.045) self.LWristDef.localAnchor1 = self.RWristDef.localAnchor1 = anchor - self.LHandDef.position self.LWristDef.localAnchor2 = self.RWristDef.localAnchor2 = anchor - self.LForearmDef.position self.LWristDef.referenceAngle = self.RWristDef.referenceAngle = 0.0 self.LWristDef.lowerAngle = self.RWristDef.lowerAngle = -0.174532925 self.LWristDef.upperAngle = self.RWristDef.upperAngle = 0.174532925 def DefaultPositions(self): global k_scale for foot in (self.LFootDef, self.RFootDef): foot.position = k_scale * box2d.b2Vec2(-.122,-.901) for calf in (self.LCalfDef, self.RCalfDef): calf.position = k_scale * box2d.b2Vec2(-.177,-.771) for thigh in (self.LThighDef, self.RThighDef): thigh.position = k_scale * box2d.b2Vec2(-.217,-.391) for upperarm in (self.LUpperArmDef, self.RUpperArmDef): upperarm.position = k_scale * box2d.b2Vec2(-.127,.228) for forearm in (self.LForearmDef, self.RForearmDef): forearm.position = k_scale * box2d.b2Vec2(-.117,-.011) for hand in (self.LHandDef, self.RHandDef): hand.position = k_scale * box2d.b2Vec2(-.112,-.136) self.PelvisDef.position = k_scale * box2d.b2Vec2(-.177,-.101) self.StomachDef.position= k_scale * box2d.b2Vec2(-.142,.088) self.ChestDef.position = k_scale * box2d.b2Vec2(-.132,.282) self.NeckDef.position = k_scale * box2d.b2Vec2(-.102,.518) self.HeadDef.position = k_scale * box2d.b2Vec2(.022,.738) if __name__=="__main__": main(Test_Biped) python-box2d-2.0.2+svn20100109.244/testbed/test_Gears.py0000644000000000000000000001054211136402204020574 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Gears (Framework): name="Gears" joint1=None joint2=None joint3=None joint4=None joint5=None _pickle_vars = ['joint1', 'joint2', 'joint3', 'joint4', 'joint5'] def __init__(self): super(Gears, self).__init__() bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) ground.CreateShape(sd) circle1=box2d.b2CircleDef() circle1.radius = 1.0 circle1.density = 5.0 circle2=box2d.b2CircleDef() circle2.radius = 2.0 circle2.density = 5.0 box=box2d.b2PolygonDef() box.SetAsBox(0.5, 5.0) box.density = 5.0 bd1=box2d.b2BodyDef() bd1.position = (-3.0, 12.0) body1 = self.world.CreateBody(bd1) body1.CreateShape(circle1) body1.SetMassFromShapes() jd1=box2d.b2RevoluteJointDef() jd1.body1 = ground jd1.body2 = body1 jd1.localAnchor1 = ground.GetLocalPoint(bd1.position) jd1.localAnchor2 = body1.GetLocalPoint(bd1.position) jd1.referenceAngle = body1.GetAngle() - ground.GetAngle() self.joint1 = self.world.CreateJoint(jd1).getAsType() bd2=box2d.b2BodyDef() bd2.position = (0.0, 12.0) body2 = self.world.CreateBody(bd2) body2.CreateShape(circle2) body2.SetMassFromShapes() jd2=box2d.b2RevoluteJointDef() jd2.Initialize(ground, body2, bd2.position) self.joint2 = self.world.CreateJoint(jd2).getAsType() bd3=box2d.b2BodyDef() bd3.position = (2.5, 12.0) body3 = self.world.CreateBody(bd3) body3.CreateShape(box) body3.SetMassFromShapes() jd3=box2d.b2PrismaticJointDef() jd3.Initialize(ground, body3, bd3.position, (0.0, 1.0)) jd3.lowerTranslation = -5.0 jd3.upperTranslation = 5.0 jd3.enableLimit = True self.joint3 = self.world.CreateJoint(jd3).getAsType() jd4=box2d.b2GearJointDef() jd4.body1 = body1 jd4.body2 = body2 jd4.joint1 = self.joint1 jd4.joint2 = self.joint2 jd4.ratio = circle2.radius / circle1.radius self.joint4 = self.world.CreateJoint(jd4).getAsType() jd5=box2d.b2GearJointDef() jd5.body1 = body2 jd5.body2 = body3 jd5.joint1 = self.joint2 jd5.joint2 = self.joint3 jd5.ratio = -1.0 / circle2.radius self.joint5 = self.world.CreateJoint(jd5).getAsType() def Step(self, settings): if self.joint1 and self.joint2 and self.joint3 and self.joint4 and self.joint5: ratio = self.joint4.GetRatio() value = self.joint1.GetJointAngle() + ratio * self.joint2.GetJointAngle() self.DrawStringCR("theta1 + %.2f * theta2 = %.2f" % (ratio, value)) ratio = self.joint5.GetRatio() value = self.joint2.GetJointAngle() + ratio * self.joint3.GetJointTranslation() self.DrawStringCR("theta2 + %.2f * delta = %.2f" % (ratio, value)) super(Gears, self).Step(settings) if __name__=="__main__": main(Gears) python-box2d-2.0.2+svn20100109.244/testbed/test_ContactCallbackTest.py0000644000000000000000000001237211135461416023417 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * from test_main import fwContactTypes import math import pprint pp = pprint.PrettyPrinter(indent=4) # Contributed by caspin (C++ version) class ContactCallbackTest (Framework): name="ContactCallbackTest" ball=None bullet=None ball_shape=None _pickle_vars = ['ball', 'bullet', 'ball_shape'] def __init__(self): super(ContactCallbackTest, self).__init__() groundBody = self.world.GetGroundBody() sd=box2d.b2PolygonDef() sd.friction = 0 sd.vertices = [(10.0, 10.0), (9.0, 7.0), (10.0, 0.0)] sd.userData = 1 groundBody.CreateShape(sd) sd.vertices = [(9.0, 7.0), (8.0, 0.0), (10.0, 0.0)] sd.userData = 2 groundBody.CreateShape(sd) sd.vertices = [(9.0, 7.0), (8.0, 5.0), (8.0, 0.0)] sd.userData = 3 groundBody.CreateShape(sd) sd.vertices = [(8.0, 5.0), (7.0, 4.0), (8.0, 0.0)] sd.userData = 4 groundBody.CreateShape(sd) sd.vertices = [(7.0, 4.0), (5.0, 0.0), (8.0, 0.0)] sd.userData = 5 groundBody.CreateShape(sd) sd.vertices = [(7.0, 4.0), (5.0, 3.0), (5.0, 0.0)] sd.userData = 6 groundBody.CreateShape(sd) sd.vertices = [(5.0, 3.0), (2.0, 2.0), (5.0, 0.0)] sd.userData = 7 groundBody.CreateShape(sd) sd.vertices = [(2.0, 2.0), (0.0, 0.0), (5.0, 0.0)] sd.userData = 8 groundBody.CreateShape(sd) sd.vertices = [(2.0, 2.0), (-2.0, 2.0), (0.0, 0.0)] sd.userData = 9 groundBody.CreateShape(sd) sd.vertices = [(-5.0, 0.0), (0.0, 0.0), (-2.0, 2.0)] sd.userData = 10 groundBody.CreateShape(sd) sd.vertices = [(-5.0, 0.0), (-2.0, 2.0), (-5.0, 3.0)] sd.userData = 11 groundBody.CreateShape(sd) sd.vertices = [(-5.0, 0.0), (-5.0, 3.0), (-7.0, 4.0)] sd.userData = 12 groundBody.CreateShape(sd) sd.vertices = [(-8.0, 0.0), (-5.0, 0.0), (-7.0, 4.0)] sd.userData = 13 groundBody.CreateShape(sd) sd.vertices = [(-8.0, 0.0), (-7.0, 4.0), (-8.0, 5.0)] sd.userData = 14 groundBody.CreateShape(sd) sd.vertices = [(-8.0, 0.0), (-8.0, 5.0), (-9.0, 7.0)] sd.userData = 15 groundBody.CreateShape(sd) sd.vertices = [(-10.0, 0.0), (-8.0, 0.0), (-9.0, 7.0)] sd.userData = 16 groundBody.CreateShape(sd) sd.vertices = [(-10.0, 0.0), (-9.0, 7.0), (-10.0, 10.0)] sd.userData = 17 groundBody.CreateShape(sd) sd.SetAsBox(.5,6,(10.5,6),0) groundBody.CreateShape(sd) sd.SetAsBox(.5,6,(-10.5,6),0) groundBody.CreateShape(sd) bd=box2d.b2BodyDef() bd.position=(9.5,60) self.ball = self.world.CreateBody( bd ) cd=box2d.b2PolygonDef() cd.vertexCount = 8 w = 1.0 b = w / (2.0 + math.sqrt(2.0)) s = math.sqrt(2.0) * b cd.vertices = [( 0.5 * s, 0.0), ( 0.5 * w, b), ( 0.5 * w, b + s), ( 0.5 * s, w), (-0.5 * s, w), (-0.5 * w, b + s), (-0.5 * w, b), (-0.5 * s, 0.0) ] cd.density = 1.0 cd.userData = 'BALL' self.ball_shape = self.ball.CreateShape(cd) self.ball.SetMassFromShapes() def Step(self, settings): strings = [] name_dict = { fwContactTypes.contactAdded : "added", fwContactTypes.contactRemoved : "removed", fwContactTypes.contactPersisted : "persisted" } strings = ["%s: %s, %s (%s)" % (name_dict[point.state], point.shape1.userData, point.shape2.userData, point.id.key) for point in self.points] if len(strings) > 15: strings = strings[:14] for string in strings: self.DrawStringCR(string) super(ContactCallbackTest, self).Step(settings) if __name__=="__main__": main(ContactCallbackTest) python-box2d-2.0.2+svn20100109.244/testbed/console.py0000644000000000000000000002267311156662747020174 0ustar rootroot#!/usr/bin/env python # -*- coding: utf-8 -*- # # Interactive Python-GTK Console # Copyright ©, 1998 James Henstridge # Copyright ©, 2005 Adam Hooper # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # This module implements an interactive python session in a GTK window. To # start the session, use the gtk_console command. Its specification is: # gtk_console(namespace, title) # where namespace is a dictionary representing the namespace of the session, # title is the title on the window and # # As well as the starting attributes in namespace, the session will also # have access to the list __history__, which is the command history. import sys, string, traceback import gobject import gtk import pango import gtk.keysyms stdout = sys.stdout if not hasattr(sys, 'ps1'): sys.ps1 = '>>> ' if not hasattr(sys, 'ps2'): sys.ps2 = '... ' # some functions to help recognise breaks between commands def remQuotStr(s): '''Returns s with any quoted strings removed (leaving quote marks)''' r = '' inq = 0 qt = '' prev = '_' while len(s): s0, s = s[0], s[1:] if inq and (s0 != qt or prev == '\\'): prev = s0 continue prev = s0 if s0 in '\'"': if inq: inq = 0 else: inq = 1 qt = s0 r = r + s0 return r def bracketsBalanced(s): '''Returns true iff the brackets in s are balanced''' b = filter(lambda x: x in '([{', s) e = filter(lambda x: x in ')]}', s) return len(e) >= len(b) class gtkoutfile: '''A fake output file object. It sends output to a TK test widget, and if asked for a file number, returns one set on instance creation''' def __init__(self, w, fn, tag): self.__fn = fn self.__w = w self.__tag = tag def close(self): pass flush = close def fileno(self): return self.__fn def isatty(self): return 0 def read(self, a): return '' def readline(self): return '' def readlines(self): return [] def write(self, s): #stdout.write(str(self.__w.get_point()) + '\n') self.__w.text_insert(self.__tag, s) def writelines(self, l): self.__w.text_insert(self.__tag, l) def seek(self, a): raise IOError, (29, 'Illegal seek') def tell(self): raise IOError, (29, 'Illegal seek') truncate = tell class Console(gtk.VBox): def __init__(self, namespace={}, quit_cb=None): gtk.VBox.__init__(self, spacing=12) self.set_border_width(12) self.quit_cb = quit_cb self.inp = gtk.HBox() self.pack_start(self.inp) self.inp.show() self.sw = gtk.ScrolledWindow() self.sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC); self.sw.set_shadow_type(gtk.SHADOW_IN) self.inp.pack_start(self.sw, padding=1) self.sw.show() self.text = gtk.TextView() self.text.modify_font(pango.FontDescription('Monospace')) self.text.set_editable(False) self.text.set_wrap_mode (gtk.WRAP_WORD) self.sw.add(self.text) self.text.show() buffer = self.text.get_buffer() self.normal = buffer.create_tag("normal") self.error = buffer.create_tag("error") self.error.set_property("foreground", "red") self.command = buffer.create_tag('command') self.command.set_property("foreground", "blue") self.inputbox = gtk.HBox(spacing=2) self.pack_end(self.inputbox, expand=False) self.inputbox.show() self.prompt = gtk.Label(sys.ps1) self.prompt.set_padding(2, 0) self.prompt.modify_font(pango.FontDescription('Monospace 10')) self.inputbox.pack_start(self.prompt, expand=False) self.prompt.show() self.line = gtk.Entry() self.line.modify_font(pango.FontDescription('Monospace')) self.line.connect("key_press_event", self.key_function) self.inputbox.pack_start(self.line, padding=2) self.line.show() self.namespace = namespace self.cmd = '' self.cmd2 = '' # set up hooks for standard output. self.stdout = gtkoutfile(self, sys.stdout.fileno(), self.normal) try : # this will mostly fail on win32 ... self.stderr = gtkoutfile(self, sys.stderr.fileno(), self.error) except : # ... but gtkoutfile is not using the fileno anyway self.stderr = gtkoutfile(self, -1, self.error) # set up command history self.history = [''] self.histpos = 0 self.namespace['__history__'] = self.history def scroll_to_end (self): iter = self.text.get_buffer().get_end_iter() self.text.scroll_to_iter(iter, 0.0) return False # don't requeue this handler def text_insert(self, tag, s): buffer = self.text.get_buffer() iter = buffer.get_end_iter() buffer.insert_with_tags (iter, s, tag) gobject.idle_add(self.scroll_to_end) def init(self): self.text.realize() self.text.fg = self.text.style.fg[gtk.STATE_NORMAL] self.text.bg = self.text.style.white self.line.grab_focus() def quit(self, *args): #self.destroy() if self.quit_cb: self.quit_cb() def key_function(self, entry, event): if event.keyval == gtk.keysyms.Return: self.line.emit_stop_by_name("key_press_event") self.eval() elif event.keyval == gtk.keysyms.Tab: self.line.emit_stop_by_name("key_press_event") self.line.insert_text('\t') gobject.idle_add(self.focus_text) elif event.keyval in (gtk.keysyms.KP_Up, gtk.keysyms.Up) \ or (event.keyval in (gtk.keysyms.P, gtk.keysyms.p) and event.state & gtk.gdk.CONTROL_MASK): self.line.emit_stop_by_name("key_press_event") self.historyUp() gobject.idle_add(self.focus_text) elif event.keyval in (gtk.keysyms.KP_Down, gtk.keysyms.Down) \ or (event.keyval in (gtk.keysyms.N, gtk.keysyms.n) and event.state & gtk.gdk.CONTROL_MASK): self.line.emit_stop_by_name("key_press_event") self.historyDown() gobject.idle_add(self.focus_text) elif event.keyval in (gtk.keysyms.L, gtk.keysyms.l) and \ event.state & gtk.gdk.CONTROL_MASK: self.text.get_buffer().set_text('') elif event.keyval in (gtk.keysyms.D, gtk.keysyms.d) and \ event.state & gtk.gdk.CONTROL_MASK: self.line.emit_stop_by_name("key_press_event") self.ctrld() def focus_text(self): self.line.grab_focus() return False # don't requeue this handler def ctrld(self): self.quit() pass def historyUp(self): if self.histpos > 0: l = self.line.get_text() if len(l) > 0 and l[0] == '\n': l = l[1:] if len(l) > 0 and l[-1] == '\n': l = l[:-1] self.history[self.histpos] = l self.histpos = self.histpos - 1 self.line.set_text(self.history[self.histpos]) def historyDown(self): if self.histpos < len(self.history) - 1: l = self.line.get_text() if len(l) > 0 and l[0] == '\n': l = l[1:] if len(l) > 0 and l[-1] == '\n': l = l[:-1] self.history[self.histpos] = l self.histpos = self.histpos + 1 self.line.set_text(self.history[self.histpos]) def eval(self): l = self.line.get_text() + '\n' if len(l) > 1 and l[0] == '\n': l = l[1:] self.histpos = len(self.history) - 1 if len(l) > 0 and l[-1] == '\n': self.history[self.histpos] = l[:-1] else: self.history[self.histpos] = l self.line.set_text('') self.text_insert(self.command, self.prompt.get() + l) if l == '\n': self.run(self.cmd) self.cmd = '' self.cmd2 = '' return self.histpos = self.histpos + 1 self.history.append('') self.cmd = self.cmd + l self.cmd2 = self.cmd2 + remQuotStr(l) l = string.rstrip(l) if not bracketsBalanced(self.cmd2) or l[-1] == ':' or \ l[-1] == '\\' or l[0] in ' \11': self.prompt.set_text(sys.ps2) self.prompt.queue_draw() return self.run(self.cmd) self.cmd = '' self.cmd2 = '' def run(self, cmd): sys.stdout, self.stdout = self.stdout, sys.stdout sys.stderr, self.stderr = self.stderr, sys.stderr try: try: r = eval(cmd, self.namespace, self.namespace) if r is not None: print `r` except SyntaxError: exec cmd in self.namespace except: if hasattr(sys, 'last_type') and \ sys.last_type == SystemExit: self.quit() else: traceback.print_exc() self.prompt.set_text(sys.ps1) self.prompt.queue_draw() #adj = self.text.get_vadjustment() #adj.set_value(adj.upper - adj.page_size) sys.stdout, self.stdout = self.stdout, sys.stdout sys.stderr, self.stderr = self.stderr, sys.stderr def gtk_console(parent, ns, title='Python'): existing = parent.get_data('PythonConsole') if existing: existing.present() return existing win = gtk.Window() parent._python_console = win win.set_transient_for(parent) win.set_destroy_with_parent(True) win.set_default_size(475, 300) win.set_title(title) def key_cb(win, event): if event.keyval in (gtk.keysyms.W, gtk.keysyms.w) and \ event.state & gtk.gdk.CONTROL_MASK: win.hide() if event.keyval == gtk.keysyms.Escape: win.hide() win.connect('key_press_event', key_cb) def delete(win, event): win.hide(); return True win.connect('delete-event', delete) def quit(): win.hide() cons = Console(namespace=ns, quit_cb=quit) win.add(cons) cons.show() win.show() cons.init() return win def console_cb(action, window): gtk_console(window, { '__builtins__':__builtins__, 'window':window, }) python-box2d-2.0.2+svn20100109.244/testbed/test_SensorTest.py0000644000000000000000000000726711135461416021667 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class SensorTest (Framework): name="SensorTest" sensor=None _pickle_vars=['sensor'] def __init__(self): super(SensorTest, self).__init__() bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) ground.CreateShape(sd) if True: sd=box2d.b2PolygonDef() sd.SetAsBox(10.0, 2.0, (0.0, 20.0), 0.0) sd.isSensor = True self.sensor = ground.CreateShape(sd) else: # Alternative test: cd=box2d.b2CircleDef() cd.isSensor = True cd.radius = 5.0 cd.localPosition = (0.0, 20.0) self.sensor = ground.CreateShape(cd) sd=box2d.b2CircleDef() sd.radius = 1.0 sd.density = 1.0 for i in range(10): bd=box2d.b2BodyDef() bd.position = (0.0 + 3.0 * i, 20.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() def Step(self, settings): # Traverse the contact results. Apply a force on shapes # that overlap the sensor. for point in self.points: if point.state == fwContactTypes.contactPersisted: continue shape1, shape2=point.shape1, point.shape2 other=None if shape1 == self.sensor: other = shape2.GetBody() elif shape2 == self.sensor: other = shape1.GetBody() else: continue ground = self.sensor.GetBody() typedshape = self.sensor.getAsType() if self.sensor.GetType() == box2d.e_circleShape: center = ground.GetWorldPoint(typedshape.GetLocalPosition()) elif self.sensor.GetType() == box2d.e_polygonShape: center = ground.GetWorldPoint(typedshape.GetCentroid()) else: print "don't know how to get the center of this shape, using (0,0)" center = ground.GetWorldPoint(box2d.b2Vec2(0.0, 0.0)) d = center - point.position if d.LengthSquared() < box2d.B2_FLT_EPSILON * box2d.B2_FLT_EPSILON: continue d.Normalize() F = 100.0 * d other.ApplyForce(F, point.position) super(SensorTest, self).Step(settings) if __name__=="__main__": main(SensorTest) python-box2d-2.0.2+svn20100109.244/testbed/test_Web.py0000644000000000000000000001446611136402204020261 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * # This tests distance joints, body destruction, and joint destruction. class Web (Framework): name="Web" bodies=[] joints=[] _pickle_vars=['bodies', 'joints'] def __init__(self): super(Web, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 0.5) sd.density = 5.0 sd.friction = 0.2 bd=box2d.b2BodyDef() bd.position = (-5.0, 5.0) self.bodies.append(self.world.CreateBody(bd)) self.bodies[0].CreateShape(sd) self.bodies[0].SetMassFromShapes() bd.position = (5.0, 5.0) self.bodies.append(self.world.CreateBody(bd)) self.bodies[1].CreateShape(sd) self.bodies[1].SetMassFromShapes() bd.position = (5.0, 15.0) self.bodies.append(self.world.CreateBody(bd)) self.bodies[2].CreateShape(sd) self.bodies[2].SetMassFromShapes() bd.position = (-5.0, 15.0) self.bodies.append(self.world.CreateBody(bd)) self.bodies[3].CreateShape(sd) self.bodies[3].SetMassFromShapes() jd=box2d.b2DistanceJointDef() jd.frequencyHz = 4.0 jd.dampingRatio = 0.5 jd.body1 = ground jd.body2 = self.bodies[0] jd.localAnchor1 = (-10.0, 10.0) jd.localAnchor2 = (-0.5, -0.5) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) jd.body1 = ground jd.body2 = self.bodies[1] jd.localAnchor1 = (10.0, 10.0) jd.localAnchor2 = (0.5, -0.5) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) jd.body1 = ground jd.body2 = self.bodies[2] jd.localAnchor1 = (10.0, 30.0) jd.localAnchor2 = (0.5, 0.5) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) jd.body1 = ground jd.body2 = self.bodies[3] jd.localAnchor1 = (-10.0, 30.0) jd.localAnchor2 = (-0.5, 0.5) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) jd.body1 = self.bodies[0] jd.body2 = self.bodies[1] jd.localAnchor1 = (0.5, 0.0) jd.localAnchor2 = (-0.5, 0.0) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) jd.body1 = self.bodies[1] jd.body2 = self.bodies[2] jd.localAnchor1 = (0.0, 0.5) jd.localAnchor2 = (0.0, -0.5) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) jd.body1 = self.bodies[2] jd.body2 = self.bodies[3] jd.localAnchor1 = (-0.5, 0.0) jd.localAnchor2 = (0.5, 0.0) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) jd.body1 = self.bodies[3] jd.body2 = self.bodies[0] jd.localAnchor1 = (0.0, -0.5) jd.localAnchor2 = (0.0, 0.5) p1 = jd.body1.GetWorldPoint(jd.localAnchor1) p2 = jd.body2.GetWorldPoint(jd.localAnchor2) d = p2 - p1 jd.length = d.Length() self.joints.append(self.world.CreateJoint(jd).getAsType()) def Keyboard(self, key): # Note: these functions are still causing some problems if key==K_b: for body in self.bodies: self.bodies.remove(body) self.world.DestroyBody(body) break elif key==K_j: for joint in self.joints: self.joints.remove(joint) self.world.DestroyJoint(joint) break def Step(self, settings): self.DrawStringCR("This demonstrates a soft distance joint.") self.DrawStringCR("Press: (b) to delete a body, (j) to delete a joint") super(Web, self).Step(settings) def JointDestroyed(self, joint): if joint in self.joints: print "Joint destroyed and removed from the list" self.joints.remove(joint) if __name__=="__main__": main(Web) python-box2d-2.0.2+svn20100109.244/testbed/test_CollisionFiltering.py0000644000000000000000000001206511135461416023345 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class CollisionFiltering (Framework): name="CollisionFiltering" # This is a test of collision filtering. # There is a triangle, a box, and a circle. # There are 6 shapes. 3 large and 3 small. # The 3 small ones always collide. # The 3 large ones never collide. # The boxes don't collide with triangles (except if both are small). k_smallGroup = 1 k_largeGroup = -1 k_defaultCategory = 0x0001 k_triangleCategory = 0x0002 k_boxCategory = 0x0004 k_circleCategory = 0x0008 k_triangleMask = 0xFFFF k_boxMask = 0xFFFF ^ k_triangleCategory k_circleMask = 0xFFFF def __init__(self): super(CollisionFiltering, self).__init__() # Ground body sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) sd.friction = 0.3 bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) # Small triangle triangleShapeDef=box2d.b2PolygonDef() triangleShapeDef.vertexCount = 3 triangleShapeDef.setVertex(0,-1.0, 0.0) triangleShapeDef.setVertex(1,1.0, 0.0) triangleShapeDef.setVertex(2,0.0, 2.0) triangleShapeDef.density = 1.0 triangleShapeDef.filter.groupIndex = self.k_smallGroup triangleShapeDef.filter.categoryBits = self.k_triangleCategory triangleShapeDef.filter.maskBits = self.k_triangleMask triangleBodyDef=box2d.b2BodyDef() triangleBodyDef.position = (-5.0, 2.0) body1 = self.world.CreateBody(triangleBodyDef) body1.CreateShape(triangleShapeDef) body1.SetMassFromShapes() # Large triangle (recycle definitions) triangleShapeDef.setVertex(0, 2.0*triangleShapeDef.getVertex(0)) triangleShapeDef.setVertex(1, 2.0*triangleShapeDef.getVertex(1)) triangleShapeDef.setVertex(2, 2.0*triangleShapeDef.getVertex(2)) triangleShapeDef.filter.groupIndex = self.k_largeGroup triangleBodyDef.position = (-5.0, 6.0) triangleBodyDef.fixedRotation = True body2 = self.world.CreateBody(triangleBodyDef) body2.CreateShape(triangleShapeDef) body2.SetMassFromShapes() # Small box boxShapeDef=box2d.b2PolygonDef() boxShapeDef.SetAsBox(1.0, 0.5) boxShapeDef.density = 1.0 boxShapeDef.filter.groupIndex = self.k_smallGroup boxShapeDef.filter.categoryBits = self.k_boxCategory boxShapeDef.filter.maskBits = self.k_boxMask boxBodyDef=box2d.b2BodyDef() boxBodyDef.position = (0.0, 2.0) body3 = self.world.CreateBody(boxBodyDef) body3.CreateShape(boxShapeDef) body3.SetMassFromShapes() # Large box (recycle definitions) boxShapeDef.SetAsBox(2.0, 1.0) boxShapeDef.filter.groupIndex = self.k_largeGroup boxBodyDef.position = (0.0, 6.0) body4 = self.world.CreateBody(boxBodyDef) body4.CreateShape(boxShapeDef) body4.SetMassFromShapes() # Small circle circleShapeDef=box2d.b2CircleDef() circleShapeDef.radius = 1.0 circleShapeDef.density = 1.0 circleShapeDef.filter.groupIndex = self.k_smallGroup circleShapeDef.filter.categoryBits = self.k_circleCategory circleShapeDef.filter.maskBits = self.k_circleMask circleBodyDef=box2d.b2BodyDef() circleBodyDef.position = (5.0, 2.0) body5 = self.world.CreateBody(circleBodyDef) body5.CreateShape(circleShapeDef) body5.SetMassFromShapes() # Large circle circleShapeDef.radius *= 2.0 circleShapeDef.filter.groupIndex = self.k_largeGroup circleBodyDef.position = (5.0, 6.0) body6 = self.world.CreateBody(circleBodyDef) body6.CreateShape(circleShapeDef) body6.SetMassFromShapes() if __name__=="__main__": main(CollisionFiltering) python-box2d-2.0.2+svn20100109.244/testbed/pygame_keycodes.py0000644000000000000000000000642511156662747021677 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # While the testbed tests were created with Pygame in mind, other backends # can also be used. The keycodes are usualy the same in other frameworks # but the testbed tests can use these constants to recognise the keyboard # events. K_0 = 48 K_1 = 49 K_2 = 50 K_3 = 51 K_4 = 52 K_5 = 53 K_6 = 54 K_7 = 55 K_8 = 56 K_9 = 57 K_AMPERSAND = 38 K_ASTERISK = 42 K_AT = 64 K_BACKQUOTE = 96 K_BACKSLASH = 92 K_BACKSPACE = 8 K_BREAK = 318 K_CAPSLOCK = 301 K_CARET = 94 K_CLEAR = 12 K_COLON = 58 K_COMMA = 44 K_DELETE = 127 K_DOLLAR = 36 K_DOWN = 274 K_END = 279 K_EQUALS = 61 K_ESCAPE = 27 K_EURO = 321 K_EXCLAIM = 33 K_F1 = 282 K_F10 = 291 K_F11 = 292 K_F12 = 293 K_F13 = 294 K_F14 = 295 K_F15 = 296 K_F2 = 283 K_F3 = 284 K_F4 = 285 K_F5 = 286 K_F6 = 287 K_F7 = 288 K_F8 = 289 K_F9 = 290 K_FIRST = 0 K_GREATER = 62 K_HASH = 35 K_HELP = 315 K_HOME = 278 K_INSERT = 277 K_KP0 = 256 K_KP1 = 257 K_KP2 = 258 K_KP3 = 259 K_KP4 = 260 K_KP5 = 261 K_KP6 = 262 K_KP7 = 263 K_KP8 = 264 K_KP9 = 265 K_KP_DIVIDE = 267 K_KP_ENTER = 271 K_KP_EQUALS = 272 K_KP_MINUS = 269 K_KP_MULTIPLY = 268 K_KP_PERIOD = 266 K_KP_PLUS = 270 K_LALT = 308 K_LAST = 323 K_LCTRL = 306 K_LEFT = 276 K_LEFTBRACKET = 91 K_LEFTPAREN = 40 K_LESS = 60 K_LMETA = 310 K_LSHIFT = 304 K_LSUPER = 311 K_MENU = 319 K_MINUS = 45 K_MODE = 313 K_NUMLOCK = 300 K_PAGEDOWN = 281 K_PAGEUP = 280 K_PAUSE = 19 K_PERIOD = 46 K_PLUS = 43 K_POWER = 320 K_PRINT = 316 K_QUESTION = 63 K_QUOTE = 39 K_QUOTEDBL = 34 K_RALT = 307 K_RCTRL = 305 K_RETURN = 13 K_RIGHT = 275 K_RIGHTBRACKET = 93 K_RIGHTPAREN = 41 K_RMETA = 309 K_RSHIFT = 303 K_RSUPER = 312 K_SCROLLOCK = 302 K_SEMICOLON = 59 K_SLASH = 47 K_SPACE = 32 K_SYSREQ = 317 K_TAB = 9 K_UNDERSCORE = 95 K_UNKNOWN = 0 K_UP = 273 K_a = 97 K_b = 98 K_c = 99 K_d = 100 K_e = 101 K_f = 102 K_g = 103 K_h = 104 K_i = 105 K_j = 106 K_k = 107 K_l = 108 K_m = 109 K_n = 110 K_o = 111 K_p = 112 K_q = 113 K_r = 114 K_s = 115 K_t = 116 K_u = 117 K_v = 118 K_w = 119 K_x = 120 K_y = 121 K_z = 122 if __name__ == '__main__': # This file is generated using the code below from pygame import locals for nm_val in [(key, locals.__dict__[key]) for key in dir(locals) if key.startswith('K_')]: print "%s = %s" % nm_val python-box2d-2.0.2+svn20100109.244/testbed/demos.py0000644000000000000000000002007111135471136017612 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. import os import pygame import Box2D as box2d from pygame.locals import * from settings import fwSettings from pgu import gui from test_main import fwDebugDraw from distutils import sysconfig global width, height width, height = 640, 480 def main(): # Initialize pygame screen = pygame.display.set_mode((width,height)) caption= "Python Box2D Testbed Demos" pygame.display.set_caption(caption) # Initialize the GUI theme = gui.Theme("default") app = gui.Desktop(theme=theme) app.connect(gui.QUIT,app.quit,None) main = gui.Container(width=width, height=height) # Label at the top left main.add(gui.Label("Box2D Testbed Demos", cls="h1"), 20, 20) # The dimensions of the list of the demos list_size= (width / 2, height / 2) list_pos = (width/2 - list_size[0]/2, height/2 - list_size[1]/2) # Create the actual widget demolist = gui.List(width=list_size[0], height=list_size[1]) main.add(demolist, list_pos[0], list_pos[1]) # Add all the demos found in the directory to the list add_demos(demolist) buttonw = (list_size[0]/2-20) # width of the buttons bottom = list_pos[1]+list_size[1]+20 # the y-location of the bottom of the list # Create a Run button, calling run_demo on click b = gui.Button("Run", width=buttonw) main.add(b, list_pos[0], bottom) b.connect(gui.CLICK, run_demo, demolist) # Create a Quit button b = gui.Button("Quit", width=buttonw) main.add(b, list_pos[0]+buttonw+30, bottom) b.connect(gui.CLICK, lambda x:pygame.event.post(pygame.event.Event(pygame.QUIT)), None) # box2d initialization z=10 #scale (10 pixels/physics unit) # Since we're taking the debug draw implementation from the testbed, it requires a bit # of ugliness to set it up properly. renderer = fwDebugDraw() renderer.surface = screen renderer.viewZoom=z renderer.viewCenter=box2d.b2Vec2(0,0) renderer.width, renderer.height = width, height renderer.viewOffset = renderer.viewCenter - box2d.b2Vec2(width, height)/2 renderer.SetFlags(box2d.b2DebugDraw.e_shapeBit) # we only want shapes to be drawn renderer.DrawSolidPolygon = lambda a,b,c: 0 # make it not draw the polygons! renderer.DrawPolygon = lambda a,b,c: 0 # # Create the world worldAABB=box2d.b2AABB() worldAABB.lowerBound = (-100.0, -100.0) worldAABB.upperBound = ( 100.0, 100.0) gravity = (0.0, -10.0) world = box2d.b2World(worldAABB, gravity, True) world.SetDebugDraw(renderer) # Create the ground bd = box2d.b2BodyDef() bd.position = (0.0, 0.0) ground = world.CreateBody(bd) # The borders of the screen sd = box2d.b2PolygonDef() sd.SetAsBox(1, height/z, (-width/(2*z)-1, 0), 0) ground.CreateShape(sd) sd.SetAsBox(1, height/z, (width/(2*z)+1, 0), 0) ground.CreateShape(sd) sd.SetAsBox(width/z, 1, (0,-height/(2*z)-1), 0) ground.CreateShape(sd) sd.SetAsBox(width/z, 1, (0,height/(2*z)+1), 0) ground.CreateShape(sd) # The shape for the file list sd.SetAsBox(list_size[0]/(2*z), list_size[1]/(2*z)) ground.CreateShape(sd) # Create a few balls to bounce around the screen for i in range(10): bd = box2d.b2BodyDef() bd.allowSleep = True bd.position = (box2d.b2Random(-width/(2*z), width/(2*z)), box2d.b2Random(-height/(2*z), height/(2*z))) bd.isBullet = True bomb = world.CreateBody(bd) bomb.SetLinearVelocity(-5.0 * bd.position) sd = box2d.b2CircleDef() sd.radius = 1 sd.density = 1.0 sd.restitution = 0.7 bomb.CreateShape(sd) bomb.SetMassFromShapes() app.init(main) main_loop(world, screen, demolist, app) def get_shapes(world): for body in world.bodyList: shape = body.GetShapeList() while shape: yield (body, shape.getAsType()) shape=shape.GetNext() def update_shapes(world): # Check to see if any objects are sleeping or coming to a stop. # Then give them a little push. for body in world.bodyList: v = body.GetLinearVelocity() if body.IsSleeping() or v.LengthSquared() < 0.2: i = body.GetWorldVector((box2d.b2Random(-200,200), box2d.b2Random(-200,200))) p = body.GetWorldPoint((0.0, 0.0)) body.ApplyImpulse(i, p) def main_loop(world, screen, demolist, app): # Create a surface to draw the GUI onto app_surface = pygame.Surface((width,height), SWSURFACE) hz = 60.0 clock = pygame.time.Clock() while True: for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): return elif event.type == KEYDOWN: if event.key == K_RETURN: run_demo(demolist) elif event.type == MOUSEBUTTONDOWN: if event.button ==3: run_demo(demolist) elif event.button ==4: demolist.set_vertical_scroll(demolist.vscrollbar.value-100) elif event.button ==5: demolist.set_vertical_scroll(demolist.vscrollbar.value+100) app.event(event) # Tell the GUI to update itself, then blit it to the screen app.update(app_surface) # pygame 1.8.1/pgu problem? 1.8.0 works fine screen.blit(app_surface, (0,0)) # Wake up non/slow-moving shapes update_shapes(world) # Step the world # (calls the debugdraw functions, so this is where the balls are drawn) world.Step(1/hz, 10, 8) clock.tick(hz) #fps = clock.get_fps() pygame.display.flip() def add_demos(demolist): # I don't feel like maintaining a list of demos. # So just glob to see what test_*.py files are in the current # directory and add them to the demo list. import glob ignore_list=("main") for f in glob.glob("test_*.py"): name = f[5:-3] if name.lower() in ignore_list: continue demolist.add(name,value=f) def run_demo(demolist): # Run the currently selected demo (the widget itself is passed as an argument) if demolist.value == None: return print "Running: ", demolist.value from sys import executable as python_interpreter from platform import system as sys_platform if sys_platform() == "Windows": # Just in case we're in some directory with a space in it, use quotes # around the path. cmd = '"%s" -OO %s' % (python_interpreter, demolist.value) else: cmd = "%s -OO %s" % (python_interpreter, demolist.value) print "-> %s" % cmd ret = os.system(cmd) if ret == 10 or ret/256 == 10: # user hit reload (somehow the retval on linux is *256) run_demo(demolist) if __name__=="__main__": main() python-box2d-2.0.2+svn20100109.244/testbed/test_PolyShapes.py0000644000000000000000000001024211135461416021630 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * import math class PolyShapes (Framework): name="PolyShapes" bodyIndex=0 bodies=[] sds=[] circleDef=None _pickle_vars=['bodies'] def __init__(self): super(PolyShapes, self).__init__() # Ground body sds = self.sds sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) sd.friction = 0.3 for i in range(4): sds.append(box2d.b2PolygonDef()) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sds[0].vertexCount = 3 sds[0].setVertex(0,-0.5, 0.0) sds[0].setVertex(1,0.5, 0.0) sds[0].setVertex(2,0.0, 1.5) sds[0].density = 1.0 sds[0].friction = 0.3 sds[1].vertexCount = 3 sds[1].setVertex(0,-0.1, 0.0) sds[1].setVertex(1,0.1, 0.0) sds[1].setVertex(2,0.0, 1.5) sds[1].density = 1.0 sds[1].friction = 0.3 sds[2].vertexCount = 8 w = 1.0 b = w / (2.0 + math.sqrt(2.0)) s = math.sqrt(2.0) * b sds[2].setVertex(0,0.5 * s, 0.0) sds[2].setVertex(1,0.5 * w, b) sds[2].setVertex(2,0.5 * w, b + s) sds[2].setVertex(3,0.5 * s, w) sds[2].setVertex(4,-0.5 * s, w) sds[2].setVertex(5,-0.5 * w, b + s) sds[2].setVertex(6,-0.5 * w, b) sds[2].setVertex(7,-0.5 * s, 0.0) sds[2].density = 1.0 sds[2].friction = 0.3 sds[3].SetAsBox(0.5, 0.5) #sds[3].vertexCount = 4 #sds[3].setVertex(0,-0.5, 0.0) #sds[3].setVertex(1,0.5, 0.0) #sds[3].setVertex(2,0.5, 1.0) #sds[3].setVertex(3,-0.5, 1.0) sds[3].density = 1.0 sds[3].friction = 0.3 self.circleDef=box2d.b2CircleDef() self.circleDef.radius = 0.5 self.circleDef.density = 1.0 self.bodyIndex = 0 def Create(self, index): bd=box2d.b2BodyDef() x = box2d.b2Random(-2.0, 2.0) bd.position = (x, 10.0) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) if index == 4: bd.angularDamping = 0.02 self.bodies.append(self.world.CreateBody(bd) ) if index < 4: self.bodies[-1].CreateShape(self.sds[index]) else: self.bodies[-1].CreateShape(self.circleDef) self.bodies[-1].SetMassFromShapes() def DestroyBody(self): for body in self.bodies: self.bodies.remove(body) self.world.DestroyBody(body) return def Keyboard(self, key): if key==K_1 or key==K_2 or key==K_3 or key==K_4 or key==K_5: self.Create(key - K_1) elif key==K_d: self.DestroyBody() def Step(self, settings): super(PolyShapes, self).Step(settings) self.DrawStringCR("Press 1-5 to drop stuff") if __name__=="__main__": main(PolyShapes) python-box2d-2.0.2+svn20100109.244/testbed/test_BreakableBody.py0000644000000000000000000003604211135471136022235 0ustar rootroot#!/usr/bin/python # # Testbed example showing deformable and breakable bodies using the soft # b2DistanceJoint and a small,liteweight triangle mesher. # 2008-05-09 / nimodo # # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # from test_main import * import TriangleMesh as tm def H(x): return x/2.0 MIN_SQUAREDLENGTH =0.25 #0.5*0.5 # want the value on restart, # break joint if reaction exceeds g_maxAllowableForce = 200.0 data = { 'ring_nodes' : ( (6.00, 3.00), (5.12, 5.12), (3.00, 6.00), (0.88, 5.12), (0.00, 3.00), (0.88, 0.88), (3.00, 0.00), (5.12, 0.88), (4.50, 3.00), (4.06, 4.06), (3.00, 4.50), (1.94, 4.06), (1.50, 3.00), (1.94, 1.94), (3.00, 1.50), (4.06, 1.94)), 'ring_segments' : ( (9, 10), (10, 11), (11, 12), (12, 13), (13, 14), (14, 15), (15, 16), (16, 9)), 'ring_holes' : ( (3.00, 3.00), ), # 'B' 'B_nodes' : ( (0.00, 0.00), (4.00, 0.00), (5.00, 2.00), (5.00, 4.00), (4.00, 5.00), (5.00, 6.00), (5.00, 8.00), (4.00, 9.00), (0.00, 9.00), (0.00, 5.00), (1.50, 1.50), (3.50, 1.50), (3.50, 4.00), (1.50, 4.00), (1.50, 6.00), (3.50, 6.00), (3.50, 8.50), (1.50, 8.50)), 'B_segments' : ( (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 1), (11, 12), (12, 13), (13, 14), (14, 11), (15, 16), (16, 17), (17, 18), (18, 15)), 'B_holes' : ( (5.00, 5.00), (2.50, 2.50), (2.50, 7.00)), # 'D' 'D_nodes' : ( (0.00, 0.00), (4.00, 0.00), (5.00, 2.50), (5.00, 7.00), (4.00, 9.00), (0.00, 9.00), (0.00, 5.00), (1.50, 2.50), (3.50, 2.50), (3.50, 7.00), (1.50, 7.00)), 'D_segments' : ( (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 1), (8, 9), (9, 10), (10, 11), (11, 8)), 'D_holes' : ( (2.50, 5.00), ), # 'x' 'x_nodes' : ( (0.00, 0.00), (1.00, 0.00), (5.00, 0.00), (6.00, 0.00), (6.00, 1.00), (6.00, 5.00), (6.00, 6.00), (1.00, 6.00), (5.00, 6.00), (0.00, 6.00), (0.00, 5.00), (0.00, 1.00), (3.00, 2.00), (4.00, 3.00), (3.00, 4.00), (2.00, 3.00)), 'x_segments' : ( (2, 13), (3, 13), (5, 14), (6, 14), (8, 15), (9, 15), (11, 16), (12, 16)), 'x_holes' : ( (3.00, 1.00), (5.00, 3.00), (3.00, 5.00), (1.00, 3.00)), # '2' 'two_nodes' : ( (0.00, 0.00), (6.00, 0.00), (6.00, 1.00), (2.00, 1.00), (2.00, 2.00), (6.00, 6.00), (6.00, 8.00), (5.00, 9.00), (2.00, 9.00), (1.00, 7.50), (0.00, 2.50), (5.00, 6.50), (5.00, 8.00), (2.50, 8.00), (2.00, 7.50)), 'two_segments' : ( (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 15), (11, 12), (12, 13), (13, 14), (14, 15)), 'two_holes' : ( (3.00, 5.00), (4.00, 3.00)), # '-' beam 'beanodes' : ( (0.00, 0.00), (32.00, 0.00), (32.00, 3.00), (0.00, 3.00)), 'beasegments' : None, 'beaholes' : None, # 'b' a box 'b_nodes' : ( (0.00, 0.00), (10.00, 0.00), (10.00, 10.00), (0.00, 10.00), (2.00, 2.00), (8.00, 2.00), (8.00, 8.00), (2.00, 8.00)), 'b_segments' : ( (5, 6), (6, 7), (7, 8), (8, 5)), 'b_holes' : ( (5.0, 5.0), ) } # convert the data to the specific types for key in data.keys(): if data[key] == None: continue if key[-6:] == "_nodes" or key[-6:] == "_holes": data[key] = [tm.tmVertex( (x, y) ) for x, y in data[key]] elif key[-9:] == "_segments": data[key] = [tm.tmSegmentId((v0,v1)) for v0,v1 in data[key]] class BreakableBody(Framework): name="BreakableBody" maxAllowableForce = 0.0 drawMode = False drawCount = 0 drawVertices = [] staticBodies=False _pickle_vars=['maxAllowableForce', 'drawMode', 'drawCount', 'drawVertices', 'staticBodies'] def __init__(self): super(BreakableBody, self).__init__() if not self.settings.onlyInit: self.viewZoom = 6.0 # geometries gx, gy = 100.0, 1.0 dx, br = 34.0, 0.3 sx, sy = -dx-H(dx), 30 # ground sd=box2d.b2PolygonDef() bd=box2d.b2BodyDef() bd.position = (0.0, 0.0) ground = self.world.CreateBody(bd) # bottom sd.SetAsBox( H(gx), H(gy) ) ground.CreateShape(sd) sd.SetAsBox( H(dx), H(gy), (-dx,sy-1.0), 0.0 ) ground.CreateShape(sd) # dyn bodies pd=box2d.b2PolygonDef() dj=box2d.b2DistanceJointDef() dj.dampingRatio = 1.0 dj.collideConnected = True nodes, segments, holes = self.ExampleData('B') dj.frequencyHz = 20 pd.density = 1.0/70.0 pd.friction = 0.4 pd.restitution = 0.01 self.CreateSoftBody( (sx,sy), 0, 0, pd, dj, nodes, segments, holes) nodes, segments, holes = self.ExampleData('ring') dj.frequencyHz = 20 pd.density = 1.0/36.0 pd.friction = 0.1 pd.restitution = 0.5 self.CreateSoftBody( (sx+6,sy), 0, 0, pd, dj,nodes, segments, holes) nodes, segments, holes = self.ExampleData('x') dj.frequencyHz = 0.0 pd.density = 0.2 pd.friction = 1.0 pd.restitution = 0.1 self.CreateSoftBody( (sx+13,sy), 0, 0, pd, dj,nodes, segments, holes) nodes, segments, holes = self.ExampleData('two') dj.frequencyHz = 20.0 pd.density = 0.01 pd.friction = 0.3 pd.restitution = 0.3 self.CreateSoftBody( (sx+20,sy), 0, 0, pd, dj, nodes, segments, holes) nodes, segments, holes = self.ExampleData('D') self.CreateSoftBody( (sx+28,sy), 0, 0, pd, dj, nodes, segments, holes) nodes, segments, holes = self.ExampleData('b') dj.frequencyHz = 20 dj.dampingRatio = 2.0 pd.restitution = 0.01 pd.density = 0.01 pd.friction = 0.9 self.CreateSoftBody( (-5,5*gy), 0, 0, pd, dj ,nodes, segments, holes) cd=box2d.b2CircleDef() bd=box2d.b2BodyDef() cd.radius = br cd.density= 0.001 bd.position = (0.0,10.0*gy) for i in range(60): b = self.world.CreateBody(bd) b.CreateShape(cd) b.SetMassFromShapes() # Create compound (soft) body using a triangle mesh # If meshDensity is 0, a minimal grid is generated. # Actually pd and dj define the behaviour for all triangles def CreateSoftBody(self, pos, meshDensity, options, pd, dj,nodes=[], segments=[], holes=[]): n_nodes =len(nodes) n_segments=len(segments) n_holes =len(holes) # TriangleMesh defs md = tm.TriangleMesh() # box2d defs bd=box2d.b2BodyDef() # in case of meshDensity>3 ... md.SetMaxVertexCount(meshDensity) if options: md.SetOptions(options) # triangulator main i = md.Mesh(nodes, segments, holes) md.PrintData() print "TriangleMesh.py:%s" % md.GetErrorMessage(i) # check if enough proxies set in box2d, 10 proxies as reserve if self.world.GetProxyCount()+md.GetInsideTriangleCount() > (box2d.b2_maxProxies-10): print print "Current proxy count:", self.world.GetProxyCount() print "World proxy count if added:", self.world.GetProxyCount()+md.GetInsideTriangleCount() print "Max proxies (Box2D setting):", (box2d.b2_maxProxies-10) print "Error: Not enough proxies to insert the mesh!" md.Reset() return # bodies (triangles) triangles = md.GetTriangles() if triangles==None: return pd.vertexCount = 3 for i in range(md.GetTriangleCount()): if triangles[i].inside: pd.setVertices([triangles[i].v[0], triangles[i].v[1], triangles[i].v[2]]) try: pd.checkValues() except ValueError: print "** Created an invalid shape" exit(0) bd.position=pos b = self.world.CreateBody(bd) b.CreateShape(pd) b.SetMassFromShapes() # we need the body pointer in the triangles for the joints later triangles[i].userData = b # joints if pd.density>0.0: # for each triangle-pair in edges, connect with a distance joint edges = md.GetEdges() for i in range(md.GetEdgeCount()): t0 = edges[i].t[0] t1 = edges[i].t[1] if t0.inside==False or t1.inside==False: continue # Get bodies b1 = t0.userData b2 = t1.userData if b1==None or b2==None: continue dj.Initialize( b1,b2, b1.GetWorldCenter(), b2.GetWorldCenter()) self.world.CreateJoint(dj).getAsType() # clean TriangleMesh md.Reset() # maybe here to check for maximal reaction forces to break a body def Step(self, settings): global g_maxAllowableForce F=0.0 jStressed = 0 for j in self.world.jointList: tmp = j.GetReactionForce(settings.hz).Length() # for newer builds #tmp = j.GetReactionForce().Length() # works for older builds if tmp>F: F = tmp jStressed = j if jStressed and (F>g_maxAllowableForce): self.world.DestroyJoint(jStressed) self.DrawStringCR("max.reactionforce=%f.0 allowable=%f.0 change:-+" % (F,g_maxAllowableForce)); onoff = { False: 'off', True: 'on' } self.DrawStringCR("(d)rawmode-%s (m)esh (s)taticbody-%s" % (onoff[self.drawMode], onoff[self.staticBodies])) p1, p2 = box2d.b2Vec2(), box2d.b2Vec2() for i in xrange(self.drawCount-1): p1 = (self.drawVertices[i].x ,self.drawVertices[i].y) if i 0.0: g_maxAllowableForce -= 5.0 elif key==K_PLUS or key==K_EQUALS: g_maxAllowableForce += 5.0 elif key==K_d: self.drawMode = not self.drawMode elif key==K_s: self.staticBodies = not self.staticBodies elif key==K_m: if self.drawCount>0: pd = box2d.b2PolygonDef() dj = box2d.b2DistanceJointDef() dj.collideConnected = True dj.frequencyHz = 20.0 dj.dampingRatio = 10.0 pd.friction = 0.9 pd.restitution = 0.1 if self.staticBodies: pd.density = 0.0 else: pd.density = 1.0/32.0 self.CreateSoftBody( box2d.b2Vec2(0.0,0.0), 0, tm.tmO_SEGMENTBOUNDARY|tm.tmO_GRADING|tm.tmO_CHECKINTERSECT, pd, dj, self.drawVertices) self.drawVertices = [] self.drawCount = 0 self.drawMode = False def AddVertex(self, p): if self.drawCount>0: dx = self.drawVertices[self.drawCount-1].x - p.x dy = self.drawVertices[self.drawCount-1].y - p.y if dx*dx+dy*dy > MIN_SQUAREDLENGTH: self.drawVertices.append( box2d.b2Vec2(p.x, p.y) ) self.drawCount+=1 else: self.drawVertices.append( box2d.b2Vec2(p.x, p.y) ) self.drawCount+=1 def MouseDown(self, p): if self.drawMode: self.AddVertex(p) else: super(BreakableBody, self).MouseDown(p) def MouseUp(self, p): if not self.drawMode: super(BreakableBody, self).MouseUp(p) # examples def ExampleData(self, which): print "\nLoading data:", which nodes = data["%s_nodes" % which] segments = data["%s_segments" % which] holes = data["%s_holes" % which] return (nodes, segments, holes) if __name__=="__main__": main(BreakableBody) python-box2d-2.0.2+svn20100109.244/testbed/test_Prismatic.py0000644000000000000000000000601611136402204021467 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Prismatic (Framework): name="Prismatic" _pickle_vars=['joint'] def __init__(self): super(Prismatic, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(2.0, 0.5) sd.density = 5.0 sd.friction = 0.05 bd=box2d.b2BodyDef() bd.position = (-10.0, 10.0) bd.angle = 0.5 * box2d.b2_pi body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() pjd=box2d.b2PrismaticJointDef() # Bouncy limit pjd.Initialize(ground, body, (0.0, 0.0), (1.0, 0.0)) # Non-bouncy limit #pjd.Initialize(ground, body, (-10.0, 10.0), (1.0, 0.0)) pjd.motorSpeed = 10.0 pjd.maxMotorForce = 1000.0 pjd.enableMotor = True pjd.lowerTranslation = 0.0 pjd.upperTranslation = 20.0 pjd.enableLimit = True self.joint = self.world.CreateJoint(pjd).getAsType() def Keyboard(self, key): if not self.joint: return if key==K_l: self.joint.EnableLimit(not self.joint.IsLimitEnabled()) elif key==K_m: self.joint.EnableMotor(not self.joint.IsMotorEnabled()) elif key==K_p: self.joint.SetMotorSpeed(-self.joint.GetMotorSpeed()) def Step(self, settings): self.DrawStringCR("Keys: (l) limits, (m) motors, (p) speed") if self.joint: force = self.joint.GetMotorForce() self.DrawStringCR("Motor Force = %f.0" % force) super(Prismatic, self).Step(settings) if __name__=="__main__": main(Prismatic) python-box2d-2.0.2+svn20100109.244/testbed/test_SliderCrank.py0000644000000000000000000000773311136402204021744 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * # A motor driven slider crank with joint friction. class SliderCrank (Framework): name="SliderCrank" joint1=None joint2=None _pickle_vars=['joint1', 'joint2'] def __init__(self): super(SliderCrank, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) # Define crank. sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 2.0) sd.density = 1.0 rjd=box2d.b2RevoluteJointDef() prevBody=ground bd=box2d.b2BodyDef() bd.position = (0.0, 7.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() rjd.Initialize(prevBody, body, (0.0, 5.0)) rjd.motorSpeed = 1.0 * box2d.b2_pi rjd.maxMotorTorque = 10000.0 rjd.enableMotor = True self.joint1 = self.world.CreateJoint(rjd).getAsType() prevBody = body # Define follower. sd.SetAsBox(0.5, 4.0) bd.position = (0.0, 13.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() rjd.Initialize(prevBody, body, (0.0, 9.0)) rjd.enableMotor = False self.world.CreateJoint(rjd).getAsType() prevBody = body # Define piston sd.SetAsBox(1.5, 1.5) bd.position = (0.0, 17.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() rjd.Initialize(prevBody, body, (0.0, 17.0)) self.world.CreateJoint(rjd).getAsType() pjd=box2d.b2PrismaticJointDef() pjd.Initialize(ground, body, (0.0, 17.0), (0.0, 1.0)) pjd.maxMotorForce = 1000.0 pjd.enableMotor = True self.joint2 = self.world.CreateJoint(pjd).getAsType() # Create a payload sd.density = 2.0 bd.position = (0.0, 23.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() def Keyboard(self, key): if not self.joint1 or not self.joint2: return if key==K_f: self.joint2.enableMotor = not self.joint2.enableMotor self.joint2.GetBody2().WakeUp() elif key==K_m: self.joint1.enableMotor = not self.joint1.enableMotor self.joint1.GetBody2().WakeUp() def Step(self, settings): self.DrawStringCR("Keys: (f) toggle friction, (m) toggle motor") if self.joint1: torque = self.joint1.GetMotorTorque() self.DrawStringCR("Motor Torque = %.0f" % (torque)) super(SliderCrank, self).Step(settings) if __name__=="__main__": main(SliderCrank) python-box2d-2.0.2+svn20100109.244/testbed/test_TheoJansen.py0000644000000000000000000001656011136402204021577 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * from pygame.locals import * # Inspired by a contribution by roman_m (C++ version) # Dimensions scooped from APE (http://www.cove.org/ape/index.htm) class TheoJansen (Framework): name="TheoJansen" offset=None chassis=None wheel=None motorJoint=None motorOn = False motorSpeed = 0 _pickle_vars=['offset', 'chassis', 'wheel', 'motorJoint', 'motorOn', 'motorSpeed'] def CreateLeg(self, s, wheelAnchor): p1=box2d.b2Vec2(5.4 * s, -6.1) p2=box2d.b2Vec2(7.2 * s, -1.2) p3=box2d.b2Vec2(4.3 * s, -1.9) p4=box2d.b2Vec2(3.1 * s, 0.8) p5=box2d.b2Vec2(6.0 * s, 1.5) p6=box2d.b2Vec2(2.5 * s, 3.7) sd1=box2d.b2PolygonDef() sd2=box2d.b2PolygonDef() sd1.vertexCount = 3 sd2.vertexCount = 3 sd1.filter.groupIndex = -1 sd2.filter.groupIndex = -1 sd1.density = 1.0 sd2.density = 1.0 if s > 0.0: sd1.setVertex(0, p1) sd1.setVertex(1, p2) sd1.setVertex(2, p3) sd2.setVertex(0, (0,0)) sd2.setVertex(1, p5 - p4) sd2.setVertex(2, p6 - p4) else: sd1.setVertex(0, p1) sd1.setVertex(1, p3) sd1.setVertex(2, p2) sd2.setVertex(0, (0,0)) sd2.setVertex(1, p6 - p4) sd2.setVertex(2, p5 - p4) bd1=box2d.b2BodyDef() bd2=box2d.b2BodyDef() bd1.position = self.offset bd2.position = p4 + self.offset bd1.angularDamping = 10.0 bd2.angularDamping = 10.0 body1 = self.world.CreateBody(bd1) body2 = self.world.CreateBody(bd2) body1.CreateShape(sd1) body2.CreateShape(sd2) body1.SetMassFromShapes() body2.SetMassFromShapes() djd=box2d.b2DistanceJointDef() # Using a soft distance constraint can reduce some jitter. # It also makes the structure seem a bit more fluid by # acting like a suspension system. #djd.dampingRatio = 0.5 #djd.frequencyHz = 10.0 # usable, but doesn't act like it seems it should? djd.Initialize(body1, body2, p2 + self.offset, p5 + self.offset) self.world.CreateJoint(djd).getAsType() djd.Initialize(body1, body2, p3 + self.offset, p4 + self.offset) self.world.CreateJoint(djd).getAsType() djd.Initialize(body1, self.wheel, p3 + self.offset, wheelAnchor + self.offset) self.world.CreateJoint(djd).getAsType() djd.Initialize(body2, self.wheel, p6 + self.offset, wheelAnchor + self.offset) self.world.CreateJoint(djd).getAsType() rjd=box2d.b2RevoluteJointDef() rjd.Initialize(body2, self.chassis, p4 + self.offset) self.world.CreateJoint(rjd).getAsType() def __init__(self): super(TheoJansen, self).__init__() self.offset = (0.0, 8.0) self.motorSpeed = 2.0 self.motorOn = True pivot=box2d.b2Vec2(0.0, 0.8) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd.SetAsBox(0.5, 5.0, (-50.0, 15.0), 0.0) ground.CreateShape(sd) sd.SetAsBox(0.5, 5.0, (50.0, 15.0), 0.0) ground.CreateShape(sd) for i in range(40): sd = box2d.b2CircleDef() sd.density = 1.0 sd.radius = 0.25 bd=box2d.b2BodyDef() bd.position = (-40.0 + 2.0 * i, 0.5) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() sd=box2d.b2PolygonDef() sd.density = 1.0 sd.SetAsBox(2.5, 1.0) sd.filter.groupIndex = -1 bd=box2d.b2BodyDef() bd.position = pivot + self.offset self.chassis = self.world.CreateBody(bd) self.chassis.CreateShape(sd) self.chassis.SetMassFromShapes() sd = box2d.b2CircleDef() sd.density = 1.0 sd.radius = 1.6 sd.filter.groupIndex = -1 bd=box2d.b2BodyDef() bd.position = pivot + self.offset self.wheel = self.world.CreateBody(bd) self.wheel.CreateShape(sd) self.wheel.SetMassFromShapes() jd=box2d.b2RevoluteJointDef() jd.Initialize(self.wheel, self.chassis, pivot + self.offset) jd.collideConnected = False jd.motorSpeed = self.motorSpeed jd.maxMotorTorque = 400.0 jd.enableMotor = self.motorOn self.motorJoint = self.world.CreateJoint(jd).getAsType() wheelAnchor = pivot + box2d.b2Vec2(0.0, -0.8) self.CreateLeg(-1.0, wheelAnchor) self.CreateLeg(1.0, wheelAnchor) self.wheel.SetXForm(self.wheel.GetPosition(), 120.0 * box2d.b2_pi / 180.0) self.CreateLeg(-1.0, wheelAnchor) self.CreateLeg(1.0, wheelAnchor) self.wheel.SetXForm(self.wheel.GetPosition(), -120.0 * box2d.b2_pi / 180.0) self.CreateLeg(-1.0, wheelAnchor) self.CreateLeg(1.0, wheelAnchor) def Step(self, settings): self.DrawStringCR("Keys: left = a, brake = s, right = d, toggle motor = m") super(TheoJansen, self).Step(settings) def Keyboard(self, key): if not self.chassis: return if key==K_a: self.chassis.WakeUp() self.motorJoint.SetMotorSpeed(-self.motorSpeed) elif key==K_s: self.chassis.WakeUp() self.motorJoint.SetMotorSpeed(0.0) elif key==K_d: self.chassis.WakeUp() self.motorJoint.SetMotorSpeed(self.motorSpeed) elif key==K_m: self.chassis.WakeUp() self.motorJoint.EnableMotor(not self.motorJoint.IsMotorEnabled()) if __name__=="__main__": main(TheoJansen) python-box2d-2.0.2+svn20100109.244/testbed/test_CollisionProcessing.py0000644000000000000000000001220311151077147023532 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class CollisionProcessing (Framework): name="CollisionProcessing" def __init__(self): super(CollisionProcessing, self).__init__() # Ground body sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) sd.friction = 0.3 bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) xLo = -5.0 xHi = 5.0 yLo = 2.0 yHi = 35.0 # Small triangle triangleShapeDef=box2d.b2PolygonDef() triangleShapeDef.vertexCount = 3 triangleShapeDef.setVertex(0,-1.0, 0.0) triangleShapeDef.setVertex(1,1.0, 0.0) triangleShapeDef.setVertex(2,0.0, 2.0) triangleShapeDef.density = 1.0 triangleBodyDef=box2d.b2BodyDef() triangleBodyDef.position = (box2d.b2Random(xLo, xHi), box2d.b2Random(yLo, yHi)) body1 = self.world.CreateBody(triangleBodyDef) body1.CreateShape(triangleShapeDef) body1.SetMassFromShapes() # Large triangle (recycle definitions) triangleShapeDef.setVertex(0, 2.0*triangleShapeDef.getVertex(0)) triangleShapeDef.setVertex(1, 2.0*triangleShapeDef.getVertex(1)) triangleShapeDef.setVertex(2, 2.0*triangleShapeDef.getVertex(2)) triangleBodyDef.position = (box2d.b2Random(xLo, xHi), box2d.b2Random(yLo, yHi)) body2 = self.world.CreateBody(triangleBodyDef) body2.CreateShape(triangleShapeDef) body2.SetMassFromShapes() # Small box boxShapeDef=box2d.b2PolygonDef() boxShapeDef.SetAsBox(1.0, 0.5) boxShapeDef.density = 1.0 boxBodyDef=box2d.b2BodyDef() boxBodyDef.position = (box2d.b2Random(xLo, xHi), box2d.b2Random(yLo, yHi)) body3 = self.world.CreateBody(boxBodyDef) body3.CreateShape(boxShapeDef) body3.SetMassFromShapes() # Large box (recycle definitions) boxShapeDef.SetAsBox(2.0, 1.0) boxBodyDef.position = (box2d.b2Random(xLo, xHi), box2d.b2Random(yLo, yHi)) body4 = self.world.CreateBody(boxBodyDef) body4.CreateShape(boxShapeDef) body4.SetMassFromShapes() # Small circle circleShapeDef=box2d.b2CircleDef() circleShapeDef.radius = 1.0 circleShapeDef.density = 1.0 circleBodyDef=box2d.b2BodyDef() circleBodyDef.position = (box2d.b2Random(xLo, xHi), box2d.b2Random(yLo, yHi)) body5 = self.world.CreateBody(circleBodyDef) body5.CreateShape(circleShapeDef) body5.SetMassFromShapes() # Large circle circleShapeDef.radius *= 2.0 circleBodyDef.position = (box2d.b2Random(xLo, xHi), box2d.b2Random(yLo, yHi)) body6 = self.world.CreateBody(circleBodyDef) body6.CreateShape(circleShapeDef) body6.SetMassFromShapes() def Step(self, settings): # We are going to destroy some bodies according to contact # points. We must buffer the bodies that should be destroyed # because they may belong to multiple contact points. nuke = [] # Traverse the contact results. Destroy bodies that # are touching heavier bodies. body_pairs = [(p.shape1.GetBody(), p.shape2.GetBody()) for p in self.points] for body1, body2 in body_pairs: mass1, mass2 = body1.GetMass(), body2.GetMass() if mass1 > 0.0 and mass2 > 0.0: if mass2 > mass1: nuke_body = body1 else: nuke_body = body2 if nuke_body not in nuke: nuke.append(nuke_body) # Destroy the bodies, skipping duplicates. for b in nuke: print "Nuking:", b self.world.DestroyBody(b) nuke = None super(CollisionProcessing, self).Step(settings) if __name__=="__main__": main(CollisionProcessing) python-box2d-2.0.2+svn20100109.244/testbed/test_ApplyForce.py0000644000000000000000000000665111136402204021605 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class ApplyForce (Framework): name="ApplyForce" body=None _pickle_vars=['body'] def __init__(self): super(ApplyForce, self).__init__() self.world.SetGravity((0.0, 0.0)) k_restitution = 0.4 bd=box2d.b2BodyDef() bd.position = (0.0, 20.0) ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.density = 0.0 sd.restitution = k_restitution sd.SetAsBox(0.2, 20.0, (-20.0, 0.0), 0.0) ground.CreateShape(sd) sd.SetAsBox(0.2, 20.0, (20.0, 0.0), 0.0) ground.CreateShape(sd) sd.SetAsBox(0.2, 20.0, (0.0, -20.0), 0.5 * box2d.b2_pi) ground.CreateShape(sd) sd.SetAsBox(0.2, 20.0, (0.0, 20.0), -0.5 * box2d.b2_pi) ground.CreateShape(sd) xf1 = box2d.b2XForm () xf1.R.Set(0.3524 * box2d.b2_pi) xf1.position = box2d.b2Mul(xf1.R, (1.0, 0.0)) sd1=box2d.b2PolygonDef() sd1.vertexCount = 3 sd1.setVertex(0, box2d.b2Mul(xf1, (-1.0, 0.0))) sd1.setVertex(1, box2d.b2Mul(xf1, (1.0, 0.0))) sd1.setVertex(2, box2d.b2Mul(xf1, (0.0, 0.5))) sd1.density = 2.0 xf2 = box2d.b2XForm () xf2.R.Set(-0.3524 * box2d.b2_pi) xf2.position = box2d.b2Mul(xf2.R, (-1.0, 0.0)) sd2=box2d.b2PolygonDef() sd2.vertexCount = 3 sd2.setVertex(0, box2d.b2Mul(xf2, (-1.0, 0.0))) sd2.setVertex(1, box2d.b2Mul(xf2, (1.0, 0.0))) sd2.setVertex(2, box2d.b2Mul(xf2, (0.0, 0.5))) sd2.density = 2.0 bd=box2d.b2BodyDef() bd.angularDamping = 2.0 bd.linearDamping = 0.1 bd.position = (0.0, 1.05) bd.angle = box2d.b2_pi self.body = self.world.CreateBody(bd) self.body.CreateShape(sd1) self.body.CreateShape(sd2) self.body.SetMassFromShapes() def Keyboard(self, key): if not self.body: return if key==K_w: f = self.body.GetWorldVector((0.0, -200.0)) p = self.body.GetWorldPoint((0.0, 2.0)) self.body.ApplyForce(f, p) elif key==K_a: self.body.ApplyTorque(20.0) elif key==K_d: self.body.ApplyTorque(-20.0) if __name__=="__main__": main(ApplyForce) python-box2d-2.0.2+svn20100109.244/testbed/test_BoxCutter.py0000644000000000000000000002351311144324535021465 0ustar rootroot#!/usr/bin/python # # Original C++ version by Daid # http://www.box2d.org/forum/viewtopic.php?f=3&t=1473 # # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class BoxCutter (Framework): name="BoxCutter" laserBody=None _pickle_vars=['laserBody'] def __init__(self): super(BoxCutter, self).__init__() self.world.GetGroundBody().SetUserData("ground") bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) bd.userData = "ground1" ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) ground.CreateShape(sd) bd=box2d.b2BodyDef() bd.position = (0.0, 50.0) bd.userData = "ground2" ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) ground.CreateShape(sd) bd=box2d.b2BodyDef() bd.position = (0.0, 1.0) bd.userData = "laser" self.laserBody = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(5.0, 1.0) sd.density = 4.0 self.laserBody.CreateShape(sd) self.laserBody.SetMassFromShapes() sd=box2d.b2PolygonDef() sd.SetAsBox(3.0, 3.0) sd.density = 5.0 bd=box2d.b2BodyDef() bd.userData = 1 bd.position = (0.0, 8.0) body1 = self.world.CreateBody(bd) body1.CreateShape(sd) body1.SetMassFromShapes() sd=box2d.b2PolygonDef() sd.SetAsBox(3.0, 3.0) sd.density = 5.0 bd=box2d.b2BodyDef() bd.userData = 1 bd.position = (0.0, 8.0) body1 = self.world.CreateBody(bd) body1.CreateShape(sd) body1.SetMassFromShapes() # Split a shape through a segment # Returns: # False - Error on split # True - Normal result is two new shape definitions. def SplitShape(self, shape, segment, splitSize, newPolygon): b = shape.GetBody() xf = b.GetXForm() hit,lambda_,normal=shape.TestSegment(xf, segment, 1.0) if hit != box2d.e_hitCollide: return False entryPoint = (1-lambda_)*segment.p1+lambda_*segment.p2 reverseSegment=box2d.b2Segment() reverseSegment.p1=segment.p2 reverseSegment.p2=segment.p1 hit,lambda_,normal=shape.TestSegment(xf, reverseSegment, 1.0) if hit != box2d.e_hitCollide: return False exitPoint = (1-lambda_)*reverseSegment.p1+lambda_*reverseSegment.p2 localEntryPoint = b.GetLocalPoint(entryPoint) localExitPoint = b.GetLocalPoint(exitPoint) vertices = shape.getVertices_b2Vec2() cutAdded = [-1,-1] last = -1 for i in range(shape.GetVertexCount()): #Find out if this vertex is on the old or new shape. if box2d.b2Dot(box2d.b2Cross(localExitPoint-localEntryPoint, 1), vertices[i]-localEntryPoint) > 0: n = 0 else: n = 1 if last != n: #If we switch from one shape to the other add the cut vertices. if last == 0: assert(cutAdded[0]==-1) cutAdded[0] = newPolygon[last].vertexCount newPolygon[last].setVertex(newPolygon[last].vertexCount, localExitPoint) newPolygon[last].vertexCount+=1 newPolygon[last].setVertex(newPolygon[last].vertexCount, localEntryPoint) newPolygon[last].vertexCount+=1 elif last == 1: assert(cutAdded[last]==-1) cutAdded[last] = newPolygon[last].vertexCount newPolygon[last].setVertex(newPolygon[last].vertexCount, localEntryPoint) newPolygon[last].vertexCount+=1 newPolygon[last].setVertex(newPolygon[last].vertexCount, localExitPoint) newPolygon[last].vertexCount+=1 newPolygon[n].setVertex(newPolygon[n].vertexCount, vertices[i]) newPolygon[n].vertexCount+=1 last = n #Add the cut in case it has not been added yet. if cutAdded[0]==-1: cutAdded[0] = newPolygon[0].vertexCount newPolygon[0].setVertex(newPolygon[0].vertexCount, localExitPoint) newPolygon[0].vertexCount+=1 newPolygon[0].setVertex(newPolygon[0].vertexCount, localEntryPoint) newPolygon[0].vertexCount+=1 if cutAdded[1]==-1: cutAdded[1] = newPolygon[1].vertexCount newPolygon[1].setVertex(newPolygon[1].vertexCount, localEntryPoint) newPolygon[1].vertexCount+=1 newPolygon[1].setVertex(newPolygon[1].vertexCount, localExitPoint) newPolygon[1].vertexCount+=1 # Cut based on the split size for n in range(2): if cutAdded[n] > 0: offset = newPolygon[n].getVertex(cutAdded[n]-1) - newPolygon[n].getVertex(cutAdded[n]) else: offset = newPolygon[n].getVertex(newPolygon[n].vertexCount-1) - newPolygon[n].getVertex(0) offset.Normalize() newPolygon[n].setVertex(cutAdded[n], newPolygon[n].getVertex(cutAdded[n]) + splitSize * offset) if cutAdded[n] < newPolygon[n].vertexCount-2: offset = newPolygon[n].getVertex(cutAdded[n]+2) - newPolygon[n].getVertex(cutAdded[n]+1) else: offset = newPolygon[n].getVertex(0) - newPolygon[n].getVertex(newPolygon[n].vertexCount-1) offset.Normalize() newPolygon[n].setVertex(cutAdded[n]+1, newPolygon[n].getVertex(cutAdded[n]+1) + splitSize * offset) #Check if the new shapes are not too tiny. for n in range(2): for i in range(newPolygon[n].vertexCount): for j in range(newPolygon[n].vertexCount): if i != j and (newPolygon[n].getVertex(i) - newPolygon[n].getVertex(j)).Length() < 0.1: return False # Make sure the shapes are valid before creation try: for n in range(2): box2d.b2CheckPolygonDef(newPolygon[n]) except ValueError, s: print "Created bad shape:", s return False return True def Cut(self): segmentLength = 30.0 segment=box2d.b2Segment() laserStart=(5.0-0.1,0.0) laserDir =(segmentLength,0.0) segment.p1 = self.laserBody.GetWorldPoint(laserStart) segment.p2 = segment.p1 + self.laserBody.GetWorldVector(laserDir) max_shapes = 64 count, shapes = self.world.Raycast(segment, max_shapes, False, None) for i in range(count): #Make sure it's a polygon, we cannot cut circles. if shapes[i].GetType() != box2d.e_polygonShape: continue polyShape = shapes[i].getAsType() b = polyShape.GetBody() #Custom check to make sure we don't cut stuff we don't want to cut. if b.GetUserData() != 1: continue #return if we cannot pass trough uncutable shapes. pd=[box2d.b2PolygonDef(),box2d.b2PolygonDef()] pd[0].density = 5.0 pd[1].density = 5.0 if self.SplitShape(polyShape, segment, 0.1, pd): b.DestroyShape(shapes[i]) b.CreateShape(pd[0]) b.SetMassFromShapes() b.WakeUp() bd=box2d.b2BodyDef() bd.userData = 1 bd.position = b.GetPosition() bd.angle = b.GetAngle() newBody = self.world.CreateBody(bd) newBody.CreateShape(pd[1]) newBody.SetMassFromShapes() newBody.SetAngularVelocity(b.GetAngularVelocity()) newBody.SetLinearVelocity(b.GetLinearVelocity()) def Keyboard(self, key): if key==K_c: self.Cut() def Step(self, settings): super(BoxCutter, self).Step(settings) if not self.laserBody: return self.DrawStringCR("Keys: Cut = c") segmentLength = 30.0 segment=box2d.b2Segment() laserStart=(5.0-0.1,0.0) laserDir =(segmentLength,0.0) segment.p1 = self.laserBody.GetWorldPoint(laserStart) segment.p2 = segment.p1+self.laserBody.GetWorldVector(laserDir) laserColor=box2d.b2Color(1,0,0) self.debugDraw.DrawSegment(segment.p1,segment.p2,laserColor) if __name__=="__main__": main(BoxCutter) python-box2d-2.0.2+svn20100109.244/testbed/test_EdgesBuoyancy.py0000644000000000000000000002255211135471136022311 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class EdgesBuoyancy (Framework): name="EdgesBuoyancy" def __init__(self): super(EdgesBuoyancy, self).__init__() bcd = box2d.b2BuoyancyControllerDef() bcd.offset = 15 bcd.normal = (0,1) bcd.density = 2 bcd.linearDrag = 2 bcd.angularDrag = 1 print bcd self.bc = self.world.CreateController(bcd) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) body = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) body.CreateShape(sd) sd1=box2d.b2CircleDef() sd1.radius = 0.5 sd1.localPosition = (-0.5, 0.5) sd1.density = 2.0 sd2=box2d.b2CircleDef() sd2.radius = 0.5 sd2.localPosition = (0.5, 0.5) sd2.density = 0.0 # massless for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x + 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() self.bc.AddBody(body) sd1=box2d.b2PolygonDef() sd1.SetAsBox(0.25, 0.5) sd1.density = 2.0 sd2=box2d.b2PolygonDef() sd2.SetAsBox(0.25, 0.5, (0.0, -0.5), 0.5 * box2d.b2_pi) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x - 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() self.bc.AddBody(body) xf1=box2d.b2XForm() xf1.R.Set(0.3524 * box2d.b2_pi) xf1.position = box2d.b2Mul(xf1.R, (1.0, 0.0)) sd1=box2d.b2PolygonDef() sd1.vertexCount = 3 sd1.setVertex(0, box2d.b2Mul(xf1, (-1.0, 0.0))) sd1.setVertex(1, box2d.b2Mul(xf1, (1.0, 0.0))) sd1.setVertex(2, box2d.b2Mul(xf1, (0.0, 0.5))) sd1.density = 2.0 xf2=box2d.b2XForm() xf2.R.Set(-0.3524 * box2d.b2_pi) xf2.position = box2d.b2Mul(xf2.R, (-1.0, 0.0)) sd2=box2d.b2PolygonDef() sd2.vertexCount = 3 sd2.setVertex(0, box2d.b2Mul(xf2, (-1.0, 0.0))) sd2.setVertex(1, box2d.b2Mul(xf2, (1.0, 0.0))) sd2.setVertex(2, box2d.b2Mul(xf2, (0.0, 0.5))) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x, 2.05 + 2.5 * i) bd.angle = 0.0 body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() self.bc.AddBody(body) sd_bottom=box2d.b2PolygonDef() sd_bottom.SetAsBox( 1.5, 0.15 ) sd_bottom.density = 4.0 sd_left=box2d.b2PolygonDef() sd_left.SetAsBox(0.15, 2.7, (-1.45, 2.35), 0.2) sd_left.density = 4.0 sd_right=box2d.b2PolygonDef() sd_right.SetAsBox(0.15, 2.7, (1.45, 2.35), -0.2) sd_right.density = 4.0 bd=box2d.b2BodyDef() bd.position = ( 0.0, 2.0 ) body = self.world.CreateBody(bd) body.CreateShape(sd_bottom) body.CreateShape(sd_left) body.CreateShape(sd_right) body.SetMassFromShapes() self.bc.AddBody(body) loop1=[ (0.063134534,8.3695248), (0.94701801,9.3165428), (0.0,9.0640047), (-0.12626907,10.326695), (1.4520943,11.77879), (2.2728432,10.137292), (2.3991123,11.147444), (3.5986685,10.958041), (3.9143411,7.3593722), (4.1668793,9.4428119), (5.4295699,9.3165428), (6.2503189,8.3063903), (6.6922606,10.137292), (4.9876282,9.8216191), (4.7350901,10.958041), (7.2604714,11.652521), (10.732871,11.147444), (10.480333,10.642368), (10.732871,9.8216191), (11.55362,9.4428119), (12.374369,9.3796773), (13.005714,9.8216191), (13.195118,10.38983), (13.005714,10.768637), (12.626907,10.894906), (12.753176,11.526252), (13.573925,11.715655), (14.836616,11.399982), (16.351844,10.768637), (17.867073,11.399982), (17.803939,10.263561), (17.361997,8.3063903), (17.803939,8.1801212), (18.056477,9.5059464), (18.182746,11.336848), (18.561553,11.210579), (18.561553,9.6322155), (18.561553,7.7381795), (18.687822,5.5284708), (19.382302,5.6547398), (19.066629,8.1801212), (19.003495,10.263561), (19.066629,11.463117), (19.887378,11.841924), (20.708127,11.273713), (21.0238,10.011023), (20.708127,7.2962377), (21.086934,6.2860852), (21.150069,3.7607038), (20.392455,2.5611476), (18.624688,2.5611476), (20.771262,2.1192059), (20.771262,0.22516988), (18.624688,-0.2799064), (13.826463,0.16203534), (14.015867,1.7403987), (13.195118,2.1823404), (12.626907,1.5509951), (12.879445,0.85651522), (12.626907,0.35143895), (10.543467,1.298457), (11.490485,3.9501074), (13.889598,3.6344347), (13.889598,2.9399549), (14.584077,3.8869729), (11.932427,5.2127981), (9.7227183,4.0132419), (10.796005,3.5081657), (9.7858528,3.2556275), (10.796005,2.4980131), (7.9549513,1.7403987), (9.6595837,1.424726), (9.217642,0.66711162), (8.270624,-0.090502792), (7.0079333,0.85651522), (6.1240498,-0.15363733), (6.1240498,3.192493), (5.6821081,2.4348786), (4.9876282,2.1192059), (4.1037447,1.8666678), (3.0304576,1.8666678), (2.0834396,2.245475), (1.6414979,2.6242822), (1.3258252,3.5081657), (1.2626907,0.47770802), (0.63134534,0.035766276), (0.063134534,0.9827842), ] loop2 = [ (8.270624,6.1598161), (8.270624,5.3390672), (8.7757003,5.086529), (9.4701801,5.5284708), (9.217642,6.033547), (8.7757003,6.412354), ] b2Loop1 = [(loop[0] + 10.0, loop[1]+1.0) for loop in loop1] b2Loop2 = [(loop[0] - 10.0, loop[1]) for loop in loop2] b2Loop1.reverse() bd=box2d.b2BodyDef() bd.position = ( 0.0, 0.0 ) body = self.world.CreateBody(bd) weight=box2d.b2CircleDef() weight.filter.maskBits = 0 weight.density = 4.0 weight.radius = 0.5 weight.localPosition = (8.9, 5.75) body.CreateShape(weight) edgeDef=box2d.b2EdgeChainDef() edgeDef.setVertices(b2Loop2) body.CreateShape(edgeDef) body.SetMassFromShapes() #self.bc.AddBody(body) # edges and buoyancy aren't quite working yet # you can uncomment this and see what happens body = self.world.CreateBody(bd) weight.radius = 5.0 weight.localPosition = (20.5, 7.0) body.CreateShape(weight) edgeDef.setVertices(b2Loop1) body.CreateShape(edgeDef) body.SetMassFromShapes() #self.bc.AddBody(body) if __name__=="__main__": main(EdgesBuoyancy) python-box2d-2.0.2+svn20100109.244/testbed/cairo_main.glade0000644000000000000000000006071511157660415021245 0ustar rootroot 640 480 800 600 True True True True True True True True True True GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK True True True Hertz: GTK_JUSTIFY_RIGHT True True 5 5 200 1 10 0 False False 1 False False True False 4 1 True True Position Iterations: True True 1 1 500 1 10 0 False False 1 False False 2 True True Velocity Iterations: True True 0 0 100 1 10 0 False False 1 False False 3 True False 4 4 True 0 GTK_SHADOW_NONE True 12 True True True Shapes 0 True True True Joints 0 True 1 True True Controllers 0 True 2 True True Core Shapes 0 True 3 True True AABBs 0 True 4 True True OBBs 0 True 5 True True Pairs 0 True 6 True True Center of Masses 0 True 7 True <b>Draw</b> True label_item False False 5 True False 4 6 True True Draw with Antialiasing 0 True False False 7 True False 4 8 True True True True 0 True True gtk-media-play True Play 1 True True True 0 True True gtk-media-pause True Pause 1 1 True True True 0 True True gtk-media-next True Step 1 2 False False 9 True False 4 10 True True True True You can access the "framework" and "world" variables Open Python Console 0 False False 11 False False 4 1 True 2 False 1 python-box2d-2.0.2+svn20100109.244/testbed/test_SphereStack.py0000644000000000000000000000435311135461416021763 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class SphereStack (Framework): name="SphereStack" bodies = [ ] e_count = 10 _pickle_vars=['bodies'] def __init__(self): super(SphereStack, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2CircleDef() sd.radius = 1.0 sd.density = 1.0 for i in xrange(self.e_count): bd=box2d.b2BodyDef() bd.position = (0.0, 2.0 + 3.0 * i) self.bodies.append( self.world.CreateBody(bd) ) self.bodies[-1].CreateShape(sd) self.bodies[-1].SetMassFromShapes() def Step(self, settings): #for body in self.bodies: # print "%g " % body.GetWorldCenter().y, #for body in self.bodies: # print "%g " % body.GetLinearVelocity().y, #print "" super(SphereStack, self).Step(settings) if __name__=="__main__": main(SphereStack) python-box2d-2.0.2+svn20100109.244/testbed/test_ElasticBody.py0000644000000000000000000003773311135461416021761 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * import math class ElasticBody (Framework): name="ElasticBody" bodies=[] ground=None elev=None joint_elev=None _pickle_vars=['bodies', 'ground', 'elev', 'joint_elev'] def __init__(self): super(ElasticBody, self).__init__() # Bottom static body sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 2.0) sd.friction = 0.1 sd.restitution = 0.1 bd=box2d.b2BodyDef() bd.position = (-1.0, -7.5) self.ground = self.world.CreateBody(bd) self.ground.CreateShape(sd) # Upper static body sd=box2d.b2PolygonDef() sd.SetAsBox(20.0, 0.50,(0,0),0.047*box2d.b2_pi) sd.friction = 0.01 sd.restitution = 0.001 bd=box2d.b2BodyDef() bd.position = (-20, 93.0) g = self.world.CreateBody(bd) g.CreateShape(sd) sd.SetAsBox(15, 0.50,(-15.0,12.5),0.0) g.CreateShape(sd) sd.SetAsBox(20,0.5,(0.0,-25.0),-0.5) g.CreateShape(sd) # Left channel left wall sd=box2d.b2PolygonDef() sd.SetAsBox(0.7, 55.0) sd.friction = 0.1 sd.restitution = 0.1 bd=box2d.b2BodyDef() bd.position = (-49.3, 50.0) g = self.world.CreateBody(bd) g.CreateShape(sd) # Right wall sd=box2d.b2PolygonDef() sd.SetAsBox(0.7, 55.0) sd.friction = 0.1 sd.restitution = 0.1 bd=box2d.b2BodyDef() bd.position = (45, 50.0) g = self.world.CreateBody(bd) g.CreateShape(sd) # Left channel right upper wall sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 20.0) sd.friction = 0.05 sd.restitution = 0.01 bd=box2d.b2BodyDef() bd.position = (-42.0, 70.0) bd.angle = -0.03*box2d.b2_pi g = self.world.CreateBody(bd) g.CreateShape(sd) # Left channel right lower wall sd=box2d.b2PolygonDef() sd.SetAsBox(0.50, 23.0) sd.friction = 0.05 sd.restitution = 0.01 bd=box2d.b2BodyDef() bd.position = (-44.0, 27.0) g = self.world.CreateBody(bd) g.CreateShape(sd) # Bottom motors cd=box2d.b2CircleDef() cd.radius = 3.0 cd.density = 15.0 cd.friction = 1 cd.restitution = 0.2 # 1. bd.position = (-40.0,2.5) body = self.world.CreateBody(bd) body.CreateShape(cd) body.SetMassFromShapes() jr=box2d.b2RevoluteJointDef() jr.Initialize (g,body,body.GetWorldCenter()+(0,1)) jr.maxMotorTorque = 30000 jr.enableMotor = True jr.motorSpeed = 20 self.world.CreateJoint(jr).getAsType() # 1. left down bd.position = (-46.0,-2.5) cd.radius = 1.5 jr.motorSpeed = -20 body = self.world.CreateBody(bd) body.CreateShape(cd) sd.SetAsBox(2.0, 0.50) body.CreateShape(sd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()) self.world.CreateJoint(jr).getAsType() # 2. cd.radius = 3.0 jr.motorSpeed = 20 bd.position = (-32.0,2.5) body = self.world.CreateBody(bd) body.CreateShape(cd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()+(0,1)) self.world.CreateJoint(jr).getAsType() # 3. jr.motorSpeed = 20 bd.position = (-24.0,1.5) body = self.world.CreateBody(bd) body.CreateShape(cd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()+(0,1)) self.world.CreateJoint(jr).getAsType() # 4. bd.position = (-16.0,0.8) body = self.world.CreateBody(bd) body.CreateShape(cd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()+(0,1)) self.world.CreateJoint(jr).getAsType() # 5. bd.position = (-8.0,0.5) body = self.world.CreateBody(bd) body.CreateShape(cd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()+(0,1)) self.world.CreateJoint(jr).getAsType() # 6. bd.position = (0.0,0.1) body = self.world.CreateBody(bd) body.CreateShape(cd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()+(0,1)) self.world.CreateJoint(jr).getAsType() # 7. bd.position = (8.0,-0.5) body = self.world.CreateBody(bd) body.CreateShape(cd) sd.SetAsBox(3.7, 0.5) body.CreateShape(sd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()+(0,1)) self.world.CreateJoint(jr).getAsType() # 8. right rotator sd.SetAsBox(5, 0.5) sd.density = 2.0 bd.position = (18.0,1) rightmotor = self.world.CreateBody(bd) # rightmotor.CreateShape(sd) sd.SetAsBox(4.5, 0.5, (0,0),box2d.b2_pi/3) rightmotor.CreateShape(sd) sd.SetAsBox(4.5, 0.5, (0,0),box2d.b2_pi*2/3) rightmotor.CreateShape(sd) cd.radius = 4.2 rightmotor.CreateShape(cd) rightmotor.SetMassFromShapes() jr.Initialize (g,rightmotor,rightmotor.GetWorldCenter()) jr.maxMotorTorque = 70000 jr.motorSpeed = -4 self.world.CreateJoint(jr).getAsType() # 9. left rotator sd.SetAsBox(8.5, 0.5) sd.density = 2.0 bd.position = (-34.0,17) body = self.world.CreateBody(bd) body.CreateShape(sd) sd.SetAsBox(8.5, 0.5, (0,0),box2d.b2_pi*.5) body.CreateShape(sd) cd.radius = 7 cd.friction = 0.9 body.CreateShape(cd) body.SetMassFromShapes() jr.Initialize (g,body,body.GetWorldCenter()) jr.maxMotorTorque = 100000 jr.motorSpeed = -5 self.world.CreateJoint(jr).getAsType() # big compressor sd.SetAsBox(3.0,4) sd.density = 10.0 bd.position = (-16.0,17) hammerleft = self.world.CreateBody(bd) hammerleft.CreateShape(sd) hammerleft.SetMassFromShapes() jd=box2d.b2DistanceJointDef() jd.Initialize(body, hammerleft, body.GetWorldCenter()+(0,6), hammerleft.GetWorldCenter() ) self.world.CreateJoint(jd).getAsType() bd.position = (4.0,17) hammerright = self.world.CreateBody(bd) hammerright.CreateShape(sd) hammerright.SetMassFromShapes() jd.Initialize(body, hammerright, body.GetWorldCenter()-(0,6), hammerright.GetWorldCenter() ) self.world.CreateJoint(jd).getAsType() # pusher sd.SetAsBox(6,0.75) bd.position = (-21.0,9) pusher = self.world.CreateBody(bd) # pusher.CreateShape(sd) sd.SetAsBox(2,1.5,(-5,0),0) pusher.SetMassFromShapes() pusher.CreateShape(sd) jd.Initialize(rightmotor,pusher,rightmotor.GetWorldCenter()+(-8.0,0), pusher.GetWorldCenter()+(5.0,0) ) self.world.CreateJoint(jd).getAsType() # Static bodies above motors sd=box2d.b2PolygonDef() cd=box2d.b2CircleDef() sd.SetAsBox(9.0, 0.5) sd.friction = 0.05 sd.restitution = 0.01 bd=box2d.b2BodyDef() bd.position = (-15.5, 12) bd.angle = 0.0 g = self.world.CreateBody(bd) g.CreateShape(sd) sd.SetAsBox(8, 0.5, (23,0),0) g.CreateShape(sd) # compressor statics sd.SetAsBox(7.0, 0.5, (-2,9),0) g.CreateShape(sd) sd.SetAsBox(9.0, 0.5, (22,9),0) g.CreateShape(sd) sd.SetAsBox(19.0, 0.5, (-9,15),-0.05) g.CreateShape(sd) sd.SetAsBox(4.7, 0.5, (15,11.5),-0.5) g.CreateShape(sd) # below compressor sd.SetAsBox(26.0, 0.3, (17,-4.4),-0.02) g.CreateShape(sd) cd.radius = 1.0 cd.friction = 1.0 cd.localPosition = (29,-6) g.CreateShape(cd) cd.radius = 0.7 cd.localPosition = (-2,-4.5) g.CreateShape(cd) # Elevator bd=box2d.b2BodyDef() cd=box2d.b2CircleDef() sd=box2d.b2PolygonDef() bd.position = (40.0,4.0) self.elev = self.world.CreateBody(bd) sd.SetAsBox(0.5, 2.5,(3.0,-3.0), 0) sd.density = 1 sd.friction = 0.01 self.elev.CreateShape(sd) sd.SetAsBox(7.0, 0.5, (-3.5,-5.5), 0) self.elev.CreateShape(sd) sd.SetAsBox(0.5, 2.5, (-11,-3.5), 0) self.elev.CreateShape(sd) self.elev.SetMassFromShapes() jp=box2d.b2PrismaticJointDef() jp.Initialize(self.ground,self.elev, bd.position, (0.0, 1.0)) jp.lowerTranslation = 0.0 jp.upperTranslation = 100.0 jp.enableLimit = True jp.enableMotor = True jp.maxMotorForce = 10000 jp.motorSpeed = 0 self.joint_elev = self.world.CreateJoint(jp).getAsType() # Korb sd.SetAsBox(2.3, 0.5,(1,0.0), 0.0) sd.density = 0.5 bd.position = (29.0,6.5) body = self.world.CreateBody(bd) # body.CreateShape(sd) sd.SetAsBox(2.5, 0.5,(3.0,-2), box2d.b2_pi/2) body.CreateShape(sd) sd.SetAsBox(4.6, 0.5,(7.8,-4.0), 0) body.CreateShape(sd) sd.SetAsBox(0.5, 4.5,(12,0.0), 0) body.CreateShape(sd) sd.SetAsBox(0.5, 0.5,(13,4.0), 0) body.CreateShape(sd) cd.radius = 0.7 cd.density = 1 cd.friction = 0.01 cd.localPosition = (0,0) body.CreateShape(cd) body.SetMassFromShapes() jr=box2d.b2RevoluteJointDef() jr.Initialize(self.elev,body, bd.position) jr.enableLimit = True jr.lowerAngle = -0.2 jr.upperAngle = box2d.b2_pi*1.1 jr.collideConnected = True self.world.CreateJoint(jr).getAsType() # upper body exit sd.SetAsBox(14.0, 0.5,(-3.5,-10.0), 0.0) bd.position = (17.5,96.0) body = self.world.CreateBody(bd) body.CreateShape(sd) # "Elastic body" 64 bodies - something like a lin. elastic compound # connected via dynamic forces (springs) bodies = self.bodies for i in range(64): bodies.append(None) sd=box2d.b2PolygonDef() sd.SetAsBox(0.55, 0.55) sd.density = 1.5 sd.friction = 0.01 sd.filter.groupIndex = -1 startpoint=(30,20) bd=box2d.b2BodyDef() bd.isBullet = False bd.allowSleep = False for i in range(8): for j in range(8): bd.position = (j*1.02, 2.51 + 1.02 * i) bd.position += startpoint body = self.world.CreateBody(bd) bodies[8*i+j] = body body.CreateShape(sd) body.SetMassFromShapes() # Apply dynamic forces (springs) and check elevator state def Step(self, settings): bodies = self.bodies for i in range(8): for j in range(8): zero =(0.0,0.0) down =(0.0, -0.5) up =(0.0, 0.5) right=(0.5, 0.0) left =(-0.5, 0.0) ind = i*8+j indr = ind+1 indd = ind+8 spring = 500.0 damp = 5.0 if j<7: self.AddSpringForce((bodies[ind]),zero,(bodies[indr]),zero,spring, damp, 1.0) self.AddSpringForce((bodies[ind]),right,(bodies[indr]),left,0.5*spring, damp, 0.0) if i<7: self.AddSpringForce((bodies[ind]),zero,(bodies[indd]),zero,spring, damp, 1.0) self.AddSpringForce((bodies[ind]),up,(bodies[indd]),down,0.5*spring,damp,0.0) inddr = indd + 1 inddl = indd - 1 drdist = math.sqrt(2.0) if i < 7 and j < 7: self.AddSpringForce((bodies[ind]),zero,(bodies[inddr]),zero,spring, damp, drdist) if i < 7 and j > 0: self.AddSpringForce((bodies[ind]),zero,(bodies[inddl]),zero,spring, damp, drdist) indr = ind+2 indd = ind+8*2 if j<6: self.AddSpringForce((bodies[ind]),zero,(bodies[indr]),zero,spring, damp, 2.0) if i<6: self.AddSpringForce((bodies[ind]),zero,(bodies[indd]),zero,spring,damp,2.0) inddr = indd + 2 inddl = indd - 2 drdist = math.sqrt(2.0)*2.0 if i < 6 and j < 6: self.AddSpringForce((bodies[ind]),zero,(bodies[inddr]),zero,spring, damp, drdist) if i < 6 and j > 1: self.AddSpringForce((bodies[ind]),zero,(bodies[inddl]),zero,spring, damp, drdist) # Check if bodies are near elevator # Look if the body to lift is near the elevator p1 = bodies[0].GetWorldCenter() p2 = bodies[63].GetWorldCenter() # self.elev: elevator prism. joint e = self.elev.GetWorldCenter() + (0,7) # maybe not the best way to do it... # Bodies reached the elevator side if p1.x>e.x or p2.x>e.x: # go up if (p1.y= self.joint_elev.GetUpperLimit()-2: self.joint_elev.SetMotorSpeed(-15) #printf("lift goes down: %G\n",self.joint_elev.GetJointTranslation()) super(ElasticBody, self).Step(settings) # Add a spring force def AddSpringForce(self, bA, localA, bB, localB, k, friction, desiredDist): pA = bA.GetWorldPoint(localA) pB = bB.GetWorldPoint(localB) diff=pB - pA #Find velocities of attach points vA = bA.GetLinearVelocity() - box2d.b2Cross(bA.GetWorldVector(localA), bA.GetAngularVelocity()) vB = bB.GetLinearVelocity() - box2d.b2Cross(bB.GetWorldVector(localB), bB.GetAngularVelocity()) vdiff=vB-vA dx = diff.Normalize() #normalizes diff and puts length into dx vrel = vdiff.x*diff.x + vdiff.y*diff.y forceMag = -k*(dx-desiredDist) - friction*vrel diff *= forceMag bB.ApplyForce(diff, bA.GetWorldPoint(localA)) diff *= -1.0 bA.ApplyForce(diff, bB.GetWorldPoint(localB)) if __name__=="__main__": main(ElasticBody) python-box2d-2.0.2+svn20100109.244/testbed/test_ShapeEditing.py0000644000000000000000000000537011136402204022102 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class ShapeEditing (Framework): name="ShapeEditing" body=None shape1=None shape2=None _pickle_vars=['body', 'shape1', 'shape2'] def __init__(self): super(ShapeEditing, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) bodydef=box2d.b2BodyDef() bodydef.position = (0.0, 10.0) self.body = self.world.CreateBody(bodydef) sd=box2d.b2PolygonDef() sd.SetAsBox(4.0, 4.0, (0.0, 0.0), 0.0) sd.density = 10.0 self.shape1 = self.body.CreateShape(sd) self.body.SetMassFromShapes() self.shape2 = None def Keyboard(self, key): if not self.body: return if key==K_c: if not self.shape2: sd=box2d.b2CircleDef() sd.radius = 3.0 sd.density = 10.0 sd.localPosition = (0.5, -4.0) self.shape2 = self.body.CreateShape(sd) self.body.SetMassFromShapes() self.body.WakeUp() elif key==K_d: if self.shape2: self.body.DestroyShape(self.shape2) self.shape2 = None self.body.SetMassFromShapes() self.body.WakeUp() def Step(self, settings): self.DrawStringCR("Press: (c) create a shape, (d) destroy the shape") super(ShapeEditing, self).Step(settings) if __name__=="__main__": main(ShapeEditing) python-box2d-2.0.2+svn20100109.244/testbed/data/0000755000000000000000000000000011414467236017050 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/0000755000000000000000000000000011414467236020335 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/0000755000000000000000000000000011414467236021277 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/select.options.png0000644000000000000000000000026511130023047024740 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ(%¹tEXtCommentCreated with The GIMPïd%n+IDAT8Ëc` `d``øÿÿ?¥¦022QËE£4jШA£ ƒ¨;…,;)k“IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/menu.option.normal.png0000644000000000000000000000020311130023047025521 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ $¢3UQ"IDAT8Ëc¼rá5•À¨A£4jШA£‘:kœÆËºÜIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/box.normal.png0000644000000000000000000000034611130023047024046 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  0à©ötEXtCommentCreated with The GIMPïd%nJIDAT8Ëcd``øÏ@`b```øÿÿ?ÉØÁÁfÒÕ‹'‰¶u͆¨. Ø £Œ@©,Ø’'É8::’íFJ³3Å1ó]IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/Vera.ttf0000644000000000000000000020061411130023047022675 0ustar rootrootOS/2´_ôcëpVPCLTÑŠ^—ëÈ6cmap¤Ãè ±lXcvt ÿÓ9üüfpgmç´ñÄ&`‹gaspH glyf tAÏ&ìŠ~hdmx4ð!ìHheadÝ„¢ÐT6hheaEoëL$hmtx ÆŽ²´Ä0kernÜRÕ™½ -ŠlocaóËÒ=»„maxpG:ë, nameټȵßpost´Z/»¸ôŽprep;ñ øh::_:: dM0­l  ƒ p t › &   Y &  &   c . 5 ` õ s 0¡ & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5¸ËËÁªœ¦¸fqË ²…u¸Ãˉ-˦ðÓª‡ËªJ3ËÙôT´œ99N´R¸çÍ7sÍ`s3¢V¦V9Åɸßsºé3¼Dßͪåªˤ{¸o{RÇÍššoËÍžÓðºƒÕ˜HžÕÁËöƒT3fÓǤ͚sÕ þ+¤´œbœ-ÕÕÕð{T¤¸#Ӹ˦Ãì“ Ó\qÛ…#¨H99`Õš#fy```{œw`ªé`b{Å{´RÍf¼fwÍ;…‰{ÍJ/œœ}oo5jo{®²-–{öƒT7öœáföÍD)fîs¸€@ÿûþúù%ø2÷–öõþôþó%òñ–ð%ïŠAïþî–í–ìúëúêþé:èBçþæ2åäSå–äŠAäSãâ/ãúâ/áþàþß2ÞÝ–ÜþÛÚ}Ù»ØþÖŠAÖ}ÕÔGÕ}ÔGÓÒÓþÒÑþÐþÏþÎþÍ–ÌËÌþËÊ2ÉþÆ…ÆÅÄþÃþÂþÁþÀþ¿þ¾þ½þ¼þ»þº¹†%¹þ¸·»¸þ·¶]·»·€¶µ%¶]@ÿ¶@µ%´þ³–²þ±þ°þ¯þ®d­¬«%¬d«ª«%ª©ŠA©ú¨þ§þ¦þ¥¤þ£¢£2¢¡d ŠA –Ÿþž žþ œ›œd›š›š™ ˜þ—– —þ– •ŠA•–”“”(“’ú‘»‘þ]»€Ž%]@Ž%þŒ‹.Œþ‹.І%ŠA‰ˆ ‰ˆ ‡†%‡d†…†%…„þƒ‚ƒþ‚þ€þþ@ÿ~}}~þ}}|d{T{%zþyþxw v uþtúsúrúqúpþoþnþl!kþjBjSiþh}gBfþeþdþcþbþa:`ú^ ]þ[þZþYX YúX WW2VþUTUBTSSRQJQþP OþNMNþMLþKJKþJIJI IH GþF–E–DþC-CúB»AK@þ?þ>=>=<=<; <@ÿ; :þ9þ878ú76765 65 43 21 2þ1 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $þ#þ"!! dú d BþúBBþdþþþþBþ-B}dþ  þ   þ  þ-þdþ@-þ-þ¸d…++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++¶, °%Id°@QX ÈY!-,°%Id°@QX ÈY!-,  °P° y ¸ÿÿPXY°°%°%#á °P° y ¸ÿÿPXY°°%á-,KPX °ýEDY!-,°%E`D-,KSX°%°%EDY!!-,ED-fþ–f¤@ ûû/ÄÔì1ÔìÔì0!%!!füsüåþ–øòr)5Õ @@ƒ ü<ì2991/äüÌ0K° TX½ @ ÿÀ878Y¶ P ]%3#3#5ËËË¢þþÕýqþ›eŪéÕM@„üüÜì1ô<ì20K°TK°T[X½@ÿÀ878Y@0 @ P ` p   ¿ ]#!#oª$ªÕýÕ+ýÕ+ž¾`@1 ‡  ‡   üÌ91/<Ô<<ü<<Ô<<Ä2ì220@   ]!! !3!!!!#!#!5!!5!þÝT%Dh$i g8þ¡R>þ›h gþÛg¡hþÅ`Tþ¾if…þ²‡þaŸþašþ²™þbžþbž™NšŸªþÓm!(/Õ@U" '&( /)/))/B" ) *!††#Љ*Љ- ) " & 0ü<ìô<ü<ôäì1/äìÄÔäì2Äîî99990KSXíí9í9íY"K° TX½0@00ÿÀ878YK° TK°T[K°T[X½0ÿÀ00@878Y#.'5.546753.'>54&´diÒjfÑoÝÉÚÌd]®SS¯\ãÖãÖdtzqá{þÓ---´@AÈ$¬–£¼ëè¯*.þU#´œ©Ãš jXV`ÕþOnZXhqÿã)ð #'3•@6$%&%&'$'B’ ’.’$’ &Œ($‘4'!%   ! + 1 4üÄìôìîöî991ä2ô<äìîöîî0KSXííY"K° TK° T[K° T[K°T[K°T[K° T[X½4@44ÿÀ878Y"32654&'2#"&546"32654&%3#2#"&546ÑWccWUccUžº» º»ü—VcbWWcd1 üZ ž¼»ŸŸ¹º‘”„‚••‚ƒ•Ü»»ÛÛ»¼Ûa•‚„””„–ùó Û»½ÚÛ¼ºÜÿãþð 0Í@–  † †  † †††  !         B  (('•+•'”$‘Œ .  .'.'!!1üìÄÔÔìÆî99999991/ÆäöæîîÆ9990KSXíí9í9í9í9í9íí9í9ííí9Y"²2]@² " ) **&:4D ^YZ UZZY0g{›š™—• “••"™-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z““—•œœŸš › š 2 2°29]]3267 >73#'#"5467.54632.#"ò[UÔ _¦Iþ{ü;Bº h]ühäƒñþΆ†02Þ¸S¥UWžDiƒ;#Q¡X’Â?@ýøYËr„þþ~þã“YW×€ác?}<¢Å$$¶/1oX3gŪoÕB@ „üì1ôì0K°TK°T[X½@ÿÀ878Y@ @P`p ]#oªÕýÕ+°þò{ O@˜—  Üä2ì991üì0K°TX½@ÿÀ878YK°TX½ÿÀ@878Y#&547{†‚ƒ… –•”—æþ>ççþ;åëÆàßÄì¤þòo @˜— Ü<ôì991üì03#654¤ –••– …ƒƒìþ<ßàþ:ëåÅççÂ=JÃðN@,  ™ ™ ‘    Ô<ä2Ü<ä2991ôÔ<ì2Äì2990%#'%%73%Ãþ™g:þ°rþ°:gþ™:PrPßÂÃbËþ‡yËbÃÂcËyþ‡ËÙÛ #@ œ  Üü<ü<ì1/Ô<ü<Ä0!!#!5!®-ýÓ¨ýÓ-ýÓªýÓ-ª-žÿÃþ@ žƒüìÔÌ1üì073#ðÓ¤Rþ¬þÀ@d߃¶œÜÌ1Ôì0!!dý僤ۮþ·ƒüì1/ì073#ÛÓÓþþÿB²Õ-@BŸ/Ä991ôì0KSXííY"3#ªýøªÕùm‡ÿãð #@   ‘Œ üìôì1äôìî0"32'2#"‹œœû þ÷ûûþ÷ PþÍþÌþÍþÍ3343 þsþ†þ‡þsyzáZÕ K@B     ÔìÄüì1/ì2ôìÔì0KSXY"K°TX½ ÿÀ @878Y´]7!5%3!!þJþ™eÊJü¤ªsH¸HúÕª–Jð¥@'B¡”  ‘   üÄÔìÀÀ91/ì2ôìôì0KSXíí9Y"K°TK°T[K°T[X½@ÿÀ878Y@2UVVzzv‡tvust‚†‚‚‚¨¨]]%!!567>54&#"5>32‰ÁüLs3aM§†_ÓxzÔXèE[þôªªªw‘:m—Iw–BCÌ12èÂ\¥pþëœÿãsð({@. † †     “  “#‘Œ£)&  )üÄÄÔìôì991ìäôäìæîîîî90K°TK°T[X½)@))ÿÀ878Y@ daa d!]!"&'532654&+532654&#"5>32?‘£þÐþè^ÇjTÈm¾Ç¹¥®¶•ž£˜S¾rsÉYæ Ž%ÄÝò%%Ã12–„•¦wps{$&´ Ѳ|«d¤Õ Œ@   B     ÜÔ<Äì291/äÔ<ì290KSXÉÉY"K° TK° T[X½@ÿÀ878Y@* *HYiwŠ+&+6NO O Vfuz… ]] !33##!5þþ5þÕÕÉý^%üãÍü3¨þ `ÞÿãdÕu@#†  ‰   Œ¤  üÄÔìÄî1ääôìæîþÄî90K°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y!!>32!"&'532654&#"Ýý ,X,ú$þÔþï^ÃhZÀk­ÊÊ­Q¡TÕªþ’þîêñþõ Ë10¶œœ¶$&ÿã–ð $X@$ †   ¥  ‰"‘Œ% " !%üììôìä1äôäüäîîî90@ËËÍÍÍËˤ²]]"32654&.#">32# !2¤ˆŸŸˆˆŸŸ L›LÈÓ;²káþðâþýþîPL›;º¢¡»»¡¢ºy¸$&þòþïW]þïëæþêyb¥¨hÕc@B üÌÄ991/ôì0KSXííY"K°TX½@ÿÀ878Y@X9Hg°°]]!#!¨ÀýâÓþý3ÕVú+‹ÿã‹ð #/C@%  ' - ‘Œ'£0 $*$ !0üÄìôÄìîî991ìäôìîî990"32654&%&&54632#"$54632654&#"‹¥¥¦¥þ¥‚‘ÿÞßþ‘’£þ÷÷÷þ÷¤H‘ƒ‚““‚ƒ‘Åš‡‡š›†‡šV ²€³Ðг€² "ÆÙèèÙÆat‚‚tt‚‚ÿã‡ð$X@#†  ¥ ‰ ‘Œ%!"" %üìäôìì1äôìæþõîî90@ÄÂÀÀÀÂμé]]7532#"543 !"&2654&#"áLœKÈÓ:²làþûâþ±þåLœ>ˆŸŸˆˆŸŸ¸$& V\ëæþsþ†þŸþ[—º¢¡»»¡¢ºðÃ#@ƒ¦ƒü<ì21/ìôì073#3#ðÓÓÓÓþþ#þžÿÃ# %@ƒžƒ¦  ü<ì2ÔÌ1äüìî03#3#ðÓÓÓ¤R#þýÙ¬þÀ@Ù^Û¦M@*œœœœB¨§$#üì291ôì90KSXííííY" 5Ûûøúþðþ‘þ“¶ѦÑÙ`Û¢@ œœ#ü<Ä21ÔìÔì0!!!!Ùúþúþ¢¨ðªÙ^Û¦O@+œœœœB¨§$#ü<ì91ôì90KSXííííY"55Ùúþð¶þ/¦þ/¶m“°ð$p@+$  †ˆ•‘ƒ   &%ÜÄüìÔìî99991/îöþôîÍ9990K° TX½%@%%ÿÀ878Y¶y z z ]%3##546?>54&#"5>32‡ËËÅ¿8ZZ93ƒlO³a^Ág¸ßHZX/'þþ‘še‚VY5^1YnFC¼98ŸL‰VV/5<4‡þœq¢ L•@2  ©©L43¬0©7¬$©7CM34( (+(I+*(I,=MÜìüìþýþ<Æî991ÔÄüìþíÔÆÅî2Äî990K° TK° T[K°T[K°T[K°T[X½MÿÀMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32úŽ|{zy!<›g¬×Ø«gœ;’¥?@hþÕ°{â`±smiùhZ}þÙ˜¹þ¸€€†ˆ~R½Ôk{KOþÂþè£¤ŽŒ¥¤þHMIùÈÈúKLƒý ß±k¼Pƒ‹A@fþµÁŸþêjhmWQoagƒ}}I½¶J}‡® bæ{þùþÐhÕ º@A       B•    ÔÄ91/<äÔì90KSXííííííííY"² ]@:XvpŒ VXP ghxv|rwx‡ˆ€ ˜™–]] !3#!#¼þî%þ{å9Òˆý_ˆÕý®ú+þÉìÕ C@#• •• ­ . !üì2üìÔì9991/ììôìî90²"]!2654&#!2654&#%!2#!“D££þ¼+”‘‘”þ çú€|•¥þðûýèÉý݇‹Œ…fþ>orqp¦À±‰¢ ˘ÈÚsÿã'ð6@ ¡® •¡®•‘Œ 0üì2ì1äôìôìîöî0´].# !267# !2'fç‚ÿþð‚çfjí„þ­þz†S†íbÕ_^þÇþØþÙþÇ^_ÓHHŸghŸGɰÕ.@• •  2 üìôì99991/ìôì0²`]3 !%! )“ô5þáþËþBŸ²–þhþPþa/ûw.,¦þ—þ€þ~þ–É‹Õ .@•••­   üì2ÔÄÄ1/ììôìî0² ]!!!!!!ɰýÇý9øü>ÕªþFªýãªÉ#Õ )@••­ üì2ÔÄ1/ìôìî0² ]!!!!#ÉZýpPý°ÊÕªþHªý7sÿã‹ð9@ ••¡®•‘Œ43 üìüäüÄ1äôìôìþÔî990%!5!# !2&&# !26Ãþ¶uþæ þ¢þu‹^’opü‹þîþík¨Õ‘¦ýSU™mn™HF×_`þÎþÑþÒþÎ%É;Õ ,@•­ 8  üì2üì21/<ä2üì0²P ]3!3#!#ÉÊÞÊÊý"ÊÕýœdú+Çý9É“Õ9·¯üì1/ì0K°TX½ÿÀ@878Y@ 0@P`Ÿ]3#ÉÊÊÕú+ÿ–þf“Õ M@ •° 9 üìä991äüì990K°TX½ ÿÀ @878Y@ 0 @ P ` Ÿ ]3+53265ÉÊÍãM?†nÕú“þòôª–ÂÉjÕ ï@(B¯  üì2ÔÄ91/<ì290KSXííííY"²]@’ ((764GFCUgvwƒˆ”›ç    (+*66650 A@E@@@ b`hgwp ‹‹Ž š¶µÅÅ×Öèéèê÷øù,]q]q3! !#ÉÊžýþöý3ÊÕý‰wýHüãÏý1ÉjÕ%@ •:üìì1/äì0@ 0P€€]3!!ÉÊ×ü_ÕúÕªÉÕ ¿@4  B ¯   >  üìüì91/<Äì290KSXííííY"²p]@V   && & 45 i|{y €‚‚  #,'( 4<VY ej vy •›]]! !###É-}-ÅþËþÄÕüøú+üúáÉ3Õ y@B¯6 üìüì991/<ì2990KSXííY"² ]@068HGif€ FIWXeiy…Š•šŸ ]]!3!#É–ÄþðýjÄÕûáú+áûsÿãÙð #@•• ‘Œ 3üìüì1äôìî0"32' ! 'ÜþýÜÜþÿÜ:xþˆþÆþÅþ‡yLþ¸þåþæþ¸HH¤þ[þžþŸþ[¤bb¥ÉÕ:@••   ? üì2üì91/ôìÔì0@ ?_¯]32654&#%!2+#“þššþ8ÈûþÿûþÊ/ýÏ’‡†’¦ãÛÝâý¨sþøÙð R@*  B ••‘Œ    3üìüì9991Ääôìî990KSXíí9Y""32#'# ! 'ÜþýÜÜþÿ? ôÝ!#þÅþ‡y;:xÑLþ¸þåþæþ¸HHúÏþÝï¥ab¥þ[þžþüþŽÉTÕ±@5  B• •   ?  üì2üÄì99991/<ôìÔì9990KSXíí9Y"²@]@Bz%%%&'&&& 66FFhuuwˆˆ˜˜]]#.+#! 32654&#A{>ÍÙ¿J‹xÜÊÈüƒý‰þ’••’¼~þh–bý‰ÕÖØºOýƒ…‡ÿã¢ð'~@<    B ¡”••”%‘Œ( "-"(ÜÄìüìä99991äôäìîöîÆ90KSXí9í9Y"²)]¶)/)O)].#"!"&'532654&/.54$32HsÌ_¥³w¦zâ×þÝþçjï€{ìr­¼‡š{âÊõiÚ¤Å76€vce+Ù¶Ùà0/ÐEFˆ~n|-À«Æä&ÿúéÕJ@•@@Ôäüä1/ôì20K° TX½@ÿÀ878Y@  @ p Ÿ ]!!#!ïýîËýîÕªúÕ+²ÿã)ÕK@ •Œ  8Aüìüì1ä2ôì99990K°TX½@ÿÀ878Y¶Ÿ]332653! ²Ë®Ã®ËþßþæþåþßÕüuðÓÓð‹ü\þÜþÖ*$hÕ·@'B¯ÔÄ91/ì290KSXííííY"²P]@b*GGZ}ƒ *&&))% 833<<7HEEIIGYVfiizvvyyu€˜—)]]!3 3JýÆÓÙÚÒýÇÕûéú+D¦Õ {@I      B ¯    ÔÌ91/<ì2290KSXííííííííY"²]@ò  ($ >>4 0 LMB @ Yjkg ` {|€ –•     !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx  †‡ˆ‰… Š —Ÿ¯[]]3 3 3# #DÌ:9ã:9Íþ‰þþÅþÂþÕûîûîú+úð=;Õ ]@F      B ¯   ÔÄÜÄ91/<ì290KSXííííííííY"K° TK° T[K°T[X½ ÿÀ @878Y@¸ '' 486 KX[fkww †€‡‹… ”—–     &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x €€ƒˆ…„ƒ ”——•“ Ÿ ¯ @]]3 3 # #ÙsuÙþ Ùþ\þYÚÕýÕ+ý3üø{ý…ÿüçÕ”@(B¯@@ Ôäüä91/ì290KSXííííY"² ]@<5000F@@@QQQe„“ &)78@ ghxp Ÿ ]]3 3#Ùž›ÙýðËÕýšfüòý9Ç\Õ ›@B••B ÜÄÔä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878Y@@ )&8HGH    / 59? GJO UYfio wx Ÿ ]]!!!5!s•üPÇû=°ügÕšûoªš‘°þòXS@©²©±CÜüÌ21üìôì0K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y!#3!°¨ððþXùüÿB²Õ-@BŸ/Ä991ôì0KSXííY"#ªªýøÕùm“Çþòo<@©²©±Cü<Üì1üìôì0K°TK°T[X½ÿÀ@878Y!53#5oþXïïøÞÙ¨ÛÕ@ ÜÌ91ôÌ290##¼ÉþHþHÉÕýÓ‹þu-ÿìþþ¬µ©ÄÄ1Ôì0!5ûØþ¬ªð‰f1@ ´³DÜì1ôì0K° TK°T[X½ÿÀ@878Y #o™þºfþŠv{ÿã-{ %¼@'  ©¹ †º¹#¸Œ   E&üìÌÔì22991/ÄäôüôìÆîî9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p'…‡‡‡ ‡!…"' 'ð'000 0!@@@ @!PPP P!``` `!ppp p!€€€ €!]]"326=7#5#"&5463!54&#"5>32¾ß¬o™¹¸¸?¼ˆ¬Ëýû§—`¶Te¾Zóð3f{bsÙ´)LýªfaÁ¢½À‹..ª''üºÿ㤠8@¹  ¹Œ¸—G Füì22ôì1/ìäôÄìÆî0¶`€ ]4&#"326>32#"&'#3å§’’§§’’§ýŽ:±{ÌÿÿÌ{±:¹¹/ËççËËççRdaþ¼þøþøþ¼ad¨qÿãç{?@†ˆ† ˆ ¹¹¸Œ HEüä2ì1äôìþôîõî0@ € ].#"3267#"!2çNP³ÆÆ³PNM¥]ýþÖ-U¢5¬++ãÍÍã++ª$$>:#qÿãZ8@¹¹Œ¸—G Eüìôì221/ìäôÄìÄî0¶`€ ]3#5#"3232654&#"¢¸¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶^ùì¨daDDaþËççËËççqÿã{p@$ †ˆ©¹ »¹¸ ŒKEüìôìÄ91äôìäîîôî90@)?p Ðð?????,// , ooooo ]q]!3267# 32.#"ü² Í·jÇbcÐkþôþÇ)ü⸥ˆš¹^Z¾Ç44®*,8 CþÝÄ—´®ž/øp@ ©‡—¼    Lü<Äü<ÄÄ991/ä2üìî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y¶@P ]#"!!##535463ø°cM/þѹ°°®½™Phcü/ÑN»«qþVZ{ (J@#  †¹¹&#¸'¼ ¹½& G E)üÄìôì221/ÄäìäôÄìþÕî990¶`*€* *]4&#"326!"&'5326=#"3253¢¥•”¥¥”•¥¸þþúa¬QQžRµ´9²|ÎüüÎ|²9¸=ÈÜÜÈÇÜÜëþâþé³,*½¿[cb::bcªºd4@ ‡¸ — N  Füì2ôì1/<ìôÄì90²`]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡ýžedïÁy+@¾±¼Fü<ì21/äüì0@  @ P ` p ]3#3#Á¸¸¸¸`û éÿÛþVy D@ ¾ ‡½¼ ±O  Fü<ì2ä991ìäôìî990@ @P`p]3+532653#Á¸£µF1iL¸¸`ûŒÖÀœa™(麜 ¼@)B¼— F üì2ÔÄ91/<ìä90KSXííííY"² ]@_ ')+Vfgsw‚‰Ž“–—£    ('(++@ h` ‰…‰š—ª§¶ÅÖ÷ð÷ð]q]33 ##º¹%ëý®kðýǹüiãýôý¬#ýÝÁy"·—Füì1/ì0@ @P`pð]3#Á¸¸ùìº{"Z@&  ‡ ¸¼PPF#üì2üüüì91/<<äô<Äì290@0$P$p$$ $ $¿$ß$ÿ$ ]>32#4&#"#4&#"#3>32)EÀ‚¯¾¹ru¦¹rw¦¹¹?°yz«‰|võâý\ž¡œ¾¤ý‡ž¢›¿£ý‡`®gb|ºd{6@ ‡¸ ¼ N  Füì2ôì1/<äôÄì90´`Ï]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡`®edïqÿãu{ J@¹¹ ¸Œ QEüìôì1äôìî0@#?{{   {  { ð]"32654&'2#"s”¬«•“¬¬“ðþîðñþïßçÉÉçèÈÇéœþÈþìþíþÇ98ºþV¤{>@¹¹¸Œ½¼ GFüì22ôì1äääôÄìÄî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý® ªdaþ¼þøþøþ¼aëËççËËççqþVZ{ >@¹  ¹¸Œ½¼ GEüìôì221äääôÄìÆî0@ `€ à]32654&#"#"3253#/§’’¨¨’’§s:±|ËÿÿË|±:¸¸/ËççËËççý®daDDadªùöºJ{0@  ‡¸ ¼ FüÄì21/äôìÄÔÌ90´PŸ].#"#3>32JI,œ§¹¹:º….´˾ý²`®fcoÿãÇ{'ç@<  S  SB †‰†‰¹¹%¸Œ( R"E(üÄìÔìä99991äôìþõîõî90KSXí9í9Y"²']@m   . , , , ; ; ; ; $( ( *//*(() )!$'† † † †      '/)?)_))€)) )ð)]]q.#"#"&'532654&/.54632‹N¨Z‰‰b”?Ä¥÷ØZÃlfÆa‚Œe«@«˜àÎf´?®((TT@I!*™‰œ¶##¾55YQKP%$•‚ž¬7òž8@©¼‡  Fü<Äü<Ä2991/ìô<Äì2990²¯]!!;#"&5#53w{þ…Ks½½Õ¢‡‡žþÂý ‰NšŸÒ`>®ÿãX`6@ ‡Œ ¼  NFüìôì21/ä2ôÄì90´`Ï]332653#5#"&®¸||•­¸¸C±uÁȺ¦ýaŸŸ¾¤{û ¬fcð=`@'B¿ÔÄ91/ì290KSXííííY"K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@ŽHj{†€‘¤  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz……‰‰‰†––—š˜˜—¨§°Àßÿ>]]3 3#=Ã^^Ãþ\ú`üT¬û V5` @IU U U U   B ¿    ÔÌ91/<ì2290KSXííííííííY"K° TK°T[K°T[K°T[K° T[X½ ÿÀ @878YK° TK° T[K°T[X½ @ ÿÀ878Y@ÿ" 5 IIF @ [[U P nnf yy‡™˜” ¼¼ÎÇÏ         %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } ‡ˆ——”“œ›˜˜™@/– Ÿ¦¦¤¤««©©«¤ ¯µ±½»¸ ¿ÄÃÌÊy]]333# #V¸æåÙæå¸þÛÙñòÙ`ü–jü–jû –üj;y` Z@F      B ¿  ÔÄÔÄ91/<ì290KSXííííííííY"K° TK°T[K°T[K°T[X½ ÿÀ @878YK°TX½ @ ÿÀ878Y@˜   & =1 UWX f vzvt ‚ ™Ÿ—’ ¦©¯¥£       )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x ›”«¤° Ï ß ÿ /]] # # 3 dþkªÙþºþºÙ³þrÙ))`ýßýÁ¸þHJþq=þV`¢@C        B  ‡½ ¼  ÔÄÄ91ä2ôì9990KSXíííííí2Y"K° TK°T[X½ÿÀ@878YK°TX½@ÿÀ878Y@ð     # 5 I O N Z Z j ‡ € “        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx‰Š … … ‰ ‰‰™ • • šš¤ ¤ ««°Ïßÿe]]+5326?3 3“N”|“lLT3!þ;Ã^^ÃhÈzšH†TNü”lXÛ` ´@B©¼© ÜÄ2Ä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878YK°TX½ ÿÀ @878Y@B&GI  + 690 @@E@@CWY_ ``f``b € ¯ ]]!!!5!qjýL´ü}´ýe`¨üÛ“¨%þ²$‚@4 %   ! © ©À ©±% $  C %Ô<Äü<Ä299999991üìÄôìî99999990K° TX½%ÿÀ%%@878Y²&]#"&=4&+5326=46;#"3>ù©lŽ==k©ù>DV[noZV¾”Ýï—ts•ðÝ“XøŽŽœøXþ®·±Ôì1üÌ0#®ªøþ²$ž@6%   ©©#À©±%#C %Ô<Ä2ü<Ä99999991üìÄôìî99999990K° TX½%@%%ÿÀ878YK°TX½%ÿÀ%%@878Y²&]326=467.=4&+532;#"+FŒUZooZUŒF?ù§lŽ>>Žl§ù?¾VøœŽŽøŽW“Ýð•st—ïÝ”ÙÓÛ1#@ œœ ÔÄ1ÔüÔìÀ990#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©1²OD;>MS²OE<>LÿÿhN'$¼uhm !Ë@T   !!  ! !!!B  Á • Ž  !  VV!"ÔÄÔì2Ôî299999991/<æÖîÔî9990KSXííííííííY"² #]@  s › P#f iu {yyv v!€# ]]4&#"326!.54632#!#TY?@WX??Y˜þð!þX=>Ÿsr¡?<Òˆý_ˆÕZ?YWA?XXþóýN)sIs ¡rFv)ú‹þÿÿsþu'ð'&Ý-ÿÿÉ‹k'(žuÿÿÉ3^'1þuÿÿsÿãÙN'2'uÿÿ²ÿã)N'8îuÿÿ{ÿã-f'DRÿÿ{ÿã-f'DCRÿÿ{ÿã-f'D×Rÿÿ{ÿã-'DŽRÿÿ{ÿã-7'DØRÿÿ{ÿã-'DÜRÿÿqþuç{'FÝÿÿqÿãf'H‹ÿÿqÿãf'HC‹ÿÿqÿãf'H׋ÿÿqÿã'HŽ‹ÿÿof'ÖÿÿÿÿǦf'ÖCÿÿÿÿÞ\f'Ö×ÿÿÿÿôF'ÖŽÿÿÿºd7'Qؘÿÿqÿãuf'Rsÿÿqÿãuf'RCsÿÿqÿãuf'R×sÿÿqÿãu'RŽsÿÿqÿãu7'RØsÿÿ®ÿãXf'X{ÿÿ®ÿãXf'XC{ÿÿ®ÿãXf'X×{ÿÿ®ÿãX'XŽ{9ÿ;ÇÕ '@¹  YW Y Ô<ìü<ì1äôÔ<ì203!!#!5!¨°oþ‘°þ‘oÕþ\™û£]™Ãu=ð  @ÃÄà ‘ Z[ZÜìüì1ôìüì0"32654&'2#"&546PnnPPnoO@v+..¹†‡´¸ooPOmmOOp1.-rB„·´‡†º¬þÇ#˜!Q@+  †ˆ †ˆ ¹ ¹¸Œ"  "ÜìÔ<Ô<<ì221äô<ÄìÄþôîõî9990%&&'667#&73¦“¤¤JˆDF‰HA‰Mfñþ÷ ñfI‰ƒX⸹⡬)*ü *'ª#þä 32þá!bð`@!† ©  ”‘   Ü<ÌÌü<ÄÔÄ1/ì2ôäìÔ<î2î990K° TX½ÿÀ@878Y´66].#"!!!!53#535632NLˆ=”t‡þy-üìÇÇÖè=—´¶))›Ô×þ/ªªÑîó\ÿ=¢ð >‘@54&.#"#"&'532654/.5467.54632{?>‹ú?>ÌS8alÎÓƒ\]>9Ì­IšXW”:fqÝÖ€][;;ȦI™¨.Z.L…‡-[.Kˆ“¤''PGZswšeZŒ54m@ލ¤''TLf{x™f[1,pE‚Ÿ3Ñ…! · Ç \ Ôì1Ôì04632#"&3­~|«¬}}¬ú|««|}¬¬žÿ;9Õ %@Á]] ÔÔüÜì91Ä2ôì90!###&&54$yÀ¾Ž×ëÕùfùáNݸ¾èºÿã¬/š@0-'!  *†¹*¹—Œ.  !' $'$-F0üÄüÌÆîÔîî99991/äþîþÕî990@@'(Š Š     ! "&  : :!MM I!I"jj ¥¥¦ ]]4632#"&'532654&/.5467.#"#ºïÚÐÛ—¨:A9¦`áÓ@ˆIPŒAtx;e\`W§—ƒq‚ˆ»qÈÛèàs`/Q*%jŽd¬·¤_[?T>7;‡[¬gp‹ƒû“åÍ/8L`@6EBC?2ÉH0É9JCÊ 9ÊÉÈ É$HE301BKL?gwyVpMIßÑ`3þœDåÍ/IC@&=Ë>:ÌAÊ$1Ë04ÌGÊÉÈ$É 7aD=0^* D^ JÜÌüìþí2î1/îöþýîÖîýîÖî02#"$'&5476$"32676654&'&&&&#"3267#"&54632˜mmllmmþù˜˜þùmmllmm˜ƒâ^^``^^⃄ã^]]^\^ã§B‚B•§«›@zBC‰FØûûØIˆÍnmmþúš˜þûmmnnmm˜šmmng^^^å‚ã^^__^]⃅ã]^^õ! ¯Ÿ®"ôÐÑò'“FÕ >@!  É  b b cbcÔäüäÔìÔì91ô<<ì2Ô<<Ä903#######5J®¤ªqÃ7ËrqËrÉÕÿý¾äþÑ/þB^þä^sîRf1@ ´³DÔì1ôì0K° TK°T[X½ÿÀ@878Y3#‹Çþº™fþˆ×F)’@ÎÍddÜüÔì1ü<ì20K° TK° T[X½@ÿÀ878YK° TK° T[K°T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@````pppp]3#%3#^ËËþyËËÊÊÊÙ'ÛÝ>@" Ïœ Ï œ  Ü<Ä291Ô<Ì2ü<ìþ<ì990!!!!!'7!5!7!Ù}®/þHÃ{üúþþ}®þÕ¶Ãý‡¢;fÕ¨ðªþÇfÓªðHÕ‡@9  B• ••••­    ÔÔ<ì2ÔÄÄ91/<ììÄôììîî0KSXííííY"²€]@gww† …– ¿ ]!!!!!!#!5ýÇý9øü=ýð Íq‹þ¶ËÕªþFªýãªþÕžüðfÿºå +ž@< +,  )&  *&•& •‘&Œ,+,* # )#3,üìüìÀ999999991äôìîÀÀ99999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''¶ý3>¡_Ü'y=¡_Üþý''†NOy;‚ÝW¢fªNPþˆþÆ€Ý[¢gXü²@CHp¸¸@Cþ¸þåp¼Džf b¥MK¿YÆgþöžþŸþ[KK¿XÝÝÏî /ÿ@- !$'!!0 $*0ÔÄÔÄ99991ÔÄÔÄÀ9990@¾     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV´° °!°"°&°'°(´)]]32654&#".#"326#"&54632>32#"&“1†Te€vYR…Ä1…UfvYR†F^ˆº§†_™HDža†¼§†^•/XZ‡ie†‡7XX„je†ˆ‡ߦ¯Ø~ŠŠƒá§¯ÖwÙÛ .@МР œ   Ô<ì2ü<ì21/ìÔ<ìü<ì0!!#!5!!!®-ýÓ¨ýÓ-ýÓúþþ}ªþ}ƒªƒû¦ªÙÛ¨ T@.œœœœBѧœ $# ü<ì2291/ìôì90KSXííííY" 5!!Ûü@Àúþúþúþøþëþî²pªoüªÙÛ¨ V@/œœœœBѧœ$ # ü<<ì291/ìôì90KSXííííY"55!5ÙúþÁAúþø°þ‘ªþ²ýǪªRÃÕÆ@F  B Ó Ó   fe f eÔ<ì2ìüì2ì99991/ä2Ô<ì2Ô<ì290KSXííííY"K° TX½ÿÀ@878Y@(†¦ µ' ' ')((79‡ ˆ¦ ¥ª©]]!#!5!5'!5!3 3!!!þcÉþ` Tþ´þþ{y¿þÂþµTŸÇþ9Ç{3›{JýD¼ý¶{›3®þVå` M@% ‡Œ ¼½!   NF!üì2ôìÄ91ää2ô<ìÜÄ990¶"`"Ï"]3326533267#"&'#"&'®¸Š‡”•¸#% )I#ER2‘bf*þV ýH‘”¨¨ü¢<9 ”NPOONNý×hÿçÁ-)b@'! '!Õ* $$*ÔÌÜÌ9991äÌÜÌÎÎ990K° TK° T[K°T[K°T[K°T[X½*@**ÿÀ878Y>54&#"#"&54632#"&54324&#"32ôIH7$$0e´ÖþßÕ˜ËÝ¢e‚ WOmVPmmW£Kƒt,>bþÊþùþ±þFØ£Æ[àt}þþÏt{þw;Á ]@    ÔÄ91ÄÔÌÎ990@0QVPZ spvupz €€ Z pp{ t €€ ]]!! !!5 7êüA ýJïúÞÕýIÁÁý3ýÀ•!ãœþwqÁ@×Ö¯ggÔìÔì1üìì20!#!#œÕðý ïÁø¶}ùƒÿáÿðª/#Ë@1 ÚÙ"ØÕ $ #" #h#$ÔÔÔì9999991/<äôì22î9990K° TX½$ÿÀ$$@878Y@V             ##(]]#3267#"&5467!##"#>3!‡¶i/7.%7vy"PþºÂµÃ)6<  ¥y‘þJ\:1fd.¡xüo‘@E¦}/þú%&@ Û Ûܱ& iji&Üìüì1üìÜäÞä026732#"&'&&#"#"&546327j ¾ÊPd@7*8  k½ÄOeD=!0 þú°l9¼TA6?&#Hý•Ánþ!þbSA8?SsÕ;ð)_@3(%ãÝá%Ý ßÞÝ à‘* "(kl"k *ÜìÌüì22ÀÀ9991ôäüôìÄîíÖîî99990!!#5#"&5463354&#"56632"32655‹°ýP®•,]€˜¿¼¶uu>ˆDI‘E·³þì¡~bRh‚P{¸þ@p?D‡q‡Š[[""°ðCO@Mr`Õdð.@ãáÝ àÝ‘ klk Üìüì991ôìôìüì0!!2#"&546"32654&‹°ýPX³Îγ³Ðгi~hi}|P{Ý¿¿Ûܾ¿Ýs¡ˆ…  …‰ NÏç@@" å‘å  mm  ÔììÔììÀÀ9991/<ì2ôì0%!5654#"!5!&5! Ïý¨±ÆþøØØþ÷Dzý¨?ž‘1/Ž¡²²²aLÊð"þÝïÊþ´a²²‹*¸>ŠþwþËÂþØ{ÿão{3>@C'-%= 4©%†ˆ©:¹.†-º*¹»1 ¸Œ%?47&%7& =&-7"E?üìÌÔü<ÔìÄ999991Ää2ô<Ääü<ôìÄî2îôîî9990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0…+…0€@@ @°@À@Ð@à@à@ð@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/€,€-€.€/]q].#">32!3267#"&'#"&5463!54&#"5>32"326=¶¥‰™¹DJÔ„âü² Ì·hÈddÐj§øMIؽÒýû§—`¶Te¾ZŽÕï߬o™¹”—´®ž0Z^þÝúZ¿È55®*,ywxx»¨½À‹..ª''`þf{bsÙ´)Hÿ¢œ¼ +ä@<+,&  )&  *&¹& ¹¸&Œ,+,* # #Q)E,üì2ôì2À9999991äôìîÀÀ99999990@p(?-YVUV jf!{    { z{ {!"#$%{&›•%¨ -ð-&YVUZ(ifej(ztvz(‰•š$¢­$]] 32654&'.#".5327#"&''‰þ)gA“¬\*g>—©}66ñ]ŸC‹_’56þîð`¡?‹`!ý°*(èÈOuš))ëÓHn.—MÅw834¨O³MÆxþíþÇ43¨Nÿã¬Õ $†@/ †ˆ !ƒ# •Œ#%" " "!& %ÜìÔüìÔì99991äôìþÍôî9990K°TK°T[K°T[X½%ÿÀ%%@878Y@ ttttv]33267#"&546?>7>5#53ô¾7ZZ:3ƒmN´`^Àg¸àIYX0&ÄÊÊDœe‚WX5^1YnFC¼98ŸL‰VV/5<6þ5Õ b@ƒ ü<ì2991/ôüÌ0K° TX½ @ ÿÀ878YK°TK°T[K°T[X½ ÿÀ @878Y¶ P ]#53#3ËËË¢×þú+eþ›ÙÛ^@ œÜÔì1ÔÄì0!#!Ù¨û¦^ýÁ•=ÿ×} *@    ÔÌ91ÔÌÄ903##'%\½sý®BþÁ}}`ùºs-Pbý;þV#Š@@   B   ©Šæ©Šæ©!—$  $ÔÌ91Ä2Äüìôìîöîî299990KSXí2í9Y"K° TX½$ÿÀ$$@878Y.#"!!#"&'53267#5!>32&P,`r<þÃ:¼º:d/4a/am"‰ø?$Æ—5dð¤z„þÉý…þãÓ¦!!‰¦­J·ÃÙÛô;?@.9*-" *œ19œ"œ œ<-<Ô<Ä21ÔìÔìÜüÔìÀ9999990#"'&'&'&#"56632326#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©gi³an’ ›^X¬bi³an“ ›^V©o³NE;=LT³NE;=KÚ²OE;=LS²NE;=Kÿú`Á8@ÔÌ91/ÄÌ90@cmpxyvn]] !3!¬þ^DýïàCúšîûÄú?ž%# †@Ièèèè è è è  è B  ç¦ o o nüü<Ôì2991ô<ì2990KSXííííííííY"55%þÓ-þ+#þÓ-þ+#¿þôþô¿¢R¢¿þôþô¿¢RÁH# †@I è è è è èèèèB  ç¦ o opü<üÔ<ì991ô<ì2990KSXííííííííY"5%5ÁÕþ+-þÓ²Õþ+-þÓ#þ^Rþ^¿  ¿þ^Rþ^¿  ìþ #@ƒ   ÔüÔìÔì1/<<ì220%3#%3#%3#–ÔÔ©ÕÕú­ÕÕþþþþþþÿÿhk'$¼uÿÿh^'$¼uÿÿsÿãÙ^'2'us Õ;@•••­   üìÔÄÄÔì299991/ìì2ôì2î0!!!!! !# !3úýÇý9øû×þOþA¿±gþ¿þÀ@AÕªþFªýãª|pm|ªþáþàþßþßqÿãÃ{'3„@1†ˆ ©. ¹(¹»"%¸Œ4"1 K1 Q+E4üìôüôìÄ9991ä2ô<Ääì2Äî2îôî90@%?5_5p5Ÿ5Ï5Ð5ð5????? ooooo ]q].#"!3267#"&'#"32>32%"32654& ¤‰™¹Hü² Ì·jÈbdÐj òQGÑŒñþïñŒÓBNèâú°”¬«•“¬¬”˜³®ž5Z¾Ç44®*,nmnm98olkpþ݇çÉÉçèÈÇééy¶©é/Æ1üì0!!üyéyµ©/Ì1Ôì0!!øy®émÕ '@ž   ÜüÌÔÌþÔÎ1ô<ì20#53#53Ó¤RšÓ¤Ré­?þÁ­­?þÁ®émÕ '@ ž  ÜìÔÌÜîÔÎ1ô<ì203#%3#Ó¤RšÓ¤RÕ¬þÀ@¬¬þÀ@®éÓÕ@ žÜüÔÌ1ôì0#53Ó¤Ré­?þÁ²þ×Õ@ žqÜìÔÌ1ôì03#Ó¤RÕ˜þÁ?Ù–Ûo )@êêœ r ÜÔ<ü<Ä1ÔÄüÄîî03#3#!!ßööööýúúþoöþõAªþ#îu"@ÔÌ91ÔÌ990 úþþôþ þ üÏüÇ9%ûÛûÓ-ÿÿ=þV'\Ž^ÿÿÿüçN'<suþ‰ÿãÍð+@BŒ‘ÔÌ1ää0KSXííY"3#- ü\ ðùó^R¼²#/ƒ@I -'! - -¹ëì'¹ë!0 *$0* $ $(st*(s0Üäìôäì9999999991ÔäìôäìÀ9999999907'#"&''7&&5467'766324&#"326{ÏrÎ%$&(ÑrÏ;t=:x=ÏqÏ%%&&ÏsÏ7t@?s9ÏqÏ(&%%ÏsÎ>v:@t8ÎsÏ'%$þ|pššprœžs#G@%èèèèBç¦onüì291ôì90KSXííííY"5sþÓ-þ+#¿þôþô¿¢RÁ–#I@&èèèèBç¦opü<ì91ôì90KSXííííY"5ÁÕþ+-þÓ#þ^Rþ^¿  /J›@( ©‡¾±— ¼ Lü<Ä2Äü<Äî2991/<æ2îþîîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€€€ Ðï]]#!##53546;#"3#J¹þ¹°°­³¹°cMù¹¹`û Ñü/ÑN·¯™Phc²é/J„@! © ‡— ¼   Lü<ÄÄü<Äî991/<æ2þîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€ € € Ðï]!#!"!!##53546J¹þ·cM/þѹ°°®ùì{Phcü/ÑN»«9ÿ;ÇÕ>@ ¹¹  ÂY W Y Ô<<ì2ü<<ì21äôÄ2Ä2î2î20%!#!5!!5!3!!!Çþ‘°þ‘oþ‘o°oþ‘oßþ\¤š™¤þ\™ýáÛH®F·ƒÔì1Ôì03#ÛÓÓFþ®ÿÓþ@ žƒÔìÔÌ1üì0%3#Ó¤Rþ¬þÀ@®ÿmþ '@ žƒ   ÜìÔÌÜîÔÎ1ü<ì20%3#%3#šÓ¤RþfÓ¤Rþ¬þÀ@¬¬þÀ@qÿã Lð #'3?K®@D$%&%&'$'B@’ .’(’F’4 :&Œ$‘L%IC'1+C =  1 =I 7+ ! LüäìÔÄìäîîöîî991ä2ô<<ä2ì2îöîî20KSXííY"K°TK° T[K° T[K° T[K° T[K°T[X½L@LLÿÀ878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&ôWddWUccUžº» º»ùtž¼»ŸŸ¹º% üZ VcbWWcd²žº» º»ŸWccWUcc‘”„‚••‚ƒ•Ü»»ÛÛ»¼ÛàÛ»½ÚÛ¼ºÜùóŽ•‚„””„–ýŸÜ»»ÛÛ»¼Û”„‚••‚ƒ•ÿÿhm'$¼uÿÿÉ‹m'(žuÿÿhk'$¼uÿÿÉ‹N'(žuÿÿÉ‹k'(žuÿÿ¢k',ÿ/uÿÿÿþ`m',ÿ/uÿÿXN',ÿ/uÿÿ;ºk',ÿ/uÿÿsÿãÙk'2'uÿÿsÿãÙm'2'uÿÿsÿãÙk'2'uÿÿ²ÿã)k'8îuÿÿ²ÿã)m'8îuÿÿ²ÿã)k'8îuÁy` ·¿Füì1/ì0@ @P`p]3#Á¸¸`û Áî?f7@ ´³uÜì91ôì290K° TK°T[X½ÿÀ@878Y3#'#¶”õ‹´´‹fþˆõõ¶J7c@$  Ãà íVwVvôìüì99991ü<üÔ<ì99990K° TK° T[X½ÿÀ@878Y'.#"#>3232673#"&ü9! &$}f[&@%9! &$}f[&@Z7IR‡“!7IR‡“Õb+ö/·ïîÔÌ1üì0K° TK°T[X½ÿÀ@878Y!!ÕVýªö”Ç)9H W@ ð³VVÜìÔì1ô<Ôì0K° TX½ÿÀ@878YK°TK°T[K°T[X½@ÿÀ878Y332673#"&Çv aWV` v ž‘‘žHKKJLšDf,@ ÎÍdÔì1üì0K° TX½ÿÀ@878Y3#šÌÌÌîá _@Áò ÁñV xVÔìôì1ôìôì0K° TK° T[X½ÿÀ@878YK° TK° T[K° T[X½ÿÀ@878Y4&#"3267#"&54632˜X@AWWA@XzŸssŸŸssŸô?XW@AWX@s  ssŸŸ#þuÁ@  ó' ÜÔìÔÌ1/ÔüÄ90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ ƒ0.W=ðî®fB@´³ÔÜÔÌ991ô<ì20K° TK°T[X½ÿÀ@878Y3#3#ü²ø‡ªß‰fþˆxþˆLþuÁ @  óô 'ÔìÄÔÌ1/üüÄ90!33267#"&546¸w-+76 >&Dzs5=X..… W]0iÁî?f7@ ´³uÜì91ô<ì90K° TK°T[X½ÿÀ@878Y373¶õ‹´´‹õîxõõþˆÿòuÕ ?@ •  : yô<ìÄü<Ä991/äì90´0P]3%!!'7ÓË9Pþw×ü^”MáÕý˜Ûoþîýãª;jnžH ^@ — z z Ô<äü<ä991/ì90K°TX½ @ ÿÀ878Y@ @ P ` sz p à ð ]37#'7Ǹ}Lɸ{JÅý¦ZjüãšXjÿÿ‡ÿã¢m'6‹uÿÿoÿãÇf'Vàÿÿ\m'=¾uÿÿXÛf']àþ¢®˜@ õõÜ<ì21ÔìÔì0##®ªªª˜ý öý ö ºÕ g@  © ••  2  yô<ì2ÄôìÄ91/Æ2îöîî20@( °Ÿ Ÿ Ÿ Ÿ ŸŸŸŸ¿ ¿ ¿ ¿ ¿¿¿¿]]! )#53!!3 !Ó ±–þiþPþ`ÉÉËPþ°ó5þáþËÕþ—þ€þ~þ–¼ãþýê.,qÿãu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ##¹ ¹Œ#±)&' ! (%#" QE)üìôì99999991ìÄôìî9990KSXÉÉÉÉííííY"²?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x" *ð*']].#"32654&#"5432''%'3%F2X)§¹®’‘®6 ~rþäæçþåÝ4*ŸþÁ!µäM!þÙ“ØÃ¼ÞÞ¼z¼&þà­ÿþÉ7ÿú7´kc\Ì‘oabÿÿÿüçk'<suÿÿ=þVf'\^ÉÕ =@• •ö  ? üì22üì91/ôüìÔì0@ ?_]332+#32654&#ÉÊþûþÿûþÊÊþš™ŽÕþøáÜÜâþ®'ýÑ’††‘ºþV¤>@¹¹Œ¸½— GFüì22ôì1ìääôÄìÆî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý®¾ý¢daþ¼þøþøþ¼aëËççËËççÙ-Û×¶œÔÄ1Ôì0!!Ùúþת?œÅ …@M œ  œœœœœ œ œ B   Ô<Ì291Ô<Ì290KSXííííííííY" '7œþ7Éwþ5þ5vÈþ8vËËLþ5þ7yËþ5yÉËyþ5ˉœÅß ,@Ý ÝÝ ÷‘ |]|| Üôäüä1ôììÔìî2035733!œÌßæ‰Íý× c)t'ý+n^œ´ðJ@$}}BÝÝ÷ Ý‘~ÜÄÔÄì91ôÄìüìî90KSXí2íY"!!56754&#"56632 ¨ýª"?XhU4zHM…9‘®þµ8rn81^BQ##{„l‹þä0bÍð(H@' Ý Ý Ý Ý ø÷Ý ø#‘)~&~ )ÜÄÄÔìÔì9991ôäìüäìÔìîî90#"&'532654&##532654&#"56632 \e¾±9}F4wCmxolV^^ad_(fQI€7©Z`mR|†yOFJLl?<:=svcE`ÿÿ‰ÿãð'ð'¼5 ‹ýdÿÿ‰ÿã?ð'ð'¼5ñ‹ýdÿÿbÿãð'ò'¼5 ‹ýdÿÿsÿã‹m'* uÿÿqþVZH'JÚ‹ÿÿÉ•P', ÿ/uÿÿ‡þu¢ð'6Ý‹ÿÿoþuÇ{'VÝÿÿsÿã'k'&-uÿÿqÿãçf'F‰ÿÿsÿã'm'&-uÿÿqÿãçf'Fà‰qÿãô$J@$Ó ù"¹¹ Œ¸—   GE%üìô<Äü<Ä1/ìäôÄìÄîý<î20¶`&€& &]!5!533##5#"3232654&#"¢þºF¸šš¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶N}““}úü¨daDDaþËççËËççd߃¶œÜÌ1Ôì0!!dý僤ÛH®F·ƒÔì1Ôì03#ÛÓÓFþÿãð1@: Ó"+Ó ¡®•¡®•/‘Œ) 2+"!)#&  , & &*!/<ÔÄ2üÄÄ99999999991Ä2äôìôìîöîî2Ý<î20K° TK° T[K° T[K°T[K°T[K°T[X½2ÿÀ22@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-ŸŸŸ Ÿ Ÿ Ÿ Ÿ ŸŸŸŸŸŸ–Ÿ Ÿ!Ÿ"Ÿ#Ÿ$Ÿ%Ÿ&Ÿ'Ÿ(Ÿ)Ÿ*Ÿ+Ÿ,-2   USjg ]].#"!!!!3267#"#734&5465#7332[©fÊ A7ýæ¾8þŠ Êf©[Y¹`íþË(Ó7‹Â7œ(6ìb¹bÕiZÈ»{.# .{»ÊZiÓHH"{/ #/{"G×)Ù¥@ ÎddÔüÜì1Ô<ì20K°TK°T[X½@ÿÀ878YK°TK° T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y@````pppp]3#%3#^ËËþyËËÙËËËsîðö@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@ %%6FVjg //]]3#7¹ä™öþø¶Jéu@!  ÃÃúVV ÔìÔì99991ô<ìÔì2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y´ ]'.#"#4632326=3#"&ü9 $(}gV$=09" (}gT";9! 2-ev 3)dw î‹ö‰@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@*$$5CUUŸŸ¯¯//]]#ÇÄ™æöþøÏî1øw@ úÔÄ91ô<Ä90K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ //- ]3#'#¢¼Ó‹¦¦‹øþö²²Ïî1ø†@ úÔÄ91ôÄ290K° TK° T[K° T[K° T[X½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ "  ]373¢Ó‹¦¦‹Óî ²²þö?œôß Ô@ Ý ÷‘ ] ÜÔ<Äì291ôüÔ<ì290K°TK°T[K°T[K°T[K° T[K° T[X½@ÿÀ878YK°TK°T[X½ÿÀ@878Y@T /9IFYi‹«»       "5GK S[ e„¥µ]] !33##5!5ÝþË5¦‡‡þbfþ]ýämººyÇ9ø j@à úVVÔìÔì1ôüÄ20K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TK°T[X½ÿÀ@878Y332673#"&Çv cSRav  Ÿø6978w{zšfÛ¶úÔÌ1ôÌ03#šÌÌÛÍ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßà>: ~ÿ1BSax~’ÇÝ©À & 0 : ¬!""""+"H"e%Êûÿÿ   0AR^x}’ÆØ©À  0 9 ¬!""""+"H"`%ÊûÿÿÿãÿõÿØÿ ÿ^ÿCÿhÿüöüÛà–à…àVßjÞqÞ_Úï¿8ôüúúü (B¬£„…½–熎‹©¤ŠÙƒ“ñò—ˆÃÝðžªóôõ¢­ÉÇ®bcdËeÈÊÏÌÍÎèfÒÐѯgï‘ÕÓÔhêì‰jikmln oqprsutvwéxzy{}|¸¡~€ëíºýþÿøÖùúãä×àÚÛÜßØÞ²³¶·Ä´µÅ‚‡«˜¨š™î¼¥’”•Íf‹‹55®Å´žªšq=3ۤ=´Ù‹žãd‹Û²‡á–œdž¨‹²ð²ž´Ù´Ù´Ù?“‡y}É–s)ÉÉšÉ3sÉ\É\ÿ–?ÉuÉçÉüÉLsÓÉLsɇãÿúÛ²yéD{=ãÿü{\°²Ç´Ùÿìªç{ºfqqìqÑ/qº9Á9ÿÛ¢º9Á˺ºåqºqJº+o#7®¼=‹V¼;¼=3X²´Ùyy–sÉüÉLsÛ²ç{ç{ç{ç{ç{ç{fqìqìqìqìq99ÿÇ9ÿÞ9ÿôºåqåqåqåqåq®®®®9ì\¸3ž º's×´ÙËLfªÝ´Ù´Ù´ÙR®#hdœ¶ÿá+/ÅsÅ`NÛ{åH?55´Ù=´ÙZÿúåžåÁìyyLss/q%®%®‹®‹²´Ùô¼=ãÿüVþ‰^3ž3Á / /9‹Û‹®%® ¼qyÉyÉÉ\¢\ÿþ\\;LsLsLsÛ²Û²Û²9ÁÁ¶ÕÇšî#ðLÁÿòF‡+o{\3X²3 åqãÿü¼=×ɺ´Ù´5‰5^5bÁ‰Á‰Áb3sq\ɇ+o–sfq–sfqqãd‹Û×s¶ ÏÏ5?Çšÿ+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóõôöøùúûüýþÿ     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""X“ÿ¶Oƒ²ö!n˜´ÊÞE‚~áL·üeÏî  R s ®  ß X ° û : i “ æ  = z /¬E…ëuñ)pཊëP‹±á@Ö"m¹#{ßC€øw³R¡Ø‡Äº‡wè [ r ó!5!B!â!ï!ü" ""#"0"="J"W"d"q"~"‹"˜"¥"²"¿"Ì"Ù"æ"ó## ##'#4#A#N#[#h#”#Ï$4$%3%S%&&º'K''·((X(Ã)_*%*\*£*é+z+Ó,D,,±-P- ..R.ª/‡0A0½11!1P1Ï2H2z2ß3F3p3p3}3Š3—3æ4z44£4Ñ4ÿ5595g5‘5ž5«5Ï6[6“6Í7C7©7ë888J999)969C9P9]9j9w9„9‘9ž9«9¸9Å9Ò9ï::{: :å;;^;Ž;Ä;ô<"<_<§<´<Á<Î<Û<þ=c>;>H>U>˜>ç>ý?a??Ü@:@K@\@m@z@‡@”@¡@®@»@È@Õ@âA@AVAkBEBªB÷C_C²CÿDUDÛE*E?-†” x$ÿÓ%ÿ·&')*K+-r./2934K57ÿD9ÿˆ:ÿ­;ÿš<ÿ =IQR&UYÿÉZ\ÿÜbÿÓdg9xy&z&{&|&}&‰­ÿÓ®ÿÓ¯9ºÿÜ»ÿ ÇÿÓÉÿÓÐ9Ñ9Ò9åéêÿ ëÿÜìöKûý$ÿÓ$ÿÜ$ÿÜ$$9$&ÿÜ$*ÿÜ$2ÿÜ$4ÿÜ$6$7ÿa$8$9ÿ}$:ÿ$;$<ÿa$FÿÜ$GÿÜ$HÿÜ$Iÿ·$RÿÜ$TÿÜ$WÿÜ$X$Yÿˆ$Zÿ­$\ÿu$b9$dÿÜ$gÿÜ$h$oÿÜ$pÿÜ$qÿÜ$rÿÜ$sÿÜ$yÿÜ$zÿÜ${ÿÜ$|ÿÜ$}ÿÜ$~$$€$$©ÿ·$ª$­9$®9$¯ÿÜ$´þø$µÿ$ºÿu$»ÿa$Å/$Ç9$É9$ÐÿÜ$ÑÿÜ$ÒÿÜ$Ó$Ô$Õ$ã$êÿa$ëÿu$öÿÜ$ù$ûÿÜ$üÿÜ$ýÿÜ$þÿÜ%%&ÿÜ%*ÿÜ%2ÿÜ%6ÿÜ%9ÿÁ%:ÿ·%<ÿ%dÿÜ%gÿÜ%©ÿÁ%ªÿÜ%¯ÿÜ%´ÿ%µÿ%»ÿ%Åÿ­%ÐÿÜ%ÑÿÜ%ÒÿÜ%ãÿÜ%êÿ%öÿÜ%ùÿÜ%ûÿÜ%ýÿÜ&&$&6&<ÿÜ&b&©ÿÜ&ªÿÜ&­&®&´&µ&&»ÿÜ&Å&Ç&É&ã&êÿÜ&ù''$ÿÜ'9ÿÜ':'<ÿ'bÿÜ'©ÿÜ'ªÿÜ'­ÿÜ'®ÿÜ'´ÿÓ'µÿÉ'»ÿ'ÅÿD'ÇÿÜ'ÉÿÜ'êÿ))þ·)ÿa)$ÿD)6ÿÜ)7ÿÜ)DÿD)Hÿ)Lÿk)Rÿ·)Uÿk)Xÿ)\ÿD)bÿD)iÿD)jÿD)kÿD)lÿD)mÿD)nÿD)pÿ)qÿ)rÿ)sÿ)yÿ·)zÿ·){ÿ·)|ÿ·)}ÿ·)~ÿ)ÿ)€ÿ)ÿ)©)ª)­ÿD)®ÿD)´ÿÓ)µ)ºÿD)Åþˆ)ÇÿD)ÉÿD)ãÿÜ)ëÿD)ùÿÜ**$*7ÿ·*:*<ÿš*b*©ÿÜ*ªÿÜ*­*®*´ÿÓ*µÿÓ*»ÿš*ÅÿÉ*Ç*É*êÿš++ÿÜ++©+ª+´ÿ·+µÿÁ+Åÿ·-ÿ·-$ÿÜ-bÿÜ-©ÿÜ-ªÿÜ-­ÿÜ-®ÿÜ-´ÿ·-µÿÁ-Åÿ-ÇÿÜ-ÉÿÜ.ÿ).$ÿÜ.&ÿ.2ÿ.7ÿa.8ÿÉ.:ÿ·.<ÿ·.DÿÜ.Hÿš.Rÿš.Xÿš.\ÿk.bÿÜ.dÿ.gÿ.hÿÉ.iÿÜ.jÿÜ.kÿÜ.lÿÜ.mÿÜ.nÿÜ.pÿš.qÿš.rÿš.sÿš.yÿš.zÿš.{ÿš.|ÿš.}ÿš.~ÿš.ÿš.€ÿš.ÿš.©ÿ}.ª.­ÿÜ.®ÿÜ.¯ÿ.´ÿÁ.µÿÁ.ºÿk.»ÿ·.Å.ÇÿÜ.ÉÿÜ.Ðÿ.Ñÿ.Òÿ.ÓÿÉ.ÔÿÉ.ÕÿÉ.êÿ·.ëÿk.ûÿ.ýÿ/ÿÜ/$//2ÿ·/7þæ/8ÿš/9ÿ/:ÿD/<þð/D/HÿÜ/RÿÜ/XÿÜ/\ÿD/b//gÿ·/hÿš/i/j/k/l/m/n/pÿÜ/qÿÜ/rÿÜ/sÿÜ/yÿÜ/zÿÜ/{ÿÜ/|ÿÜ/}ÿÜ/~ÿÜ/ÿÜ/€ÿÜ/ÿÜ/©/ª/­//®//¯ÿ·/´þa/µýæ/ºÿD/»þð/Å/Ç//É//Ðÿ·/Ñÿ·/Òÿ·/Óÿš/Ôÿš/Õÿš/êþð/ëÿD292ÿ­2ÿÜ2$ÿÜ29ÿÜ2;ÿ}2<ÿ2bÿÜ2©ÿÜ2ª2­ÿÜ2®ÿÜ2´ÿÓ2µÿÜ2»ÿ2ÅÿD2ÇÿÜ2ÉÿÜ2êÿ3ÿÓ3þÁ33$ÿ}383:3<ÿÓ3Dÿ¤3Hÿ·3LÿÓ3QÿÜ3Rÿ·3UÿÜ3VÿÜ3XÿÜ3\3bÿ}3h3iÿ¤3jÿ¤3kÿ¤3lÿ¤3mÿ¤3nÿ¤3pÿ·3qÿ·3rÿ·3sÿ·3xÿÜ3yÿ·3zÿ·3{ÿ·3|ÿ·3}ÿ·3~ÿÜ3ÿÜ3€ÿÜ3ÿÜ3©ÿÜ3ª3­ÿ}3®ÿ}3´&3µ&3º3»ÿÓ3Åþ·3Çÿ}3Éÿ}3Ó3Ô3Õ3äÿÜ3êÿÓ3ë3úÿÜ494©4ª4´ÿÓ4µÿÜ4Åÿ}5ÿ­5ÿ·5ÿÁ5$ÿ­5&ÿš57ÿk59ÿ5:ÿ­5<ÿ}5DÿÓ5Hÿ¤5Rÿ¤5Xÿ¤5\ÿ5bÿ­5dÿš5iÿÓ5jÿÓ5kÿÓ5lÿÓ5mÿÓ5nÿÓ5pÿ¤5qÿ¤5rÿ¤5sÿ¤5yÿ¤5zÿ¤5{ÿ¤5|ÿ¤5}ÿ¤5~ÿ¤5ÿ¤5€ÿ¤5ÿ¤5©ÿ5ªÿÜ5­ÿ­5®ÿ­5´ÿk5µÿ}5ºÿ5»ÿ}5ÅÿÜ5Çÿ­5Éÿ­5êÿ}5ëÿ5ûÿš5ýÿš6$&6&6*6264666b&6d6g6­&6®&6¯6Ç&6É&6Ð6Ñ6Ò6ã6ö6ù6û6ý7ÿD7ÿ 7ÿ7$ÿa7&ÿˆ77ÿÜ7Dþ­7Fþ¤7Hþ¤7LÿÁ7Rþ¤7UþÓ7Vþ­7XþÉ7Zþ­7\þÁ7bÿa7dÿˆ7iþ­7jþ­7kþ­7lþ­7mþ­7nþ­7oþ¤7pþ¤7qþ¤7rþ¤7sþ¤7yþ¤7zþ¤7{þ¤7|þ¤7}þ¤7~þÉ7þÉ7€þÉ7þÉ7©ÿD7ªÿ7­ÿa7®ÿa7´7µÿÓ7ºþÁ7Åþø7Çÿa7Éÿa7äþ­7ëþÁ7úþ­7ûÿˆ7üþ¤7ýÿˆ7þþ¤8$8-8=ÿÜ8b8­8®8Ç8É8åÿÜ9ÿˆ9þø9ÿY9$ÿ}92ÿÜ9Dÿa9Hÿa9LÿÓ9Rÿa9Xÿu9\ÿÉ9bÿ}9gÿÜ9iÿa9jÿa9kÿa9lÿa9mÿa9nÿa9pÿa9qÿa9rÿa9sÿa9yÿa9zÿa9{ÿa9|ÿa9}ÿa9~ÿu9ÿu9€ÿu9ÿu9©ÿN9ªÿ9­ÿ}9®ÿ}9¯ÿÜ9´9µ9ºÿÉ9Åþæ9Çÿ}9Éÿ}9ÐÿÜ9ÑÿÜ9ÒÿÜ9ëÿÉ:ÿ­:ÿ:ÿˆ:$ÿ:Dÿ}:Hÿˆ:LÿÓ:Rÿˆ:Uÿ¤:Xÿ·:\ÿÜ:bÿ:iÿ}:jÿ}:kÿ}:lÿ}:mÿ}:nÿ}:pÿˆ:qÿˆ:rÿˆ:sÿˆ:yÿˆ:zÿˆ:{ÿˆ:|ÿˆ:}ÿˆ:~ÿ·:ÿ·:€ÿ·:ÿ·:©ÿ:ªÿÜ:­ÿ:®ÿ:´ÿÜ:µ:ºÿÜ:Åþø:Çÿ:Éÿ:ëÿÜ;ÿš;$;&ÿk;2ÿ};7ÿÜ;Hÿ¤;b;dÿk;gÿ};pÿ¤;qÿ¤;rÿ¤;sÿ¤;©ÿ;ª;­;®;¯ÿ};´ÿa;µÿ­;ÅÿÓ;Ç;É;Ðÿ};Ñÿ};Òÿ};ûÿk;ýÿk<ÿ <þa<þð<$ÿa<&ÿ<2ÿ<Dþæ<Hþð<Lÿ·<Rþð<Xÿ<bÿa<dÿ<gÿ<iþæ<jþæ<kþæ<lþæ<mþæ<nþæ<pþð<qþð<rþð<sþð<yþð<zþð<{þð<|þð<}þð<~ÿ<ÿ<€ÿ<ÿ<©ÿ<ªÿk<­ÿa<®ÿa<¯ÿ<´ÿ<µÿÜ<Åþø<Çÿa<Éÿa<Ðÿ<Ñÿ<Òÿ<ûÿ<ýÿ=ÿÜ=©=ª=´ÿÜ=µÿÜ=ÅÿÜH[ÿÜIÿIÿkIÿ·IWÿÜIZÿÜI\ÿÜI©ÿ·IªÿÜI´AIµIºÿÜIÅÿIëÿÜNDÿÜNHÿ·NRÿ·NXÿÁN\ÿ·NiÿÜNjÿÜNkÿÜNlÿÜNmÿÜNnÿÜNpÿ·Nqÿ·Nrÿ·Nsÿ·Nyÿ·Nzÿ·N{ÿ·N|ÿ·N}ÿ·N~ÿÁNÿÁN€ÿÁNÿÁNºÿ·Nëÿ·QQQQ©QªQ´ÿkQµÿQÅÿ¤R&RÿÜRR[ÿÁR©RªR´ÿkRµÿ·RÅÿ}Uÿ}UÿDUÿÜUFÿÓUGÿÜUHÿÓUIUJÿÜUKÿÜUPÿÜUQÿÜURÿÓUTÿÜUUÿÜUXUYUZU[ÿÉU\U]UoÿÓUpÿÓUqÿÓUrÿÓUsÿÓUxÿÜUyÿÓUzÿÓU{ÿÓU|ÿÓU}ÿÓU~UU€UU©ÿ·UªU´UµVUºUÅþÉUæUëU÷ÿÜUüÿÓUþÿÓYÿÉYÿaYÿY©ÿÜYªÿÜY´YµÿÜYÅþðZZÿDZÿZ©ÿÜZªÿÜZ´ZµZÅÿ)[FÿÜ[HÿÁ[RÿÁ[oÿÜ[pÿÁ[qÿÁ[rÿÁ[sÿÁ[yÿÁ[zÿÁ[{ÿÁ[|ÿÁ[}ÿÁ[üÿÜ[þÿÜ\ÿÜ\þÜ\ÿk\©ÿÜ\ªÿÜ\´\µ\ÅþÓbÿÓbÿÜbÿÜb$9b&ÿÜb*ÿÜb2ÿÜb4ÿÜb6b7ÿab8b9ÿ}b:ÿb;b<ÿabFÿÜbGÿÜbHÿÜbIÿ·bRÿÜbTÿÜbWÿÜbXbYÿˆbZÿ­b\ÿubb9bdÿÜbgÿÜbhboÿÜbpÿÜbqÿÜbrÿÜbsÿÜbyÿÜbzÿÜb{ÿÜb|ÿÜb}ÿÜb~bb€bb©ÿ·bªb­9b®9b¯ÿÜb´þøbµÿbºÿub»ÿabÅ/bÇ9bÉ9bÐÿÜbÑÿÜbÒÿÜbÓbÔbÕbãbêÿabëÿuböÿÜbùbûÿÜbüÿÜbýÿÜbþÿÜdd$d6d<ÿÜdbd©ÿÜdªÿÜd­d®d´dµ&d»ÿÜdÅdÇdÉdãdêÿÜdùg9gÿ­gÿÜg$ÿÜg9ÿÜg;ÿ}g<ÿgbÿÜg©ÿÜgªg­ÿÜg®ÿÜg´ÿÓgµÿÜg»ÿgÅÿDgÇÿÜgÉÿÜgêÿh$h-h=ÿÜhbh­h®hÇhÉhåÿÜp[ÿÜq[ÿÜr[ÿÜs[ÿÜxxxx©xªx´ÿkxµÿxÅÿ¤y&yÿÜyy[ÿÁy©yªy´ÿkyµÿ·yÅÿ}z&zÿÜzz[ÿÁz©zªz´ÿkzµÿ·zÅÿ}{&{ÿÜ{{[ÿÁ{©{ª{´ÿk{µÿ·{Åÿ}|&|ÿÜ||[ÿÁ|©|ª|´ÿk|µÿ·|Åÿ}}&}ÿÜ}}[ÿÁ}©}ª}´ÿk}µÿ·}Åÿ}‰&‰©‰ª‰´ÿ‰µÿ‰Åÿ­©ª´ÿ­µÿ¤Åÿ©$©%ÿÜ©&ÿÜ©'ÿÜ©)©*ÿÜ©+©-ÿÜ©.©/©2©3©4©5©7ÿ©9ÿ©:ÿÜ©;©<ÿk©=©I©Q©R©U©YÿÜ©ZÿÜ©\ÿÜ©b©dÿÜ©g©x©y©z©{©|©}©‰©—©­©®©¯©ºÿÜ©»ÿk©Ç©É©Ð©Ñ©Ò©å©é©êÿk©ëÿÜ©ì©öÿÜ©ûÿÜ©ýÿܪ$ÿ·ª%ÿ·ª&ÿܪ'ÿܪ)ª*ª+ª-ÿܪ.ª/ª2ÿܪ3ª4ª5ª7ÿDª9ÿNª:ÿª;ÿª<ÿª=ªIªQªRªUªYÿܪZÿܪ\ÿܪbÿ·ªdÿܪgÿܪxªyªzª{ª|ª}ª‰ªª­ÿ·ª®ÿ·ª¯ÿܪºÿܪ»ÿªÇÿ·ªÉÿ·ªÐÿܪÑÿܪÒÿܪåªéªêÿªëÿܪìªöªûÿܪýÿÜ­ÿÓ­ÿÜ­ÿÜ­$9­&ÿÜ­*ÿÜ­2ÿÜ­4ÿÜ­6­7ÿa­8­9ÿ}­:ÿ­;­<ÿa­FÿÜ­GÿÜ­HÿÜ­Iÿ·­RÿÜ­TÿÜ­WÿÜ­X­Yÿˆ­Zÿ­­\ÿu­b9­dÿÜ­gÿÜ­h­oÿÜ­pÿÜ­qÿÜ­rÿÜ­sÿÜ­yÿÜ­zÿÜ­{ÿÜ­|ÿÜ­}ÿÜ­~­­€­­©ÿ·­ª­­9­®9­¯ÿÜ­´þø­µÿ­ºÿu­»ÿa­Å/­Ç9­É9­ÐÿÜ­ÑÿÜ­ÒÿÜ­Ó­Ô­Õ­ã­êÿa­ëÿu­öÿÜ­ù­ûÿÜ­üÿÜ­ýÿÜ­þÿÜ®ÿÓ®ÿÜ®ÿÜ®$9®&ÿÜ®*ÿÜ®2ÿÜ®4ÿÜ®6®7ÿa®8®9ÿ}®:ÿ®;®<ÿa®FÿÜ®GÿÜ®HÿÜ®Iÿ·®RÿÜ®TÿÜ®WÿÜ®X®Yÿˆ®Zÿ­®\ÿu®b9®dÿÜ®gÿÜ®h®oÿÜ®pÿÜ®qÿÜ®rÿÜ®sÿÜ®yÿÜ®zÿÜ®{ÿÜ®|ÿÜ®}ÿÜ®~®®€®®©ÿ·®ª®­9®®9®¯ÿÜ®´þø®µÿ®ºÿu®»ÿa®Å/®Ç9®É9®ÐÿÜ®ÑÿÜ®ÒÿܮӮԮծã®êÿa®ëÿu®öÿÜ®ù®ûÿÜ®üÿÜ®ýÿÜ®þÿܯ9¯ÿ­¯ÿܯ$ÿܯ9ÿܯ;ÿ}¯<ÿ¯bÿܯ©ÿܯª¯­ÿܯ®ÿܯ´ÿÓ¯µÿܯ»ÿ¯ÅÿD¯ÇÿܯÉÿܯêÿ´$þø´%ÿÁ´&ÿ·´'ÿÁ´)ÿÁ´*ÿ·´+ÿÁ´-ÿÁ´.ÿÁ´/ÿÁ´2ÿ·´3ÿÁ´4ÿ·´5ÿÁ´7´9´:´;ÿˆ´<´=ÿÜ´Iÿ·´Qÿ´Rÿk´Uÿ´Yÿ·´Zÿ·´\ÿ·´bþø´dÿ·´gÿ·´xÿ´yÿk´zÿk´{ÿk´|ÿk´}ÿk´‰ÿÁ´þ}´­þø´®þø´¯ÿ·´ºÿ·´»´Çþø´Éþø´Ðÿ·´Ñÿ·´Òÿ·´åÿÜ´éÿ·´ê´ëÿ·´ìÿÁ´öÿ·´ûÿ·´ýÿ·ºÿܺþܺÿkº©ÿܺªÿܺ´ºµºÅþÓ»ÿ »þa»þð»$ÿa»&ÿ»2ÿ»Dþæ»Hþð»Lÿ·»Rþð»Xÿ»bÿa»dÿ»gÿ»iþæ»jþæ»kþæ»lþæ»mþæ»nþæ»pþð»qþð»rþð»sþð»yþð»zþð»{þð»|þð»}þð»~ÿ»ÿ»€ÿ»ÿ»©ÿ»ªÿk»­ÿa»®ÿa»¯ÿ»´ÿ»µÿÜ»Åþø»Çÿa»Éÿa»Ðÿ»Ñÿ»Òÿ»ûÿ»ýÿÅ$&Å%ÿ·Å&ÿÅ'ÿ·Å)ÿ·Å*ÿ·Å+ÿ·Å-/Å.ÿ·Å/ÿ·Å2ÿÅ3ÿ·Å4ÿÅ5ÿ·Å7þæÅ9þˆÅ:ÿÅ;ÿ·Å<þˆÅ=ÅIÿÜÅQÿ·ÅRÿ·ÅUÿ·ÅYÿÅZÿ<Å\ÿÅb&ÅdÿÅgÿÅxÿ·Åyÿ·Åzÿ·Å{ÿ·Å|ÿ·Å}ÿ·Å‰ÿ·Å&Å­&Å®&ůÿźÿÅ»þˆÅÇ&ÅÉ&ÅÐÿÅÑÿÅÒÿÅåÅéÿ·ÅêþˆÅëÿÅìÿ·Åöÿ·ÅûÿÅýÿÇÿÓÇÿÜÇÿÜÇ$9Ç&ÿÜÇ*ÿÜÇ2ÿÜÇ4ÿÜÇ6Ç7ÿaÇ8Ç9ÿ}Ç:ÿÇ;Ç<ÿaÇFÿÜÇGÿÜÇHÿÜÇIÿ·ÇRÿÜÇTÿÜÇWÿÜÇXÇYÿˆÇZÿ­Ç\ÿuÇb9ÇdÿÜÇgÿÜÇhÇoÿÜÇpÿÜÇqÿÜÇrÿÜÇsÿÜÇyÿÜÇzÿÜÇ{ÿÜÇ|ÿÜÇ}ÿÜÇ~ÇÇ€ÇÇ©ÿ·ÇªÇ­9Ç®9ǯÿÜÇ´þøÇµÿǺÿuÇ»ÿaÇÅ/ÇÇ9ÇÉ9ÇÐÿÜÇÑÿÜÇÒÿÜÇÓÇÔÇÕÇãÇêÿaÇëÿuÇöÿÜÇùÇûÿÜÇüÿÜÇýÿÜÇþÿÜÉÿÓÉÿÜÉÿÜÉ$9É&ÿÜÉ*ÿÜÉ2ÿÜÉ4ÿÜÉ6É7ÿaÉ8É9ÿ}É:ÿÉ;É<ÿaÉFÿÜÉGÿÜÉHÿÜÉIÿ·ÉRÿÜÉTÿÜÉWÿÜÉXÉYÿˆÉZÿ­É\ÿuÉb9ÉdÿÜÉgÿÜÉhÉoÿÜÉpÿÜÉqÿÜÉrÿÜÉsÿÜÉyÿÜÉzÿÜÉ{ÿÜÉ|ÿÜÉ}ÿÜÉ~ÉÉ€ÉÉ©ÿ·ÉªÉ­9É®9ɯÿÜÉ´þøÉµÿɺÿuÉ»ÿaÉÅ/ÉÇ9ÉÉ9ÉÐÿÜÉÑÿÜÉÒÿÜÉÓÉÔÉÕÉãÉêÿaÉëÿuÉöÿÜÉùÉûÿÜÉüÿÜÉýÿÜÉþÿÜÐ9Ðÿ­ÐÿÜÐ$ÿÜÐ9ÿÜÐ;ÿ}Ð<ÿÐbÿÜЩÿÜЪЭÿÜЮÿÜдÿÓеÿÜлÿÐÅÿDÐÇÿÜÐÉÿÜÐêÿÑ9Ñÿ­ÑÿÜÑ$ÿÜÑ9ÿÜÑ;ÿ}Ñ<ÿÑbÿÜÑ©ÿÜѪѭÿÜÑ®ÿÜÑ´ÿÓѵÿÜÑ»ÿÑÅÿDÑÇÿÜÑÉÿÜÑêÿÒ9Òÿ­ÒÿÜÒ$ÿÜÒ9ÿÜÒ;ÿ}Ò<ÿÒbÿÜÒ©ÿÜÒªÒ­ÿÜÒ®ÿÜÒ´ÿÓÒµÿÜÒ»ÿÒÅÿDÒÇÿÜÒÉÿÜÒêÿÓ$Ó-Ó=ÿÜÓbÓ­Ó®ÓÇÓÉÓåÿÜÔ$Ô-Ô=ÿÜÔbÔ­Ô®ÔÇÔÉÔåÿÜÕ$Õ-Õ=ÿÜÕbÕ­Õ®ÕÇÕÉÕåÿÜã$&ã&ã*ã2ã4ã6ãb&ãdãgã­&ã®&ã¯ãÇ&ãÉ&ãÐãÑãÒãããöãùãûãýåÿÜå©åªå´ÿÜåµÿÜåÅÿÜéé©éªé´ÿ¤éµÿéÅÿ·êÿ êþaêþðê$ÿaê&ÿê2ÿêDþæêHþðêLÿ·êRþðêXÿêbÿaêdÿêgÿêiþæêjþæêkþæêlþæêmþæênþæêpþðêqþðêrþðêsþðêyþðêzþðê{þðê|þðê}þðê~ÿêÿê€ÿêÿê©ÿêªÿkê­ÿaê®ÿaê¯ÿê´ÿêµÿÜêÅþøêÇÿaêÉÿaêÐÿêÑÿêÒÿêûÿêýÿëÿÜëþÜëÿkë©ÿÜëªÿÜë´ëµëÅþÓììÿkìÿ·ì©ìªì´ÿÜìµìÅÿDöö$ö7ÿ·ö:ö<ÿšöbö©ÿÜöªÿÜö­ö®ö´ÿÓöµÿÓö»ÿšöÅÿÉöÇöÉöêÿšù$&ù&ù*ù2ù4ù6ùb&ùdùgù­&ù®&ù¯ùÇ&ùÉ&ùÐùÑùÒùãùöùùùûùýûû$û6û<ÿÜûbû©ÿÜûªÿÜû­û®û´ûµ&û»ÿÜûÅûÇûÉûãûêÿÜûùýý$ý6ý<ÿÜýbý©ÿÜýªÿÜý­ý®ý´ýµ&ý»ÿÜýÅýÇýÉýãýêÿÜýù MB@hmþ ¼þ‰þ‰ L GÌþBGÌSf €¯ JBits@ ûþšmãB±‹`#cÕVeraSansÿÿÿÿ6ÿÿþ628R00@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "                      "       #                       #     $               $    &              &    ÿÿ P ì_<õº¹ð¸ºÂg‘þ‰þ Lmpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/input.focus.png0000644000000000000000000000026511130023047024244 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ(%¹tEXtCommentCreated with The GIMPïd%n+IDAT8Ëc` `d``øÿÿ?¥¦022QËE£4jШA£ ƒ¨;…,;)k“IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/input.normal.png0000644000000000000000000000032011130023047024405 0ustar rootroot‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ +–ðrctEXtCommentCreated with The GIMPïd%n4IDAT8Ëclhh` `a``HHH Ð” 01P Œ4jШA£4t bÔ”J”‘¡Å-IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/menu.down.png0000644000000000000000000000022511130023047023675 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ;3¼‡í>4IDAT8Ëclhh` Ô×׳000„xPn•À¨A£4jШACÇ ÆÿÿÿSÅ ›¾9CKIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/config.txt0000644000000000000000000001425511130023047023273 0ustar rootrootdesktop background desktop.png input font Vera.ttf 16 input background input.normal.png input color #000000 input:focus background input.focus.png input padding_left 6 input padding_right 6 input padding_top 3 input padding_bottom 3 label font Vera.ttf 16 label color #000000 document font Vera.ttf 16 document color #000000 div font Vera.ttf 16 div color #000000 td font Vera.ttf 16 td color #000000 th font Vera.ttf 16 th color #000000 h1 font Vera.ttf 24 h1 color #000000 h2 font Vera.ttf 20 h2 color #000000 h3 font Vera.ttf 16 h3 color #000000 h4 font Vera.ttf 14 h4 color #000000 h5 font Vera.ttf 12 h5 color #000000 h6 font Vera.ttf 10 h6 color #000000 ul font Vera.ttf 16 ul color #000000 ol font Vera.ttf 16 ol color #000000 li font Vera.ttf 16 li color #000000 li padding_left 32 pre font mono 16 pre color #000000 code font mono 16 code color #000000 checkbox off checkbox.off.normal.png checkbox on checkbox.on.normal.png checkbox:down off checkbox.off.down.png checkbox:down on checkbox.on.down.png switch off checkbox.off.normal.png switch on checkbox.on.normal.png switch:down off checkbox.off.down.png switch:down on checkbox.on.down.png radio off radio.off.normal.png radio on radio.on.normal.png radio:down off radio.off.down.png radio:down on radio.on.down.png button background button.normal.png button:down background button.down.png button padding_left 8 button padding_right 8 button padding_top 1 button padding_bottom 1 button.label font Vera.ttf 16 button.label color #000000 slider background slider.png slider bar slider.bar.normal.png slider:down bar slider.bar.down.png slider width 16 slider height 16 hslider background slider.png hslider bar slider.bar.normal.png hslider:down bar slider.bar.down.png hslider width 16 hslider height 16 vslider background slider.png vslider bar slider.bar.normal.png vslider:down bar slider.bar.down.png vslider width 16 vslider height 16 select.selected background select.selected.normal.png #select.selected:down background select.selected.down.png select.selected padding_left 4 select.selected padding_right 4 select.selected padding_top 1 select.selected padding_bottom 1 select.arrow background select.arrow.normal.png select.arrow:down background select.arrow.down.png select.arrow padding_left 1 select.arrow padding_right 1 select.options background select.options.png select.option background select.option.normal.png #select.option:hover background select.option.hover.png select.option padding_left 4 select.option padding_right 4 select.option padding_top 1 select.option padding_bottom 1 #select.option border_top 1 #select.option border_right 1 #select.option border_bottom 1 #select.option border_left 1 select.option.label font Vera.ttf 16 select.option.label color #000000 select.options padding_left 1 select.options padding_right 1 select.options padding_top 1 select.options padding_bottom 1 select arrow select.arrow.png dialog.bar background dialog.bar.png dialog.bar padding_left 8 dialog.bar padding_right 8 dialog.bar padding_top 2 dialog.bar padding_bottom 1 dialog.bar.close image dialog.close.normal.png dialog.bar.close:down image dialog.close.down.png dialog.main background dialog.png dialog.main padding_left 8 dialog.main padding_right 8 dialog.main padding_top 4 dialog.main padding_bottom 4 keysym font helvetica 16 keysym background input.normal.png keysym color #000000 keysym:focus background input.focus.png keysym padding_left 6 keysym padding_right 6 keysym padding_top 3 keysym padding_bottom 3 tool background tool.normal.png tool:down background tool.down.png tool padding_left 4 tool padding_right 4 tool padding_top 1 tool padding_bottom 1 tool.label font Vera.ttf 16 tool.label color #000000 menu background menu.normal.png menu:hover background menu.hover.png menu:down background menu.down.png menu padding_left 6 menu padding_right 6 menu padding_top 3 menu padding_bottom 3 menu.label font Vera.ttf 16 menu.label color #000000 menu-open background menu.down.png menu-open:down background menu.down.png menu-open padding_left 6 menu-open padding_right 6 menu-open padding_top 3 menu-open padding_bottom 3 menu.options background select.options.png menu.option background menu.option.normal.png menu.option:hover background menu.option.hover.png #menu.option.label color #FF0000 menu.option padding_left 6 menu.option padding_right 6 menu.option padding_top 1 menu.option padding_bottom 1 menu.option.label font Vera.ttf 16 menu.option.label color #000000 menu.options padding_left 1 menu.options padding_right 1 menu.options padding_top 1 menu.options padding_bottom 1 menu arrow select.arrow.png scrollarea.content background #ffffff scrollarea.content padding_left 1 scrollarea.content padding_right 1 scrollarea.content padding_top 1 scrollarea.content padding_bottom 1 hscrollbar height 15 ##hscrollbar background scroller.slide.h.png hscrollbar background slider.png ##hscrollbar bar scroller.slide.bar.normal.png hscrollbar bar slider.bar.normal.png ##hscrollbar:down bar scroller.slide.bar.down.png vscrollbar width 15 ##vscrollbar background scroller.slide.v.png vscrollbar background slider.png ##vscrollbar bar scroller.slide.bar.normal.png vscrollbar bar slider.bar.normal.png ##vscrollbar:down bar scroller.slide.bar.down.png list.item background list.item.normal.png #list.item:down background list.item.down.png list.item padding_left 4 list.item padding_right 4 list.item padding_top 2 list.item padding_bottom 2 list.item margin_bottom 1 list.item align -1 list.item.label font Vera.ttf 14 list.item.label color #000000 list background list.png list padding_left 1 list padding_right 1 list padding_top 1 list padding_bottom 1 list.content background #eeeeee list.content padding_left 1 list.content padding_right 1 list.content padding_top 1 list.content padding_bottom 1 filedialog.folder image filebrowser.folder.png filedialog.label font Vera.ttf 14 filedialog.label color #000000 filedialog.title.label font Vera.ttf 16 filedialog.title.label color #000000 filedialog.input font Vera.ttf 14 filedialog.input background input.normal.png filedialog.input color #000000 filedialog.input:focus background input.focus.png filedialog.input padding_left 6 filedialog.input padding_right 6 filedialog.input padding_top 3 filedialog.input padding_bottom 3 python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/select.option.normal.png0000644000000000000000000000025411130023047026042 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/menu.option.hover.png0000644000000000000000000000022311130023047025356 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ cRHú2IDAT8ËcäRÉb `a``8µ&ŽBSÌB11P Œ4jШA£4t b¤VuBua4Î ¥IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/list.item.normal.png0000644000000000000000000000025411130023047025164 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/slider.bar.normal.png0000644000000000000000000000026511130023047025303 0ustar rootroot‰PNG  IHDRàw=ø pHYs  šœtIMEÕ  3ÇÛ%STIDATHÇc¼ráÄœ‚ m}sªÞØØÈÀÀÀ±€áêÅ“4ñÁ¨£ŒZ0jÁ¨£  X+hZF‡ÿ´ô0‘ ¹0:jôIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/select.arrow.down.png0000644000000000000000000000022511130023047025341 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ  _¸ÏŽ4IDAT8Ëclhh` `a`` ð Ð”5v01P Œ4jШA£4t bÔ”¦ÈÒžõIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/menu.normal.png0000644000000000000000000000017011130023047024215 0ustar rootroot‰PNG  IHDR Ù˰ pHYs  šœtIMEÕ ô€‘rIDATÓc¼rá!ÀÄ@UDoEEL„JRåöIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/select.arrow.png0000644000000000000000000000023411130023047024373 0ustar rootroot‰PNG  IHDR}Œß¬ pHYs  šœtIMEÕ 6·`;IDATÓcd````dÀÞÃwþcÀ»È*Ï IžA7j7’änlv­‚J®bÀf2üg˜É€t rò,!¿H:©IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/tool.normal.png0000644000000000000000000000025011130023047024225 0ustar rootroot‰PNG  IHDRàw=ø pHYs  šœtIMEÕ  +#c¦GIDATHÇíÖ¡ Á Cÿ• ´€DPÏc‘âþ ÈNT’DRAØk~Þú œ 0`à©zè”ÏP汎 È"IpIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/radio.on.normal.png0000644000000000000000000000037211130023047024766 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ 7:iî–™IDAT8ËÍS;à ó«r›;7{ܧCÇn022pw¢ „ Jé7Zò §ªÜÁ¥ÇdDŒ1Žø°Ö‚$¼÷²PUVba(àœc¨*­µüõJN¬i/8xKÞÇiû"¿½^o÷(azB7IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/radio.on.down.png0000644000000000000000000000037011130023047024443 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ 8/ƒ«â²—IDAT8ËcdÀþãgDcĦñÀØô38880üÿÿŸ¡±±‘À†††ÿ0S&t`5 § ‚ÁÞÞn#²f\±5v0444021PqÙ®c`¿ráVW`uºf\b {a€-À°‰ ŽtÀË$$ÛŽ33…xàÔˆž+)ÍάNnNÌ)^IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/dialog.close.down.png0000644000000000000000000000041611130023047025276 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ  8”­­IDAT8Ë¥’1‚@E߮ܠ:(§´1¡ð &`)¥³°ÞcÈZÍÄ Yßíßü—ý³ãD$ò§Bd"²:|jo€6ÖʳQ& ¬ʪY䛀ûíú è°¾KVйpr:`…“«Âb€~¶5“ä/ÌUø…d©î)ßoÙBcŒ[6Ñ郈Ä÷´EÁ±®Ùç9qäÒ÷œ‡ç4Ñu3dù:øÑ ŒÖDÇ3 }òIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/checkbox.off.normal.png0000644000000000000000000000026211130023047025612 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ  :C4ºQIDAT8ËíÓ¡À0@ÑŸ^öYY‘}ÀVVt"z€ÄTä{Þ! ¨j0™ˆPÜ==Ü®àÌ,¼Ï ÀÁbØÀ?€:cÜv¶±²A‰´ÐÂAÉIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/list.png0000644000000000000000000000020111130023047022730 0ustar rootroot‰PNG  IHDR„ž„HIDAT8íÔ± @!EÑ‹‹Á*LÆ*lƯLŒ•ÄîÇ[¿S‚TfV4ËLU-€ˆ8†îÀèÂu?Zjëá‡ç‰6÷ró >8‘Øîê¼IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/dialog.close.normal.png0000644000000000000000000000033111130023047025613 0ustar rootroot‰PNG  IHDR&/œŠ pHYs  šœtIMEÕ  7£ë¾xIDAT(Ï¥’1€ E?†ã002–û:8zÝ$ÑóÔÍ4á%ï¥-5ÌÌèLŒ®´ÿ†çeLL&p>Àù€Öz&8í$,ßTÁ[¢Áê$PƒUAi„fl»´“Ï_¨P’Xmö–úð!Yy–=1DÄ#ÜT2^áº5IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/radio.off.down.png0000644000000000000000000000034011130023047024576 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ 9¡Þó;IDAT8ËcdÀþãgDcĦñÀØô38880üÿÿŸ¡±±‘À†††ÿ0S&t`5 § ‚ÁÞÞn#²f\±5v0444021PɱÙ»`Ô€Á˜`™ÄÁÁdÛqf¦œÑs%#¥Ù‰¾En.P–«IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/desktop.png0000644000000000000000000000020311130023047023430 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ  "³¬û"IDAT8Ëc¼rá5•À¨A£4jШA£‘:kœÆËºÜIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/button.normal.png0000644000000000000000000000030711130023047024566 0ustar rootroot‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  4.Ñ0•²TIDATHÇíÖ!€@ DÑ¿dÖÞä Hç) ± ²ã¦IõëÔ´(„µTU{Gó“žûj›z?Î5|E 0`À€˜g®ÈLY‚¡~[^ ÅIÓ3IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/radio.off.normal.png0000644000000000000000000000035611130023047025126 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ 9ØKŸIDAT8Ëí“¡Ã0C}Sÿf`p0—?»üÏÀàXò?Š´¶×jRÈÀŒ¢“l? ™î²½‰g,¥x~¨*H"¥$»3ã0æœÝ€# „° ™QUù­z«´LjèGØž®·ûxršàð ÿ`EÑ[eoõ´ù³–ÍÒxVòx¾v«”Ù9¿ëÛ¹N pœIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/console.png0000644000000000000000000000034011130023047023423 0ustar rootroot‰PNG  IHDRàw=ø§IDATH‰í–1à ^†ü±»û˜µŸrëM[&‰"lK)‰æŠ¸fI’p$"Úá˜Y:ÎÒ^PƒK)=ù Ùˆ^‚ˆP >+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/console.input.focus.png0000644000000000000000000000034011130023047025677 0ustar rootroot‰PNG  IHDRàw=ø§IDATH‰í–AÂ0 ×Eü£¶ûÇ#rír€šD™Tâ•|±”Ç—µD)w¯›_HU¥ìZÆv¶ˆ?à`" ’03â†G!XÏ÷fÆÕwo5n€VH€œsl%´yvŸ¾øEê>z¡€€€$Tµ{¨ê+Dª(ýY›çÑ‘)ïW…»sYÌ—94õtRÚ…¾´ÎU -î^íúqÒz§xaIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/checkbox.on.down.png0000644000000000000000000000032511130023047025133 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ :$"Â% tIDAT8ËclhhøÏ@&¨¯¯g`a```8pàÉš§Lè````€€,@*`b Ð× ò À¦§èŠqiÆë˜&dÍW.œ Í „4ã4]1.Íx]Ó„O3A/ÒL½„Dn>`````üÿÿÿJ\Ô¼$_óƒÙIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/box.down.png0000644000000000000000000000034111130023047023520 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  1)2#ôTtEXtCommentCreated with The GIMPïd%nEIDAT8ËíÓ¡€0Ñ_^‡C"(!l‡kk=§’‚Û’tÉIÞìÛÚ$çƒÌÀ ü#P¿Ûn¥ŒÞùÃ^ 77i$IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/button.down.png0000644000000000000000000000027711130023047024253 0ustar rootroot‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  6OºpLIDATHÇíÖ¡À0 Á“GŸ /ÈÀÐÝ% ,Ø"ž¿~¡ÀCa ©d\ÒôûÚ:>æ Qœ 0pÿº»¨~[^¼Ë G¸k'IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/select.selected.normal.png0000644000000000000000000000020711130023047026320 0ustar rootroot‰PNG  IHDRàw=ø pHYs  šœtIMEÕ  4âu½Ä&IDATHÇíÍ1ðÏÅû€mÊ ~-,KB“IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/dialog.png0000644000000000000000000000021211130023047023216 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ùŽ‚)IDAT8Ëcd``¸ráe@ÇÀ‚‰J`Ô QƒF 5hÔ hÕþŠ.7ƒKIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/checkbox.off.down.png0000644000000000000000000000024511130023047025272 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ :Ž~ÜJDIDAT8Ëí“! ¿7‰Dð ý¬ 0N6饦ÉÝÅ!fFˆˆíro` Ö`—Ì%_ð N$éfÁLÇ_¨`WãIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/slider.png0000644000000000000000000000022111130023047023241 0ustar rootroot‰PNG  IHDRàw=ø pHYs  šœtIMEÕ  5ü\f>0IDATHÇíÏ¡ ÄÀß2$‚}Êàªêš\¦ €¯æs>]D (P à¤ [™TYOÍthIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/filebrowser.folder.png0000644000000000000000000000117211130023047025562 0ustar rootroot‰PNG  IHDR/Ä<ðAIDAT8­ÔMKTQÀñÿÔ” M3ˆƒ‹Ç[HM‚/©Ì,Ú"—ÑÊe´ û~‚hш¢¸pÛÜ)ÂÊD-,˲73|IÆÇ;sï9çi¡CZ£nzàð8çüx8o>ᆿұm[²Ù,¶m³ð~ßÑì§ã•1*c¹\ŽL&C<÷U}"B:–Çc÷H´’èl¥ùtÙWŸ¸4x—Þö(½íQ.^h¦+ÖDvbžö###ûƒÃÃÃÒ×ÙF_ÓO”2h­PJã¹ ÏS(Oá)ç)Ê®¢ÿæCüÇëH¥RX–µöƒAž<Ÿ%<†ëþ”= ùÊÔG œŠ2a_aîÍ ²33X–õïÆãql;C¡ä'¿þ §èPÜ,s"%ÐØBk[=õ଀³ ’ãÑä$ÁpLJµ צ¹£{(.‚³ ²„¬-b Æ2ão¹uçzu0™LúÉçòœéì'Tz¬|#ˆŒÖh£·³V­™žûVYW½B§¸ÅÉZ…·áb´Æh…6JVZs¤&XíwƒBm Ï-SÚÌcŒBë]UíÀZkÖsE"‘Èa 44ÅØZ™§TÌï©ÊSŠrÙÅqÊÌ.¬2öì#‘H÷á`aí;u…|npy9ûƒw_Ö˜þ°Ì×5Ž®7ªz±D„øù˜8ùE¹wûª ^>+çZ …IJ,I¥R255%•¹5_åsH§Ó2::J("‘HL&÷}¯Åo{T{.wTºIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/tool.down.png0000644000000000000000000000025011130023047023704 0ustar rootroot‰PNG  IHDRàw=ø pHYs  šœtIMEÕ  .5êºÌ²GIDATHÇíÕ¡ ÁƒIqH¥óG`(€æOFd'* EI"2óùò5ÀîÁë:Å0`À€Uÿ $•^°Ws s®9IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/checkbox.on.normal.png0000644000000000000000000000033011130023047025450 0ustar rootroot‰PNG  IHDRóÿa pHYs  šœtIMEÕ  8â{MfwIDAT8˽“1 €0 E_¤÷nGGïÓ®Žž'Rb[£âŸó?HAyï= ¥d†çi81F“`[^æ_ˆ<\ÁUA9\ƒ› 2t†UÕ¶B® ÊáÜl¡Ü]¡rH.?F¾mkDïôld f)Ð1…¶IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/select.arrow.normal.png0000644000000000000000000000025011130023047025660 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ 9¼BÍÍGIDAT8Ëc¼ráÅ § ‚…A[ßœSX œ«ORè(&*QƒF 5hÔ QƒpxéM!`tpp Š‹‚† »*R0öIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/menu.hover.png0000644000000000000000000000022611130023047024052 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ wSµ5IDAT8Ëcüÿÿ?Å ±±‘…áêÅ“”›ÅÄ@%0jШA£4jÐÐ1ˆ¥±±‘*kq¦Js«IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/gray/console.input.normal.png0000644000000000000000000000034011130023047026050 0ustar rootroot‰PNG  IHDRàw=ø§IDATH‰í–1à ^†ü±»û˜µŸrëM[&‰"lK)‰æŠ¸fI’p$"Úá˜Y:ÎÒ^PƒK)=ù Ùˆ^‚ˆP >+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/0000755000000000000000000000000011414467236021475 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.fill.tga0000644000000000000000000000230511130023047024365 0ustar rootroot 00 (¯¯¯¯œ‚ªªªÿšªªªÿUUUÿªªªÿÿÿÿÿªªªÿ™ªªªÿ‚UUUÿªªªÿ‚ÿÿÿÿªªªÿ‹™ªªªÿ‚UUUÿªªªÿ„ÿÿÿÿªªªÿ‰˜ªªªÿƒUUUÿªªªÿ…ÿÿÿÿªªªÿ‡˜ªªªÿƒUUUÿƒªªªÿ…ÿÿÿÿªªªÿ…—ªªªÿƒUUUÿ†ªªªÿ„ÿÿÿÿªªªÿ…—ªªªÿ‚UUUÿ‰ªªªÿƒÿÿÿÿªªªÿ„—ªªªÿ‚UUUÿ‹ªªªÿÿÿÿÿªªªÿ„–ªªªÿUUUÿÿªªªÿ„–ªªªÿÿªªªÿ„–‚ÿªªªÿ‚UUUÿŠªªªÿ…–ÿ‚ªªªÿ„UUUÿˆªªªÿ…•‚ÿ‚‚ªªªÿƒUUUÿ…ªªªÿ†•‚ÿ…‚ªªªÿ‚UUUÿªªªÿˆ•ƒÿ‡ƒªªªÿ‰‹ÿ•†•ÿ’…™ÿ„šÿ„…ÿ„„¦ÿƒ„§ÿ‚„§ÿ‚„§ÿ‚…¦ÿ‚‘šÿ‚’‰ÿ„‰ÿƒ£…ÿ…¯¯ƒ…ÿˆÿ†ÿ“ƒÿÿ†ÿ“ƒÿÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿˆÿƒÿ†ÿ“‚„ÿ…ÿƒÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿˆÿƒÿ†ÿ“ƒÿÿ†ÿ’’ÿš¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/config.txt0000644000000000000000000000046511130023047023467 0ustar rootroottool.draw image icons48.draw.tga tool.pixel image icons48.pixel.tga tool.line image icons48.line.tga tool.fill image icons48.fill.tga tool.select image icons48.select.tga tool.eraser image icons48.eraser.tga tool.tile image icons48.tile.tga tool.code image icons48.code.tga tool.bkgr image icons48.bkgr.tga python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.tile.tga0000644000000000000000000000236411130023047024401 0ustar rootroot 00 (¯¯¯¯¯¯…‡ÿÿÿÿ¡…ªªªÿ…ÿÿÿÿªªªÿ¡…ªªªÿƒÿÿÿÿªªªÿ¡…‚ªªªÿÿÿÿÿ‚ªªªÿ¡…‡ªªªÿˆ‡ÿÿÿÿ…‚ªªªÿUUUÿ‚ªªªÿˆªªªÿ…ÿÿÿÿªªªÿ…ªªªÿƒUUUÿªªªÿˆªªªÿƒÿÿÿÿªªªÿ…ªªªÿ…UUUÿªªªÿˆ‚ªªªÿÿÿÿÿ‚ªªªÿ…‡UUUÿˆ‡ªªªÿ–‚ªªªÿUUUÿ‚ªªªÿ–ªªªÿƒUUUÿªªªÿ–ªªªÿ…UUUÿªªªÿ–‡UUUÿ¯‡ÿÿÿÿ—ªªªÿ…ÿÿÿÿªªªÿ—ªªªÿƒÿÿÿÿªªªÿ—‚ªªªÿÿÿÿÿ‚ªªªÿ—‡ªªªÿ—‚ªªªÿUUUÿ‚ªªªÿ…‡ÿÿÿÿ‰ªªªÿƒUUUÿªªªÿ…ªªªÿ…ÿÿÿÿªªªÿ‰ªªªÿ…UUUÿªªªÿ…ªªªÿƒÿÿÿÿªªªÿ‰‡UUUÿ…‚ªªªÿÿÿÿÿ‚ªªªÿ‰‡ªªªÿ‰‚ªªªÿUUUÿ‚ªªªÿ‰ªªªÿƒUUUÿªªªÿ‰ªªªÿ…UUUÿªªªÿ‰‡UUUÿ‰‰ÿÿ’‰ÿÿ’‰ÿ†ÿˆÿ……ÿ†‰ÿÿ…ÿƒÿ†‰ÿÿ…ÿ„ÿ††‡ÿƒÿ†ÿ…ÿ…ÿ…‰ÿ‡ÿ†ÿ…‡ÿ…‰ÿ‡ÿ†ÿ…ÿŒ‰ÿ†ÿ†ÿ„ÿŒŠÿÿ„ÿ†ÿ„‚ÿ‚ÿ†Šƒÿ”„ÿ†¯¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.eraser.tga0000644000000000000000000000254511130023047024726 0ustar rootroot 00 (¯¯¯¯ŸÿŽžÿŽe­ôÿÿŽe­ôÿ‘Ùÿÿœe­ôÿ‘Ùÿÿœe­ôÿ‘Ùÿÿ›e­ôÿ‘Ùÿÿše­ôÿ‘Ùÿÿ‘še­ôÿ‘Ùÿÿ’™e­ôÿ‘Ùÿÿ’™e­ôÿ‘Ùÿÿ“˜e­ôÿ‘Ùÿÿ“—e­ôÿ‘Ùÿÿ”—e­ôÿ‘Ùÿÿ•–e­ôÿ‘Ùÿÿ•–e­ôÿ‘Ùÿÿ–”ªªªÿ‘Ùÿÿ–Œ…ÿ¹¿ÿÿªªªÿÿÿÿÿ—‰ˆÿ¹¿ÿÿÿÿÿÿ—„Œÿ‚¹¿ÿÿÿ”ƒŒÿ†ƒÿ“‚Œÿ†…ÿ’‚‹ÿ†‡ÿ†…ÿ„‚Šÿ†˜ÿ‹ÿ…™ÿŠÿ…›ÿ€‰ÿ…œÿ€‚‡ÿ…ÿ€žÿ€ŽŸÿ€ŸÿŽŠÿ„ÿ‚†ÿ‰ˆÿ…¯‚…ÿƒÿ¡ÿƒÿ‚ÿ„ƒÿ†…ÿ‚…ÿ‚ÿ…ÿ‚‚ÿÿÿ„ÿƒÿ‚ÿƒÿÿ…ÿÿƒÿƒÿ„ÿ‡ÿ„ÿˆÿÿ‚ÿƒÿ„‚ÿ…‡ÿÿ‰ÿ‚ÿ„ÿ‡ƒÿÿˆÿ‰ÿ‚ÿƒÿŠÿÿˆ‚ÿ‡ÿ‚‚ÿ‚ÿƒÿ„ÿÿ„ÿ„ƒÿ‰‚ÿ‚ÿ…ÿƒ†ÿ¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.line.tga0000644000000000000000000000216511130023047024372 0ustar rootroot 00 (¯¯¯¯œ¹¿ÿÿ›ÿÿÿÿ¹¿ÿÿ›ÿÿÿÿªªªÿ¹¿ÿÿš‘Ùÿÿªªªÿš‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ“˜‘Ùÿÿe­ôÿ“—‘Ùÿÿe­ôÿ”—‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ–•‘Ùÿÿe­ôÿ–”‘Ùÿÿe­ôÿ—”‘Ùÿÿe­ôÿ˜“‘Ùÿÿe­ôÿ˜“‘Ùÿÿe­ôÿ™’ÿe­ôÿ™’ÿš’ÿ›‘‚ÿš”‚ÿ——‚ÿ”šÿ’œ‚ÿŸ‚ÿŒ¢ÿФ‚ÿ‡§‚ÿ„„ÿ¤ÿ‚„ÿ†ÿ¡„ÿ™ƒÿ‹„ÿÿ„ÿƒÿ‚ÿ‰„ÿ†ÿ…‚ÿ‚ÿ‚ÿ„ÿˆ„ÿ†ÿ…ÿ…ÿ‚ÿ…ÿˆ„ÿ†ÿ…ÿ…ÿ‚ÿ…ÿ‡„ÿ†ÿ…ÿ…ÿ‚ˆÿ‡„ÿ†ÿ…ÿ…ÿ‚ÿ„ÿ†ÿ…ÿ…ÿ‚ÿŽ„ÿ†ÿ…ÿ…ÿƒ‡ÿ‡„ÿ“ÿ“¯¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.pixel.tga0000644000000000000000000000227211130023047024563 0ustar rootroot 00 (¯¯¯¯œ¹¿ÿÿ›ÿÿÿÿ¹¿ÿÿ›ÿÿÿÿªªªÿ¹¿ÿÿš‘Ùÿÿªªªÿš‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ“˜‘Ùÿÿe­ôÿ“—‘Ùÿÿe­ôÿ”—‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ–•‘Ùÿÿe­ôÿ–”‘Ùÿÿe­ôÿ—ÿƒ‘Ùÿÿe­ôÿ˜“‘Ùÿÿe­ôÿ˜‹ÿ†‘Ùÿÿe­ôÿ™“ÿe­ôÿ™’ÿ‡ÿ‚ÿ“ÿƒÿŠÿ‰¯ÿ“ÿ‡¯¯¯¯¯¤ÿ‰¤ÿ‰¤ÿ‰ÿ•ÿ‰—ÿƒ‚ÿ„ÿ‰†ƒÿ†ÿƒÿ‚ÿÿƒÿ‰ƒ‚ÿ‚ÿ‚ÿ‚‚ÿÿƒÿ‚ÿƒÿ‰ƒÿ„ÿ‚ÿ„ƒÿ‚ÿƒÿ‚ÿ‰ƒÿ„ÿ‚ÿ…ÿƒ†ÿ‚ÿ‰ƒÿƒÿ‚ÿ…‚ÿ‚ÿˆÿ‰„ÿ‚ÿƒÿ„ÿÿÿ‡ÿ‰„‚ÿ…ÿƒÿ‚ÿ‚…ÿ‚ÿˆ„ÿ‹ÿÿˆ„ÿ©„ÿ©¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.code.tga0000644000000000000000000000252011130023047024350 0ustar rootroot 00 (¯¯¯¯†ÿ§†ÿ§†ÿ™‚ÿІÿœÿ‰†ÿœÿ‰†ÿ›ÿ‰†ÿšƒÿˆ†ÿ‚ÿŠÿˆ†ÿŽÿÿ‰ÿˆšÿ‰ÿˆšÿ…ƒÿ‰šÿ“™ÿ“˜ÿ”ÿˆ†ÿŒ‚ÿŸ‹ÿ‚ÿžŠÿÿÿŠÿÿ“ÿŠÿ”‚ÿˆÿ–ÿ‡ÿŽŠÿ†ÿ–ÿ‡ÿ•ÿˆ£ÿ‰¯¯ÿÿÿÿÿ†„ÿ‚„ÿƒ„ÿÿ‚„ÿˆ…ÿ‚ÿÿ‚ÿÿ‚‚ÿÿ‚ÿ‡…ÿ†ÿ„ÿÿ„ÿÿ„ÿ‡…ÿ†ÿ…ÿÿ…ÿÿ„ÿ‡…ÿ†ÿ…ÿÿ„ÿ†ÿ‡…ÿ†ÿ…ÿÿ„ÿÿ…ÿ†ÿ…ÿÿƒÿÿŒ…ÿ†‚ÿ‚ÿƒ‚ÿÿ‚ÿƒÿ†……ÿƒ„ÿ†ƒÿƒ„ÿ†ˆÿ“ÿ¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.bkgr.tga0000644000000000000000000000307311130023047024367 0ustar rootroot 00 (¯¯¯¯¯¯¯¯¯¯¯–…ÿ’”ÿªÿ‚UÿUÿÿ‘“ÿªÿ„UÿUÿÿ“ÿªÿ†UÿUÿÿ„ÿŠ’ÿ‚ªÿ†UÿUÿ‚ÿªÿUÿUÿÿ‰’ÿªÿ‡UÿUÿÿªÿ‚UÿUÿÿˆ’ÿªÿˆUÿUÿÿªÿ„UÿUÿÿˆ‘ÿ‚ªÿˆUÿUÿÿ„UÿUÿÿ‡‘ÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡‘ÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡Œ…ÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡Š‚ÿªÿUÿUÿÿ‚ªÿ‰UÿUÿÿ…UÿUÿÿ‡Šÿ‚ªÿ‚UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ„UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ„UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ…UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ…UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡‰ÿ‚ªÿ…UÿUÿÿªÿ‰UÿUÿÿ…UÿUÿÿ‡†£ÿ„¯¯¯ÿ†ÿˆÿ†ÿˆÿ†ÿˆÿ‚ÿ‡ÿÿ‚ÿ‰†ÿˆÿÿ†„ÿ‚ƒÿ††ÿˆÿÿ†ÿ‚ÿ‚ÿˆ†…ÿƒÿÿ†ÿƒÿ‚ÿ‰‡ÿƒÿ‚ƒÿ†ÿƒÿ‚ÿ‰‡ÿƒÿ‚ÿÿ„ÿƒÿ‚ÿ‰‡ÿƒÿ‚ÿ‚‚ÿƒÿ‚ÿ‚ÿ‰‡ÿƒÿ‚ÿ…ÿ„ÿÿÿ‰‡ÿ‚ÿ‚ÿˆÿ„ÿ‚ÿ‰‡„ÿ†ÿ¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.select.tga0000644000000000000000000000266111130023047024723 0ustar rootroot 00 (¯¯¯¯…¡ÿÿÿÿ‡…¡ÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…ÿÿÿÿÿÿÿÿ‡…¡ÿÿÿÿ‡…¡ÿÿÿÿ‡“ÿ”ÿ„“ÿ”ÿ„“ÿ”ÿ„„‚ÿ„ÿ„ÿ’…ÿƒÿÿƒÿÿ‚ÿ…„ÿ‰ÿ„ƒÿ…ÿ‚ÿ‚ÿ…ÿƒÿƒÿ‚ÿ„ƒÿ…ÿƒÿ‚ÿ„ÿƒÿÿ…ÿ„ƒƒÿ‚…ÿ‚ÿ„†ÿÿ…ÿ„†ÿÿ†ÿ„ÿ†ÿ†ÿ„‡ÿ‚ÿ†ÿƒÿ…ÿ†ÿ„‡ÿ‚‚ÿ…ÿ„ÿ„ÿ…ÿƒƒÿÿ„ƒÿ‚ÿ…‚ÿ„ƒÿ‚‚ÿƒƒÿŒ‚ÿ—¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/tools/icons48.draw.tga0000644000000000000000000000264311130023047024401 0ustar rootroot 00 (¯¯¯¯œ¹¿ÿÿ›ÿÿÿÿ¹¿ÿÿ›ÿÿÿÿªªªÿ¹¿ÿÿš‘Ùÿÿªªªÿš‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ’™‘Ùÿÿe­ôÿ“˜‘Ùÿÿe­ôÿ“—‘Ùÿÿe­ôÿ”—‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ•–‘Ùÿÿe­ôÿ–•‘Ùÿÿe­ôÿ–”‘Ùÿÿe­ôÿ—Œ„ÿ‚‘Ùÿÿe­ôÿ˜‹ÿƒÿ‘Ùÿÿe­ôÿ˜Šÿ„ÿ‘Ùÿÿe­ôÿ™Šÿ†ÿe­ôÿ™Šÿ†ÿe­ôÿ‡ˆÿ‰Šÿ‹„ÿ†ÿˆ‹ÿ‡‚ÿŒÿˆ‡ÿÿ‡¦ÿ‡¦ÿ‡¦ÿ‡¦ÿ‡•„ÿŠÿ‡“‚ÿ‚ÿˆÿˆ’ÿ†ÿ…ÿ‰†ÿ‰ÿˆ‡ÿІÿ§†ÿ§†ÿ£ÿ‚‡ÿÿ’ÿ‚‡ÿƒƒÿƒƒÿƒÿ„ÿ„ÿƒ‡ÿƒÿ…ÿÿ„ÿ‚‚ÿƒÿƒƒ„ÿ‚ÿ…ÿ‚‚ÿ„ÿ‚ÿÿ‚ÿ„ƒÿÿ‚ÿ…ÿ‚ÿÿ„ÿÿÿÿ„‚ÿ‚ÿ‚ÿ…ÿ‚ÿÿ„ÿÿƒÿÿ„‚ÿ‚ÿ‚ÿ…ÿ‚ÿÿƒ‚ÿƒ‚ÿ…‚„ÿƒÿ†ƒÿˆÿ…ÿ…¯¯¯python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/0000755000000000000000000000000011414467237021762 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.options.png0000644000000000000000000000026511130023047025422 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ(%¹tEXtCommentCreated with The GIMPïd%n+IDAT8Ëc` `d``øÿÿ?¥¦022QËE£4jШA£ ƒ¨;…,;)k“IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.option.hover.png0000644000000000000000000000027611130023047026363 0ustar rootroot‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ)ïvŸtEXtCommentCreated with The GIMPïd%n"IDAT8Ëc<òõ?5•À¨A£4jШA£‘AÊè)£ðNIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vslider.tga0000644000000000000000000000231711130023047024110 0ustar rootroot  (‚€€€ÿÿÿ£££ÿªªªÿˆ®®®ÿ°°°ÿ®®®ÿªªªÿ‚ÿÿÿ€€€€€€ÿÿÿ£££ÿ®®®ÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿ¼¼¼ÿ®®®ÿÿÿÿ€€€€€€€ÿÿÿ£££ÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿµµµÿÿÿÿÿÿÿ£££ÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿµµµÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿ£££ÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€¼¼¼ÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ°°°ÿÎÎÎÿéééÿùùùÿýýýÿŠþþþÿÿÿÿÿ‚þþþÿýýýÿùùùÿéééÿ€ÎÎÎÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿÿÿÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿÿÿÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿÿÿÿ€€€ÿÿÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿ‚ÿÿÿ€€€‚ÿÿÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿƒÿÿÿ€€€€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dot.normal.png0000644000000000000000000000055611130023047024531 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÕ^1\£tEXtCommentCreated with The GIMPïd%nÖIDAT(ÏuѱJQ…áïÆËŠZ)ØYÄÁÂÎÖÎ7Ê+Ylµ²0ZZ  "A š±Èn²ÁÍ›9wæÌLêY«Pª‚\%]:R`æÍM¼—¢Ôƒ¸p®U+0wï–´¨gº¾­Ó5õRfOǧÿt¼˜Ê¢íC3mÏ‘)Œ+ãå@ÉöbŠ/³ ~Y³ÞHfËþZƒXîi²LoøýŠ, cg¹Ð:?†¤L¸sÕ ¸¥É4ÒWØ­½B߈TÝ‚h9uâcOÍK§Uó47ˆAùÿþ7³Ìié´IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/tool.hover.tga0000644000000000000000000000106311130023047024534 0ustar rootroot  (@@@•@@@ÿ€@@@@@@ÿ•ÿÿÿÿ€@@@ÿ@@@ÿ÷óáÿ÷óßÿ÷óáÿ‰÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ@@@ÿ•ïæ¿ÿ€@@@ÿ@@@ÿ…çÛ¡ÿˆçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ@@@ÿ•àÏ€ÿ€@@@ÿ@@@ÿ‚×Âaÿ×Â_ÿ×Âaÿˆ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ×ÁYÿ×ÀWÿ‹×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ@@@ÿ•àÌpÿ€@@@ÿ@@@ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿ‹çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ@@@ÿ•ïá¡ÿ€@@@ÿ@@@ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿŠ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ@@@ÿ•ÿ÷Ñÿ€@@@ÿ@@@•@@@ÿ€@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/tool.normal.tga0000644000000000000000000000067111130023047024705 0ustar rootroot  (•ÿ€ÿ•ÿÿÿÿ€ÿÿ•úúúÿ€ÿÿ•ðððÿ€ÿÿ•ãããÿ€ÿÿ•ÒÒÒÿ€ÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿˆ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ‚¿¿¿ÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ»»»ÿºººÿ‹»»»ÿºººÿ»»»ÿºººÿ»»»ÿ€ÿÿ•ËËËÿ€ÿÿ•ØØØÿ€ÿÿ•åååÿ€ÿÿ•ïïïÿ€ÿÿ•÷÷÷ÿ€ÿ•ÿ€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dot.hover.png0000644000000000000000000000104411130023047024355 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ&]L_tEXtCommentCreated with The GIMPïd%nˆIDAT8Ë¥“Í+DaÆw¼H³ð&$Y aCL³r³“¤(›òGXøØ`ce'R²¥$ÙH±›f(a1¢L¾ÆmÌu羓ÛÌex6oÞóœç<=GQU•,d‡’Y™å• ŒŽájo§¦´€Û§|~?›k«2òpŸF¤¤(=½ O D’ט)¯al¬,s¸»c‘|)­]¨/á˜üÕã%ú¦qrx EØívšG¸~{·>Ú”ïͦLÖ›G|hš†¤£ÍMH— Çù-mn®Žö¥x¯kà&#èõp´Ÿôà®´´xNWYFÿ  $¦ÈÙb™”ͼLcc¡Kž¿Ì‹ŽÖŽœ&_],ÊëY@– È+(LÛ)5D©ÁJèqNÏŽ±r€iâ_š§jáWÓ·gfâ{”ËœÍ OÏQTŸuÿ˜þÁúì$Ás+ÊJÆ5J[žÀÙ݇«»gm ÁÐ-¾½‚{Û˜ ãÇcúÓ9†Œ=OÏd"IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.arrow.down.tga0000644000000000000000000000053011130023047026011 0ustar rootroot  (–ÿ€–ÿÿÿÿ€ÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿ€ÿ–êߪÿ€ÿßÎÿßÎÿ„ßÎÿ€ÿ–Õ¾Uÿ€ÿÊ®*ÿË®+ÿÊ®*ÿË®+ÿ‚Ê®*ÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿ–Àžÿ€ÿʬ ÿË­ÿʬ ÿË­ÿʬ ÿ€ÿ–Õ»Aÿ€ÿ’ßÈ_ÿßÉaÿßÈ_ÿ€ÿ–ê×€ÿ€ÿ–ôå ÿ€ÿ–ÿôÁÿ€ÿ–ÿ€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vslider.up.tga0000644000000000000000000000154011130023047024530 0ustar rootroot  (þþþ~~~ÿ€þþþ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿƒÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿ…ÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿ‡ÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿ‰ÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/box.normal.png0000644000000000000000000000036211130023047024526 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÕ)ƒÄÏtEXtCommentCreated with The GIMPïd%nZIDAT(Ï¥‘± €P /ÒAAÿÿt\êòl3¶Ç•PÉw$²ÜpR%àpÀî€Í+´*"è©°”†“€¹éyº'“3Œ¿Á} Ƚû0,2²ÌºIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/Vera.ttf0000644000000000000000000020061411130023047023357 0ustar rootrootOS/2´_ôcëpVPCLTÑŠ^—ëÈ6cmap¤Ãè ±lXcvt ÿÓ9üüfpgmç´ñÄ&`‹gaspH glyf tAÏ&ìŠ~hdmx4ð!ìHheadÝ„¢ÐT6hheaEoëL$hmtx ÆŽ²´Ä0kernÜRÕ™½ -ŠlocaóËÒ=»„maxpG:ë, nameټȵßpost´Z/»¸ôŽprep;ñ øh::_:: dM0­l  ƒ p t › &   Y &  &   c . 5 ` õ s 0¡ & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5¸ËËÁªœ¦¸fqË ²…u¸Ãˉ-˦ðÓª‡ËªJ3ËÙôT´œ99N´R¸çÍ7sÍ`s3¢V¦V9Åɸßsºé3¼Dßͪåªˤ{¸o{RÇÍššoËÍžÓðºƒÕ˜HžÕÁËöƒT3fÓǤ͚sÕ þ+¤´œbœ-ÕÕÕð{T¤¸#Ӹ˦Ãì“ Ó\qÛ…#¨H99`Õš#fy```{œw`ªé`b{Å{´RÍf¼fwÍ;…‰{ÍJ/œœ}oo5jo{®²-–{öƒT7öœáföÍD)fîs¸€@ÿûþúù%ø2÷–öõþôþó%òñ–ð%ïŠAïþî–í–ìúëúêþé:èBçþæ2åäSå–äŠAäSãâ/ãúâ/áþàþß2ÞÝ–ÜþÛÚ}Ù»ØþÖŠAÖ}ÕÔGÕ}ÔGÓÒÓþÒÑþÐþÏþÎþÍ–ÌËÌþËÊ2ÉþÆ…ÆÅÄþÃþÂþÁþÀþ¿þ¾þ½þ¼þ»þº¹†%¹þ¸·»¸þ·¶]·»·€¶µ%¶]@ÿ¶@µ%´þ³–²þ±þ°þ¯þ®d­¬«%¬d«ª«%ª©ŠA©ú¨þ§þ¦þ¥¤þ£¢£2¢¡d ŠA –Ÿþž žþ œ›œd›š›š™ ˜þ—– —þ– •ŠA•–”“”(“’ú‘»‘þ]»€Ž%]@Ž%þŒ‹.Œþ‹.І%ŠA‰ˆ ‰ˆ ‡†%‡d†…†%…„þƒ‚ƒþ‚þ€þþ@ÿ~}}~þ}}|d{T{%zþyþxw v uþtúsúrúqúpþoþnþl!kþjBjSiþh}gBfþeþdþcþbþa:`ú^ ]þ[þZþYX YúX WW2VþUTUBTSSRQJQþP OþNMNþMLþKJKþJIJI IH GþF–E–DþC-CúB»AK@þ?þ>=>=<=<; <@ÿ; :þ9þ878ú76765 65 43 21 2þ1 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $þ#þ"!! dú d BþúBBþdþþþþBþ-B}dþ  þ   þ  þ-þdþ@-þ-þ¸d…++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++¶, °%Id°@QX ÈY!-,°%Id°@QX ÈY!-,  °P° y ¸ÿÿPXY°°%°%#á °P° y ¸ÿÿPXY°°%á-,KPX °ýEDY!-,°%E`D-,KSX°%°%EDY!!-,ED-fþ–f¤@ ûû/ÄÔì1ÔìÔì0!%!!füsüåþ–øòr)5Õ @@ƒ ü<ì2991/äüÌ0K° TX½ @ ÿÀ878Y¶ P ]%3#3#5ËËË¢þþÕýqþ›eŪéÕM@„üüÜì1ô<ì20K°TK°T[X½@ÿÀ878Y@0 @ P ` p   ¿ ]#!#oª$ªÕýÕ+ýÕ+ž¾`@1 ‡  ‡   üÌ91/<Ô<<ü<<Ô<<Ä2ì220@   ]!! !3!!!!#!#!5!!5!þÝT%Dh$i g8þ¡R>þ›h gþÛg¡hþÅ`Tþ¾if…þ²‡þaŸþašþ²™þbžþbž™NšŸªþÓm!(/Õ@U" '&( /)/))/B" ) *!††#Љ*Љ- ) " & 0ü<ìô<ü<ôäì1/äìÄÔäì2Äîî99990KSXíí9í9íY"K° TX½0@00ÿÀ878YK° TK°T[K°T[X½0ÿÀ00@878Y#.'5.546753.'>54&´diÒjfÑoÝÉÚÌd]®SS¯\ãÖãÖdtzqá{þÓ---´@AÈ$¬–£¼ëè¯*.þU#´œ©Ãš jXV`ÕþOnZXhqÿã)ð #'3•@6$%&%&'$'B’ ’.’$’ &Œ($‘4'!%   ! + 1 4üÄìôìîöî991ä2ô<äìîöîî0KSXííY"K° TK° T[K° T[K°T[K°T[K° T[X½4@44ÿÀ878Y"32654&'2#"&546"32654&%3#2#"&546ÑWccWUccUžº» º»ü—VcbWWcd1 üZ ž¼»ŸŸ¹º‘”„‚••‚ƒ•Ü»»ÛÛ»¼Ûa•‚„””„–ùó Û»½ÚÛ¼ºÜÿãþð 0Í@–  † †  † †††  !         B  (('•+•'”$‘Œ .  .'.'!!1üìÄÔÔìÆî99999991/ÆäöæîîÆ9990KSXíí9í9í9í9í9íí9í9ííí9Y"²2]@² " ) **&:4D ^YZ UZZY0g{›š™—• “••"™-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z““—•œœŸš › š 2 2°29]]3267 >73#'#"5467.54632.#"ò[UÔ _¦Iþ{ü;Bº h]ühäƒñþΆ†02Þ¸S¥UWžDiƒ;#Q¡X’Â?@ýøYËr„þþ~þã“YW×€ác?}<¢Å$$¶/1oX3gŪoÕB@ „üì1ôì0K°TK°T[X½@ÿÀ878Y@ @P`p ]#oªÕýÕ+°þò{ O@˜—  Üä2ì991üì0K°TX½@ÿÀ878YK°TX½ÿÀ@878Y#&547{†‚ƒ… –•”—æþ>ççþ;åëÆàßÄì¤þòo @˜— Ü<ôì991üì03#654¤ –••– …ƒƒìþ<ßàþ:ëåÅççÂ=JÃðN@,  ™ ™ ‘    Ô<ä2Ü<ä2991ôÔ<ì2Äì2990%#'%%73%Ãþ™g:þ°rþ°:gþ™:PrPßÂÃbËþ‡yËbÃÂcËyþ‡ËÙÛ #@ œ  Üü<ü<ì1/Ô<ü<Ä0!!#!5!®-ýÓ¨ýÓ-ýÓªýÓ-ª-žÿÃþ@ žƒüìÔÌ1üì073#ðÓ¤Rþ¬þÀ@d߃¶œÜÌ1Ôì0!!dý僤ۮþ·ƒüì1/ì073#ÛÓÓþþÿB²Õ-@BŸ/Ä991ôì0KSXííY"3#ªýøªÕùm‡ÿãð #@   ‘Œ üìôì1äôìî0"32'2#"‹œœû þ÷ûûþ÷ PþÍþÌþÍþÍ3343 þsþ†þ‡þsyzáZÕ K@B     ÔìÄüì1/ì2ôìÔì0KSXY"K°TX½ ÿÀ @878Y´]7!5%3!!þJþ™eÊJü¤ªsH¸HúÕª–Jð¥@'B¡”  ‘   üÄÔìÀÀ91/ì2ôìôì0KSXíí9Y"K°TK°T[K°T[X½@ÿÀ878Y@2UVVzzv‡tvust‚†‚‚‚¨¨]]%!!567>54&#"5>32‰ÁüLs3aM§†_ÓxzÔXèE[þôªªªw‘:m—Iw–BCÌ12èÂ\¥pþëœÿãsð({@. † †     “  “#‘Œ£)&  )üÄÄÔìôì991ìäôäìæîîîî90K°TK°T[X½)@))ÿÀ878Y@ daa d!]!"&'532654&+532654&#"5>32?‘£þÐþè^ÇjTÈm¾Ç¹¥®¶•ž£˜S¾rsÉYæ Ž%ÄÝò%%Ã12–„•¦wps{$&´ Ѳ|«d¤Õ Œ@   B     ÜÔ<Äì291/äÔ<ì290KSXÉÉY"K° TK° T[X½@ÿÀ878Y@* *HYiwŠ+&+6NO O Vfuz… ]] !33##!5þþ5þÕÕÉý^%üãÍü3¨þ `ÞÿãdÕu@#†  ‰   Œ¤  üÄÔìÄî1ääôìæîþÄî90K°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y!!>32!"&'532654&#"Ýý ,X,ú$þÔþï^ÃhZÀk­ÊÊ­Q¡TÕªþ’þîêñþõ Ë10¶œœ¶$&ÿã–ð $X@$ †   ¥  ‰"‘Œ% " !%üììôìä1äôäüäîîî90@ËËÍÍÍËˤ²]]"32654&.#">32# !2¤ˆŸŸˆˆŸŸ L›LÈÓ;²káþðâþýþîPL›;º¢¡»»¡¢ºy¸$&þòþïW]þïëæþêyb¥¨hÕc@B üÌÄ991/ôì0KSXííY"K°TX½@ÿÀ878Y@X9Hg°°]]!#!¨ÀýâÓþý3ÕVú+‹ÿã‹ð #/C@%  ' - ‘Œ'£0 $*$ !0üÄìôÄìîî991ìäôìîî990"32654&%&&54632#"$54632654&#"‹¥¥¦¥þ¥‚‘ÿÞßþ‘’£þ÷÷÷þ÷¤H‘ƒ‚““‚ƒ‘Åš‡‡š›†‡šV ²€³Ðг€² "ÆÙèèÙÆat‚‚tt‚‚ÿã‡ð$X@#†  ¥ ‰ ‘Œ%!"" %üìäôìì1äôìæþõîî90@ÄÂÀÀÀÂμé]]7532#"543 !"&2654&#"áLœKÈÓ:²làþûâþ±þåLœ>ˆŸŸˆˆŸŸ¸$& V\ëæþsþ†þŸþ[—º¢¡»»¡¢ºðÃ#@ƒ¦ƒü<ì21/ìôì073#3#ðÓÓÓÓþþ#þžÿÃ# %@ƒžƒ¦  ü<ì2ÔÌ1äüìî03#3#ðÓÓÓ¤R#þýÙ¬þÀ@Ù^Û¦M@*œœœœB¨§$#üì291ôì90KSXííííY" 5Ûûøúþðþ‘þ“¶ѦÑÙ`Û¢@ œœ#ü<Ä21ÔìÔì0!!!!Ùúþúþ¢¨ðªÙ^Û¦O@+œœœœB¨§$#ü<ì91ôì90KSXííííY"55Ùúþð¶þ/¦þ/¶m“°ð$p@+$  †ˆ•‘ƒ   &%ÜÄüìÔìî99991/îöþôîÍ9990K° TX½%@%%ÿÀ878Y¶y z z ]%3##546?>54&#"5>32‡ËËÅ¿8ZZ93ƒlO³a^Ág¸ßHZX/'þþ‘še‚VY5^1YnFC¼98ŸL‰VV/5<4‡þœq¢ L•@2  ©©L43¬0©7¬$©7CM34( (+(I+*(I,=MÜìüìþýþ<Æî991ÔÄüìþíÔÆÅî2Äî990K° TK° T[K°T[K°T[K°T[X½MÿÀMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32úŽ|{zy!<›g¬×Ø«gœ;’¥?@hþÕ°{â`±smiùhZ}þÙ˜¹þ¸€€†ˆ~R½Ôk{KOþÂþè£¤ŽŒ¥¤þHMIùÈÈúKLƒý ß±k¼Pƒ‹A@fþµÁŸþêjhmWQoagƒ}}I½¶J}‡® bæ{þùþÐhÕ º@A       B•    ÔÄ91/<äÔì90KSXííííííííY"² ]@:XvpŒ VXP ghxv|rwx‡ˆ€ ˜™–]] !3#!#¼þî%þ{å9Òˆý_ˆÕý®ú+þÉìÕ C@#• •• ­ . !üì2üìÔì9991/ììôìî90²"]!2654&#!2654&#%!2#!“D££þ¼+”‘‘”þ çú€|•¥þðûýèÉý݇‹Œ…fþ>orqp¦À±‰¢ ˘ÈÚsÿã'ð6@ ¡® •¡®•‘Œ 0üì2ì1äôìôìîöî0´].# !267# !2'fç‚ÿþð‚çfjí„þ­þz†S†íbÕ_^þÇþØþÙþÇ^_ÓHHŸghŸGɰÕ.@• •  2 üìôì99991/ìôì0²`]3 !%! )“ô5þáþËþBŸ²–þhþPþa/ûw.,¦þ—þ€þ~þ–É‹Õ .@•••­   üì2ÔÄÄ1/ììôìî0² ]!!!!!!ɰýÇý9øü>ÕªþFªýãªÉ#Õ )@••­ üì2ÔÄ1/ìôìî0² ]!!!!#ÉZýpPý°ÊÕªþHªý7sÿã‹ð9@ ••¡®•‘Œ43 üìüäüÄ1äôìôìþÔî990%!5!# !2&&# !26Ãþ¶uþæ þ¢þu‹^’opü‹þîþík¨Õ‘¦ýSU™mn™HF×_`þÎþÑþÒþÎ%É;Õ ,@•­ 8  üì2üì21/<ä2üì0²P ]3!3#!#ÉÊÞÊÊý"ÊÕýœdú+Çý9É“Õ9·¯üì1/ì0K°TX½ÿÀ@878Y@ 0@P`Ÿ]3#ÉÊÊÕú+ÿ–þf“Õ M@ •° 9 üìä991äüì990K°TX½ ÿÀ @878Y@ 0 @ P ` Ÿ ]3+53265ÉÊÍãM?†nÕú“þòôª–ÂÉjÕ ï@(B¯  üì2ÔÄ91/<ì290KSXííííY"²]@’ ((764GFCUgvwƒˆ”›ç    (+*66650 A@E@@@ b`hgwp ‹‹Ž š¶µÅÅ×Öèéèê÷øù,]q]q3! !#ÉÊžýþöý3ÊÕý‰wýHüãÏý1ÉjÕ%@ •:üìì1/äì0@ 0P€€]3!!ÉÊ×ü_ÕúÕªÉÕ ¿@4  B ¯   >  üìüì91/<Äì290KSXííííY"²p]@V   && & 45 i|{y €‚‚  #,'( 4<VY ej vy •›]]! !###É-}-ÅþËþÄÕüøú+üúáÉ3Õ y@B¯6 üìüì991/<ì2990KSXííY"² ]@068HGif€ FIWXeiy…Š•šŸ ]]!3!#É–ÄþðýjÄÕûáú+áûsÿãÙð #@•• ‘Œ 3üìüì1äôìî0"32' ! 'ÜþýÜÜþÿÜ:xþˆþÆþÅþ‡yLþ¸þåþæþ¸HH¤þ[þžþŸþ[¤bb¥ÉÕ:@••   ? üì2üì91/ôìÔì0@ ?_¯]32654&#%!2+#“þššþ8ÈûþÿûþÊ/ýÏ’‡†’¦ãÛÝâý¨sþøÙð R@*  B ••‘Œ    3üìüì9991Ääôìî990KSXíí9Y""32#'# ! 'ÜþýÜÜþÿ? ôÝ!#þÅþ‡y;:xÑLþ¸þåþæþ¸HHúÏþÝï¥ab¥þ[þžþüþŽÉTÕ±@5  B• •   ?  üì2üÄì99991/<ôìÔì9990KSXíí9Y"²@]@Bz%%%&'&&& 66FFhuuwˆˆ˜˜]]#.+#! 32654&#A{>ÍÙ¿J‹xÜÊÈüƒý‰þ’••’¼~þh–bý‰ÕÖØºOýƒ…‡ÿã¢ð'~@<    B ¡”••”%‘Œ( "-"(ÜÄìüìä99991äôäìîöîÆ90KSXí9í9Y"²)]¶)/)O)].#"!"&'532654&/.54$32HsÌ_¥³w¦zâ×þÝþçjï€{ìr­¼‡š{âÊõiÚ¤Å76€vce+Ù¶Ùà0/ÐEFˆ~n|-À«Æä&ÿúéÕJ@•@@Ôäüä1/ôì20K° TX½@ÿÀ878Y@  @ p Ÿ ]!!#!ïýîËýîÕªúÕ+²ÿã)ÕK@ •Œ  8Aüìüì1ä2ôì99990K°TX½@ÿÀ878Y¶Ÿ]332653! ²Ë®Ã®ËþßþæþåþßÕüuðÓÓð‹ü\þÜþÖ*$hÕ·@'B¯ÔÄ91/ì290KSXííííY"²P]@b*GGZ}ƒ *&&))% 833<<7HEEIIGYVfiizvvyyu€˜—)]]!3 3JýÆÓÙÚÒýÇÕûéú+D¦Õ {@I      B ¯    ÔÌ91/<ì2290KSXííííííííY"²]@ò  ($ >>4 0 LMB @ Yjkg ` {|€ –•     !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx  †‡ˆ‰… Š —Ÿ¯[]]3 3 3# #DÌ:9ã:9Íþ‰þþÅþÂþÕûîûîú+úð=;Õ ]@F      B ¯   ÔÄÜÄ91/<ì290KSXííííííííY"K° TK° T[K°T[X½ ÿÀ @878Y@¸ '' 486 KX[fkww †€‡‹… ”—–     &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x €€ƒˆ…„ƒ ”——•“ Ÿ ¯ @]]3 3 # #ÙsuÙþ Ùþ\þYÚÕýÕ+ý3üø{ý…ÿüçÕ”@(B¯@@ Ôäüä91/ì290KSXííííY"² ]@<5000F@@@QQQe„“ &)78@ ghxp Ÿ ]]3 3#Ùž›ÙýðËÕýšfüòý9Ç\Õ ›@B••B ÜÄÔä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878Y@@ )&8HGH    / 59? GJO UYfio wx Ÿ ]]!!!5!s•üPÇû=°ügÕšûoªš‘°þòXS@©²©±CÜüÌ21üìôì0K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y!#3!°¨ððþXùüÿB²Õ-@BŸ/Ä991ôì0KSXííY"#ªªýøÕùm“Çþòo<@©²©±Cü<Üì1üìôì0K°TK°T[X½ÿÀ@878Y!53#5oþXïïøÞÙ¨ÛÕ@ ÜÌ91ôÌ290##¼ÉþHþHÉÕýÓ‹þu-ÿìþþ¬µ©ÄÄ1Ôì0!5ûØþ¬ªð‰f1@ ´³DÜì1ôì0K° TK°T[X½ÿÀ@878Y #o™þºfþŠv{ÿã-{ %¼@'  ©¹ †º¹#¸Œ   E&üìÌÔì22991/ÄäôüôìÆîî9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p'…‡‡‡ ‡!…"' 'ð'000 0!@@@ @!PPP P!``` `!ppp p!€€€ €!]]"326=7#5#"&5463!54&#"5>32¾ß¬o™¹¸¸?¼ˆ¬Ëýû§—`¶Te¾Zóð3f{bsÙ´)LýªfaÁ¢½À‹..ª''üºÿ㤠8@¹  ¹Œ¸—G Füì22ôì1/ìäôÄìÆî0¶`€ ]4&#"326>32#"&'#3å§’’§§’’§ýŽ:±{ÌÿÿÌ{±:¹¹/ËççËËççRdaþ¼þøþøþ¼ad¨qÿãç{?@†ˆ† ˆ ¹¹¸Œ HEüä2ì1äôìþôîõî0@ € ].#"3267#"!2çNP³ÆÆ³PNM¥]ýþÖ-U¢5¬++ãÍÍã++ª$$>:#qÿãZ8@¹¹Œ¸—G Eüìôì221/ìäôÄìÄî0¶`€ ]3#5#"3232654&#"¢¸¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶^ùì¨daDDaþËççËËççqÿã{p@$ †ˆ©¹ »¹¸ ŒKEüìôìÄ91äôìäîîôî90@)?p Ðð?????,// , ooooo ]q]!3267# 32.#"ü² Í·jÇbcÐkþôþÇ)ü⸥ˆš¹^Z¾Ç44®*,8 CþÝÄ—´®ž/øp@ ©‡—¼    Lü<Äü<ÄÄ991/ä2üìî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y¶@P ]#"!!##535463ø°cM/þѹ°°®½™Phcü/ÑN»«qþVZ{ (J@#  †¹¹&#¸'¼ ¹½& G E)üÄìôì221/ÄäìäôÄìþÕî990¶`*€* *]4&#"326!"&'5326=#"3253¢¥•”¥¥”•¥¸þþúa¬QQžRµ´9²|ÎüüÎ|²9¸=ÈÜÜÈÇÜÜëþâþé³,*½¿[cb::bcªºd4@ ‡¸ — N  Füì2ôì1/<ìôÄì90²`]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡ýžedïÁy+@¾±¼Fü<ì21/äüì0@  @ P ` p ]3#3#Á¸¸¸¸`û éÿÛþVy D@ ¾ ‡½¼ ±O  Fü<ì2ä991ìäôìî990@ @P`p]3+532653#Á¸£µF1iL¸¸`ûŒÖÀœa™(麜 ¼@)B¼— F üì2ÔÄ91/<ìä90KSXííííY"² ]@_ ')+Vfgsw‚‰Ž“–—£    ('(++@ h` ‰…‰š—ª§¶ÅÖ÷ð÷ð]q]33 ##º¹%ëý®kðýǹüiãýôý¬#ýÝÁy"·—Füì1/ì0@ @P`pð]3#Á¸¸ùìº{"Z@&  ‡ ¸¼PPF#üì2üüüì91/<<äô<Äì290@0$P$p$$ $ $¿$ß$ÿ$ ]>32#4&#"#4&#"#3>32)EÀ‚¯¾¹ru¦¹rw¦¹¹?°yz«‰|võâý\ž¡œ¾¤ý‡ž¢›¿£ý‡`®gb|ºd{6@ ‡¸ ¼ N  Füì2ôì1/<äôÄì90´`Ï]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡`®edïqÿãu{ J@¹¹ ¸Œ QEüìôì1äôìî0@#?{{   {  { ð]"32654&'2#"s”¬«•“¬¬“ðþîðñþïßçÉÉçèÈÇéœþÈþìþíþÇ98ºþV¤{>@¹¹¸Œ½¼ GFüì22ôì1äääôÄìÄî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý® ªdaþ¼þøþøþ¼aëËççËËççqþVZ{ >@¹  ¹¸Œ½¼ GEüìôì221äääôÄìÆî0@ `€ à]32654&#"#"3253#/§’’¨¨’’§s:±|ËÿÿË|±:¸¸/ËççËËççý®daDDadªùöºJ{0@  ‡¸ ¼ FüÄì21/äôìÄÔÌ90´PŸ].#"#3>32JI,œ§¹¹:º….´˾ý²`®fcoÿãÇ{'ç@<  S  SB †‰†‰¹¹%¸Œ( R"E(üÄìÔìä99991äôìþõîõî90KSXí9í9Y"²']@m   . , , , ; ; ; ; $( ( *//*(() )!$'† † † †      '/)?)_))€)) )ð)]]q.#"#"&'532654&/.54632‹N¨Z‰‰b”?Ä¥÷ØZÃlfÆa‚Œe«@«˜àÎf´?®((TT@I!*™‰œ¶##¾55YQKP%$•‚ž¬7òž8@©¼‡  Fü<Äü<Ä2991/ìô<Äì2990²¯]!!;#"&5#53w{þ…Ks½½Õ¢‡‡žþÂý ‰NšŸÒ`>®ÿãX`6@ ‡Œ ¼  NFüìôì21/ä2ôÄì90´`Ï]332653#5#"&®¸||•­¸¸C±uÁȺ¦ýaŸŸ¾¤{û ¬fcð=`@'B¿ÔÄ91/ì290KSXííííY"K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@ŽHj{†€‘¤  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz……‰‰‰†––—š˜˜—¨§°Àßÿ>]]3 3#=Ã^^Ãþ\ú`üT¬û V5` @IU U U U   B ¿    ÔÌ91/<ì2290KSXííííííííY"K° TK°T[K°T[K°T[K° T[X½ ÿÀ @878YK° TK° T[K°T[X½ @ ÿÀ878Y@ÿ" 5 IIF @ [[U P nnf yy‡™˜” ¼¼ÎÇÏ         %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } ‡ˆ——”“œ›˜˜™@/– Ÿ¦¦¤¤««©©«¤ ¯µ±½»¸ ¿ÄÃÌÊy]]333# #V¸æåÙæå¸þÛÙñòÙ`ü–jü–jû –üj;y` Z@F      B ¿  ÔÄÔÄ91/<ì290KSXííííííííY"K° TK°T[K°T[K°T[X½ ÿÀ @878YK°TX½ @ ÿÀ878Y@˜   & =1 UWX f vzvt ‚ ™Ÿ—’ ¦©¯¥£       )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x ›”«¤° Ï ß ÿ /]] # # 3 dþkªÙþºþºÙ³þrÙ))`ýßýÁ¸þHJþq=þV`¢@C        B  ‡½ ¼  ÔÄÄ91ä2ôì9990KSXíííííí2Y"K° TK°T[X½ÿÀ@878YK°TX½@ÿÀ878Y@ð     # 5 I O N Z Z j ‡ € “        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx‰Š … … ‰ ‰‰™ • • šš¤ ¤ ««°Ïßÿe]]+5326?3 3“N”|“lLT3!þ;Ã^^ÃhÈzšH†TNü”lXÛ` ´@B©¼© ÜÄ2Ä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878YK°TX½ ÿÀ @878Y@B&GI  + 690 @@E@@CWY_ ``f``b € ¯ ]]!!!5!qjýL´ü}´ýe`¨üÛ“¨%þ²$‚@4 %   ! © ©À ©±% $  C %Ô<Äü<Ä299999991üìÄôìî99999990K° TX½%ÿÀ%%@878Y²&]#"&=4&+5326=46;#"3>ù©lŽ==k©ù>DV[noZV¾”Ýï—ts•ðÝ“XøŽŽœøXþ®·±Ôì1üÌ0#®ªøþ²$ž@6%   ©©#À©±%#C %Ô<Ä2ü<Ä99999991üìÄôìî99999990K° TX½%@%%ÿÀ878YK°TX½%ÿÀ%%@878Y²&]326=467.=4&+532;#"+FŒUZooZUŒF?ù§lŽ>>Žl§ù?¾VøœŽŽøŽW“Ýð•st—ïÝ”ÙÓÛ1#@ œœ ÔÄ1ÔüÔìÀ990#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©1²OD;>MS²OE<>LÿÿhN'$¼uhm !Ë@T   !!  ! !!!B  Á • Ž  !  VV!"ÔÄÔì2Ôî299999991/<æÖîÔî9990KSXííííííííY"² #]@  s › P#f iu {yyv v!€# ]]4&#"326!.54632#!#TY?@WX??Y˜þð!þX=>Ÿsr¡?<Òˆý_ˆÕZ?YWA?XXþóýN)sIs ¡rFv)ú‹þÿÿsþu'ð'&Ý-ÿÿÉ‹k'(žuÿÿÉ3^'1þuÿÿsÿãÙN'2'uÿÿ²ÿã)N'8îuÿÿ{ÿã-f'DRÿÿ{ÿã-f'DCRÿÿ{ÿã-f'D×Rÿÿ{ÿã-'DŽRÿÿ{ÿã-7'DØRÿÿ{ÿã-'DÜRÿÿqþuç{'FÝÿÿqÿãf'H‹ÿÿqÿãf'HC‹ÿÿqÿãf'H׋ÿÿqÿã'HŽ‹ÿÿof'ÖÿÿÿÿǦf'ÖCÿÿÿÿÞ\f'Ö×ÿÿÿÿôF'ÖŽÿÿÿºd7'Qؘÿÿqÿãuf'Rsÿÿqÿãuf'RCsÿÿqÿãuf'R×sÿÿqÿãu'RŽsÿÿqÿãu7'RØsÿÿ®ÿãXf'X{ÿÿ®ÿãXf'XC{ÿÿ®ÿãXf'X×{ÿÿ®ÿãX'XŽ{9ÿ;ÇÕ '@¹  YW Y Ô<ìü<ì1äôÔ<ì203!!#!5!¨°oþ‘°þ‘oÕþ\™û£]™Ãu=ð  @ÃÄà ‘ Z[ZÜìüì1ôìüì0"32654&'2#"&546PnnPPnoO@v+..¹†‡´¸ooPOmmOOp1.-rB„·´‡†º¬þÇ#˜!Q@+  †ˆ †ˆ ¹ ¹¸Œ"  "ÜìÔ<Ô<<ì221äô<ÄìÄþôîõî9990%&&'667#&73¦“¤¤JˆDF‰HA‰Mfñþ÷ ñfI‰ƒX⸹⡬)*ü *'ª#þä 32þá!bð`@!† ©  ”‘   Ü<ÌÌü<ÄÔÄ1/ì2ôäìÔ<î2î990K° TX½ÿÀ@878Y´66].#"!!!!53#535632NLˆ=”t‡þy-üìÇÇÖè=—´¶))›Ô×þ/ªªÑîó\ÿ=¢ð >‘@54&.#"#"&'532654/.5467.54632{?>‹ú?>ÌS8alÎÓƒ\]>9Ì­IšXW”:fqÝÖ€][;;ȦI™¨.Z.L…‡-[.Kˆ“¤''PGZswšeZŒ54m@ލ¤''TLf{x™f[1,pE‚Ÿ3Ñ…! · Ç \ Ôì1Ôì04632#"&3­~|«¬}}¬ú|««|}¬¬žÿ;9Õ %@Á]] ÔÔüÜì91Ä2ôì90!###&&54$yÀ¾Ž×ëÕùfùáNݸ¾èºÿã¬/š@0-'!  *†¹*¹—Œ.  !' $'$-F0üÄüÌÆîÔîî99991/äþîþÕî990@@'(Š Š     ! "&  : :!MM I!I"jj ¥¥¦ ]]4632#"&'532654&/.5467.#"#ºïÚÐÛ—¨:A9¦`áÓ@ˆIPŒAtx;e\`W§—ƒq‚ˆ»qÈÛèàs`/Q*%jŽd¬·¤_[?T>7;‡[¬gp‹ƒû“åÍ/8L`@6EBC?2ÉH0É9JCÊ 9ÊÉÈ É$HE301BKL?gwyVpMIßÑ`3þœDåÍ/IC@&=Ë>:ÌAÊ$1Ë04ÌGÊÉÈ$É 7aD=0^* D^ JÜÌüìþí2î1/îöþýîÖîýîÖî02#"$'&5476$"32676654&'&&&&#"3267#"&54632˜mmllmmþù˜˜þùmmllmm˜ƒâ^^``^^⃄ã^]]^\^ã§B‚B•§«›@zBC‰FØûûØIˆÍnmmþúš˜þûmmnnmm˜šmmng^^^å‚ã^^__^]⃅ã]^^õ! ¯Ÿ®"ôÐÑò'“FÕ >@!  É  b b cbcÔäüäÔìÔì91ô<<ì2Ô<<Ä903#######5J®¤ªqÃ7ËrqËrÉÕÿý¾äþÑ/þB^þä^sîRf1@ ´³DÔì1ôì0K° TK°T[X½ÿÀ@878Y3#‹Çþº™fþˆ×F)’@ÎÍddÜüÔì1ü<ì20K° TK° T[X½@ÿÀ878YK° TK° T[K°T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@````pppp]3#%3#^ËËþyËËÊÊÊÙ'ÛÝ>@" Ïœ Ï œ  Ü<Ä291Ô<Ì2ü<ìþ<ì990!!!!!'7!5!7!Ù}®/þHÃ{üúþþ}®þÕ¶Ãý‡¢;fÕ¨ðªþÇfÓªðHÕ‡@9  B• ••••­    ÔÔ<ì2ÔÄÄ91/<ììÄôììîî0KSXííííY"²€]@gww† …– ¿ ]!!!!!!#!5ýÇý9øü=ýð Íq‹þ¶ËÕªþFªýãªþÕžüðfÿºå +ž@< +,  )&  *&•& •‘&Œ,+,* # )#3,üìüìÀ999999991äôìîÀÀ99999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''¶ý3>¡_Ü'y=¡_Üþý''†NOy;‚ÝW¢fªNPþˆþÆ€Ý[¢gXü²@CHp¸¸@Cþ¸þåp¼Džf b¥MK¿YÆgþöžþŸþ[KK¿XÝÝÏî /ÿ@- !$'!!0 $*0ÔÄÔÄ99991ÔÄÔÄÀ9990@¾     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV´° °!°"°&°'°(´)]]32654&#".#"326#"&54632>32#"&“1†Te€vYR…Ä1…UfvYR†F^ˆº§†_™HDža†¼§†^•/XZ‡ie†‡7XX„je†ˆ‡ߦ¯Ø~ŠŠƒá§¯ÖwÙÛ .@МР œ   Ô<ì2ü<ì21/ìÔ<ìü<ì0!!#!5!!!®-ýÓ¨ýÓ-ýÓúþþ}ªþ}ƒªƒû¦ªÙÛ¨ T@.œœœœBѧœ $# ü<ì2291/ìôì90KSXííííY" 5!!Ûü@Àúþúþúþøþëþî²pªoüªÙÛ¨ V@/œœœœBѧœ$ # ü<<ì291/ìôì90KSXííííY"55!5ÙúþÁAúþø°þ‘ªþ²ýǪªRÃÕÆ@F  B Ó Ó   fe f eÔ<ì2ìüì2ì99991/ä2Ô<ì2Ô<ì290KSXííííY"K° TX½ÿÀ@878Y@(†¦ µ' ' ')((79‡ ˆ¦ ¥ª©]]!#!5!5'!5!3 3!!!þcÉþ` Tþ´þþ{y¿þÂþµTŸÇþ9Ç{3›{JýD¼ý¶{›3®þVå` M@% ‡Œ ¼½!   NF!üì2ôìÄ91ää2ô<ìÜÄ990¶"`"Ï"]3326533267#"&'#"&'®¸Š‡”•¸#% )I#ER2‘bf*þV ýH‘”¨¨ü¢<9 ”NPOONNý×hÿçÁ-)b@'! '!Õ* $$*ÔÌÜÌ9991äÌÜÌÎÎ990K° TK° T[K°T[K°T[K°T[X½*@**ÿÀ878Y>54&#"#"&54632#"&54324&#"32ôIH7$$0e´ÖþßÕ˜ËÝ¢e‚ WOmVPmmW£Kƒt,>bþÊþùþ±þFØ£Æ[àt}þþÏt{þw;Á ]@    ÔÄ91ÄÔÌÎ990@0QVPZ spvupz €€ Z pp{ t €€ ]]!! !!5 7êüA ýJïúÞÕýIÁÁý3ýÀ•!ãœþwqÁ@×Ö¯ggÔìÔì1üìì20!#!#œÕðý ïÁø¶}ùƒÿáÿðª/#Ë@1 ÚÙ"ØÕ $ #" #h#$ÔÔÔì9999991/<äôì22î9990K° TX½$ÿÀ$$@878Y@V             ##(]]#3267#"&5467!##"#>3!‡¶i/7.%7vy"PþºÂµÃ)6<  ¥y‘þJ\:1fd.¡xüo‘@E¦}/þú%&@ Û Ûܱ& iji&Üìüì1üìÜäÞä026732#"&'&&#"#"&546327j ¾ÊPd@7*8  k½ÄOeD=!0 þú°l9¼TA6?&#Hý•Ánþ!þbSA8?SsÕ;ð)_@3(%ãÝá%Ý ßÞÝ à‘* "(kl"k *ÜìÌüì22ÀÀ9991ôäüôìÄîíÖîî99990!!#5#"&5463354&#"56632"32655‹°ýP®•,]€˜¿¼¶uu>ˆDI‘E·³þì¡~bRh‚P{¸þ@p?D‡q‡Š[[""°ðCO@Mr`Õdð.@ãáÝ àÝ‘ klk Üìüì991ôìôìüì0!!2#"&546"32654&‹°ýPX³Îγ³Ðгi~hi}|P{Ý¿¿Ûܾ¿Ýs¡ˆ…  …‰ NÏç@@" å‘å  mm  ÔììÔììÀÀ9991/<ì2ôì0%!5654#"!5!&5! Ïý¨±ÆþøØØþ÷Dzý¨?ž‘1/Ž¡²²²aLÊð"þÝïÊþ´a²²‹*¸>ŠþwþËÂþØ{ÿão{3>@C'-%= 4©%†ˆ©:¹.†-º*¹»1 ¸Œ%?47&%7& =&-7"E?üìÌÔü<ÔìÄ999991Ää2ô<Ääü<ôìÄî2îôîî9990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0…+…0€@@ @°@À@Ð@à@à@ð@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/€,€-€.€/]q].#">32!3267#"&'#"&5463!54&#"5>32"326=¶¥‰™¹DJÔ„âü² Ì·hÈddÐj§øMIؽÒýû§—`¶Te¾ZŽÕï߬o™¹”—´®ž0Z^þÝúZ¿È55®*,ywxx»¨½À‹..ª''`þf{bsÙ´)Hÿ¢œ¼ +ä@<+,&  )&  *&¹& ¹¸&Œ,+,* # #Q)E,üì2ôì2À9999991äôìîÀÀ99999990@p(?-YVUV jf!{    { z{ {!"#$%{&›•%¨ -ð-&YVUZ(ifej(ztvz(‰•š$¢­$]] 32654&'.#".5327#"&''‰þ)gA“¬\*g>—©}66ñ]ŸC‹_’56þîð`¡?‹`!ý°*(èÈOuš))ëÓHn.—MÅw834¨O³MÆxþíþÇ43¨Nÿã¬Õ $†@/ †ˆ !ƒ# •Œ#%" " "!& %ÜìÔüìÔì99991äôìþÍôî9990K°TK°T[K°T[X½%ÿÀ%%@878Y@ ttttv]33267#"&546?>7>5#53ô¾7ZZ:3ƒmN´`^Àg¸àIYX0&ÄÊÊDœe‚WX5^1YnFC¼98ŸL‰VV/5<6þ5Õ b@ƒ ü<ì2991/ôüÌ0K° TX½ @ ÿÀ878YK°TK°T[K°T[X½ ÿÀ @878Y¶ P ]#53#3ËËË¢×þú+eþ›ÙÛ^@ œÜÔì1ÔÄì0!#!Ù¨û¦^ýÁ•=ÿ×} *@    ÔÌ91ÔÌÄ903##'%\½sý®BþÁ}}`ùºs-Pbý;þV#Š@@   B   ©Šæ©Šæ©!—$  $ÔÌ91Ä2Äüìôìîöîî299990KSXí2í9Y"K° TX½$ÿÀ$$@878Y.#"!!#"&'53267#5!>32&P,`r<þÃ:¼º:d/4a/am"‰ø?$Æ—5dð¤z„þÉý…þãÓ¦!!‰¦­J·ÃÙÛô;?@.9*-" *œ19œ"œ œ<-<Ô<Ä21ÔìÔìÜüÔìÀ9999990#"'&'&'&#"56632326#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©gi³an’ ›^X¬bi³an“ ›^V©o³NE;=LT³NE;=KÚ²OE;=LS²NE;=Kÿú`Á8@ÔÌ91/ÄÌ90@cmpxyvn]] !3!¬þ^DýïàCúšîûÄú?ž%# †@Ièèèè è è è  è B  ç¦ o o nüü<Ôì2991ô<ì2990KSXííííííííY"55%þÓ-þ+#þÓ-þ+#¿þôþô¿¢R¢¿þôþô¿¢RÁH# †@I è è è è èèèèB  ç¦ o opü<üÔ<ì991ô<ì2990KSXííííííííY"5%5ÁÕþ+-þÓ²Õþ+-þÓ#þ^Rþ^¿  ¿þ^Rþ^¿  ìþ #@ƒ   ÔüÔìÔì1/<<ì220%3#%3#%3#–ÔÔ©ÕÕú­ÕÕþþþþþþÿÿhk'$¼uÿÿh^'$¼uÿÿsÿãÙ^'2'us Õ;@•••­   üìÔÄÄÔì299991/ìì2ôì2î0!!!!! !# !3úýÇý9øû×þOþA¿±gþ¿þÀ@AÕªþFªýãª|pm|ªþáþàþßþßqÿãÃ{'3„@1†ˆ ©. ¹(¹»"%¸Œ4"1 K1 Q+E4üìôüôìÄ9991ä2ô<Ääì2Äî2îôî90@%?5_5p5Ÿ5Ï5Ð5ð5????? ooooo ]q].#"!3267#"&'#"32>32%"32654& ¤‰™¹Hü² Ì·jÈbdÐj òQGÑŒñþïñŒÓBNèâú°”¬«•“¬¬”˜³®ž5Z¾Ç44®*,nmnm98olkpþ݇çÉÉçèÈÇééy¶©é/Æ1üì0!!üyéyµ©/Ì1Ôì0!!øy®émÕ '@ž   ÜüÌÔÌþÔÎ1ô<ì20#53#53Ó¤RšÓ¤Ré­?þÁ­­?þÁ®émÕ '@ ž  ÜìÔÌÜîÔÎ1ô<ì203#%3#Ó¤RšÓ¤RÕ¬þÀ@¬¬þÀ@®éÓÕ@ žÜüÔÌ1ôì0#53Ó¤Ré­?þÁ²þ×Õ@ žqÜìÔÌ1ôì03#Ó¤RÕ˜þÁ?Ù–Ûo )@êêœ r ÜÔ<ü<Ä1ÔÄüÄîî03#3#!!ßööööýúúþoöþõAªþ#îu"@ÔÌ91ÔÌ990 úþþôþ þ üÏüÇ9%ûÛûÓ-ÿÿ=þV'\Ž^ÿÿÿüçN'<suþ‰ÿãÍð+@BŒ‘ÔÌ1ää0KSXííY"3#- ü\ ðùó^R¼²#/ƒ@I -'! - -¹ëì'¹ë!0 *$0* $ $(st*(s0Üäìôäì9999999991ÔäìôäìÀ9999999907'#"&''7&&5467'766324&#"326{ÏrÎ%$&(ÑrÏ;t=:x=ÏqÏ%%&&ÏsÏ7t@?s9ÏqÏ(&%%ÏsÎ>v:@t8ÎsÏ'%$þ|pššprœžs#G@%èèèèBç¦onüì291ôì90KSXííííY"5sþÓ-þ+#¿þôþô¿¢RÁ–#I@&èèèèBç¦opü<ì91ôì90KSXííííY"5ÁÕþ+-þÓ#þ^Rþ^¿  /J›@( ©‡¾±— ¼ Lü<Ä2Äü<Äî2991/<æ2îþîîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€€€ Ðï]]#!##53546;#"3#J¹þ¹°°­³¹°cMù¹¹`û Ñü/ÑN·¯™Phc²é/J„@! © ‡— ¼   Lü<ÄÄü<Äî991/<æ2þîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€ € € Ðï]!#!"!!##53546J¹þ·cM/þѹ°°®ùì{Phcü/ÑN»«9ÿ;ÇÕ>@ ¹¹  ÂY W Y Ô<<ì2ü<<ì21äôÄ2Ä2î2î20%!#!5!!5!3!!!Çþ‘°þ‘oþ‘o°oþ‘oßþ\¤š™¤þ\™ýáÛH®F·ƒÔì1Ôì03#ÛÓÓFþ®ÿÓþ@ žƒÔìÔÌ1üì0%3#Ó¤Rþ¬þÀ@®ÿmþ '@ žƒ   ÜìÔÌÜîÔÎ1ü<ì20%3#%3#šÓ¤RþfÓ¤Rþ¬þÀ@¬¬þÀ@qÿã Lð #'3?K®@D$%&%&'$'B@’ .’(’F’4 :&Œ$‘L%IC'1+C =  1 =I 7+ ! LüäìÔÄìäîîöîî991ä2ô<<ä2ì2îöîî20KSXííY"K°TK° T[K° T[K° T[K° T[K°T[X½L@LLÿÀ878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&ôWddWUccUžº» º»ùtž¼»ŸŸ¹º% üZ VcbWWcd²žº» º»ŸWccWUcc‘”„‚••‚ƒ•Ü»»ÛÛ»¼ÛàÛ»½ÚÛ¼ºÜùóŽ•‚„””„–ýŸÜ»»ÛÛ»¼Û”„‚••‚ƒ•ÿÿhm'$¼uÿÿÉ‹m'(žuÿÿhk'$¼uÿÿÉ‹N'(žuÿÿÉ‹k'(žuÿÿ¢k',ÿ/uÿÿÿþ`m',ÿ/uÿÿXN',ÿ/uÿÿ;ºk',ÿ/uÿÿsÿãÙk'2'uÿÿsÿãÙm'2'uÿÿsÿãÙk'2'uÿÿ²ÿã)k'8îuÿÿ²ÿã)m'8îuÿÿ²ÿã)k'8îuÁy` ·¿Füì1/ì0@ @P`p]3#Á¸¸`û Áî?f7@ ´³uÜì91ôì290K° TK°T[X½ÿÀ@878Y3#'#¶”õ‹´´‹fþˆõõ¶J7c@$  Ãà íVwVvôìüì99991ü<üÔ<ì99990K° TK° T[X½ÿÀ@878Y'.#"#>3232673#"&ü9! &$}f[&@%9! &$}f[&@Z7IR‡“!7IR‡“Õb+ö/·ïîÔÌ1üì0K° TK°T[X½ÿÀ@878Y!!ÕVýªö”Ç)9H W@ ð³VVÜìÔì1ô<Ôì0K° TX½ÿÀ@878YK°TK°T[K°T[X½@ÿÀ878Y332673#"&Çv aWV` v ž‘‘žHKKJLšDf,@ ÎÍdÔì1üì0K° TX½ÿÀ@878Y3#šÌÌÌîá _@Áò ÁñV xVÔìôì1ôìôì0K° TK° T[X½ÿÀ@878YK° TK° T[K° T[X½ÿÀ@878Y4&#"3267#"&54632˜X@AWWA@XzŸssŸŸssŸô?XW@AWX@s  ssŸŸ#þuÁ@  ó' ÜÔìÔÌ1/ÔüÄ90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ ƒ0.W=ðî®fB@´³ÔÜÔÌ991ô<ì20K° TK°T[X½ÿÀ@878Y3#3#ü²ø‡ªß‰fþˆxþˆLþuÁ @  óô 'ÔìÄÔÌ1/üüÄ90!33267#"&546¸w-+76 >&Dzs5=X..… W]0iÁî?f7@ ´³uÜì91ô<ì90K° TK°T[X½ÿÀ@878Y373¶õ‹´´‹õîxõõþˆÿòuÕ ?@ •  : yô<ìÄü<Ä991/äì90´0P]3%!!'7ÓË9Pþw×ü^”MáÕý˜Ûoþîýãª;jnžH ^@ — z z Ô<äü<ä991/ì90K°TX½ @ ÿÀ878Y@ @ P ` sz p à ð ]37#'7Ǹ}Lɸ{JÅý¦ZjüãšXjÿÿ‡ÿã¢m'6‹uÿÿoÿãÇf'Vàÿÿ\m'=¾uÿÿXÛf']àþ¢®˜@ õõÜ<ì21ÔìÔì0##®ªªª˜ý öý ö ºÕ g@  © ••  2  yô<ì2ÄôìÄ91/Æ2îöîî20@( °Ÿ Ÿ Ÿ Ÿ ŸŸŸŸ¿ ¿ ¿ ¿ ¿¿¿¿]]! )#53!!3 !Ó ±–þiþPþ`ÉÉËPþ°ó5þáþËÕþ—þ€þ~þ–¼ãþýê.,qÿãu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ##¹ ¹Œ#±)&' ! (%#" QE)üìôì99999991ìÄôìî9990KSXÉÉÉÉííííY"²?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x" *ð*']].#"32654&#"5432''%'3%F2X)§¹®’‘®6 ~rþäæçþåÝ4*ŸþÁ!µäM!þÙ“ØÃ¼ÞÞ¼z¼&þà­ÿþÉ7ÿú7´kc\Ì‘oabÿÿÿüçk'<suÿÿ=þVf'\^ÉÕ =@• •ö  ? üì22üì91/ôüìÔì0@ ?_]332+#32654&#ÉÊþûþÿûþÊÊþš™ŽÕþøáÜÜâþ®'ýÑ’††‘ºþV¤>@¹¹Œ¸½— GFüì22ôì1ìääôÄìÆî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý®¾ý¢daþ¼þøþøþ¼aëËççËËççÙ-Û×¶œÔÄ1Ôì0!!Ùúþת?œÅ …@M œ  œœœœœ œ œ B   Ô<Ì291Ô<Ì290KSXííííííííY" '7œþ7Éwþ5þ5vÈþ8vËËLþ5þ7yËþ5yÉËyþ5ˉœÅß ,@Ý ÝÝ ÷‘ |]|| Üôäüä1ôììÔìî2035733!œÌßæ‰Íý× c)t'ý+n^œ´ðJ@$}}BÝÝ÷ Ý‘~ÜÄÔÄì91ôÄìüìî90KSXí2íY"!!56754&#"56632 ¨ýª"?XhU4zHM…9‘®þµ8rn81^BQ##{„l‹þä0bÍð(H@' Ý Ý Ý Ý ø÷Ý ø#‘)~&~ )ÜÄÄÔìÔì9991ôäìüäìÔìîî90#"&'532654&##532654&#"56632 \e¾±9}F4wCmxolV^^ad_(fQI€7©Z`mR|†yOFJLl?<:=svcE`ÿÿ‰ÿãð'ð'¼5 ‹ýdÿÿ‰ÿã?ð'ð'¼5ñ‹ýdÿÿbÿãð'ò'¼5 ‹ýdÿÿsÿã‹m'* uÿÿqþVZH'JÚ‹ÿÿÉ•P', ÿ/uÿÿ‡þu¢ð'6Ý‹ÿÿoþuÇ{'VÝÿÿsÿã'k'&-uÿÿqÿãçf'F‰ÿÿsÿã'm'&-uÿÿqÿãçf'Fà‰qÿãô$J@$Ó ù"¹¹ Œ¸—   GE%üìô<Äü<Ä1/ìäôÄìÄîý<î20¶`&€& &]!5!533##5#"3232654&#"¢þºF¸šš¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶N}““}úü¨daDDaþËççËËççd߃¶œÜÌ1Ôì0!!dý僤ÛH®F·ƒÔì1Ôì03#ÛÓÓFþÿãð1@: Ó"+Ó ¡®•¡®•/‘Œ) 2+"!)#&  , & &*!/<ÔÄ2üÄÄ99999999991Ä2äôìôìîöîî2Ý<î20K° TK° T[K° T[K°T[K°T[K°T[X½2ÿÀ22@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-ŸŸŸ Ÿ Ÿ Ÿ Ÿ ŸŸŸŸŸŸ–Ÿ Ÿ!Ÿ"Ÿ#Ÿ$Ÿ%Ÿ&Ÿ'Ÿ(Ÿ)Ÿ*Ÿ+Ÿ,-2   USjg ]].#"!!!!3267#"#734&5465#7332[©fÊ A7ýæ¾8þŠ Êf©[Y¹`íþË(Ó7‹Â7œ(6ìb¹bÕiZÈ»{.# .{»ÊZiÓHH"{/ #/{"G×)Ù¥@ ÎddÔüÜì1Ô<ì20K°TK°T[X½@ÿÀ878YK°TK° T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y@````pppp]3#%3#^ËËþyËËÙËËËsîðö@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@ %%6FVjg //]]3#7¹ä™öþø¶Jéu@!  ÃÃúVV ÔìÔì99991ô<ìÔì2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y´ ]'.#"#4632326=3#"&ü9 $(}gV$=09" (}gT";9! 2-ev 3)dw î‹ö‰@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@*$$5CUUŸŸ¯¯//]]#ÇÄ™æöþøÏî1øw@ úÔÄ91ô<Ä90K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ //- ]3#'#¢¼Ó‹¦¦‹øþö²²Ïî1ø†@ úÔÄ91ôÄ290K° TK° T[K° T[K° T[X½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ "  ]373¢Ó‹¦¦‹Óî ²²þö?œôß Ô@ Ý ÷‘ ] ÜÔ<Äì291ôüÔ<ì290K°TK°T[K°T[K°T[K° T[K° T[X½@ÿÀ878YK°TK°T[X½ÿÀ@878Y@T /9IFYi‹«»       "5GK S[ e„¥µ]] !33##5!5ÝþË5¦‡‡þbfþ]ýämººyÇ9ø j@à úVVÔìÔì1ôüÄ20K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TK°T[X½ÿÀ@878Y332673#"&Çv cSRav  Ÿø6978w{zšfÛ¶úÔÌ1ôÌ03#šÌÌÛÍ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßà>: ~ÿ1BSax~’ÇÝ©À & 0 : ¬!""""+"H"e%Êûÿÿ   0AR^x}’ÆØ©À  0 9 ¬!""""+"H"`%ÊûÿÿÿãÿõÿØÿ ÿ^ÿCÿhÿüöüÛà–à…àVßjÞqÞ_Úï¿8ôüúúü (B¬£„…½–熎‹©¤ŠÙƒ“ñò—ˆÃÝðžªóôõ¢­ÉÇ®bcdËeÈÊÏÌÍÎèfÒÐѯgï‘ÕÓÔhêì‰jikmln oqprsutvwéxzy{}|¸¡~€ëíºýþÿøÖùúãä×àÚÛÜßØÞ²³¶·Ä´µÅ‚‡«˜¨š™î¼¥’”•Íf‹‹55®Å´žªšq=3ۤ=´Ù‹žãd‹Û²‡á–œdž¨‹²ð²ž´Ù´Ù´Ù?“‡y}É–s)ÉÉšÉ3sÉ\É\ÿ–?ÉuÉçÉüÉLsÓÉLsɇãÿúÛ²yéD{=ãÿü{\°²Ç´Ùÿìªç{ºfqqìqÑ/qº9Á9ÿÛ¢º9Á˺ºåqºqJº+o#7®¼=‹V¼;¼=3X²´Ùyy–sÉüÉLsÛ²ç{ç{ç{ç{ç{ç{fqìqìqìqìq99ÿÇ9ÿÞ9ÿôºåqåqåqåqåq®®®®9ì\¸3ž º's×´ÙËLfªÝ´Ù´Ù´ÙR®#hdœ¶ÿá+/ÅsÅ`NÛ{åH?55´Ù=´ÙZÿúåžåÁìyyLss/q%®%®‹®‹²´Ùô¼=ãÿüVþ‰^3ž3Á / /9‹Û‹®%® ¼qyÉyÉÉ\¢\ÿþ\\;LsLsLsÛ²Û²Û²9ÁÁ¶ÕÇšî#ðLÁÿòF‡+o{\3X²3 åqãÿü¼=×ɺ´Ù´5‰5^5bÁ‰Á‰Áb3sq\ɇ+o–sfq–sfqqãd‹Û×s¶ ÏÏ5?Çšÿ+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóõôöøùúûüýþÿ     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""X“ÿ¶Oƒ²ö!n˜´ÊÞE‚~áL·üeÏî  R s ®  ß X ° û : i “ æ  = z /¬E…ëuñ)pཊëP‹±á@Ö"m¹#{ßC€øw³R¡Ø‡Äº‡wè [ r ó!5!B!â!ï!ü" ""#"0"="J"W"d"q"~"‹"˜"¥"²"¿"Ì"Ù"æ"ó## ##'#4#A#N#[#h#”#Ï$4$%3%S%&&º'K''·((X(Ã)_*%*\*£*é+z+Ó,D,,±-P- ..R.ª/‡0A0½11!1P1Ï2H2z2ß3F3p3p3}3Š3—3æ4z44£4Ñ4ÿ5595g5‘5ž5«5Ï6[6“6Í7C7©7ë888J999)969C9P9]9j9w9„9‘9ž9«9¸9Å9Ò9ï::{: :å;;^;Ž;Ä;ô<"<_<§<´<Á<Î<Û<þ=c>;>H>U>˜>ç>ý?a??Ü@:@K@\@m@z@‡@”@¡@®@»@È@Õ@âA@AVAkBEBªB÷C_C²CÿDUDÛE*E?-†” x$ÿÓ%ÿ·&')*K+-r./2934K57ÿD9ÿˆ:ÿ­;ÿš<ÿ =IQR&UYÿÉZ\ÿÜbÿÓdg9xy&z&{&|&}&‰­ÿÓ®ÿÓ¯9ºÿÜ»ÿ ÇÿÓÉÿÓÐ9Ñ9Ò9åéêÿ ëÿÜìöKûý$ÿÓ$ÿÜ$ÿÜ$$9$&ÿÜ$*ÿÜ$2ÿÜ$4ÿÜ$6$7ÿa$8$9ÿ}$:ÿ$;$<ÿa$FÿÜ$GÿÜ$HÿÜ$Iÿ·$RÿÜ$TÿÜ$WÿÜ$X$Yÿˆ$Zÿ­$\ÿu$b9$dÿÜ$gÿÜ$h$oÿÜ$pÿÜ$qÿÜ$rÿÜ$sÿÜ$yÿÜ$zÿÜ${ÿÜ$|ÿÜ$}ÿÜ$~$$€$$©ÿ·$ª$­9$®9$¯ÿÜ$´þø$µÿ$ºÿu$»ÿa$Å/$Ç9$É9$ÐÿÜ$ÑÿÜ$ÒÿÜ$Ó$Ô$Õ$ã$êÿa$ëÿu$öÿÜ$ù$ûÿÜ$üÿÜ$ýÿÜ$þÿÜ%%&ÿÜ%*ÿÜ%2ÿÜ%6ÿÜ%9ÿÁ%:ÿ·%<ÿ%dÿÜ%gÿÜ%©ÿÁ%ªÿÜ%¯ÿÜ%´ÿ%µÿ%»ÿ%Åÿ­%ÐÿÜ%ÑÿÜ%ÒÿÜ%ãÿÜ%êÿ%öÿÜ%ùÿÜ%ûÿÜ%ýÿÜ&&$&6&<ÿÜ&b&©ÿÜ&ªÿÜ&­&®&´&µ&&»ÿÜ&Å&Ç&É&ã&êÿÜ&ù''$ÿÜ'9ÿÜ':'<ÿ'bÿÜ'©ÿÜ'ªÿÜ'­ÿÜ'®ÿÜ'´ÿÓ'µÿÉ'»ÿ'ÅÿD'ÇÿÜ'ÉÿÜ'êÿ))þ·)ÿa)$ÿD)6ÿÜ)7ÿÜ)DÿD)Hÿ)Lÿk)Rÿ·)Uÿk)Xÿ)\ÿD)bÿD)iÿD)jÿD)kÿD)lÿD)mÿD)nÿD)pÿ)qÿ)rÿ)sÿ)yÿ·)zÿ·){ÿ·)|ÿ·)}ÿ·)~ÿ)ÿ)€ÿ)ÿ)©)ª)­ÿD)®ÿD)´ÿÓ)µ)ºÿD)Åþˆ)ÇÿD)ÉÿD)ãÿÜ)ëÿD)ùÿÜ**$*7ÿ·*:*<ÿš*b*©ÿÜ*ªÿÜ*­*®*´ÿÓ*µÿÓ*»ÿš*ÅÿÉ*Ç*É*êÿš++ÿÜ++©+ª+´ÿ·+µÿÁ+Åÿ·-ÿ·-$ÿÜ-bÿÜ-©ÿÜ-ªÿÜ-­ÿÜ-®ÿÜ-´ÿ·-µÿÁ-Åÿ-ÇÿÜ-ÉÿÜ.ÿ).$ÿÜ.&ÿ.2ÿ.7ÿa.8ÿÉ.:ÿ·.<ÿ·.DÿÜ.Hÿš.Rÿš.Xÿš.\ÿk.bÿÜ.dÿ.gÿ.hÿÉ.iÿÜ.jÿÜ.kÿÜ.lÿÜ.mÿÜ.nÿÜ.pÿš.qÿš.rÿš.sÿš.yÿš.zÿš.{ÿš.|ÿš.}ÿš.~ÿš.ÿš.€ÿš.ÿš.©ÿ}.ª.­ÿÜ.®ÿÜ.¯ÿ.´ÿÁ.µÿÁ.ºÿk.»ÿ·.Å.ÇÿÜ.ÉÿÜ.Ðÿ.Ñÿ.Òÿ.ÓÿÉ.ÔÿÉ.ÕÿÉ.êÿ·.ëÿk.ûÿ.ýÿ/ÿÜ/$//2ÿ·/7þæ/8ÿš/9ÿ/:ÿD/<þð/D/HÿÜ/RÿÜ/XÿÜ/\ÿD/b//gÿ·/hÿš/i/j/k/l/m/n/pÿÜ/qÿÜ/rÿÜ/sÿÜ/yÿÜ/zÿÜ/{ÿÜ/|ÿÜ/}ÿÜ/~ÿÜ/ÿÜ/€ÿÜ/ÿÜ/©/ª/­//®//¯ÿ·/´þa/µýæ/ºÿD/»þð/Å/Ç//É//Ðÿ·/Ñÿ·/Òÿ·/Óÿš/Ôÿš/Õÿš/êþð/ëÿD292ÿ­2ÿÜ2$ÿÜ29ÿÜ2;ÿ}2<ÿ2bÿÜ2©ÿÜ2ª2­ÿÜ2®ÿÜ2´ÿÓ2µÿÜ2»ÿ2ÅÿD2ÇÿÜ2ÉÿÜ2êÿ3ÿÓ3þÁ33$ÿ}383:3<ÿÓ3Dÿ¤3Hÿ·3LÿÓ3QÿÜ3Rÿ·3UÿÜ3VÿÜ3XÿÜ3\3bÿ}3h3iÿ¤3jÿ¤3kÿ¤3lÿ¤3mÿ¤3nÿ¤3pÿ·3qÿ·3rÿ·3sÿ·3xÿÜ3yÿ·3zÿ·3{ÿ·3|ÿ·3}ÿ·3~ÿÜ3ÿÜ3€ÿÜ3ÿÜ3©ÿÜ3ª3­ÿ}3®ÿ}3´&3µ&3º3»ÿÓ3Åþ·3Çÿ}3Éÿ}3Ó3Ô3Õ3äÿÜ3êÿÓ3ë3úÿÜ494©4ª4´ÿÓ4µÿÜ4Åÿ}5ÿ­5ÿ·5ÿÁ5$ÿ­5&ÿš57ÿk59ÿ5:ÿ­5<ÿ}5DÿÓ5Hÿ¤5Rÿ¤5Xÿ¤5\ÿ5bÿ­5dÿš5iÿÓ5jÿÓ5kÿÓ5lÿÓ5mÿÓ5nÿÓ5pÿ¤5qÿ¤5rÿ¤5sÿ¤5yÿ¤5zÿ¤5{ÿ¤5|ÿ¤5}ÿ¤5~ÿ¤5ÿ¤5€ÿ¤5ÿ¤5©ÿ5ªÿÜ5­ÿ­5®ÿ­5´ÿk5µÿ}5ºÿ5»ÿ}5ÅÿÜ5Çÿ­5Éÿ­5êÿ}5ëÿ5ûÿš5ýÿš6$&6&6*6264666b&6d6g6­&6®&6¯6Ç&6É&6Ð6Ñ6Ò6ã6ö6ù6û6ý7ÿD7ÿ 7ÿ7$ÿa7&ÿˆ77ÿÜ7Dþ­7Fþ¤7Hþ¤7LÿÁ7Rþ¤7UþÓ7Vþ­7XþÉ7Zþ­7\þÁ7bÿa7dÿˆ7iþ­7jþ­7kþ­7lþ­7mþ­7nþ­7oþ¤7pþ¤7qþ¤7rþ¤7sþ¤7yþ¤7zþ¤7{þ¤7|þ¤7}þ¤7~þÉ7þÉ7€þÉ7þÉ7©ÿD7ªÿ7­ÿa7®ÿa7´7µÿÓ7ºþÁ7Åþø7Çÿa7Éÿa7äþ­7ëþÁ7úþ­7ûÿˆ7üþ¤7ýÿˆ7þþ¤8$8-8=ÿÜ8b8­8®8Ç8É8åÿÜ9ÿˆ9þø9ÿY9$ÿ}92ÿÜ9Dÿa9Hÿa9LÿÓ9Rÿa9Xÿu9\ÿÉ9bÿ}9gÿÜ9iÿa9jÿa9kÿa9lÿa9mÿa9nÿa9pÿa9qÿa9rÿa9sÿa9yÿa9zÿa9{ÿa9|ÿa9}ÿa9~ÿu9ÿu9€ÿu9ÿu9©ÿN9ªÿ9­ÿ}9®ÿ}9¯ÿÜ9´9µ9ºÿÉ9Åþæ9Çÿ}9Éÿ}9ÐÿÜ9ÑÿÜ9ÒÿÜ9ëÿÉ:ÿ­:ÿ:ÿˆ:$ÿ:Dÿ}:Hÿˆ:LÿÓ:Rÿˆ:Uÿ¤:Xÿ·:\ÿÜ:bÿ:iÿ}:jÿ}:kÿ}:lÿ}:mÿ}:nÿ}:pÿˆ:qÿˆ:rÿˆ:sÿˆ:yÿˆ:zÿˆ:{ÿˆ:|ÿˆ:}ÿˆ:~ÿ·:ÿ·:€ÿ·:ÿ·:©ÿ:ªÿÜ:­ÿ:®ÿ:´ÿÜ:µ:ºÿÜ:Åþø:Çÿ:Éÿ:ëÿÜ;ÿš;$;&ÿk;2ÿ};7ÿÜ;Hÿ¤;b;dÿk;gÿ};pÿ¤;qÿ¤;rÿ¤;sÿ¤;©ÿ;ª;­;®;¯ÿ};´ÿa;µÿ­;ÅÿÓ;Ç;É;Ðÿ};Ñÿ};Òÿ};ûÿk;ýÿk<ÿ <þa<þð<$ÿa<&ÿ<2ÿ<Dþæ<Hþð<Lÿ·<Rþð<Xÿ<bÿa<dÿ<gÿ<iþæ<jþæ<kþæ<lþæ<mþæ<nþæ<pþð<qþð<rþð<sþð<yþð<zþð<{þð<|þð<}þð<~ÿ<ÿ<€ÿ<ÿ<©ÿ<ªÿk<­ÿa<®ÿa<¯ÿ<´ÿ<µÿÜ<Åþø<Çÿa<Éÿa<Ðÿ<Ñÿ<Òÿ<ûÿ<ýÿ=ÿÜ=©=ª=´ÿÜ=µÿÜ=ÅÿÜH[ÿÜIÿIÿkIÿ·IWÿÜIZÿÜI\ÿÜI©ÿ·IªÿÜI´AIµIºÿÜIÅÿIëÿÜNDÿÜNHÿ·NRÿ·NXÿÁN\ÿ·NiÿÜNjÿÜNkÿÜNlÿÜNmÿÜNnÿÜNpÿ·Nqÿ·Nrÿ·Nsÿ·Nyÿ·Nzÿ·N{ÿ·N|ÿ·N}ÿ·N~ÿÁNÿÁN€ÿÁNÿÁNºÿ·Nëÿ·QQQQ©QªQ´ÿkQµÿQÅÿ¤R&RÿÜRR[ÿÁR©RªR´ÿkRµÿ·RÅÿ}Uÿ}UÿDUÿÜUFÿÓUGÿÜUHÿÓUIUJÿÜUKÿÜUPÿÜUQÿÜURÿÓUTÿÜUUÿÜUXUYUZU[ÿÉU\U]UoÿÓUpÿÓUqÿÓUrÿÓUsÿÓUxÿÜUyÿÓUzÿÓU{ÿÓU|ÿÓU}ÿÓU~UU€UU©ÿ·UªU´UµVUºUÅþÉUæUëU÷ÿÜUüÿÓUþÿÓYÿÉYÿaYÿY©ÿÜYªÿÜY´YµÿÜYÅþðZZÿDZÿZ©ÿÜZªÿÜZ´ZµZÅÿ)[FÿÜ[HÿÁ[RÿÁ[oÿÜ[pÿÁ[qÿÁ[rÿÁ[sÿÁ[yÿÁ[zÿÁ[{ÿÁ[|ÿÁ[}ÿÁ[üÿÜ[þÿÜ\ÿÜ\þÜ\ÿk\©ÿÜ\ªÿÜ\´\µ\ÅþÓbÿÓbÿÜbÿÜb$9b&ÿÜb*ÿÜb2ÿÜb4ÿÜb6b7ÿab8b9ÿ}b:ÿb;b<ÿabFÿÜbGÿÜbHÿÜbIÿ·bRÿÜbTÿÜbWÿÜbXbYÿˆbZÿ­b\ÿubb9bdÿÜbgÿÜbhboÿÜbpÿÜbqÿÜbrÿÜbsÿÜbyÿÜbzÿÜb{ÿÜb|ÿÜb}ÿÜb~bb€bb©ÿ·bªb­9b®9b¯ÿÜb´þøbµÿbºÿub»ÿabÅ/bÇ9bÉ9bÐÿÜbÑÿÜbÒÿÜbÓbÔbÕbãbêÿabëÿuböÿÜbùbûÿÜbüÿÜbýÿÜbþÿÜdd$d6d<ÿÜdbd©ÿÜdªÿÜd­d®d´dµ&d»ÿÜdÅdÇdÉdãdêÿÜdùg9gÿ­gÿÜg$ÿÜg9ÿÜg;ÿ}g<ÿgbÿÜg©ÿÜgªg­ÿÜg®ÿÜg´ÿÓgµÿÜg»ÿgÅÿDgÇÿÜgÉÿÜgêÿh$h-h=ÿÜhbh­h®hÇhÉhåÿÜp[ÿÜq[ÿÜr[ÿÜs[ÿÜxxxx©xªx´ÿkxµÿxÅÿ¤y&yÿÜyy[ÿÁy©yªy´ÿkyµÿ·yÅÿ}z&zÿÜzz[ÿÁz©zªz´ÿkzµÿ·zÅÿ}{&{ÿÜ{{[ÿÁ{©{ª{´ÿk{µÿ·{Åÿ}|&|ÿÜ||[ÿÁ|©|ª|´ÿk|µÿ·|Åÿ}}&}ÿÜ}}[ÿÁ}©}ª}´ÿk}µÿ·}Åÿ}‰&‰©‰ª‰´ÿ‰µÿ‰Åÿ­©ª´ÿ­µÿ¤Åÿ©$©%ÿÜ©&ÿÜ©'ÿÜ©)©*ÿÜ©+©-ÿÜ©.©/©2©3©4©5©7ÿ©9ÿ©:ÿÜ©;©<ÿk©=©I©Q©R©U©YÿÜ©ZÿÜ©\ÿÜ©b©dÿÜ©g©x©y©z©{©|©}©‰©—©­©®©¯©ºÿÜ©»ÿk©Ç©É©Ð©Ñ©Ò©å©é©êÿk©ëÿÜ©ì©öÿÜ©ûÿÜ©ýÿܪ$ÿ·ª%ÿ·ª&ÿܪ'ÿܪ)ª*ª+ª-ÿܪ.ª/ª2ÿܪ3ª4ª5ª7ÿDª9ÿNª:ÿª;ÿª<ÿª=ªIªQªRªUªYÿܪZÿܪ\ÿܪbÿ·ªdÿܪgÿܪxªyªzª{ª|ª}ª‰ªª­ÿ·ª®ÿ·ª¯ÿܪºÿܪ»ÿªÇÿ·ªÉÿ·ªÐÿܪÑÿܪÒÿܪåªéªêÿªëÿܪìªöªûÿܪýÿÜ­ÿÓ­ÿÜ­ÿÜ­$9­&ÿÜ­*ÿÜ­2ÿÜ­4ÿÜ­6­7ÿa­8­9ÿ}­:ÿ­;­<ÿa­FÿÜ­GÿÜ­HÿÜ­Iÿ·­RÿÜ­TÿÜ­WÿÜ­X­Yÿˆ­Zÿ­­\ÿu­b9­dÿÜ­gÿÜ­h­oÿÜ­pÿÜ­qÿÜ­rÿÜ­sÿÜ­yÿÜ­zÿÜ­{ÿÜ­|ÿÜ­}ÿÜ­~­­€­­©ÿ·­ª­­9­®9­¯ÿÜ­´þø­µÿ­ºÿu­»ÿa­Å/­Ç9­É9­ÐÿÜ­ÑÿÜ­ÒÿÜ­Ó­Ô­Õ­ã­êÿa­ëÿu­öÿÜ­ù­ûÿÜ­üÿÜ­ýÿÜ­þÿÜ®ÿÓ®ÿÜ®ÿÜ®$9®&ÿÜ®*ÿÜ®2ÿÜ®4ÿÜ®6®7ÿa®8®9ÿ}®:ÿ®;®<ÿa®FÿÜ®GÿÜ®HÿÜ®Iÿ·®RÿÜ®TÿÜ®WÿÜ®X®Yÿˆ®Zÿ­®\ÿu®b9®dÿÜ®gÿÜ®h®oÿÜ®pÿÜ®qÿÜ®rÿÜ®sÿÜ®yÿÜ®zÿÜ®{ÿÜ®|ÿÜ®}ÿÜ®~®®€®®©ÿ·®ª®­9®®9®¯ÿÜ®´þø®µÿ®ºÿu®»ÿa®Å/®Ç9®É9®ÐÿÜ®ÑÿÜ®ÒÿܮӮԮծã®êÿa®ëÿu®öÿÜ®ù®ûÿÜ®üÿÜ®ýÿÜ®þÿܯ9¯ÿ­¯ÿܯ$ÿܯ9ÿܯ;ÿ}¯<ÿ¯bÿܯ©ÿܯª¯­ÿܯ®ÿܯ´ÿÓ¯µÿܯ»ÿ¯ÅÿD¯ÇÿܯÉÿܯêÿ´$þø´%ÿÁ´&ÿ·´'ÿÁ´)ÿÁ´*ÿ·´+ÿÁ´-ÿÁ´.ÿÁ´/ÿÁ´2ÿ·´3ÿÁ´4ÿ·´5ÿÁ´7´9´:´;ÿˆ´<´=ÿÜ´Iÿ·´Qÿ´Rÿk´Uÿ´Yÿ·´Zÿ·´\ÿ·´bþø´dÿ·´gÿ·´xÿ´yÿk´zÿk´{ÿk´|ÿk´}ÿk´‰ÿÁ´þ}´­þø´®þø´¯ÿ·´ºÿ·´»´Çþø´Éþø´Ðÿ·´Ñÿ·´Òÿ·´åÿÜ´éÿ·´ê´ëÿ·´ìÿÁ´öÿ·´ûÿ·´ýÿ·ºÿܺþܺÿkº©ÿܺªÿܺ´ºµºÅþÓ»ÿ »þa»þð»$ÿa»&ÿ»2ÿ»Dþæ»Hþð»Lÿ·»Rþð»Xÿ»bÿa»dÿ»gÿ»iþæ»jþæ»kþæ»lþæ»mþæ»nþæ»pþð»qþð»rþð»sþð»yþð»zþð»{þð»|þð»}þð»~ÿ»ÿ»€ÿ»ÿ»©ÿ»ªÿk»­ÿa»®ÿa»¯ÿ»´ÿ»µÿÜ»Åþø»Çÿa»Éÿa»Ðÿ»Ñÿ»Òÿ»ûÿ»ýÿÅ$&Å%ÿ·Å&ÿÅ'ÿ·Å)ÿ·Å*ÿ·Å+ÿ·Å-/Å.ÿ·Å/ÿ·Å2ÿÅ3ÿ·Å4ÿÅ5ÿ·Å7þæÅ9þˆÅ:ÿÅ;ÿ·Å<þˆÅ=ÅIÿÜÅQÿ·ÅRÿ·ÅUÿ·ÅYÿÅZÿ<Å\ÿÅb&ÅdÿÅgÿÅxÿ·Åyÿ·Åzÿ·Å{ÿ·Å|ÿ·Å}ÿ·Å‰ÿ·Å&Å­&Å®&ůÿźÿÅ»þˆÅÇ&ÅÉ&ÅÐÿÅÑÿÅÒÿÅåÅéÿ·ÅêþˆÅëÿÅìÿ·Åöÿ·ÅûÿÅýÿÇÿÓÇÿÜÇÿÜÇ$9Ç&ÿÜÇ*ÿÜÇ2ÿÜÇ4ÿÜÇ6Ç7ÿaÇ8Ç9ÿ}Ç:ÿÇ;Ç<ÿaÇFÿÜÇGÿÜÇHÿÜÇIÿ·ÇRÿÜÇTÿÜÇWÿÜÇXÇYÿˆÇZÿ­Ç\ÿuÇb9ÇdÿÜÇgÿÜÇhÇoÿÜÇpÿÜÇqÿÜÇrÿÜÇsÿÜÇyÿÜÇzÿÜÇ{ÿÜÇ|ÿÜÇ}ÿÜÇ~ÇÇ€ÇÇ©ÿ·ÇªÇ­9Ç®9ǯÿÜÇ´þøÇµÿǺÿuÇ»ÿaÇÅ/ÇÇ9ÇÉ9ÇÐÿÜÇÑÿÜÇÒÿÜÇÓÇÔÇÕÇãÇêÿaÇëÿuÇöÿÜÇùÇûÿÜÇüÿÜÇýÿÜÇþÿÜÉÿÓÉÿÜÉÿÜÉ$9É&ÿÜÉ*ÿÜÉ2ÿÜÉ4ÿÜÉ6É7ÿaÉ8É9ÿ}É:ÿÉ;É<ÿaÉFÿÜÉGÿÜÉHÿÜÉIÿ·ÉRÿÜÉTÿÜÉWÿÜÉXÉYÿˆÉZÿ­É\ÿuÉb9ÉdÿÜÉgÿÜÉhÉoÿÜÉpÿÜÉqÿÜÉrÿÜÉsÿÜÉyÿÜÉzÿÜÉ{ÿÜÉ|ÿÜÉ}ÿÜÉ~ÉÉ€ÉÉ©ÿ·ÉªÉ­9É®9ɯÿÜÉ´þøÉµÿɺÿuÉ»ÿaÉÅ/ÉÇ9ÉÉ9ÉÐÿÜÉÑÿÜÉÒÿÜÉÓÉÔÉÕÉãÉêÿaÉëÿuÉöÿÜÉùÉûÿÜÉüÿÜÉýÿÜÉþÿÜÐ9Ðÿ­ÐÿÜÐ$ÿÜÐ9ÿÜÐ;ÿ}Ð<ÿÐbÿÜЩÿÜЪЭÿÜЮÿÜдÿÓеÿÜлÿÐÅÿDÐÇÿÜÐÉÿÜÐêÿÑ9Ñÿ­ÑÿÜÑ$ÿÜÑ9ÿÜÑ;ÿ}Ñ<ÿÑbÿÜÑ©ÿÜѪѭÿÜÑ®ÿÜÑ´ÿÓѵÿÜÑ»ÿÑÅÿDÑÇÿÜÑÉÿÜÑêÿÒ9Òÿ­ÒÿÜÒ$ÿÜÒ9ÿÜÒ;ÿ}Ò<ÿÒbÿÜÒ©ÿÜÒªÒ­ÿÜÒ®ÿÜÒ´ÿÓÒµÿÜÒ»ÿÒÅÿDÒÇÿÜÒÉÿÜÒêÿÓ$Ó-Ó=ÿÜÓbÓ­Ó®ÓÇÓÉÓåÿÜÔ$Ô-Ô=ÿÜÔbÔ­Ô®ÔÇÔÉÔåÿÜÕ$Õ-Õ=ÿÜÕbÕ­Õ®ÕÇÕÉÕåÿÜã$&ã&ã*ã2ã4ã6ãb&ãdãgã­&ã®&ã¯ãÇ&ãÉ&ãÐãÑãÒãããöãùãûãýåÿÜå©åªå´ÿÜåµÿÜåÅÿÜéé©éªé´ÿ¤éµÿéÅÿ·êÿ êþaêþðê$ÿaê&ÿê2ÿêDþæêHþðêLÿ·êRþðêXÿêbÿaêdÿêgÿêiþæêjþæêkþæêlþæêmþæênþæêpþðêqþðêrþðêsþðêyþðêzþðê{þðê|þðê}þðê~ÿêÿê€ÿêÿê©ÿêªÿkê­ÿaê®ÿaê¯ÿê´ÿêµÿÜêÅþøêÇÿaêÉÿaêÐÿêÑÿêÒÿêûÿêýÿëÿÜëþÜëÿkë©ÿÜëªÿÜë´ëµëÅþÓììÿkìÿ·ì©ìªì´ÿÜìµìÅÿDöö$ö7ÿ·ö:ö<ÿšöbö©ÿÜöªÿÜö­ö®ö´ÿÓöµÿÓö»ÿšöÅÿÉöÇöÉöêÿšù$&ù&ù*ù2ù4ù6ùb&ùdùgù­&ù®&ù¯ùÇ&ùÉ&ùÐùÑùÒùãùöùùùûùýûû$û6û<ÿÜûbû©ÿÜûªÿÜû­û®û´ûµ&û»ÿÜûÅûÇûÉûãûêÿÜûùýý$ý6ý<ÿÜýbý©ÿÜýªÿÜý­ý®ý´ýµ&ý»ÿÜýÅýÇýÉýãýêÿÜýù MB@hmþ ¼þ‰þ‰ L GÌþBGÌSf €¯ JBits@ ûþšmãB±‹`#cÕVeraSansÿÿÿÿ6ÿÿþ628R00@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "                      "       #                       #     $               $    &              &    ÿÿ P ì_<õº¹ð¸ºÂg‘þ‰þ Lmpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/hslider.left.tga0000644000000000000000000000056411130023047025025 0ustar rootroot  (þþþ~~~ÿ€þþþ~~~ÿþþþÿ€~~~ÿ~~~ÿûûûÿ€~~~ÿ~~~ÿ‡öööÿÿ„öööÿ€~~~ÿ~~~ÿ†ïïïÿÿ„ïïïÿ€~~~ÿ~~~ÿ…çççÿ‚ÿ„çççÿ€~~~ÿ~~~ÿ‚ÞÞÞÿÝÝÝÿƒÿÝÝÝÿÞÞÞÿ‚ÝÝÝÿ€~~~ÿ~~~ÿƒÓÓÓÿ„ÿ„ÓÓÓÿ€~~~ÿ~~~ÿƒÓÓÓÿ„ÿ„ÓÓÓÿ€~~~ÿ~~~ÿ„ÛÛÛÿƒÿ„ÛÛÛÿ€~~~ÿ~~~ÿ…ãããÿ‚ÿ„ãããÿ€~~~ÿ~~~ÿ†êêêÿÿ„êêêÿ€~~~ÿ~~~ÿ‡ðððÿÿ„ðððÿ€~~~ÿ~~~ÿõõõÿ€~~~ÿ~~~ÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dialog.close.normal.tga0000644000000000000000000000110611130023047026265 0ustar rootroot  („@@@…@@@ÿ„@@@‚@@@@@@ÿTTUÿ¦¦¹ÿÝÝîÿùùýÿÝÝîÿ¦¦¹ÿTTUÿ@@@ÿ‚@@@@@@@@@ÿÿÚÚóÿßß÷ÿàà÷ÿßß÷ÿàà÷ÿßß÷ÿÚÚóÿÿ@@@ÿ@@@@@@@@@ÿrr‚ÿ‰¿¿ïÿrr‚ÿ@@@ÿ€@@@@@@KKKÿœœáÿ‚ŸŸçÿ„  çÿŸŸçÿ  çÿœœáÿKKKÿ€@@@@@@ÿbbƒÿ‹€€àÿbbƒÿ€@@@ÿ@@@ÿZZ¬ÿ‹``×ÿZZ­ÿ€@@@ÿ@@@ÿ@@Æÿ‹@@Ðÿ@@Æÿ€@@@ÿ@@@ÿ@@Æÿ‹@@Ðÿ@@Æÿ€@@@ÿ@@@ÿPPªÿXX×ÿWW×ÿ„XX×ÿWW×ÿ‚XX×ÿPPªÿ€@@@ÿ@@@ÿNNvÿ‹ppàÿNNvÿ€@@@ÿ@@@@@Bÿƒƒàÿ‡‡çÿ‚ˆˆçÿ‡‡çÿˆˆçÿ‡‡çÿˆˆçÿ‡‡çÿƒƒàÿAABÿ€@@@@@@@@@ÿNNgÿ‰  ïÿNNgÿ@@@ÿ€@@@@@@@@@ÿRRlÿ°°òÿ‚¸¸÷ÿ··÷ÿ¸¸÷ÿ°°òÿRRkÿ@@@ÿ@@@‚@@@@@@ÿBBCÿii“ÿ  àÿÆÆûÿ  àÿii“ÿBBCÿ@@@ÿ‚@@@„@@@…@@@ÿ„@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vbox.normal.png0000644000000000000000000000035111130023047024712 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ - ;tEXtCommentCreated with The GIMPïd%nQIDAT(Ï¥‘1 À0 ÏÚB ýÿCéPèÒAù€ƒk>¤3@¬ÄÏÇËÃÍ.:ÆÉÎÁ†Ih „kP‚% rõ Û@Á¡~E¦îÝÐ#}ŸIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/radio.on.normal.tga0000644000000000000000000000120611130023047025434 0ustar rootroot  („…ÿ„‚ÿÿ œˆÿçãÑÿûú÷ÿçãÑÿ œˆÿÿÿ‚ÿgcSÿîèÌÿóíÓÿóîÕÿóíÓÿóîÕÿóíÓÿîèÌÿgcSÿÿÿXTBÿ‰éÞ©ÿXTBÿÿ€ ÿÖÆzÿ‚ÞÍ~ÿ„ÞÍ€ÿÞÍ~ÿÞÍ€ÿÖÆzÿ ÿ€ÿXP,ÿ„Ô½Tÿÿ„Ô½TÿXP,ÿ€ÿÿ|!ÿÊ­*ÿÉ­)ÿÊ­*ÿƒÿÊ­*ÿÉ­)ÿÊ­*ÿ}"ÿ€ÿÿ³“ÿ‚¿ÿ…ÿ‚¿ÿ³“ÿ€ÿÿ³“ÿ‚¿ÿ…ÿ‚¿ÿ³“ÿ€ÿÿŽxÿÉ«ÿʬÿÉ«ÿƒÿʬÿ‚É«ÿŒwÿ€ÿÿG=ÿ„Ôº@ÿÿ„Ôº@ÿG=ÿ€ÿÿÔ¾XÿÞÇ^ÿ‚ÞÈ`ÿÞÇ^ÿÞÈ`ÿÞÇ^ÿÞÈ`ÿÞÇ^ÿÔ¾Xÿÿ€ÿ4.ÿ‰éÖÿ4.ÿÿ€ÿ93ÿìÜ”ÿ…óäŸÿìÜ”ÿ93ÿÿ‚ÿÿoe5ÿÔÅ€ÿùì³ÿÔÅ€ÿoe5ÿÿÿ‚„…ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/slider.tga0000644000000000000000000000231711130023047023722 0ustar rootroot  (‚€€€ÿÿÿ£££ÿªªªÿˆ®®®ÿ°°°ÿ®®®ÿªªªÿ‚ÿÿÿ€€€€€€ÿÿÿ£££ÿ®®®ÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿ¼¼¼ÿ®®®ÿÿÿÿ€€€€€€€ÿÿÿ£££ÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿµµµÿÿÿÿÿÿÿ£££ÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿµµµÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿ£££ÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€¼¼¼ÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ°°°ÿÎÎÎÿéééÿùùùÿýýýÿŠþþþÿÿÿÿÿ‚þþþÿýýýÿùùùÿéééÿ€ÎÎÎÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿÿÿÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿÿÿÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿÿÿÿ€€€ÿÿÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿ‚ÿÿÿ€€€‚ÿÿÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿƒÿÿÿ€€€€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/tool.down.tga0000644000000000000000000000102011130023047024351 0ustar rootroot  (•ÿ€ÿ•ÿÿÿÿ€ÿÿôïÖÿôîÔÿôïÖÿ‰ôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿ€ÿÿ•êߪÿ€ÿÿ…ßÎÿˆßÎÿßÎÿ„ßÎÿ€ÿÿ•Õ¾Uÿ€ÿÿ‚Ë®+ÿÊ®*ÿË®+ÿˆÊ®*ÿË®+ÿÊ®*ÿË®+ÿ‚Ê®*ÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿʬ ÿË­ÿ‹Ê¬ ÿË­ÿʬ ÿË­ÿʬ ÿ€ÿÿ•Õ»Aÿ€ÿÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿ‹ßÈ_ÿßÉaÿßÈ_ÿ€ÿÿ•ê×€ÿ€ÿÿ•ôå ÿ€ÿÿ•ÿôÁÿ€ÿ•ÿ€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vdot.normal.png0000644000000000000000000000054211130023047024712 0ustar rootroot‰PNG  IHDRµú7êbKGD€G5  pHYs  šœtIMEÖ 9BÕÑ—tEXtCommentCreated with The GIMPïd%nÊIDAT(Ï}ѱJQ„áïÞHD¬lÄ">@ ÁÂÖN|!ßHìlMe!¦LDH°ˆ Ä‹ÍnXÙuªážŸÃ3éV¥ØX©4[åpW϶OtÌM"ÖPÄ™¾3_ØslÇÀ4$2âÒEal_;$È8פY\ɵŸEµå”ÈiÓ 2Ý?ÏUBûð¿2ß­ÃYŒ[WdéÁªáÖ,½2ïžcÞY­Oc¡_K±toJ*»HÏ1ÔÓõƒ¹‘‰zY¤…·Æºõ3m9}IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/slider.bar.hover.tga0000644000000000000000000000141011130023047025600 0ustar rootroot  („@@@@@@ÿ„@@@‚@@@@@@ÿVUTÿ¹¶§ÿîëÞÿ‰ýüùÿîëÞÿ¹¶§ÿVUTÿ@@@ÿ‚@@@@@@@@@ÿ‹ÿóïÛÿ÷óßÿˆ÷óáÿ÷óßÿ÷óáÿ÷óßÿóïÛÿ‹ÿ@@@ÿ@@@@@@@@@ÿ‚rÿ‘ïæ¿ÿ‚rÿ@@@ÿ€@@@@@@KKKÿáÕÿ‚çÚŸÿŒçÛ¡ÿçÚŸÿçÛ¡ÿáÕÿKKKÿ€@@@@@@ÿ„~bÿ“àÏ€ÿ„~bÿ€@@@ÿ@@@ÿ¬Zÿ“×Âaÿ­Ÿ[ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿªšPÿ×ÁYÿ×ÀWÿŒ×ÁYÿ×ÀWÿ‚×ÁYÿªšPÿ€@@@ÿ@@@ÿvoNÿ“àÌpÿvoNÿ€@@@ÿ@@@BB@ÿàЄÿçÖ‡ÿ‚çÖ‰ÿˆçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿàЄÿCBAÿ€@@@@@@@@@ÿgcOÿ‘ïá¡ÿgcOÿ@@@ÿ€@@@@@@@@@ÿlgRÿòæ°ÿŠ÷ì¹ÿ÷ë·ÿ÷ì¹ÿòæ°ÿlgRÿ@@@ÿ@@@‚@@@@@@ÿDCBÿ“ŒiÿàÕ ÿ‰ûòÇÿàÕ ÿ“ŒiÿDCBÿ@@@ÿ‚@@@„@@@@@@ÿ„@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/rdot.normal.png0000644000000000000000000000056211130023047024710 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÕ6™ù¿tEXtCommentCreated with The GIMPïd%nÚIDAT(Ï…Ñ¡NзähRLjHðR@U£|A¿¤(>@AQ`²M qw%—´aÔ&»³;³#Kä_)š¢hšÛNØÁÔË\ÔC1‚|®Ùðƒ ÿ `CÙ:K¹‹jàÕÞö 1Í-›5§zSõ°/3¢€+g+øç²sc]¥R©§§Ô56'š,ȰïÈ.žÝ¸—µÒ&ÍH“œ¬ˆûå3<²6nÝJIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/input.focus.png0000644000000000000000000000026511130023047024726 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ(%¹tEXtCommentCreated with The GIMPïd%n+IDAT8Ëc` `d``øÿÿ?¥¦022QËE£4jШA£ ƒ¨;…,;)k“IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vslider.down.tga0000644000000000000000000000154011130023047025053 0ustar rootroot  (þþþ~~~ÿ€þþþ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿ‰ÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿ‡ÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿ…ÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿƒÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÝÝÝÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿ~~~ÿþþþÿûûûÿöööÿïïïÿçççÿÞÞÞÿÓÓÓÿÛÛÛÿãããÿêêêÿðððÿõõõÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/checkbox.on.hover.tga0000644000000000000000000000102711130023047025760 0ustar rootroot  (???ÿ€???ÿþþþÿ€???ÿ???ÿöòàÿöòÞÿöòàÿöòÞÿöòàÿöòÞÿöòàÿöòÞÿöòàÿöòÞÿ€???ÿ???ÿ‚îå¾ÿÿ…îå¾ÿÿ‚îå¾ÿ€???ÿ???ÿæÚ ÿ‚ÿæÚ ÿæÙžÿæÚ ÿ‚ÿæÙžÿ€???ÿ???ÿ‚ßÎÿ‚ÿßÎÿ‚ÿ‚ßÎÿ€???ÿ???ÿ‚ÖÁ`ÿÖÁ^ÿ…ÿÖÁ`ÿ‚ÖÁ^ÿ€???ÿ???ÿ„϶?ÿƒÿ„϶?ÿ€???ÿ???ÿ„϶?ÿƒÿ„϶?ÿ€???ÿ???ÿÖÀXÿÖ¿VÿÖÀXÿ…ÿÖ¿VÿÖÀXÿ€???ÿ???ÿ‚ßËoÿ‚ÿßËoÿ‚ÿ‚ßËoÿ€???ÿ???ÿæÕˆÿæÕ†ÿ‚ÿæÕˆÿ‚æÕ†ÿ‚ÿæÕ†ÿ€???ÿ???ÿ‚îà ÿÿ…îà ÿÿ‚îà ÿ€???ÿ???ÿöê¶ÿöë¸ÿöê¶ÿöë¸ÿ‚öê¶ÿ‚öë¸ÿöê¶ÿöë¸ÿöê¶ÿ€???ÿ???ÿþöÐÿ€???ÿ???ÿ€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/input.normal.png0000644000000000000000000000032011130023047025067 0ustar rootroot‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ +–ðrctEXtCommentCreated with The GIMPïd%n4IDAT8Ëclhh` `a``HHH Ð” 01P Œ4jШA£4t bÔ”J”‘¡Å-IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/out.tga0000644000000000000000000000143311130023047023245 0ustar rootroot  („``````ÿ„```‚``````ÿqqqÿ¹¹¹ÿæææÿ‰ûûûÿæææÿ¹¹¹ÿqqqÿ```ÿ‚`````````ÿ˜˜˜ÿæææÿêêêÿˆëëëÿêêêÿëëëÿêêêÿæææÿ˜˜˜ÿ```ÿ`````````ÿŽŽŽÿ‘ÖÖÖÿŽŽŽÿ```ÿ€``````iiiÿ¾¾¾ÿ‚ÁÁÁÿŒÂÂÂÿÁÁÁÿÂÂÂÿ¾¾¾ÿiiiÿ€``````ÿ„„„ÿ“­­­ÿ„„„ÿ€```ÿ```ÿŠŠŠÿ™™™ÿ˜˜˜ÿ™™™ÿ˜˜˜ÿ™™™ÿŠŠŠÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ‚‚‚ÿ“„„„ÿ‚‚‚ÿ€```ÿ```ÿ„„„ÿ”””ÿ“““ÿŒ”””ÿ“““ÿ‚”””ÿƒƒƒÿ€```ÿ```ÿuuuÿ“¤¤¤ÿuuuÿ€```ÿ``````ÿ®®®ÿ³³³ÿ‚´´´ÿˆ³³³ÿ´´´ÿ³³³ÿ´´´ÿ³³³ÿ®®®ÿaaaÿ€`````````ÿrrrÿ‘ÄÄÄÿrrrÿ```ÿ€`````````ÿuuuÿÍÍÍÿŠÔÔÔÿÓÓÓÿÔÔÔÿÍÍÍÿuuuÿ```ÿ```‚``````ÿaaaÿŒŒŒÿÀÀÀÿ‰ÝÝÝÿÀÀÀÿŒŒŒÿaaaÿ```ÿ‚```„``````ÿ„```python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.selected.normal.tga0000644000000000000000000000043211130023047026771 0ustar rootroot  (–ÿÿ–ÿÿÿÿÿ–úúúÿÿ–ðððÿÿ–ãããÿÿ–ÒÒÒÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ–ªªªÿÿ»»»ÿºººÿ“»»»ÿÿ–ËËËÿÿ–ØØØÿÿ–åååÿÿ–ïïïÿÿ–÷÷÷ÿ–ÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/button.down.tga0000644000000000000000000000142211130023047024715 0ustar rootroot  („ÿ„‚ÿÿ¡‰ÿèäÒÿ‰üûøÿèäÒÿ¡‰ÿÿÿ‚ÿhdTÿïéÍÿôîÔÿˆôïÖÿôîÔÿôïÖÿôîÔÿïéÍÿhdTÿÿÿYUCÿ‘êߪÿYUCÿÿ€ÿ×Ç{ÿ‚ßÎÿŒßÎÿßÎÿßÎÿ×Ç{ÿÿ€ÿYQ-ÿ“Õ¾UÿYQ-ÿ€ÿÿ}"ÿË®+ÿÊ®*ÿË®+ÿÊ®*ÿË®+ÿ‘~#ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿ´”ÿ“Àžÿ´”ÿ€ÿÿyÿʬ ÿË­ÿŒÊ¬ ÿË­ÿ‚ʬ ÿxÿ€ÿÿH>ÿ“Õ»AÿH>ÿ€ÿÿÕ¿YÿßÈ_ÿ‚ßÉaÿˆßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿÕ¿Yÿÿ€ÿ5/ÿ‘ê×€ÿ5/ÿÿ€ÿ:4ÿíÝ•ÿôå ÿíÝ•ÿ:4ÿÿ‚ÿÿpf6ÿÕÆÿ‰úí´ÿÕÆÿpf6ÿÿÿ‚„ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/config.txt0000644000000000000000000001723511130023047023756 0ustar rootrootdesktop background desktop.png input font Vera.ttf 16 input background input.normal.png input color #000000 input:focus background input.focus.png input padding_left 6 input padding_right 6 input padding_top 3 input padding_bottom 3 link font Vera.ttf 24 link color #0000FF link:hover color #FF0000 link:down color #00FF00 label font Vera.ttf 12 label color #000000 document font Vera.ttf 16 document color #000000 div font Vera.ttf 16 div color #000000 td font Vera.ttf 16 td color #000000 th font Vera.ttf 16 th color #000000 h1 font Vera.ttf 24 h1 color #000000 h2 font Vera.ttf 20 h2 color #000000 h3 font Vera.ttf 16 h3 color #000000 h4 font Vera.ttf 14 h4 color #000000 h5 font Vera.ttf 12 h5 color #000000 h6 font Vera.ttf 10 h6 color #000000 ul font Vera.ttf 16 ul color #000000 ol font Vera.ttf 16 ol color #000000 li font Vera.ttf 16 li color #000000 li padding_left 32 pre font mono 16 pre color #000000 code font mono 16 code color #000000 checkbox off checkbox.off.normal.tga checkbox on checkbox.on.normal.tga checkbox:hover off checkbox.off.hover.tga checkbox:hover on checkbox.on.hover.tga checkbox:down off checkbox.off.hover.tga checkbox:down on checkbox.on.hover.tga switch off checkbox.off.normal.tga switch on checkbox.on.normal.tga switch:hover off checkbox.off.hover.tga switch:hover on checkbox.on.hover.tga switch:down off checkbox.off.hover.tga switch:down on checkbox.on.hover.tga radio off radio.off.normal.tga radio on radio.on.normal.tga radio:hover off radio.off.hover.tga radio:hover on radio.on.hover.tga radio:down off radio.off.hover.tga radio:down on radio.on.hover.tga button background button.normal.tga button:hover background button.hover.tga button:down background button.down.tga button padding_left 8 button padding_right 8 button padding_top 1 button padding_bottom 1 button.label font Vera.ttf 16 button.label color #000000 slider background slider.tga slider bar slider.bar.normal.tga slider:hover bar slider.bar.hover.tga slider width 16 slider height 16 hslider background hslider.tga hslider bar hslider.bar.normal.tga hslider:hover bar hslider.bar.hover.tga hslider:down bar hslider.bar.hover.tga hslider width 16 hslider height 16 vslider background vslider.tga vslider bar vslider.bar.normal.tga vslider:hover bar vslider.bar.hover.tga vslider:down bar vslider.bar.hover.tga vslider width 16 vslider height 16 xhscrollbar height 16 xhscrollbar background scroller.slide.h.tga xhscrollbar bar scroller.slide.bar.normal.tga xhscrollbar:hover bar scroller.slide.bar.hover.tga xvscrollbar width 16 xvscrollbar background scroller.slide.v.tga xvscrollbar bar scroller.slide.bar.normal.tga xvscrollbar:hover bar scroller.slide.bar.hover.tga hscrollbar.slider background hslider.tga hscrollbar.slider bar hslider.bar.normal.tga hscrollbar.slider:hover bar hslider.bar.hover.tga hscrollbar.slider:down bar hslider.bar.hover.tga hscrollbar.slider width 16 hscrollbar.slider height 16 hscrollbar minus hslider.left.tga hscrollbar plus hslider.right.tga vscrollbar.slider background vslider.tga vscrollbar.slider bar vslider.bar.normal.tga vscrollbar.slider:hover bar vslider.bar.hover.tga vscrollbar.slider:down bar vslider.bar.hover.tga vscrollbar.slider width 16 vscrollbar.slider height 16 vscrollbar minus vslider.up.tga vscrollbar plus vslider.down.tga select.selected background select.selected.normal.tga select.selected:hover background select.selected.hover.tga select.selected:down background select.selected.down.tga select.selected padding_left 4 select.selected padding_right 4 select.selected padding_top 1 select.selected padding_bottom 1 select.arrow background select.arrow.normal.tga select.arrow:hover background select.arrow.hover.tga select.arrow:down background select.arrow.down.tga select.arrow padding_left 1 select.arrow padding_right 1 select.options background select.options.png select.option background select.option.normal.png select.option:hover background select.option.hover.png select.option:down background select.option.hover.png select.option padding_left 4 select.option padding_right 4 select.option padding_top 1 select.option padding_bottom 1 #select.option border_top 1 #select.option border_right 1 #select.option border_bottom 1 #select.option border_left 1 select.option.label font Vera.ttf 16 select.option.label color #000000 select.options padding_left 1 select.options padding_right 1 select.options padding_top 1 select.options padding_bottom 1 select arrow select.arrow.png dialog background dialog.bar.png xdialog.bar background dialog.bar.png dialog.bar padding_left 8 dialog.bar padding_right 8 dialog.bar padding_top 2 dialog.bar padding_bottom 1 dialog.bar.close image dialog.close.normal.tga dialog.bar.close:hover image dialog.close.hover.tga dialog.bar.close:down image dialog.close.down.tga dialog.main background dialog.png dialog.main padding_left 8 dialog.main padding_right 8 dialog.main padding_top 4 dialog.main padding_bottom 4 keysym font Vera.ttf 16 keysym background input.normal.png keysym color #000000 keysym:focus background input.focus.png keysym padding_left 6 keysym padding_right 6 keysym padding_top 3 keysym padding_bottom 3 tool background tool.normal.tga tool:hover background tool.hover.tga tool:down background tool.down.tga tool padding_left 4 tool padding_right 4 tool padding_top 1 tool padding_bottom 1 tool.label font Vera.ttf 16 tool.label color #000000 menu background menu.normal.tga menu:hover background menu.hover.tga menu:down background menu.down.tga menu padding_left 6 menu padding_right 6 menu padding_top 3 menu padding_bottom 3 menu.label font Vera.ttf 16 menu.label color #000000 menu-open background menu.down.tga menu-open:hover background menu.down.tga menu-open:down background menu.down.tga menu-open padding_left 6 menu-open padding_right 6 menu-open padding_top 3 menu-open padding_bottom 3 menu.options background select.options.png menu.option background select.option.normal.png menu.option:hover background select.option.hover.png menu.option:down background select.option.hover.png menu.option padding_left 6 menu.option padding_right 6 menu.option padding_top 1 menu.option padding_bottom 1 menu.option.label font Vera.ttf 16 menu.option.label color #000000 menu.options padding_left 1 menu.options padding_right 1 menu.options padding_top 1 menu.options padding_bottom 1 menu arrow select.arrow.tga scrollarea.content background #ffffff scrollarea.content padding_left 1 scrollarea.content padding_right 1 scrollarea.content padding_top 1 scrollarea.content padding_bottom 1 list.item background list.item.normal.png list.item:hover background list.item.down.png list.item:down background list.item.down.png list.item padding_left 4 list.item padding_right 4 list.item padding_top 2 list.item padding_bottom 2 list.item margin_bottom 1 list.item align -1 list.item.label font Vera.ttf 14 list.item.label color #000000 list background list.png list padding_left 1 list padding_right 1 list padding_top 1 list padding_bottom 1 list.content background #eeeeee list.content padding_left 1 list.content padding_right 1 list.content padding_top 1 list.content padding_bottom 1 filedialog.folder image filebrowser.folder.png filedialog.label font Vera.ttf 14 filedialog.label color #000000 filedialog.title.label font Vera.ttf 16 filedialog.title.label color #000000 filedialog.input font Vera.ttf 14 filedialog.input background input.normal.png filedialog.input color #000000 filedialog.input:focus background input.focus.png filedialog.input padding_left 6 filedialog.input padding_right 6 filedialog.input padding_top 3 filedialog.input padding_bottom 3 dialog.title.label font Vera.ttf 16 dialog.title.label color #000000 progressbar background progressbar.tga progressbar bar progressbar.bar.tga progressbar width 16 progressbar height 16 python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.option.normal.png0000644000000000000000000000025411130023047026524 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/progressbar.tga0000644000000000000000000000063411130023047024771 0ustar rootroot  (ÿÿÿ•ÿ€ÿÿÿÿ•ÿÿÿÿ€ÿÿ•üüüÿ€ÿÿ•÷÷÷ÿ€ÿÿ•ðððÿ€ÿÿ•èèèÿ€ÿÿ‚ßßßÿÞÞÞÿßßßÿˆÞÞÞÿßßßÿÞÞÞÿßßßÿ‚ÞÞÞÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÔÔÔÿ€ÿÿ•ÜÜÜÿ€ÿÿ•äääÿ€ÿÿ•ëëëÿ€ÿÿ•ñññÿ€ÿÿ•öööÿ€ÿÿ•úúúÿ€ÿÿÿÿ•ÿ€ÿÿÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/list.item.normal.png0000644000000000000000000000025411130023047025646 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/rdot.down.png0000644000000000000000000000101511130023047024361 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  †tEXtCommentCreated with The GIMPïd%nqIDAT8Ë¥“±KQÇ?'WF‚ "('œý E´9GcCAqÍ945tsÒ`[S mƒâàTƒ§àPÐ,ˆBÂyšæk0;SPú.~ïý¾ßï{¿ï“˜ 1§.M|Ó1E÷†AÃ4Ú6CÛ¦ašÜ1EÓänF‘:>ÆH§Yñûw%ÂYý>××dŸžœÞ 8I&¹I¥XçÙ,ÅâD6‚Añªë¬É²Ë›4ãeÆnzƒ{™ ŸŽ$BSUFootYšªòP« `ײ°êuÊìÙÇÝ^¯Ç l}|,¥°9gŒKCx‡9æÛwYŸ bYÐlŽ òß߯ãK)ªUÇ”o·Ñ(ë««^®¹ƒÕýú¢P*y<‰D(DN×a&C¹Õú“±‰ð|y‰?˜yÿ¾eqtuÅK£ñ'ÊÎqÙçã,‘àTÓØÞÙà½Rá.—ã¶\f8yú¤ÿ~ç9ðŒ„-°IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/rdot.hover.png0000644000000000000000000000102111130023047024532 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ/÷ÙwtEXtCommentCreated with The GIMPïd%nuIDAT8Ë¥“±KaÆg' …Z9µe›G»®A‚DÿC[Sõ7D“Ð*sã¡ :ˆÃé’ˆ)Ò©×} êuÊ VÏòÂ÷ñ=ïó>ßóJªªâ;¤ùyþáF(ÄE*Åa<ÎZ4 À‡®SÔ4r9ñÞjÍI"™Hpyv†ìõNn%®æhÄýã#ùBÁ&™*'dT³ÑÀd12ªJ¿×ã¥\€$øý~ÒŠ‚Q¯;¦•\œ«I+ Z¥B¿ßGÄq8ŒÐu,ãp˜çZMÈ»†Á§³ûP†Cž§l5›¿ê°9©þ @__gßçûù27óæŒ­t:c‚’eq‰üªs©V³H¥nW ²*˳ !rk`š”^_±s`·Å"w©ÔRݯs9¬ éL”÷nÎÏñú|®ó ƒ«l–·vÛŽ²4·bÅãátg‡d<Îv,@£Z%¯i„8#VKD™9Œ+p8’ 7}ú ß°ñIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.arrow.png0000644000000000000000000000023411130023047025055 0ustar rootroot‰PNG  IHDR}Œß¬ pHYs  šœtIMEÕ 6·`;IDATÓcd````dÀÞÃwþcÀ»È*Ï IžA7j7’änlv­‚J®bÀf2üg˜É€t rò,!¿H:©IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/generate.py0000644000000000000000000000665511130023047024120 0ustar rootrootimport pygame from pygame.locals import * pygame.display.init() pygame.display.set_mode((80,80),32) def prep(name): fname = name+".png" img = pygame.image.load(fname) w,h = img.get_width()/2,img.get_height()/2 out = pygame.Surface((w*3,h*3),SWSURFACE|SRCALPHA,32) out.fill((0,0,0,0)) out.blit(img.subsurface(0,0,w,h),(0,0)) out.blit(img.subsurface(w,0,w,h),(w*2,0)) out.blit(img.subsurface(0,h,w,h),(0,h*2)) out.blit(img.subsurface(w,h,w,h),(w*2,h*2)) for i in range(0,w): img = out.subsurface((w-1,0,1,h*3)).convert_alpha() out.blit(img,(w+i,0)) for i in range(0,h): img = out.subsurface((0,h-1,w*3,1)).convert_alpha() out.blit(img,(0,h+i)) return out,w,h todo = [ ('button.normal','dot.normal',None,3,3,'789456123'), ('button.hover','dot.hover',None,3,3,'789456123'), ('button.down','dot.down',None,3,3,'789456123'), ('checkbox.off.normal','box.normal',None,2,2,'7913'), ('checkbox.on.normal','box.down','check',2,2,'7913'), ('checkbox.off.hover','box.hover',None,2,2,'7913'), ('checkbox.on.hover','box.hover','check',2,2,'7913'), ('radio.off.normal','dot.normal',None,2,2,'7913'), ('radio.on.normal','dot.down','radio',2,2,'7913'), ('radio.off.hover','dot.hover',None,2,2,'7913'), ('radio.on.hover','dot.hover','radio',2,2,'7913'), ('tool.normal','box.normal',None,3,3,'789456123'), ('tool.hover','box.hover',None,3,3,'789456123'), ('tool.down','box.down',None,3,3,'789456123'), ('hslider','idot.normal',None,3,3,'789456123'), ('hslider.bar.normal','dot.normal',None,3,3,'789456123'), ('hslider.bar.hover','dot.hover',None,3,3,'789456123'), ('hslider.left','sbox.normal','left',2,2,'7913'), ('hslider.right','sbox.normal','right',2,2,'7913'), ('vslider','idot.normal',None,3,3,'789456123'), ('vslider.bar.normal','vdot.normal',None,3,3,'789456123'), ('vslider.bar.hover','vdot.hover',None,3,3,'789456123'), ('vslider.up','vsbox.normal','up',2,2,'7913'), ('vslider.down','vsbox.normal','down',2,2,'7913'), ('dialog.close.normal','rdot.hover',None,2,2,'7913'), ('dialog.close.hover','rdot.hover','x',2,2,'7913'), ('dialog.close.down','rdot.down','x',2,2,'7913'), ('menu.normal','desktop',None,1,1,'7'), ('menu.hover','box.normal',None,3,3,'789456123'), ('menu.down','box.down',None,3,3,'789456123'), ('select.selected.normal','box.normal',None,3,3,'788455122'), ('select.selected.hover','box.hover',None,3,3,'788455122'), ('select.selected.down','box.down',None,3,3,'788455122'), ('select.arrow.normal','box.hover',None,3,3,'889556223'), ('select.arrow.hover','box.hover',None,3,3,'889556223'), ('select.arrow.down','box.down',None,3,3,'889556223'), ('progressbar','sbox.normal',None,3,3,'789456123'), ('progressbar.bar','box.hover',None,3,3,'789456123'), ] for fname,img,over,ww,hh,s in todo: print fname img,w,h = prep(img) out = pygame.Surface((ww*w,hh*h),SWSURFACE|SRCALPHA,32) out.fill((0,0,0,0)) n = 0 for y in range(0,hh): for x in range(0,ww): c = int(s[n]) xx,yy = (c-1)%3,2-(c-1)/3 out.blit(img.subsurface((xx*w,yy*h,w,h)),(x*w,y*h)) n += 1 if over != None: over = pygame.image.load(over+".png") out.blit(over,(0,0)) pygame.image.save(out,fname+".tga") python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/list.item.hover.png0000644000000000000000000000025411130023047025501 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕ ¿xÄtEXtCommentCreated with The GIMPïd%n"IDAT8Ëcüÿÿ?5•À¨A£4jШA£‘Ñ-IÓiIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.selected.down.tga0000644000000000000000000000050211130023047026446 0ustar rootroot  (–ÿÿ–ÿÿÿÿÿôïÖÿôîÔÿôïÖÿ‘ôîÔÿÿ–êߪÿÿ…ßÎÿßÎÿÿ–Õ¾Uÿÿ‚Ë®+ÿÊ®*ÿË®+ÿÊ®*ÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿ–Àžÿÿʬ ÿË­ÿ“ʬ ÿÿ–Õ»AÿÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿÿ–ê×€ÿÿ–ôå ÿÿ–ÿôÁÿ–ÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vslider.bar.hover.tga0000644000000000000000000000260411130023047025774 0ustar rootroot  („@@@@@@ÿ„@@@‚@@@@@@ÿKKKÿ„~bÿ­Ÿ[ÿ‰Æ®@ÿªšPÿvoNÿCBAÿ@@@ÿ‚@@@@@@@@@ÿ‚rÿáÕÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿàЄÿgcOÿ@@@ÿ@@@@@@@@@ÿ‹ÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‡ÿïá¡ÿlgRÿ@@@ÿ€@@@@@@VUTÿóïÛÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿòæ°ÿDCBÿ€@@@@@@ÿ¹¶§ÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÀWÿàÌpÿçÖ‡ÿïá¡ÿ÷ì¹ÿ“Œiÿ€@@@ÿ@@@ÿîëÞÿ÷óáÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÀWÿàÌpÿçÖ‡ÿïá¡ÿ÷ë·ÿàÕ ÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ë·ÿûòÇÿ€@@@ÿ@@@ÿýüùÿ÷óáÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‡ÿïá¡ÿ÷ì¹ÿûòÇÿ€@@@ÿ@@@ÿîëÞÿ÷óßÿïæ¿ÿçÛ¡ÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ì¹ÿàÕ ÿ€@@@ÿ@@@ÿ¹¶§ÿ÷óßÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿ÷ì¹ÿ“Œiÿ€@@@ÿ@@@VUTÿóïÛÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿçÖ‰ÿïá¡ÿòæ°ÿDCBÿ€@@@@@@@@@ÿ‹ÿïæ¿ÿçÚŸÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÀWÿàÌpÿçÖ‡ÿïá¡ÿlgRÿ@@@ÿ€@@@@@@@@@ÿ‚rÿáÕÿàÏ€ÿ×Âaÿ‰Ð·@ÿ×ÁYÿàÌpÿàЄÿgcOÿ@@@ÿ@@@‚@@@@@@ÿKKKÿ„~bÿ¬Zÿ‰Æ®@ÿªšPÿvoNÿBB@ÿ@@@ÿ‚@@@„@@@@@@ÿ„@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/checkbox.off.normal.tga0000644000000000000000000000050011130023047026256 0ustar rootroot  (ÿ€ÿÿÿÿÿ€ÿÿúúúÿ€ÿÿðððÿ€ÿÿãããÿ€ÿÿÒÒÒÿ€ÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ‚¿¿¿ÿ€ÿÿªªªÿ€ÿÿªªªÿ€ÿÿ»»»ÿºººÿƒ»»»ÿºººÿ»»»ÿºººÿ»»»ÿ€ÿÿËËËÿ€ÿÿØØØÿ€ÿÿåååÿ€ÿÿïïïÿ€ÿÿ÷÷÷ÿ€ÿÿ€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/scroller.slide.v.tga0000644000000000000000000000237611130023047025635 0ustar rootroot $ÿÿÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿÿÿÿØØØÿËËËÿ»»»ÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿÀÀÀÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿÀÀÀÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿ»»»ÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿ¿¿¿ÿÒÒÒÿãããÿØØØÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿÀÀÀÿÒÒÒÿãããÿØØØÿËËËÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿÀÀÀÿÒÒÒÿãããÿÿÿÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿÿÿÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vslider.bar.normal.tga0000644000000000000000000000260411130023047026141 0ustar rootroot  („ÿ„‚ÿŠŠŠÿªªªÿ±±±ÿ‰§§§ÿªªªÿ™™™ÿ€€€ÿÿ‚ÿ´´´ÿáááÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿÔÔÔÿ•••ÿÿÿ¿¿¿ÿðððÿãããÿÒÒÒÿ¿¿¿ÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿ™™™ÿÿ€”””ÿøøøÿðððÿãããÿÒÒÒÿ¿¿¿ÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿëëëÿÿ€ÿÝÝÝÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿºººÿËËËÿØØØÿåååÿïïïÿ³³³ÿ€ÿÿùùùÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿºººÿËËËÿØØØÿåååÿïïïÿâââÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿÿÿÿÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿôôôÿ€ÿÿùùùÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿâââÿ€ÿÿÝÝÝÿúúúÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿïïïÿ³³³ÿ€ÿ”””ÿøøøÿðððÿãããÿÒÒÒÿ¿¿¿ÿ‰ªªªÿ»»»ÿËËËÿØØØÿåååÿëëëÿÿ€ÿ¿¿¿ÿðððÿãããÿÒÒÒÿÀÀÀÿ‰ªªªÿºººÿËËËÿØØØÿåååÿ™™™ÿÿ€ÿ´´´ÿáááÿÒÒÒÿÀÀÀÿ‰ªªªÿ»»»ÿËËËÿÔÔÔÿ•••ÿÿ‚ÿŠŠŠÿªªªÿ°°°ÿ‰§§§ÿªªªÿ™™™ÿ€€€ÿÿ‚„ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/scroller.slide.bar.normal.tga0000644000000000000000000000052611130023047027416 0ustar rootroot $ÿÿÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿÿÿÿ€€€ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¦¦¦ÿ€€€ÿ€€€ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ¦¦¦ÿ€€€ÿÿÿÿÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿÿÿÿÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dialog.bar.png0000644000000000000000000000051111130023047024445 0ustar rootroot‰PNG  IHDR\é.&bKGDÿÿÿ ½§“ pHYs  šœtIMEÖ 4-x‡ètEXtCommentCreated with The GIMPïd%n­IDAT8ËcdÀþ3 üg```hZ±†,Óë"B0ÌE¶àÛºMpŽ®µ5I†_>zή òƒ›Íˆn8©ã²f Lâϯ_ Ú–– ¿~ü Èucc†«ÇÃùL ÿÉ s|jæ66Šƒ::ÂƒŠ‰Æ€þ”†=:øóë}ÀÂÆÆÀÆÁA]ƒÙØFã`Ä ¶"v4FóIqà7IÚá¶¢{IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/scroller.slide.h.tga0000644000000000000000000000237611130023047025617 0ustar rootroot $ÿÿÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿÿÿÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿºººÿºººÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿºººÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿºººÿËËËÿËËËÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿÀÀÀÿËËËÿËËËÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿËËËÿÿÿÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿÿÿÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/menu.hover.tga0000644000000000000000000000067111130023047024527 0ustar rootroot  (•ÿ€ÿ•ÿÿÿÿ€ÿÿ•úúúÿ€ÿÿ•ðððÿ€ÿÿ•ãããÿ€ÿÿ•ÒÒÒÿ€ÿÿ‚ÀÀÀÿ¿¿¿ÿÀÀÀÿˆ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ‚¿¿¿ÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ•ªªªÿ€ÿÿ»»»ÿºººÿ‹»»»ÿºººÿ»»»ÿºººÿ»»»ÿ€ÿÿ•ËËËÿ€ÿÿ•ØØØÿ€ÿÿ•åååÿ€ÿÿ•ïïïÿ€ÿÿ•÷÷÷ÿ€ÿ•ÿ€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vdot.hover.png0000644000000000000000000000101711130023047024543 0ustar rootroot‰PNG  IHDRóÿabKGD€€€D(“M pHYs  šœtIMEÖ n{H,tEXtCommentCreated with The GIMPïd%nsIDAT8Ë¥“½/ƒQÅ÷õª4¨ ADL%e!Õ˜ÚØD ‰Iˆ&ÿ€ÁÇ‚Åd"+‰4ÒÙ(eCƒP©jªÕÞkÑ[o?hâl÷$çÜç9÷(EyˆbÂ,:\C¤»zˆÕ·Ððò€¼¹$q}¥”ÌYŒ~¨~ÿ0žÉî3Š»D ’iìî>\ýƒ4™ÙÙ$~Uy#/ö ..aÚlTB­Žñ•-ݽzM ©¹…©ù¤ª¨×·M¯n`Ô˜šS³s˜æ7!J…ySù}¶ÛjqŒ(Àçõj÷j øF‚…©ÚõÚ½ì躀»£ÝÊU3,2ÔºØkü× Ê]½¸‹H¤$°¿piq|°O6›­:ÄTæ“hø@/ÏOííþšúÏ ×—‘¹¬å+‹ó³J¼'ñLÎT|…\&ÍÉöñÛ¨îƒ(j£.ÓGg7Î6K™Þ®/AJK™Äëü}Yz2c<~IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/radio.png0000644000000000000000000000030511130023047023542 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ=˜£htEXtCommentCreated with The GIMPïd%n)IDAT8Ëc`4ÿ¡'`$ ™ ZF"5ãTÏD©)öÅ8 ¨k:.=ßÝIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/check.png0000644000000000000000000000031511130023047023522 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÕ4x@’ÙtEXtCommentCreated with The GIMPïd%n5IDAT(Ïc` #øÇˆ"€…Lj¦‡]1#K1(JD™¹+8ò?þ€¢¦O¨ sÃIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/slider.bar.normal.tga0000644000000000000000000000133111130023047025747 0ustar rootroot  („ÿ„‚ÿ”””ÿÝÝÝÿùùùÿ‰ÿÿÿÿùùùÿÝÝÝÿ”””ÿÿ‚ÿ¿¿¿ÿøøøÿúúúÿøøøÿ¿¿¿ÿÿÿ´´´ÿ‘ðððÿ´´´ÿÿ€ŠŠŠÿáááÿ‘ãããÿáááÿŠŠŠÿ€ÿªªªÿ“ÒÒÒÿªªªÿ€ÿÿ°°°ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ±±±ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿªªªÿ»»»ÿºººÿŒ»»»ÿºººÿ‚»»»ÿªªªÿ€ÿÿ™™™ÿ“ËËËÿ™™™ÿ€ÿ€€€ÿÔÔÔÿ‘ØØØÿÔÔÔÿ€€€ÿ€ÿ•••ÿ‘åååÿ•••ÿÿ€ÿ™™™ÿëëëÿïïïÿëëëÿ™™™ÿÿ‚ÿÿ³³³ÿâââÿ‰ôôôÿâââÿ³³³ÿÿÿ‚„ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dot.down.png0000644000000000000000000000104511130023047024202 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ&~S-stEXtCommentCreated with The GIMPïd%n‰IDAT8Ë¥“;,ÃQÆ÷ŸÏ‰x$ˆ#1x³U"Dl»`&›ALlÒÉ`0• H<"1P<IEú Úþ=†zU[iã[ÎÍ99ß9ç;÷(bCâøÕo‡ñ;±¨¸D¦ç8¹qb¾¼b¾¼rrãdz~¢âùƒéÇGÎÜOræ~’ O¤uÜy¤{`8‚ä³%iíéghf–D07>Êβ @)€¬ìÙ8@§¦Å ôá>›XÛ›x|ð* H©¥ƒË@~E©¥ƒÓ›h_e^ÿ‡ü‚Šû+ž[aV5Š p]P^I!¿<î¨IAäÝ^‘YÓ‚(…’è5KX눘ïÒÁý'ÁÛþ&e–¶¤*Û·¿:Pî½-)Ô’žñC¿€¡Â¾ßÁ€ŸÝýíïHnu#‹ë U·öuâ:>Œ ÂÚf&–VÉLK™è3Ÿ™êíÂydyXbh-õƒc2i?—5WPÖ\A™´ŸKýà˜ZG“úï9¿싪±?›bIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/list.png0000644000000000000000000000020111130023047023412 0ustar rootroot‰PNG  IHDR„ž„HIDAT8íÔ± @!EÑ‹‹Á*LÆ*lƯLŒ•ÄîÇ[¿S‚TfV4ËLU-€ˆ8†îÀèÂu?Zjëá‡ç‰6÷ró >8‘Øîê¼IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/down.png0000644000000000000000000000031211130023047023411 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ 4y»çtEXtCommentCreated with The GIMPïd%n2IDAT(Ïc`€JÿÇ%ÇçþÇ®•Iè?“Q ”0âvÓ¬®aÀj ÙP¿ Ò'¢dIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.arrow.normal.tga0000644000000000000000000000055311130023047026337 0ustar rootroot  (–@@@ÿ€@@@–ÿÿÿÿ€@@@ÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ–ïæ¿ÿ€@@@ÿçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ–àÏ€ÿ€@@@ÿ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ–àÌpÿ€@@@ÿ’çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ–ïá¡ÿ€@@@ÿ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ–ÿ÷Ñÿ€@@@ÿ–@@@ÿ€@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/button.hover.tga0000644000000000000000000000141011130023047025066 0ustar rootroot  („@@@@@@ÿ„@@@‚@@@@@@ÿVUTÿ¹¶§ÿîëÞÿ‰ýüùÿîëÞÿ¹¶§ÿVUTÿ@@@ÿ‚@@@@@@@@@ÿ‹ÿóïÛÿ÷óßÿˆ÷óáÿ÷óßÿ÷óáÿ÷óßÿóïÛÿ‹ÿ@@@ÿ@@@@@@@@@ÿ‚rÿ‘ïæ¿ÿ‚rÿ@@@ÿ€@@@@@@KKKÿáÕÿ‚çÚŸÿŒçÛ¡ÿçÚŸÿçÛ¡ÿáÕÿKKKÿ€@@@@@@ÿ„~bÿ“àÏ€ÿ„~bÿ€@@@ÿ@@@ÿ¬Zÿ“×Âaÿ­Ÿ[ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ“з@ÿÆ®@ÿ€@@@ÿ@@@ÿªšPÿ×ÁYÿ×ÀWÿŒ×ÁYÿ×ÀWÿ‚×ÁYÿªšPÿ€@@@ÿ@@@ÿvoNÿ“àÌpÿvoNÿ€@@@ÿ@@@BB@ÿàЄÿçÖ‡ÿ‚çÖ‰ÿˆçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿàЄÿCBAÿ€@@@@@@@@@ÿgcOÿ‘ïá¡ÿgcOÿ@@@ÿ€@@@@@@@@@ÿlgRÿòæ°ÿŠ÷ì¹ÿ÷ë·ÿ÷ì¹ÿòæ°ÿlgRÿ@@@ÿ@@@‚@@@@@@ÿDCBÿ“ŒiÿàÕ ÿ‰ûòÇÿàÕ ÿ“ŒiÿDCBÿ@@@ÿ‚@@@„@@@@@@ÿ„@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/up.png0000644000000000000000000000030311130023047023066 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ ”šœ–tEXtCommentCreated with The GIMPïd%n+IDAT(Ïc` 7øÏð¿4F0b5‚»‚ÿØ42ât#ªlîcd6¢r \¬IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/desktop.png0000644000000000000000000000026511130023047024122 0ustar rootroot‰PNG  IHDRoª¯ pHYs  šœtIMEÕC}k2tEXtCommentCreated with The GIMPïd%n+IDAT8Ëcüÿÿ?5•Ë?—‹GÃh4ŒFÃh4ŒFÃhÈ„Ãa#•ßžÔ†IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/listitem.normal.tga0000644000000000000000000000442211130023047025560 0ustar rootroot $ÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿËËËÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/hslider.tga0000644000000000000000000000231711130023047024072 0ustar rootroot  (‚€€€ÿÿÿ£££ÿªªªÿˆ®®®ÿ°°°ÿ®®®ÿªªªÿ‚ÿÿÿ€€€€€€ÿÿÿ£££ÿ®®®ÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿ¼¼¼ÿ®®®ÿÿÿÿ€€€€€€€ÿÿÿ£££ÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿµµµÿÿÿÿÿÿÿ£££ÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿµµµÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿ£££ÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€¼¼¼ÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿ°°°ÿÎÎÎÿéééÿùùùÿýýýÿŠþþþÿÿÿÿÿ‚þþþÿýýýÿùùùÿéééÿ€ÎÎÎÿ®®®ÿÍÍÍÿçççÿøøøÿýýýÿŽþþþÿýýýÿøøøÿçççÿ€ÍÍÍÿªªªÿÅÅÅÿáááÿôôôÿüüüÿŽþþþÿüüüÿôôôÿáááÿ€ÅÅÅÿÿÿÿ¼¼¼ÿ×××ÿíííÿùùùÿýýýÿŒþþþÿýýýÿùùùÿíííÿ×××ÿ€ÿÿÿÿÿÿ®®®ÿÆÆÆÿÞÞÞÿðððÿùùùÿüüüÿŠýýýÿüüüÿùùùÿðððÿÞÞÞÿÆÆÆÿ€ÿÿÿÿÿÿµµµÿÍÍÍÿÞÞÞÿíííÿôôôÿˆøøøÿùùùÿøøøÿôôôÿíííÿÞÞÞÿÍÍÍÿÿÿÿ€€€ÿÿÿµµµÿÆÆÆÿ×××ÿáááÿˆçççÿéééÿçççÿáááÿ×××ÿÆÆÆÿ‚ÿÿÿ€€€‚ÿÿÿ¼¼¼ÿÅÅÅÿˆÍÍÍÿÎÎÎÿÍÍÍÿÅÅÅÿƒÿÿÿ€€€€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dialog.close.hover.tga0000644000000000000000000000123411130023047026122 0ustar rootroot  („…???ÿ„‚???ÿSSTÿ¥¥¸ÿÜÜíÿøøüÿÜÜíÿ¥¥¸ÿSSTÿ???ÿ‚???ÿ~~ŒÿÙÙòÿÞÞöÿßßöÿÞÞöÿßßöÿÞÞöÿÙÙòÿ~~Œÿ???ÿ???ÿqqÿ‰¾¾îÿqqÿ???ÿ€JJJÿ››àÿžžæÿÿƒŸŸæÿÿžžæÿŸŸæÿ››àÿJJJÿ€???ÿaa‚ÿßÿ‚ÿßÿ‚ÿßÿaa‚ÿ€???ÿ???ÿYY«ÿ‚__Öÿ…ÿ‚__ÖÿYY¬ÿ€???ÿ???ÿ??Åÿƒ??Ïÿƒÿƒ??Ïÿ??Åÿ€???ÿ???ÿ??Åÿƒ??Ïÿƒÿƒ??Ïÿ??Åÿ€???ÿ???ÿOO©ÿWWÖÿVVÖÿWWÖÿ…ÿ‚WWÖÿOO©ÿ€???ÿ???ÿMMuÿooßÿ‚ÿooßÿ‚ÿooßÿMMuÿ€???ÿ??Aÿ‚‚ßÿ††æÿ‡‡æÿÿ‡‡æÿ††æÿ‡‡æÿ††æÿÿ‡‡æÿ††æÿ‚‚ßÿ@@Aÿ€???ÿMMfÿ‰ŸŸîÿMMfÿ???ÿ€???ÿQQkÿ¯¯ñÿ‚··öÿ¶¶öÿ··öÿ¯¯ñÿQQjÿ???ÿ‚???ÿAABÿhh’ÿŸŸßÿÅÅúÿŸŸßÿhh’ÿAABÿ???ÿ‚„…???ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/left.png0000644000000000000000000000032111130023047023374 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ tOuˆtEXtCommentCreated with The GIMPïd%n9IDAT(Ïc`ð™Ã„_SÁtõLø¥á þãÆæì þ300bSÀˆÕ‘Œ¸­`$9 èùl ¦’IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/sbox.normal.png0000644000000000000000000000035011130023047024706 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ =L‚åtEXtCommentCreated with The GIMPïd%nPIDAT(Ï¥Ñ1„P Ñ ·þ¹4bB¦¤".˜úÉC£Š×ªêJ¸èJ88ø;° ˆ@ØÚ… SÂú,ü˜È„»ûÞ30 ùIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/idot.normal.png0000644000000000000000000000063011130023047024673 0ustar rootroot‰PNG  IHDRµú7êbKGD€G5  pHYs  šœtIMEÖ  &Pw6tEXtCommentCreated with The GIMPïd%nIDAT(ÏmÑMŠqð_ýÓ¦“Œ(…(Þb–s„ì\Ìy’œÅœÁÇB`hg|Ñéra´3`­¼÷¨zõb–Ød­Rô:kÄ K›¼óÎÔDHG/¾k±²´É¹Fcf¬èíµZ‹ Ò&ç>j¼W«„Ô9yÖÚZDÅFcnj$@åNˆ¯ùÉg¼U]iH_v~(µ©™úŸûÏ„‘ÚÌT©LŒ_¹ÿJ*c¥冾EE(½ÔË›íê¥Ò9:ënˆá̳£ò{'—W’tq²÷/×ÃÒÅÁ³‘ø–ÿÿä}PÖXÄÖÖΓÖO­';[÷ah¾çÐæÃ5íÚol^ae¢³ÂIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/desktop.xcf0000644000000000000000000000366711130023047024127 0ustar rootrootgimp xcf fileBœBœ/ gimp-commentCreated with The GIMPS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) 5†b¤Empty Layer#2@      ³Ç×@@@1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ 5ÿEmpty Layer#1ÿ     ßó@@@þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿûÿÿþÿþÿþÿÿ ÿ ÿ Empty Layer      .BR@@@@ÿBackground copyÿ     "2þÿÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷þÿÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷þÿÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷Èÿþÿÿÿÿÿ ÿ Backgroundÿ     K_o/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷/ÿ/÷python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/button.normal.tga0000644000000000000000000000133111130023047025235 0ustar rootroot  („ÿ„‚ÿ”””ÿÝÝÝÿùùùÿ‰ÿÿÿÿùùùÿÝÝÝÿ”””ÿÿ‚ÿ¿¿¿ÿøøøÿúúúÿøøøÿ¿¿¿ÿÿÿ´´´ÿ‘ðððÿ´´´ÿÿ€ŠŠŠÿáááÿ‘ãããÿáááÿŠŠŠÿ€ÿªªªÿ“ÒÒÒÿªªªÿ€ÿÿ°°°ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ±±±ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿªªªÿ»»»ÿºººÿŒ»»»ÿºººÿ‚»»»ÿªªªÿ€ÿÿ™™™ÿ“ËËËÿ™™™ÿ€ÿ€€€ÿÔÔÔÿ‘ØØØÿÔÔÔÿ€€€ÿ€ÿ•••ÿ‘åååÿ•••ÿÿ€ÿ™™™ÿëëëÿïïïÿëëëÿ™™™ÿÿ‚ÿÿ³³³ÿâââÿ‰ôôôÿâââÿ³³³ÿÿÿ‚„ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/console.png0000644000000000000000000000034011130023047024105 0ustar rootroot‰PNG  IHDRàw=ø§IDATH‰í–1à ^†ü±»û˜µŸrëM[&‰"lK)‰æŠ¸fI’p$"Úá˜Y:ÎÒ^PƒK)=ù Ùˆ^‚ˆP >+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.selected.hover.tga0000644000000000000000000000052211130023047026624 0ustar rootroot  (@@@–@@@ÿ@@@ÿ–ÿÿÿÿ@@@ÿ÷óáÿ÷óßÿ÷óáÿ‘÷óßÿ@@@ÿ–ïæ¿ÿ@@@ÿ…çÛ¡ÿçÚŸÿ@@@ÿ–àÏ€ÿ@@@ÿ‚×Âaÿ×Â_ÿ×Âaÿ×Â_ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ–з@ÿ@@@ÿ×ÁYÿ×ÀWÿ“×ÁYÿ@@@ÿ–àÌpÿ@@@ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿ@@@ÿ–ïá¡ÿ@@@ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿ’÷ë·ÿ@@@ÿ–ÿ÷Ñÿ@@@–@@@ÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/console.input.focus.png0000644000000000000000000000034011130023047026361 0ustar rootroot‰PNG  IHDRàw=ø§IDATH‰í–AÂ0 ×Eü£¶ûÇ#rír€šD™Tâ•|±”Ç—µD)w¯›_HU¥ìZÆv¶ˆ?à`" ’03â†G!XÏ÷fÆÕwo5n€VH€œsl%´yvŸ¾øEê>z¡€€€$Tµ{¨ê+Dª(ýY›çÑ‘)ïW…»sYÌ—94õtRÚ…¾´ÎU -î^íúqÒz§xaIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/box.down.png0000644000000000000000000000047011130023047024205 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕl–átEXtCommentCreated with The GIMPïd%nœIDAT8Ë¥“;à DŸªxÆ9B’û_'ŸÖ7 )Q !v#¶X±Å@UÕ¹[ˆ¯”)«FkÛqÑ_¾r€ ÜÓ/ÌÁ;ïN 4ýCaÏF@×Edã+÷'ðHÙí 0ˆpO¨˜Ué2Ñòýš¥ ÜΓëô¥uФÓvß>\æi¼CÞX^¿óh–>¢\ÓŠ2IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/hslider.bar.normal.tga0000644000000000000000000000133111130023047026117 0ustar rootroot  („ÿ„‚ÿ”””ÿÝÝÝÿùùùÿ‰ÿÿÿÿùùùÿÝÝÝÿ”””ÿÿ‚ÿ¿¿¿ÿøøøÿúúúÿøøøÿ¿¿¿ÿÿÿ´´´ÿ‘ðððÿ´´´ÿÿ€ŠŠŠÿáááÿ‘ãããÿáááÿŠŠŠÿ€ÿªªªÿ“ÒÒÒÿªªªÿ€ÿÿ°°°ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ¿¿¿ÿÀÀÀÿ±±±ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿ§§§ÿ“ªªªÿ§§§ÿ€ÿÿªªªÿ»»»ÿºººÿŒ»»»ÿºººÿ‚»»»ÿªªªÿ€ÿÿ™™™ÿ“ËËËÿ™™™ÿ€ÿ€€€ÿÔÔÔÿ‘ØØØÿÔÔÔÿ€€€ÿ€ÿ•••ÿ‘åååÿ•••ÿÿ€ÿ™™™ÿëëëÿïïïÿëëëÿ™™™ÿÿ‚ÿÿ³³³ÿâââÿ‰ôôôÿâââÿ³³³ÿÿÿ‚„ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/hslider.right.tga0000644000000000000000000000056411130023047025210 0ustar rootroot  (þþþ~~~ÿ€þþþ~~~ÿþþþÿ€~~~ÿ~~~ÿûûûÿ€~~~ÿ~~~ÿ„öööÿÿ‡öööÿ€~~~ÿ~~~ÿ„ïïïÿÿ†ïïïÿ€~~~ÿ~~~ÿ„çççÿ‚ÿ…çççÿ€~~~ÿ~~~ÿ‚ÞÞÞÿÝÝÝÿƒÿÝÝÝÿÞÞÞÿ‚ÝÝÝÿ€~~~ÿ~~~ÿ„ÓÓÓÿ„ÿƒÓÓÓÿ€~~~ÿ~~~ÿ„ÓÓÓÿ„ÿƒÓÓÓÿ€~~~ÿ~~~ÿ„ÛÛÛÿƒÿ„ÛÛÛÿ€~~~ÿ~~~ÿ„ãããÿ‚ÿ…ãããÿ€~~~ÿ~~~ÿ„êêêÿÿ†êêêÿ€~~~ÿ~~~ÿ„ðððÿÿ‡ðððÿ€~~~ÿ~~~ÿõõõÿ€~~~ÿ~~~ÿùùùÿ€~~~ÿþþþ~~~ÿ€þþþpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vsbox.normal.png0000644000000000000000000000034011130023047025073 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ  û’tEXtCommentCreated with The GIMPïd%nHIDAT(ϵ‘A €0gEëþº¹øå¢HY_ ‹•æ<$0±¨¯‘¬†èÜ\œ4à8;…•ƒ…$ßË€øÝÀü‰˜ïaHµew?¬ž™Dl%¼IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/listitem.down.tga0000644000000000000000000000426211130023047025241 0ustar rootroot $ôïÖÿôîÔÿôîÔÿôïÖÿôïÖÿôîÔÿôîÔÿôïÖÿôîÔÿôîÔÿôïÖÿôïÖÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôîÔÿôïÖÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿêߪÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿßÎÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿÕ¾UÿË®+ÿË®+ÿË®+ÿÊ®*ÿÊ®*ÿË®+ÿÊ®*ÿË®+ÿË®+ÿË®+ÿÊ®*ÿÊ®*ÿË®+ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿÊ®*ÿË®+ÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿÀžÿʬ ÿË­ÿË­ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿʬ ÿË­ÿʬ ÿË­ÿË­ÿʬ ÿʬ ÿʬ ÿʬ ÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿÕ»AÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÉaÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿßÉaÿßÈ_ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿê×€ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿôå ÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿÿôÁÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/right.png0000644000000000000000000000031611130023047023563 0ustar rootroot‰PNG  IHDRµú7êbKGDÿ‡Ì¿ pHYs  šœtIMEÖ Ž@HëtEXtCommentCreated with The GIMPïd%n6IDAT(Ïc` 3ø)ÄDH !S˜°[ô¯†ÿŒp%L„Ü͈Õ~Fün`ÄïHFŠ[ OïtIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/radio.off.hover.tga0000644000000000000000000000110611130023047025424 0ustar rootroot  („@@@…@@@ÿ„@@@‚@@@@@@ÿVUTÿ¹¶§ÿîëÞÿýüùÿîëÞÿ¹¶§ÿVUTÿ@@@ÿ‚@@@@@@@@@ÿ‹ÿóïÛÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿóïÛÿ‹ÿ@@@ÿ@@@@@@@@@ÿ‚rÿ‰ïæ¿ÿ‚rÿ@@@ÿ€@@@@@@KKKÿáÕÿ‚çÚŸÿ„çÛ¡ÿçÚŸÿçÛ¡ÿáÕÿKKKÿ€@@@@@@ÿ„~bÿ‹àÏ€ÿ„~bÿ€@@@ÿ@@@ÿ¬Zÿ‹×Âaÿ­Ÿ[ÿ€@@@ÿ@@@ÿÆ®@ÿ‹Ð·@ÿÆ®@ÿ€@@@ÿ@@@ÿÆ®@ÿ‹Ð·@ÿÆ®@ÿ€@@@ÿ@@@ÿªšPÿ×ÁYÿ×ÀWÿ„×ÁYÿ×ÀWÿ‚×ÁYÿªšPÿ€@@@ÿ@@@ÿvoNÿ‹àÌpÿvoNÿ€@@@ÿ@@@BB@ÿàЄÿçÖ‡ÿ‚çÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿàЄÿCBAÿ€@@@@@@@@@ÿgcOÿ‰ïá¡ÿgcOÿ@@@ÿ€@@@@@@@@@ÿlgRÿòæ°ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿòæ°ÿlgRÿ@@@ÿ@@@‚@@@@@@ÿDCBÿ“ŒiÿàÕ ÿûòÇÿàÕ ÿ“ŒiÿDCBÿ@@@ÿ‚@@@„@@@…@@@ÿ„@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/menu.normal.tga0000644000000000000000000000011611130023047024666 0ustar rootroot (‹ÿÿÿÿ‹ÿÿÿÿ‹÷÷÷ÿ‹÷÷÷ÿ‹ÿÿÿÿ‹ÿÿÿÿ‹÷÷÷ÿ‹÷÷÷ÿ‹ÿÿÿÿ‹ÿÿÿÿ‹÷÷÷ÿ‹÷÷÷ÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/listitem.hover.tga0000644000000000000000000000426211130023047025415 0ustar rootroot $÷óßÿ÷óßÿ÷óáÿ÷óáÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿ÷óáÿ÷óáÿ÷óßÿ÷óßÿ÷óßÿ÷óßÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿïæ¿ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÚŸÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÛ¡ÿçÚŸÿçÚŸÿçÚŸÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿàÏ€ÿ×Âaÿ×Âaÿ×Â_ÿ×Â_ÿ×Âaÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Â_ÿ×Âaÿ×Âaÿ×Â_ÿ×Â_ÿ×Âaÿ×Â_ÿ×Â_ÿ×Â_ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿз@ÿ×ÀWÿ×ÀWÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÀWÿ×ÀWÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿ×ÁYÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿàÌpÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‰ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‰ÿçÖ‡ÿçÖ‡ÿçÖ‡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿïá¡ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿ÷ë·ÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿÿ÷Ñÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/list.item.down.png0000644000000000000000000000027611130023047025331 0ustar rootroot‰PNG  IHDRoª¯bKGDÿÿÿ ½§“ pHYs  šœtIMEÕ)ïvŸtEXtCommentCreated with The GIMPïd%n"IDAT8Ëc<òõ?5•À¨A£4jШA£‘AÊè)£ðNIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/progressbar.bar.tga0000644000000000000000000000106311130023047025531 0ustar rootroot  (@@@•@@@ÿ€@@@@@@ÿ•ÿÿÿÿ€@@@ÿ@@@ÿ÷óáÿ÷óßÿ÷óáÿ‰÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ@@@ÿ•ïæ¿ÿ€@@@ÿ@@@ÿ…çÛ¡ÿˆçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ@@@ÿ•àÏ€ÿ€@@@ÿ@@@ÿ‚×Âaÿ×Â_ÿ×Âaÿˆ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ•з@ÿ€@@@ÿ@@@ÿ×ÁYÿ×ÀWÿ‹×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ@@@ÿ•àÌpÿ€@@@ÿ@@@ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿçÖ‡ÿçÖ‰ÿ‹çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ@@@ÿ•ïá¡ÿ€@@@ÿ@@@ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ÷ì¹ÿŠ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ@@@ÿ•ÿ÷Ñÿ€@@@ÿ@@@•@@@ÿ€@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dialog.png0000644000000000000000000000050211130023047023702 0ustar rootroot‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIMEÕõîºrtEXtCommentCreated with The GIMPïd%n¦IDATHÇí–1à EB¹SĘ8j&¶Lˆ‰ E^èЦ"­:¤NxÅzÆÿß (t, BèwÎ=ˆó<7…§”¸Ñ¹4€1†išš‚1Ü@Dض­)XD†ÃáÁðà´ëº6Ë„= ö ”÷¾ùÏŸL¥kÍrÎXk/cŒ/ýTõVêl>;(ÆxÈâ­Þú À²,Wd9pÕ—Þ_O™Þ1@ø‹ "IEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dot.xcf0000644000000000000000000000361211130023047023232 0ustar rootrootgimp xcf fileBB/ gimp-commentCreated with The GIMPS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) ýqá{Empty Layer#3ÿ     §»Ë‘ ÿ ÿ ÿ ÿ ÿÿ‘ À À À À ÀÀ‘ À À À À ÀÀ‘ü+*++*+ûU Uùw€€÷€€wþªªþý!ÆÕÕÔüÕÆ ÷I«ïï«IEmpty Layer#2ÿ     /?ÿ ÿ ÿ ÿ ÿ ÿ‘ÿ ÿ ÿ ÿ ÿ ÿ‘ÿ ÿ ÿ ÿ ÿ ÿ‘÷ˆÑ÷÷шõTÍÔÔÕÔÕÔÍTþCªªþCý{€ø€{-U Uø-"++*++*ý+# Empty Layerÿ     ‰­À À À À À À À À À À À À ÀÀ÷I«ïï«Iý'íÿÿýí'þ'ÿÿþ'ýíÿÿúíIÿ ÿûI«ÿ ÿû«ïÿ ÿûïïÿ ÿûï«ÿ ÿû«Iÿ ÿúIíÿÿýíþ'ÿÿþ'ý'íÿÿýí'÷I«ïï«I Backgroundÿ     *>Nÿ ÿ ÿ ÿ ÿþÿ^ÿþÿ ÿ ÿ ÿ ÿÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/filebrowser.folder.png0000644000000000000000000000117211130023047026244 0ustar rootroot‰PNG  IHDR/Ä<ðAIDAT8­ÔMKTQÀñÿÔ” M3ˆƒ‹Ç[HM‚/©Ì,Ú"—ÑÊe´ û~‚hш¢¸pÛÜ)ÂÊD-,˲73|IÆÇ;sï9çi¡CZ£nzàð8çüx8o>ᆿұm[²Ù,¶m³ð~ßÑì§ã•1*c¹\ŽL&C<÷U}"B:–Çc÷H´’èl¥ùtÙWŸ¸4x—Þö(½íQ.^h¦+ÖDvbžö###ûƒÃÃÃÒ×ÙF_ÓO”2h­PJã¹ ÏS(Oá)ç)Ê®¢ÿæCüÇëH¥RX–µöƒAž<Ÿ%<†ëþ”= ùÊÔG œŠ2a_aîÍ ²33X–õïÆãql;C¡ä'¿þ §èPÜ,s"%ÐØBk[=õ଀³ ’ãÑä$ÁpLJµ צ¹£{(.‚³ ²„¬-b Æ2ão¹uçzu0™LúÉçòœéì'Tz¬|#ˆŒÖh£·³V­™žûVYW½B§¸ÅÉZ…·áb´Æh…6JVZs¤&XíwƒBm Ï-SÚÌcŒBë]UíÀZkÖsE"‘Èa 44ÅØZ™§TÌï©ÊSŠrÙÅqÊÌ.¬2öì#‘H÷á`aí;u…|npy9ûƒw_Ö˜þ°Ì×5Ž®7ªz±D„øù˜8ùE¹wûª ^>+çZ …IJ,I¥R255%•¹5_åsH§Ó2::J("‘HL&÷}¯Åo{T{.wTºIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/dialog.close.down.tga0000644000000000000000000000124511130023047025750 0ustar rootroot  („…ÿ„‚ÿÿ‡‡ ÿÐÐçÿööûÿÐÐçÿ‡‡ ÿÿÿ‚ÿSSfÿÌÌîÿÓÓóÿÔÔóÿÓÓóÿÔÔóÿÓÓóÿÌÌîÿSSfÿÿÿBBWÿ‰©©éÿBBWÿÿ€ ÿzzÖÿ~~ÞÿÿƒÞÿÿ~~ÞÿÞÿzzÖÿ ÿ€ÿ,,XÿTTÔÿ‚ÿTTÔÿ‚ÿTTÔÿ,,Xÿ€ÿÿ!!ÿ**Éÿ))Éÿ…ÿ))Éÿ**Éÿ""ÿ€ÿÿ²ÿƒ¿ÿƒÿƒ¿ÿ²ÿ€ÿÿ²ÿƒ¿ÿƒÿƒ¿ÿ²ÿ€ÿÿÿÉÿÉÿÉÿ…ÿ‚ÉÿŒÿ€ÿÿGÿ??Ôÿ‚ÿ??Ôÿ‚ÿ??ÔÿGÿ€ÿÿXXÔÿ^^Þÿ__Þÿÿ__Þÿ^^Þÿ__Þÿ^^Þÿÿ__Þÿ^^ÞÿXXÔÿÿ€ÿ3ÿ‰éÿ3ÿÿ€ÿ9ÿ””ìÿ‚ŸŸóÿžžóÿŸŸóÿ””ìÿ8ÿÿ‚ÿÿ55nÿÔÿ²²ùÿÔÿ55nÿÿÿ‚„…ÿ„python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/box.xcf0000644000000000000000000000372411130023047023240 0ustar rootrootgimp xcf fileBB/ gimp-commentCreated with The GIMPS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) oÎEmpty Layer#2ÿ     ³Çב ÿ ÿ ÿ ÿ ÿ ÿ‘ À À À À À À‘ À À À À À À‘ü+**++*ø+**++U Uù€€€€€ ªûÔÕÔÕÔÔÕùÔÕÔÔÿ ÿEmpty Layer#1ÿ     -= ÿ ÿ ÿ ÿ ÿ ÿ‘ ÿ ÿ ÿ ÿ ÿ ÿ‘ ÿ ÿ ÿ ÿ ÿ ÿ‘ ÿïÕÔÔÕÕÔÔÕÔÕÕÔÕÔª ª€ü€€ U+*ù+*++*+**‘ Empty Layerÿ     vŠš À À À À À À À À À À À À À À ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ Backgroundÿ     ½Ñáþÿ ÿþÿßÿþÿ ÿSelection Mask vŠš ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿpython-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/select.arrow.hover.tga0000644000000000000000000000055311130023047026172 0ustar rootroot  (–@@@ÿ€@@@–ÿÿÿÿ€@@@ÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ÷óáÿ÷óßÿ€@@@ÿ–ïæ¿ÿ€@@@ÿçÚŸÿçÛ¡ÿ„çÚŸÿ€@@@ÿ–àÏ€ÿ€@@@ÿ×Â_ÿ×Âaÿ×Â_ÿ×Âaÿ‚×Â_ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ–з@ÿ€@@@ÿ×ÁYÿ×ÀWÿ×ÁYÿ×ÀWÿ×ÁYÿ€@@@ÿ–àÌpÿ€@@@ÿ’çÖ‡ÿçÖ‰ÿçÖ‡ÿ€@@@ÿ–ïá¡ÿ€@@@ÿ÷ë·ÿ‚÷ì¹ÿ÷ë·ÿ÷ì¹ÿ÷ë·ÿ€@@@ÿ–ÿ÷Ñÿ€@@@ÿ–@@@ÿ€@@@python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/menu.down.tga0000644000000000000000000000102011130023047024340 0ustar rootroot  (•ÿ€ÿ•ÿÿÿÿ€ÿÿôïÖÿôîÔÿôïÖÿ‰ôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿôïÖÿôîÔÿ€ÿÿ•êߪÿ€ÿÿ…ßÎÿˆßÎÿßÎÿ„ßÎÿ€ÿÿ•Õ¾Uÿ€ÿÿ‚Ë®+ÿÊ®*ÿË®+ÿˆÊ®*ÿË®+ÿÊ®*ÿË®+ÿ‚Ê®*ÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿ•Àžÿ€ÿÿʬ ÿË­ÿ‹Ê¬ ÿË­ÿʬ ÿË­ÿʬ ÿ€ÿÿ•Õ»Aÿ€ÿÿßÉaÿßÈ_ÿßÉaÿßÈ_ÿßÉaÿ‹ßÈ_ÿßÉaÿßÈ_ÿ€ÿÿ•ê×€ÿ€ÿÿ•ôå ÿ€ÿÿ•ÿôÁÿ€ÿ•ÿ€python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/box.hover.png0000644000000000000000000000050411130023047024357 0ustar rootroot‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ&¾ »ÜtEXtCommentCreated with The GIMPïd%n¨IDAT8Ë¥“Mƒ „?I­vÝ¿ÓÀɹI›vãÔÔnÀEýA¢Iõy3“ ´Öž´ ðÖÚ¤×Æ¯ÞmA9®áÙE¸ ú àÑô¤ÖOA·Mà+ ¹I$ÁÝER.9$åî’„ ˲tÝø53¹»J)ÝkùI|¾àN†`†`þAI0³ËûÀ̶>H©©ÒÓÔÌÛ+³)ýu]1MS—`žgäœß—þ3ëú¶DD³ëé” „)ëIEND®B`‚python-box2d-2.0.2+svn20100109.244/testbed/data/themes/default/vdot.down.png0000644000000000000000000000103411130023047024366 0ustar rootroot‰PNG  IHDRóÿabKGD€€€D(“M pHYs  šœtIMEÖ gÍtEXtCommentCreated with The GIMPïd%n€IDAT8Ë“;,CqÆ÷¦Õ"QƒW‚ ^ ‰ÆÈ "6‚M„0xÅ ¯ÒÄæ1"F›4ÒvÕ. $ .-Õöþ ­Û‡^gúç$ç;ß÷ÿÎ'‘¸„F_ú«!2L™54ã­6s“S @öý%A—ƒ7§ ÆÌEˆÆö.Ìc3\½+\¸½œ»=g¤QbJ'OöÑn^ÎŽÕYù{¸­w€þ¥eR ư†Ÿ*RRÓÚµ’W[¯Ê”ò ™X´  ]r˜ïôÞ²NÇ7€ž[À ×MIŠR'¤Ð[ “J7¨í2@sS“Šžlµt÷EVäf©è ½"F@Mey ã¤$Z"\==ÿÊ Ñ’ÓËëÀ¡ÍÙ’äXw6Uiev ŸßwËÚ”<>N¶×$àáþËäDÜkÛ8ßÑŠÄÚ¾¿µÎÆø߇¦ Ÿï^V;[x 200 5 10 1 0 5 500 1 10 1 0 1 100 0 10 1 0 0 640 480 800 600 True True True True True True True True True True GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK True True True Hertz: GTK_JUSTIFY_RIGHT True True adjustment1 False False 1 False False True False 4 1 True True Position Iterations: True True adjustment2 False False 1 False False 2 True True Velocity Iterations: True True adjustment3 False False 1 False False 3 True False 4 4 True 0 GTK_SHADOW_NONE True 12 True True True Shapes True True True Joints True 1 True True Controllers True 2 True True Core Shapes True 3 True True AABBs True 4 True True OBBs True 5 True True Pairs True 6 True True Center of Masses True 7 True <b>Draw</b> True False False 5 True False 4 6 True True Draw with Antialiasing True False False 7 True False 4 8 True True True True True True gtk-media-play True Play 1 True True True True True gtk-media-pause True Pause 1 1 True True True True True gtk-media-next True Step 1 2 False False 9 True False 4 10 True True True True You can access the "framework" and "world" variables Open Python Console False False 11 False False 4 1 True 2 False 1 python-box2d-2.0.2+svn20100109.244/testbed/pickle_example_web0000644000000000000000000001466511135461416021707 0ustar rootroot(lp1 ccopy_reg _reconstructor p2 (cBox2D.Box2D b2World p3 c__builtin__ object p4 NtRp5 (dp6 S'worldAABB' p7 g2 (cBox2D.Box2D b2AABB p8 g4 NtRp9 (dp10 S'lowerBound' p11 g2 (cBox2D.Box2D b2Vec2 p12 g4 NtRp13 (dp14 S'y' F-100 sS'x' F-200 sbsS'upperBound' p15 g2 (g12 g4 NtRp16 (dp17 S'y' F200 sS'x' F200 sbsbsS'bodyList' p18 (lp19 g2 (cBox2D.Box2D b2Body p20 g4 NtRp21 (dp22 S'isBullet' p23 I00 sS'massData' p24 g2 (cBox2D.Box2D b2MassData p25 g4 NtRp26 (dp27 S'I' F0 sS'mass' p28 F0 sS'center' p29 g2 (g12 g4 NtRp30 (dp31 S'y' F0 sS'x' F0 sbsbsS'angle' p32 F0 sS'fixedRotation' p33 I00 sS'linearDamping' p34 F0 sS'userData' p35 NsS'allowSleep' p36 I01 sS'angularVelocity' p37 F0 sS'shapeList' p38 (lp39 g2 (cBox2D.Box2D b2PolygonShape p40 g4 NtRp41 (dp42 g35 NsS'density' p43 F0 sS'isSensor' p44 I00 sS'vertices' p45 (lp46 (F-50 F-10 tp47 a(F50 F-10 tp48 a(F50 F10 tp49 a(F-50 F10 tp50 asS'friction' p51 F0.20000000298023224 sS'filter' p52 g2 (cBox2D.Box2D b2FilterData p53 g4 NtRp54 (dp55 S'maskBits' p56 I65535 sS'groupIndex' p57 I0 sS'categoryBits' p58 I1 sbsS'restitution' p59 F0 sbasS'isSleeping' p60 I00 sS'angularDamping' p61 F0 sS'position' p62 g2 (g12 g4 NtRp63 (dp64 S'y' F-10 sS'x' F0 sbsS'linearVelocity' p65 g2 (g12 g4 NtRp66 (dp67 S'y' F0 sS'x' F0 sbsbag2 (g20 g4 NtRp68 (dp69 g23 I00 sg24 g2 (g25 g4 NtRp70 (dp71 S'I' F0.83333337306976318 sg28 F5 sg29 g2 (g12 g4 NtRp72 (dp73 S'y' F0 sS'x' F0 sbsbsg32 F0.13723009824752808 sg33 I00 sg34 F0 sg35 Nsg36 I01 sg37 F1.0670644044876099 sg38 (lp74 g2 (g40 g4 NtRp75 (dp76 g35 Nsg43 F5 sg44 I00 sg45 (lp77 (F-0.5 F-0.5 tp78 a(F0.5 F-0.5 tp79 a(F0.5 F0.5 tp80 a(F-0.5 F0.5 tp81 asg51 F0.20000000298023224 sg52 g2 (g53 g4 NtRp82 (dp83 g56 I65535 sg57 I0 sg58 I1 sbsg59 F0 sbasg60 I00 sg61 F0 sg62 g2 (g12 g4 NtRp84 (dp85 S'y' F4.9506378173828125 sS'x' F-4.9847636222839355 sbsg65 g2 (g12 g4 NtRp86 (dp87 S'y' F-0.051486153155565262 sS'x' F0.0037257550284266472 sbsbag2 (g20 g4 NtRp88 (dp89 g23 I00 sg24 g2 (g25 g4 NtRp90 (dp91 S'I' F0.83333337306976318 sg28 F5 sg29 g2 (g12 g4 NtRp92 (dp93 S'y' F0 sS'x' F0 sbsbsg32 F-0.13723026216030121 sg33 I00 sg34 F0 sg35 Nsg36 I01 sg37 F-1.0670629739761353 sg38 (lp94 g2 (g40 g4 NtRp95 (dp96 g35 Nsg43 F5 sg44 I00 sg45 (lp97 (F-0.5 F-0.5 tp98 a(F0.5 F-0.5 tp99 a(F0.5 F0.5 tp100 a(F-0.5 F0.5 tp101 asg51 F0.20000000298023224 sg52 g2 (g53 g4 NtRp102 (dp103 g56 I65535 sg57 I0 sg58 I1 sbsg59 F0 sbasg60 I00 sg61 F0 sg62 g2 (g12 g4 NtRp104 (dp105 S'y' F4.9506373405456543 sS'x' F4.9847636222839355 sbsg65 g2 (g12 g4 NtRp106 (dp107 S'y' F-0.051486458629369736 sS'x' F-0.0037254334893077612 sbsbag2 (g20 g4 NtRp108 (dp109 g23 I00 sg24 g2 (g25 g4 NtRp110 (dp111 S'I' F0.83333337306976318 sg28 F5 sg29 g2 (g12 g4 NtRp112 (dp113 S'y' F0 sS'x' F0 sbsbsg32 F0.008322935551404953 sg33 I00 sg34 F0 sg35 Nsg36 I01 sg37 F-0.043074753135442734 sg38 (lp114 g2 (g40 g4 NtRp115 (dp116 g35 Nsg43 F5 sg44 I00 sg45 (lp117 (F-0.5 F-0.5 tp118 a(F0.5 F-0.5 tp119 a(F0.5 F0.5 tp120 a(F-0.5 F0.5 tp121 asg51 F0.20000000298023224 sg52 g2 (g53 g4 NtRp122 (dp123 g56 I65535 sg57 I0 sg58 I1 sbsg59 F0 sbasg60 I00 sg61 F0 sg62 g2 (g12 g4 NtRp124 (dp125 S'y' F14.951677322387695 sS'x' F5.0156054496765137 sbsg65 g2 (g12 g4 NtRp126 (dp127 S'y' F-0.044206161051988602 sS'x' F0.010378838516771793 sbsbag2 (g20 g4 NtRp128 (dp129 g23 I00 sg24 g2 (g25 g4 NtRp130 (dp131 S'I' F0.83333337306976318 sg28 F5 sg29 g2 (g12 g4 NtRp132 (dp133 S'y' F0 sS'x' F0 sbsbsg32 F-0.0083229467272758484 sg33 I00 sg34 F0 sg35 Nsg36 I01 sg37 F0.043074525892734528 sg38 (lp134 g2 (g40 g4 NtRp135 (dp136 g35 Nsg43 F5 sg44 I00 sg45 (lp137 (F-0.5 F-0.5 tp138 a(F0.5 F-0.5 tp139 a(F0.5 F0.5 tp140 a(F-0.5 F0.5 tp141 asg51 F0.20000000298023224 sg52 g2 (g53 g4 NtRp142 (dp143 g56 I65535 sg57 I0 sg58 I1 sbsg59 F0 sbasg60 I00 sg61 F0 sg62 g2 (g12 g4 NtRp144 (dp145 S'y' F14.951677322387695 sS'x' F-5.0156059265136719 sbsg65 g2 (g12 g4 NtRp146 (dp147 S'y' F-0.044209308922290802 sS'x' F-0.010375554673373699 sbsbasS'gravity' p148 g2 (g12 g4 NtRp149 (dp150 S'y' F-10 sS'x' F0 sbsS'controllerList' p151 (lp152 sS'doSleep' p153 I01 sS'jointList' p154 (lp155 (dp156 g35 NsS'_type' p157 S'Distance' p158 sS'frequencyHz' p159 F4 sS'localAnchor1' p160 g2 (g12 g4 NtRp161 (dp162 S'y' F10 sS'x' F-10 sbsS'localAnchor2' p163 g2 (g12 g4 NtRp164 (dp165 S'y' F-0.5 sS'x' F-0.5 sbsS'collideConnected' p166 I00 sS'length' p167 F6.3639612197875977 sS'dampingRatio' p168 F0.5 sS'body1' p169 I1 sS'body2' p170 I2 sa(dp171 g35 Nsg157 g158 sg159 F4 sg160 g2 (g12 g4 NtRp172 (dp173 S'y' F10 sS'x' F10 sbsg163 g2 (g12 g4 NtRp174 (dp175 S'y' F-0.5 sS'x' F0.5 sbsg166 I00 sg167 F6.3639612197875977 sg168 F0.5 sg169 I1 sg170 I3 sa(dp176 g35 Nsg157 g158 sg159 F4 sg160 g2 (g12 g4 NtRp177 (dp178 S'y' F30 sS'x' F10 sbsg163 g2 (g12 g4 NtRp179 (dp180 S'y' F0.5 sS'x' F0.5 sbsg166 I00 sg167 F6.3639612197875977 sg168 F0.5 sg169 I1 sg170 I4 sa(dp181 g35 Nsg157 g158 sg159 F4 sg160 g2 (g12 g4 NtRp182 (dp183 S'y' F30 sS'x' F-10 sbsg163 g2 (g12 g4 NtRp184 (dp185 S'y' F0.5 sS'x' F-0.5 sbsg166 I00 sg167 F6.3639612197875977 sg168 F0.5 sg169 I1 sg170 I5 sa(dp186 g35 Nsg157 g158 sg159 F4 sg160 g2 (g12 g4 NtRp187 (dp188 S'y' F0 sS'x' F0.5 sbsg163 g2 (g12 g4 NtRp189 (dp190 S'y' F0 sS'x' F-0.5 sbsg166 I00 sg167 F9 sg168 F0.5 sg169 I2 sg170 I3 sa(dp191 g35 Nsg157 g158 sg159 F4 sg160 g2 (g12 g4 NtRp192 (dp193 S'y' F0.5 sS'x' F0 sbsg163 g2 (g12 g4 NtRp194 (dp195 S'y' F-0.5 sS'x' F0 sbsg166 I00 sg167 F9 sg168 F0.5 sg169 I3 sg170 I4 sa(dp196 g35 Nsg157 g158 sg159 F4 sg160 g2 (g12 g4 NtRp197 (dp198 S'y' F0 sS'x' F-0.5 sbsg163 g2 (g12 g4 NtRp199 (dp200 S'y' F0 sS'x' F0.5 sbsg166 I00 sg167 F9 sg168 F0.5 sg169 I4 sg170 I5 sa(dp201 g35 Nsg157 g158 sg159 F4 sg160 g2 (g12 g4 NtRp202 (dp203 S'y' F-0.5 sS'x' F0 sbsg163 g2 (g12 g4 NtRp204 (dp205 S'y' F0.5 sS'x' F0 sbsg166 I00 sg167 F9 sg168 F0.5 sg169 I5 sg170 I2 sasS'groundBody' p206 g2 (g20 g4 NtRp207 (dp208 g23 I00 sg24 g2 (g25 g4 NtRp209 (dp210 S'I' F0 sg28 F0 sg29 g2 (g12 g4 NtRp211 (dp212 S'y' F0 sS'x' F0 sbsbsg32 F0 sg33 I00 sg34 F0 sg35 Nsg36 I01 sg37 F0 sg38 (lp213 sg60 I00 sg61 F0 sg62 g2 (g12 g4 NtRp214 (dp215 S'y' F0 sS'x' F0 sbsg65 g2 (g12 g4 NtRp216 (dp217 S'y' F0 sS'x' F0 sbsbsba(dp218 S'joints' p219 (lp220 (dp221 S'joint' p222 I0 sS'pickle_type' p223 S'b2Joint' p224 sa(dp225 g222 I1 sg223 g224 sa(dp226 g222 I2 sg223 g224 sa(dp227 g222 I3 sg223 g224 sa(dp228 g222 I4 sg223 g224 sa(dp229 g222 I5 sg223 g224 sa(dp230 g222 I6 sg223 g224 sa(dp231 g222 I7 sg223 g224 sasS'bodies' p232 (lp233 (dp234 S'body' p235 I2 sg223 S'b2Body' p236 sa(dp237 g235 I3 sg223 g236 sa(dp238 g235 I4 sg223 g236 sa(dp239 g235 I5 sg223 g236 sasa.python-box2d-2.0.2+svn20100109.244/testbed/test_Bridge.py0000644000000000000000000000576711135471136020755 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Bridge(Framework): name = "Bridge" def __init__(self): super(Bridge, self).__init__() sd = box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd = box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd = box2d.b2PolygonDef() sd.SetAsBox(0.5, 0.125) sd.density = 20.0 sd.friction = 0.2 jd = box2d.b2RevoluteJointDef() numPlanks = 30 prevBody = ground for i in xrange(numPlanks): bd = box2d.b2BodyDef() bd.position = (-14.5 + 1.0 * i, 5.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() anchor=(-15.0 + 1.0 * i, 5.0) jd.Initialize(prevBody, body, anchor) self.world.CreateJoint(jd) prevBody = body anchor = (-15.0 + 1.0 * numPlanks, 5.0) jd.Initialize(prevBody, ground, anchor) self.world.CreateJoint(jd) for i in xrange(2): sd=box2d.b2PolygonDef() sd.vertexCount = 3 sd.setVertex(0,-0.5, 0.0) sd.setVertex(1,0.5, 0.0) sd.setVertex(2,0.0, 1.5) sd.density = 1.0 bd=box2d.b2BodyDef() bd.position = (-8.0 + 8.0 * i, 12.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() for i in xrange(3): sd=box2d.b2CircleDef() sd.radius = 0.5 sd.density = 1.0 bd=box2d.b2BodyDef() bd.position = (-6.0 + 6.0 * i, 10.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() if __name__=="__main__": main(Bridge) python-box2d-2.0.2+svn20100109.244/testbed/TriangleMesh.py0000644000000000000000000010633311132441204021061 0ustar rootroot#!/usr/bin/python # # A lite constrained delauney triangle mesh generator,supporting holes and # non convex boundaries. # (c) 2008 nimodo@hispeed.ch # # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # # Python changelog: # Updated to SVN r168 on 7/25 # Updated to 08.08.2008 version from http://www.box2d.org/forum/viewtopic.php?f=3&t=836 # # ----------------------------------------------------------------------------- # Original comments (ported from the C++ version): # # See # 1) A Delaunay Refinement Algorithm for Quality 2-Dimensional Mesh Generation # Jim Ruppert - Journal of Algorithms, 1995 # 2) Jonathan Shewchuk # http://www.cs.cmu.edu/~quake/triangle.html # 3) Recursive triangle eating # Francois Labelle # http://www.cs.berkeley.edu/~flab/ # 4) example - at the end of this file # # # 2001/03 as part of a basic FEA package # 2008/05 some small changes for box2d # 2008/06 small bugs # tmO_BASICMESH option for testing only, works sometimes ;) # some comments (see .h file) # variable names changed for better understanding, example # - tmO_MINIMALGRID renamed to tmO_GRADING, used option with # gradingLowerAngle # bug in SegmentVertices() # playing with "zero tolerances..." # GetVersion() added # 2008/07 tmO_CHECKINTERSEC (optional) added, see HasIntersections() # alternative to Mesh() added, using tmVertex* instead of tmSegmentId* # malloc() replaced with Alloc() # zlib license added # from math import sin, cos, atan2, sqrt, pow, floor, log from test_main import box2d # errors and warnings tmE_OK =0 tmE_MEM =1 tmE_HOLES =2 tmE_NOINSIDETRIANGLES=3 tmE_INTERSECTS =4 tmE_OPENFILEWT =5 # constants tmC_MAXVERTEXCOUNT =500 tmVERSION =1.004 tmC_ZEROTOL =0.00001 tmC_PI =3.14159265359 tmC_PIx2 =6.28318530718 tmC_PI_3 =1.04719755119 tmC_SQRT2 =1.41421356237 # default big number to calculate a triangle covering all points (vertices[0-2]) tmC_BIGNUMBER =1.0e10 #default maximal number of vertices (resp. nodes) tmC_DEFAULTMAXVERTEX=500 # default abort-inserting if tmO_GRADING option set (angle in deg) tmC_DEFAULTGRADINGLOWERANGLE =30.0 # TriangleMesh.options # automatic segment boundary vertices => SegmentVertices() tmO_SEGMENTBOUNDARY= 2 # hull vertices => ConvexHull() tmO_CONVEXHULL = 4 # abort (=>InsertSegments()), if worst angle > minAngle tmO_MINIMALGRID = 8 # deprecated tmO_GRADING = 8 # turn on intesection check => HasIntersections() tmO_CHECKINTERSECT = 16 # bits for playing... around,debugging and testing, see code tmO_BASICMESH = 64 tmO_NOCALC =128 tmO_BASICMESHNODEL =256 tmO_WRITEINPUT =512 tmErrorMessages = { tmE_OK: "ok", tmE_MEM: "memory allocation failed", tmE_HOLES: "could not drill the holes", tmE_NOINSIDETRIANGLES: "there are no inside triangles,all might be eaten", tmE_INTERSECTS: "intersecting boundary segments found" } class tmVertex(box2d.b2Vec2): # x, y def __init__(self, tuple=(0.0, 0.0)): super(tmVertex, self).__init__() self.x, self.y = tuple def __repr__(self): return "(%f, %f)" % (self.x, self.y) class tmSegment(object): # tmVertex v[2] def __init__(self): self.v = [tmVertex(), tmVertex()] class tmSegmentId(object): # i1, i2 def __init__(self, tuple=(0, 0)): self.i1, self.i2 = tuple class tmEdge(object): def __init__(self): self.v = [None, None] self.locked = False self.t = [None, None] class Triangle(object): minAngle = 0.0 angle = 0.0 inside = False # hold attributes for the triangles, external use only userData = None area = 0.0 def __init__(self): self.v = [None, None, None] self.e = [tmEdge(), tmEdge(), tmEdge()] class TriangleMesh(object): Vertices = [] Edges = [] Triangles = [] Segments = [] gradingLowerAngle = tmC_DEFAULTGRADINGLOWERANGLE maxVertexCount=0 maxEdgeCount=0 maxTriangleCount=0 maxSegmentCount=0 vertexCount=0 inputVertexCount=0 edgeCount=0 triangleCount=0 segmentCount=0 holeCount=0 insideTriangleCount=0 haveEnoughVertices=False options=0 lastTriangle = None lastErrorMessage = "" # defaults at instancing def __init__(self, aMaxVertexCount=tmC_MAXVERTEXCOUNT, aOptions=tmO_MINIMALGRID|tmO_CONVEXHULL): self.Reset() self.maxVertexCount = aMaxVertexCount self.options = aOptions # set-funtions def SetMaxVertexCount(self, count): if count>3: self.maxVertexCount = count self.options &= ~tmO_GRADING def SetOptions(self, options): self.options = options def AddOption(self, options): self.options |= options def DeleteOption(self, options): self.options &= ~options def SetGradingLowerAngle(self, angle): self.gradingLowerAngle = angle self.options |= tmO_GRADING # get-functions def GetVertexCount(self): return self.vertexCount def GetInputVertexCount(self): return self.inputVertexCount def GetEdgeCount(self): return self.edgeCount def GetTriangleCount(self): return self.triangleCount def GetSegmentCount(): return self.segmentCount def GetHoleCount(): return self.holeCount def GetInsideTriangleCount(self): return self.insideTriangleCount def GetVertices(self): return self.Vertices def GetEdges(self): return self.Edges def GetTriangles(self): return self.Triangles def GetSegments(): return self.Segments def GetHoles(): return self.Holes # main mesh function def Mesh(self, input, segment, hole): # check segment type -- two separate functions for each if len(segment) > 0 and isinstance(segment[0], tmVertex): return self.MeshSV(input, segment, hole) # otherwise, it's hopefully a tmSegmentID endVertex, rtn = self.Setup(input, segment, hole) if rtn!=tmE_OK: return rtn # for testing only if self.options&tmO_NOCALC: return 0 # check intersections if self.options&tmO_CHECKINTERSECT: if self.HasIntersections(input, 0, endVertex): return tmE_INTERSECTS # mesh main return self.DoMesh(len(input)) # secondary mesh function (for segments passed as points) def MeshSV(self, input, segment, hole): n_input =len(input) n_segment=len(segment) n_holes =len(hole) sid = [] v = [] # alloc space for i in xrange(n_segment): sid.append(tmSegmentId()) for i in xrange(n_input + n_segment): v.append(tmVertex()) # copy points and assign seg id's for i in xrange(0, n_input): v[i].x = input[i].x v[i].y = input[i].y for i in xrange(n_input, n_input+n_segment): v[i].x = segment[i-n_input].x v[i].y = segment[i-n_input].y for i in (0,n_segment-1): sid[i].i1 = n_input+i+1 sid[i].i2 = n_input+i+2 sid[n_segment-1].i1 = n_input+n_segment sid[n_segment-1].i2 = n_input+1 # setup data endVertex, rtn = self.Setup(v, sid, hole) if rtn!=tmE_OK: return rtn # for testing only if self.options&tmO_NOCALC: return 0 # check intersections if self.options&tmO_CHECKINTERSECT: if self.HasIntersections(input, 0, endVertex): return tmE_INTERSECTS # mesh main return self.DoMesh(n_input+n_segment) def DoMesh(self, n_input): rtn = tmE_OK hasInsideTriangles=False self.Triangulate() if self.options & tmO_BASICMESH ==0: self.inputVertexCount = self.vertexCount # non convex graphs if self.options & tmO_CONVEXHULL: self.ConvexHull() self.InsertSegments() # mark triangles if self.haveEnoughVertices: self.MarkInsideTriangles(True) for i in range(self.triangleCount): if self.Triangles[i].inside: hasInsideTriangles = True break if not hasInsideTriangles: return tmE_NOINSIDETRIANGLES else: self.MarkInsideTriangles(False) # for i in range(self.segmentCount): e = self.GetEdge(self.Segments[i].v[0], self.Segments[i].v[1]) if e: e.locked = True # self.DeleteBadTriangles() # debug - for testing purposes only ! else: # for testing only # quick & dirty hack for a mesh with lesser angles than with the # tmO_GRADING flag and gradingLowerAngle set self.MarkInsideTriangles( not (self.options&tmO_BASICMESHNODEL) ) # restore original number of input vertices self.inputVertexCount = n_input # count inner triangles self.insideTriangleCount = 0 for i in range(self.triangleCount): if self.Triangles[i].inside: self.insideTriangleCount += 1 return rtn def Setup(self, input, segment, holes): rtn = tmE_OK n_input =len(input) n_segment=len(segment) n_holes =len(holes) self.inputVertexCount = n_input self.vertexCount = n_input + 3 # max sizes if n_input>self.maxVertexCount: self.maxVertexCount = n_input self.maxVertexCount += 3 self.maxEdgeCount = 3*self.maxVertexCount - 6 self.maxTriangleCount = 2*self.maxVertexCount - 5 + 1 self.maxSegmentCount = 3*self.maxVertexCount - 6 # allocate space for i in xrange(self.maxVertexCount): self.Vertices.append(tmVertex()) for i in xrange(self.maxEdgeCount): self.Edges.append(tmEdge()) for i in xrange(self.maxTriangleCount): self.Triangles.append(Triangle()) for i in xrange(self.maxSegmentCount): self.Segments.append(tmSegment()) # first 3 points make a big equilateral triangle for i in range(3): self.Vertices[i].x = tmC_BIGNUMBER * cos(i*(tmC_PIx2/3.0)) self.Vertices[i].y = tmC_BIGNUMBER * sin(i*(tmC_PIx2/3.0)) # copy input vertices if input and n_input>0: for i in range(3,self.vertexCount): self.Vertices[i].x = input[i-3].x self.Vertices[i].y = input[i-3].y # add boundary and close last/first,this adds ALL input vertices but # to the first input segment endVertex = self.inputVertexCount if self.options & tmO_SEGMENTBOUNDARY: # find outer boundary end-node, assume first segment input is start # of inner boundaries (holes) if n_segment>0: if segment[0].i10: k = 0 for i in xrange(self.segmentCount+n_segment): self.Segments[i].v[0] = self.Vertices[segment[k].i1+3-1] self.Segments[i].v[1] = self.Vertices[segment[k].i2+3-1] k += 1 self.segmentCount += n_segment # assign hole pointer self.holeCount = n_holes self.Holes = holes if self.options & tmO_WRITEINPUT: self.WriteInput(segment) return endVertex, rtn def Intersect(self, v0, v1, w0, w1): # check consecutive vertices if v0==w1 or v1==w0: return False # test v for intersection d1 = self.GetVertexPosition(v0, v1, w0) d2 = self.GetVertexPosition(v0, v1, w1) if d1*d2 > 0.0: return False # same sign # test w for intersection d1 = self.GetVertexPosition(w0, w1, v0) d2 = self.GetVertexPosition(w0, w1, v1) if d1*d2 > 0.0: return False # same sign # intersection return True def HasIntersections(self, v, start, end): for i in range(start, end): if i < end-1: i1 = i+1 else: i1 = start for k in range(i+1, end): if k < end-1: k1 = k+1 else: k1 = start if self.Intersect( v[i],v[i1], v[k],v[k1] ): return True return False def Triangulate(self): self.triangleCount = 0 self.edgeCount = 0 self.lastTriangle = None v0 = self.Vertices[0] v1 = self.Vertices[1] v2 = self.Vertices[2] t0 = self.AddTriangle() t1 = self.AddTriangle() e0 = self.AddEdge() e1 = self.AddEdge() e2 = self.AddEdge() self.SetTriangle( t0, v0, v1, v2, e0, e1, e2) self.SetTriangle( t1, v0, v2, v1, e2, e1, e0) self.SetEdge(e0, v0, v1, t0, t1) self.SetEdge(e1, v1, v2, t0, t1) self.SetEdge(e2, v2, v0, t0, t1) for i in range(3, self.vertexCount): self.InsertVertex(self.Vertices[i]) def CircumCenter(self, c, t): # center c0x = (t.v[0].x + t.v[1].x + t.v[2].x)/3.0 c0y = (t.v[0].y + t.v[1].y + t.v[2].y)/3.0 # deltas dx = t.v[1].x - t.v[0].x dy = t.v[1].y - t.v[0].y ex = t.v[2].x - t.v[0].x ey = t.v[2].y - t.v[0].y # f = 0.5 / (ex*dy - ey*dx) e2 = ex*ex + ey*ey d2 = dx*dx + dy*dy c1x = t.v[0].x + f * (e2*dy - d2*ey) c1y = t.v[0].y + f * (d2*ex - e2*dx) # look if already existing for i in range(20): c.x = c1x c.y = c1y if self.FindVertex(c): v = self.GetClosestVertex(c1x, c1y) if (v==t.v[0] or v==t.v[1] or v==t.v[2]): return c1x = c0x + 0.9*(c1x-c0x) c1y = c0y + 0.9*(c1y-c0y) # center c.x = c0x c.y = c0y def DeleteTriangle(self, t): # delete recursive if t.inside==False: return t.inside = False for i in range(3): e = t.e[i] if self.GetSegment( e.v[0], e.v[1])==None: if e.t[0]==t: self.DeleteTriangle(e.t[1]) elif e.t[1]==t: self.DeleteTriangle(e.t[0]) else: assert( e.t[0]==t or e.t[1]==t ) def SegmentVertices(self, startNode, endNode, doclose): k = self.segmentCount for i in range(startNode-1, endNode-1): k+=1 self.Segments[k].v[0] = self.Vertices[i+3] self.Segments[k].v[1] = self.Vertices[i+3+1] self.segmentCount+=1 if doclose: self.Segments[k].v[0] = self.Vertices[i+3] self.Segments[k].v[1] = self.Vertices[3] self.segmentCount+=1 def AddVertex(self): if self.vertexCount >= self.maxVertexCount: return None self.vertexCount+=1 return self.Vertices[self.vertexCount-1] def AddEdge(self): assert( self.edgeCount tmC_PI: d -= tmC_PIx2 while d <= -tmC_PI: d += tmC_PIx2 return d def GetSegment(self,v0,v1): for i in range(self.segmentCount): x0, x1 = self.Segments[i].v if (v0==x0 and v1==x1) or (v0==x1 and v1==x0): return self.Segments[i] return None def GetAdjacentEdges(self, e, t) : assert( (e==t.e[0])or(e==t.e[1])or(e==t.e[2]) ) if (e==t.e[0]): return (t.e[1], t.e[2], t.v[2]) elif (e==t.e[1]): return (t.e[2], t.e[0], t.v[0]) elif (e==t.e[2]): return (t.e[0], t.e[1], t.v[1]) def IsOppositeVertex(self, v0, v1, v2): return ( (v1 in self.Vertices[:self.inputVertexCount] ) and ( self.GetSegment(v0, v1) != None ) and ( self.GetSegment(v1, v2) != None ) ) def FixEdge(self, e, t0, t1): assert( (e.t[0]==t0) or (e.t[1]==t0) ) if e.t[0]==t0: e.t[0] = t1 elif e.t[1]==t0: e.t[1] = t1 def InsertVertexAt(self, v, e): t0, t1 = e.t v0, v2 = e.v e2, e3, v3 = self.GetAdjacentEdges(e, t0) e0, e1, v1 = self.GetAdjacentEdges(e, t1) t2 = self.AddTriangle() t3 = self.AddTriangle() f0 = self.AddEdge() f1 = self.AddEdge() f2 = self.AddEdge() i0 = t0.inside i1 = t1.inside locked = e.locked self.SetTriangle( t0, v3, v0, v, e3, e, f2) self.SetTriangle( t1, v0, v1, v, e0, f0, e) self.SetTriangle( t2, v1, v2, v, e1, f1, f0) self.SetTriangle( t3, v2, v3, v, e2, f2, f1) self.SetEdge(e, v0, v, t0, t1) self.SetEdge(f0, v1, v, t1, t2) self.SetEdge(f1, v2, v, t2, t3) self.SetEdge(f2, v3, v, t3, t0) self.FixEdge(e1, t1, t2) self.FixEdge(e2, t0, t3) t0.inside = i0 t1.inside = i1 t2.inside = i1 t3.inside = i0 e.locked = locked f1.locked = locked if i0: self.CheckEdge( e2) self.CheckEdge( e3) if i1: self.CheckEdge( e0) self.CheckEdge( e1) return True def InsertVertex(self, v): t0 = self.FindVertex(v) if t0 == None: return False for i in range(3): v0 = t0.v[i] if i == 2: v1 = t0.v[0] else: v1 = t0.v[i+1] if self.GetVertexPosition(v0, v1, v)==0.0: return self.InsertVertexAt( v, t0.e[i] ) v0, v1, v2 = t0.v e0, e1, e2 = t0.e t1 = self.AddTriangle() t2 = self.AddTriangle() f0 = self.AddEdge() f1 = self.AddEdge() f2 = self.AddEdge() self.SetTriangle( t0, v0, v1, v, e0, f1, f0) self.SetTriangle( t1, v1, v2, v, e1, f2, f1) self.SetTriangle( t2, v2, v0, v, e2, f0, f2) self.SetEdge(f0, v0, v, t2, t0) self.SetEdge(f1, v1, v, t0, t1) self.SetEdge(f2, v2, v, t1, t2) self.FixEdge(e1, t0, t1) self.FixEdge(e2, t0, t2) self.CheckEdge(e0) self.CheckEdge(e1) self.CheckEdge(e2) return True def CheckEdge(self, e): if e.locked: return False t0, t1 = e.t assert( t0.inside==t1.inside ) v0, v2 = e.v e2, e3, v3 = self.GetAdjacentEdges(e, t0) e0, e1, v1 = self.GetAdjacentEdges(e, t1) if self.GetVertexPosition( v1, v3, v2)>=0.0 or self.GetVertexPosition( v1, v3, v0)<=0.0: return False cCount = 0 if self.HasBoundingVertices( v0, v2, v3): cCount+=1 if self.HasBoundingVertices( v2, v0, v1): cCount+=1 a0 = t0.minAngle a1 = t1.minAngle cAngle = min(a0, a1) pCount = 0 if self.HasBoundingVertices( v1, v3, v0): pCount+=1 if self.HasBoundingVertices( v3, v1, v2): pCount+=1 a0, q0, s = self.SetTriangleData( v1, v3, v0) a1, q1, s = self.SetTriangleData( v3, v1, v2) pAngle = min(a0, a1) if pCountcAngle: self.SetTriangle( t0, v1, v3, v0, e, e3, e0) self.SetTriangle( t1, v3, v1, v2, e, e1, e2) self.SetEdge( e, v1, v3, t0, t1) self.FixEdge( e0, t1, t0) self.FixEdge( e2, t0, t1) self.CheckEdge( e0) self.CheckEdge( e1) self.CheckEdge( e2) self.CheckEdge( e3) return True return False def GetClosestVertex(self, x, y): dmin=0.0 v=None for i in range(self.vertexCount): dx = self.Vertices[i].x - x dy = self.Vertices[i].y - y d2 = dx*dx + dy*dy if i==0 or d2=self.gradingLowerAngle): return self.CircumCenter(vc, tBad) isInside = False for i in range(self.segmentCount): if self.ContainsVertex(self.Segments[i].v[0], self.Segments[i].v[1], vc): isInside = self.SplitSegment( self.Segments[i]) if not isInside: v = self.AddVertex() if not v: return v.x, v.y = vc.x, vc.y self.InsertVertex( v) def FindVertex(self, v): # initialize t = self.lastTriangle if t==None: t = self.Triangles[1] # search repeat = True while repeat: repeat = False for i in range(3): v0 = t.v[i] if i==2: v1 = t.v[0] else: v1 = t.v[i+1] if self.GetVertexPosition(v0, v1, v) < 0.0: e = t.e[i] if e.t[0]==t: t = e.t[1] elif e.t[1]==t: t = e.t[0] else: assert( False ) repeat = True break # found self.lastTriangle = t if t.inside: return t else: return None def ContainsVertex(self, v0, v1, v): cx = 0.5 * (v0.x + v1.x) cy = 0.5 * (v0.y + v1.y) dx = v1.x - cx dy = v1.y - cy r2 = dx*dx + dy*dy dx = v.x - cx dy = v.y - cy d2 = dx*dx + dy*dy return d2 < r2 def GetVertexPosition(self, a, b, c): if c in self.Vertices[:3]: d1 = (b.x - a.x)*(c.y - a.y) d2 = (b.y - a.y)*(c.x - a.x) else: d1 = (a.x - c.x)*(b.y - c.y) d2 = (a.y - c.y)*(b.x - c.x) return d1-d2 def GetSplitPosition(self, v, v0, v1): vt = tmVertex() if v1 in self.Vertices[:self.inputVertexCount]: v0, v1 = v1, v0 if v0 in self.Vertices[:self.inputVertexCount]: dx = v1.x - v0.x dy = v1.y - v0.y d = sqrt(dx*dx + dy*dy) # 1) p41 f = pow(2.0, floor(tmC_SQRT2 * log(0.5*d) + 0.5) )/d v.x = v0.x + f*dx v.y = v0.y + f*dy else : v.x = 0.5*(v0.x + v1.x) v.y = 0.5*(v0.y + v1.y) def SplitSegment(self, s): e = self.GetEdge( s.v[0], s.v[1]) assert(e!=None) v0 = s.v[0] v1 = s.v[1] if self.SameVertex(v0,v1): return False v = self.AddVertex() if not v: return False t = self.AddSegment() self.SetSegment(s, v0, v) self.SetSegment(t, v, v1) self.GetSplitPosition( v, v0, v1) self.InsertVertexAt( v, e) return True def InsertSegments(self): inserting = True while inserting: inserting = False for i in range(self.segmentCount): s = self.Segments[i] v0 = s.v[0] v1 = s.v[1] e = self.GetEdge(v0, v1) if not e: v = self.AddVertex() if not v: return t = self.AddSegment() self.SetSegment(s, v0, v) self.SetSegment(t, v, v1) self.GetSplitPosition( v, v0, v1) inserting = self.InsertVertex( v) elif (self.ContainsVertex(e.v[0], e.v[1], self.GetOppositeVertex(e, e.t[0])) or self.ContainsVertex(e.v[0], e.v[1], self.GetOppositeVertex(e, e.t[1]))): inserting = self.SplitSegment(s) if self.vertexCount==self.maxVertexCount: self.haveEnoughVertices = False return self.haveEnoughVertices = True def SetSegment(self,s,v0,v1): s.v[0], s.v[1] = v0, v1 def ConvexHull(self): for i in range(self.triangleCount): # Check all combinations for j in range(3): if j == 0: i0, i1, i2 = 0, 1, 2 elif j==1: i0, i1, i2 = 1, 2, 0 elif j==2: i0, i1, i2 = 2, 0, 1 if (self.Triangles[i].v[i0] in self.Vertices[3:] and self.Triangles[i].v[i1] in self.Vertices[3:] and self.Triangles[i].v[i2] in self.Vertices[:3] and self.GetSegment(self.Triangles[i].v[i0], self.Triangles[i].v[i1])==None): s = self.AddSegment() self.SetSegment(s, self.Triangles[i].v[i0], self.Triangles[i].v[i1]) def Reset(self): self.Vertices = [] self.Edges = [] self.Triangles = [] self.Segments = [] self.vertexCount = 0 self.inputVertexCount = 0 self.edgeCount = 0 self.triangleCount = 0 self.segmentCount = 0 self.holeCount = 0 self.insideTriangleCount = 0 def PolygonCenter(self, v, n, from_=0): vc = tmVertex( (v[from_].x, v[from_].y) ) for i in range(from_+1, n): vc.x += v[i].x vc.y += v[i].y vc.x /= n-from_ vc.y /= n-from_ return vc def GetErrorMessage(self, errId): if errId in tmErrorMessages: return tmErrorMessages[errId] else: return "unknown error occurred" def WriteInput(self, seg): pass def PrintData(self): print "Options : %d" % (self.options) print "MinAngle : %G" % (self.gradingLowerAngle) print "Max V/E/T/S: %d %d %d %d" % (self.maxVertexCount,self.maxEdgeCount,self.maxTriangleCount,self.maxSegmentCount) print " actual : %d %d %d %d %d" % (self.vertexCount,self.edgeCount, self.triangleCount, self.segmentCount, self.holeCount) print "self.Vertices : %d" % (self.vertexCount) print "self.Segments : %d" % (self.segmentCount) print "self.Triangles : %d (total: %d)" % (self.insideTriangleCount,self.triangleCount) def PrintTriangles(): for t in self.Triangles: print "%04d;%6.2f;%6.2f;%6.2f;%6.2f;%6.2f;%6.2f;%d;%6.2f;%6.2f\n" % (i, t.v[0].x,t.v[0].y,t.v[1].x,t.v[1].y, t.v[2].x,t.v[2].y,t.inside,t.minAngle,t.angle) def main(): rtn = 0 # the geometry-boundary to mesh, points in length units. # a ring # # node points nodes = ( ( 5.00, 0.00), # 1 outer boundary ( 3.54, 3.54), # 2 ( 0.00, 5.00), # 3 (-3.54, 3.54), # 4 (-5.00, 0.00), # 5 (-3.54, -3.54), # 6 ( 0.00, -5.00), # 7 ( 3.54, -3.54), # 8 ( 2.00, 0.00), # 9 inner boundary ( 1.41, 1.41), # 10 ( 0.00, 2.00), # 11 (-1.41, 1.41), # 12 (-2.00, 0.00), # 13 (-1.41, -1.41), # 14 ( 0.00, -2.00), # 15 ( 1.41, -1.41)) # 16 nodes = [tmVertex(node) for node in nodes] holes = [ tmVertex( (0.0, 0.0) ) ] # center hole boundary segs = ( ( 9, 10), # point indices (see nodes[]) starting at 1 (10, 11), (11, 12), (12, 13), (13, 14), (14, 15), (15, 16), (16, 9)) segs = [tmSegmentId(seg) for seg in segs] # instead of nodes indices segXY = (( 2.00, 0.00), # inner boundary ( 1.41, 1.41), ( 0.00, 2.00), (-1.41, 1.41), (-2.00, 0.00), (-1.41, -1.41), ( 0.00, -2.00), ( 1.41, -1.41)) segXY = [tmVertex(seg) for seg in segXY] # go md = TriangleMesh() # 1. possibility rtn = md.Mesh( nodes, segs, holes) vc = md.PolygonCenter(nodes, 16, 8) print " PolygonCenter: [%G %G]" % (vc.x,vc.y) print " %s [%d]" % (md.GetErrorMessage(rtn), rtn) md.PrintData() md.Reset() exit(0) # not working in python yet... # 2. possibility rtn = md.Mesh( nodes[:8], segXY, holes) print " %s [%d]" % (md.GetErrorMessage(rtn), rtn) md.PrintData() if __name__=="__main__": main() python-box2d-2.0.2+svn20100109.244/testbed/test_Buoyancy.py0000644000000000000000000000713111135471136021335 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Buoyancy (Framework): name="Buoyancy" bc=None _pickle_vars=['bc'] def __init__(self): super(Buoyancy, self).__init__() bcd = box2d.b2BuoyancyControllerDef() bcd.offset = 15 bcd.normal = (0,1) bcd.density = 2 bcd.linearDrag = 2 bcd.angularDrag = 1 self.bc = self.world.CreateController(bcd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 0.125) sd.density = 2.0 sd.friction = 0.2 jd=box2d.b2RevoluteJointDef() numPlanks = 30 prevBody = ground for i in range(numPlanks): bd=box2d.b2BodyDef() bd.position = (-14.5 + 1.0 * i, 5.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() anchor=(-15.0 + 1.0 * i, 5.0) jd.Initialize(prevBody, body, anchor) self.world.CreateJoint(jd).getAsType() prevBody = body self.bc.AddBody(body) anchor=(-15.0 + 1.0 * numPlanks, 5.0) jd.Initialize(prevBody, ground, anchor) self.world.CreateJoint(jd).getAsType() for i in range(2): sd=box2d.b2PolygonDef() sd.vertexCount = 3 sd.setVertex(0,-0.5, 0.0) sd.setVertex(1,0.5, 0.0) sd.setVertex(2,0.0, 1.5) sd.density = 1.0 bd=box2d.b2BodyDef() bd.position = (-8.0 + 8.0 * i, 12.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() self.bc.AddBody(body) for i in range(3): sd=box2d.b2CircleDef() sd.radius = 0.5 sd.density = 1.0 bd=box2d.b2BodyDef() bd.position = (-6.0 + 6.0 * i, 10.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() self.bc.AddBody(body) def Step(self, settings): super(Buoyancy, self).Step(settings) if __name__=="__main__": main(Buoyancy) python-box2d-2.0.2+svn20100109.244/testbed/test_Gravity.py0000644000000000000000000000522311144075331021166 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Gravity (Framework): name="Gravity" gc=None bodies = [ ] _pickle_vars=['bodies', 'gc'] def __init__(self): super(Gravity, self).__init__() gcd = box2d.b2GravityControllerDef() gcd.G=0.8 gcd.invSqr=True self.gc = self.world.CreateController(gcd) self.world.gravity = (0,0) bd=box2d.b2BodyDef() bd.position = (0.0, 20.0) ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.density = 0.0 sd.restitution = 1 sd.SetAsBox(0.2, 20.0, (-20.0, 0.0), 0.0) ground.CreateShape(sd) sd.SetAsBox(0.2, 20.0, (20.0, 0.0), 0.0) ground.CreateShape(sd) sd.SetAsBox(0.2, 20.0, (0.0, -20.0), 0.5 * box2d.b2_pi) ground.CreateShape(sd) sd.SetAsBox(0.2, 20.0, (0.0, 20.0), -0.5 * box2d.b2_pi) ground.CreateShape(sd) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) sd=box2d.b2CircleDef() sd.density = 1.0 sd.isBullet=True bd=box2d.b2BodyDef() for i in range(1,4): sd.radius = 0.25*i bd.position = (0.25*i, 2.0 + 7.5 * i) body=self.world.CreateBody(bd) self.bodies.append(body) body.CreateShape(sd) body.SetMassFromShapes() self.gc.AddBody(body) body.ApplyForce( (-10*i, 2), body.GetWorldCenter() ) if __name__=="__main__": main(Gravity) python-box2d-2.0.2+svn20100109.244/testbed/test_Chain.py0000644000000000000000000000415311135471136020567 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Chain (Framework): name="Chain" def __init__(self): super(Chain, self).__init__() bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.6, 0.125) sd.density = 20.0 sd.friction = 0.2 jd=box2d.b2RevoluteJointDef() jd.collideConnected = False y = 25.0 prevBody=ground for i in range(30): bd=box2d.b2BodyDef() bd.position = (0.5 + i, y) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() anchor=(i, y) jd.Initialize(prevBody, body, anchor) self.world.CreateJoint(jd).getAsType() prevBody = body if __name__=="__main__": main(Chain) python-box2d-2.0.2+svn20100109.244/testbed/test_CCDTest.py0000644000000000000000000000617311135461416021002 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class CCDTest (Framework): name="CCDTest" def __init__(self): super(CCDTest, self).__init__() # Note that this test has a lot of commented-out versions that aren't implemented here. # See the original source code for more (Box2D/Examples/TestBed/Tests/CCDTest.h) k_restitution = 1.4 bd=box2d.b2BodyDef() bd.position = (0.0, 20.0) body = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.density = 0.0 sd.restitution = k_restitution sd.SetAsBox(0.1, 10.0, (-10.0, 0.0), 0.0) body.CreateShape(sd) sd.SetAsBox(0.1, 10.0, (10.0, 0.0), 0.0) body.CreateShape(sd) sd.SetAsBox(0.1, 10.0, (0.0, -10.0), 0.5 * box2d.b2_pi) body.CreateShape(sd) sd.SetAsBox(0.1, 10.0, (0.0, 10.0), -0.5 * box2d.b2_pi) body.CreateShape(sd) sd_bottom=box2d.b2PolygonDef() sd_bottom.SetAsBox( 1.5, 0.15 ) sd_bottom.density = 4.0 sd_left=box2d.b2PolygonDef() sd_left.SetAsBox(0.15, 2.7, (-1.45, 2.35), 0.2) sd_left.density = 4.0 sd_right=box2d.b2PolygonDef() sd_right.SetAsBox(0.15, 2.7, (1.45, 2.35), -0.2) sd_right.density = 4.0 bd=box2d.b2BodyDef() bd.position = ( 0.0, 15.0 ) body = self.world.CreateBody(bd) body.CreateShape(sd_bottom) body.CreateShape(sd_left) body.CreateShape(sd_right) body.SetMassFromShapes() return for i in range(0): bd=box2d.b2BodyDef() bd.position = (0.0, 15.0 + i) bd.isBullet = True body = self.world.CreateBody(bd) body.SetAngularVelocity(box2d.b2Random(-50.0, 50.0)) sd=box2d.b2CircleDef() sd.radius = 0.25 sd.density = 1.0 sd.restitution = 0.0 body.CreateShape(sd) body.SetMassFromShapes() if __name__=="__main__": main(CCDTest) python-box2d-2.0.2+svn20100109.244/testbed/test_RaycastTest.py0000644000000000000000000000716611136402204022011 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class RaycastTest (Framework): name="RaycastTest" laserBody=None _pickle_vars=['laserBody'] def __init__(self): super(RaycastTest, self).__init__() #self.world.SetGravity( (0,0) ) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) ground.CreateShape(sd) bd=box2d.b2BodyDef() bd.position = (0.0, 1.0) self.laserBody = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(5.0, 1.0) sd.density = 4.0 self.laserBody.CreateShape(sd) self.laserBody.SetMassFromShapes() #Create a few shapes bd.position = (-5.0, 10.0) body = self.world.CreateBody(bd) cd=box2d.b2CircleDef() cd.radius = 3 body.CreateShape(cd) bd.position = (5.0, 10.0) body = self.world.CreateBody(bd) body.CreateShape(cd) def Keyboard(self, key): pass def Step(self, settings): super(RaycastTest, self).Step(settings) if not self.laserBody: return segmentLength = 30.0 segment=box2d.b2Segment() laserStart=(5.0-0.1,0.0) laserDir=(segmentLength,0.0) segment.p1 = self.laserBody.GetWorldPoint(laserStart) segment.p2 = self.laserBody.GetWorldVector(laserDir) segment.p2+=segment.p1 for rebounds in xrange(10): lambda_, normal, shape = self.world.RaycastOne(segment,False,None) laserColor=box2d.b2Color(1.0,0,0) if shape: self.debugDraw.DrawSegment(segment.p1,(1-lambda_)*segment.p1+lambda_*segment.p2,laserColor) else: self.debugDraw.DrawSegment(segment.p1,segment.p2,laserColor) break #Bounce segmentLength *= (1-lambda_) if segmentLength <= box2d.B2_FLT_EPSILON: break laserStart = (1-lambda_)*segment.p1+lambda_*segment.p2 laserDir = segment.p2-segment.p1 laserDir.Normalize() laserDir = laserDir -2 * box2d.b2Dot(laserDir,normal) * normal segment.p1 = laserStart-0.1*laserDir segment.p2 = laserStart+segmentLength*laserDir if __name__=="__main__": main(RaycastTest) python-box2d-2.0.2+svn20100109.244/testbed/test_Car.py0000644000000000000000000001364111136402204020243 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Car (Framework): name="Car" leftWheel=None rightWheel=None vehicle=None leftJoint=None rightJoint=None _pickle_vars=['leftWheel','rightWheel','vehicle','leftJoint','rightJoint'] def __init__(self): super(Car, self).__init__() # car body poly1=box2d.b2PolygonDef() poly2=box2d.b2PolygonDef() # bottom half poly1.vertexCount = 5 poly1.setVertex(4,-2.2,-0.74) poly1.setVertex(3,-2.2,0) poly1.setVertex(2,1.0,0) poly1.setVertex(1,2.2,-0.2) poly1.setVertex(0,2.2,-0.74) poly1.filter.groupIndex = -1 poly1.density = 20.0 poly1.friction = 0.68 poly1.filter.groupIndex = -1 # top half poly2.vertexCount = 4 poly2.setVertex(3,-1.7,0) poly2.setVertex(2,-1.3,0.7) poly2.setVertex(1,0.5,0.74) poly2.setVertex(0,1.0,0) poly2.filter.groupIndex = -1 poly2.density = 5.0 poly2.friction = 0.68 poly2.filter.groupIndex = -1 bd=box2d.b2BodyDef() bd.position = (-35.0, 2.8) self.vehicle = self.world.CreateBody(bd) self.vehicle.CreateShape(poly1) self.vehicle.CreateShape(poly2) self.vehicle.SetMassFromShapes() # vehicle wheels circ = box2d.b2CircleDef() circ.density = 40.0 circ.radius = 0.38608 circ.friction = 0.8 circ.filter.groupIndex = -1 bd=box2d.b2BodyDef() bd.allowSleep = False bd.position = (-33.8, 2.0) self.rightWheel = self.world.CreateBody(bd) self.rightWheel.CreateShape(circ) self.rightWheel.SetMassFromShapes() bd.position = (-36.2, 2.0) self.leftWheel = self.world.CreateBody(bd) self.leftWheel.CreateShape(circ) self.leftWheel.SetMassFromShapes() # join wheels to chassis jd=box2d.b2RevoluteJointDef() jd.Initialize(self.vehicle, self.leftWheel, self.leftWheel.GetWorldCenter()) jd.collideConnected = False jd.enableMotor = True jd.maxMotorTorque = 10.0 jd.motorSpeed = 0.0 self.leftJoint = self.world.CreateJoint(jd).getAsType() jd.Initialize(self.vehicle, self.rightWheel, self.rightWheel.GetWorldCenter()) jd.collideConnected = False self.rightJoint = self.world.CreateJoint(jd).getAsType() # ground box=box2d.b2PolygonDef() box.SetAsBox(19.5, 0.5) box.friction = 0.62 bd=box2d.b2BodyDef() bd.position = (-25.0, 1.0) ground = self.world.CreateBody(bd) ground.CreateShape(box) # more ground box=box2d.b2PolygonDef() bd=box2d.b2BodyDef() box.SetAsBox(9.5, 0.5, (0,0), 0.1 * box2d.b2_pi) box.friction = 0.62 bd.position = (27.0 - 30.0, 3.1) ground = self.world.CreateBody(bd) ground.CreateShape(box) # more ground box=box2d.b2PolygonDef() bd=box2d.b2BodyDef() box.SetAsBox(9.5, 0.5, (0,0), -0.1 * box2d.b2_pi) box.friction = 0.62 bd.position = (55.0 - 30.0, 3.1) ground = self.world.CreateBody(bd) ground.CreateShape(box) # more ground box=box2d.b2PolygonDef() bd=box2d.b2BodyDef() box.SetAsBox(9.5, 0.5, (0,0), 0.03 * box2d.b2_pi) box.friction = 0.62 bd.position = (41.0, 2.0) ground = self.world.CreateBody(bd) ground.CreateShape(box) # more ground box=box2d.b2PolygonDef() bd=box2d.b2BodyDef() box.SetAsBox(5.0, 0.5, (0,0), 0.15 * box2d.b2_pi) box.friction = 0.62 bd.position = (50.0, 4.0) ground = self.world.CreateBody(bd) ground.CreateShape(box) # more ground box=box2d.b2PolygonDef() bd=box2d.b2BodyDef() box.SetAsBox(20.0, 0.5) box.friction = 0.62 bd.position = (85.0, 2.0) ground = self.world.CreateBody(bd) ground.CreateShape(box) def Step(self, settings): self.DrawStringCR("Keys: left = a, brake = s, right = d") super(Car, self).Step(settings) def Keyboard(self, key): if not self.leftJoint: return if key==K_a: self.leftJoint.SetMaxMotorTorque(800.0) self.leftJoint.SetMotorSpeed(12.0) elif key==K_s: self.leftJoint.SetMaxMotorTorque(100.0) self.leftJoint.SetMotorSpeed(0.0) elif key==K_d: self.leftJoint.SetMaxMotorTorque(1200.0) self.leftJoint.SetMotorSpeed(-36.0) if __name__=="__main__": main(Car) python-box2d-2.0.2+svn20100109.244/testbed/test_PolyCollision.py0000644000000000000000000000527511136402204022341 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class PolyCollision (Framework): name="PolyCollision" body1=None body2=None _pickle_vars=['body1', 'body2'] def __init__(self): super(PolyCollision, self).__init__() sd=box2d.b2PolygonDef() sd.setVertex(0,-9.0, -1.1) sd.setVertex(1,7.0, -1.1) sd.setVertex(2,5.0, -0.9) sd.setVertex(3,-11.0, -0.9) sd.vertexCount = 4 sd.density = 0.0 bd=box2d.b2BodyDef() bd.position = (0.0, 10.0) self.body1 = self.world.CreateBody(bd) self.body1.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 0.5) sd.density = 1.0 bd=box2d.b2BodyDef() bd.position = (0.0, 10.0) self.body2 = self.world.CreateBody(bd) self.body2.CreateShape(sd) self.body2.SetMassFromShapes() self.world.SetGravity( (0,0) ) def Step(self, settings): settings.pause = True super(PolyCollision, self).Step(settings) settings.pause = False def Keyboard(self, key): if not self.body2: return p = self.body2.GetPosition() a = self.body2.GetAngle() if key==K_a: p.x -= 0.1 elif key==K_d: p.x += 0.1 elif key==K_s: p.y -= 0.1 elif key==K_w: p.y += 0.1 elif key==K_q: a += 0.1 * box2d.b2_pi elif key==K_e: a -= 0.1 * box2d.b2_pi self.body2.SetXForm(p, a) if __name__=="__main__": main(PolyCollision) python-box2d-2.0.2+svn20100109.244/testbed/test_VaryingRestitution.py0000644000000000000000000000370111135461416023434 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class VaryingRestitution (Framework): name="VaryingRestitution" def __init__(self): super(VaryingRestitution, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2CircleDef() sd.radius = 1.0 sd.density = 1.0 restitution = [0.0, 0.1, 0.3, 0.5, 0.75, 0.9, 1.0] for i in range(7): bd=box2d.b2BodyDef() bd.position = (-10.0 + 3.0 * i, 20.0) body = self.world.CreateBody(bd) sd.restitution = restitution[i] body.CreateShape(sd) body.SetMassFromShapes() if __name__=="__main__": main(VaryingRestitution) python-box2d-2.0.2+svn20100109.244/testbed/pyglet_main.py0000644000000000000000000010633211156664767021041 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ Keys: Space - shoot projectile Z/X - zoom Escape - quit Other keys can be set by the individual test Mouse: Left click - select/drag body (creates mouse joint) Right click - pan Shift+Left - drag to create a directional projectile Scroll - zoom You can easily add your own tests based on test_empty. -kne """ import pyglet from pyglet import gl import Box2D as box2d from settings import fwSettings from pygame_keycodes import * import math class fwDestructionListener(box2d.b2DestructionListener): """ The destruction listener callback: "SayGoodbye" is called when a joint or shape is deleted. """ test = None def __init__(self): super(fwDestructionListener, self).__init__() def SayGoodbye(self, object): if isinstance(object, box2d.b2Joint): if self.test.mouseJoint==object: self.test.mouseJoint=None else: self.test.JointDestroyed(object) elif isinstance(object, box2d.b2Shape): self.test.ShapeDestroyed(object) class fwBoundaryListener(box2d.b2BoundaryListener): """ The boundary listener callback: Violation is called when the specified body leaves the world AABB. """ test = None def __init__(self): super(fwBoundaryListener, self).__init__() def Violation(self, body): # So long as it's not the user-created bomb, let the test know that # the specific body has left the world AABB if self.test.bomb != body: self.test.BoundaryViolated(body) class fwContactTypes: """ Acts as an enum, holding the types necessary for contacts: Added, persisted, and removed """ contactUnknown = 0 contactAdded = 1 contactPersisted = 2 contactRemoved = 3 class fwContactPoint: """ Structure holding the necessary information for a contact point. All of the information is copied from the contact listener callbacks. """ shape1 = None shape2 = None normal = None position = None velocity = None id = box2d.b2ContactID() state = 0 class fwContactListener(box2d.b2ContactListener): """ Handles all of the contact states passed in from Box2D. """ test = None def __init__(self): super(fwContactListener, self).__init__() def handleCall(self, state, point): if not self.test: return cp = fwContactPoint() cp.shape1 = point.shape1 cp.shape2 = point.shape2 cp.position = point.position.copy() cp.normal = point.normal.copy() cp.id = point.id cp.state = state self.test.points.append(cp) def Add(self, point): self.handleCall(fwContactTypes.contactAdded, point) def Persist(self, point): self.handleCall(fwContactTypes.contactPersisted, point) def Remove(self, point): self.handleCall(fwContactTypes.contactRemoved, point) class grBlended (pyglet.graphics.Group): """ This pyglet rendering group enables blending. """ def set_state(self): gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) def unset_state(self): gl.glDisable(gl.GL_BLEND) class grPointSize (pyglet.graphics.Group): """ This pyglet rendering group sets a specific point size. """ def __init__(self, size=4.0): super(grPointSize, self).__init__() self.size = size def set_state(self): gl.glPointSize(self.size) def unset_state(self): gl.glPointSize(1.0) class grText(pyglet.graphics.Group): """ This pyglet rendering group sets the proper projection for displaying text when used. """ window = None def __init__(self, window=None): super(grText, self).__init__() self.window = window def set_state(self): gl.glMatrixMode(gl.GL_PROJECTION) gl.glPushMatrix() gl.glLoadIdentity() gl.gluOrtho2D(0, self.window.width, 0, self.window.height) gl.glMatrixMode(gl.GL_MODELVIEW) gl.glPushMatrix() gl.glLoadIdentity() def unset_state(self): gl.glPopMatrix() gl.glMatrixMode(gl.GL_PROJECTION) gl.glPopMatrix() gl.glMatrixMode(gl.GL_MODELVIEW) class fwDebugDraw(box2d.b2DebugDraw): """ This debug draw class accepts callbacks from Box2D (which specifies what to draw) and handles all of the rendering. If you are writing your own game, you likely will not want to use debug drawing. Debug drawing, as its name implies, is for debugging. """ blended = grBlended() circle_segments = 16 surface = None circle_cache_tf = {} # triangle fan (inside) circle_cache_ll = {} # line loop (border) def __init__(self): super(fwDebugDraw, self).__init__() def triangle_fan(self, vertices): """ in: vertices arranged for gl_triangle_fan ((x,y),(x,y)...) out: vertices arranged for gl_triangles (x,y,x,y,x,y...) """ out = [] for i in range(1, len(vertices)-1): # 0,1,2 0,2,3 0,3,4 .. out.extend( vertices[0 ] ) out.extend( vertices[i ] ) out.extend( vertices[i+1] ) return len(out) / 2, out def line_loop(self, vertices): """ in: vertices arranged for gl_line_loop ((x,y),(x,y)...) out: vertices arranged for gl_lines (x,y,x,y,x,y...) """ out = [] for i in range(0, len(vertices)-1): # 0,1 1,2 2,3 ... len-1,len len,0 out.extend( vertices[i ] ) out.extend( vertices[i+1] ) out.extend( vertices[len(vertices)-1] ) out.extend( vertices[0] ) return len(out)/2, out def _getLLCircleVertices(self, radius, points): """ Get the line loop-style vertices for a given circle. Drawn as lines. "Line Loop" is used as that's how the C++ code draws the vertices, with lines going around the circumference of the circle (GL_LINE_LOOP). This returns 'points' amount of lines approximating the border of a circle. (x1, y1, x2, y2, x3, y3, ...) """ ret = [] step = 2*math.pi/points n = 0 for i in range(0, points): ret.append( (math.cos(n) * radius, math.sin(n) * radius ) ) n += step ret.append( (math.cos(n) * radius, math.sin(n) * radius ) ) return ret def _getTFCircleVertices(self, radius, points): """ Get the triangle fan-style vertices for a given circle. Drawn as triangles. "Triangle Fan" is used as that's how the C++ code draws the vertices, with triangles originating at the center of the circle, extending around to approximate a filled circle (GL_TRIANGLE_FAN). This returns 'points' amount of lines approximating the circle. (a1, b1, c1, a2, b2, c2, ...) """ ret = [] step = 2*math.pi/points n = 0 for i in range(0, points): ret.append( (0.0, 0.0) ) ret.append( (math.cos(n) * radius, math.sin(n) * radius ) ) n += step ret.append( (math.cos(n) * radius, math.sin(n) * radius ) ) return ret def getCircleVertices(self, center, radius, points): """ Returns the triangles that approximate the circle and the lines that border the circles edges, given (center, radius, points). Caches the calculated LL/TF vertices, but recalculates based on the center passed in. TODO: As of this point, there's only one point amount, so the circle cache ignores it when storing. Could cause some confusion if you're using multiple point counts as only the first stored point-count for that radius will show up. Returns: (tf_vertices, ll_vertices) """ if radius not in self.circle_cache_tf.keys(): self.circle_cache_tf[radius]=self._getTFCircleVertices(radius,points) self.circle_cache_ll[radius]=self._getLLCircleVertices(radius,points) ret_tf, ret_ll = [], [] for x, y in self.circle_cache_tf[radius]: ret_tf.extend( (x+center.x, y+center.y) ) for x, y in self.circle_cache_ll[radius]: ret_ll.extend( (x+center.x, y+center.y) ) return ret_tf, ret_ll def DrawCircle(self, center, radius, color): """ Draw an unfilled circle given center, radius and color. """ unused, ll_vertices = self.getCircleVertices( center, radius, self.circle_segments) ll_count = len(ll_vertices)/2 self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count))) def DrawSolidCircle(self, center, radius, axis, color): """ Draw an filled circle given center, radius, axis (of orientation) and color. """ tf_vertices, ll_vertices = self.getCircleVertices( center, radius, self.circle_segments) tf_count, ll_count = len(tf_vertices) / 2, len(ll_vertices) / 2 self.batch.add(tf_count, gl.GL_TRIANGLES, self.blended, ('v2f', tf_vertices), ('c4f', [0.5 * color.r, 0.5 * color.g, 0.5 * color.b, 0.5] * (tf_count))) self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count))) p = center + radius * axis self.batch.add(2, gl.GL_LINES, None, ('v2f', (center.x, center.y, p.x, p.y)), ('c3f', [1.0, 0.0, 0.0] * 2)) def DrawPolygon(self, vertices, vertexCount, color): """ Draw a wireframe polygon given the world vertices (tuples) with the specified color. """ ll_count, ll_vertices = self.line_loop(vertices) self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count))) def DrawSolidPolygon(self, vertices, vertexCount, color): """ Draw a wireframe polygon given the world vertices (tuples) with the specified color. """ tf_count, tf_vertices = self.triangle_fan(vertices) self.batch.add(tf_count, gl.GL_TRIANGLES, self.blended, ('v2f', tf_vertices), ('c4f', [0.5 * color.r, 0.5 * color.g, 0.5 * color.b, 0.5] * (tf_count))) ll_count, ll_vertices = self.line_loop(vertices) self.batch.add(ll_count, gl.GL_LINES, None, ('v2f', ll_vertices), ('c4f', [color.r, color.g, color.b, 1.0] * (ll_count))) def DrawSegment(self, p1, p2, color): """ Draw the line segment from p1-p2 with the specified color. """ self.batch.add(2, gl.GL_LINES, None, ('v2f', (p1.x, p1.y, p2.x, p2.y)), ('c3f', [color.r, color.g, color.b]*2)) def DrawXForm(self, xf): """ Draw the transform xf on the screen """ p1 = xf.position k_axisScale = 0.4 p2 = p1 + k_axisScale * xf.R.col1 p3 = p1 + k_axisScale * xf.R.col2 self.batch.add(3, gl.GL_LINES, None, ('v2f', (p1.x, p1.y, p2.x, p2.y, p1.x, p1.y, p3.x, p3.y)), ('c3f', [1.0, 0.0, 0.0] * 2 + [0.0, 1.0, 0.0] * 2)) def DrawPoint(self, p, size, color): """ Draw a single point at point p given a point size and color. """ self.batch.add(1, gl.GL_POINTS, grPointSize(size), ('v2f', (p.x, p.y)), ('c3f', [color.r, color.g, color.b])) def DrawAABB(self, aabb, color): """ Draw a wireframe around the AABB with the given color. """ self.debugDraw.batch.add(8, gl.GL_LINES, None, ('v2f', (aabb.lowerBound.x, aabb.lowerBound.y, abb.upperBound.x, aabb.lowerBound.y, abb.upperBound.x, aabb.lowerBound.y, aabb.upperBound.x, aabb.upperBound.y, aabb.upperBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.upperBound.y, aabb.lowerBound.x, aabb.lowerBound.y)), ('c3f', [color.r, color.g, color.b] * 8)) class Framework(pyglet.window.Window): """ The main testbed framework. It handles basically everything: * The initialization of pyglet, Box2D, and the window itself * Contains the main loop * Handles all user input. The window itself is derived from pyglet's Window, so you can use all of its functionality. You should derive your class from this one to implement your own tests. See test_Empty.py or any of the other tests for more information. """ name = "None" # Box2D-related worldAABB = None points = [] world = None bomb = None bombSpawning = False bombSpawnPoint = None points = [] mouseJoint = None settings = fwSettings mouseWorld = None destroyList = [] # Box2D-callbacks destructionListener= None boundaryListener = None contactListener = None debugDraw = None # Window-related fontname = "Arial" fontsize = 10 font = None textGroup = None keys = pyglet.window.key.KeyStateHandler() # Screen-related _viewZoom = 1.0 _viewCenter = None screenSize = None textLine = 30 font = None fps = 0 def __init__(self, **kw): super(Framework, self).__init__(**kw) # Initialize the text display group self.textGroup = grText(self) # Load the font and record the screen dimensions self.font = pyglet.font.load(self.fontname, self.fontsize) self.screenSize = box2d.b2Vec2(self.width, self.height) # Box2D Initialization self.worldAABB = box2d.b2AABB() self.worldAABB.lowerBound = (-200.0, -100.0) self.worldAABB.upperBound = ( 200.0, 200.0) gravity = (0.0, -10.0) doSleep = True self.world = box2d.b2World(self.worldAABB, gravity, doSleep) self.destructionListener = fwDestructionListener() self.boundaryListener = fwBoundaryListener() self.contactListener = fwContactListener() self.debugDraw = fwDebugDraw() self.debugDraw.surface = self.screen self.destructionListener.test = self self.boundaryListener.test = self self.contactListener.test = self self.world.SetDestructionListener(self.destructionListener) self.world.SetBoundaryListener(self.boundaryListener) self.world.SetContactListener(self.contactListener) self.world.SetDebugDraw(self.debugDraw) self._viewCenter = box2d.b2Vec2(0,10.0) def on_close(self): """ Callback: user tried to close the window """ pyglet.clock.unschedule(self.SimulationLoop) super(Framework, self).on_close() def on_show(self): """ Callback: the window was shown. """ self.updateProjection() def updateProjection(self): """ Recalculates the necessary projection. """ gl.glViewport(0, 0, self.width, self.height) gl.glMatrixMode(gl.GL_PROJECTION) gl.glLoadIdentity() ratio = float(self.width) / self.height extents = box2d.b2Vec2(ratio * 25.0, 25.0) extents *= self._viewZoom lower = self._viewCenter - extents upper = self._viewCenter + extents # L/R/B/T gl.gluOrtho2D(lower.x, upper.x, lower.y, upper.y) gl.glMatrixMode(gl.GL_MODELVIEW) gl.glLoadIdentity() def setCenter(self, value): """ Updates the view offset based on the center of the screen. """ if isinstance(value, box2d.b2Vec2): self._viewCenter = value.copy() elif isinstance(value, (list, tuple)): self._viewCenter = box2d.b2Vec2( *value ) else: raise ValueError, 'Expected b2Vec2 or sequence' self.updateProjection() def setZoom(self, zoom): self._viewZoom = zoom self.updateProjection() viewZoom = property(lambda self: self._viewZoom, setZoom, doc='Zoom factor for the display') viewCenter = property(lambda self: self._viewCenter, setCenter, doc='Screen center in camera coordinates') def on_key_press(self, key, modifiers): """ Checks for the initial keydown of the basic testbed keys. Passes the unused ones onto the test via the Keyboard() function. """ if key==pyglet.window.key.ESCAPE: exit(0) elif key==pyglet.window.key.Z: # Zoom in self.viewZoom = min(1.1 * self.viewZoom, 20.0) elif key==pyglet.window.key.X: # Zoom out self.viewZoom = max(0.9 * self.viewZoom, 0.02) elif key==pyglet.window.key.R: # Reload (disabled) #print "Reload not functional" exit(10) elif key==pyglet.window.key.SPACE: # Launch a bomb self.LaunchRandomBomb() elif key==pyglet.window.key.F5: # Save state self.pickle_save('pickle_output') elif key==pyglet.window.key.F7: # Load state self.pickle_load('pickle_output') else: # Inform the test of the key press self.Keyboard(key) def on_mouse_motion(self, x, y, dx, dy): self.invalid=False def on_mouse_press(self, x, y, button, modifiers): """ Mouse down """ p = self.ConvertScreenToWorld(x, y) self.mouseWorld = p if button == pyglet.window.mouse.LEFT: if modifiers & pyglet.window.key.MOD_SHIFT: self.ShiftMouseDown( p ) else: self.MouseDown( p ) elif button == pyglet.window.mouse.MIDDLE: pass def on_mouse_release(self, x, y, button, modifiers): """ Mouse up """ p = self.ConvertScreenToWorld(x, y) self.mouseWorld = p if button == pyglet.window.mouse.LEFT: self.MouseUp(p) def on_mouse_scroll(self, x, y, scroll_x, scroll_y): """ Mouse scrollwheel used """ if scroll_y < 0: self.viewZoom *= 1.1 elif scroll_y > 0: self.viewZoom /= 1.1 def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): """ Mouse moved while clicking """ p = self.ConvertScreenToWorld(x, y) self.mouseWorld = p self.MouseMove(p) if buttons & pyglet.window.mouse.RIGHT: self.viewCenter -= (float(dx)/5, float(dy)/5) def pickle_load(self, fn, set_vars=True, additional_vars=[]): """ Load the pickled world in file fn. additional_vars is a dictionary to be populated with the loaded variables. """ import cPickle as pickle try: world, variables = pickle.load(open(fn, 'rb')) except Exception, s: print 'Error while loading world: ', s return self.world = world._pickle_finalize() variables=box2d.pickle_fix(self.world, variables, 'load') if set_vars: for var, value in variables.items(): if hasattr(self, var): setattr(self, var, value) else: print 'Unknown property %s=%s' % (var, value) self.bomb = None self.bombSpawning = False # have to reset a few things that can't be saved: self.world.SetDestructionListener(self.destructionListener) self.world.SetBoundaryListener(self.boundaryListener) self.world.SetContactListener(self.contactListener) self.world.SetDebugDraw(self.debugDraw) print 'Loaded' return variables def pickle_save(self, fn, additional_vars={}): import cPickle as pickle if self.mouseJoint: self.MouseUp(self.mouseWorld) # remove a mouse joint if it exists if not additional_vars and hasattr(self, '_pickle_vars'): additional_vars=dict((var, getattr(self, var)) for var in self._pickle_vars) save_values = [self.world, box2d.pickle_fix(self.world, additional_vars, 'save')] try: pickle.dump(save_values, open(fn, 'wb')) except Exception, s: print 'Pickling failed: ', s return print 'Saved' def run(self): """ Main loop. """ if self.settings.hz > 0.0: pyglet.clock.schedule_interval(self.SimulationLoop, 1.0 / self.settings.hz) pyglet.app.run() def SetTextLine(self, line): """ Kept for compatibility with C++ Box2D's testbeds. """ self.textLine=line def Step(self, settings): """ The main physics step. Takes care of physics drawing (callbacks are executed after the world.Step() ) and drawing additional information. """ # Don't do anything if the setting's Hz are <= 0 if settings.hz > 0.0: timeStep = 1.0 / settings.hz else: timeStep = 0.0 # If paused, display so if settings.pause: if settings.singleStep: settings.singleStep=False else: timeStep = 0.0 self.DrawStringCR("****PAUSED****") # Set the flags based on what the settings show (uses a bitwise or mask) flags = 0 if settings.drawShapes: flags |= box2d.b2DebugDraw.e_shapeBit if settings.drawJoints: flags |= box2d.b2DebugDraw.e_jointBit if settings.drawControllers:flags |= box2d.b2DebugDraw.e_controllerBit if settings.drawCoreShapes: flags |= box2d.b2DebugDraw.e_coreShapeBit if settings.drawAABBs: flags |= box2d.b2DebugDraw.e_aabbBit if settings.drawOBBs: flags |= box2d.b2DebugDraw.e_obbBit if settings.drawPairs: flags |= box2d.b2DebugDraw.e_pairBit if settings.drawCOMs: flags |= box2d.b2DebugDraw.e_centerOfMassBit self.debugDraw.SetFlags(flags) # Set the other settings that aren't contained in the flags self.world.SetWarmStarting(settings.enableWarmStarting) self.world.SetContinuousPhysics(settings.enableTOI) # Reset the collision points self.points = [] # Tell Box2D to step self.world.Step(timeStep, settings.velocityIterations, settings.positionIterations) self.world.Validate() # Destroy bodies that have left the world AABB (can be removed if not using pickling) for obj in self.destroyList: self.world.DestroyBody(obj) self.destroyList = [] # If the bomb is frozen, get rid of it. if self.bomb and self.bomb.IsFrozen(): self.world.DestroyBody(self.bomb) self.bomb = None if settings.drawStats: self.DrawStringCR("proxies(max) = %d(%d), pairs(max) = %d(%d)" % ( self.world.GetProxyCount(), box2d.b2_maxProxies, self.world.GetPairCount(), box2d.b2_maxPairs) ) self.DrawStringCR("bodies/contacts/joints = %d/%d/%d" % (self.world.GetBodyCount(), self.world.GetContactCount(), self.world.GetJointCount())) self.DrawStringCR("hz %d vel/pos iterations %d/%d" % (settings.hz, settings.velocityIterations, settings.positionIterations)) self.DrawStringCR("heap bytes = %d" % box2d.cvar.b2_byteCount) if settings.drawFPS: #python version only self.DrawStringCR("FPS %d" % self.fps) # If there's a mouse joint, draw the connection between the object and the current pointer position. if self.mouseJoint: body = self.mouseJoint.GetBody2() p1 = body.GetWorldPoint(self.mouseJoint.localAnchor) p2 = self.mouseJoint.target self.debugDraw.DrawPoint(p1, settings.pointSize, box2d.b2Color(0,1.0,0)) self.debugDraw.DrawPoint(p2, settings.pointSize, box2d.b2Color(0,1.0,0)) self.debugDraw.DrawSegment(p1, p2, box2d.b2Color(0.8,0.8,0.8)) # Draw the slingshot bomb if self.bombSpawning: self.debugDraw.DrawPoint(self.bombSpawnPoint, settings.pointSize, box2d.b2Color(0,0,1.0)) self.debugDraw.DrawSegment(self.bombSpawnPoint, self.mouseWorld, box2d.b2Color(0.8,0.8,0.8)) # Draw each of the contact points in different colors. if self.settings.drawContactPoints: #k_impulseScale = 0.1 k_axisScale = 0.3 for point in self.points: if point.state == fwContactTypes.contactAdded: self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.3, 0.95, 0.3)) elif point.state == fwContactTypes.contactPersisted: self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.3, 0.3, 0.95)) else: #elif point.state == fwContactTypes.contactRemoved: self.debugDraw.DrawPoint(point.position, settings.pointSize, box2d.b2Color(0.95, 0.3, 0.3)) if settings.drawContactNormals: p1 = point.position p2 = p1 + k_axisScale * point.normal self.debugDraw.DrawSegment(p1, p2, box2d.b2Color(0.4, 0.9, 0.4)) def LaunchBomb(self, position, velocity): """ A bomb is a simple circle which has the specified position and velocity. """ if self.bomb: self.world.DestroyBody(self.bomb) self.bomb = None bd = box2d.b2BodyDef() bd.allowSleep = True bd.position = position bd.isBullet = True self.bomb = self.world.CreateBody(bd) self.bomb.SetLinearVelocity(velocity) sd = box2d.b2CircleDef() sd.radius = 0.3 sd.density = 20.0 sd.restitution = 0.1 minV = position - box2d.b2Vec2(0.3,0.3) maxV = position + box2d.b2Vec2(0.3,0.3) aabb = box2d.b2AABB() aabb.lowerBound = minV aabb.upperBound = maxV if self.world.InRange(aabb): self.bomb.CreateShape(sd) self.bomb.SetMassFromShapes() def LaunchRandomBomb(self): """ Create a new bomb and launch it at the testbed. """ p = box2d.b2Vec2( box2d.b2Random(-15.0, 15.0), 30.0 ) v = -5.0 * p self.LaunchBomb(p, v) def CheckKeys(self): """ Check the keys that are evaluated on every main loop iteration. I.e., they aren't just evaluated when first pressed down """ if self.keys[pyglet.window.key.LEFT]: self.viewCenter.x -= 0.5 elif self.keys[pyglet.window.key.RIGHT]: self.viewCenter.x += 0.5 if self.keys[pyglet.window.key.UP]: self.viewCenter.y += 0.5 elif self.keys[pyglet.window.key.DOWN]: self.viewCenter.y -= 0.5 if self.keys[pyglet.window.key.HOME]: self._viewZoom = 1.0 self.viewCenter = (0.0, 20.0) def SimulationLoop(self, dt): """ The main simulation loop. Don't override this, override Step instead. And be sure to call super(classname, self).Step(settings) at the end of your Step function. """ # Check the input self.CheckKeys() # Clear the screen self.clear() # Update the keyboard status self.push_handlers(self.keys) # Create a new batch for drawing self.debugDraw.batch = pyglet.graphics.Batch() # Reset the text position self.SetTextLine(15) # Draw the title of the test at the top self.DrawStringCR(self.name) # Step the physics self.Step(self.settings) self.debugDraw.batch.draw() self.invalid = True self.fps = pyglet.clock.get_fps() def ConvertScreenToWorld(self, x, y): """ Takes screen (x, y) and returns world coordinate b2Vec2(x,y). """ u = float(x) / self.width v = float(y) / self.height ratio = float(self.width) / self.height extents = box2d.b2Vec2(ratio * 25.0, 25.0) extents *= self._viewZoom lower = self._viewCenter - extents upper = self._viewCenter + extents p = box2d.b2Vec2( (1.0 - u) * lower.x + u * upper.x, (1.0 - v) * lower.y + v * upper.y ) return p def DrawString(self, x, y, str, color=(229,153,153,255)): """ Draw some text, str, at screen coordinates (x, y). """ text = pyglet.text.Label(str, font_name=self.fontname, font_size=self.fontsize, x=x, y=self.height-y, color=color, batch=self.debugDraw.batch, group=self.textGroup) def DrawStringCR(self, str, color=(229,153,153,255)): """ Draw some text, str, at screen coordinates (x, y). """ text = pyglet.text.Label(str, font_name=self.fontname, font_size=self.fontsize, x=5, y=self.height-self.textLine, color=color, batch=self.debugDraw.batch, group=self.textGroup) self.textLine += 15 def ShiftMouseDown(self, p): """ Indicates that there was a left click at point p (world coordinates) with the left shift key being held down. """ self.mouseWorld = p if self.mouseJoint != None: return self.SpawnBomb(p) def MouseDown(self, p): """ Indicates that there was a left click at point p (world coordinates) """ if self.mouseJoint != None: return # Make a small box. aabb = box2d.b2AABB() d = box2d.b2Vec2(0.001, 0.001) aabb.lowerBound = p - d aabb.upperBound = p + d # Query the world for overlapping shapes. body = None k_maxCount = 10 (count, shapes) = self.world.Query(aabb, k_maxCount) for shape in shapes: shapeBody = shape.GetBody() if shapeBody.IsStatic() == False and shapeBody.GetMass() > 0.0: if shape.TestPoint(shapeBody.GetXForm(), p): # is it inside? body = shapeBody break if body: md = box2d.b2MouseJointDef() md.body1 = self.world.GetGroundBody() md.body2 = body md.target = p md.maxForce= 1000.0 * body.GetMass() self.mouseJoint = self.world.CreateJoint(md).getAsType() body.WakeUp() def MouseUp(self, p): """ Left mouse button up. """ if self.mouseJoint: self.world.DestroyJoint(self.mouseJoint) self.mouseJoint = None if self.bombSpawning: self.CompleteBombSpawn(p) def MouseMove(self, p): """ Mouse moved to point p, in world coordinates. """ if self.mouseJoint: self.mouseJoint.SetTarget(p) def SpawnBomb(self, worldPt): """ Begins the slingshot bomb by recording the initial position. Once the user drags the mouse and releases it, then CompleteBombSpawn will be called and the actual bomb will be released. """ self.bombSpawnPoint = worldPt.copy() self.bombSpawning = True def CompleteBombSpawn(self, p): """ Create the slingshot bomb based on the two points (from the worldPt passed to SpawnBomb to p passed in here) """ if not self.bombSpawning: return multiplier = 30.0 vel = self.bombSpawnPoint - p vel *= multiplier self.LaunchBomb(self.bombSpawnPoint, vel) self.bombSpawning = False # These should be implemented in the subclass: (Step() also if necessary) def ShapeDestroyed(self, joint): pass def JointDestroyed(self, joint): pass def BoundaryViolated(self, body): # Be sure to check if any of these bodies are ones your game # stores. Using a reference to a deleted object will cause a crash. # e.g., # if body==self.player: # self.player=None # # The following checks for generic usage by testing the pickle variables. if hasattr(self, '_pickle_vars'): for var in self._pickle_vars: value=getattr(self, var) if body==value: setattr(self, var, None) elif isinstance(value, list): if body in value: value.remove(body) # Not destroying bodies outside the world AABB will cause # pickling to fail, so destroy it after the next step: self.destroyList.append(body) def Keyboard(self, key): pass def main(test_class): print "Loading %s..." % test_class.name test = test_class() if fwSettings.onlyInit: return test.run() if __name__=="__main__": from test_empty import Empty main(Empty) python-box2d-2.0.2+svn20100109.244/testbed/test_Revolute.py0000644000000000000000000000536311136402204021345 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Revolute (Framework): name="Revolute" joint=None _pickle_vars=['joint'] def __init__(self): super(Revolute, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2CircleDef() sd.radius = 0.5 sd.density = 5.0 bd=box2d.b2BodyDef() rjd=box2d.b2RevoluteJointDef() bd.position = (0.0, 20.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() w = 100.0 body.SetAngularVelocity(w) body.SetLinearVelocity((-8.0 * w, 0.0)) rjd.Initialize(ground, body, (0.0, 12.0)) rjd.motorSpeed = 1.0 * box2d.b2_pi rjd.maxMotorTorque = 10000.0 rjd.enableMotor = False rjd.lowerAngle = -0.25 * box2d.b2_pi rjd.upperAngle = 0.5 * box2d.b2_pi rjd.enableLimit = True rjd.collideConnected = True self.joint = self.world.CreateJoint(rjd).getAsType() def Keyboard(self, key): if not self.joint: return if key==K_l: self.joint.EnableLimit(not self.joint.IsLimitEnabled()) elif key==K_s: self.joint.EnableMotor(False) def Step(self, settings): super(Revolute, self).Step(settings) self.DrawStringCR("Keys: (l) toggle limits, (s) motor off") if __name__=="__main__": main(Revolute) python-box2d-2.0.2+svn20100109.244/testbed/test_TimeOfImpact.py0000644000000000000000000000711111136402204022052 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class TimeOfImpact (Framework): name="TimeOfImpact" body1=None body2=None shape1=None shape2=None _pickle_vars=['body1', 'body2', 'shape1', 'shape2'] def __init__(self): super(TimeOfImpact, self).__init__() sd=box2d.b2PolygonDef() sd.density = 0.0 sd.SetAsBox(0.1, 10.0, (10.0, 0.0), 0.0) bd=box2d.b2BodyDef() bd.position = (0.0, 20.0) bd.angle = 0.0 self.body1 = self.world.CreateBody(bd) self.shape1 = self.body1.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.25, 0.25) sd.density = 1.0 bd=box2d.b2BodyDef() bd.position = (9.6363468, 28.050615) bd.angle = 1.6408679 self.body2 = self.world.CreateBody(bd) self.shape2 = self.body2.CreateShape(sd).getAsType() self.body2.SetMassFromShapes() def Step(self, settings): if not self.body1 or not self.body2 or not self.shape1 or not self.shape2: return sweep1=box2d.b2Sweep() sweep1.c0 = (0.0, 20.0) sweep1.a0 = 0.0 sweep1.c = sweep1.c0 sweep1.a = sweep1.a0 sweep1.t0 = 0.0 sweep1.localCenter = self.body1.GetLocalCenter() sweep2=box2d.b2Sweep() sweep2.c0 = (9.6363468, 28.050615) sweep2.a0 = 1.6408679 sweep2.c = sweep2.c0 + (-0.075121880, 0.27358246) sweep2.a = sweep2.a0 - 10.434675 sweep2.t0 = 0.0 sweep2.localCenter = self.body2.GetLocalCenter() toi = box2d.b2TimeOfImpact(self.shape1, sweep1, self.shape2, sweep2) self.DrawStringCR("toi = %g" % (toi)) xf2=box2d.b2XForm() sweep2.GetXForm(xf2, toi) vertexCount = self.shape2.GetVertexCount() vertices = [] localVertices = self.shape2.getVertices_b2Vec2() for vertex in localVertices: vertices.append( box2d.b2Mul(xf2, vertex).tuple() ) self.debugDraw.DrawPolygon(vertices, vertexCount, box2d.b2Color(0.5, 0.7, 0.9)) localVertices = self.shape2.getCoreVertices_b2Vec2() for vertex in localVertices: vertices.append( box2d.b2Mul(xf2, vertex).tuple() ) self.debugDraw.DrawPolygon(vertices, vertexCount, box2d.b2Color(0.5, 0.7, 0.9)) settings.pause = True super(TimeOfImpact, self).Step(settings) settings.pause = False if __name__=="__main__": main(TimeOfImpact) python-box2d-2.0.2+svn20100109.244/testbed/test_StaticEdges.py0000644000000000000000000001676111135461416021754 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class StaticEdges (Framework): name="StaticEdges" def __init__(self): super(StaticEdges, self).__init__() sd1=box2d.b2CircleDef() sd1.radius = 0.5 sd1.localPosition = (-0.5, 0.5) sd1.density = 2.0 sd2=box2d.b2CircleDef() sd2.radius = 0.5 sd2.localPosition = (0.5, 0.5) sd2.density = 0.0 # massless for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x + 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() sd1=box2d.b2PolygonDef() sd1.SetAsBox(0.25, 0.5) sd1.density = 2.0 sd2=box2d.b2PolygonDef() sd2.SetAsBox(0.25, 0.5, (0.0, -0.5), 0.5 * box2d.b2_pi) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x - 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() xf1=box2d.b2XForm() xf1.R.Set(0.3524 * box2d.b2_pi) xf1.position = box2d.b2Mul(xf1.R, (1.0, 0.0)) sd1=box2d.b2PolygonDef() sd1.vertexCount = 3 sd1.setVertex(0, box2d.b2Mul(xf1, (-1.0, 0.0))) sd1.setVertex(1, box2d.b2Mul(xf1, (1.0, 0.0))) sd1.setVertex(2, box2d.b2Mul(xf1, (0.0, 0.5))) sd1.density = 2.0 xf2=box2d.b2XForm() xf2.R.Set(-0.3524 * box2d.b2_pi) xf2.position = box2d.b2Mul(xf2.R, (-1.0, 0.0)) sd2=box2d.b2PolygonDef() sd2.vertexCount = 3 sd2.setVertex(0, box2d.b2Mul(xf2, (-1.0, 0.0))) sd2.setVertex(1, box2d.b2Mul(xf2, (1.0, 0.0))) sd2.setVertex(2, box2d.b2Mul(xf2, (0.0, 0.5))) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x, 2.05 + 2.5 * i) bd.angle = 0.0 body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() loop1 = [ (0.063134534,8.3695248), (0.94701801,9.3165428), (0.0,9.0640047), (-0.12626907,10.326695), (1.4520943,11.77879), (2.2728432,10.137292), (2.3991123,11.147444), (3.5986685,10.958041), (3.9143411,7.3593722), (4.1668793,9.4428119), (5.4295699,9.3165428), (6.2503189,8.3063903), (6.6922606,10.137292), (4.9876282,9.8216191), (4.7350901,10.958041), (7.2604714,11.652521), (10.732871,11.147444), (10.480333,10.642368), (10.732871,9.8216191), (11.55362,9.4428119), (12.374369,9.3796773), (13.005714,9.8216191), (13.195118,10.38983), (13.005714,10.768637), (12.626907,10.894906), (12.753176,11.526252), (13.573925,11.715655), (14.836616,11.399982), (16.351844,10.768637), (17.867073,11.399982), (17.803939,10.263561), (17.361997,8.3063903), (17.803939,8.1801212), (18.056477,9.5059464), (18.182746,11.336848), (18.561553,11.210579), (18.561553,9.6322155), (18.561553,7.7381795), (18.687822,5.5284708), (19.382302,5.6547398), (19.066629,8.1801212), (19.003495,10.263561), (19.066629,11.463117), (19.887378,11.841924), (20.708127,11.273713), (21.0238,10.011023), (20.708127,7.2962377), (21.086934,6.2860852), (21.150069,3.7607038), (20.392455,2.5611476), (18.624688,2.5611476), (20.771262,2.1192059), (20.771262,0.22516988), (18.624688,-0.2799064), (13.826463,0.16203534), (14.015867,1.7403987), (13.195118,2.1823404), (12.626907,1.5509951), (12.879445,0.85651522), (12.626907,0.35143895), (10.543467,1.298457), (11.490485,3.9501074), (13.889598,3.6344347), (13.889598,2.9399549), (14.584077,3.8869729), (11.932427,5.2127981), (9.7227183,4.0132419), (10.796005,3.5081657), (9.7858528,3.2556275), (10.796005,2.4980131), (7.9549513,1.7403987), (9.6595837,1.424726), (9.217642,0.66711162), (8.270624,-0.090502792), (7.0079333,0.85651522), (6.1240498,-0.15363733), (6.1240498,3.192493), (5.6821081,2.4348786), (4.9876282,2.1192059), (4.1037447,1.8666678), (3.0304576,1.8666678), (2.0834396,2.245475), (1.6414979,2.6242822), (1.3258252,3.5081657), (1.2626907,0.47770802), (0.63134534,0.035766276), (0.063134534,0.9827842), ] loop2 = [ (8.270624,6.1598161), (8.270624,5.3390672), (8.7757003,5.086529), (9.4701801,5.5284708), (9.217642,6.033547), (8.7757003,6.412354), ] b2Loop1 = [(loop[0] - 10.0, loop[1]) for loop in loop1] b2Loop2 = [(loop[0] - 10.0, loop[1]) for loop in loop2] bd=box2d.b2BodyDef() bd.position = ( 0.0, 0.0 ) body = self.world.CreateBody(bd) edgeDef=box2d.b2EdgeChainDef() edgeDef.vertices=b2Loop1 body.CreateShape(edgeDef) edgeDef.vertices=b2Loop2 body.CreateShape(edgeDef) #body.SetMassFromShapes() if __name__=="__main__": main(StaticEdges) python-box2d-2.0.2+svn20100109.244/testbed/test_Belt.py0000644000000000000000000001012111144320631020414 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * from math import atan2 # C++ version by Smartcode # See http://www.box2d.org/forum/viewtopic.php?f=3&t=2280 class Belt (Framework): name="Belt" def __init__(self): super(Belt, self).__init__() bd=box2d.b2BodyDef() # static body bd.position=(0.0, 0.0) stat_c = self.world.CreateBody(bd) # first circle bd.position=(-5, 10) c1 = self.world.CreateBody(bd) sd=box2d.b2CircleDef() sd.radius = 4.3 sd.density = 3.0 sd.friction = 0.8 sd.restitution = 0.4 c1.CreateShape(sd) c1.SetMassFromShapes() # first joint rjd=box2d.b2RevoluteJointDef() rjd.Initialize(stat_c, c1, c1.GetWorldCenter()) self.world.CreateJoint(rjd) #.getAsType() use getAsType if you want to refer to this joint # second circle bd.position=(10, 15) c2 = self.world.CreateBody(bd) sd.radius = 2.2 c2.CreateShape(sd) c2.SetMassFromShapes() # second joint rjd.Initialize(stat_c, c2, c2.GetWorldCenter()) self.world.CreateJoint(rjd) # create belt from the table of points tuple_points = [ (-5.97, 14.91), (-3.17, 15.46), (-0.38, 16.01), ( 2.42, 16.56), ( 5.22, 17.11), (8.01, 17.67 ), (10.82, 17.88), (12.83, 16.01), (12.46, 13.29), (10.12, 11.73), (7.56, 10.49 ), ( 4.99, 9.26), ( 2.42, 8.02), (-0.15, 6.79), (-2.72, 5.55), (-5.48, 5.02), (-8.09, 6.07), (-9.72, 8.36), (-9.86, 11.17), (-8.46, 13.61) ] points = [box2d.b2Vec2(*t) for t in tuple_points] pd=box2d.b2PolygonDef() jd=box2d.b2RevoluteJointDef() pd.density = 3.0 pd.friction = 0.8 thickness = 1.0 first_body= None prev_body = None next_body = None for i in range(20): v = points[(i+1)%20] - points[i] angle = atan2(v.y, v.x) bd.position = points[i] + 0.5 * v next_body = self.world.CreateBody(bd) if i == 0: first_body = next_body # remember the body of first fragment pd.SetAsBox(0.5 * v.Length() + thickness / 2.0, thickness / 2.0, (0,0), angle) shape = next_body.CreateShape(pd) next_body.SetMassFromShapes() if prev_body: # if we have previous body, create joint local_anchor=points[i] jd.Initialize(prev_body, next_body, local_anchor) self.world.CreateJoint(jd) prev_body = next_body # last anchor between last and first element jd.Initialize(prev_body, first_body, points[0]) self.world.CreateJoint(jd) if __name__=="__main__": main(Belt) python-box2d-2.0.2+svn20100109.244/testbed/test_VerticalStack.py0000644000000000000000000000600611135471136022303 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class VerticalStack (Framework): name="VerticalStack" bullet=None _pickle_vars=['bullet'] def __init__(self): super(VerticalStack, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0, (0.0, -10.0), 0.0) bd=box2d.b2BodyDef() bd.position = (0.0, 0.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd.SetAsBox(0.1, 10.0, (20.0, 10.0), 0.0) ground.CreateShape(sd) xs = [0.0, -10.0, -5.0, 5.0, 10.0] for j in xrange(5): sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 0.5) sd.density = 1.0 sd.friction = 0.3 for i in xrange(16): bd=box2d.b2BodyDef() x = 0.0 #x = b2Random(-0.1, 0.1) #x = i % 2 == 0 ? -0.025 : 0.025 bd.position = (xs[j] + x, 0.752 + 1.54 * i) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() self.bullet = None def Keyboard(self, key): if key == K_COMMA: if self.bullet: self.world.DestroyBody(self.bullet) self.bullet = None sd=box2d.b2CircleDef() sd.density = 20.0 sd.radius = 0.25 sd.restitution = 0.05 bd=box2d.b2BodyDef() bd.isBullet = True bd.position = (-31.0, 5.0) self.bullet = self.world.CreateBody(bd) self.bullet.CreateShape(sd) self.bullet.SetMassFromShapes() self.bullet.SetLinearVelocity((400.0, 0.0)) def Step(self, settings): self.DrawStringCR("Press: (,) to launch a bullet.") super(VerticalStack, self).Step(settings) if __name__=="__main__": main(VerticalStack) python-box2d-2.0.2+svn20100109.244/testbed/test_main.py0000644000000000000000000000314011156662747020501 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from settings import fwSettings # Note that if you are making your own program and want it to be pyglet/pygame # only, you can take 'pyglet_main.py' or 'pygame_main.py' and overwrite # 'test_main.py'. known_backends = ("pyglet", "pygame", "cairo") if fwSettings.backend in known_backends: exec("from %s_main import *" % fwSettings.backend) else: from sys import argv print ''' Please set a proper "backend". Either use the command line: > %s --backend pygame or edit the default settings in settings.py. ''' % (argv[0]) exit(0) python-box2d-2.0.2+svn20100109.244/testbed/test_Tribute.py0000644000000000000000000001342411156225217021164 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # A tribute to Gish # Contributed by Giorgos Giagas (giorgosg) from test_main import * from math import cos, sin, pi class Tribute (Framework): name="Tribute to Gish" _pickle_vars = ['bodies', 'move', 'moving', 'jump', 'radius'] moving = None jump = False move = None def __init__(self): super(Tribute, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) sd.friction = 0.2 bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd.SetAsBox(0.5, 5.0, (-50.0, 15.0), 0.0) ground.CreateShape(sd) sd.SetAsBox(0.5, 5.0, (50.0, 15.0), 0.0) ground.CreateShape(sd) sd.SetAsBox(3.0,1.0) sd.density = 3.0 boxd = box2d.b2BodyDef() for i in range(0, 16, 2): boxd.position = (-10.1, i) box = self.world.CreateBody(boxd) box.CreateShape(sd) box.SetMassFromShapes() sd=box2d.b2CircleDef() sd.density = 5.0 sd.friction = 0.5 sd.radius = 0.4 sd.restitution= 0.0 bd=box2d.b2BodyDef() bd.angularDamping = 0.5 bd.linearDamping = 0.5 bd.fixedRotation = True bd.allowSleep = False self.bodies = bodies = [] radius = self.radius = 2 blob_center = box2d.b2Vec2(-10, +50) for i in range(0, 360, 15): # 24 circles pos = (cos(i*2*pi/360)*radius + blob_center.x, sin(i*2*pi/360)*radius + blob_center.y) bd.position = pos bodyx = self.world.CreateBody(bd) bodyx.CreateShape(sd) bodyx.SetMassFromShapes() bodies.append(bodyx) bodycount = len(self.bodies) pjd=box2d.b2DistanceJointDef() for i in range(bodycount): body1 = bodies[i] body2 = bodies[i+1] if i+1 3: self.selected_point = 0 def Step(self, settings): super(BezierEdges, self).Step(settings) for p in self.control_points: self.debugDraw.DrawCircle(p, 0.25, box2d.b2Color(1.0,0.0,0)) if __name__=="__main__": main(BezierEdges) python-box2d-2.0.2+svn20100109.244/testbed/test_CompoundShapes.py0000644000000000000000000001066311135471136022500 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class CompoundShapes (Framework): name="CompoundShapes" def __init__(self): super(CompoundShapes, self).__init__() bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) body = self.world.CreateBody(bd) sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) body.CreateShape(sd) sd1=box2d.b2CircleDef() sd1.radius = 0.5 sd1.localPosition = (-0.5, 0.5) sd1.density = 2.0 sd2=box2d.b2CircleDef() sd2.radius = 0.5 sd2.localPosition = (0.5, 0.5) sd2.density = 0.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x + 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() sd1=box2d.b2PolygonDef() sd1.SetAsBox(0.25, 0.5) sd1.density = 2.0 sd2=box2d.b2PolygonDef() sd2.SetAsBox(0.25, 0.5, (0.0, -0.5), 0.5 * box2d.b2_pi) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x - 5.0, 1.05 + 2.5 * i) bd.angle = box2d.b2Random(-box2d.b2_pi, box2d.b2_pi) body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() xf1 = box2d.b2XForm() xf1.R.Set(0.3524 * box2d.b2_pi) xf1.position = box2d.b2Mul(xf1.R, (1.0, 0.0)) sd1=box2d.b2PolygonDef() sd1.vertexCount = 3 sd1.setVertex(0, box2d.b2Mul(xf1, (-1.0, 0.0))) sd1.setVertex(1, box2d.b2Mul(xf1, (1.0, 0.0))) sd1.setVertex(2, box2d.b2Mul(xf1, (0.0, 0.5))) sd1.density = 2.0 xf2 = box2d.b2XForm() xf2.R.Set(-0.3524 * box2d.b2_pi) xf2.position = box2d.b2Mul(xf2.R, (-1.0, 0.0)) sd2=box2d.b2PolygonDef() sd2.vertexCount = 3 sd2.setVertex(0, box2d.b2Mul(xf2, (-1.0, 0.0))) sd2.setVertex(1, box2d.b2Mul(xf2, (1.0, 0.0))) sd2.setVertex(2, box2d.b2Mul(xf2, (0.0, 0.5))) sd2.density = 2.0 for i in range(10): x = box2d.b2Random(-0.1, 0.1) bd=box2d.b2BodyDef() bd.position = (x, 2.05 + 2.5 * i) bd.angle = 0.0 body = self.world.CreateBody(bd) body.CreateShape(sd1) body.CreateShape(sd2) body.SetMassFromShapes() sd_bottom=box2d.b2PolygonDef() sd_bottom.SetAsBox( 1.5, 0.15 ) sd_bottom.density = 4.0 sd_left=box2d.b2PolygonDef() sd_left.SetAsBox(0.15, 2.7, (-1.45, 2.35), 0.2) sd_left.density = 4.0 sd_right=box2d.b2PolygonDef() sd_right.SetAsBox(0.15, 2.7, (1.45, 2.35), -0.2) sd_right.density = 4.0 bd=box2d.b2BodyDef() bd.position = ( 0.0, 2.0 ) body = self.world.CreateBody(bd) body.CreateShape(sd_bottom) body.CreateShape(sd_left) body.CreateShape(sd_right) body.SetMassFromShapes() if __name__=="__main__": main(CompoundShapes) python-box2d-2.0.2+svn20100109.244/testbed/test_VaryingFriction.py0000644000000000000000000000606311135461416022664 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class VaryingFriction (Framework): name="VaryingFriction" def __init__(self): super(VaryingFriction, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 20.0) bd=box2d.b2BodyDef() bd.position = (0.0, -20.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(13.0, 0.25) bd=box2d.b2BodyDef() bd.position = (-4.0, 22.0) bd.angle = -0.25 ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.25, 1.0) bd=box2d.b2BodyDef() bd.position = (10.5, 19.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(13.0, 0.25) bd=box2d.b2BodyDef() bd.position = (4.0, 14.0) bd.angle = 0.25 ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.25, 1.0) bd=box2d.b2BodyDef() bd.position = (-10.5, 11.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(13.0, 0.25) bd=box2d.b2BodyDef() bd.position = (-4.0, 6.0) bd.angle = -0.25 ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 0.5) sd.density = 25.0 friction = [0.75, 0.5, 0.35, 0.1, 0.0] for i in range(5): bd=box2d.b2BodyDef() bd.position = (-15.0 + 4.0 * i, 28.0) body = self.world.CreateBody(bd) sd.friction = friction[i] body.CreateShape(sd) body.SetMassFromShapes() if __name__=="__main__": main(VaryingFriction) python-box2d-2.0.2+svn20100109.244/testbed/pygame_main.py0000644000000000000000000011056211151077147021000 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. """ Keys: F1 - toggle menu (can greatly improve fps) F5 - save state F7 - load state Space - shoot projectile Z/X - zoom Escape - quit Other keys can be set by the individual test Mouse: Left click - select/drag body (creates mouse joint) Right click - pan Shift+Left - drag to create a directional projectile Scroll - zoom You can easily add your own tests based on test_empty. -kne """ import pygame import Box2D as box2d from pygame.locals import * from settings import fwSettings from pgu import gui # Use psyco if available try: import psyco psyco.full() except ImportError: pass class fwDestructionListener(box2d.b2DestructionListener): """ The destruction listener callback: "SayGoodbye" is called when a joint or shape is deleted. """ test = None def __init__(self): super(fwDestructionListener, self).__init__() def SayGoodbye(self, object): if isinstance(object, box2d.b2Joint): if self.test.mouseJoint==object: self.test.mouseJoint=None else: self.test.JointDestroyed(object) elif isinstance(object, box2d.b2Shape): self.test.ShapeDestroyed(object) class fwBoundaryListener(box2d.b2BoundaryListener): """ The boundary listener callback: Violation is called when the specified body leaves the world AABB. """ test = None def __init__(self): super(fwBoundaryListener, self).__init__() def Violation(self, body): # So long as it's not the user-created bomb, let the test know that # the specific body has left the world AABB if self.test.bomb != body: self.test.BoundaryViolated(body) class fwContactTypes: """ Acts as an enum, holding the types necessary for contacts: Added, persisted, and removed """ contactUnknown = 0 contactAdded = 1 contactPersisted = 2 contactRemoved = 3 class fwContactPoint: """ Structure holding the necessary information for a contact point. All of the information is copied from the contact listener callbacks. """ shape1 = None shape2 = None normal = None position = None velocity = None id = None state = 0 class fwContactListener(box2d.b2ContactListener): """ Handles all of the contact states passed in from Box2D. """ test = None def __init__(self): super(fwContactListener, self).__init__() def handleCall(self, state, point): if not self.test: return cp = fwContactPoint() cp.shape1 = point.shape1 cp.shape2 = point.shape2 cp.position = point.position.copy() cp.normal = point.normal.copy() cp.id = point.id cp.state = state self.test.points.append(cp) def Add(self, point): self.handleCall(fwContactTypes.contactAdded, point) def Persist(self, point): self.handleCall(fwContactTypes.contactPersisted, point) def Remove(self, point): self.handleCall(fwContactTypes.contactRemoved, point) class fwDebugDraw(box2d.b2DebugDraw): """ This debug draw class accepts callbacks from Box2D (which specifies what to draw) and handles all of the rendering. If you are writing your own game, you likely will not want to use debug drawing. Debug drawing, as its name implies, is for debugging. """ circle_segments = 16 surface = None viewZoom = 1.0 viewCenter = None viewOffset = None width, height = 0, 0 def __init__(self): super(fwDebugDraw, self).__init__() def _setValues(self, viewZoom, viewCenter, viewOffset, width, height): """ Sets the view zoom, center, offset, and width and height of the screen such that access to the main window is unnecessary. """ self.viewZoom=viewZoom self.viewCenter=viewCenter self.viewOffset=viewOffset self.width = width self.height = height def convertColor(self, color): """ Take a floating point color in range (0..1,0..1,0..1) and convert it to (255,255,255) """ if isinstance(color, box2d.b2Color): return (int(255*color.r), int(255*color.g), int(255*color.b)) return (int(255*color[0]), int(255*color[1]), int(255*color[2])) def DrawPoint(self, p, size, color): """ Draw a single point at point p given a pixel size and color. """ self.DrawCircle(p, size/self.viewZoom, color, drawwidth=0) def DrawAABB(self, aabb, color): """ Draw a wireframe around the AABB with the given color. """ points = [self.toScreen(p) for p in [ (aabb.lowerBound.x, aabb.lowerBound.y ), (aabb.upperBound.x, aabb.lowerBound.y ), (aabb.upperBound.x, aabb.upperBound.y ), (aabb.lowerBound.x, aabb.upperBound.y ), ] ] pygame.draw.aalines(self.surface, color, True, points) def DrawSegment(self, p1, p2, color): """ Draw the line segment from p1-p2 with the specified color. """ color = self.convertColor(color) pygame.draw.aaline(self.surface, color, self.toScreen_v(p1), self.toScreen_v(p2)) def DrawXForm(self, xf): """ Draw the transform xf on the screen """ p1 = xf.position k_axisScale = 0.4 p2 = self.toScreen_v(p1 + k_axisScale * xf.R.col1) p3 = self.toScreen_v(p1 + k_axisScale * xf.R.col2) p1 = self.toScreen_v(p1) color = (255,0,0) pygame.draw.aaline(self.surface, color, p1, p2) color = (0,255,0) pygame.draw.aaline(self.surface, color, p1, p3) def DrawCircle(self, center, radius, color, drawwidth=1): """ Draw a wireframe circle given the b2Vec2 center_v, radius, axis of orientation and color. """ color = self.convertColor(color) radius *= self.viewZoom if radius < 1: radius = 1 else: radius = int(radius) center = self.toScreen_v(center) pygame.draw.circle(self.surface, color, center, radius, drawwidth) def DrawSolidCircle(self, center_v, radius, axis, color): """ Draw a solid circle given the b2Vec2 center_v, radius, axis of orientation and color. """ color = self.convertColor(color) radius *= self.viewZoom if radius < 1: radius = 1 else: radius = int(radius) center = self.toScreen_v(center_v) pygame.draw.circle(self.surface, (color[0]/2, color[1]/2, color[1]/2, 127), center, radius, 0) pygame.draw.circle(self.surface, color, center, radius, 1) p = radius * axis pygame.draw.aaline(self.surface, (255,0,0), center, (center[0] - p.x, center[1] + p.y)) def DrawPolygon(self, in_vertices, vertexCount, color): """ Draw a wireframe polygon given the world vertices in_vertices (tuples) with the specified color. """ color = self.convertColor(color) vertices = [self.toScreen(v) for v in in_vertices] pygame.draw.polygon(self.surface, color, vertices, 1) def DrawSolidPolygon(self, in_vertices, vertexCount, color): """ Draw a filled polygon given the world vertices in_vertices (tuples) with the specified color. """ color = self.convertColor(color) vertices = [self.toScreen(v) for v in in_vertices] pygame.draw.polygon(self.surface, (color[0]/2, color[1]/2, color[1]/2, 127), vertices, 0) pygame.draw.polygon(self.surface, color, vertices, 1) def toScreen_v(self, pt): """ Input: pt - a b2Vec2 in world coordinates Output: (x, y) - a tuple in screen coordinates """ return (int((pt.x * self.viewZoom) - self.viewOffset.x), int(self.height - ((pt.y * self.viewZoom) - self.viewOffset.y))) def toScreen(self, pt): """ Input: (x, y) - a tuple in world coordinates Output: (x, y) - a tuple in screen coordinates """ return ((pt[0] * self.viewZoom) - self.viewOffset.x, self.height - ((pt[1] * self.viewZoom) - self.viewOffset.y)) def scaleValue(self, value): """ Input: value - unscaled value Output: scaled value according to the view zoom ratio """ return value/self.viewZoom class fwGUI(gui.Table): """ Deals with the initialization and changing the settings based on the GUI controls. Callbacks are not used, but the checkboxes and sliders are polled by the main loop. """ checkboxes =( ("Warm Starting", "enableWarmStarting"), ("Time of Impact", "enableTOI"), ("Draw", None), ("Shapes", "drawShapes"), ("Joints", "drawJoints"), ("Controllers", "drawControllers"), ("Core Shapes", "drawCoreShapes"), ("AABBs", "drawAABBs"), ("OBBs", "drawOBBs"), ("Pairs", "drawPairs"), ("Contact Points", "drawContactPoints"), ("Contact Normals", "drawContactNormals"), ("Center of Masses", "drawCOMs"), ("Statistics", "drawStats"), ("FPS", "drawFPS"), ("Control", None), ("Pause", "pause"), ("Single Step", "singleStep") ) form = None def __init__(self,settings, **params): # The framework GUI is just basically a HTML-like table. # There are 2 columns, and basically everything is right-aligned. gui.Table.__init__(self,**params) self.form=gui.Form() fg = (255,255,255) # "Hertz" self.tr() self.td(gui.Label("F1: Toggle Menu",color=(255,0,0)),align=1,colspan=2) self.tr() self.td(gui.Label("Hertz",color=fg),align=1,colspan=2) # Hertz slider self.tr() e = gui.HSlider(settings.hz,5,200,size=20,width=100,height=16,name='hz') self.td(e,colspan=2,align=1) # "Vel Iters" self.tr() self.td(gui.Label("Vel Iters",color=fg),align=1,colspan=2) # Velocity Iterations slider (min 1, max 500) self.tr() e = gui.HSlider(settings.velocityIterations,1,500,size=20,width=100,height=16,name='velIters') self.td(e,colspan=2,align=1) # "Pos Iters" self.tr() self.td(gui.Label("Pos Iters",color=fg),align=1,colspan=2) # Position Iterations slider (min 0, max 100) self.tr() e = gui.HSlider(settings.positionIterations,0,100,size=20,width=100,height=16,name='posIters') self.td(e,colspan=2,align=1) # Add each of the checkboxes. for text, variable in self.checkboxes: self.tr() if variable == None: # Checkboxes that have no variable (i.e., None) are just labels. self.td(gui.Label(text, color=fg), align=1, colspan=2) else: # Add the label and then the switch/checkbox self.td(gui.Label(text, color=fg), align=1) self.td(gui.Switch(value=getattr(settings, variable),name=variable)) def updateGUI(self, settings): """ Change all of the GUI elements based on the current settings """ for text, variable in self.checkboxes: if not variable: continue if hasattr(settings, variable): self.form[variable].value = getattr(settings, variable) # Now do the sliders self.form['hz'].value = settings.hz self.form['posIters'].value = settings.positionIterations self.form['velIters'].value = settings.velocityIterations def updateSettings(self, settings): """ Change all of the settings based on the current state of the GUI. """ for text, variable in self.checkboxes: if variable == None: continue setattr(settings, variable, self.form[variable].value) # Now do the sliders settings.hz = int(self.form['hz'].value) settings.positionIterations = int(self.form['posIters'].value) settings.velocityIterations = int(self.form['velIters'].value) # If we're in single-step mode, update the GUI to reflect that. if settings.singleStep: settings.pause=True self.form['pause'].value = True self.form['singleStep'].value = False class Framework(object): """ The main testbed framework. It handles basically everything: * The initialization of pygame, Box2D * Contains the main loop * Handles all user input. You should derive your class from this one to implement your own tests. See test_Empty.py or any of the other tests for more information. """ name = "None" # Box2D-related worldAABB = None points = [] world = None bomb = None mouseJoint = None settings = fwSettings bombSpawning = False bombSpawnPoint = None mouseWorld = None destroyList = [] # Box2D-callbacks destructionListener= None boundaryListener = None contactListener = None debugDraw = None # Screen/rendering-related _viewZoom = 10.0 _viewCenter = None _viewOffset = None screenSize = None rMouseDown = False textLine = 30 font = None fps = 0 # GUI-related (PGU) gui_app = None gui_table = None def __init__(self): # Box2D Initialization self.worldAABB=box2d.b2AABB() self.worldAABB.lowerBound = (-200.0, -100.0) self.worldAABB.upperBound = ( 200.0, 200.0) gravity = (0.0, -10.0) doSleep = True self.world = box2d.b2World(self.worldAABB, gravity, doSleep) self.destructionListener = fwDestructionListener() self.boundaryListener = fwBoundaryListener() self.contactListener = fwContactListener() self.debugDraw = fwDebugDraw() self.destructionListener.test = self self.boundaryListener.test = self self.contactListener.test = self self.world.SetDestructionListener(self.destructionListener) self.world.SetBoundaryListener(self.boundaryListener) self.world.SetContactListener(self.contactListener) self.world.SetDebugDraw(self.debugDraw) # Pygame Initialization if fwSettings.onlyInit: # testing mode doesn't initialize pygame return pygame.init() caption= "Python Box2D Testbed - " + self.name pygame.display.set_caption(caption) self.screen = pygame.display.set_mode( (640,480) ) self.debugDraw.surface = self.screen self.screenSize = box2d.b2Vec2(*self.screen.get_size()) try: self.font = pygame.font.Font(None, 15) except IOError: try: self.font = pygame.font.Font("freesansbold.ttf", 15) except IOError: print "Unable to load default font or 'freesansbold.ttf'" print "Disabling text drawing." self.DrawString = lambda x,y,z: 0 # GUI Initialization self.gui_app = gui.App() self.gui_table=fwGUI(self.settings) container = gui.Container(align=1,valign=-1) container.add(self.gui_table,0,0) self.gui_app.init(container) self.viewCenter = (0,10.0*20.0) def setCenter(self, value): """ Updates the view offset based on the center of the screen. Tells the debug draw to update its values also. """ if isinstance(value, box2d.b2Vec2): self._viewCenter = value.copy() elif isinstance(value, (list, tuple)): self._viewCenter = box2d.b2Vec2( *value ) else: raise ValueError, 'Expected b2Vec2 or sequence' self._viewOffset = self._viewCenter - self.screenSize/2 self.debugDraw._setValues(self.viewZoom, self.viewCenter, self.viewOffset, self.screenSize.x, self.screenSize.y) def setZoom(self, zoom): self._viewZoom = zoom self.debugDraw.viewZoom = zoom viewZoom = property(lambda self: self._viewZoom, setZoom, doc='Zoom factor for the display') viewCenter = property(lambda self: self._viewCenter, setCenter, doc='Screen center in camera coordinates') viewOffset = property(lambda self: self._viewOffset, doc='The offset of the top-left corner of the screen') def checkEvents(self): """ Check for pygame events (mainly keyboard/mouse events). Passes the events onto the GUI also. """ for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): return False elif event.type == KEYDOWN: self._Keyboard_Event(event.key) elif event.type == MOUSEBUTTONDOWN: p = self.ConvertScreenToWorld(*event.pos) if event.button == 1: # left mods = pygame.key.get_mods() if mods & KMOD_LSHIFT: self.ShiftMouseDown( p ) else: self.MouseDown( p ) elif event.button == 2: #middle pass elif event.button == 3: #right self.rMouseDown = True elif event.button ==4: self.viewZoom *= 1.1 elif event.button == 5: self.viewZoom /= 1.1 elif event.type == MOUSEBUTTONUP: p = self.ConvertScreenToWorld(*event.pos) if event.button == 3: #right self.rMouseDown = False else: self.MouseUp(p) elif event.type == MOUSEMOTION: p = self.ConvertScreenToWorld(*event.pos) self.MouseMove(p) if self.rMouseDown: self.viewCenter -= (event.rel[0], -event.rel[1]) self.gui_app.event(event) #Pass the event to the GUI return True def run(self): """ Main loop. Continues to run while checkEvents indicates the user has requested to quit. Updates the screen and tells the GUI to paint itself. """ running = True clock = pygame.time.Clock() while running: running = self.checkEvents() self.screen.fill( (0,0,0) ) # Check keys that should be checked every loop (not only on initial keydown) self.CheckKeys() # Run the simulation loop self.SimulationLoop() if self.settings.drawMenu: self.gui_app.paint(self.screen) pygame.display.flip() clock.tick(self.settings.hz) self.fps = clock.get_fps() def Step(self, settings): """ The main physics step. Takes care of physics drawing (callbacks are executed after the world.Step() ) and drawing additional information. """ # Don't do anything if the setting's Hz are <= 0 if settings.hz > 0.0: timeStep = 1.0 / settings.hz else: timeStep = 0.0 # If paused, display so if settings.pause: if settings.singleStep: settings.singleStep=False else: timeStep = 0.0 self.DrawStringCR("****PAUSED****", (200,0,0)) # Set the flags based on what the settings show (uses a bitwise or mask) flag_info = [ (settings.drawShapes, box2d.b2DebugDraw.e_shapeBit), (settings.drawJoints, box2d.b2DebugDraw.e_jointBit), (settings.drawControllers,box2d.b2DebugDraw.e_controllerBit), (settings.drawCoreShapes, box2d.b2DebugDraw.e_coreShapeBit), (settings.drawAABBs, box2d.b2DebugDraw.e_aabbBit), (settings.drawOBBs, box2d.b2DebugDraw.e_obbBit), (settings.drawPairs, box2d.b2DebugDraw.e_pairBit), (settings.drawCOMs, box2d.b2DebugDraw.e_centerOfMassBit), ] flags = 0 for setting, flag in flag_info: if setting: flags |= flag self.debugDraw.SetFlags(flags) # Set the other settings that aren't contained in the flags self.world.SetWarmStarting(settings.enableWarmStarting) self.world.SetContinuousPhysics(settings.enableTOI) # Reset the collision points self.points = [] # Tell Box2D to step self.world.Step(timeStep, settings.velocityIterations, settings.positionIterations) self.world.Validate() # Destroy bodies that have left the world AABB (can be removed if not using pickling) for obj in self.destroyList: self.world.DestroyBody(obj) self.destroyList = [] # If the bomb is frozen, get rid of it. if self.bomb and self.bomb.IsFrozen(): self.world.DestroyBody(self.bomb) self.bomb = None # Take care of additional drawing (stats, fps, mouse joint, slingshot bomb, contact points) if settings.drawStats: self.DrawStringCR("proxies(max) = %d(%d), pairs(max) = %d(%d)" % ( self.world.GetProxyCount(), box2d.b2_maxProxies, self.world.GetPairCount(), box2d.b2_maxPairs) ) self.DrawStringCR("bodies/contacts/joints = %d/%d/%d" % (self.world.GetBodyCount(), self.world.GetContactCount(), self.world.GetJointCount())) self.DrawStringCR("hz %d vel/pos iterations %d/%d" % (settings.hz, settings.velocityIterations, settings.positionIterations)) self.DrawStringCR("heap bytes = %d" % box2d.cvar.b2_byteCount) if settings.drawFPS: self.DrawStringCR("FPS %d" % self.fps) # If there's a mouse joint, draw the connection between the object and the current pointer position. if self.mouseJoint: body = self.mouseJoint.GetBody2() p1 = body.GetWorldPoint(self.mouseJoint.localAnchor) p2 = self.mouseJoint.target self.debugDraw.DrawPoint(p1, settings.pointSize, (0,1.0,0)) self.debugDraw.DrawPoint(p2, settings.pointSize, (0,1.0,0)) self.debugDraw.DrawSegment(p1, p2, (0.8,0.8,0.8)) # Draw the slingshot bomb if self.bombSpawning: self.debugDraw.DrawPoint(self.bombSpawnPoint, settings.pointSize, (0,0,1.0)) self.debugDraw.DrawSegment(self.bombSpawnPoint, self.mouseWorld, (0.8,0.8,0.8)) # Draw each of the contact points in different colors. if self.settings.drawContactPoints: #k_impulseScale = 0.1 k_axisScale = 0.3 for point in self.points: if point.state == fwContactTypes.contactAdded: self.debugDraw.DrawPoint(point.position, settings.pointSize, (0.3, 0.95, 0.3)) elif point.state == fwContactTypes.contactPersisted: self.debugDraw.DrawPoint(point.position, settings.pointSize, (0.3, 0.3, 0.95)) else: #elif point.state == fwContactTypes.contactRemoved: self.debugDraw.DrawPoint(point.position, settings.pointSize, (0.95, 0.3, 0.3)) if settings.drawContactNormals: p1 = point.position p2 = p1 + k_axisScale * point.normal self.debugDraw.DrawSegment(p1, p2, (0.4, 0.9, 0.4)) def pickle_load(self, fn, set_vars=True, additional_vars=[]): """ Load the pickled world in file fn. additional_vars is a dictionary to be populated with the loaded variables. """ import cPickle as pickle try: world, variables = pickle.load(open(fn, 'rb')) world = world._pickle_finalize() variables = box2d.pickle_fix(world, variables, 'load') except Exception, s: print 'Error while loading world: ', s return self.world = world self.bomb = None self.bombSpawning = False self.points = [] if set_vars: # reset the additional saved variables: for var, value in variables.items(): if hasattr(self, var): setattr(self, var, value) else: print 'Unknown property %s=%s' % (var, value) # have to reset a few things that can't be saved: self.world.SetDestructionListener(self.destructionListener) self.world.SetBoundaryListener(self.boundaryListener) self.world.SetContactListener(self.contactListener) self.world.SetDebugDraw(self.debugDraw) print 'Loaded from %s' % fn return variables def pickle_save(self, fn, additional_vars={}): import cPickle as pickle if self.mouseJoint: self.MouseUp(self.mouseWorld) # remove a mouse joint if it exists if not additional_vars and hasattr(self, '_pickle_vars'): additional_vars=dict((var, getattr(self, var)) for var in self._pickle_vars) save_values = [self.world, box2d.pickle_fix(self.world, additional_vars, 'save')] try: pickle.dump(save_values, open(fn, 'wb')) except Exception, s: print 'Pickling failed: ', s return print 'Saved to %s' % fn def _Keyboard_Event(self, key): """ Internal keyboard event, don't override this. Checks for the initial keydown of the basic testbed keys. Passes the unused ones onto the test via the Keyboard() function. """ if key==K_z: # Zoom in self.viewZoom = min(1.1 * self.viewZoom, 20.0) elif key==K_x: # Zoom out self.viewZoom = max(0.9 * self.viewZoom, 0.02) elif key==K_SPACE: # Launch a bomb self.LaunchRandomBomb() elif key==K_F1: # Toggle drawing the menu self.settings.drawMenu = not self.settings.drawMenu elif key==K_F5: # Save state self.pickle_save('pickle_output_%s' % self.name) elif key==K_F7: # Load state self.pickle_load('pickle_output_%s' % self.name) else: # Inform the test of the key press self.Keyboard(key) def ShiftMouseDown(self, p): """ Indicates that there was a left click at point p (world coordinates) with the left shift key being held down. """ self.mouseWorld = p if not self.mouseJoint: self.SpawnBomb(p) def MouseDown(self, p): """ Indicates that there was a left click at point p (world coordinates) """ if self.mouseJoint != None: return # Create a mouse joint on the selected body (assuming it's dynamic) # Make a small box. aabb = box2d.b2AABB() aabb.lowerBound = p - (0.001, 0.001) aabb.upperBound = p + (0.001, 0.001) # Query the world for overlapping shapes. body = None k_maxCount = 10 # maximum amount of shapes to return (count, shapes) = self.world.Query(aabb, k_maxCount) for shape in shapes: shapeBody = shape.GetBody() if not shapeBody.IsStatic() and shapeBody.GetMass() > 0.0: if shape.TestPoint(shapeBody.GetXForm(), p): # is it inside? body = shapeBody break if body: # A body was selected, create the mouse joint md = box2d.b2MouseJointDef() md.body1 = self.world.GetGroundBody() md.body2 = body md.target = p md.maxForce= 1000.0 * body.GetMass() self.mouseJoint = self.world.CreateJoint(md).getAsType() body.WakeUp() def MouseUp(self, p): """ Left mouse button up. """ if self.mouseJoint: self.world.DestroyJoint(self.mouseJoint) self.mouseJoint = None if self.bombSpawning: self.CompleteBombSpawn(p) def MouseMove(self, p): """ Mouse moved to point p, in world coordinates. """ self.mouseWorld = p if self.mouseJoint: self.mouseJoint.SetTarget(p) def SpawnBomb(self, worldPt): """ Begins the slingshot bomb by recording the initial position. Once the user drags the mouse and releases it, then CompleteBombSpawn will be called and the actual bomb will be released. """ self.bombSpawnPoint = worldPt.copy() self.bombSpawning = True def CompleteBombSpawn(self, p): """ Create the slingshot bomb based on the two points (from the worldPt passed to SpawnBomb to p passed in here) """ if not self.bombSpawning: return multiplier = 30.0 vel = self.bombSpawnPoint - p vel *= multiplier self.LaunchBomb(self.bombSpawnPoint, vel) self.bombSpawning = False def LaunchBomb(self, position, velocity): """ A bomb is a simple circle which has the specified position and velocity. position and velocity must be b2Vec2's. """ if self.bomb: self.world.DestroyBody(self.bomb) self.bomb = None bd = box2d.b2BodyDef() bd.allowSleep = True bd.position = position bd.isBullet = True self.bomb = self.world.CreateBody(bd) self.bomb.SetLinearVelocity(velocity) sd = box2d.b2CircleDef() sd.radius = 0.3 sd.density = 20.0 sd.restitution = 0.1 minV = position - (0.3,0.3) maxV = position + (0.3,0.3) aabb = box2d.b2AABB() aabb.lowerBound = minV aabb.upperBound = maxV if self.world.InRange(aabb): self.bomb.CreateShape(sd) self.bomb.SetMassFromShapes() def LaunchRandomBomb(self): """ Create a new bomb and launch it at the testbed. """ p = box2d.b2Vec2( box2d.b2Random(-15.0, 15.0), 30.0 ) v = -5.0 * p self.LaunchBomb(p, v) def CheckKeys(self): """ Check the keys that are evaluated on every main loop iteration. I.e., they aren't just evaluated when first pressed down """ pygame.event.pump() self.keys = keys = pygame.key.get_pressed() if keys[K_LEFT]: self.viewCenter -= (0.5, 0) elif keys[K_RIGHT]: self.viewCenter += (0.5, 0) if keys[K_UP]: self.viewCenter += (0, 0.5) elif keys[K_DOWN]: self.viewCenter -= (0, 0.5) if keys[K_HOME]: self.viewZoom = 1.0 self.viewCenter = (0.0, 20.0) def SimulationLoop(self): """ The main simulation loop. Don't override this, override Step instead. """ # Reset the text line to start the text from the top self.textLine = 15 # Draw the name of the test running self.DrawStringCR(self.name, (127,127,255)) # Update the settings based on the GUI self.gui_table.updateSettings(self.settings) # Do the main physics step self.Step(self.settings) # In case during the step the settings changed, update the GUI reflecting # those settings. self.gui_table.updateGUI(self.settings) def ConvertScreenToWorld(self, x, y): """ Return a b2Vec2 in world coordinates of the passed in screen coordinates x, y """ return box2d.b2Vec2((x + self.viewOffset.x) / self.viewZoom, ((self.screenSize.y - y + self.viewOffset.y) / self.viewZoom)) def DrawString(self, x, y, str, color=(229,153,153,255)): """ Draw some text, str, at screen coordinates (x, y). """ text = self.font.render(str, True, color) self.screen.blit(text, (x,y)) def DrawStringCR(self, str, color=(229,153,153,255)): """ Draw some text at the top status lines and advance to the next line. """ text = self.font.render(str, True, color) self.screen.blit(text, (5,self.textLine)) self.textLine += 15 def __del__(self): pass # These can/should be implemented in the subclass: (Step() also if necessary) # See test_Empty.py for a simple example. def ShapeDestroyed(self, shape): """ Callback indicating 'shape' has been destroyed. """ pass def JointDestroyed(self, joint): """ Callback indicating 'joint' has been destroyed. """ pass def BoundaryViolated(self, body): """ Callback indicating 'body' has left the world AABB. """ # Be sure to check if any of these bodies are ones your game # stores. Using a reference to a deleted object will cause a crash. # e.g., # if body==self.player: # self.player=None # # The following checks for generic usage by testing the pickle variables. if hasattr(self, '_pickle_vars'): for var in self._pickle_vars: value=getattr(self, var) if body==value: setattr(self, var, None) elif isinstance(value, list): if body in value: value.remove(body) # Not destroying bodies outside the world AABB will cause # pickling to fail, so destroy it after the next step: self.destroyList.append(body) def Keyboard(self, key): """ Callback indicating 'key' has been pressed down. The key is from pygame.locals.K_*: from pygame.locals import * ... if key == K_z: pass """ pass def main(test_class): """ Loads the test class and executes it. """ print "Loading %s..." % test_class.name test = test_class() if fwSettings.onlyInit: return test.run() if __name__=="__main__": from test_empty import Empty main(Empty) python-box2d-2.0.2+svn20100109.244/testbed/test_PyramidStaticEdges.py0000644000000000000000000000433211135471136023271 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class PyramidStaticEdges (Framework): name="PyramidStaticEdges" def __init__(self): super(PyramidStaticEdges, self).__init__() verts = [ (50.0,0.0), (-50.0,0.0) ] bd=box2d.b2BodyDef() bd.position = ( 0.0, 0.0 ) body = self.world.CreateBody(bd) edgeDef = box2d.b2EdgeChainDef() edgeDef.setVertices_tuple(verts) edgeDef.isALoop = False body.CreateShape(edgeDef) #body.SetMassFromShapes() sd=box2d.b2PolygonDef() a = 0.5 sd.SetAsBox(a, a) sd.density = 5.0 x=box2d.b2Vec2(-10.0, 1.0) deltaX=(0.5625, 2.0) deltaY=(1.125, 0.0) for i in range(25): y = x.copy() for j in range(i, 25): bd=box2d.b2BodyDef() bd.position = y body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() y += deltaY x += deltaX if __name__=="__main__": main(PyramidStaticEdges) python-box2d-2.0.2+svn20100109.244/testbed/test_LineJoint.py0000644000000000000000000000423111135461416021435 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class LineJoint (Framework): name="LineJoint" def __init__(self): super(LineJoint, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() sd.SetAsBox(0.5, 2.0) sd.density = 1.0 bd=box2d.b2BodyDef() bd.position = (0.0, 7.0) body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() jd = box2d.b2LineJointDef() axis=box2d.b2Vec2(2.0, 1.0) axis.Normalize() jd.Initialize(ground, body, (0.0, 8.5), axis) jd.motorSpeed = 0.0 jd.maxMotorForce = 100.0 jd.enableMotor = True jd.lowerTranslation = -4.0 jd.upperTranslation = 4.0 jd.enableLimit = True self.world.CreateJoint(jd) if __name__=="__main__": main(LineJoint) python-box2d-2.0.2+svn20100109.244/testbed/settings.py0000644000000000000000000000626211156056674020362 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. class fwSettings(object): backend='pygame' # The default backend to use in ('pyglet', 'pygame') # Physics options hz=60.0 velocityIterations=10 positionIterations=8 enableWarmStarting=True # Makes physics results more accurate (see Box2D wiki) enableTOI=True # Calculate time of impact # Drawing drawStats=False drawShapes=True drawControllers=True drawJoints=True drawCoreShapes=False drawAABBs=False drawOBBs=False drawPairs=False drawContactPoints=False drawContactNormals=False drawContactForces=False drawFrictionForces=False drawFPS=True drawMenu=True # toggle by pressing F1 drawCOMs=False # Centers of mass pointSize=2.5 # pixel radius for drawing points # Miscellaneous testbed options pause=False singleStep=False onlyInit=False # run the test's initialization without graphics, and then quit (for testing) from optparse import OptionParser parser = OptionParser() list_options = [i for i in dir(fwSettings) if not i.startswith('_')] for opt_name in list_options: value = getattr(fwSettings, opt_name) if isinstance(value, bool): if value: parser.add_option('','--NO'+opt_name, dest=opt_name, default=value, action='store_'+str(not value).lower(), help="don't "+opt_name) else: parser.add_option('','--'+opt_name, dest=opt_name, default=value, action='store_'+str(not value).lower(), help=opt_name) else: if isinstance(value, int): opttype = 'int' elif isinstance(value, float): opttype = 'float' else: opttype = 'string' parser.add_option('','--'+opt_name, dest=opt_name, default=value, type=opttype, help='sets the %s option'%(opt_name,)) (fwSettings, args) = parser.parse_args() python-box2d-2.0.2+svn20100109.244/testbed/test_Pyramid.py0000644000000000000000000000401111135471136021143 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from test_main import * class Pyramid (Framework): name="Pyramid" def __init__(self): super(Pyramid, self).__init__() sd=box2d.b2PolygonDef() sd.SetAsBox(50.0, 10.0) bd=box2d.b2BodyDef() bd.position = (0.0, -10.0) ground = self.world.CreateBody(bd) ground.CreateShape(sd) sd=box2d.b2PolygonDef() a = 0.5 sd.SetAsBox(a, a) sd.density = 5.0 x=box2d.b2Vec2(-10.0, 0.75) deltaX=(0.5625, 2.0) deltaY=(1.125, 0.0) for i in range(25): y = x.copy() for j in range(i, 25): bd=box2d.b2BodyDef() bd.position = y body = self.world.CreateBody(bd) body.CreateShape(sd) body.SetMassFromShapes() y += deltaY x += deltaX if __name__=="__main__": main(Pyramid) python-box2d-2.0.2+svn20100109.244/testbed/cairo_main.py0000644000000000000000000004406011163233664020613 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008 kne / sirkne at gmail dot com # Cairo backend Copyright (c) 2009 Giorgos Giagas / giorgosg at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. from __future__ import division import math import time import operator import itertools import pygtk pygtk.require('2.0') import gtk, gobject, cairo import Box2D as box2d from settings import fwSettings import console from pygame_keycodes import * # Use psyco if available try: import psyco psyco.full() except ImportError: pass class FpsCount(object): def __init__(self, avg_count): self._list = [0 for i in range(avg_count)] self.oldest = 0 self.count = avg_count def __call__(self): new_time = time.time() self._list[self.oldest] = time.time() self.oldest = self.oldest + 1 if self.oldest + 1 < self.count else 0 avg_frame_time = (new_time - self._list[self.oldest]) / self.count return 1 / avg_frame_time class CairoDebugDraw(box2d.b2DebugDraw): def __init__(self): super(CairoDebugDraw, self).__init__() self.scale = 8 self.view = (-50.0, 50.0) # the upper left corner in b2world coords. self.line_width = 0.04 # in world units self.min_line_width = 1.0 # in screen units # some colors look bad when inverted self.colordict = {( 0, 0, 204): [0.0, 0.0, 0.8], (127, 229, 127): [0.56, 0.22, 0.0]} self.antialias = cairo.ANTIALIAS_NONE self.font_options = cairo.FontOptions() self.font_options.set_antialias(self.antialias) def draw_begin(self, drawing_area): width, height = drawing_area.window.get_size() region = gtk.gdk.region_rectangle((0, 0, width, height)) drawing_area.window.begin_paint_region(region) cr = self.cr = drawing_area.window.cairo_create() cr.set_antialias(self.antialias) cr.set_font_options(self.font_options) cr.rectangle(0, 0, width, height) cr.clip() cr.save() cr.set_source_rgb(1.0, 1.0, 1.0) cr.paint() cr.scale(self.scale, -self.scale) cr.translate(- self.view[0], - self.view[1]) if self.line_width * self.scale >= self.min_line_width: line_width = self.line_width else: line_width = self.min_line_width / self.scale cr.set_tolerance(0.2) cr.set_line_width(line_width) cr.set_line_join(cairo.LINE_JOIN_ROUND) cr.set_line_cap(cairo.LINE_CAP_ROUND) def draw_end(self, drawing_area): drawing_area.window.end_paint() def screen_to_world(self, pos): pos = (pos[0] / self.scale, -pos[1] / self.scale) pos = (pos[0] + self.view[0], pos[1] + self.view[1]) return pos def world_to_screen(self, pos): pos = (pos[0] * self.scale, -pos[0] * self.scale) pos = (pos[0] - (self.view[0]*self.scale), pos[1] - (-self.view[0]*self.scale)) return pos def convert_color(self, color): color = (color.r, color.g, color.b) lkup = tuple(int(c*255) for c in color) if lkup in self.colordict: return self.colordict[lkup] else: return [1-c for c in color] def DrawPolygon(self, vertices, vertex_count, color): cr = self.cr color = self.convert_color(color) cr.set_source_rgb(color[0], color[1], color[2]) cr.move_to(*vertices[0]) for v in vertices: cr.line_to(*v) cr.close_path() cr.stroke() def DrawSolidPolygon(self, vertices, vertex_count, color): cr = self.cr color = self.convert_color(color) cr.set_source_rgba(color[0], color[1], color[2], 0.7) cr.move_to(*vertices[0]) for v in vertices: cr.line_to(*v) cr.close_path() cr.fill_preserve() cr.set_source_rgb(color[0], color[1], color[2]) cr.stroke() def DrawCircle(self, center, radius, color): cr = self.cr color = self.convert_color(color) cr.set_source_rgb(color[0], color[1], color[2]) cr.arc(center.x, center.y, radius, 0, 2*math.pi) cr.stroke() def DrawSolidCircle(self, center, radius, axis, color): cr = self.cr color = self.convert_color(color) cr.set_source_rgba(color[0], color[1], color[2], 0.7) cr.arc(center.x, center.y, radius, 0, 2*math.pi) cr.fill_preserve() cr.set_source_rgb(color[0], color[1], color[2]) cr.stroke() p = radius * axis cr.move_to(center.x, center.y) cr.line_to(center.x + p.x, center.y + p.y) cr.stroke() def DrawSegment(self, v1, v2, color): color = self.convert_color(color) cr = self.cr cr.set_source_rgba(color[0], color[1], color[2], 0.5) cr.move_to(v1.x, v1.y) cr.line_to(v2.x, v2.y) cr.stroke() def DrawPoint(self, p, size, color): self.DrawCircle(p, size/self.scale, color) def DrawXForm(self, xf): cr = self.cr k_axis_scale = 0.4 p1 = xf.position p2 = p1 + xf.R.col1 * k_axis_scale p3 = p1 + xf.R.col2 * k_axis_scale cr.set_source_rgba(0,0,1,0.4) cr.move_to(p1.x, p1.y) cr.line_to(p2.x, p2.y) cr.stroke() cr.set_source_rgba(1,0,0,0.4) cr.move_to(p1.x, p1.y) cr.line_to(p3.x, p3.y) cr.stroke() class Framework(object): """ The main testbed framework. It handles basically everything: * The initialization of pygame, Box2D * Contains the main loop * Handles all user input. You should derive your class from this one to implement your own tests. See test_Empty.py or any of the other tests for more information. """ name = "None" # Box2D-related worldAABB = None points = [] world = None bomb = None settings = fwSettings bombSpawning = False bombSpawnPoint = None mouseWorld = None destroyList = [] # Box2D-callbacks destructionListener= None boundaryListener = None contactListener = None debugDraw = None def __init__(self): # Box2D Initialization self.worldAABB=box2d.b2AABB() self.worldAABB.lowerBound = (-200.0, -100.0) self.worldAABB.upperBound = ( 200.0, 200.0) gravity = (0.0, -10.0) doSleep = True self.world = box2d.b2World(self.worldAABB, gravity, doSleep) self.debugDraw = CairoDebugDraw() self.world.SetDebugDraw(self.debugDraw) settings = fwSettings self.flag_info = [ ('draw_shapes', settings.drawShapes, box2d.b2DebugDraw.e_shapeBit), ('draw_joints', settings.drawJoints, box2d.b2DebugDraw.e_jointBit), ('draw_controlers', settings.drawControllers, box2d.b2DebugDraw.e_controllerBit), ('draw_core_shapes', settings.drawCoreShapes, box2d.b2DebugDraw.e_coreShapeBit), ('draw_aabbs', settings.drawAABBs, box2d.b2DebugDraw.e_aabbBit), ('draw_obbs', settings.drawOBBs, box2d.b2DebugDraw.e_obbBit), ('draw_pairs', settings.drawPairs, box2d.b2DebugDraw.e_pairBit), ('draw_center_of_masses', settings.drawCOMs, box2d.b2DebugDraw.e_centerOfMassBit),] builder = self.builder = gtk.Builder() builder.add_from_file('cairo_main.xml') builder.connect_signals(self) #builder.get_object('messages_expander').set_expanded(True) self.drawing_area = builder.get_object('drawing_area') self.window = builder.get_object('window') self.window.set_title("Python Box2D Cairo Testbed - " + self.name) self.window.show_all() gobject.timeout_add(int(1/self.settings.hz*1000), self.SimulationLoop, priority=gobject.PRIORITY_LOW) # Need to check if this is dropping the overall fps #gobject.timeout_add(100, self.Draw, # priority=gobject.PRIORITY_DEFAULT_IDLE) builder.get_object('hertz').set_value(self.settings.hz) builder.get_object('position_iterations' ).set_value(self.settings.positionIterations) builder.get_object('velocity_iterations' ).set_value(self.settings.velocityIterations) builder.get_object('antialiasing' ).set_active(self.debugDraw.antialias == cairo.ANTIALIAS_DEFAULT) for widget, setting, b2 in self.flag_info: builder.get_object(widget).set_active(setting) self.scrolling = False self.hz_changed = False self.mouse_joint = None self.mouse_coords = (0,0) self.text_lines = [] self.fps = FpsCount(30) def on_window_destroy(self, widget): gtk.main_quit() def on_py_console_clicked(self, widget): pyconsole = console.gtk_console(self.window, {'world':self.world, 'framework':self}, 'python interactive console') self.window.set_data('PythonConsole', pyconsole) def on_step_button_clicked(self, widget): self.settings.pause = True self.SimulationLoop(True) def on_play_button_clicked(self, widget): self.settings.pause = False def on_pause_button_clicked(self, widget): self.settings.pause = True def on_draw_toggled(self, widget): active_flags = [flag[2] for flag in self.flag_info if self.builder.get_object(flag[0]).get_active()] + [0] self.debugDraw.SetFlags(reduce(operator.or_, active_flags)) def on_antialiasing_toggled(self, widget): antialiasing = self.builder.get_object('antialiasing').get_active() self.debugDraw.antialias = cairo.ANTIALIAS_DEFAULT if antialiasing\ else cairo.ANTIALIAS_NONE self.debugDraw.font_options.set_antialias(self.debugDraw.antialias) def on_velocity_iterations_value_changed(self, widget): self.settings.velocityIterations = widget.get_value_as_int() def on_position_iterations_value_changed(self, widget): self.settings.positionIterations = widget.get_value_as_int() def on_hertz_value_changed(self, widget): self.settings.hz = widget.get_value_as_int() self.hz_changed = True def on_drawing_area_key_press_event(self, widget, event): if event.keyval == K_z: #zoom in self.debugDraw.scale *= 1.1 elif event.keyval == K_x: #zoom out self.debugDraw.scale /= 1.1 else: self.Keyboard(event.keyval) def Keyboard(self, keyval): pass def on_drawing_area_button_press_event(self, widget, event): widget.grab_focus() if event.button == 3: self.scrolling = (event.x, event.y) elif event.button == 1: self.create_mouse_joint(event.x, event.y) def on_drawing_area_button_release_event(self, widget, event): if event.button == 3: self.scrolling = False elif event.button == 1 and self.mouse_joint: self.world.DestroyJoint(self.mouse_joint) self.mouse_joint = None def on_drawing_area_motion_notify_event(self, widget, event): if self.scrolling !=False: distance = (self.scrolling[0] - event.x, self.scrolling[1] - event.y) distance = (distance[0] / self.debugDraw.scale, - distance[1] / self.debugDraw.scale) self.debugDraw.view = (self.debugDraw.view[0] + distance[0], self.debugDraw.view[1] + distance[1]) self.scrolling = (event.x, event.y) if self.mouse_joint: world_coords = self.debugDraw.screen_to_world((event.x, event.y)) self.mouse_joint.SetTarget(world_coords) self.mouse_coords = (event.x, event.y) def on_drawing_area_scroll_event(self, widget, event): if event.direction not in (gtk.gdk.SCROLL_UP, gtk.gdk.SCROLL_DOWN): return # we keep the center of the screen in the same place as we zoom. da_res = self.drawing_area.window.get_size() s = self.debugDraw.scale view_w = (da_res[0] / (s*2) , - da_res[1] / (s*2)) world_center = (box2d.b2Vec2(view_w) + box2d.b2Vec2(self.debugDraw.view)) if event.direction == gtk.gdk.SCROLL_UP: self.debugDraw.scale *= 1.1 elif event.direction == gtk.gdk.SCROLL_DOWN: self.debugDraw.scale /= 1.1 s = self.debugDraw.scale view_w = (da_res[0] / (s*2), - da_res[1] / (s*2)) new_view = world_center - view_w self.debugDraw.view = (new_view.x, new_view.y) def create_mouse_joint(self, x, y): """ create a mouse joint to the body on world coordinates x, y """ if self.mouse_joint: return world_coord = box2d.b2Vec2(self.debugDraw.screen_to_world((x, y))) aabb = box2d.b2AABB() aabb.lowerBound = world_coord - (0.001, 0.001) aabb.upperBound = world_coord + (0.001, 0.001) max_count = 10 count, shapes = self.world.Query(aabb, max_count) body = (body for shape, body in ((shape, shape.GetBody()) for shape in shapes) if not body.IsStatic() and body.GetMass() > 0.0 and shape.TestPoint(body.GetXForm(), world_coord)) body = list(itertools.islice(body, 1)) body = body[0] if len(body) == 1 else None if body: md = box2d.b2MouseJointDef() md.body1 = self.world.GetGroundBody() md.body2 = body md.target = world_coord md.maxForce = 1000 * body.GetMass() self.mouse_joint = self.world.CreateJoint(md).getAsType() body.WakeUp() def run(self): """ Main loop. """ gtk.main() def Draw(self, settings=None): #print 'idle redrawing' self.world.Step(0, 0, 0) def draw_extra(self): if self.mouse_joint: body = self.mouse_joint.GetBody2() p1 = body.GetWorldPoint(self.mouse_joint.localAnchor) p2 = self.mouse_joint.target self.debugDraw.DrawSegment(p1, p2, box2d.b2Color(1, 1, 1)) #message_label = self.builder.get_object('messages_label') #if self.builder.get_object('messages_expander').get_expanded() == True: # self.builder.get_object('messages_label' # ).set_text('\n'.join(self.text_lines)) cr = self.debugDraw.cr cr.restore() cr.scale(1.5,1.5) pos = 20 for line in self.text_lines: cr.move_to(10, pos) cr.show_text(line) pos += 10 def SimulationLoop(self, ignore_pause=False): self.debugDraw.draw_begin(self.drawing_area) if ignore_pause or (self.settings.pause == False): self.text_lines = [] self.DrawStringCR("Fps: %.1f" % (self.fps(),)) self.Step(self.settings) else: self.Draw() self.draw_extra() self.debugDraw.draw_end(self.drawing_area) if self.hz_changed: gobject.timeout_add(int(1/self.settings.hz*1000), self.SimulationLoop, priority=gobject.PRIORITY_LOW) self.hz_changed = False return False else: return True def Step(self, settings): """ The main physics step. Takes care of physics drawing (callbacks are executed after the world.Step() ) """ timestep = 1/settings.hz self.world.Step(timestep, settings.velocityIterations, settings.positionIterations) def DrawStringCR(self, string): self.text_lines.append(string) def main(test_class): """ Loads the test class and executes it. """ print "Loading %s..." % test_class.name test = test_class() if fwSettings.onlyInit: return test.run() if __name__=="__main__": from test_empty import Empty main(Empty) python-box2d-2.0.2+svn20100109.244/LICENSE0000644000000000000000000000225111156663460015512 0ustar rootrootThis software is covered under the zlib license. The file console.py used by the testbed framework's cairo backend is GPL licenced. C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com Python version Copyright (c) 2008-2009 Ken Lauer / sirkne at gmail dot com Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. python-box2d-2.0.2+svn20100109.244/MANIFEST0000644000000000000000000003040411150552457015634 0ustar rootrootINSTALL LICENSE MANIFEST README __init__.py Box2D/Box2D-License.txt Box2D/Box2D.h Box2D/Box2D.i Box2D/Box2D_printing.i Box2D/Box2D_deprecated.i Box2D/Box2D_doxygen.i Box2D/Box2D_pickling.i Box2D/Box2D_userdata.i Box2D/Collision/Shapes/b2CircleShape.cpp Box2D/Collision/Shapes/b2CircleShape.h Box2D/Collision/Shapes/b2EdgeShape.cpp Box2D/Collision/Shapes/b2EdgeShape.h Box2D/Collision/Shapes/b2PolygonShape.cpp Box2D/Collision/Shapes/b2PolygonShape.h Box2D/Collision/Shapes/b2Shape.cpp Box2D/Collision/Shapes/b2Shape.h Box2D/Collision/b2BroadPhase.cpp Box2D/Collision/b2BroadPhase.h Box2D/Collision/b2CollideCircle.cpp Box2D/Collision/b2CollidePoly.cpp Box2D/Collision/b2Collision.cpp Box2D/Collision/b2Collision.h Box2D/Collision/b2Distance.cpp Box2D/Collision/b2PairManager.cpp Box2D/Collision/b2PairManager.h Box2D/Collision/b2TimeOfImpact.cpp Box2D/Common/Fixed.h Box2D/Common/b2BlockAllocator.cpp Box2D/Common/b2BlockAllocator.h Box2D/Common/b2Math.cpp Box2D/Common/b2Math.h Box2D/Common/b2Settings.cpp Box2D/Common/b2Settings.h Box2D/Common/b2StackAllocator.cpp Box2D/Common/b2StackAllocator.h Box2D/Common/jtypes.h Box2D/Dynamics/Contacts/b2CircleContact.cpp Box2D/Dynamics/Contacts/b2CircleContact.h Box2D/Dynamics/Contacts/b2Contact.cpp Box2D/Dynamics/Contacts/b2Contact.h Box2D/Dynamics/Contacts/b2ContactSolver.cpp Box2D/Dynamics/Contacts/b2ContactSolver.h Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h Box2D/Dynamics/Contacts/b2NullContact.h Box2D/Dynamics/Contacts/b2PolyAndCircleContact.cpp Box2D/Dynamics/Contacts/b2PolyAndCircleContact.h Box2D/Dynamics/Contacts/b2PolyAndEdgeContact.cpp Box2D/Dynamics/Contacts/b2PolyAndEdgeContact.h Box2D/Dynamics/Contacts/b2PolyContact.cpp Box2D/Dynamics/Contacts/b2PolyContact.h Box2D/Dynamics/Controllers/b2BuoyancyController.cpp Box2D/Dynamics/Controllers/b2BuoyancyController.h Box2D/Dynamics/Controllers/b2ConstantAccelController.cpp Box2D/Dynamics/Controllers/b2ConstantAccelController.h Box2D/Dynamics/Controllers/b2ConstantForceController.cpp Box2D/Dynamics/Controllers/b2ConstantForceController.h Box2D/Dynamics/Controllers/b2Controller.cpp Box2D/Dynamics/Controllers/b2Controller.h Box2D/Dynamics/Controllers/b2GravityController.cpp Box2D/Dynamics/Controllers/b2GravityController.h Box2D/Dynamics/Controllers/b2TensorDampingController.cpp Box2D/Dynamics/Controllers/b2TensorDampingController.h Box2D/Dynamics/Joints/b2DistanceJoint.cpp Box2D/Dynamics/Joints/b2DistanceJoint.h Box2D/Dynamics/Joints/b2GearJoint.cpp Box2D/Dynamics/Joints/b2GearJoint.h Box2D/Dynamics/Joints/b2Joint.cpp Box2D/Dynamics/Joints/b2Joint.h Box2D/Dynamics/Joints/b2LineJoint.cpp Box2D/Dynamics/Joints/b2LineJoint.h Box2D/Dynamics/Joints/b2MouseJoint.cpp Box2D/Dynamics/Joints/b2MouseJoint.h Box2D/Dynamics/Joints/b2PrismaticJoint.cpp Box2D/Dynamics/Joints/b2PrismaticJoint.h Box2D/Dynamics/Joints/b2PulleyJoint.cpp Box2D/Dynamics/Joints/b2PulleyJoint.h Box2D/Dynamics/Joints/b2RevoluteJoint.cpp Box2D/Dynamics/Joints/b2RevoluteJoint.h Box2D/Dynamics/b2Body.cpp Box2D/Dynamics/b2Body.h Box2D/Dynamics/b2ContactManager.cpp Box2D/Dynamics/b2ContactManager.h Box2D/Dynamics/b2Island.cpp Box2D/Dynamics/b2Island.h Box2D/Dynamics/b2World.cpp Box2D/Dynamics/b2World.h Box2D/Dynamics/b2WorldCallbacks.cpp Box2D/Dynamics/b2WorldCallbacks.h Box2D/Makefile Box2D/pybox2d_license_header.txt doc/manual.htm doc/manual_files/Python_testbed.png doc/manual_files/ajax.js doc/manual_files/ajaxwatch.js doc/manual_files/commonPrint.css doc/manual_files/convex_concave.gif doc/manual_files/distanceJoint.gif doc/manual_files/gearJoint.gif doc/manual_files/index.php doc/manual_files/poweredby_mediawiki_88x31.png doc/manual_files/prismaticJoint.gif doc/manual_files/pulleyJoint.gif doc/manual_files/revoluteJoint.gif doc/manual_files/wikibits.js misc/do_osx_setup.sh misc/do_win32_setup.cmd setup.py testbed/TriangleMesh.py testbed/data/themes/default/Vera.ttf testbed/data/themes/default/box.down.png testbed/data/themes/default/box.hover.png testbed/data/themes/default/box.normal.png testbed/data/themes/default/box.xcf testbed/data/themes/default/button.down.tga testbed/data/themes/default/button.hover.tga testbed/data/themes/default/button.normal.tga testbed/data/themes/default/check.png testbed/data/themes/default/checkbox.off.hover.tga testbed/data/themes/default/checkbox.off.normal.tga testbed/data/themes/default/checkbox.on.hover.tga testbed/data/themes/default/checkbox.on.normal.tga testbed/data/themes/default/config.txt testbed/data/themes/default/console.input.focus.png testbed/data/themes/default/console.input.normal.png testbed/data/themes/default/console.png testbed/data/themes/default/desktop.png testbed/data/themes/default/desktop.xcf testbed/data/themes/default/dialog.bar.png testbed/data/themes/default/dialog.close.down.tga testbed/data/themes/default/dialog.close.hover.tga testbed/data/themes/default/dialog.close.normal.tga testbed/data/themes/default/dialog.png testbed/data/themes/default/dot.down.png testbed/data/themes/default/dot.hover.png testbed/data/themes/default/dot.normal.png testbed/data/themes/default/dot.xcf testbed/data/themes/default/down.png testbed/data/themes/default/filebrowser.folder.png testbed/data/themes/default/generate.py testbed/data/themes/default/hslider.bar.hover.tga testbed/data/themes/default/hslider.bar.normal.tga testbed/data/themes/default/hslider.left.tga testbed/data/themes/default/hslider.right.tga testbed/data/themes/default/hslider.tga testbed/data/themes/default/idot.normal.png testbed/data/themes/default/input.focus.png testbed/data/themes/default/input.normal.png testbed/data/themes/default/left.png testbed/data/themes/default/list.item.down.png testbed/data/themes/default/list.item.hover.png testbed/data/themes/default/list.item.normal.png testbed/data/themes/default/list.png testbed/data/themes/default/listitem.down.tga testbed/data/themes/default/listitem.hover.tga testbed/data/themes/default/listitem.normal.tga testbed/data/themes/default/menu.down.tga testbed/data/themes/default/menu.hover.tga testbed/data/themes/default/menu.normal.tga testbed/data/themes/default/notes.txt testbed/data/themes/default/out.tga testbed/data/themes/default/progressbar.bar.tga testbed/data/themes/default/progressbar.tga testbed/data/themes/default/radio.off.hover.tga testbed/data/themes/default/radio.off.normal.tga testbed/data/themes/default/radio.on.hover.tga testbed/data/themes/default/radio.on.normal.tga testbed/data/themes/default/radio.png testbed/data/themes/default/rdot.down.png testbed/data/themes/default/rdot.hover.png testbed/data/themes/default/rdot.normal.png testbed/data/themes/default/right.png testbed/data/themes/default/sbox.normal.png testbed/data/themes/default/scroller.slide.bar.hover.tga testbed/data/themes/default/scroller.slide.bar.normal.tga testbed/data/themes/default/scroller.slide.h.tga testbed/data/themes/default/scroller.slide.v.tga testbed/data/themes/default/select.arrow.down.tga testbed/data/themes/default/select.arrow.hover.tga testbed/data/themes/default/select.arrow.normal.tga testbed/data/themes/default/select.arrow.png testbed/data/themes/default/select.option.hover.png testbed/data/themes/default/select.option.normal.png testbed/data/themes/default/select.options.png testbed/data/themes/default/select.selected.down.tga testbed/data/themes/default/select.selected.hover.tga testbed/data/themes/default/select.selected.normal.tga testbed/data/themes/default/slider.bar.hover.tga testbed/data/themes/default/slider.bar.normal.tga testbed/data/themes/default/slider.tga testbed/data/themes/default/tool.down.tga testbed/data/themes/default/tool.hover.tga testbed/data/themes/default/tool.normal.tga testbed/data/themes/default/up.png testbed/data/themes/default/vbox.normal.png testbed/data/themes/default/vdot.down.png testbed/data/themes/default/vdot.hover.png testbed/data/themes/default/vdot.normal.png testbed/data/themes/default/vsbox.normal.png testbed/data/themes/default/vslider.bar.hover.tga testbed/data/themes/default/vslider.bar.normal.tga testbed/data/themes/default/vslider.down.tga testbed/data/themes/default/vslider.tga testbed/data/themes/default/vslider.up.tga testbed/data/themes/default/x.png testbed/data/themes/gray/Vera.ttf testbed/data/themes/gray/box.down.png testbed/data/themes/gray/box.normal.png testbed/data/themes/gray/button.down.png testbed/data/themes/gray/button.normal.png testbed/data/themes/gray/checkbox.off.down.png testbed/data/themes/gray/checkbox.off.normal.png testbed/data/themes/gray/checkbox.on.down.png testbed/data/themes/gray/checkbox.on.normal.png testbed/data/themes/gray/config.txt testbed/data/themes/gray/console.input.focus.png testbed/data/themes/gray/console.input.normal.png testbed/data/themes/gray/console.png testbed/data/themes/gray/desktop.png testbed/data/themes/gray/dialog.bar.png testbed/data/themes/gray/dialog.close.down.png testbed/data/themes/gray/dialog.close.normal.png testbed/data/themes/gray/dialog.png testbed/data/themes/gray/filebrowser.folder.png testbed/data/themes/gray/input.focus.png testbed/data/themes/gray/input.normal.png testbed/data/themes/gray/list.item.normal.png testbed/data/themes/gray/list.png testbed/data/themes/gray/menu.down.png testbed/data/themes/gray/menu.hover.png testbed/data/themes/gray/menu.normal.png testbed/data/themes/gray/menu.option.hover.png testbed/data/themes/gray/menu.option.normal.png testbed/data/themes/gray/radio.off.down.png testbed/data/themes/gray/radio.off.normal.png testbed/data/themes/gray/radio.on.down.png testbed/data/themes/gray/radio.on.normal.png testbed/data/themes/gray/select.arrow.down.png testbed/data/themes/gray/select.arrow.normal.png testbed/data/themes/gray/select.arrow.png testbed/data/themes/gray/select.option.normal.png testbed/data/themes/gray/select.options.png testbed/data/themes/gray/select.selected.normal.png testbed/data/themes/gray/slider.bar.normal.png testbed/data/themes/gray/slider.png testbed/data/themes/gray/tool.down.png testbed/data/themes/gray/tool.normal.png testbed/data/themes/tools/config.txt testbed/data/themes/tools/icons48.bkgr.tga testbed/data/themes/tools/icons48.code.tga testbed/data/themes/tools/icons48.draw.tga testbed/data/themes/tools/icons48.eraser.tga testbed/data/themes/tools/icons48.fill.tga testbed/data/themes/tools/icons48.line.tga testbed/data/themes/tools/icons48.pixel.tga testbed/data/themes/tools/icons48.select.tga testbed/data/themes/tools/icons48.tile.tga testbed/demos.py testbed/hello.py testbed/pgu/__init__.py testbed/pgu/gui/__init__.py testbed/pgu/gui/app.py testbed/pgu/gui/area.py testbed/pgu/gui/basic.py testbed/pgu/gui/button.py testbed/pgu/gui/const.py testbed/pgu/gui/container.py testbed/pgu/gui/deprecated.py testbed/pgu/gui/dialog.py testbed/pgu/gui/document.py testbed/pgu/gui/form.py testbed/pgu/gui/group.py testbed/pgu/gui/input.py testbed/pgu/gui/keysym.py testbed/pgu/gui/layout.py testbed/pgu/gui/menus.py testbed/pgu/gui/misc.py testbed/pgu/gui/readme.txt testbed/pgu/gui/select.py testbed/pgu/gui/slider.py testbed/pgu/gui/style.py testbed/pgu/gui/surface.py testbed/pgu/gui/table.py testbed/pgu/gui/theme.py testbed/pgu/gui/widget.py testbed/pickle_example_web testbed/pygame_main.py testbed/pyglet_keymapper.py testbed/pyglet_main.py testbed/settings.py testbed/test_ApplyForce.py testbed/test_Belt.py testbed/test_BezierEdges.py testbed/test_Biped.py testbed/test_BoxCutter.py testbed/test_BreakableBody.py testbed/test_Bridge.py testbed/test_Buoyancy.py testbed/test_CCDTest.py testbed/test_Car.py testbed/test_Chain.py testbed/test_CollisionFiltering.py testbed/test_CollisionProcessing.py testbed/test_CompoundShapes.py testbed/test_ContactCallbackTest.py testbed/test_DistanceTest.py testbed/test_Dominos.py testbed/test_DynamicEdges.py testbed/test_EdgesBuoyancy.py testbed/test_ElasticBody.py testbed/test_Gears.py testbed/test_Gravity.py testbed/test_LineJoint.py testbed/test_MotorsAndLimits.py testbed/test_PolyCollision.py testbed/test_PolyShapes.py testbed/test_Prismatic.py testbed/test_Pulleys.py testbed/test_Pyramid.py testbed/test_PyramidStaticEdges.py testbed/test_RaycastTest.py testbed/test_Revolute.py testbed/test_SensorTest.py testbed/test_ShapeEditing.py testbed/test_SliderCrank.py testbed/test_SphereStack.py testbed/test_StaticEdges.py testbed/test_TheoJansen.py testbed/test_TimeOfImpact.py testbed/test_VaryingFriction.py testbed/test_VaryingRestitution.py testbed/test_VerticalStack.py testbed/test_Web.py testbed/test_empty.py testbed/test_main.py testbed/test_pickle.py python-box2d-2.0.2+svn20100109.244/INSTALL0000644000000000000000000001134411252311722015525 0ustar rootrootBuilding from Source Contents ======== 1. Linux 2. Windows 3. OS X 1. Linux ======== 1. Download and install the latest version of SWIG (preferably 1.3.31+) with your package manager. If you are using Ubuntu, you can install it via Synaptic Package Manager (package name 'swig'). You will also need to install the python-dev package, and build-essential (and python-pygame if you want to run the testbed). sudo apt-get install build-essential python-dev swig python-pygame 2. Check out the SVN svn checkout http://pybox2d.googlecode.com/svn/trunk/ pybox2d 3. Build and install the pyBox2D library python setup.py build # Assuming everything goes well... sudo python setup.py install Note that if you receive some errors about -fPIC, adding -fPIC to your CXXFLAGS might fix the problem. 2. Windows ========== 1. Install MinGW and then MSYS so that you can compile Box2D and pyBox2D. 2. Install SWIG for making the Python wrapper. Install it in a location in your PATH, or add the SWIG directory to your PATH. 3. Create Python\Lib\distutils\distutils.cfg, if it doesn't exist, and add: [build] compiler=mingw32 [build_ext] compiler=mingw32 4. If you want to build from the SVN, install the Subversion client. Check out the project by doing svn checkout http://pybox2d.googlecode.com/svn/trunk/ pybox2d 5. Run MSYS and locate your pybox2d directory cd /c/path/to/pybox2d/ 6. Build and install pyBox2D setup.py build setup.py install 3. OS X ======= Dependencies To build pyBox2D, you will need: * Apple Developer Tools (see below) * SWIG (see below) * Python (of course) Install Apple Developer Tools 1. This step is only required if the Apple Developer tools have not already been installed. 2. Download the Apple Developer Tools or install them from the System Installer CD provided with your Mac. 3. Download from: http://developer.apple.com/tools/ 4. This will give your system all the tools it needs for software development. 5. These tools are required for you to proceed to the next step. SWIG Installation 1. Download the latest source release of SWIG: http://downloads.sourceforge.net/swig/swig-1.3.36.tar.gz 2. Place the file onto your Desktop 3. Open Terminal.app located in the Applications/Utilities folder 4. Then enter the following into the terminal window: cd ~/Desktop tar -zxf swig-*.tar.gz cd swig-* ./configure make sudo make install 5. Hopefully all went well and no errors occurred. 6. Close the Terminal.app window 7. SWIG is now installed onto the system; we can now move to the next step. pyBox2D Installation 1. Download the latest source distribution of pyBox2D: http://pybox2d.googlecode.com/files/pyBox2D-2.0.2b0-Source.zip 2. Place the file onto your Desktop 3. Open Terminal.app located in the Applications/Utilities folder 4. Then enter the following into the terminal window: cd ~/Desktop unzip pyBox2D-*-Source.zip cd pyBox2D-*-Source/ python setup.py build 5. If you get this error: ld: warning in Gen/float/libbox2d.a, file is not of required architecture, run python setup.py build again. sudo python setup.py install 6. Hopefully all went well and no errors occurred. 7. Close the Terminal.app window Test pyBox2D Installation (optional) 1. NOTE: The pyBox2D testbed examples require pygame. 2. Download pygame from: http://www.pygame.org/download.shtml 3. For a simple gui installer download (as on pygame site): http://rene.f0o.com/~rene/stuff/macosx/pygame-1.8.0rc5-py2.5-macosx10.4.mpkg.zip 4. To test if the pyBox2D installation works we can see if the testbed examples included in the distribution run cd ~/Desktop/pyBox2D-*-Source/Box2D/Python/testbed python demos.py 5. At this stage take a look at the other examples provided. They are a good starting point to get an idea of how pyBox2D works. 6. For documentation / technical support to further your software development experience see the links on the project home page. Building pyBox2D from the SVN This is only necessary if you want the latest features that pyBox2D has to offer. Follow the above headings Install Apple Developer Tools and SWIG Installation. Now follow steps 2 and beyond for Linux. python-box2d-2.0.2+svn20100109.244/misc/0000755000000000000000000000000011414467240015433 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/misc/do_win32_setup.cmd0000644000000000000000000000272411151025342020760 0ustar rootroot @echo This script creates release installers for the supported versions of Python @echo in Windows. Though it's a windows command script, it does uses some stuff @echo from MSYS (cat/mv/rm/etc) @pause cd .. @echo Clean all first... c:\python24\python.exe setup.py clean -a c:\python25\python.exe setup.py clean -a c:\python26\python.exe setup.py clean -a rm -rf build @echo --------------------------------------------------------------------------- @echo Python 2.4 - MinGW c:\python24\python.exe setup.py build --force cat Box2D/pybox2d_license_header.txt > Box2D_.py cat Box2D.py >> Box2D_.py mv Box2D_.py Box2D.py c:\python24\python.exe setup.py bdist_wininst -t"pyBox2D Installer" -dinstaller @echo --------------------------------------------------------------------------- @echo Python 2.5 - MinGW c:\python25\python.exe setup.py build --force cat Box2D/pybox2d_license_header.txt > Box2D_.py cat Box2D.py >> Box2D_.py mv Box2D_.py Box2D.py c:\python25\python.exe setup.py bdist_wininst -t"pyBox2D Installer" -dinstaller @echo --------------------------------------------------------------------------- @echo Python 2.6 - Compiles with VC9 c:\python26\python.exe setup.py build --force cat Box2D/pybox2d_license_header.txt > Box2D_.py cat Box2D.py >> Box2D_.py mv Box2D_.py Box2D.py c:\python26\python.exe setup.py bdist_wininst -t"pyBox2D Installer" -dinstaller rm -rf build temp Box2D_wrap* Box2D*.py _Box2D.pyd cd misc @pause python-box2d-2.0.2+svn20100109.244/misc/do_osx_setup.sh0000644000000000000000000000060511130023047020467 0ustar rootroot# for releasing mpkg versions of pybox2d. not required for normal installations! cd .. # python 2.5 rm -rf dist build temp Box2D.py _Box2D.so python2.5 setup.py build /Library/Frameworks/Python.framework/Versions/2.5/bin/bdist_mpkg # python 2.6 rm -rf dist build temp Box2D.py _Box2D.so python2.6 setup.py build /Library/Frameworks/Python.framework/Versions/2.6/bin/bdist_mpkg cd misc python-box2d-2.0.2+svn20100109.244/doc/0000755000000000000000000000000011414467236015252 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/doc/manual.htm0000644000000000000000000043221511151077147017244 0ustar rootroot Python Manual - Box2D Wiki

Python Manual

From Box2D Wiki
Latest version http://www.box2d.org/wiki/index.php?title=Python_Manual

Jump to: navigation, search

Contents

[hide]

[edit] Box2D v2.0.1 User Manual

Image:Icon-manual.png Copyright 2007-2009 Erin Catto

[edit] About

Box2D is a 2D rigid body simulation library for games. Programmers can use it in their games to make objects move in believable ways and make the world seem more interactive. From the game's point of view a physics engine is just a system for procedural animation. Rather than paying (or begging) an animator to move your actors around, you can let Sir Isaac Newton do the directing. Box2D is written in portable C++ and bound to Python by SWIG. Most of the types defined in the engine begin with the b2 prefix. Hopefully this is sufficient to avoid name clashing with your game engine if you choose to import it to your global namespace (which you probably shouldn't do in the first place).

[edit] Prerequisites

In this manual I'll assume you are familiar with basic physics concepts, such as mass, force, torque, and impulses. If not, please first consult the many tutorials provided by Chris Hecker and David Baraff (google these names). You do not need to understand their tutorials in great detail, but they do a good job of laying out the basic concepts that will help you use Box2D.

Wikipedia is also an excellent source of physics and mathematics knowledge. In some ways it is more useful than Google, because it has carefully crafted content.

This is not a prerequisite, but if you are curious about the about the inner workings of Box2D, you can look at these articles.

You can get by knowing the basics of Python.

The current release of pybox2d, 2.0.2b1, offers much more functionality and ease of use compared to previous versions. It's difficult to support older versions, so please take the time to upgrade and update your code.

[edit] Core Concepts

Box2D works with several fundamental objects. We briefly define these objects here and more details are given later in this document.

rigid body
A chunk of matter that is so strong that the distance between any two bits of matter on the chunk is completely constant. They are hard like a diamond. In the following discussion we use body interchangably with rigid body.
shape
A 2D piece of collision geometry that is rigidly attached to a body. Shapes have material properties of friction and restitution.
constraint
A constraint is a physical connection that removes degrees of freedom from bodies. In 2D a body has 3 degrees of freedom. If we take a body and pin it to the wall (like a pendulum) we have constrained the body to the wall. At this point the body can only rotate about the pin, so the constraint has removed 2 degrees of freedom.
contact constraint
A special constraint designed to prevent penetration of rigid bodies and to simulate friction and restitution. You will never create a contact constraint, they are created automatically by Box2D.
joint
This is a contraint used to hold two or more bodies together. Box2D supports these joint types: revolute, prismatic, distance, and more. Joints may support limits and motors.
joint limit
A joint limit restricts the range of motion of a joint. For example, the human elbow only allows a certain range of angles.
joint motor
A joint motor drives the motion of the connected bodies according to the joint's degrees of freedom. For example, you can use a motor to drive the rotation of an elbow.
world
A physics world is a collection of bodies, shapes, and constraints that interact together. Box2D supports the creation of multiple worlds, but this is usually not necessary or desirable.

[edit] Hello Box2D

There is a Hello World project on the wiki. The program creates a large ground box and a small dynamic box. This code does not contain any graphics, so prepare to be underwhelmed. :)

For simplicity's sake, the Hello World program imports Box2D as:

from Box2D2 import *

However, it's recommended that you import Box2D as follows:

import Box2D2 as box2d

Or something similar. You will experience problems importing Box2D from multiple modules otherwise. (See the Multiple Source Files section of Box2D with Python)

[edit] Creating a World

Every Box2D program begins with the creation of a world object. This is the physics hub that manages memory, objects, and simulation.

To create a world object, first we need to define a bounding box for the world. Box2D uses the bounding box to accelerate collision detection. The size isn't critical, but a better fit will improve performance. It is better to make the box too big than to make it too small.

worldAABB=b2AABB()
worldAABB.lowerBound.Set(-100, -100)
worldAABB.upperBound.Set(100, 100)

From pybox2d 2.0.2b1 onward, you will now be able to use a slightly simpler syntax:

worldAABB=b2AABB()
worldAABB.lowerBound = (-100, -100)
worldAABB.upperBound = (100, 100)

For more information on b2Vec2 -- Box2D 2D vectors -- see here.

Caution

The world AABB should always be bigger then the region where your bodies are located. It is better to make the world AABB too big than too small. If a body reaches the boundary of the world AABB it will be frozen and will stop simulating.

Next we define the gravity vector. Yes, you can make gravity go sideways (or you could just rotate your monitor). Also we tell the world to allow bodies to sleep when they come to rest. A sleeping body doesn't require any simulation.

gravity = (0, -10) # for pybox2d < 2.0.2b1, this must be a b2Vec2
doSleep = True

Now we create the world object.

world = b2World(worldAABB, gravity, doSleep)

So now we have our physics world, let's start adding some stuff to it.

[edit] Creating a Ground Box

Bodies are built using the following steps:

  1. Define a body with a position, damping, etc.
  2. Use the world object to create the body.
  3. Define shapes with geometry, friction, density, etc.
  4. Create shapes on the body.
  5. Optionally adjust the body's mass to match the attached shapes.

For step 1 we create the ground body. For this we need a body definition. With the body definition we specify the initial position of the ground body.

groundBodyDef = b2BodyDef()
groundBodyDef.position = (0, -10)

For step 2 the body definition is passed to the world object to create the ground body. The world object does not keep a reference to the body definition. The ground body is created as a static body. Static bodies don't collide with other static bodies and are immovable. Box2D determines that a body is static when it has zero mass. Bodies have zero mass by default, therefore they are static by default.

groundBody = world.CreateBody(groundBodyDef)

For step 3 we create a ground polygon definition. We use the SetAsBox shortcut to form the ground polygon into a box shape, with the box centered on the origin of the parent body.

groundShapeDef = b2PolygonDef()
groundShapeDef.SetAsBox(50, 10)

The SetAsBox function takes the half-width and half-height. So in this case the ground box is 100 units wide (x-axis) and 20 units tall (y-axis). Box2D is tuned for meters, kilograms, and seconds. So you can consider the extents to be in meters. However, it is possible to change unit systems, as discussed later in this document.

We finish the ground body in step 4 by creating the ground polygon shape on the ground body.

groundBody.CreateShape(groundShapeDef)

Again, Box2D does not keep a reference to the shape or body definitions. It copies the data into the b2Body structure.

Note that every shape must have a parent body, even shapes that are static. However, you can attach all static shapes to a single static body. This need for static bodies is done to make the Box2D code more uniform internally, reducing the number of potential bugs.

You might notice a pattern here. Most Box2D types are prefixed with b2. This is done to reduce the chance for naming conflicts with your code.

[edit] Creating a Dynamic Body

So now we have a ground body. We can use the same technique to create a dynamic body. The main difference, besides dimensions, is that we must establish the dynamic body's mass properties.

First we create the body using CreateBody.

bodyDef = b2BodyDef()
bodyDef.position = (0, 4)
body = world.CreateBody(bodyDef)

Next we create and attach a polygon shape. Notice that we set density to 1. The default density is zero. Also, the friction on the shape is set to 0.3. Once the shape is attached, we instruct the body to compute it's mass properties from the attached shapes using the method SetMassFromShapes. This gives you a hint that you can attach more than one shape per body. If the computed mass is zero, then the body becomes truly static. Bodies have a mass of zero by default, that's why we didn't need to call SetMassFromShapes for the ground body.

shapeDef = b2PolygonDef()
shapeDef.SetAsBox(1, 1)
shapeDef.density = 1
shapeDef.friction = 0.3
body.CreateShape(shapeDef)
body.SetMassFromShapes()

That's it for initialization. We are now ready to begin simulating.

[edit] Simulating the World (of Box2D)

So we have initialized the ground box and a dynamic box. Now we are ready to set Newton loose to do his thing. We just have a couple more issues to consider.

Box2D uses a bit of numerical code called an integrator. Integrators simulate the physics equations at discrete points of time. This goes along with the traditional game loop where we essentially have a flip book of movement on the screen. So we need to pick a time step for Box2D. Generally physics engines for games like a time step at least as fast as 60Hz or 1/60 seconds. You can get away with larger time steps, but you will have to be more careful about setting up the definitions for your world. We also don't like the time step to change much. So don't tie the time step to your frame rate (unless you really, really have to). Without further ado, here is the time step.

timeStep = 1.0 / 60.0

In addition to the integrator, Box2D also uses a larger bit of code called a constraint solver. The constraint solver solves all the constraints in the simulation, one at a time. A single constraint can be solved perfectly. However, when we solve one constraint, we slightly disrupt other constraints. To get a good solution, we need to iterate over all constraints a number of times. The suggested iteration count for Box2D is 10. You can tune this number to your liking, just keep in mind that this has a trade-off between speed and accuracy. Using fewer iterations increases performance but accuracy suffers. Likewise, using more iterations decreases performance but improves the quality of your simulation. Here is our chosen iteration count.

For newer versions of pyBox2D (2.0.2 and beyond), general iterations have been broken up into velocity and position iterations.

velocityIterations = 10
positionIterations = 8

For previous versions of pyBox2D (<= 2.0.1):

iterations = 10

Note that the time step and the iteration count are completely unrelated. An iteration is not a sub-step. One iteration is a single pass over all the constraints withing a time step. You can have multiple passes over the constraints within a single time step.

We are now ready to begin the simulation loop. In your game the simulation loop can be merged with your game loop. In each pass through your game loop you call b2World.Step. Just one call is usually enough, depending on your frame rate and your physics time step.

The Hello World program was designed to be dead simple, so it has no graphical output. Rather that being utterly boring by producing no output, the code prints out the position and rotation of the dynamic body. Yay! Here is the simulation loop that simulates 60 time steps for a total of 1 second of simulated time.

for i in range(60):
    world.Step(timeStep, velocityIterations, positionIterations)
    print body.position, body.angle

For previous versions of pyBox2D (<= 2.0.1):

for i in range(60):
    world.Step(timeStep, iterations)
    position = body.GetPosition()
    angle = body.GetAngle()
    print position, angle


[edit] The Testbed

Once you have conquered the HelloWorld example, you should start looking at pybox2d's testbed. The testbed is a unit-testing framework and demo environment. Here are some of the features:

  • Camera with pan and zoom.
  • Mouse picking of shapes attached to dynamic bodies.
  • Extensible set of tests.
  • GUI for parameter tuning, and debug drawing options.
  • Pause and single step simulation.
  • Pygame/pyglet support, both with debug drawing code for reference.
  • Save/load architecture built in with Pickle

Image:python_testbed.png

The testbed has many examples of Box2D usage in the test cases and the framework itself. I encourage you to explore and tinker with the testbed as you learn Box2D.

Note: the Python testbed is written using pygame. The testbed is not part of the Box2D library, though it is included in the distribution. Box2D is agnostic about rendering. As shown by the HelloWorld example, you don't need a renderer to use Box2D.

[edit] API Design

[edit] Memory Management

Fortunately, the memory management is taken care of for us on the C++ side of things, so in general there is no need to worry about memory. The only problem you might run into is if you are using cyclical references with userData. Using circular references will likely cause the garbage collector to not properly collect your objects until the application has ended.

In order to work around this, before destroying a body with a circular reference is to clear its userData: body.ClearUserData(). Destroy it, and then your Python object should be deallocated properly (as in, its __del__ is called and then freed).

[edit] Factories and Definitions

As mentioned above, memory management plays a central role in the design of the Box2D API. So when you create a b2Body or a b2Joint, you need to call the factory functions on b2World.

There are creation functions:

Note: Indicated are the types that should be used (or will be returned). Do NOT name your variables b2Body, b2World, etc.

b2Body = b2World.CreateBody(b2BodyDef)
b2Joint = b2World.CreateJoint(b2JointDef)

b2World.CreateJoint returns a b2Joint, which can represent any type of joint. If you want to access the joint parameters specific to the joint you created, however, you must use:

typecasted_joint = b2World.CreateJoint(b2JointDef).getAsType()

The above will return a b2DistanceJoint, for example, if the definition passed in described a distance joint.

And there are corresponding destruction functions:

b2World.DestroyBody(b2Body)

b2World.DestroyJoint(b2Joint)

When you create a body or joint, you need to provide a definition or def for short. These definitions contain all the information needed to build the body or joint. By using this approach we can prevent construction errors, keep the number of function parameters small, provide sensible defaults, and reduce the number of accessors.

Since shapes must be parented to a body, they are created and destroyed using a factory method on b2Body:

b2Shape = b2Body.CreateShape(b2ShapeDef)
b2Body.DestroyShape(b2Shape)

Factories do not retain references to the definitions. So you can create definitions on the stack and keep them in temporary resources.

[edit] Units

Box2D works with floating point numbers, so some tolerances have to be used to make Box2D perform well. These tolerance have been tuned to work well with meters-kilogram-second (MKS) units. In particular, Box2D has been tuned to work well with moving objects between 0.1 and 10 meters. So this means objects between soup cans and buses in size should work well.

Being a 2D physics engine it is tempting to use pixels as your units. Unfortunately this will lead to a poor simulation and possibly weird behavior. An object of length 200 pixels would be seen by Box2D as the size of a 45 story building. Imagine trying to simulate the movement of a high-rise building with an engine that is tuned to simulate ragdolls and barrels. It isn't pretty.

*** Caution ***

Box2D is tuned for MKS units. Keep the size of moving objects roughly between 0.1 and 10 meters. You'll need to use some scaling system when you render your environment and actors. The Box2D examples do this by using an OpenGL viewport transform.

[edit] User Data

The b2Shape, b2Body, and b2Joint classes allow you to attach any Python object as user data. This is handy when you are examining Box2D data structures and you want to determine how they relate to the data structures in your game engine.

For example, it is typical to attach an actor to the rigid body on that actor. This sets up a circular reference. If you have the actor, you can get the body. If you have the body, you can get the actor.

actor = GameCreateActor()
bodyDef = b2BodyDef()
bodyDef.userData = actor # you could just as well use a dictionary, tuple, integer, etc.
actor.body = world.CreateBody(bodyDef)

Here are some examples of cases where you would need the user data:

  • Applying damage to an actor using a collision result.
  • Playing a scripted event if the player is inside an axis-aligned box.
  • Accessing a game structure when Box2D notifies you that a joint is going to be destroyed.

Keep in mind that user data is optional and you can put anything in it. However, you should be consistent. For example, if you want to store an actor on one body, you should probably keep an actor on all bodies.

Caution If you use userData, be sure to see the Working with userData' section of Box2D with Python.

[edit] Dealing with C++

C++ is great for encapsulation and polymorphism, but it's not so great for API design. There are always significant trade-offs when creating a C++ library.

Should we use abstract factories or the pimpl idiom? These make the API look cleaner, but they ultimately get in the way of debugging and efficient development.

Should we use private data and friends as necessary? Perhaps, but eventually the number of friends can become ridiculous.

Should we just wrap the C++ code with a C-API? Perhaps, but this is extra work and may lead to internal choices that are non-optimal. Also, C-APIs are harder to debug and maintain. A C-API also breaks encapsulation.

For Box2D I have chosen the path of least resistance. For some cases a class is well contained in its design and function, so I use public functions and private data. For everything else I use classes or structs with all public members. These choices let me develop the code rapidly, it is easy to debug, and it creates minimal internal clutter while maintaining tight encapsulation. The downside is that you don't see a clean, simple API. Of course, you have this nice manual to help you out. :)

The Python bindings expose only public members of the C++ classes.

[edit] Strawman

If you don't like this API design, that's ok! You have the source code! Seriously, if you have feedback about anything related to Box2D, please leave a comment in the forum.

[edit] The World

[edit] About

The b2World class contains the bodies and joints. It manages all aspects of the simulation and allows for asynchronous queries (like AABB queries). Much of your interactions with Box2D will be with a b2World object.

[edit] Creating and Destroying a World

Creating a world is fairly simple. You need to provide a bounding box and a gravity vector.

The axis-aligned bounding box should encapsulate the world. You can improve performance by making the bounding box a bit bigger than your world, say 2x just to be safe. If you have lots of bodies that fall into the abyss, your application should detect this and remove the bodies. This will improve performance and prevent floating point overflow.


myWorld = b2World(aabb, gravity, doSleep)
 
When myWorld goes out of use, it will automatically be deleted by the garbage collector.

Caution

Recall that the world AABB should always be bigger then the region where your bodies are located. If bodies leave the world AABB, then they will be frozen. This is not a bug.

[edit] Using a World

The world class contains factories for creating and destroying bodies and joints. These factories are discussed later in the sections on bodies and joints. There are some other interactions with b2World that I will cover now.

[edit] Simulation

The world class is used to drive the simulation. You specify a time step and an iteration count. For example:

For versions of pyBox2D <= 2.0.1:

timeStep = 1.0 / 60
iterations = 10
world.Step(timeStep, iterations)

For newer versions of pyBox2D (2.0.2 and beyond):

timeStep = 1.0 / 60
velocityIterations = 10
positionIterations = 8
world.Step(timeStep, velocityIterations, positionIterations)

After the time step you can examine your bodies and joints for information. Most likely you will grab the position off the bodies so that you can update your actors and render them. You can perform the time step anywhere in your game loop, but you should be aware of the order of things. For example, you must create bodies before the time step if you want to get collision results for the new bodies in that frame.

As I discussed above in the HelloWorld tutorial, you should use a fixed time step. By using a larger time step you can improve performance in low frame rate scenarios. But generally you should use a time step no larger than 1/30 seconds. A time step of 1/60 seconds will usually deliver a high quality simulation.

The iteration count controls how many times the constraint solver sweeps over all the contacts and joints in the world. More iterations always yields a better simulation. But don't trade a small time step for a large iteration count. 60Hz and 10 iterations is far better than 30Hz and 20 iterations.

[edit] Exploring the World

As mentioned before, the world is a container for bodies and joints. You can grab the body and joint lists off the world and iterate over them. For example, this code wakes up all the bodies in the world.

for body in world: 
    body.WakeUp()
    body = body.GetNext()

As you can see, iterating over a world iterates over the bodies; the list itself is available as world.bodyList.



[edit] AABB Queries

Sometimes you want to determine all the shapes in a region. The b2World class has a fast log(N) method for this using the broad-phase data structure. You provide an AABB in world coordinates and b2World returns an array of all the shapes that potentially intersect the AABB. This is not exact because what the function actually does is return all the shapes whose AABBs intersect the specified AABB. For example, the following code finds all the shapes that potentially intersect a specified AABB and wakes up all of the associated bodies.

aabb = b2AABB()
aabb.lowerBound.Set(-1.0, -1.0)
aabb.upperBound.Set(1.0, 1.0)
 
(count, shapes) = b2World.Query(aabb, 10) # maximum of 10 shapes
for shape in shapes:
    shape.GetBody().WakeUp()

[edit] Bodies

[edit] About

Bodies have position and velocity. You can apply forces, torques, and impulses to bodies. Bodies can be static or dynamic. Static bodies never move and don't collide with other static bodies.

Bodies are the backbone for shapes. Bodies carry shapes and move them around in the world. Bodies are always rigid bodies in Box2D. That means that two shapes attached to the same rigid body never move relative to each other.

You usually keep pointers to all the bodies you create. This way you can query the body positions to update the positions of your graphical entities. You should also keep body pointers so you can destroy them when you are done with them.

[edit] Body Definition

Before a body is created you must create a body definition (b2BodyDef). You can create a body definition on the stack or build it into your game's data structures. The choice is up to you.

Box2D copies the data out of the body definition, it does not keep a pointer to the body definition. This means you can recycle a body definition to create multiple bodies.

Lets go over some of the key members of the body definition.

[edit] Mass Properties

There are a few ways to establish the mass properties for a body.

  1. Set the mass properties explicitly in the body definition.
  2. Set the mass properties explicitly on the body (after it has been created).
  3. Set the mass properties based on the density of the attaced shapes.

In many game scenarios it makes sense to compute mass based on shape densities. This helps to ensure that bodies have reasonable and consistent mass values.

However, other game scenarios may require specific mass values. For example, you may have a mechanism, like a scale that needs precise mass values.

You can explicitly set the mass properties in the body definition as follows:

bodyDef.massData.mass = 2.0              # the body's mass in kg
bodyDef.massData.center = (0,0)          # the center of mass in local coordinates
bodyDef.massData.I = 3.0                 # the rotational inertia in kg*m^2.

The other methods of setting the mass properties are covered elsewhere in this document.

[edit] Position and Angle

The body definition gives you the chance to initialize the position of the body on creation. This has better performance than creating the body at the world origin and then moving the body.

A body has two main points of interest. The first point is the body's origin. Shapes and joints are attached relative to the body's origin. The second point of interest is the center of mass. The center of mass is determined from mass distribution of the attached shapes or is explicitly set with b2MassData. Much of Box2D's internal computations use the center of mass position. For example b2Body stores the linear velocity for the center of mass.

When you are building the body definition, you may not know where the center of mass is located. Therefore you specify the position of the body's origin. You may also specify the body's angle in radians, which is not affected by the position of the center of mass. If you later change the mass properties of the body, then the center of mass may move on the body, but the origin position does not change and the attached shapes and joints do not move.

bodyDef.position = (0.0, 2.0)     # the body's origin position.
bodyDef.angle = 0.25 * b2_pi      # the body's angle in radians.

[edit] Damping

Damping is used to reduce the world velocity of bodies. Damping is different than friction because friction only occurs with contact and damping is much cheaper to simulate than friction. However, damping is not a replacement for friction and the two effects should be used together.

Damping parameters should be between 0 and infinity, with 0 meaning no damping, and infinity meaning full damping. Normally you will use a damping value between 0 and 1.0. I generally do not use linear damping because it makes bodies look floaty.

bodyDef.linearDamping = 0.0 
bodyDef.angularDamping = 0.1

Damping is approximated for stability and performance. At small damping values the damping effect is mostly independent of the time step. At larger damping values, the damping effect will vary with the time step. This is not an issue if you use a fixed time step (recommended).

[edit] Sleep Parameters

What does sleep mean? Well it is expensive to simulate bodies, so the less we have to simulate the better. When a body comes to rest we would like to stop simulating it.

When Box2D determines that a body (or group of bodies) has come to rest, the body enters a sleep state which has very little CPU overhead. If an awake body collides with a sleeping body, then the sleeping body wakes up. Bodies will also wake up if a joint or contact attached to them is destroyed. You can also wake a body manually.

The body definition lets you specify whether a body can sleep and whether a body is created sleeping.

bodyDef.allowSleep = True
bodyDef.isSleeping = False

[edit] Bullets

Game simulation usually generates a sequence of images that are played at some frame rate. In this setting rigid bodies can move by a large amount in one time step. If a physics engine doesn't account for the large motion, you may see some objects incorrectly pass through each other. This effect is called tunneling.

By default, Box2D uses continuous collision detection (CCD) to prevent dynamic bodies from tunneling through static bodies. This is done by sweeping shapes from their old position to their new positions. The engine looks for new collisions during the sweep and computes the time of impact (TOI) for these collisions. Bodies are moved to their first TOI and then simulated to the end of the original time step. This process is repeated as necessary.

Normally CCD is not used between dynamic bodies. This is done to keep performance reasonable. In some game scenarios you need dynamic bodies to use CCD. For example, you may want to shoot a high speed bullet at a thin wall. Without CCD, the bullet my tunnel through the wall.

Fast moving objects in Box2D are called bullets. You should decide what bodies should be bullets based on your game design. If you decide a body should be treated as a bullet, use the following setting.

bodyDef.isBullet = True


The bullet flag only affects dynamic bodies.

CCD is expensive so you probably don't want all moving bodies to be bullets. So by default Box2D only uses CCD between moving bodies and static bodies. This is an effective approach to prevent bodies from escaping your game world. However, you may have some fast moving bodies that that require CCD all the time.

[edit] Body Factory

Bodies are created and destroyed using a body factory provided by the world class. This lets the world create the body with an efficient allocator and add the body to the world data structure.

Bodies can be dynamic or static depending on the mass properties. Both body types use the same creation and destruction methods.

dynamicBody = myWorld.CreateBody(bodyDef)
# ... do stuff ...
myWorld.DestroyBody(dynamicBody)
dynamicBody = None


Static bodies do not move under the influence of other bodies. You may manually move static bodies, but you should be careful so that you don't squash dynamic bodies between two or more static bodies. Friction will not work correctly if you move a static body. Static bodies never simulate on their own and they never collide with other static bodies. It is faster to attach several shapes to a static body than to create several static bodies with a single shape on each one. Internally, Box2D sets the mass and inverse mass of static bodies to zero. This makes the math work out so that most algorithms don't need to treat static bodies as a special case.

Box2D does not keep a reference to the body definition or any of the data it holds (except user data pointers). So you can create temporary body definitions and reuse the same body definitions.

Box2D allows you to avoid destroying bodies by deleting your b2World object, which does all the cleanup work for you. However, you should be mindful to nullify any body pointers that you keep in your game engine.

When you destroy a body, the attached shapes and joints are automatically destroyed. This has important implications for how you manage shape and joint pointers. See [[Python_Manual#Implicit_Destruction|Implicit Destruction] for details.

Suppose you want to connect a dynamic body to ground with a joint. You'll need to connect the joint to a static body. If you don't have a static body, you can get a shared ground body from your world object. You can also attach static shapes to the ground body.


ground = myWorld.GetGroundBody()
# ... build a joint using the ground body ...

[edit] Using a Body

After creating a body, there are many operations you can perform on the body. These include setting mass properties, accessing position and velocity, applying forces, and transforming points and vectors.

[edit] Mass Data

You can adjust the mass of a body at run-time. This is usually done when you create or destroy shapes on a body. You may want to adjust the mass of the body based on the current shapes.

b2Body.SetMassFromShapes()

You may also want to set the mass properties directly. For example, you may change the shapes, but want to use your own mass formulas.

b2Body.massData = b2MassData

The body's mass data is available through the following functions:

float = b2Body.GetMass() # returns a float
float = b2Body.GetInertia()
b2Vec2= b2Body.GetLocalCenter()

[edit] State Information

There are many aspects to the body's state. You can access this state data efficient through the following functions:

bool_value = b2Body.isBullet
b2Body.isBullet = True
 
bool_value = b2Body.IsStatic() 
bool_value = b2Body.IsDynamic() 
 
bool_value = b2Body.IsFrozen() 
 
bool_value = b2Body.IsSleeping()
b2Body.AllowSleeping(True)
b2Body.WakeUp()

The bullet state is described in Bullets. The frozen state is described in World Boundary.

[edit] Position and Velocity

You access the position and rotation of a body. This is common when rendering your associated game actor. You can also set the position, although this is less common since you will normally use Box2D to simulate movement.

bool    = b2Body.SetXForm(position, radian_angle)
b2XForm = b2Body.GetXForm()
b2Vec2  = b2Body.position
float   = b2Body.angle

You can access the center of mass position in world coordinates. Much of the internal simulation in Box2D uses the center of mass. However, you should normally not need to access it. Instead you will usually work with the body transform.

b2Vec2 = b2Body.GetWorldCenter()

You can access the linear and angular velocity. The linear velocity is for the center of mass.

b2Body.linearVelocity = linvel_vec
linvel_vec = b2Body.linearVelocity
b2Body.angularVelocity = float(angvel)
angvel = b2Body.angularVelocity

[edit] Forces and Impulses

You can apply forces, torques, and impulses to a body. When you apply a force or an impulse, you provide a world point where the load is applied. This often results in a torque about the center of mass.

b2Body.ApplyForce(force_vector, point)
b2Body.ApplyTorque(torque)
b2Body.ApplyImpulse(impulse_vector, point)

Applying a force, torque, or impulse wakes the body. Sometimes this is undesirable. For example, you may be applying a steady force and want to allow the body to sleep to improve performance. In this case you can use the following code.

if not myBody.IsSleeping():
    myBody.ApplyForce(myForce, myPoint)

[edit] Coordinate Transformations

The body class has some utility functions to help you transform points and vectors between local and world space. If you don't understand these concepts, please read "Essential Mathematics for Games and Interactive Applications" by Jim Van Verth and Lars Bishop. These functions are efficient, so use them with impunity.

b2Vec2 = b2Body.GetWorldPoint(localPoint)
b2Vec2 = b2Body.GetWorldVector(localVector)
b2Vec2 = b2Body.GetLocalPoint(worldPoint)
b2Vec2 = b2Body.GetLocalVector(worldVector)

[edit] Lists

You can iterate over a body's shapes. This is mainly useful if you need to access the shape's user data.

for shape in body: # iterates over body.shapeList
    data = shape.userData
    # ... do something with data ...

You can similarly iterate over the body's joint list.

[edit] Shapes

[edit] About

Shapes are the collision geometry attached to bodies. Shapes are also used to define the mass of a body. This lets you specify the density and let Box2D do the work of computing the mass properties.

Shapes have properties of friction and restitution. Shapes carry collision filtering information to let you prevent collisions between certain game objects.

Shapes are always owned by a body. You can attach multiple shapes to a single body. Shapes are abstract classes so that many types of shapes can be implemented in Box2D. If you are brave, you can implement your own shape type (and collision algorithms).

[edit] The Shape Definition

Shape definitions are used to create shapes. There is common shape data held by b2ShapeDef and specific shape data held by derived classes.

[edit] Friction and Restitution

Friction is used to make objects slide along each other realistically. Box2D supports static and dynamic friction, but uses the same parameter for both. Friction is simulated accurately in Box2D and the friction strength is proportional to the normal force (this is called Coulomb friction). The friction parameter is usually set between 0 and 1. A value of zero turns off friction and a value of one makes the friction strong. When the friction is computed between two shapes, Box2D must combine the friction parameters of the two shapes. This is done with the following formula:

from math import sqrt
friction = sqrt(shape1.friction * shape2.friction)

Restitution is used to make objects bounce. The restitution value is usually set to be between 0 and 1. Consider dropping a ball on a table. A value of zero means the ball won't bounce. This is called an inelastic collision. A value of one means the ball's velocity will be exactly reflected. This is called a perfectly elastic collision. Restitution is combined using the following formula.

restitution = b2Max(shape1.restitution, shape2.restitution)

When a shape develops multiple contacts, restitution is simulated approximately. This is because Box2D uses an iterative solver. Box2D also uses inelastic collisions when the collision velocity is small. This is done to prevent jitter.

[edit] Density

Box2D optionally computes the mass and rotational inertia of bodies using the mass distribution implied by the attached shapes. Specifying mass directly can often lead to poorly tuned simulations. Therefore, the recommended way of specifying body mass is by setting the shape densities and calling b2Body.SetMassFromShape once all the shapes are attached to the body.

[edit] Filtering

Collision filtering is a system for preventing collision between shapes. For example, say you make a character that rides a bicycle. You want the bicycle to collide with the terrain and the character to collide with the terrain, but you don't want the character to collide with the bicycle (because they must overlap). Box2D supports such collision filtering using categories and groups.

Box2D supports 16 collision categories. For each shape you can specify which category it belongs to. You also specify what other categories this shape can collide with. For example, you could specify in a multiplayer game that all players don't collide with each other and monsters don't collide with each other, but players and monsters should collide. This is done with masking bits. For example:

playerShapeDef.filter.categoryBits   = 0x0002
monsterShapeDef.filter.categoryBits  = 0x0004
playerShape.filter.maskBits          = 0x0004
monsterShapeDef.filter.maskBits      = 0x0002

Collision groups let you specify an integral group index. You can have all shapes with the same group index always collide (positive index) or never collide (negative index). Group indices are usually used for things that are somehow related, like the parts of a bicycle. In the following example, shape1 and shape2 always collide, but shape3 and shape4 never collide.

shape1Def.filter.groupIndex = 2
shape2Def.filter.groupIndex = 2
shape3Def.filter.groupIndex = -8
shape4Def.filter.groupIndex = -8

Collisions between shapes of different group indices are filtered according the category and mask bits. In other words, group filtering has higher precendence than category filtering.

Note that additional collision filtering occurs in Box2D. Here is a list:

  • A shape on a static body never collides with a shape on another static body.
  • Shapes on the same body never collide with each other.
  • You can optionally enable/disable collision between shapes on bodies connected by a joint.

Sometimes you might need to change collision filtering after a shape has already been created. You can get and set the b2FilterData structure on an existing shape using b2Shape.GetFilterData and b2Shape.SetFilterData. Box2D caches filtering results, so you must manually re-filter a shape using b2World.Refilter.

[edit] Sensors

Some times game logic needs to know when two shapes overlap yet there should be no collision response. This is done by using sensors. A sensor is a shape that detects collision but does not produce a response.

You can flag any shape as being a sensor. Sensors may be static or dynamic. Remember that you may have multiple shapes per body and you can have any mix of sensors and solid shapes.

myShapeDef.isSensor = True

[edit] Circle Definitions

b2CircleDef extends b2ShapeDef and adds a radius and a local position.

cdef = b2CircleDef()
cdef.radius = 1.5
cdef.localPosition.Set(1.0, 0.0)

[edit] Polygon Definitions

b2PolyDef is used to implement convex polygons. They are a bit tricky to use correctly, so please read closely. The maximum vertex count is defined by b2_maxPolyVertices which is currently 8. If you need to use more vertices, you must modify b2_maxPolyVertices in file b2Settings.

When you build a polygon definition you must specify the number of vertices you will use. The vertices must be specified in counter-clockwise (CCW) order about the z-axis of a right-handed coordinate system. This might turn out to be clockwise on your screen, depending on your coordinate system conventions.

Polygons must be convex. In other words, each vertex must point outwards to some degree. Finally, you must not overlap any vertices. Box2D will automatically close the loop.

convex_concave.gif

Here is an example of a polygon definition of a triangle:

triangleDef = b2PolygonDef()
triangleDef.setVertices( [ (-1.0, 0.0), (1.0, 0.0), (0.0, 2.0) ] )


The vertices are defined in the coordinate system of the parent body. If you need to offset a polygon within the parent body, then just offset all the vertices.

For convenience, there are functions to initialize polygons as boxes. You can have either an axis-aligned box centered at the body origin or an oriented box offset from the body origin.

alignedBoxDef = b2PolygonDef()
hx = 1.0 # half-width
hy = 2.0 # half-height
alignedBoxDef.SetAsBox(hx, hy)
 
orientedBoxDef = b2PolygonDef() 
center = (-1.5, 0.0)
angle = 0.5 * b2_pi
orientedBoxDef.SetAsBox(hx, hy, center, angle)

[edit] Shape Factory

Shapes are created by initializing a shape definition and then passing the definition to the parent body.

circleDef = b2CircleDef()
circleDef.radius = 3.0
circleDef.density = 2.5
myShape = myBody.CreateShape(circleDef)
# [optionally store the shape object somewhere]

This creates the shape and attaches it to the body. You do not need to store the shape pointer since the shape will automatically be destroyed when the parent body is destroyed (see Implicit Destruction).

After you finish adding shapes to a body, you may want to recompute the mass properties of the body based on the child shapes.

myBody.SetMassFromShapes()

This function is expensive, so you should only call it when necessary.

You can destroy a shape on the parent body easily. You may do this to model a breakable object. Otherwise you can just leave the shape alone and let the body destruction take care of destroying the attached shapes.

myBody.DestroyShape(myShape)

After removing shapes from a body, you may want to call SetMassFromShapes again.

[edit] Using a Shape

There's not much to say here. You can get a shape's type and its parent body. You can also test a point to see if it is contained within the shape. Look at b2Shape.h for details.

[edit] Joints

[edit] About

Joints are used to constrain bodies to the world or to each other. Typical examples in games include ragdolls, teeters, and pulleys. Joints can be combined in many different ways to create interesting motions.

Some joints provide limits so you can control the range of motion. Some joints provide motors which can be used to drive the joint at a prescribed speed until a prescribed force/torque is exceeded.

Joint motors can be used in many ways. You can use motors to control position by specifying a joint velocity that is proportional to the difference between the actual and desired position. You can also use motors to simulate joint friction: set the joint velocity to zero and provide a small, but significant maximum motor force/torque. Then the motor will attempt to keep the joint from moving until the load becomes too strong.

[edit] The Joint Definition

Each joint type has a definition that derives from b2JointDef. All joints are connected between two different bodies. One body may static. If you want to waste memory, then create a joint between two static bodies. :)

You can specify user data for any joint type and you can provide a flag to prevent the attached bodies from colliding with each other. This is actually the default behavior and you must set the collideConnected Boolean to allow collision between to connected bodies.

Many joint definitions require that you provide some geometric data. Often a joint will be defined by anchor points. These are points fixed in the attached bodies. Box2D requires these points to be specified in local coordinates. This way the joint can be specified even when the current body transforms violate the joint constraint --- a common ocurrence when a game is saved and reloaded. Additionally, some joint definitions need to know the default relative angle between the bodies. This is necessary to constraint rotation correctly via joint limits or a fixed relative angle.

Initializing the geometric data can be tedious, so many joints have initialization functions that use the current body transforms to remove much of the work. However, these initialization functions should usually only be used for prototyping. Production code should define the geometry directly. This will make joint behavior more robust.

The rest of the joint definition data depends on the joint type. We cover these now.

[edit] Distance Joint

One of the simplest joint is a distance joint which says that the distance between two points on two bodies must be constant. When you specify a distance joint the two bodies should already be in place. Then you specify the two anchor points in world coordinates. The first anchor point is connected to body 1, and the second anchor point is connected to body 2. These points imply the length of the distance constraint.

distanceJoint.gif

Here is an example of a distance joint definition. In this case we decide to allow the bodies to collide.

jointDef = b2DistanceJointDef()
jointDef.Initialize(myBody1, myBody2, worldAnchorOnBody1, worldAnchorOnBody2)
jointDef.collideConnected = True

[edit] Revolute Joint

A revolute joint forces two bodies to share a common anchor point, often called a hinge point. The revolute joint has a single degree of freedom: the relative rotation of the two bodies. This is called the joint angle.

revoluteJoint.gif

To specify a revolute you need to provide two bodies and a single anchor point in world space. The initialization function assumes that the bodies are already in the correct position.

In this example, two bodies are connected by a revolute joint at the first body's center of mass.

jointDef = b2RevoluteJointDef()
jointDef.Initialize(myBody1, myBody2, myBody1.GetWorldCenter())

The revolute joint angle is positive when body2 rotates CCW about the angle point. Like all angles in Box2D, the revolute angle is measured in radians. By convention the revolute joint angle is zero when the joint is created using Initialize(), regardless of the current rotation of the two bodies.

In some cases you might wish to control the joint angle. For this, the revolute joint can optionally simulate a joint limit and/or a motor.

A joint limit forces the joint angle to remain between an lower and upper bound. The limit will apply as much torque as needed to make this happen. The limit range should include zero, otherwise the joint will lurch when the simulation begins.

A joint motor allows you to specify the joint speed (the time derivative of the angle). The speed can be negative or positive. A motor can have infinite force, but this is usually not desirable. Have you ever heard the expression:

Caution

"What happens when an irresistible force meets an immovable object?"

I can tell you it's not pretty. So you can provide a maximum torque for the joint motor. The joint motor will maintain the specified speed unless the required torque exceeds the specified maximum. When the maximum torque is exceeded, the joint will slow down and can even reverse.

You can use a joint motor to simulate joint friction. Just set the joint speed to zero, and set the maximum torque to some small, but significant value. The motor will try to prevent the joint from rotating, but will yield to a significant load.

Here's a revision of the revolute joint definition above; this time the joint has a limit and a motor enabled. The motor is setup to simulate joint friction.

jointDef = b2RevoluteJointDef()
jointDef.Initialize(body1, body2, myBody1.GetWorldCenter())
jointDef.lowerAngle    = -0.5 * b2_pi  # -90 degrees
jointDef.upperAngle    = 0.25 * b2_pi  #  45 degrees
jointDef.enableLimit   = True
jointDef.maxMotorTorque= 10.0
jointDef.motorSpeed    = 0.0
jointDef.enableMotor   = True

[edit] Prismatic Joint

A prismatic joint allows for relative translation of two bodies along a specified axis. A prismatic joint prevents relative rotation. Therefore, a prismatic joint has a single degree of freedom.

prismaticJoint.gif

The prismatic joint definition is similar to the revolute joint description; just substitute translation for angle and force for torque. Using this analogy provides an example prismatic joint definition with a joint limit and a friction motor:

jointDef = b2PrismaticJointDef()
worldAxis = (1.0, 0.0)
jointDef.Initialize(myBody1, myBody2, myBody1.GetWorldCenter(), worldAxis)
jointDef.lowerTranslation = -5.0
jointDef.upperTranslation = 2.5
jointDef.enableLimit      = True
jointDef.maxMotorForce    = 1.0
jointDef.motorSpeed       = 0.0
jointDef.enableMotor      = True

The revolute joint has an implicit axis coming out of the screen. The prismatic joint needs an explicit axis parallel to the screen. This axis is fixed in the two bodies and follows their motion.

Like the revolute joint, the prismatic joint translation is zero when the joint is created using Initialize(). So be sure zero is between your lower and upper translation limits.

[edit] Pulley Joint

A pulley is used to create an idealized pulley. The pulley connects two bodies to ground and to each other. As one body goes up, the other goes down. The total length of the pulley rope is conserved according to the initial configuration.

length1 + length2 == constant

pulleyJoint.gif

You can supply a ratio that simulates a block and tackle. This causes one side of the pulley to extend faster than the other. At the same time the constraint force is smaller on one side than the other. You can use this to create mechanical leverage.

length1 + ratio * length2 == constant

For example, if the ratio is 2, then length1 will vary at twice the rate of length2. Also the force in the rope attached to body1 will have half the constraint force as the rope attached to body2.

Pulleys can be troublesome when one side is fully extended. The rope on the other side will have zero length. At this point the constraint equations become singular (bad). Therefore the pulley joint constrains the maximum length that either side can attain. Also, you may want to control the maximum lengths for gameplay reasons. So the maximum lengths improve stability and give you more control.

Here is an example pulley definition:

anchor1 = myBody1.GetWorldCenter()
anchor2 = myBody2.GetWorldCenter()
groundAnchor1 = (p1.x, p1.y + 10.0)
groundAnchor2 = (p2.x, p2.y + 12.0)
ratio = 1.0
jointDef = b2PulleyJointDef()
jointDef.Initialize(myBody1, myBody2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio)
jointDef.maxLength1 = 18.0
jointDef.maxLength2 = 20.0

[edit] Gear Joint

If you want to create a sophisticated mechanical contraption you might want to use gears. In principle you can create gears in Box2D by using compound shapes to model gear teeth. This is not very efficient and might be tedious to author. You also have to be careful to line up the gears so the teeth mesh smoothly. Box2D has a simpler method of creating gears: the gear joint.

gearJoint.gif

The gear joint requires that you have two bodies connected to a ground by a revolute or prismatic joint. You can use any combination of those joint types. Also, Box2D requires that the revolute and prismatic joints were created with the ground as body1.

Like the pulley ratio, you can specify a gear ratio. However, in this case the gear ratio can be negative. Also keep in mind that when one joint is a revolute joint (angular) and the other joint is prismatic (translation), then the gear ratio will have units of length or one over length.

coordinate1 + ratio * coordinate2 == constant

Here is an example gear joint:

jointDef = b2GearJointDef()
jointDef.body1 = myBody1
jointDef.body2 = myBody2
jointDef.joint1 = myRevoluteJoint
jointDef.joint2 = myPrismaticJoint
jointDef.ratio = 2.0 * b2_pi / myLength

Note that the gear joint depends on two other joints. This creates a fragile situation. What happens if those joints are deleted?

Caution

Always delete gear joints before the revolute/prismatic joints on the gears. Otherwise your code will crash in a bad way due to the orphaned joint pointers in the gear joint. You should also delete the gear joint before you delete any of the bodies involved.

[edit] Mouse Joint

The mouse joint is used in the testbed to manipulate bodies with the mouse. Please see the testbed and b2MouseJoint.h for details.

[edit] Joint Factory

Joints are created and destroyed using the world factory methods. This brings up an old issue:

Caution

Don't try to create a body or joint on the stack or on the heap using new or malloc. You must create and destroy bodies and joints using the create and destroy methods of the b2World class.

Here's an example of the lifetime of a revolute joint:

jointDef = b2RevoluteJointDef()
jointDef.body1 = myBody1
jointDef.body2 = myBody2
jointDef.anchorPoint = myBody1.GetCenterPosition()
joint = myWorld.CreateJoint(jointDef).getAsType()
# ... do stuff ...
myWorld.DestroyJoint(joint)
joint = None

It is always good to nullify your pointer after they are destroyed. This will make the program crash in a controlled manner if you try to reuse the pointer.

The lifetime of a joint is not simple. Heed this warning well:

Caution

Joints are destroyed when an attached body is destroyed.

This precaution is not always necessary. You may organize your game engine so that joints are always destroyed before the attached bodies. In this case you don't need to implement the listener class. See Implicit Destruction for details.

[edit] Using Joints

Many simulations create the joints and don't access them again until they are detroyed. However, there is a lot of useful data contained in joints that you can use to create a rich simulation.

First of all, you can get the bodies, anchor points, and user data from a joint.

b2Body = b2Joint.body1

b2Body = b2Joint.body2
b2Vec2 = b2Joint.GetAnchor1()
b2Vec2 = b2Joint.GetAnchor2()
anyType = b2Joint.userData

All joints have a reaction force and torque. This the reaction force applied to body 2 at the anchor point. You can use reaction forces to break joints or trigger other game events. These functions may do some computations, so don't call them if you don't need the result.

b2Vec2 = b2Joint.GetReactionForce()

float = b2Joint.GetReactionTorque()

[edit] Using Distance Joints

Distance joints don't have motors or limits, so there are no extra runtime methods for distance joints.

[edit] Using Revolute Joints

You can access a revolute joint's angle, speed, and motor torque.

float = b2RevoluteJoint.GetJointAngle()

float = b2RevoluteJoint.GetJointSpeed() 
float = b2RevoluteJoint.GetMotorTorque() 

You also update the motor parameters each step.

b2RevoluteJoint.SetMotorSpeed(float(speed))
b2RevoluteJoint.SetMaxMotorTorque(float(torque))

Joint motors have some interesting abilities. You can update the joint speed every time step so you can make the joint move back-and-forth like a sine-wave or according to whatever function you want.

from math import cos
# ...
# ... Game Loop Begin ...
myJoint.SetMotorSpeed(cos(0.5 * time))
# ... Game Loop End ...

You can also use joint motors to track a desired joint angle. For example:

#... Game Loop Begin ...
angleError = myJoint.GetJointAngle() - angleTarget
gain = 0.1
myJoint.SetMotorSpeed(-gain * angleError)
# ... Game Loop End ...

Generally your gain parameter should not be too large. Otherwise your joint may become unstable.

[edit] Using Prismatic Joints

Using a prismatic joint is similar to using a revolute joint. Here are the relevant member functions:

float = b2PrismaticJoint.GetJointTranslation()

float = b2PrismaticJoint.GetJointSpeed() 
float = b2PrismaticJoint.GetMotorForce() 
b2PrismaticJoint.SetMotorSpeed(float(speed))
b2PrismaticJoint.SetMotorForce(float(force))

[edit] Using Pulley Joints

Pully joints provide the current lengths.

float = b2PulleyJoint.length1

float = b2PulleyJoint.length2

[edit] Using Gear Joints

Gear joints don't provide any information beyond the functions defined in b2Joint.

[edit] Using Mouse Joints

The mouse joint is able to manipulate the attached body by updating the target point each time step.

[edit] Contacts

[edit] About

Contacts are objects created by Box2D to manage collision between shapes. There are different kinds of contacts, derived from b2Contact, for managing contact between different kinds of shapes. For example there is a contact class for managing polygon-polygon collision and another contact class for managing circle-circle collision. This is normally not important to you, I just thought you might like to know.

Here is some terminlogy associated with contacts. This terminology is particular to Box2D, but you might find similar terminology in other physics engines.

contact point
A contact point is a point where two shapes touch. In reality objects may touch over regions when surfaces touch. Box2D approximates contact with a small number of points.
contact normal
A contact normal is a unit vector that points from shape1 to shape2.
contact separation
Separation is the opposite of penetration. Separation is negative when shapes overlap. It is possible that future versions of Box2D will create contact points with positive separation, so you may want to check the sign when contact points are reported.
normal force
Box2D use an iterative contact solver and stores the results with the contact points. You can safely use the normal force to guage the collision intensity. For example, you can use the force to trigger breakables or to play collision sounds.
tangent force
The tangent force is the contact solver's estimate of the friction force.
contact ids
Box2D tries to re-use the contact force results from a time step as the initial guess for the next time step. Box2D uses contact ids to match contact points across time steps. The ids contain geometric features indices that help to distinguish one contact point from another.

Contacts are created when two shape's AABBs overlap. Sometimes collision filtering will prevent the creation of contacts. Box2D sometimes needs to create a contact even though the collision is filtered. In this case it uses a b2NullContact that prevents collision from occuring. Contacts are destroyed with the AABBs cease to overlap.

So you might gather that there may be contacts created for shapes that are not touching (just their AABBs). Well, this is correct. It's a "chicken or egg" problem. We don't know if we need a contact object until one is created to analyze the collision. We could delete the contact right away if the shapes are not touching, or we can just wait until the AABBS stop overlapping. Box2D takes the latter approach.

[edit] Contact Listener

You can receive contact data by implementing b2ContactListener. This listener reports a contact point when it is created, when it persists for more than one time step, and when it is destroyed. Keep in mind that two shapes may have multiple contact points.

class MyContactListener(b2ContactListener):
    def __init__(self): super(myContactListener, self).__init__() 
    def Add(self, point):
        """Handle add point"""
        pass
    def Persist(self, point):
        """Handle persist point"""
        pass
    def Remove(self, point):
        """Handle remove point"""
        pass
    def Result(self, point):
        """Handle results"""
        pass

Caution

Do not keep a reference to the contact points returned to b2ContactListener. Instead make a deep copy of the contact point data into your own buffer. The example below shows one way of doing this.

Continuous physics uses sub-stepping, so a contact point may be added and removed within the same time step. This is normally not a problem, but your code should handle this gracefully.

Contact points are reported immediately when they are added, persisted, or removed. This occurs before the solver is called, so the b2ContactPoint object does not contain the computed impulse. However, the relative velocity at the contact point is provided so that you can estimated the contact impulse. If you implement the Result listener function, you will receive b2ContactResult objects for solid contact points after the solver has been called. These result structures contain the sub-step impulses. Again, due to continuous physics you may receive multiple results per contact point per b2World.Step.

It is tempting to implement game logic that alters the physics world inside a contact callback. For example, you may have a collision that applies damage and try to destroy the associated actor and its rigid body. However, Box2D does not allow you to alter the physics world inside a callback because you might destroy objects that Box2D is currently processing, leading to orphaned pointers.

The recommended practice for processing contact points is to buffer all contact points that you care about and process them after the time step. You should always process the contact points immediately after the time step, otherwise some other client code might alter the physics world, invalidating the contact buffer. When you process the contact point buffer you can alter the physics world, but you still need to be careful that you don't orphan pointers stored in the contact point buffer. The testbed has example contact point processing that is safe from orphaned pointers.

This code from the CollisionProcessing test (test_CollisionProcessing.py) shows how to handle orphaned bodies when processing the contact buffer. Here is an excerpt.

# We are going to destroy some bodies according to contact
# points. We must buffer the bodies that should be destroyed
# because they may belong to multiple contact points.
nuke = []
 
# Traverse the contact results. Destroy bodies that
# are touching heavier bodies.
body_pairs = [(p.shape1.GetBody(), p.shape2.GetBody()) for p in self.points]
 
for body1, body2 in body_pairs:
    mass1, mass2 = body1.GetMass(), body2.GetMass()
 
    if mass1 > 0.0 and mass2 > 0.0:
        if mass2 > mass1:
            nuke_body = body1
        else:
            nuke_body = body2
 
        if nuke_body not in nuke:
            nuke.append(nuke_body)
 
# Destroy the bodies, skipping duplicates.
for b in nuke:
    print "Nuking:", b
    self.world.DestroyBody(b)

[edit] Contact Filtering

Often in a game you don't want all objects to collide. For example, you may want to create a door that only certain characters can pass through. This is called contact filtering, because some interactions are filtered out.

Box2D allows you to achieve custom contact filtering by implementing a b2ContactFilter class. This class requires you to implement a ShouldCollide function that receives two b2Shape pointers. Your function returns True if the shapes should collide.

The default implementation of ShouldCollide uses the b2FilterData defined in the Filtering section of the Shapes chapter Filtering.

class MyContactFilter(b2ContactFilter):
    def __init__(self):
        super(MyContactFilter, self).__init__()
    def ShouldCollide(self, shape1, shape2):
        # Implements the default behavior of b2ContactFilter in Python
        filter1 = shape1.GetFilterData()
        filter2 = shape2.GetFilterData()
        if filter1.groupIndex == filter2.groupIndex and filter1.groupIndex != 0:
            return filter1.groupIndex > 0
 
        collide = (filter1.maskBits & filter2.categoryBits) != 0 and (filter1.categoryBits & filter2.maskBits) != 0
        return collide
 
# Setting it:
myCF = MyContactFilter()
world.SetContactFilter( myCF )

[edit] Loose Ends

[edit] World Boundary

You can implement a b2BoundaryListener that allows b2World to inform you when a body has gone outside the world AABB. When you get the callback, you shouldn't try to delete the body, instead you should mark the parent actor for deletion or error handling. After the physics time step, you should handle the event.

class MyBoundaryListener(b2BoundaryListener):
    def __init__(self):
        super(MyBoundaryListener, self).__init__()
    def Violation(self, body):
        myActor = body.userData['actor'] # if you stored it as a dict
        myActor.MarkForErrorHandling()

You can then register an instance of your boundary listener with your world object. You should do this during world initialization.

myWorld.SetBoundaryListener(myBoundaryListener)

[edit] Implicit Destruction

Box2D doesn't use reference counting. So if you destroy a body it is really gone. Accessing a pointer to a destroyed body has undefined behavior. In other words, your program will likely crash and burn. To help fix these problems, the debug build memory manager fills destroyed entities with FDFDFDFD. This can help find problems more easily in some cases.

If you destroy a Box2D entity, it is up to you to make sure you remove all references to the destroyed object. This is easy if you only have a single reference to the entity. If you have multiple references, you might consider implementing a handle class to wrap the raw pointer.

Often when using Box2D you will create and destroy many bodies, shapes, and joints. Managing these entities is somewhat automated by Box2D. If you destroy a body then all associated shapes and joints are automatically destroyed. This is called implicit destruction.

When you destroy a body, all its attached shapes, joints, and contacts are destroyed. This is called implicit destruction. Any body connected to one of those joints and/or contacts is woken. This process is usually convenient. However, you must be aware of one crucial issue:

Caution

When a body is destroyed, all shapes and joints attached to the body are automatically destroyed. You must nullify any pointers you have to those shapes and joints. Otherwise, your program will die horribly if you try to access or destroy those shapes or joints later.

To help you nullify your joint pointers, Box2D provides a listener class named b2WorldListener that you can implement and provide to your world object. Then the world object will notify you when a joint is going to be implicity destroyed.

Implicit destruction is a great convenience in many cases. It can also make your program fall apart. You may store pointers to shapes and joints somewhere in your code. These pointers become orphaned when an associated body is destroyed. The situation becomes worse when you consider that joints are often created by a part of the code unrelated to management of the associated body. For example, the testbed creates a b2MouseJoint for interactive manipulation of bodies on the screen.

Box2D provides a callback mechanism to inform your application when implicit destruction occurs. This gives your application a chance to nullify the orphaned pointers. This callback mechanism is described later in this manual.

You can implement a b2DestructionListener that allows b2World to inform you when a shape or joint is implicitly destroyed because an associated body was destroyed. This will help prevent your code from accessing orphaned pointers.

class MyDestructionListener(b2DestructionListener):
    def __init__(self):
        super(MyDestructionListener, self).__init__()
    def SayGoodbye(self, joint):
        # remove all references to joint.
        pass

You can then register an instance of your destruction listener with your world object. You should do this during world initialization.

myWorld.SetDestructionListener(myDestructionListener)

[edit] Settings

[edit] About

There are two source files included in Box2D that are supplied specifically for user customization. These are b2Settings.h and b2Settings.cpp.

Box2D works with floating point numbers, so some tolerances have to be used to make Box2D perform well.

[edit] Tolerances

There are many tolerances settings that depend on using MKS units. See Units for a deeper explanation of the unit system. See the doxygen docs for explanation of the individual tolerances.

[edit] Memory Allocation

All of Box2D's memory allocations are funnelled through b2Alloc and b2Free except in the following cases.

  • b2World can be built on the stack or with whatever allocator you like.
  • Any other Box2D class that you create without using a factory method. This includes things like callbacks classes and contact point buffers.

Feel free to redirect the allocation by modifying b2Settings.cpp.

[edit] Rendering

[edit] Debug Drawing

Note: Debug Drawing should probably not be used for your final game. Its purpose is as the name implies, debugging.

You can implement the b2DebugDraw class to get detailed drawing of the physics world. Here are the available entities:

  • shape outlines
  • joint connectivity
  • core shapes (for continuous collision)
  • broad-phase axis-aligned bounding boxes (AABBs), including the world AABB
  • polygon oriented bounding boxes (OBBs)
  • broad-phase pairs (potential contacts)
  • center of mass

This the preferred method of drawing these physics entities for debugging, rather than accessing the data directly. The reason is that much of the necessary data is internal and subject to change.

The testbed draws physics entities using the debug draw facility and the contact listener, so it serves as the primary example of how to implement debug drawing as well as how to draw contact points.

See the pyBox2D b2DebugDraw Callbacks section.

python-box2d-2.0.2+svn20100109.244/doc/manual_files/0000755000000000000000000000000011414467235017710 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/doc/manual_files/revoluteJoint.gif0000644000000000000000000000360011130023047023227 0ustar rootrootGIF89a‹aÕ €€€@@@ðððÀÀÀ¿¿¿???ïïïßßß   ```pppààà ŸŸŸÐÐÐ___PPP///ÏÏϰ°°OOO¯¯¯000oooÿÿÿÿÿÿ!ù ,‹aÿ@pH,ȤrÉl‚§tJ­Z¯S Áz¿àpU¡D”¨xÍnW†!ò©_î¼~z,uƒ |ˆ‰V  ƒ‘ Š–—HZ ’’ ˜£Šdfžž¤®yprtª´ ¯¹`~´¿uºÄUŽÀÀ]ÅÏK ›©ËË ÐÚD¦egÖàÎÛϱsáéiåļ¾êéwí¯Ç ññ…‡ô—ÒÔùRê—¨›™€?€EVJded€ƒaL+B€h¼&’(Ñ®"02 pDà ,<³‡¤MaFR:aiD4ÿbÿ8Ùú¡YÎ d°€~4’ @æƒ 'AhP9Êà,¢D±¡l%!S O€P0l˦}² YõÒ¹ˆ`óŽC‰Qž SÃòÁ- Y|´rdÞÇì†èñT°TÑ‚àÙT¥Íu÷ÐTö¸ô<Édñ8¨b”ò ?ª)±" Z­té}C,:@,$ªƒ“N5TÐÜJˆ…”äêÑàÍ·õH*ay ý ×Ã×YhŰLRï›bÃ#&°¿žáÖ{#µ×ÏÏ‹ó~‘ìç›Qþ!A½ HÝ(À >¶WCX àµ_d‚ÿÁW6]`€‚àÑáZ€UÀˆw"Žy‚À@’AUŽu¬8H:^—݉ À¢*p‚@ä|Èw8²8\xy¦§ß `À$úx@™#ú˜€gc{\-xÁ˜g5bÌH‡9 x€}æ§Juà‰¦B ŒštR@Ö!J €ª`°Áx°Á@A†`À ˜ ‰ ào¥6 €fš˜à’Á®¤Òª$PúX°ÀbšR¡:\€£_>VÀ ,ÀP³DX¨ß\ ·C|ÿá2–bÚ ºE(⺪Ôz+¼LÀÌŒªdiÈ*ËlC½Û„‘¿\pO£\@ÆÚtm¶ÛR8^ªkălLÒ¸åž[àÅTÌ)  T;ɼù´›i;)Ñň4ÇhA÷TqеVTqö€~€èÉAêØ‹k9TpÑfhApˆ<Ð…SXÀZtkuðT¿(ßÔ¢Á<€¦ûÄÐÈ—¬ ‹C%ƒ`´U¤pE  všC00…£ETöQ Hƒ P½À½>…ƒMC- ±D,¨OýVqž*RAŸËGÁ¯yq Ü"X:'²3VDdÏ æFuÿpW¾¹kê˜  È|< 5´ œ¯Ž?#{†È>tÀxdO6âÆ+Ò«à‡ÁXÃM NZkÂür„hà~ºX@¡2rÄDL %~ž ×Äñ’’E·`¹Yæ$h¯®„KOl ‹Oè€ М¨T@. ”s¦@˜¤Ð€‹é‰ìQðÚ¦ÍÖ0@£¼ ~R¤º $7 a– ™(%²¬Ýs\ç!(|„dèYÄæI CÚ³8ZÃÈp¢ÂOip ˜xÀ##IÐ h'™­é€)!€ ªæuP QKoVýE}ˆ`¦0Ä%à‡¢ržÔÑÆÐ^"8™ÒeÀ° Ø…*YÙÓŽñ Ìl£]ºGÑ¢öˆ’&1ºŒèô>ú£*8&€Ì‘ÅS«àˆ/A¢‚Õ‚õôDÀ¹õ­fí©èØŽç8@xÍ«^!ð»¾Ê¯_€í×ÎDØÂ@ZoMl\=¡Ç:>ÀŸõ'[ CÙ˜éõ²à«_E«Àb€„÷ ;python-box2d-2.0.2+svn20100109.244/doc/manual_files/commonPrint.css0000644000000000000000000001225111130023047022710 0ustar rootroot/* ** MediaWiki Print style sheet for CSS2-capable browsers. ** Copyright Gabriel Wicke, http://www.aulinx.de/ ** ** Derived from the plone (http://plone.org/) styles ** Copyright Alexander Limi */ /* Thanks to A List Apart (http://alistapart.com/) for useful extras */ a.stub, a.new{ color:#ba0000; text-decoration:none; } #toc { /*border:1px solid #2f6fab;*/ border:1px solid #aaaaaa; background-color:#f9f9f9; padding:5px; } .tocindent { margin-left: 2em; } .tocline { margin-bottom: 0px; } /* images */ div.floatright { float: right; clear: right; margin: 0; position:relative; border: 0.5em solid White; border-width: 0.5em 0 0.8em 1.4em; } div.floatright p { font-style: italic;} div.floatleft { float: left; margin: 0.3em 0.5em 0.5em 0; position:relative; border: 0.5em solid White; border-width: 0.5em 1.4em 0.8em 0; } div.floatleft p { font-style: italic; } /* thumbnails */ div.thumb { margin-bottom: 0.5em; border-style: solid; border-color: White; width: auto; overflow: hidden; } div.thumb div { border:1px solid #cccccc; padding: 3px !important; background-color:#f9f9f9; font-size: 94%; text-align: center; } div.thumb div a img { border:1px solid #cccccc; } div.thumb div div.thumbcaption { border: none; padding: 0.3em 0 0.1em 0; } div.magnify { display: none; } div.tright { float: right; clear: right; border-width: 0.5em 0 0.8em 1.4em; } div.tleft { float: left; margin-right:0.5em; border-width: 0.5em 1.4em 0.8em 0; } img.thumbborder { border: 1px solid #dddddd; } /* table standards */ table.rimage { float:right; width:1pt; position:relative; margin-left:1em; margin-bottom:1em; text-align:center; } body { background: White; /*font-size: 11pt !important;*/ color: Black; margin: 0; padding: 0; } .noprint, div#jump-to-nav, div.top, div#column-one, #colophon, .editsection, .toctoggle, .tochidden, div#f-poweredbyico, div#f-copyrightico, li#viewcount, li#about, li#disclaimer, li#privacy { /* Hides all the elements irrelevant for printing */ display: none; } ul { list-style-type: square; } #content { background: none; border: none ! important; padding: 0 ! important; margin: 0 ! important; } #footer { background : white; color : black; border-top: 1px solid black; } h1, h2, h3, h4, h5, h6 { font-weight: bold; } p, .documentDescription { margin: 1em 0 ! important; line-height: 1.2em; } .tocindent p { margin: 0 0 0 0 ! important; } pre { border: 1pt dashed black; white-space: pre; font-size: 8pt; overflow: auto; padding: 1em 0; background : white; color : black; } table.listing, table.listing td { border: 1pt solid black; border-collapse: collapse; } a { color: Black !important; background: none !important; padding: 0 !important; } a:link, a:visited { color: #520; background: transparent; text-decoration: underline; } #content a.external.text:after, #content a.external.autonumber:after { /* Expand URLs for printing */ content: " (" attr(href) ") "; } #globalWrapper { width: 100% !important; min-width: 0 !important; } #content { background : white; color : black; } #column-content { margin: 0 !important; } #column-content #content { padding: 1em; margin: 0 !important; } /* MSIE/Win doesn't understand 'inherit' */ a, a.external, a.new, a.stub { color: black ! important; text-decoration: none ! important; } /* Continue ... */ a, a.external, a.new, a.stub { color: inherit ! important; text-decoration: inherit ! important; } img { border: none; } img.tex { vertical-align: middle; } span.texhtml { font-family: serif; } div.townBox { position:relative; float:right; background:White; margin-left:1em; border: 1px solid gray; padding:0.3em; width: 200px; overflow: hidden; clear: right; } div.townBox dl { padding: 0; margin: 0 0 0.3em 0; font-size: 96%; } div.townBox dl dt { background: none; margin: 0.4em 0 0 0; } div.townBox dl dd { margin: 0.1em 0 0 1.1em; background-color: #f3f3f3; } #siteNotice { display: none; } table.gallery { border: 1px solid #cccccc; margin: 2px; padding: 2px; background-color:#ffffff; } table.gallery tr { vertical-align:top; } div.gallerybox { border: 1px solid #cccccc; margin: 2px; background-color:#f9f9f9; width: 150px; } div.gallerybox div.thumb { text-align: center; border: 1px solid #cccccc; margin: 2px; } div.gallerytext { font-size: 94%; padding: 2px 4px; } /* ** Diff rendering */ table.diff { background:white; } td.diff-otitle { background:#ffffff; } td.diff-ntitle { background:#ffffff; } td.diff-addedline { background:#ccffcc; font-size: smaller; border: solid 2px black; } td.diff-deletedline { background:#ffffaa; font-size: smaller; border: dotted 2px black; } td.diff-context { background:#eeeeee; font-size: smaller; } .diffchange { color: silver; font-weight: bold; text-decoration: underline; } python-box2d-2.0.2+svn20100109.244/doc/manual_files/ajax.js0000644000000000000000000001071311130023047021153 0ustar rootroot// remote scripting library // (c) copyright 2005 modernmethod, inc var sajax_debug_mode = false; var sajax_request_type = "GET"; /** * if sajax_debug_mode is true, this function outputs given the message into * the element with id = sajax_debug; if no such element exists in the document, * it is injected. */ function sajax_debug(text) { if (!sajax_debug_mode) return false; var e= document.getElementById('sajax_debug'); if (!e) { e= document.createElement("p"); e.className= 'sajax_debug'; e.id= 'sajax_debug'; var b= document.getElementsByTagName("body")[0]; if (b.firstChild) b.insertBefore(e, b.firstChild); else b.appendChild(e); } var m= document.createElement("div"); m.appendChild( document.createTextNode( text ) ); e.appendChild( m ); return true; } /** * compatibility wrapper for creating a new XMLHttpRequest object. */ function sajax_init_object() { sajax_debug("sajax_init_object() called..") var A; try { // Try the new style before ActiveX so we don't // unnecessarily trigger warnings in IE 7 when // set to prompt about ActiveX usage A = new XMLHttpRequest(); } catch (e) { try { A=new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { A=new ActiveXObject("Microsoft.XMLHTTP"); } catch (oc) { A=null; } } } if (!A) sajax_debug("Could not create connection object."); return A; } /** * Perform an ajax call to mediawiki. Calls are handeled by AjaxDispatcher.php * func_name - the name of the function to call. Must be registered in $wgAjaxExportList * args - an array of arguments to that function * target - the target that will handle the result of the call. If this is a function, * if will be called with the XMLHttpRequest as a parameter; if it's an input * element, its value will be set to the resultText; if it's another type of * element, its innerHTML will be set to the resultText. * * Example: * sajax_do_call('doFoo', [1, 2, 3], document.getElementById("showFoo")); * * This will call the doFoo function via MediaWiki's AjaxDispatcher, with * (1, 2, 3) as the parameter list, and will show the result in the element * with id = showFoo */ function sajax_do_call(func_name, args, target) { var i, x, n; var uri; var post_data; uri = wgServer + ((wgScript == null) ? (wgScriptPath + "/index.php") : wgScript) + "?action=ajax"; if (sajax_request_type == "GET") { if (uri.indexOf("?") == -1) uri = uri + "?rs=" + encodeURIComponent(func_name); else uri = uri + "&rs=" + encodeURIComponent(func_name); for (i = 0; i < args.length; i++) uri = uri + "&rsargs[]=" + encodeURIComponent(args[i]); //uri = uri + "&rsrnd=" + new Date().getTime(); post_data = null; } else { post_data = "rs=" + encodeURIComponent(func_name); for (i = 0; i < args.length; i++) post_data = post_data + "&rsargs[]=" + encodeURIComponent(args[i]); } x = sajax_init_object(); if (!x) { alert("AJAX not supported"); return false; } try { x.open(sajax_request_type, uri, true); } catch (e) { if (window.location.hostname == "localhost") { alert("Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing."); } throw e; } if (sajax_request_type == "POST") { x.setRequestHeader("Method", "POST " + uri + " HTTP/1.1"); x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); } x.setRequestHeader("Pragma", "cache=yes"); x.setRequestHeader("Cache-Control", "no-transform"); x.onreadystatechange = function() { if (x.readyState != 4) return; sajax_debug("received (" + x.status + " " + x.statusText + ") " + x.responseText); //if (x.status != 200) // alert("Error: " + x.status + " " + x.statusText + ": " + x.responseText); //else if ( typeof( target ) == 'function' ) { target( x ); } else if ( typeof( target ) == 'object' ) { if ( target.tagName == 'INPUT' ) { if (x.status == 200) target.value= x.responseText; //else alert("Error: " + x.status + " " + x.statusText + " (" + x.responseText + ")"); } else { if (x.status == 200) target.innerHTML = x.responseText; else target.innerHTML= "
Error: " + x.status + " " + x.statusText + " (" + x.responseText + ")
"; } } else { alert("bad target for sajax_do_call: not a function or object: " + target); } return; } sajax_debug(func_name + " uri = " + uri + " / post = " + post_data); x.send(post_data); sajax_debug(func_name + " waiting.."); delete x; return true; } python-box2d-2.0.2+svn20100109.244/doc/manual_files/convex_concave.gif0000644000000000000000000000437711130023047023372 0ustar rootrootGIF89aß}Õ €€€   ÀÀÀðððààà@@@ïïï000°°°ÐÐÐ ```???¿¿¿ppp///PPPßßßÏÏÏŸŸŸ___oooOOO¯¯¯ÿÿÿÿÿÿ!ù ,ß}ÿ@pH,Èäb`(ŸÐ¨tJ­Z¯Ø¬VI8P0aK.›Ïè´zXXtEÄ1XÛïø¼Ú0d>€€{†‡ˆ‰T Š•–—x˜£¤¥Tžžc¦±²¤]p«ž M³½¾† ·¸«°¿ËÌd}ÅÑqtÍÖ×S ŽÒÒƒØáâDÝè’”ãį́ªèò ¢î÷± ¶òý‘ àx)Øþt@°á¡>Jü ™2‡Óhã6¡‚êdYf‚x'‚™p‘¤K) P@™r¢…“^ê„¢_ÍÿŸÚI´H*(°(Ñ"* h—=D"怀#Õ©4$C”  Ö'M¯˜¤ùuêG^†tHÀò¬†VÁKÁBÛ¿€ŽÕÕaÃÍ…v‡#dE_b€ÛÞtÀ©aduÊ(@½Rú$yè5 "<T!­Î˜æ>~ÂÀÀÒ¸EÊig€†N 2Ð2c°Ç€>gëš»ù§Pw¬º0‡!ÉΔGpÒ¹ó°¯Ö8`ȃ«ÊaŸË>ûnŸÞ›‡‹æÀúU „)>î8ääí¡ÏñxŒhL U1à5Ø­¢¢há4Õ˜ñÀhÅH@ÿA†á¨WÌ„F0âÕ…ñ™fƪɆY×ø ‰Dh Š(ªA =Ä5áŒíqGŽÞ)€ÀfZ$ð_7‡Y׋ˆÝÐXË“HzÀgØ7QfL’ÒrèØY^¨d˜YTp¢?úAà&µAÓτϤ‰c qYMó‰‰I7Þ9”‰zæˆÀœ[ÐbMÔ9àD%mô%‘råÜ—hìˆÆP…Áy‰ÔÙÑgš¹in$À(ÒQ•ß~†šÒg „ºª…€£†~}eHWÙQi°§ì®ñI`dxù—‡ ¦aêOÊƬw<¸…‚¤½øª¶*¥\®Û6çÿ,´d`gdºÅ.ÇR¥Ý²é’A±i°Ø\”[\kïPÜ–/`8€G>~ç ›Q”û•vèzp[HiG¬Z†1.=!;ñP$ òÅ?%¬ÇšÊç Pq8ò£L•×Wh³sLšD9oÎ,„£6›Ë¥¢8êè Q‹ª;ídÑ)­¹‡ ™]ÅŒe[$ºIõ©Gëáo–ÃBÐZ‚†õØ)Ùô%'J­PÿEbÉ_ÃK§ˆà«çô bûŽ«ˆH«¸¹§=õãÒŽˆ¶”c{ZSg>ݳ‰¸ëyM4‚°@Оw«Hj£ß:›ä­?²®" üÿû¥³q~; ªWÂñîó´·ÀΞK °%ãoèÞžñ%¯üˆíõ»Ê—$=½4¥ 1|ëÏ_ÒüöÜ€Ì~oP¶%g“O=… Sn5&º»ÿ>H?ö–¥tn¿'ÝÂÐW´ùÂqÿcOF9xЉK “<¿µêc¡[¤„ ¼kl–+E® ·½ ¡v4ŒD -sŸ …PAªuÀ[– &à€t`ykÝ AàÁ±Ín€€`àd±¢oÆÖ»= Ð@žx»!‚ÀAÜÔûó€$€ð QæE|ð`ÐØ=€œÿ†ó"lw1ìaD‡°c€¸? Œ( ŸK’¸Ä&òb^æò…h%‰XÔ"·ItåË€giÀ 4®1>‘ü"7ſĎfDc /”ÊIî ”®Ð€0F&•ždŸrÉ%2ñ‡¾ŒZJ¶J´-Š˜S`¤°Åf - 5ÛU¡IQf2jü¥!‡P±]]›Z€åÓ¶q ™«ê:ͰKâQsT¨ O™›1γ €ì!2“EÀŒ e"ÐÏl@mNÿ™Fs“ÁÓB08¨J…rÀ3€h2WáOŠ®Á›ÿYÜâS™ŽÒñ£8h€€…¾Ð3€è×öåÒ‡ –¦ÄMÅQ|ô¨M¨B€ ¯¨‰@ íÙ²¥Zb£ýhΰª@ ’^%«K-Š ¸S­pA0Ö¸Úõ®xÍ«^÷Ê×¾úõ¯€ ¬`KØÂö°ˆM¬bËØÆ:ö±¬dó0€V ®ƒ­ì.[”2R‚ó¬gAZ¢tÀš2€$@ «% † H¢¤èi[BÕ²Öµi¡£m=*ˆdN ÀZ=(±p€àÔQµ ƒ€=TÈÍ@ è“f(ú\"DwºÕ]ÿÛ°+„ L¹ `€|«+€> ˆ.Ê8ŠaÖ8à+Í À’ è“Y`ïAÀWÿô/<´˜£ö%B¾Ë`Ð6¸¶Þ›"ê[„—K61ª †”å GÓ†ˆ‰Ib"¨@ñPL,á¡`(D‹Ÿ{€ÀxƆ8­k( ¯mÇu˜ÀŽ·×ÀÈð<•<áÊ &‚ÆàßW€L.#èÊ€œ—ºÖ…²\à©î7Ê…X€Ïæ¹fäºYºp~²T¼ÀרÍP`É9 ¾bzb«\æ £CkJlO(éÜv ¹]«¤)½\X`ºÉMqjrk[‘— ÝódgMë^;python-box2d-2.0.2+svn20100109.244/doc/manual_files/distanceJoint.gif0000644000000000000000000000446611130023047023167 0ustar rootrootGIF89a›vÕ @@@ÀÀÀ€€€¿¿¿???ðððïïïÐÐÐÏÏÏààà   000ppp¯¯¯ooo°°°```PPPßßß ___///OOOŸŸŸÿÿÿÿÿÿ!ù ,›vÿ@pH,Ȥr¸hT0HbI­Z¯Ø¬v›4P@a£ød$Ü´zÍnƒ°æ@øØí‹{Ïïïwˆ ~ŽG  ‰švŸ kMO™›©f¡­®J^`bdªµv¯º¯prt¶Àv»ÅŽ€‚„†ÁÌvÆÑ¢“•—¨ÍØÒÜW£P¦×ØãÝèG±aceäïˆé齃¿ðùˆÐôÆÈƒ ÒGðÎ þ^I¢d SÁ‡ˆ`Høé[©S3&‚°€HVT<˜rD@Ç„‚Úi\™¨C"rU ੈ‚Ðø«°¥OÿD‰i…¦ óó× Ãϧ  ¨ß— $<Ca€$2ÑßOŸJŠaA  \À`s0Àºm…— 1ÔIËòÌT!XèGõ£šê6b o ³ÌsÄ€T…|þüØÓ€ EÏ£H¡€æ•‹:$s¶ óxŠœúúÑ3àõÊNB X¨à±…€0òÁÉ8q®öç ‚ñŒRoO±Èƒ ß!ââbaÀØòE(hHÿp—Ûá0¾¾gúõ€wþé£M€| Aú˜ƒàpà“;?Éó  ˆóЮ1ÿAhX ?¶a+Ð!0 ÐÑÁ|ÌT", î €À"@À!*~ðã8Þq äX3͸FhS@LpÀA ÁÌÑktÁ ÀNÙqÌpä¤ P¨Ê‚~0åd¦Á!†„iGqôôÞ-iˆµ¸4g<±x‡zÖÑçŠ Ùaq{š‘Y¦ØLPrÑ”-¸d–f‰©虢¢ h§-Q•ºÅY¼¾:ûÁèÁ!ûÁ0Hr ÀNAûP€»Ú²–¯YfK p€±ú8ÿ¤d+E^Pè!è–n¬ƒ5c¸X`Æ`>œñ{Ekÿ›ÀV§Ñp€âSÈ!\EwÀÅtKgr`/qD`¼&D @Ô2òA”ɆÂÓbÉø–ßËUðWŸÇb@ðp3 lÐTÐÀÎ<_1`FEAý¥rpÀ€ œÔt úT¦´šp<Ljõµ>µ†¦¬ÁÊ-¯íG†Oy09#e·#'®TôÑISâòßÔøÐÕYoÝõ L‡ø1Q¾c6ÚjGâ€^O¾GãÈM÷áJH²çmD*)Î:k!0ú§¦2ÿ8ÒJËŽÅM¼7û¯•»‰µÖ\wÞ†èô;‚]@Ú¾÷‘è¾ü@0º+TÀé×S‘€ßÅDnYø.°¹ñèë'píøzìñ#x“ÑןÐÉëàô°^Eòç?ÊnóûšHX èr Ï'€ ”¥iFÑÂj–2„¬/Ù+® fA($Âû q—?Ù!<_3Šœ€†P € Žþ `HÀsâ;¦azp*Ç90è‰ÌC/·I]@ >*ÂKRzg“௑«ÙÀ>ÅŸáQ° !‹o,Íø§<6 ÿùBDê(±3RfK©€8‚À„E © n¥"`/3JhÐ@‚ 2E qäˆåèåˆè@Õ1ŒEÎhik#°I, &¸ N€X–¨ä£"'Á*¼®VµÐõ–6„^ZÁƒ³Á‚„ R]/Ÿ‰*Ãø)!„ÌèUø^IB,P`:lá(m1"”Q¦ôܼHÀ·$‘"hª°€O¡‡§CÝ Ë0¾£I0‘ )Oc"î6Âð˜9MŇã!‚Ó ˆód,- F髎·QŒÀ²˜Ei¨¦-Á’¦}ÿ)Å€( â% a8ô Y(¡Ðä6¢¹hü¾™-6£”ùLúš—J’^{iø–é0LTð(ÈÖæ¥>õDH ¾î‘í˜À8Gõ@Uº%Ó“¢xC è‡*<êÄ™ˆTqK]ã8˜ðɯ¬f-k€KÍ)“üΪP–öЦfS øÑåò(8´T” cyF<µÐžú-4´›øìÅP[ \°€ @Gƒa±‹}iß‚­øB¹ÖT И-`¨Û%|33ÆqPq“°L¬¾†ŒË5‚Y…›GE— (@oñÛ£F _Œ.dó!«`\ KF²ÿPt9Kòҹΰf±¹‰IcÈZ&¬Ê!Kv˜TPDh)Àðý€3a{“Ù¦BB«ê z; +XGÅñz2ø ÁˆÐf‘¸Ýgm ®aŸ>‘MUÊ`±A|¨nÎ(“_|©ŒÙ].ޱ&ГL] £ß»‰ ÿV*¾T4@2Ȫ8àÀ!´;«'"¯-kŒ wJ¨êÊ…{‡]`ú•&PàãkÖC·™Ýì{Dß[€ùgUx@ ¿co¡s¬ÞÙÑwѶÐêìø i`,q$®´y¥‚8jš/ÏS–üéf$™g¤n©5áÚµ©ïUøÒªk‘Û—Y ;¸6™®/¦mùú×ÈRŸ†MìïÆúØ~®fÃרf;»±£‰v´qMmœìZ×½ö¯ÍlÓ4;python-box2d-2.0.2+svn20100109.244/doc/manual_files/wikibits.js0000644000000000000000000011726111130023047022063 0ustar rootroot// MediaWiki JavaScript support functions var clientPC = navigator.userAgent.toLowerCase(); // Get client info var is_gecko = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1) && (clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1)); var is_safari = ((clientPC.indexOf('applewebkit')!=-1) && (clientPC.indexOf('spoofer')==-1)); var is_khtml = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled )); // For accesskeys var is_ff2_win = (clientPC.indexOf('firefox/2')!=-1 || clientPC.indexOf('minefield/3')!=-1) && clientPC.indexOf('windows')!=-1; var is_ff2_x11 = (clientPC.indexOf('firefox/2')!=-1 || clientPC.indexOf('minefield/3')!=-1) && clientPC.indexOf('x11')!=-1; if (clientPC.indexOf('opera') != -1) { var is_opera = true; var is_opera_preseven = (window.opera && !document.childNodes); var is_opera_seven = (window.opera && document.childNodes); var is_opera_95 = (clientPC.search(/opera\/(9.[5-9]|[1-9][0-9])/)!=-1); } // Global external objects used by this script. /*extern ta, stylepath, skin */ // add any onload functions in this hook (please don't hard-code any events in the xhtml source) var doneOnloadHook; if (!window.onloadFuncts) { var onloadFuncts = []; } function addOnloadHook(hookFunct) { // Allows add-on scripts to add onload functions onloadFuncts[onloadFuncts.length] = hookFunct; } function hookEvent(hookName, hookFunct) { if (window.addEventListener) { window.addEventListener(hookName, hookFunct, false); } else if (window.attachEvent) { window.attachEvent("on" + hookName, hookFunct); } } // document.write special stylesheet links if (typeof stylepath != 'undefined' && typeof skin != 'undefined') { if (is_opera_preseven) { document.write(''); } else if (is_opera_seven && !is_opera_95) { document.write(''); } else if (is_khtml) { document.write(''); } } if (wgBreakFrames) { // Un-trap us from framesets if (window.top != window) { window.top.location = window.location; } } // for enhanced RecentChanges function toggleVisibility(_levelId, _otherId, _linkId) { var thisLevel = document.getElementById(_levelId); var otherLevel = document.getElementById(_otherId); var linkLevel = document.getElementById(_linkId); if (thisLevel.style.display == 'none') { thisLevel.style.display = 'block'; otherLevel.style.display = 'none'; linkLevel.style.display = 'inline'; } else { thisLevel.style.display = 'none'; otherLevel.style.display = 'inline'; linkLevel.style.display = 'none'; } } function historyRadios(parent) { var inputs = parent.getElementsByTagName('input'); var radios = []; for (var i = 0; i < inputs.length; i++) { if (inputs[i].name == "diff" || inputs[i].name == "oldid") { radios[radios.length] = inputs[i]; } } return radios; } // check selection and tweak visibility/class onclick function diffcheck() { var dli = false; // the li where the diff radio is checked var oli = false; // the li where the oldid radio is checked var hf = document.getElementById('pagehistory'); if (!hf) { return true; } var lis = hf.getElementsByTagName('li'); for (var i=0;i= 0) ? "-" : "+") + ((tzHour < 10) ? "0" : "") + tzHour + ((tzMin < 10) ? "0" : "") + tzMin; if (tz != tzString) { var junk = msg.split('$1'); document.write(junk[0] + "UTC" + tzString + junk[1]); } } function unhidetzbutton() { var tzb = document.getElementById('guesstimezonebutton'); if (tzb) { tzb.style.display = 'inline'; } } // in [-]HH:MM format... // won't yet work with non-even tzs function fetchTimezone() { // FIXME: work around Safari bug var localclock = new Date(); // returns negative offset from GMT in minutes var tzRaw = localclock.getTimezoneOffset(); var tzHour = Math.floor( Math.abs(tzRaw) / 60); var tzMin = Math.abs(tzRaw) % 60; var tzString = ((tzRaw >= 0) ? "-" : "") + ((tzHour < 10) ? "0" : "") + tzHour + ":" + ((tzMin < 10) ? "0" : "") + tzMin; return tzString; } function guessTimezone(box) { document.getElementsByName("wpHourDiff")[0].value = fetchTimezone(); } function showTocToggle() { if (document.createTextNode) { // Uses DOM calls to avoid document.write + XHTML issues var linkHolder = document.getElementById('toctitle'); if (!linkHolder) { return; } var outerSpan = document.createElement('span'); outerSpan.className = 'toctoggle'; var toggleLink = document.createElement('a'); toggleLink.id = 'togglelink'; toggleLink.className = 'internal'; toggleLink.href = 'javascript:toggleToc()'; toggleLink.appendChild(document.createTextNode(tocHideText)); outerSpan.appendChild(document.createTextNode('[')); outerSpan.appendChild(toggleLink); outerSpan.appendChild(document.createTextNode(']')); linkHolder.appendChild(document.createTextNode(' ')); linkHolder.appendChild(outerSpan); var cookiePos = document.cookie.indexOf("hidetoc="); if (cookiePos > -1 && document.cookie.charAt(cookiePos + 8) == 1) { toggleToc(); } } } function changeText(el, newText) { // Safari work around if (el.innerText) { el.innerText = newText; } else if (el.firstChild && el.firstChild.nodeValue) { el.firstChild.nodeValue = newText; } } function toggleToc() { var toc = document.getElementById('toc').getElementsByTagName('ul')[0]; var toggleLink = document.getElementById('togglelink'); if (toc && toggleLink && toc.style.display == 'none') { changeText(toggleLink, tocHideText); toc.style.display = 'block'; document.cookie = "hidetoc=0"; } else { changeText(toggleLink, tocShowText); toc.style.display = 'none'; document.cookie = "hidetoc=1"; } } var mwEditButtons = []; var mwCustomEditButtons = []; // eg to add in MediaWiki:Common.js // this function generates the actual toolbar buttons with localized text // we use it to avoid creating the toolbar where javascript is not enabled function addButton(imageFile, speedTip, tagOpen, tagClose, sampleText, imageId) { // Don't generate buttons for browsers which don't fully // support it. mwEditButtons[mwEditButtons.length] = {"imageId": imageId, "imageFile": imageFile, "speedTip": speedTip, "tagOpen": tagOpen, "tagClose": tagClose, "sampleText": sampleText}; } // this function generates the actual toolbar buttons with localized text // we use it to avoid creating the toolbar where javascript is not enabled function mwInsertEditButton(parent, item) { var image = document.createElement("img"); image.width = 23; image.height = 22; image.className = "mw-toolbar-editbutton"; if (item.imageId) image.id = item.imageId; image.src = item.imageFile; image.border = 0; image.alt = item.speedTip; image.title = item.speedTip; image.style.cursor = "pointer"; image.onclick = function() { insertTags(item.tagOpen, item.tagClose, item.sampleText); return false; }; parent.appendChild(image); return true; } function mwSetupToolbar() { var toolbar = document.getElementById('toolbar'); if (!toolbar) { return false; } var textbox = document.getElementById('wpTextbox1'); if (!textbox) { return false; } // Don't generate buttons for browsers which don't fully // support it. if (!(document.selection && document.selection.createRange) && textbox.selectionStart === null) { return false; } for (var i = 0; i < mwEditButtons.length; i++) { mwInsertEditButton(toolbar, mwEditButtons[i]); } for (var i = 0; i < mwCustomEditButtons.length; i++) { mwInsertEditButton(toolbar, mwCustomEditButtons[i]); } return true; } function escapeQuotes(text) { var re = new RegExp("'","g"); text = text.replace(re,"\\'"); re = new RegExp("\\n","g"); text = text.replace(re,"\\n"); return escapeQuotesHTML(text); } function escapeQuotesHTML(text) { var re = new RegExp('&',"g"); text = text.replace(re,"&"); re = new RegExp('"',"g"); text = text.replace(re,"""); re = new RegExp('<',"g"); text = text.replace(re,"<"); re = new RegExp('>',"g"); text = text.replace(re,">"); return text; } // apply tagOpen/tagClose to selection in textarea, // use sampleText instead of selection if there is none function insertTags(tagOpen, tagClose, sampleText) { var txtarea; if (document.editform) { txtarea = document.editform.wpTextbox1; } else { // some alternate form? take the first one we can find var areas = document.getElementsByTagName('textarea'); txtarea = areas[0]; } var selText, isSample = false; if (document.selection && document.selection.createRange) { // IE/Opera //save window scroll position if (document.documentElement && document.documentElement.scrollTop) var winScroll = document.documentElement.scrollTop else if (document.body) var winScroll = document.body.scrollTop; //get current selection txtarea.focus(); var range = document.selection.createRange(); selText = range.text; //insert tags checkSelectedText(); range.text = tagOpen + selText + tagClose; //mark sample text as selected if (isSample && range.moveStart) { if (window.opera) tagClose = tagClose.replace(/\n/g,''); range.moveStart('character', - tagClose.length - selText.length); range.moveEnd('character', - tagClose.length); } range.select(); //restore window scroll position if (document.documentElement && document.documentElement.scrollTop) document.documentElement.scrollTop = winScroll else if (document.body) document.body.scrollTop = winScroll; } else if (txtarea.selectionStart || txtarea.selectionStart == '0') { // Mozilla //save textarea scroll position var textScroll = txtarea.scrollTop; //get current selection txtarea.focus(); var startPos = txtarea.selectionStart; var endPos = txtarea.selectionEnd; selText = txtarea.value.substring(startPos, endPos); //insert tags checkSelectedText(); txtarea.value = txtarea.value.substring(0, startPos) + tagOpen + selText + tagClose + txtarea.value.substring(endPos, txtarea.value.length); //set new selection if (isSample) { txtarea.selectionStart = startPos + tagOpen.length; txtarea.selectionEnd = startPos + tagOpen.length + selText.length; } else { txtarea.selectionStart = startPos + tagOpen.length + selText.length + tagClose.length; txtarea.selectionEnd = txtarea.selectionStart; } //restore textarea scroll position txtarea.scrollTop = textScroll; } function checkSelectedText(){ if (!selText) { selText = sampleText; isSample = true; } else if (selText.charAt(selText.length - 1) == ' ') { //exclude ending space char selText = selText.substring(0, selText.length - 1); tagClose += ' ' } } } /** * Set the accesskey prefix based on browser detection. */ var tooltipAccessKeyPrefix = 'alt-'; if (is_opera) { tooltipAccessKeyPrefix = 'shift-esc-'; } else if (is_safari || navigator.userAgent.toLowerCase().indexOf('mac') != -1 || navigator.userAgent.toLowerCase().indexOf('konqueror') != -1 ) { tooltipAccessKeyPrefix = 'ctrl-'; } else if (is_ff2_x11 || is_ff2_win) { tooltipAccessKeyPrefix = 'alt-shift-'; } var tooltipAccessKeyRegexp = /\[(ctrl-)?(alt-)?(shift-)?(esc-)?.\]$/; /** * Add the appropriate prefix to the accesskey shown in the tooltip. * If the nodeList parameter is given, only those nodes are updated; * otherwise, all the nodes that will probably have accesskeys by * default are updated. * * @param Array nodeList -- list of elements to update */ function updateTooltipAccessKeys( nodeList ) { if ( !nodeList ) { // skins without a "column-one" element don't seem to have links with accesskeys either var columnOne = document.getElementById("column-one"); if ( columnOne ) updateTooltipAccessKeys( columnOne.getElementsByTagName("a") ); // these are rare enough that no such optimization is needed updateTooltipAccessKeys( document.getElementsByTagName("input") ); updateTooltipAccessKeys( document.getElementsByTagName("label") ); return; } for ( var i = 0; i < nodeList.length; i++ ) { var element = nodeList[i]; var tip = element.getAttribute("title"); var key = element.getAttribute("accesskey"); if ( key && tooltipAccessKeyRegexp.exec(tip) ) { tip = tip.replace(tooltipAccessKeyRegexp, "["+tooltipAccessKeyPrefix+key+"]"); element.setAttribute("title", tip ); } } } /** * Add a link to one of the portlet menus on the page, including: * * p-cactions: Content actions (shown as tabs above the main content in Monobook) * p-personal: Personal tools (shown at the top right of the page in Monobook) * p-navigation: Navigation * p-tb: Toolbox * * This function exists for the convenience of custom JS authors. All * but the first three parameters are optional, though providing at * least an id and a tooltip is recommended. * * By default the new link will be added to the end of the list. To * add the link before a given existing item, pass the DOM node of * that item (easily obtained with document.getElementById()) as the * nextnode parameter; to add the link _after_ an existing item, pass * the node's nextSibling instead. * * @param String portlet -- id of the target portlet ("p-cactions", "p-personal", "p-navigation" or "p-tb") * @param String href -- link URL * @param String text -- link text (will be automatically lowercased by CSS for p-cactions in Monobook) * @param String id -- id of the new item, should be unique and preferably have the appropriate prefix ("ca-", "pt-", "n-" or "t-") * @param String tooltip -- text to show when hovering over the link, without accesskey suffix * @param String accesskey -- accesskey to activate this link (one character, try to avoid conflicts) * @param Node nextnode -- the DOM node before which the new item should be added, should be another item in the same list * * @return Node -- the DOM node of the new item (an LI element) or null */ function addPortletLink(portlet, href, text, id, tooltip, accesskey, nextnode) { var node = document.getElementById(portlet); if ( !node ) return null; node = node.getElementsByTagName( "ul" )[0]; if ( !node ) return null; var link = document.createElement( "a" ); link.appendChild( document.createTextNode( text ) ); link.href = href; var item = document.createElement( "li" ); item.appendChild( link ); if ( id ) item.id = id; if ( accesskey ) { link.setAttribute( "accesskey", accesskey ); tooltip += " ["+accesskey+"]"; } if ( tooltip ) { link.setAttribute( "title", tooltip ); } if ( accesskey && tooltip ) { updateTooltipAccessKeys( new Array( link ) ); } if ( nextnode && nextnode.parentNode == node ) node.insertBefore( item, nextnode ); else node.appendChild( item ); // IE compatibility (?) return item; } /** * Set up accesskeys/tooltips from the deprecated ta array. If doId * is specified, only set up for that id. Note that this function is * deprecated and will not be supported indefinitely -- use * updateTooltipAccessKey() instead. * * @param mixed doId string or null */ function akeytt( doId ) { // A lot of user scripts (and some of the code below) break if // ta isn't defined, so we make sure it is. Explictly using // window.ta avoids a "ta is not defined" error. if (!window.ta) window.ta = new Array; // Make a local, possibly restricted, copy to avoid clobbering // the original. var ta; if ( doId ) { ta = [doId]; } else { ta = window.ta; } // Now deal with evil deprecated ta var watchCheckboxExists = document.getElementById( 'wpWatchthis' ) ? true : false; for (var id in ta) { var n = document.getElementById(id); if (n) { var a = null; var ak = ''; // Are we putting accesskey in it if (ta[id][0].length > 0) { // Is this object a object? If not assume it's the next child. if (n.nodeName.toLowerCase() == "a") { a = n; } else { a = n.childNodes[0]; } // Don't add an accesskey for the watch tab if the watch // checkbox is also available. if (a && ((id != 'ca-watch' && id != 'ca-unwatch') || !watchCheckboxExists)) { a.accessKey = ta[id][0]; ak = ' ['+tooltipAccessKeyPrefix+ta[id][0]+']'; } } else { // We don't care what type the object is when assigning tooltip a = n; ak = ''; } if (a) { a.title = ta[id][1]+ak; } } } } function setupRightClickEdit() { if (document.getElementsByTagName) { var spans = document.getElementsByTagName('span'); for (var i = 0; i < spans.length; i++) { var el = spans[i]; if(el.className == 'editsection') { addRightClickEditHandler(el); } } } } function addRightClickEditHandler(el) { for (var i = 0; i < el.childNodes.length; i++) { var link = el.childNodes[i]; if (link.nodeType == 1 && link.nodeName.toLowerCase() == 'a') { var editHref = link.getAttribute('href'); // find the enclosing (parent) header var prev = el.parentNode; if (prev && prev.nodeType == 1 && prev.nodeName.match(/^[Hh][1-6]$/)) { prev.oncontextmenu = function(e) { if (!e) { e = window.event; } // e is now the event in all browsers var targ; if (e.target) { targ = e.target; } else if (e.srcElement) { targ = e.srcElement; } if (targ.nodeType == 3) { // defeat Safari bug targ = targ.parentNode; } // targ is now the target element // We don't want to deprive the noble reader of a context menu // for the section edit link, do we? (Might want to extend this // to all 's?) if (targ.nodeName.toLowerCase() != 'a' || targ.parentNode.className != 'editsection') { document.location = editHref; return false; } return true; }; } } } } var checkboxes; var lastCheckbox; function setupCheckboxShiftClick() { checkboxes = []; lastCheckbox = null; var inputs = document.getElementsByTagName('input'); addCheckboxClickHandlers(inputs); } function addCheckboxClickHandlers(inputs, start) { if ( !start) start = 0; var finish = start + 250; if ( finish > inputs.length ) finish = inputs.length; for ( var i = start; i < finish; i++ ) { var cb = inputs[i]; if ( !cb.type || cb.type.toLowerCase() != 'checkbox' ) continue; var end = checkboxes.length; checkboxes[end] = cb; cb.index = end; cb.onclick = checkboxClickHandler; } if ( finish < inputs.length ) { setTimeout( function () { addCheckboxClickHandlers(inputs, finish); }, 200 ); } } function checkboxClickHandler(e) { if (typeof e == 'undefined') { e = window.event; } if ( !e.shiftKey || lastCheckbox === null ) { lastCheckbox = this.index; return true; } var endState = this.checked; var start, finish; if ( this.index < lastCheckbox ) { start = this.index + 1; finish = lastCheckbox; } else { start = lastCheckbox; finish = this.index - 1; } for (var i = start; i <= finish; ++i ) { checkboxes[i].checked = endState; } lastCheckbox = this.index; return true; } function toggle_element_activation(ida,idb) { if (!document.getElementById) { return; } document.getElementById(ida).disabled=true; document.getElementById(idb).disabled=false; } function toggle_element_check(ida,idb) { if (!document.getElementById) { return; } document.getElementById(ida).checked=true; document.getElementById(idb).checked=false; } /** * Restore the edit box scroll state following a preview operation, * and set up a form submission handler to remember this state */ function scrollEditBox() { var editBox = document.getElementById( 'wpTextbox1' ); var scrollTop = document.getElementById( 'wpScrolltop' ); var editForm = document.getElementById( 'editform' ); if( editBox && scrollTop ) { if( scrollTop.value ) editBox.scrollTop = scrollTop.value; addHandler( editForm, 'submit', function() { document.getElementById( 'wpScrolltop' ).value = document.getElementById( 'wpTextbox1' ).scrollTop; } ); } } hookEvent( 'load', scrollEditBox ); var allmessages_nodelist = false; var allmessages_modified = false; var allmessages_timeout = false; var allmessages_running = false; function allmessagesmodified() { allmessages_modified = !allmessages_modified; allmessagesfilter(); } function allmessagesfilter() { if ( allmessages_timeout ) window.clearTimeout( allmessages_timeout ); if ( !allmessages_running ) allmessages_timeout = window.setTimeout( 'allmessagesfilter_do();', 500 ); } function allmessagesfilter_do() { if ( !allmessages_nodelist ) return; var text = document.getElementById('allmessagesinput').value; var nodef = allmessages_modified; allmessages_running = true; for ( var name in allmessages_nodelist ) { var nodes = allmessages_nodelist[name]; var display = ( name.indexOf( text ) == -1 ? 'none' : '' ); for ( var i = 0; i < nodes.length; i++) nodes[i].style.display = ( nodes[i].className == "def" && nodef ? 'none' : display ); } if ( text != document.getElementById('allmessagesinput').value || nodef != allmessages_modified ) allmessagesfilter_do(); // repeat allmessages_running = false; } function allmessagesfilter_init() { if ( allmessages_nodelist ) return; var nodelist = new Array(); var templist = new Array(); var table = document.getElementById('allmessagestable'); if ( !table ) return; var rows = document.getElementsByTagName('tr'); for ( var i = 0; i < rows.length; i++ ) { var id = rows[i].getAttribute('id') if ( id && id.substring(0,16) != 'sp-allmessages-r' ) continue; templist[ id ] = rows[i]; } var spans = table.getElementsByTagName('span'); for ( var i = 0; i < spans.length; i++ ) { var id = spans[i].getAttribute('id') if ( id && id.substring(0,17) != 'sp-allmessages-i-' ) continue; if ( !spans[i].firstChild || spans[i].firstChild.nodeType != 3 ) continue; var nodes = new Array(); var row1 = templist[ id.replace('i', 'r1') ]; var row2 = templist[ id.replace('i', 'r2') ]; if ( row1 ) nodes[nodes.length] = row1; if ( row2 ) nodes[nodes.length] = row2; nodelist[ spans[i].firstChild.nodeValue ] = nodes; } var k = document.getElementById('allmessagesfilter'); if (k) { k.style.display = ''; } allmessages_nodelist = nodelist; } hookEvent( "load", allmessagesfilter_init ); /* Written by Jonathan Snook, http://www.snook.ca/jonathan Add-ons by Robert Nyman, http://www.robertnyman.com Author says "The credit comment is all it takes, no license. Go crazy with it!:-)" From http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/ */ function getElementsByClassName(oElm, strTagName, oClassNames){ var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName); var arrReturnElements = new Array(); var arrRegExpClassNames = new Array(); if(typeof oClassNames == "object"){ for(var i=0; i 0) { if (table.tHead && table.tHead.rows.length > 0) { firstRow = table.tHead.rows[table.tHead.rows.length-1]; } else { firstRow = table.rows[0]; } } if (!firstRow) return; // We have a first row: assume it's the header, and make its contents clickable links for (var i = 0; i < firstRow.cells.length; i++) { var cell = firstRow.cells[i]; if ((" "+cell.className+" ").indexOf(" unsortable ") == -1) { cell.innerHTML += '  ↓'; } } if (ts_alternate_row_colors) { ts_alternate(table); } } function ts_getInnerText(el) { if (typeof el == "string") return el; if (typeof el == "undefined") { return el }; if (el.textContent) return el.textContent; // not needed but it is faster if (el.innerText) return el.innerText; // IE doesn't have textContent var str = ""; var cs = el.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { switch (cs[i].nodeType) { case 1: //ELEMENT_NODE str += ts_getInnerText(cs[i]); break; case 3: //TEXT_NODE str += cs[i].nodeValue; break; } } return str; } function ts_resortTable(lnk) { // get the span var span = lnk.getElementsByTagName('span')[0]; var td = lnk.parentNode; var tr = td.parentNode; var column = td.cellIndex; var table = tr.parentNode; while (table && !(table.tagName && table.tagName.toLowerCase() == 'table')) table = table.parentNode; if (!table) return; // Work out a type for the column if (table.rows.length <= 1) return; // Skip the first row if that's where the headings are var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1); var itm = ""; for (var i = rowStart; i < table.rows.length; i++) { if (table.rows[i].cells.length > column) { itm = ts_getInnerText(table.rows[i].cells[column]); itm = itm.replace(/^[\s\xa0]+/, "").replace(/[\s\xa0]+$/, ""); if (itm != "") break; } } sortfn = ts_sort_caseinsensitive; if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/)) sortfn = ts_sort_date; if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro sortfn = ts_sort_currency; if (itm.match(/^[\d.,]+\%?$/)) sortfn = ts_sort_numeric; var reverse = (span.getAttribute("sortdir") == 'down'); var newRows = new Array(); for (var j = rowStart; j < table.rows.length; j++) { var row = table.rows[j]; var keyText = ts_getInnerText(row.cells[column]); var oldIndex = (reverse ? -j : j); newRows[newRows.length] = new Array(row, keyText, oldIndex); } newRows.sort(sortfn); var arrowHTML; if (reverse) { arrowHTML = '↓'; newRows.reverse(); span.setAttribute('sortdir','up'); } else { arrowHTML = '↑'; span.setAttribute('sortdir','down'); } // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones // don't do sortbottom rows for (var i = 0; i < newRows.length; i++) { if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") == -1) table.tBodies[0].appendChild(newRows[i][0]); } // do sortbottom rows only for (var i = 0; i < newRows.length; i++) { if ((" "+newRows[i][0].className+" ").indexOf(" sortbottom ") != -1) table.tBodies[0].appendChild(newRows[i][0]); } // Delete any other arrows there may be showing var spans = getElementsByClassName(tr, "span", "sortarrow"); for (var i = 0; i < spans.length; i++) { spans[i].innerHTML = '↓'; } span.innerHTML = arrowHTML; ts_alternate(table); } function ts_dateToSortKey(date) { // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX if (date.length == 11) { switch (date.substr(3,3).toLowerCase()) { case "jan": var month = "01"; break; case "feb": var month = "02"; break; case "mar": var month = "03"; break; case "apr": var month = "04"; break; case "may": var month = "05"; break; case "jun": var month = "06"; break; case "jul": var month = "07"; break; case "aug": var month = "08"; break; case "sep": var month = "09"; break; case "oct": var month = "10"; break; case "nov": var month = "11"; break; case "dec": var month = "12"; break; // default: var month = "00"; } return date.substr(7,4)+month+date.substr(0,2); } else if (date.length == 10) { if (ts_europeandate == false) { return date.substr(6,4)+date.substr(0,2)+date.substr(3,2); } else { return date.substr(6,4)+date.substr(3,2)+date.substr(0,2); } } else if (date.length == 8) { yr = date.substr(6,2); if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; } if (ts_europeandate == true) { return yr+date.substr(3,2)+date.substr(0,2); } else { return yr+date.substr(0,2)+date.substr(3,2); } } return "00000000"; } function ts_parseFloat(num) { if (!num) return 0; num = parseFloat(num.replace(/,/g, "")); return (isNaN(num) ? 0 : num); } function ts_sort_date(a,b) { var aa = ts_dateToSortKey(a[1]); var bb = ts_dateToSortKey(b[1]); return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]); } function ts_sort_currency(a,b) { var aa = ts_parseFloat(a[1].replace(/[^0-9.]/g,'')); var bb = ts_parseFloat(b[1].replace(/[^0-9.]/g,'')); return (aa != bb ? aa - bb : a[2] - b[2]); } function ts_sort_numeric(a,b) { var aa = ts_parseFloat(a[1]); var bb = ts_parseFloat(b[1]); return (aa != bb ? aa - bb : a[2] - b[2]); } function ts_sort_caseinsensitive(a,b) { var aa = a[1].toLowerCase(); var bb = b[1].toLowerCase(); return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]); } function ts_sort_default(a,b) { return (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2]); } function ts_alternate(table) { // Take object table and get all it's tbodies. var tableBodies = table.getElementsByTagName("tbody"); // Loop through these tbodies for (var i = 0; i < tableBodies.length; i++) { // Take the tbody, and get all it's rows var tableRows = tableBodies[i].getElementsByTagName("tr"); // Loop through these rows // Start at 1 because we want to leave the heading row untouched for (var j = 0; j < tableRows.length; j++) { // Check if j is even, and apply classes for both possible results var oldClasses = tableRows[j].className.split(" "); var newClassName = ""; for (var k = 0; k < oldClasses.length; k++) { if (oldClasses[k] != "" && oldClasses[k] != "even" && oldClasses[k] != "odd") newClassName += oldClasses[k] + " "; } tableRows[j].className = newClassName + (j % 2 == 0 ? "even" : "odd"); } } } /* * End of table sorting code */ /** * Add a cute little box at the top of the screen to inform the user of * something, replacing any preexisting message. * * @param String message HTML to be put inside the right div * @param String className Used in adding a class; should be different for each * call to allow CSS/JS to hide different boxes. null = no class used. * @return Boolean True on success, false on failure */ function jsMsg( message, className ) { if ( !document.getElementById ) { return false; } // We special-case skin structures provided by the software. Skins that // choose to abandon or significantly modify our formatting can just define // an mw-js-message div to start with. var messageDiv = document.getElementById( 'mw-js-message' ); if ( !messageDiv ) { messageDiv = document.createElement( 'div' ); if ( document.getElementById( 'column-content' ) && document.getElementById( 'content' ) ) { // MonoBook, presumably document.getElementById( 'content' ).insertBefore( messageDiv, document.getElementById( 'content' ).firstChild ); } else if ( document.getElementById('content') && document.getElementById( 'article' ) ) { // Non-Monobook but still recognizable (old-style) document.getElementById( 'article').insertBefore( messageDiv, document.getElementById( 'article' ).firstChild ); } else { return false; } } messageDiv.setAttribute( 'id', 'mw-js-message' ); if( className ) { messageDiv.setAttribute( 'class', 'mw-js-message-'+className ); } messageDiv.innerHTML = message; return true; } /** * Inject a cute little progress spinner after the specified element * * @param element Element to inject after * @param id Identifier string (for use with removeSpinner(), below) */ function injectSpinner( element, id ) { var spinner = document.createElement( "img" ); spinner.id = "mw-spinner-" + id; spinner.src = stylepath + "/common/images/spinner.gif"; spinner.alt = spinner.title = "..."; if( element.nextSibling ) { element.parentNode.insertBefore( spinner, element.nextSibling ); } else { element.parentNode.appendChild( spinner ); } } /** * Remove a progress spinner added with injectSpinner() * * @param id Identifier string */ function removeSpinner( id ) { var spinner = document.getElementById( "mw-spinner-" + id ); if( spinner ) { spinner.parentNode.removeChild( spinner ); } } function runOnloadHook() { // don't run anything below this for non-dom browsers if (doneOnloadHook || !(document.getElementById && document.getElementsByTagName)) { return; } // set this before running any hooks, since any errors below // might cause the function to terminate prematurely doneOnloadHook = true; histrowinit(); unhidetzbutton(); tabbedprefs(); updateTooltipAccessKeys( null ); akeytt( null ); scrollEditBox(); setupCheckboxShiftClick(); sortables_init(); // Run any added-on functions for (var i = 0; i < onloadFuncts.length; i++) { onloadFuncts[i](); } } /** * Add an event handler to an element * * @param Element element Element to add handler to * @param String attach Event to attach to * @param callable handler Event handler callback */ function addHandler( element, attach, handler ) { if( window.addEventListener ) { element.addEventListener( attach, handler, false ); } else if( window.attachEvent ) { element.attachEvent( 'on' + attach, handler ); } } /** * Add a click event handler to an element * * @param Element element Element to add handler to * @param callable handler Event handler callback */ function addClickHandler( element, handler ) { addHandler( element, 'click', handler ); } //note: all skins should call runOnloadHook() at the end of html output, // so the below should be redundant. It's there just in case. hookEvent("load", runOnloadHook); hookEvent("load", mwSetupToolbar); python-box2d-2.0.2+svn20100109.244/doc/manual_files/pulleyJoint.gif0000644000000000000000000000670611130023047022706 0ustar rootrootGIF89aíÕÕ €€€ÀÀÀ@@@ðððààà¿¿¿???```ÐÐÐppp   °°°ïïï PPPßßß000ŸŸŸ___ÏÏÏooo¯¯¯///OOOÿÿÿÿÿÿ!ù ,íÕÿ@pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïèô·Ò €°PÛïøeÁ18Þg yŠ‹j}}rƒ B‘Œ˜™_Ž—F    r u  ‰ mƒC”š¿ÀW{}I  oʸr‚  É ¸” »BÁâãQÑJ¨Ôë BëÖum ïß äýþIö”$ ·L^Î"QgÏ^»wñ¸/y/ßèSËó-ðh‚%Pwõ¦H Ù7Xúå@ß á†j‘pôÐ\…7ß:Itÿy²aÆß#á(!“4­’ÈM9°SO?EÀPEñs2¹¥vÞé)ñÔQ…Ö _¼%‘ÕV]‘6¤ƒ*Q–z-‰W‘ºIbfTVi„”ue©%…³yù¥FWb&æ˜\Òuæ—iƵ¦–mÂõf•qº5§nu¶uçly²µ'k}¦õgj¢5(j…†uhi‰‚µ¨’eVö¨‘R6)h~ui”•F¶)g™Võif¡R5*f¥Nuje©.µ*e­*õjd±º4+dµ¶tkc¹V´+c½RôkbÁþ3,bÅúslaÉö³,aÍ’ól`ÑŽ3-`ÕŠsm_Ù³-_Ýóm^áþ2.^åjrÿn]éf².]íbòn\ñ22/\õ.r¯[ù*²¯\B¶gFSd~D¦ÓQGße…“@öÃoÖCeÑ]Sü—ˆ•Ô!õ þ|þ=©,öƒ ò´5dZ-B]tA5]. Ì8‡W0X…&eJ¤S ó/†)…xZ!aZÈ=ÖÐPt2 Ì AôÂ1Y©‡>œƒ&ÂO9Ì”ľ,qe¨y"цHD2Q±ŠýÚÍÕD"m‘P]dR‹˜)&îŠDÌ"̘Ÿ0¢pŒ¼pc—¾ˆ(9zÿŽV4"qE:2ÊŽnò#¤ÐD5Þv¤œI)BúÐv@¤R ©Iº„’i°dK0‰MV„“´Á#(ÍàI½8MŠ´#1•J=­’S§dS+¶ÇQ–¡”ÿ°%pé—Y ê• ò¥¡€I*ÊÍ"4¼ì‡{0€3µ”€&  @`v3Ó3)Àd ø€8Ð>,m“1̈°qºÀ›§ÎYY8àøÀÚéNq^ œSxŠ<]÷¥0ópç>û)N ¸­ YÉf†âiÑÓ‹X@Bû¹P†~À9D@€D`„âºh]ºùÍpz´£ÿ 5@ˆ‡:àl (ŒGŒ°¦B@à>œƒRs©Ô-éä€<ÊQ~zô!#Ä2"°¿ÀcF8¶ PB©>&VØ´H[GM‹=ñÉÔ~j `ªðÁ1žE ,»HˆkF<7Ðõk| @Tƒ¡mí§ú³Tf€fµkæòú"ô5t îT᬴ŠjšM,CЧ*6B°›ìxº™Jô5|oÈ[@;k ‚Üô&8EëÑÅ>¢± ½&ÌP€  Ãê`±š”¤°E!h‘€‡Ù‚x@ÕE¸P'pyëÑ· ®m%ÿ'ÌR€ít€’¯øÐx"f­ù$¯~ ÏÀÀG‹Ã"v¿në?!ƒÝ @œ¸“2ºÑ[˜¡•/`†r<ø@ á&À¦ ,Ýí…WÌP&æ<ø€‡ÝÉÈVAÄE`ƒg=^¥²øÇ1)¶&ßs»SÀqžUÜ3¿@޲8¡˜‡q@Àâ4ò0@W#¤ä ˆƒ¤òœ$b À¿Œ Y0Ç¢Åa+,e)ÏuÃð€K³üaqfàÄCð™f„£ÌoÛÆRAUì !È(‰T~u ×ùÒî|,‘€^wbàuçÿ:H„ö:â@½[=pÁf HA[Hñž1}i ì ˜Àx?pÍGðsß-‚O $Ÿkøą̂sõC6ë+0Ã>¦µ´yͺËý4@ú<¼.|Ì¨Æ PÐr p[/^½l,4ùÉÓŽ·>‘ìr`ÖîÔö#úì¢&êÌSÑ)²Ã#øí'„ÀÕ^›S r>°¼§Ý_·¤û¢õ@ˆìÎWDÅ÷Ä¥½`¶À˜¼°á©á`ã#y†Ó¢Ž³˜èói»,Væ¹…;@ï` æ=·LÁÒ=GÙ¡)ÀDžôKSÙT0-3 ÿÑq@ëU¯u—•’ë]Y¤vVÂoM»äcÀv 0vTÀìl²­ß^{O{ÖžwL ·"—÷üMŽ@¹ðRVï?0¼_Ø-i@Ÿ!åŠ÷£æ§øöþAÈó?.¹8 Á¡û<çâx9ê¥<ó`4êÓî@‰û±óÙGù”²v¨·N¬.ZtÀò8}”?-dFäzy¯qK¤Žû~`¿0íç@í¹ÀÊÜ¥ßs ]_'ï÷õþ†æóš¡·°2pÒ–ã!+Ð}#Çe¶Bx¢5ÆO €}¼¦à Ðÿ¡e8e®G^°àU¶çÌWxæwÇ[NàgØw %@x °g‚úE0"õ ”gyawÁkØVó·Ðèµ@¶P°T¦¥èQËçþµ׿{€y.áxÈgJÈgF¶P1¸Øfì×VFˆ~W¨¬—LµpØOpf_™·y5 €†S§OpM¦üt}f`c¢µýG6…tÈùÇT ‡â0mÕoogz‰e@ˆ6àN—râôi†ÈVLµàý0|`G^°È[Z¶‡måqÿ—dƒ@¦bäE ƒ]÷`‡†OÏ×q e0€ `ÔèNóçQ,ç½y ŒmU…І˜ð1WÆbÐaWßO¸…q5~0 µˆØ˜XÚçÈWg0‡â´†éç(‰‰ÅV0@x°v~7cÐN¦•EtJÁ}=çˆc…xœö{ù…€„O03vè}‰…Õ÷ñ'o²(V.уRfH[ö`OFv­g’‰Åu²2„˜FŒj‘…Ràf”x¶‰ w ¶y0àèNh·%ˆiâHŽÀ`o¹_ðxc¹g€ã°QàƒLEwK1x—w~$µ‘Èy`·È[ݶ^déýpr¨‡ˆ`‹·šÇb- {¹”ŒZÈb{§¥—†‰%”D)™p޹bÛ8IÀŽ`…_‘V©ˆ¦y𔹙SƘãТ€YY£HQ›Hý‘›à`¯Ø›†(ûœÂ™ˆ§Yœ©i‰»Gû˜X)"eñœÐ)Xå3å£ ¶Y›¸©›À›½É)ù\  ƒ¬¹GLAÑ›^gZ–yŒæÙ@x]ùž¡Q —êIŸŒÑMÉA;python-box2d-2.0.2+svn20100109.244/doc/manual_files/gearJoint.gif0000644000000000000000000000410711130023047022303 0ustar rootrootGIF89a³¼Ä€€€ÀÀÀ@@@ðððààà```   ÐÐÐ000ppp PPP°°°ÿÿÿ!ù,³¼ÿ $Ždižhª®lëŠA,ÏtmßÀ«ï|ïÿºÈ Ȥ2¸4›Ð¨Ô'œ>§Ø¬vT•^·àp²ýŠÏh¦Õ˜n»Qd¨ùMwÇ›óº^|_æ÷€Y}J†PƒI…‡ŒH‰H‹’TX‘“—/G–˜*šCœž£% @¢¤©¦?¨©£«>­®°=²³—µ<·¸’º;¼½Œ¿:Á†Ä/ÆÇ€É.ËÌzÎ-ÐÑtÓDlÖª•ÚÛ¯Ýß®Ø+Õâhä*æç|áìžé)ëï[ñ(óô‚îù“ö'øü¤øsâ- ²} ,0á’…$:ƒpâˆ#$Z‚Q„Æ?:Bø²‡H’%wÿœ,˜2ÍÊ–u^Â|#sf›š6ÑUÌF—€b,yj©E€P¡:_a¬®äZ낯Z^õ,‡±Š®G9Œ‹¬°„®·b)×£š;ïoª¶Ðm¯ÊãM]úžÙ/Šþki 0Ùç&2à[½%Àw¾1Ý`"à€oç."ßs0\c\)šõñ~kN¦"cRì€Äy„ì’ ÀÎKÀTß l4@𺰚æ€ÒMŒLñÉS4¬³Æ¶q˜œŠÇm¶ ÀX3ä³K¹ÒöP/@ÃÒ­Ýv·@€¾6{X«mµ– ž”Å~+¡À‚£  @ l=DÀ\¯0xX/F!Õ 䬦çHà ·ÿÞ È'J$°Èép4 4x "³vâ…÷°ˆ%4À;¾£{‘÷¹ï@ë }ÄtÁ—1|1I,•€µk#Àë?7/ÇóÊ$¶VàlzDJˆÃNx(±\´3’öxpÿŒâD_€û”è³Fò— íË ˜4??ô²C p€´ý l$ÄW€?F˜¨/ûÃöHñ€ 'œŒ¢?áeAk³°Z —ü(\áö²;W/‚Š˜  à´T@y4á %w –m†Y Û(¸ٱÐBªEòž&Ä,ìn¾£â³`4O0O‹HÔBè¶ÿDy%ƒZèâ%šæ¨-Šq[È⫨15‘u:[Ä@ àWzDßuÁŒñ;ÉøxЉa Ãzî(4€’!¤cTƒÉ4‚.h<'é°F1‘meJ ¡P¢a7¦Ä,åãJ4H xŒq AL…ÚÈ ÐI¢’Ï “@žÄÅDixyP¯ó”4Äâ̈AIf— ÔäˆÓÄRY¥†Í:̆7h à’€Ú\3)â<êTºÉ៩@V0t€{¶(Ÿ’(’žZÒŒ£†y_-#š½‰Rôƒ½¨J2ú†ìÿr1³!¦Ù™,`ÓL‘@æ „Ø§C¡°y@œyžŠ,…OÄ[á!c¶B«žM7·¿9K z8„ÓdÉH@BS€e*d'EÒN‘œS$É—@@@¤0ƒPì-bzÐÖjIäFjG£¿í/‚7jÑ3XÁvÁ#üàS¸Â‘¼0†©á g³Ã<˜0ˆW â§ Ä&>ŠS\ ޲¸Z ~±m!,cÓXÆ+®qŽqìbïøÅ?öqSd"ÙÄEFò‘Gœd&/ÄM†ò“;e*OYÃUÆò•/œe.3ôË`s˜m‡…;python-box2d-2.0.2+svn20100109.244/doc/manual_files/poweredby_mediawiki_88x31.png0000644000000000000000000000361511130023047025301 0ustar rootroot‰PNG  IHDRXTúÒsBITÛáOà”PLTE)kªªÖæÅÑ¿µÅÏvs”©„«¾ªªªAyÇÄzíìæ[gRÖÄM%_xqyE³«iØÜÞV„£Ðu P„áÊ$°­6=F”öööÆÂ¤£¶ÄÇÍÐÀi f™Oz˜L€£«éÔ 2jŽèçÛÎÔ×ÐÇcáÙxŽ‘7ŠòÍ ÖÖɆ•®ìÛ#^˜µß– :„­0;xv¤»æØ?õ²çá©W‹˜±Á,vDv˜N„¦®²•¬®¾mêÙªmÖÉ/!h–¹Ä›……¸+K‚){¥«ºÅ×ÒµÖÖÖ8r—ÁÎ×ßÙšåªðÊȸL…£·R‘±l¨Ò† ØÊýÖ•­¾Ä¾sòÝ5ÝÑg!e’‡§¼f‹¢çÖRÝÅEŒ›¶²¿ÇÓÍ–ÞÞÉ»ÃÏÀpðððÍ·4[†&&š2m”ÎÍÅÞÞÖž³ÀôËáäæ@\‹èä¼à׊ä×4Ïξ4§ëÕId‘BSZÛº åÎ!–zj·tœµ¥¾ËõÞT†‘’¥ÅÐ×ð¼DŠ­0N‚_ŒàæÐÔ‰÷èGÜàâL£èÇ ¤•ØÎUÿÉt¡’»øÆêáÎÖÜèÑ2”n[Ѝy÷×îÞã×jǹDœ•-bެÖÎŒæÜ…ì¿ÙÙæÁj š™¶Ì}8t›å§µrµÆôä=êèÍ‹¤µóß)ÄÅÎb‘¯ÕœÌÌÌÞÞÞ¦»È|³"c¬¿ËŸ«ÀZŒÆtàÏLֽޫ¾à± Mz™ÃÀÂè½Rƒ£FaŽ\‹Ü×®8CgîØGMU]õ¼÷Ï{§½æææ)j”Ô}S‰› ¦«¨­”´Äº°@ÑÊl•™Š¹µ¡TYšíÑÇvËÑÔÁ¾yÎËâÚ’ëØQ)>  pHYs ð ðB¬4˜IDATHÇíÐû[SuðÓXÌy"=4*™óãOCCJ Lòì„…\†¸ŽÄí;Ä6æœcvF­ [Þ¦cÔ3¹ÌK`ÉúNr]EðŸéÄõô<õ ?ô<½8ŸÏù|¾ß×_dÍ*Yóͪäx9<ûXj6ÔÔÔÌ®_–¨Ÿ£b*ߨÜûerrò£©O«5ûð¿‰va¯u‡ÃáÂÂŽæÂÒôʽã¥äX ÞªÅC2±Ø»Å>±[&Vû8[p[²°—±²Z{½ÞÙYï¹[x”NÇãñt‰©ÎÎ8®öz¹CÃ’V³YfäáY>I¨Kf–i[ó¶°­„ÛkÙa¨@kšRÄ»^xs}Ì‘NkR=·Õét^>þÛ.qJ“æ!,˜5ã¼À\`ÎkíÒj[[q®˜CøŒg… ºþòÈI)þËí ø;¼úé'ê==ýýÛ>Æñ“wÈÀ^ÆCy/³Ï!!²~0° s…J¸½6O‹g„Á†Lbxñagú{×n^kooÏŸètÖý_ÜŰIc#5p_>÷5`|)F0‚À¸‚ñ¹©Ô`àc [¦iDC×þxûpRÒ'Ó§ÆÆÆÎ=à ïì¦i BÿÓø ý.Á·N?ߨ¦ÛñÎÆœœç·¬%kŸÙò¯à°,“ô¡µ…Î>gÇ©{9--9Ïåúç>¬X!LQˆ†¢žú.jÐqöÞ¥–§[.ݹèk >è¦( B±1VÕQW%¦þŒçYuœ^hýŒšRfRÒj¥Üã‰ãfÑFŠba wו´%%¥ ä|Æ>E~`kIÂí-hÀffÆ@ì訂à&“Ç¢Nñp ø?-TŸ¥nä ¾š¦¥À³ †™„ §#¬Ö}GÚ½÷Ûo³&¬{B Ù¼*bèMI1;ÃŒ02d‚¦H±m6¯0SMIŒIùÖˆFËiÏuá&xeý¶„ï;~o lO{·ýSÇÄDÉÜ+ç lZ„3&Ï J]£¾2QÆð¨~8˜;+Ê0êcƒ"~ÙÃdD»0•B!TýP(Z‚÷¨á¹÷KbRS÷9úú¦Ï¶e[?úõón¨Þ³+Glevö¾E5d·Øm6 AB®çߔϤ’+ýqSÃPå÷‹De~»WT\žz©øH_vs³ãÁå¤cÙé=?ǰ«<£ìe6¹ƒêÜ !du©0¨P™äzûCFÝ„ˆé,la.PK0Š¢Üíøøùþóéºùñ‰‰æÔgÆP”ËŒ}MÔë¶ôfXôCÕ¦^Uµ}4·W>d ]#ÕØ” ¥T~…MÊQ—EY˜|Ý1°^)ˆ:óàë--È벨åGcdÆæ*IL•BEzP~UUQ$Aòˈ,"AùÁX%YÇ›HrL’ñ(ÚÙ‰6tîxûJb¹²<“$Ü]K’·m¨%Ñ' ?¹°ð‹«’ÿ$¼Jù±évícN6IEND®B`‚python-box2d-2.0.2+svn20100109.244/doc/manual_files/Icon-manual.png0000644000000000000000000001003611151077147022556 0ustar rootroot‰PNG  IHDR@@ªiqÞtEXtSoftwareAdobe ImageReadyqÉe<ÀIDATxÚì[yÕÿº{fvvÙ–s9C@® (‡¢&xÄ(c‰ÆJÊJŒþ‘Jþe••T¥rY&å$…Å@ŒDTN/@,÷±Èµìrì9{ÍÎt¿|ßׯ»ßôô;ƒJÅôòèéׯ_¿ï{ßñû¾÷ZB€ÿÐ4 ò=Ö¾þ2|•ÇÝ÷.ëó3*ÍZèXBX"XJœç±Ô ‹%ï[²mÂéBž©]RÞÓe;¡ô–÷ß½òYCy?È6†Ò/øúMÈ>"ò·.ûêÂbÊ{¢D±”bŠ¥K™ˆ.£J&_’g•  HWΚÂ@•sMS,Ù®W!Üy•–,mXºe]Ÿ@ÄWÿö7Oýª¦fìÝÑhÉÓ4{à ? ÈžkhÜ{àÀáWžûËò¿cU«”†4„rôEb9ˆˆ_´è–ô˜e&£–° ³#½ñN3zÔ•Èhjjž©áüâå:,™ÚæÃ€ÒP(TÒÑÑDxo<(koŠòr~Ù•xèºN¥Dª­^(¤N èéé‚x¼zº»J±-WØáŽ-”Î|Ro„%P ˆ"üúúFرk 4º»{ ´4Êõô›ŽÓ§ÀÙs0ïÚYÜ®¹¹•ïÝ·ôvxí pÇm‹a˶O¸®ºz8?~®ºªÆí›êèÙ>“oK+£¤äèÇb&‘ý-XºpàDý¦Ó™®ù7o¿³º»z¸~ß¾ÃpÇ’ÅLsÇÎ=pÕ„T9æÍÅŒ 3µ½ïžÛù¬¾/ïbOr²P„=÷#ÿüos΋oœg3„ŒH´®»v&¯;É÷¯™>ÞÞ¸…%¥¦rÔŸk ì‹Ú¾öæ>»÷4d§^ºÇŒ’žË Â2çÕÕ+ÖMœ89J6 m€#å0~|Í—¦Õ³p&À/¥--­°ñÝ͇~ò³_<Š—G$Hsƒ¹$€†ÈÄañåMaBOwöï? ‰dëmg§9L…m–á,tæb@¯ÃéÀq}IDÐäÌcYÿÎfXµz-$(ݺÆTi²SU3–ĺo¤»=Gà‹/’zúÓ5ÞÞ°ö8 ³gMGì/­zE}»T»7aN…{ͱ BŠ•+^â Ÿw~;O:β†Àfë;ØhθæjøþƒKá…•kàÈÑìz» z6°¢ça{"Âç÷Ýò…̺=‹4£θ¦H¼»wÀ™ÞS§N„ï}÷.XóÏuìU|àn˜zõ$Øþá.ˆÅ:Áq> €B¹@S¤ˆ¼P,®;W—ËÎ#Á¤óºÍœõ¦¦h< Î_„[n^ßúæ°båj8vìsx¥`Ú´ÉðÔÓ¿C¤‡qc«¡_y©_ ¬b ë ¯CE@]•¸|nŽX`ß„nì77">8Ï×sL™<Ž¢È74\€¥ަM ÏüúY°¡>ùÓG`ø°*ŽWð?u¢D1À ‘c\F °©§É‡öX –ÿõìæ®›;jjFÁ%”„M›?‚ƒ‡ŽÁ“ÿªªÁÓÏü3 ^v/ Ä[4W–7MžæZ…2€P”e<ð›(Ïä)Þò_X-uy¾æÕõĈó±?#‡å÷fÏœ ~~%¼úúzF—ñx/<úðý(ú£0L·¤qVaŠ(Úêv–E±ü}ôL1[qÛ°Ù~;½h²Ä::áŠøôi“`O³jYI0-ÊËû!ľΣMW3žxü”Žj¾g “Å_•Åwl GÒPø b0tu½³®y~ ”Ä™ìDZúmmí\5~Ü›Y4¶ìTÆùˆªÁ•0´ª™c‚0m¢SÆâ¸m›†D¡ ÝI¹ÁTŸ›Eä‘°‡á¬51ñ™b*ýû—cÐ3…Û=výýdÉ$/ú9Sß`Gi‘Ï8K ÓׯðЫä b@X¨ Ÿ"™€'šð+º²ÏЇ7661‘4{²7<›ó®›ƒÖ8|äœ:}ÆŒIs϶µÅÐ~ ‘HÆŽ©F½7Ù1U™¨H6,OBÄ'…«®Dä°‚ºCÿŠ ¸p¡ØÕl½“hÝ©G†·L¸[·ï‚ÒÒì΂ûﻞ}n¬|é5˜3{‹{Ú†wìá¶/»›™¬©™öpêJF¹ `z/Uìs?U ±4=0lÈ`×]‘DèºÁ€ç½M¡¯×8ãFà±=kßz>ûÏ~·?ÊÜuçÍ0rÄP6|Â}¼ø!Üõ†‚qçòƒ<@~@H°ø:ò×ÚÒC·³á²l`¨‰x’û"#Hõ4»TÀ#Ë–Bk{ bmPÖ¯ã³Ä8ËL‚ðä @¡) /…#Aù¹ª‘E|¸jØ]‘Û"gÀ1’»OlÜL~OEyôÇB-LI¸ë‹ìïöÂÉÂm€½š“ CÀ¤ëóV­dˆ ¾ñh¾3€/qPÔ RlOëž„b¼€£O9 &ᬮÙ~_7lëî¬S‹Ó¤ С´,,]!yb€ Þ,0Ýl4ä°72 gR$ð BΠœ|Ív"iqT§#ûLÝn …àâÅfFsqŒÜ„tma¬÷&ø~(†ÞDRº7[M?Ü·°úÆe¢´bl€n#AJW¤ë¡œÑ_øtvõ å7ù:syó'`¾÷a ÃhNÂö|v…m4™pËây0{ÆÛÙåîR€€Zo1Ыº» i* ñ,Òl–••2ð!0Pô“IÝuÑdøˆÐ’’0· ‡C …‚Çã ¬×9Ú].MhùK¥¼4q•)h5La†„~.#zQ¬Ÿxü!qÃöû \¿âÄxíw1Ø?Xv·}ß² G„(›·ì€»jÁ©™Þ|j V„:Óé@È·"l{Ïà‡f‰¥3é´ |ty?ÓÑsyßÈ ‹ Ãc®nb´OK‘žtšÅ"A#›>ѰgÚ®éééFU@1&è+,ž}¢¥'ngÛ !¢#ÿnƒ{i›zJšI_¯"Gð —!'èh^šðYZZbò>Kì8º½9ÖÝYtµÐjÂJY²?yyxœoq4Ó:`Кìõ—ýºÁXŠ%€®îš Ý~ o>’‘¡®kÁ«°ùë€ê6´bTÀK1g’MY@Ö<×V-aýÖd7² „×g!™ ÖRBãh4ªdŠ=ÄèßÀ&|ÆÈ›[U”}ŠÀ„s59pƒ Œ„ɵ X»n˜\™&“!ËÇb]L|{{'ü{ýV;<–Y!:—•Fá\ÃE¶ÔÞîWÈw‰ô¨×QËÎ %•pÞ,Ú@Æœ}u·DJ"hÄœ<Õ¨³Îì'1Ö8›± ¡Cºgà™!6‡ÑéC$b¯Q”©qNA1˜E…Üóü0ÇøÎwßû>G‚#‘b€$>׆K'Èv|üñ^ÄûÙSdRÿ/J¦,¾i.Œ^å•­b¡pÖXÀ1³çÛèMH Ô{ùvûô&rZü‹—Z8kÚ`¿Ô‹a€i«@@® uïÖ›çÁé3 èã“®õwâ|¢£/¯Ý V½òlÝþ)”–•ÁÆðuí¾#袰eÛN¾>rì{‰ÚÚð|ù8{î\B&­xáUdJ;¼¸òuØS{ÂhL7¼³Ëø»u¼^^µÖ®ÝÄý‘Í¡¶.Ù‹& á©i±âvˆØ:$ ë¢>é;…¿¥¥¥Pwü4†Ã&œDi(CF„ÃD¥<ût¿¶ÖfE÷7lØÆžƒ€¹;úƾB2‡@%RR{öâö— £³‡Ÿ§¶†nk±”¸Þ$#é;Cü¸\ªg‘_ww6múÝ #ºûöâÍ ‹_gÐP:b<`@tvvÃÖ­;d{/œvܨ“RÛ³ç \ýlÎ1ìÚµ— -)h/‘8Ê}öi-_———Áµ×΀S§ê])*ìÅQÀе™S\A‹Ð)1x>¼ z dE¼!pÞ #f16€ì@#G¼µ³:63-Ë’‘˜ WÚA.’r–àŠÙ!B!] áè:¤ý;šjh¼À;5¯´ƒ>šºt©yÏñº“«ñ²)ȵ]ž¢(ÊMÀR)¯ð2ì LeJÕì «ÁûŒÎ݆«ô—PúJ†ÒN—Ï9Ÿä©HÏiKG+4ËsjûòÙ\ÜbîÇ“ÎÎKuÿ¡ 8© ÊùZÃP¢2¡ô©~ h*íU&‰Í¤bÝ Ÿý´”1t+“c€œÇŸ~ÿÔW*î?ÿåÓ}O°ô჉ÿùãkÏMñ|ÿ 0®'vªiÑ›ŽIEND®B`‚python-box2d-2.0.2+svn20100109.244/doc/manual_files/Python_testbed.png0000644000000000000000000006420011130023047023373 0ustar rootroot‰PNG  IHDR†ù“th§gAMA± üah7IDATx^í½œUÕ¹þ/ÅAªˆ‚‚"½:Å$J3æ*"–J“"  ˆƒÂ a¤Š‚€þbQAÚ5\5Jà2áB‰Ò4DýÿfÁb³Ë9kï³û~öçÀçÌ>«~ß5ç™w­µ×[ä‹ÍëÎãE$@$@$(‡Œ<’üÿñ"  ŽÀèÑ£o¸á†Ó’ aæ‹H€H€H zI.ue¾H€H€H€|&€?ÒKò½]«ÛZ/¼‘í3í>7—Õ‘ @\ (Iò{ó«î;°/¼0ãÿ?Oª’÷ìýÇöÞEUŽëÈ`¿H€H –l-cY×nzÍY®ô’,õ’üÚ’× ÉÐc¡ÐøŸÆÒfì @, @,‰Å²ÝôR’mÕ"r¥‘äšµ«Aƒ…KI†Ë;n9Ê¥s??õ7ÅGsb9Ô;UúÎ;Áa÷ŠŽµm¬è?òÑ)xäÚÈ¢Þ$¦$ 8°+±2=Úêê+$ÜCI†Œ—Ð`ȳ˜¸~.oòuïŽ;ë6-ÇÚ¹ëÓÊ*=vki)]{Χ’}þH¡ö¸%Éê 0agZuº;çþálÛ,:¥Ër:•²¦ê9x,ÉòÑAë8w?ú+(ñE$@‘ à…$‹2­$Yl½Ò:ÍÚ;Ú\i¼d±r,ÿ‡O,ÞCŒåÒòÈU¤Nã Rj•õV’ ½m¾ã©Væ-]û3wòþ™wžÓ‘Ó^왿$´ãÏ™>#É¢BþÍú‰ß+6’H€ÈD’MWˆ¡©©%YžÄ%TY§Ð6$YxÉb»õ©W¡$‹V”Åírò9’|Úáûüƒ3ÚvVv¯˜Y8×zæúü1q½{¡Hœ¹:'®s|VCJaùw€VSqßXŽlQæéOÏum¥¢ëþ¶°’^ãýs\Ò3…‹be´?žRÇÓ2y&Å™\i‹B•‰ë}1A}Ú‚gŒ‚æ 31ÐYÚÊæ“*imêà—ŠYH€HÀ|ùØZå•é¥ô겫H²î|Lm 6$“Õp‚ÏJ²Ôæ3b¬{2J+ÉR¢´2 nB<̽äB2ÕBýÍsSêÝt)zÂÔ,Tk]çÂ÷ðƒ §ÐÏÕã3¤ÞKÖ•–ÂK%hÿŒÀ{ÙÖMàk&®Ï4+ʪS©Ç¨N’õšzîì‚Ö>-غgÀjížÚ|Îæœýâ1  %ÉFÿظfâ«Èb—µþUè.ÃQ†f§ZK>= ,—Ålð©õã×ò;]+Ÿ©ÅC/Éç*±i9§Äõôìôé&-Dºªf3ðVò:±Ñ:§ÿBøhމ'j-ɲ"Ó¢ [œã%k¼êSU˜òÑþyaŽÚìïéæžú»J'Éç ¶i™FüÊ  ? %ÉÚc³xÉ„5cH2þ—ÓÔR›±Ã tÏ%k½%£ùÁG§¦=O;ŽÖÛ»\“ä3Š"&Éż®VP5;³Nï2;›àTó­gŠ×VÉΙ‚þhNеd$ëvQ¥–d«ñm5qí›$ŸK˜{ì¹-ŽHÀoH²výØáZ²ØS ?X쯆6CƒñwÄMñÒ~û[Iò™)P1Q\( ’l:7›zÂÖ8I%K9q Ý=;q}¶šyìsTÜzG´NƒÏHïY±?”('¥$ëg€Ï݇¥­N}#›U_ÌQgæ%§±Ô~þu̺H€H@+ÉÆ€OFÿ5óµdwv\ ÿê‹ÿñ‚ã=n®¼¢ ”Bá nªH²œíÔ>y¬™Ã<³oȰSÚr{—Åžês|PÍ ±®9e-\ç³Û»t»«D rO“fg“qX›¬Ÿ[š\KÖî:[»ðËu 8ó ¶æošSéNýqvÖýty6¶wɵvÍ_ÖÛ»N-ð›þv5ÁXæ9“ðÊŠñK„H€Ü"‰$[=—,Êôö¹d»cዟð?ôb,DZç%[ΗžÑÙp‹;Ë!  Ç×]éÎßx.ÉèTYÆœ8ýÔÞ»pºµ˜²†£¬xƵ³C©8’H€H€HÀ]PÓçpé>jÚJ/Zë,Wú3®!ɺ½]"ì#A¹;JX € ²ž^¢ v«¹T% m–ò¬{öɈ¬‚H€H€âM ½$Ç»ÿì „„€‰$+ž4Æd$@$@$@îÛ¶O©ûÐŒÏiñ €×L¼d¯«dù$@$@$@¦•ÐKæÀ   à ÐKÞl @ø \uÕUÿùÏ´íÄï¾ûN½åÆty)Éê0™’H€H ¹2”äbÅŠQ’“;zØs   ¤–äR¥Jåçç8pàðáÃ3fÌ(Q¢ªYzõêµcÇŽåË—ïݻۨ^Mš4Ù´i“xë‡~ÈÍÍ¥—좽X @l ¤–äÙ³g/X° L™2¥K—^ºtéøñã…$Cƒ§Nš••‘¶ò’ñÔÓ¡C‡5jDIŽíèaÇH€H€\$ ôõ_šëÛo¿kÉp‘Ožzª{w«¢p¿[›6}úémS¦L¸÷Þ"EŠD}8²ý$@$XÐã7ß|síÚµ_}õÕ®]»þaÿ‚ЮZµêûï¿Ç9Y).$@2$¶_ƒ9öïßÊÀ4ÀdÄÀ°-Éš5ƒ –Çéa%J|ùì³PßëêÕ{÷±ÇÞüÝï¤îÂ~ò®»ì‘[o…èŠôrâZ¼yøÖ[!´_ÿéOe.¸À´(”†òÿp÷Ý›5Ûõ ¨%±C™' Hz ¿ÇLâX«cÇŽA8m]ØeË–áñ!Å ‰‘ÅV~&†CêÀ4Àd„*Û–äŽM›BP/*]ºuݺxS¯ð‘ç_µj…÷×Óº{ÑEú7gœcé%_zÑE?kÔ¹ª”/oZŠ]ñøã›4éÙßü¦CÓ¦Eé%Gú7’'H0ÌÍ„ö@P¡Fˆzô£Íëé§Ÿ†Oùµò…ÄÈb³¿“ƒh€ È€IqÛmØä…œ×Ö©A½ªð”í;²³ñ«Å:Wø¬%YsÇ´([2+ %Ïì×o÷Ÿþt[Ë– Ïì: D•\d¬˜b†!º÷“Í þ.vB}fóBd´Y•ßÉAL@|@IÕKÆö.lκ÷ºë°²ûØý—ÐKL,ÿ¹ÿê×ÇŠòÛ>*'®•Xê·iQ([ÉÜ|3¶•}òÔS½n¼1ªã‘í& €4bÜVÌÓÂ/t zPVlQþ ðÂ:±xcu!H³dÉ’ðK2h€ È€(©J²xjËsÏ=×£ÇçŸ/FÖw?3fÇóÏ/y䑚•+;–dÓ¢psH§N_üñ(îÀ˜Oðf×I€H ª0kµRìfÂê©¢e?>¤ÝÖ…,‘d0ð¥ô’ÕQÀv“ „€\<óƒ=ÆÎf­c)Éx|KΈ¹kð%Jr,›@$@ñ%àŠ— ÿxÅŠË—/ÇÿV>Õ&ˆÄZ2„™^r|Ç>{F$@!#àÊZr~~þF›²DbâÚÞZrÈŒËæ DŒ@†;®áJŽ=ú‹/¾@ÐCÅ ‰‘ÅÁV2Ÿ³hw\èœ¸ŽØÈfsI€H r2.þîóÏ?¿WùBbdñûAc›õ9y.9r¶gƒI€H€ÂF ÃÓ»°'‹¹èü+å…bÊÚÏÓ¸ìÖe<½KØ‹^rØÆ-ÛC$@ñ$á×xLB;f̘7Þxc÷îÝx–Wwá&>B‚pŽèθ–öN/ÉÚàŒx4yÁ!Ú;Ÿ>ýô­[‹â~““³áÀcÄËÿûì:u´c 2Ë8WD¦ÿê¹çðdóÕ…G€ñ" ˆ=L"A‰PM©ƒ3úÎ)ƒšd$(¹U%YœÞ…NÐ’Œ;8s΃âŒ-„\ÄQ!¸‰Ã¶jþàÁˆà¤ÝÑ…Z‹êW¯ŽFàp.“Þ¥Kþ¼>|xìG!;H$@$@© ¨Jrµ Š-ŠŠ“aâ=B@‰+•-‹“¼ð¦A¡Ü"P#´Yò…;77n¼xØ0mS®/Lb!í8Â:«xqšŠH€H€’L@U’å´3ÄUH2Ô´DñâOtë¶uòdH5¼\ûä“¶ˆYë±ÝºU¯XQ‹õŸýlãþ€Ó1á=ÿ¼Q#|„R(¡GÞvÞT.W.Éf`ßI€H€"J N:ØpæJãU%¹}ƒ.¿¯r%KêV—êÔI4n1B7޾óÎÏžyÓÔÚpŠè„ÈǘèžÕ¯ßÿLœ(æ´±, 1†T‹h®ô‡… €ŽÀUW]õŸÿü7å› ¹UŽ®ª’Œ¥_™SH2DºaU/ºHÜoQ»ö“wÝ…Ee¼G E$¨X¶¬ÌÒ¬fͺ—^Še¸åâE‹bº¾r·6màggH‡ÙI€H€HÀŠ€cI.V(jÆ+t’¬i4÷šË.ìõ¤ßüæÖ-ŠØZ/yêoûÑOüW«Vÿïá‡×=õ”HÙsçØÛ5£o_Ž$  ðˆ€TPœ5‚G ¯&Mš”*UJ<ë|øðá3f”(Q ‰{õêµcÇš;}ûöݹs'ž¹úä“Oj×®;Úr²³³… Ž«B… 8@ô›o¾A™“&MŠ. ìÓ§ž}“ZmÛ¶‰û÷ï/žæÚ³gÏàÁƒqǹ—¬“d”ußõׯ7nûÔ©ˆÜ¼V--Y,-/}äñ|TãË/aŠ»µqçòJ•<2‹%  +/yöìÙ ,(S¦LéÒ¥—.]:~üx¡ í©S§fee ‘¾é¦› µÅ‹GúeË–I•`µ3‚4#(dÉ’%/¾øâ 6Œ*|èW8vìØ¢E‹âÄEÆM$Àa_­ Ÿ".W®\ƒ ”$™¶$  H0•d¸È'Ož¬zæ` 8»RA+™ùŠ-[¶„ûk%ÉeË–…ÊV/|òW§N¶nÝ* ,_¸þ ×üÛo¿Å› /¼g~õèÑH¶é½äH›'  SI®U«œWy:'f›:¤“[®wïÞWH)®'NXI2æ´!É’výúõ9bLüÝw߉4;vD IÔ»zõjüA€;”dŽU  ˜’\·n]¹î §ïñ¿®óº­[˜²F²œœ$kÑ¢…Tm92½ÎK†âJ/YVŠÄR’E½çŸþðáñnMIŽù(d÷H€H€´~*VpáW«VM`™7oÞôéÓ1‡Œ÷UªTiß¾½Î©÷‘¥aÆXZÆZ²Tm9Z Ç‚4ÊÄZ2æ½×­[‡³?uJIÆ„ùÍ7ߌ2‘ _¿~Û·o§$s¬’ ÄŸ€V5§L™‚¹bÌW7nÜÚ™——·oß>Ì0#óÀ’Œ;ãÆÃ¾h¨æ°aä+˹öÚk¥ %^¼x1æ·<8yòdì³’d,9cŸR¢dlkÓ¦ %9þ‘=$ ˆ ®%GÅRl' @Ì P’cn`vH€H *(ÉQ±ÛI$@q 0wî\œoõú¹WêȺÄ1øñ/ù z:‹R’ã0ÄÙ ?ˆ1tè½÷Þö¦ÿ>sAŒqNvNýûßÿÆÆfÝ…›ø Lf‰Á›O?ý½Ði;Jrø‡1[H$@‘'=~óÍ7×®]ûÕW_íڵ년vÕªU8Ä §h¥¸ÉXäŠÁ…Ã®Ñ p 0a`Jrä:;@$@!' ô~!N¬Ä Yxì* ‰ÅyÑxIñBbdAÆ\ðþÑ p 0¡Ê”äd6H€"Os³ð¡=P_¨Ñ?ü€ƒ'Ÿ~úi¸‰_+_HŒ,È› @L@|(É‘èì „œ\d¬˜b†!‚úÓO?ÁßÅæ¦Ïl^È‚ŒÈ› 4ÀdÀ”è%‡|0³y$@$mÐQìc‚‹yZø…BM¡¬ØuüAá…ubñÆêB‘¡c&É@& > DIŽöXgëI€H ä0kµRìfÂê©p‘…$#®0ÔÚÖ…,ñ“d0ð%JrÈ3›G$@Ñ&oÏü`±œµ¦$ãY/9÷.æ®Á”(ÉÑël= „œ€•— ÿÑ‚—/_Žÿ­.|ªM¿µd3½ä`6H€âCÀj-9??£Í Yâ7qÍµäøŒuö„H€ÂOÀ¸ãÞáèÑ£¿øâ „DT¼Yb³×ZtD»ãväÄuø3[H$@Ñ&`ú\2üÝçŸ~¯ò…ÄÈ›‡’Ñ>—íaÍÖ“ @D Oïxa.úÀÿJy!˜²ŽÁ¹]¢ ÆÓ»„Yé%Gtx³Ù$@$1Æ3®Å1×cÆŒyã7vïÞÇsunâ#$ˆÓ×èµîŒkiHJrÄÆ4›K$@‘& ‹%Â:¥ÎƒÐOº.ÈHP:SR’#=¶Ùx  ø $ÇÇ–ì @بoçZrØlÇö @T Ô©S›´t­7½Å:îÈßýüЩÞhßkïˆû”ä( ¶™H€š·~ýúîÝ»»[¾ii®täÕ‚ýâ…*ä{Ó›”dlÊ*H€H ¤-Ztüøñ8YËY»]Q2mÕ7ÞxãÁƒ»uëvþùç)Räºë®›5k–JÛŠ+¦M¦û1m ®tdôà%ëÂûQ…w´7q/JrZ‹0 $…€Vš6mzäÈô¼B… 8ó›o¾ÁÃÁ“&M’ªÖ¿ñØÒž={Œ”2;ÿÞ6®ììlé1›%rõéÓÏ¡@xÃFÜ›6mºÿþû÷SØ«W¯;vÀ±åËQH©R¥ÄÃЇž1cF‰%DÉ^x!B;ã&|q!ù®t䎕_ˆ—l¿é"·w%å—ý$ Ô¤¦Bw'L˜€ùa¤Gˆb„D,Y²äÅ_ŒÙìQ£Fá&Þãð©Ö­[ã}¹rå4h •d­´kß›%fËÇŽ ×ÿ#f°®‘PJ$¨X±¢±ñ) œ:ujVVäV”/D!³gÏ^°`A™2eJ—.½téR̈’^èºíµ×j{¤{o«#×¼¶A¼ê½vЧî÷Å‹’ÌßP  Ó„z‰s´>þøã† –-[Ò[½zu‘¢S§N[·nÅÈ$Ž êÑ£„Mâ“êk*ÉVE‰JË—/r°zýí·ßêìQ«V-´Áh¤ÔVªTIdåËá"Ÿ,ÜÄŽkìùjÓ¦Nü¦L™‚9aÌ cŸ”ô˜M‹R‘dÞ®];1OŽ™süe€¢p3m¦’Œ?/òòòöíÛ‡¢ªyàÀDúå—_FØt=sæLq3óŽôXWðëOÎ>%~/i ù#%Ùî ez  P%ûå~ñBùÞô&½dU¦LG$@$@¼´ç¨â‹’ì/³ €*Žþ¤ø¢$«2e:  ðš×’½&ÌòI€H€H@‰%Y ‘ €Œ—ì³ €%ÆKæà  ˆ6‘#G¾õÖ[²8üK÷£xÂØõ«yóæ~ø!›ÆÃÓ›7oîÒ¥ ª°lÑnzÓ^0^²ëÆe$@$@Nà¾(OÈŒ£²pôæ?þñù#ùºôÒKÓ–k7Î1ùÂI  ÀÁ&¨«eË–8iÄ®$£RW$™ñ’ÓÚ— H€H€ü u<~üx³fÍPNÄÄA˜|ðüqÛ¶m¢}ûöݹs'œÚO>ùq¤|êÂ#¬2´)q¦æ Aƒðþ믿1"µWÍš5!öâ¼Oí¥Œ¨Si+5—là§ob!¢¿úê+´S†`¼d?Æë  P!ðþûï2)qŒeÏž=Ÿ|òIù£<·ò¦›nB¬'8µf¼lÙ2!ÉÚ8ÇâGä…׋s¶¡ÄO<ñ„xÿÑGéšrvïÞs@;wî ¥”Ÿê¼^•Jñ3¬<¿ñÆsæÌ¹à‚ Úѱ¤$3^²Ê a  ?@5_ýuÔ„5Ý+¯¼ñ*ä¿þõ¯u-À$3"LHIÖ…=a•Èò,¢9á=&ÆÝ¸âŠ+¦M›/Á%±¨¬õ¼‰STj%ɺÏ",•ˆ´ë–[napF?Æë  °EqœþùÏ^tÑE˜FF¨&œñ#‚!B8EQˆ½ˆ_ØŠ…ëĉB’µÁ›­¢Sœ™Ø¬Y•+W~å•W$ÃX¦ÝJM£A é5Q¦$Û$LL$@$àÌåþûßÿ~ä‘G.\(êûôÓOñ#æ–Ř²†Úåääà}‹-„˜¹%É( ËÆÂ“ÖÆ?V©Ô4^²éÂKFÌJÑ#­—ÌxÉ~ 2ÖA$@$ HN*ßÅxÉ$$@$@$à+zõê]}õÕ¨ù¦M›&L˜ ªW –ŒdH̰¾ÚŒ•‘ Ä’@Û¶m 0q©òéÓ§—,YRtS1X2’Q’c90Ø)  H —I³±Ñ$@$@ñ#@IŽŸMÙ#  °`¼ä°X‚í  ÇÁ†íÒÃãȇÆH¥J•²›×£ô;|ôóC§^x£}¯½#îs-Ù#°X H(È!.ìr“Çâ½|B×k"8B §€áÈ-]E®ÄXTl¼±.ÆKVDÇd$@$@žH{ô´µÂ׋-«V’/Ù [³L  U:I–¢(ƒ §{Œ9g‰xP˜‚ž1cލ4ÖŠC+qb6N®F²I“&+V¬AƒÒ5÷ÝwµYÔk)Ar×®]€XRˆ÷,Š2WÆMœÖ9wî\´ó_ÿúBAãŽ.$3î0^²ê a:  /¤ä´aqÌõ‚ Ê”)Sºté¥K—Ž?ÞØÂ%K–àÈL<û‹c¨7lØ0jÔ(¤±ò†µ’œºv *‹’rݺu£Gµƒ+ã&ŽêÄ…ó;ñ7NÜ4mã%{1ÀX& €*Ô’œ"ì1\ä“'OÊJÙÙÙ8CW«»$¢JàêÔ©;ªKrŠÚ…$Ë’;vì(JÖ^2¸2šø’5jÔÐ~jògÁÌUçi_ÚÔ†ø”êc:  E©'®E!Ú4ò}­Zµ Š˜¦¦q–®Rcpâ#GŽ(J²\l6­7!ö²ºúõë‹’qƒ+ëš!;¥_Ϧ$+&# ð‚€cI»¦ñŠVé¼dé˪L\§•d­—Ü¡C=Â4¸2¦Öá%K—Z4XbYÜa¼d/Ë$ P%àX’Qâ(ãŒhìœÂ{D5nß¾½±V¬1#™\ñÍÍÍE·$‹Ù(¹bÅŠk×®3fŒh†1¢3î/Z´èÕW_ÅŸXKnÕªîhC,‹f3^²ê a:  /d"Éü¼‹÷p¸7nLINè¨b·I€H€0Jòõ×_¿k×.!ɘӞ:ujVVV‰%pÇe¹fÍšðª‹)r饗îܹó믿F2ÜÄ‘œ¸IIv`f! H(£$ËŽB’qþ¶Œ²,â¦M›vëÖ-??ýúõÈ×yÉ’%øˆ’œÐQÅn“ 8 `”䜜é%ë‚%£,£Æ¹sç>ôÐCÏ?ÿüÝwß=a„xॗ^:t(%Ù9˜…H€H ¹Œ’ @0pøÆ‡~xìØ1<õ»yóæ.]º þKò«ûÅ µË÷¦7)ÉÁ ÖJ$@$à)óÏ?ß¾} (^¼8NáÀÓíÚµ D’Gÿw^²³x?ªðŽö&îàEIötH°p  ` ¶"@ "“®zá%÷éÓgÿþýÿжm[‘ÀEQ¤ìÙ³'ί†Ÿ=mÚ4ȼH\ªT)DŒ8pàÂ7͘1C}ÂÕ¿” ¿|Ïž=ƒ7ïXù…xÉ–˜þ(p-9˜áâ­•jÖÌÝ´ÉÿzY# øOÎ1ÔqñâÅ;w¾øâ‹eÄÙ[cÇŽ…ëŒÿ׬Y#>2FQ)"¢dÉ’î´nݺѣG‹Ä³gÏ^°`A™2eJ—.àÇãÇÇMÔòã?¶nÝïË•+'ŽØÄuÍkÄ«ÞkëÄ}ñ¢$û?N«ñúÞ½)ÉÑgÅ$@¾¸âŠ+àÚâ(i(%•k×®&¡ÅÙÔxߤI¸¿ºvÉ(Š"eõêÕEćغu+ÞÀE>yòdÕªUÅýììlÀ› /¼ðûï¿G˜EHõ9eÎ\užö¥ýÌð½d߇I@ö?Ÿ’{VK$$Ê•+#R“pˆµÛ»ðþ»ï¾-3FQħÐrÙn¹V­Zê¹sq#¤l¯X±wV¯^ ©>—’¤ñCYw…5|í5Jr(ÃF‘ xN1”ÒJ’M£(ê¼ä:ÈØMXcF'«FcÉyøðá;vì ._´¾Æâ xá1‹üH|J/Ùó¡† ÚõèÑ~ÀJrlÁ6 ø@žñˆ#Ä´3¦”±kåÊ•V’lEQH2–±–\±bŵk׎3F´|Þ¼yÓ§OG±x¼íÛ·ÇLeß|óÍbCY¿~ý¶oß.ß°ü ñ’½6ýQ$ $û06‚¯â¹s«\}5%9xK°$@¾À«ùóçcçóñãÇ1±Œ}^—]v™•$ã¾1Š¢nÇõ‹/¾(w\C¤óòòðÂoÙ²eàÀ(ò¹q,NcÇõ† Ú´i#:Úc]Á¯?9û”øQ¼$ ù#%Ù—Ñh%å«V´d š@IÔ¬œH JÜ:T$÷ËýâuêKøÌ{Ó›ô’£4>·µÍ}÷ýlÐ J²c€ÌH$@nIòK{Ž*¾(ɉf¿ýóŸ«Õ¯OIN„±ÙI —¸%ÉýIñEIvÉt!.¦Ü%— Y¶L4×!6›F$@ÜÞ÷1}÷Ý¿xè!JrÜíÌþ‘ Ä·wÅÁŠ)úÐsæÌêQ’cnfvH ¬”Ã%ÿĉë°ÚÐ¥v•©TièÛoËÂ8qíWC$uêÔÁ9]™ô–ñ’3¡«¼­î¼ó–‡¦$ÇÊ¨ì €{2ÜÃ¥’ñ’Ý3WÄKúM~þåÍšQ’#nF6ŸHÀ+*šš¢n•쌗ì•ñ¢Un©ò凯X¡m3'®£eA¶–HÀkZMÅI× .ÄQØ„xðàäÉ“‹/žV’‘`Ê”)ؤãD®»î:ÆKöÈLÑ.¶qçο,üûŽ^r´ ÉÖ“ xL Y³f‡ò´ÆKöo ïþì³uÚµ£$GÀTl" @pŠ)2qâÄ·ÞzËÓ&(KF24ƒa'<µE…ÏÊztÍÓŠ9q€=X% @( àðêcÇŽaÍ[´|øðŒ3J”(¡+ªfÍšXÁÍÊÊÒÝ7 {Œ4}ûöݹs'\êO>ù!(¤x÷ìÙs×®]ð³§M›™¥YÕn/ù3å‹’«ß¬"c-™’+£²3$Gˆc½¬X±¢±sVA‹‘~êÔ©X¡¾³gÏ^°`A™2eJ—.³©Ç¯+ ÎñîÝ»q@fçÎqµü’l {ŒOoºé&ü5€\(yÙ²eB’‘rîܹòÔëÑ£G‹rLk·Š—üÁ™kUá…ŸÄÿò¸‹’«Á޽֨qMIŽ•QÙˆ#Zµji#!Ê.¦Z uÄÔÒIņ)„y?fgg9]qÅpm·mÛ†º°¨,}_cØcm^LqÃù–’,#(ËØPp‘Mk·Š—¼Pù¢$Çg°ãYd<‘œº?\K޽Ùˆ2òåËCá•ê:‘6h±HEGvì 6O¥>§ºråʯ¼ò bB¡5tÂýÞ½{##&¨q8qB¤4 œ¢vÓxÉÊŠ¼’åA}nÛqbÎí¢$ÇÇ¢ì ÄšÖ’¡‚º.ê¼dcÐb‘É «ø_P“&M ÜV’Œ?P`Ná!K-Z´øî»ïDJ¿ô’;tè‡[¥v]¼ä+V`ýÞÈKÞÑ~DIV7hØSâ\kœnMI»Ø> BØqùá®]»Š×­[·;®S-–ðØxúôé˜+Æ*Uª´7<ü ÏxĈBP‘ {ÁV®\i%É(êÛ°aC¬UcX+ÉøkÉXö^»ví˜1cDLk·Š—¼Qù¢$Çä—qŸý)mg8q øFO%Ák„ózäÈ„ÀQ¨:uÐbÙ6Èd^^sBÞ-[¶ 8P×ìråÊÍŸ?Ïž=ÇÇ´6öy]vÙeV’ŒûãÆÃvëíÛ·6LJ2\g¹ãúÅ_”;®Mk‡ü›ÆKFó/J²ocÏÛŠ1’ÓÖAIN‹ˆ H€H@pë æ½Ê%9&coäêÕY¥J¥í %9-"&  w%YnCKû†’‡±W;;ûž¼<•žP’U(1 ¸è%c\ñ¢$Çaàuy챦·Ý¦ÒJ² %¦!  08cPä]«÷‘÷ß¿@íaJ²kÐY x@€’ìT‹¬Ù²å}/¼ X!%Y“‘ €[ƒ%#'®ÝbX9GŽlqûíŠÕS’A1 ¸E@1X2’Q’ÝbX9ÃW¬(U¾¼bõ”dEPLF$cð€øQÆ Qºûâô.ÄrÆ…§ŸqÒî‹Õ}+bŠÁ’Åábœ¸ŽðÀ»¼Y³ßäç«w€’¬ÎŠ)I€bIàòË/ÇÖÿûßï¸ãm÷µÏ%ã‰'®_¿^H²<%[{ß —r¸ä¯)ÉÑr·<üp«;ïTï%YS’ Ä’Àã?Ž3;{ì±7ÞxCÛAã}ÝQ!Íš5ÃÅ:IÆò>Þ3^r,ÇŒj§†¾ýv™3ÑÊTòP’U(1 @Œ tĽ÷Þ[§N¬ÝâlÙSã}­$#Hó³Ï>ûæ›oê$Y{Ÿñ’cµÝéÚµ+ÜeÄl6½_¿~}ù\ò·ß~ûÞ{ïŸKÖÞg¼äØ •ô7eºAK–”¯Z5}¶sSP’ícz È€r¸äSßð<*$CÚ>e‡Q‡*L[å꫘;×AÅ”dИ…H€2!6L²L@I΄³¯y…$‹ëÿ}õÕ²¿ÿÝAõ”dИ…H€2! ,É(É™pö/¯V!É¿ÿþ°Ü\ÝT¶Jk(É*”˜†H€‚"À‰ë ÈÛ¨W+Éßxâ÷+VHY®R¨GIV¡Ä4$@$JrPämÔ«•ä‘/½4rÖ,)ÉâvçWŠr)É6 3) ¸A€ñ’Ý š2t³Ö¿_¹røèÑZI TÚKIV¡Ä4$@$à"ÆKvfðEé$Yç ™’¼Ø· (Îý¸]-ËKvíÚ!R2ž0Æ!\¯¿þ:"RŒ—œ¸¡ ÒaIV)iè%+‚b²0°µO" f¢H ''çàÁƒˆ\¬X±’%K>ôÐCû÷ïÇ¡B’Mã"3^r íN›UôXÑE¦$»c–â íÈwðp/md%q €32ûõë§íÉ´iÓòóóu’Œ/9öΰ”ä 2{D è$YýïΈö—Í„@ùòå±÷ªÒ¹Qço¼ñÆ‚‚$3^r  ]¥rîθ„lk¯µè'®Cg`6ÈŒ€î/Q.*s˜xDñüñG]á8ÚúÈ‘#B’/Ù#ò‘/ÖT›Õ7vQ’#?’ÔºÈI²v}µë%3^rÖ gÝZm¦$‡ÓFlU&è"gByíظq£q-yúô麉kü(ã"[ÅQ–U3^²]+Ä!½ƒ=/œ¸ŽƒáãÞºÈq·p¸ú‡•cQ¾ýöÛ±ãú‚ .2dÈ?ÿùÏË/¿\'ÉÚ¸ÈVq”/9\¦ k(Éá·QÂ[H9á î_ýõ«W¯ÆsɈÈô—¿üEE’ÌxÉX$)•R’“béˆôÓ8ÓC9"¦c3m«iß PžqmƒlÔ“R’£nÁ8µ_ª¯ÜPM9Nöe_$ÆKæ`0'@IæÈ Sõ¥‹ë°î`¼dwyƧ4Jr|l垘€C9Ê&eÛ]#À‰k×P†¿ Jrømû*ê1ëŠýH`M P’40(É 2v(»j¥Çt‘Ci.6ÊŒ—ìÇø•BIŽŸM#Ô#u=¦‹!³&°©ˆÞˆ[êg¼duVÉJIIN–½ê­é!6VzŒ6rWW@†bµzòAäãÇ#BT“&M\aôò…ê8qí óhBIކ"ÛJ!ÆÆ€(ŠzŒŒvψ,*6<Œä±\E‹?~<ÎÚTo%ÿ²JüµòEIV‡””ä8X1”}Њ±N’Sè1]äP3¹Òž”Ù´iSªoß¾;wî.Jr²†&%9Yöö¾·¦°V’q¾¥ÓEöÞ>¬Ám€ä?þ¸aÆÚü-[¶…Çšl‰  ‹º(nöîÝ{ëÖ­Jëĉ:IÆÄµ–^ÇŽW¬Xí\ˆc‘->RVä…”äd EJr²ìAo…|j=ZY˜1"­k7Zg`fõ„€Q’1e ÑÍÉÉA}-Z´Àј©%Y4‹ñ’=1Oü ¥$ÇϦîöH*±q×4*RãÔ›¹´º®Ó6Õ~w»ÆÒH -£$W©RSÓ˜ÁÆj1Ö’SK2ã%§%Ìç $s@X°»K·H,4UQu)ùà‡eH˜N\7;¨·oß>lذԒ\½zõ5kÖ`~éñXs›6mD¿¶(_HÌç’C2üh%ÙÊ¡©Cº¼)|P[lºKÅ9v¬Ç¦sÚ¡AȆ€ ´¿‰©ßS’]À¡"(É2–ã¦UÖÁ’°œ¸6u|µŸŠv:óy6ˆc+3c„0^r„ŒåkS)ɾâ>³øjµO*ucT|\m ©ý]©ÊiÝb¹_ZQŒmé±11W‘}“¬ÎŒ—ì?óhÔ˜(IÖM©[ÈqFé/*ú©Æ&i«Ö>Ý›¢ñ*«¢²ZÇ7…ç™ÕýcS=æÙ ê#“)“@€kÉI°òé>Æ[’uRjkC¯©ª/sZeWiƒƒ¼*YtGh¥UYi×¹ûVkÌ©—®u‰$è×]%”dHqI3IN¡Á©JáΚn$6µ¿-]Ô©»³¼*ªiK‰¥÷,üWõ™j«ÉêÔÄèÊ?Æåw‹ý KŒ—ÌÁaN ê’lKƒâê,»Öç³+¥ºÙ`[šjÌkü;ÃÁi]±ÄØJu>´é´<]d~7EŽ€ÝèÈÆ2^räŒîSƒ£(ÉÎTÐè,¦ž¹M¡vΠ“[µ;øÓA½‘Zá´ëËÙ•Iݘ¦‹ìÓ/yˆ«iÛ¶-Â%aûñÑ£GÑ¡{÷î¶kúÐpÚ¬r¹Y¥UÊá’¿Aw8qÖ¦ñI Iv Hº%[u}rW‰]”a ·J&–£9uÚ¹í/€i.«ÄV9eŸïåžÜxãìÖ­›,R¤Èu×]7kÖ,åܧªˆŸ±À’,ާvY[‹J«”Ã%MI¶5$"Ÿ8œ’lKZRLÕ:˜Î\Ë}–aíÞi•þ•ØÙLu&þ±¨Q‡š«È‘ÿ6±ÙM›6ÝÿýÆL8DQàG"ÈÒ¤I“QªoŸ>}öïßðÃp¯Å(¢,–-[÷q4´ø¨S§Nƒ(ů|ùòx‡§F§WÆ¥ýðÃ5jÔÐV”z-Yœ«%B#§hŒV’S´Šñ’ã=ŒíõÎ(ZÆ;d•dŽÓ¤h±¢¥O»%¸»Û9 —^¦b!: —*žzǵ©§ppµ¨S5Sò¸©8@µÙé"+B‹Y2ȼ^L ëúU»vm­Tׯ_ÿÈ‘#:õ…¦ê‚=ˆBŒaŒu¥‰di×’e“Ò6F[”U«/9fC×ywT ’¬ò ³4©¿£Ó6O÷w€‘6cê™a»ååP(¢ Ó¼ê Ùƒ ERäJ[u O×–S’ÿVÇ('Ö’!¢ºéSè™ô’…c*4UHrݺuåMÓ0ÆeÊ”—,}n‘]›K[»QªÓ6ÆT’MËg¼ä\§]Q‘%Y¬†¦ØNeÕï´ý²Òr]*ªf¥4™äUÔEШªUíæµ;H¥¸«Ë.ºØ¤ÇŽklàêÚµ«Øqݺuk±ýjéÒ¥óæÍÃZr¥J•Ö­[—››+dØ(ÉX©…«]­Z5$0 cŒû‹-zõÕW!®XKnÕªîhs¥–ä´IÛ*ÆKŽÍpu¡#i¥ ߆J2z¨¨:޵žìb¼ä0@_Û&¾js÷æ¦zmÚ”&Aêìü”¢@À×_‡âæ jõ‚—œâS~D1 €_Hýʲ±ñ'ÀxÉñ·±U)É1v!”ää~ý…µçŒ—VËxß.Jr&ßæÌ”dï¿fXƒ‡8qí!\ÿ‹¦$Ç@TØ…LP’ýÿÚa. $»3ø¢(É™|›3o P’ƒÿb Î%ÀxÉÉ”äˆ » Jrr¿þêyÚ`PŒ—eBP-%9“osæJ²ÏßC!Œ‚œŸŸ/ È“¿¢JhOI[²‹ /ÙE˜±*Š’+s²3$àÿã"+F/®S§Ž.J²'£$´…R’Ck6,™ŒJLI¶;®¸âŠiÓ¦mÛ¶íÇÄ¢2Â8¢«`ÙThM›¦D0¨~ø¡FÚÖ2^²]Û%==%9é#€ýJ,%™Ž²][U®\ù•W^Y³fQ’{÷îÉØÿ…ëĉºZÑ5FG6•d]üfÙTÓˆËÊá’ÒK¶kôh§§$GÛ~l}Ä (*1eÇvnÒ¤ ¶7#»6<³itdm£K­Žlš²L™2ð’úÉ´©ºˆËŒ—ìØ 1ÏHIŽ¹Ù½ðÐn×ÒzÀ*﹜œÖžðŒGŒ!¤óÆùùù+W®Ä{mxfÓèÈÚR’M›¦D‹-zõÕW1ƒµäV­Záã%§µœC€’ÌAþ°ë[)4U9µ½°»jþüù{öì9~üø¡C‡°ßê²Ë.Y´á™Ñ‘µ °9Klï² x,‹’)Å_/¿ü2œrlºž9sfŠìˆ$­x¡î¸öç74µP’Ca6"¾ÜRbÎ]ÇiŒ0^rœ¬éf_(ÉnÒdY$p†€ëJLIŽÓàb¼ä8YÓ;P’ݤɲOÀ;%æ¾ë8 .ÆKŽ“5Ýì %ÙMš,+‘2Ù®¥²¥Ë˜†Ëɉh\KN¹)É 26»ê*bódMWmÂ(ÉѰ“+­¤$»‚‘…$‡•89¶ö®§?)_h%Ù;C„®dJrèLÂ…’•8”f‰j£þvøèç‡N½ðFû^{Gܧ$GÕÆÎÚMIvƹB€JœCÛê&A°©£g®õë×#»¼‰ç¡7lØ€SÃpÓ4r3î¿Z°_¼´ïMoR’m™&ò‰)É‘7!;à6ÿ·k‰Ã«¹Nì¶%½*Ï4‚…¼‰ ÍãÇ߸q£Uäf4kôà%Û‡÷£ ïhoâ^”d¯¬Îr)Éá´ [å?:Äþ3h©%jÚ´é‘#G¬"7#Á+¿/IÀôG‘€kÉ'NšMIvBybD€J#cúÔ•Ô’Œ®'L˜€Ùl«ÈÍhå5¯m¯z¯šôÖ]â¾xQ’}2jHª¡$‡Äl†Ï¨Ä>SubÙXžÀ5`ÀôN{óã?nذ!nšFn>…bæªs^Z:†è%Çið¤é %9AÆfWÏ;Ï%æ"qüÆ]Ú‰kc—µ‘›)Éñ®õˆ’ìJVÁn× +¶Ë9’ŒÊdäf¼¿|Ñú‹7à…7ÆvÈħô’›*r9)É‘3¬HÀ‡X»qZ±‘LEŠ’l¹]¾aùâ%»oú£H@IŽâ qØfJ²CpÌVTâ°Z&>íR”ä‘›{¬+øõ'g‚?Š—Ä$¤$Çgè¤í %9-"&ˆÿ•˜‹Ä‘áldî—ûÅ Í“ïMoÒK§½j%Ù+²,×*±/ýc%ñ$ðÒž£Š/Jr (Éñ±¥/=¡û‚™•ÀY”äJr‚Œí´«þo×â“ÄNmÅ|1$@IŽ¡Q­ºDIN±mv•±M`LNž ${‚5œ…R’Ãi—[E%>«&#Jr‚F%9AÆNÙU*1G øF»¯/4‰’ì›]‚¯ˆ’¼ mÏJÌEâ@­ÍÊÃBà¤òEI‹Íüi%ÙΡª%ÀíZ¡âÀÆ€–€8za!Ž?Ž«q¦w|ð4”âEIöÎ a,™’F«xÓ&ŸbFBôÆŒ,Õ+òˆ„‹?~üƽªé¼ó¾V¾(ÉÞY!Œ%S’ÃhWÛD%v' ‹-í©[M›6V÷íÛwçÎÇŽûä“Op5î˜Î…ûýû÷G(F¤Ü³gÏàÁƒ¦R¥Jåççãä¯Ã‡Ϙ1CÄ}Âõ™òEIŽí€3í%9®ö¦ÇÕ²ì—G¤Ö"ìñ„ Ö¯_Šnºé&œÀ±\³gÏ^¶l™•$ã¼L„ ÀA›HP®\¹ ˆF"ׂ Ê”)Sºtiœš ç[Üÿà̵ªðÂOâùFÜÇEIöÈÜ!-–’RÃ8m–ÏJÌíZN Å|¡# Ö’qà%®?þ¸aÆÚ&¶lÙή•$#¦ò÷ßߣG¨¯Ì»¸ªV­*îdggˆ÷ •/JrèЧ ¢${Š×ŸÂ¹]Ëά%Þ´3Ò²§…øN8Å׉'¬$÷ J‚½zõj¨/î вÔxÈ<>:tè%9Þ£(ÓÞQ’3%\~Ÿbn× ÎÔ¬ÙFIÆ”5âCäää ú-Zˆ0‹5kÖ„Ð"$Þ#…¸)/Ü>|øŽ;pQ‘ÿ[ñ^^xá¼äíGô’ý°}xê $‡ÇŠ-¡+‚b2°EÀ(ÉUªTúb;++ «ÂB}±® ‘ psþüùâ&f§o¾ùfÜÁû~ýúmß¾]TÐÓ§OÇ´6Þ£´öíÛ‹ûØÎ­xQ’m1ò‰)ÉQ1¡ÏJÌE⨠¶Ó-¦×ãÆÃ&jHì°aäCܳgOì †+'miÕÔ*ž±¬Åªjõ&¡d\Mš41-GT„£¾víÚç~Ú´iâdl\Êá’?£$Ç|üS’Ý50•Ø]ž,ŒàCh/^ܹsg¨¬L •d䨱cáCãœm)Ò¼ñÆsæÌ¹à‚ *V¬ˆMFI¶Šg,«H[µHiZŽˆö8wî\«Y©R¥uëÖ=Z¤g¼dŽóÓ(É™n×Êœ!K [®¸â x™Û¶mûñDZ¨\»vmd×Irùòåq>+\R¼A&$®V­š¨è–[nÑIrŠxÆÚ¶¥®)­Ê’Œã¯EiˆÞˆ8â½r¸ä…Ḣ l •ˆ%¦$;6XP1W÷›ŒãG råʯ¼òŠðƒu×¢³¸)¤² I–êׯ¯“äñŒM¹™V”Vå %º ø%9~c2£Q’íâ J‰í¶“éI !à‹­È©%YxÉ›(°½äñŒ­HʪëÖ­‹ub‘̪—Ü¡Cxù" ã%'d¬¦ï&%9=£ÂTbEPLF^€{:bÄ1ŒØÃùùù+W®L+ÉH°lÙ²—^z©D‰*TXµj•q-Ù*ž±ì‘UÕXÒÆ¤´œ7-GH2–™±–ŒÅìµk׎3F”¬,ɘ×^° ˧$§¦O%rt²n0#P®\¹ùóçïÙ³çøñã‡Â>¯Ë.»LE’/¹ä’wÞyO3ùå—ýû÷Çîhm.¼·Šg,[aU5L™2Î:Î*iܸ±i9º×/¾ø¢Üq­,É(É1ÿ $ ìóv-~ˆùï»JØ­-çýi`Šg—•Ã%ï¥$ûc¬Àj¡$Kôtˆ…¬˜|!P¯^½«¯¾UÁ«Þ´iÓ„ |©öt%)$Y%R²HCIöÓdÔEI¦0ìX% Ag†`âÓÝÓ§OÇô²Ÿ­H!ÉŠÁ’Åâ7×’ý´šßu%V’©Ä~5ÖG$àJ²ÃZFÒ$ÙO%æ"qXG=ÛE&@IްñÒ6= ’Ôv­´ð™€H€ì $Û%¥ô1–d?b2K¼¢d~¶•H j(ÉQ³˜öÆO’©ÄvìÏ´$@#@IŽ˜Ál576’ì§s‘ØÖcb  P’]„º¢¢.É(qè¬È‘ $†%9Î¦Ž¢$s»VœG$ûF$’%9Î$B’ì§CÌíZqôì D™%9ÊÖK×öðK2•8 ù9 @‚P’ãlìÐJ²ŸJÌíZqâì Ä‹%9^ö<·7a“ä@”8ÎfßH€âE€’/{†O’¹]+Î#Œ}#p•%ÙUœ!+,@/ÙO‡˜ÛµB6îØ ‡(ÉÁE"›ÿ’ì§s‘8ƒ$P'@IVg½”¾Ir J={°Å pú0tíŒ6ß'»hI€’çÁáµ$S‰ãûì}O<Ñmøð_õéÓ©{÷ŸwîœV±)É –”ä8¯%YluvËK¦C籑¾e.Éíþó[n¿ýÖ=î4èîÇë1~ü/¼ðàܹC—,ùþû£6nÄÿx;¸O‘掑¹—’‘‘âU3)É^‘ C¹iõ 2lgÚ*Ò 6•8C0»‹2_KNWžÜq»sÿ¸3÷ùí¹3¶åÎý{î¢/s—~‘ûîÿä®þkî†M¹/oq±;,*r(É‘3™§ÕË%™JlÃLê—ìÏ**ýÍSOáåO~ád=¶ P’m#‹P$ÙÖÜ5‰#4x’ÙÔ $Yè1„™’œÌ'{MIŽóðA’O¥!Æqf;ł@0’üò¡Ç”äX ¢Œ:AIÎ_È3«ˆeæ]°ª…SÓ™³e >ð_’sxëÇr'6½dŸ-¶ê(Éa³ˆ›íñG’us×Tb7MȲü%à³$COI²æahJ²¿]m”äЙÄÅù#ÉbîšJì¢áXTPü”d¡Ç§~}(ÉAÙ;|õR’Ãg÷Zä›$»×d–DAðM’¥S’ƒ´wøê¦$‡Ï&’ìK–”þH²V)ɉXʤ$+£Š`BJrÆ&IÀIÖé1%9H{‡¯nJrølâ^‹(Éî±dI‰ àµ$õ˜’œˆ¥ÜIJ²2ª&¤$GÐhlr<•dS=¦$iïðÕMIŸMÜk%Ù=–,)¼“d+=¦$'b`)w’’¬Œ*‚ )É4›$$9…S’ƒ´wøê¦$‡Ï&’ìK–”^Hrj=¦$'b`)w’’¬Œ*‚ )É4›$×%9­S’ƒ´wøê¦$‡Ï&’ìK–”îJ²ŠS’1°”;IIVFÁ„”äM’€‹’¬¨Ç”ä í¾º)É᳉{-¢$»Ç’%%‚€[’¬®Ç”äD ,åNR’•QE0!%9‚Fc“ƒ$àŠ$ÛÒcJrö_Ý”äðÙĽQ’ÝcÉ’A sI¶«Ç”äD ,åNR’•QE0!%9‚Fc“ƒ$¡$_Þ¼ùoòóív€Áí‹qzJrŒ{*ŒqÎС)^Hçþ³o$`“@†’ =†*Û¬“ñ’í‹szJrœ­KI޳uÙ7d"ÉÎ\dN\{`ÆIIްñÒ6’œ€–@&’ìÌE¦$sj P’ã<(Éq¶.ûæÇ’ìØE¦${`ÆIIްñÒ6’œ€+^²c™’ÌH/9)c€’œK³Ÿ.pæ%gâ"S’]2]LŠ¡—Cšvƒ’gë²op&É™¸È”dÌá")É6^Ú¦S’Ó"bÈpâ:C™’Ìȉ뤌JrR,Í~ºDÀÊKÆ}¼Ìç¢Þù,wJñ£TYÎ-G…¸d½8C/9V´ê%9ÎÖeß< `”䜜yS¼‘ÕžúhJÁà dñQš,……h³P’=°dT‹¤$GÕr*í.ü[<ÍK¥¦!„0JrŠÕe|=þe¯^Rb¥ÔYDbmJrBF—J7)É*”˜†H L¼äë¯Ï/ŽŽÚóËž=O¹Èç~”;jÏéôfYL?¢$'bl©u’’¬Æ‰©H€@À(É?wžxé$wfåç4o®ûH¦7ÍbZ%9#Kµ‹”dURLG${êרhûÎgÆYhN\Ç~xÚAJ²§xY8 @”¨oï³ÈXE6ÝùÅí]Q2yÈÚJI™AØ à(>¥}Ùêa'>œ#\3%9ÂÆcÓI€Ü%þñ Cá³Èª‰Ó>öpnw{ÄÒ¢E€’-{±µ$@ÐyÉÚ¥bùóÕâYd/.«I<ì3‹Jr˜¬Á¶ J@E’µÏ"»®Ê”ä@í|å”äàmÀ „„@ZIöÔEûÂB‚‚Í„%9ìÁWj\ ¾Ml M ­${ê"S’ƒ¶ðõS’ƒ·A -0~õ˜îU ¤m¬”‚"fǶtac—ÍíZvÓÕwÖ”ä0X!€6¤õ伺/”ÚÊ*I ~=mÚÍ›»ÞžÞå:ÒèHIŽ®í2j¹¢$w¯Ð™Îˆ;3G–ÀåÍšáx/šOIö‚jDˤ$GÔp™6Û±$›n1åÊt¦ö`þÐøõŸþtE‹^4“’ìÕˆ–IIލá2m¶»’Lg:S{0¸ ÔhÚ´Ç‹/zÔFJ²G`£X,%9ŠVs¡Í¦óÏ®?d©+δ –cA¸ï…j¶léQÍ”dÀF±XJr­æI›ÅÆ—§:Í•iOlÉB]%P£I“Ó§»Zä9…Q’½c¹’)É‘3™¯ 6ÕiOEÚê/_»ÍÊH@CÀSõP’9Ü$J2ƒmþ;Ó¦:m»ÝÌ@ö ToܸçŒöóÙÈAI¶+îI)Éq·°/ý£3í fV{Ÿ¾V«VžVLIöo´ §$GË^Qj-é(Y‹m5#P½Q£ž3gz͆’ì5á•OIޱâÐTŸ·qe:ƒ&¸>Ü;uj­k¯õº~J²×„#T>%9BÆŠgSéLÇÓ®ÑïÕeõòÞE'Jrô‹k= $»†’¹H€Î´‹0Y”3÷äåÕÎÎv–×V.J²-\ñNLIŽ·}ãÓ»8ÓhF|˜²'Ö.kذ׬Yþ¢$ûÃ9µP’#a&6Òœ€ÿÎ4ÇJÈX¼gʔڭ[ûÓYJ²?œ#Q %9fb#U ЙV%ÅtÖª5hðÛ—^ò%Ù7Ôᯈ’~±…™ 3)Á„å¿{Ê”+ýr‘–’œ°ñ•ª»”d†$ 3D««õ¹Zýú¿ýóŸÕÒº“Š’ìÇX”BIŽ…Ù 7„D§Ýè ËpNàîÉ“¯lÓÆy~û9)Éö™Å6%9¶¦eÇ\!àÿ¤7£c¹b8g…T½æšÞ³g;Ëë8%Ù1ºøe¤$ÇϦ쑇r7mÊüå ”–Q§=ìd‚‹îþÜsuÚ¶õ%Ùgàa®Ž’fë°m¡#`uÂ"éЙÊ~ƒq‘ÑLJ²}[Å6%9¶¦eǼ ðóÁƒ[ß{¯JÉ!Y™æÙ&*Æiº?ûlvíÔÓ»•’’ìÉ”CIŽÙÿ4êÐá¶'žp\ŸÿÎ4Ï6Q4Ö¥õêÝ?gŽbbw“Q’ÝåéÒ(É‘6ï7ÊW^Ùwþ|k¥3í"ÌLŠºkÒ¤º×]—I ŽóR’£‹_FJrülÊyK`ÔÆÞVP¸¸¨{9Øf7K’w]zõÕ÷ÏëµY­Ê§$E>„õR’Ch6)Ôú¼òÊ%uêøÜD:ÓžÐEF¿(Éž7Z…S’£e/¶6x·Ó¨cÇàÛAgÚ%T¹êªæÍs©0'ÅP’P‹iJrL ËnyF;®±ïÚ³â3*˜Î´|ÝþøÇ«®¿ÞAF·²P’Ý"ƒr(É10"»à+Z­ZÝûüó¾V™Ye!Y™çãXUêÖ}àå—3œinJr¦c”Ÿ’#c²+¾(}ÑEÖ/÷¥*¯* Ä™çãXÝžy檜¯@«•KIV㔈T”äD˜™t—ÀÐwÞ)S±¢»e^Z :ìÞ—Ô­Û'hv§$>øÃÓJrxlÁ–D†À=yyµ³³#ÓÜ ’Iï z*ë'^}à ®^,%YUìSR’cobvÐ}?4¨Í}÷¹_nJŒ3'Ùð<[S’Ã`…´’C°Q"аC‡_ep¬f”ºªÖÖ(:Ów>ýôÕ7Þ¨Ö?oSQ’½å©Ò)É‘2•k×î»`A8ÚÒV„Ü™vý`ÔLÌ@I΄^ÌòR’cfPvÇ'£6l8¯HŸ*‹K5!q¦ÑŒ®O?]/.2lKIŽËw¡”d ²ˆÀN]ì×M`ÇÝír0Îô3;C5ÉAIvwPEº4Jr¤ÍÇÆFà—£G7îÔ)°êc]±×ÎtîÒ/êµo„”äðØ"ð–P’7IÙ÷Üó‹!C"Ùô6ÚEg:wý¦Çׯðµ×zÏž}ßóÏw0áÖÇÿÅCåÜv÷îMºtÁ„vÍ–-«Ö«W¡zu Sìüó½FIöšp„ʧ$GÈXljˆÔlÕ _è!jPòšâÌ™Î}ãón?\¡Fª×\#Â]nrë­ÙwßóÀ¿:ôÖQ£°Ì|ß /ôž3çÁ×_Ç1m­]ûØš5ÃÞ}×TůuCÅ)Éɼ–=¦$s0€¥Ê—¾b…“œÌã´Ît‡;ïÌ]µG{ÚjB±¬¬Ò*˜ªøÍn¨xîS»o¸é&ß:œ'ÛÂÅÄ™0‘dCôtÓqΛ$xŸ~œ»{_¢Dà‹¥¹ÿ;Íï“»û©Ü]Oç[—û¿ÊÝ6#÷ï³s·¼œûÕÂÜ¿½žûŹŸ½û?ïåþõƒÜO×änZïG«ö&þw6ôL$9gèP¾H€ÒxpéÒ_Mœ˜6„„@‡Ñ£‡¯\’ư$`J€’Ì¿?HÀ!žsæÜ;}:¿Y¢B ßk¯ÝñÜsQi-Û™L”d‡_ÇÉ.ìµ–@×É“û.^L&‘ @9fb#)É”dpH ã˜1ÃÞ{_"‘ @9fb#)É¿Ž9tHFmÜHá'pKnîÃï¿þv²…$@I¦$“€sC—/ï4v,¿GBNë Xey#Ù<J²ó¯c è³páyyäft‘Ãl¶MG€’LI&çîÉÏï5o¿VÂL€.r˜­Ã¶Q’ÿrô€ŽÀ/'L´l±„–]äК† 3%@/™ MÎ üìw¿ûÝÇóË%´è"‡Ö4l%Ùù7/G Xùá‡?ì1ò ![FzxÕª6ŒM"+ô’©Ó$«گ׾‹u2%´ÍcÃHÀH€’œÑ×1‡ ôœ=ûÞ3È!ln5êºÈ X5”dJ2 dD€Çj†MŒE{ú,Zt']ä¨ R8Ç’Ÿ­¢$gôuì§©XW8 t3f8Õ ÙW?]äpþ²°Ui P’)É$)Q6ä –ö— |#@Ù7Ô¬È]”äL¿ŽÝµK‹"«*«Ýüøã|ðA¨šÄÆ€"J2%™2%ðÀ«¯v›:UñWŽÉ¼&ÀSN½&Ìò½#@IÎôëØ;Û°ä¨ౚá±]äðØ‚-q@€’LI&L ðXM_=e¡‹ìXëJr¦_Çþ؉µ„™ÀM#G>ºfM˜[˜¶ýâñÇGp9d»ß2öÜê&%™’L.ౚn}%eRõ3¡Ç¼a @Iváë8 †d‚%ðà’%¿zæ™`ÛðÚñûßX½:áØý¨ $S’IÀ=fϾÇj:eJ9êjÄöƒ%Ù…¯cŽ$  Èœ%™’L$@$@¡ `"ɸÅ €ÿF}à 7œ'Ä™ @€NI2þñ"  œÀÿYÐ;dPFIEND®B`‚python-box2d-2.0.2+svn20100109.244/doc/manual_files/index.php0000644000000000000000000000044511130023047021513 0ustar rootroot/* generated javascript */ var skin = 'monobook'; var stylepath = '/wiki/skins'; /* MediaWiki:Common.js */ /* Any JavaScript here will be loaded for all users on every page load. */ /* MediaWiki:Monobook.js (deprecated; migrate to Common.js!) */ /* Deprecated; use [[MediaWiki:common.js]] */python-box2d-2.0.2+svn20100109.244/doc/manual_files/ajaxwatch.js0000644000000000000000000001061511130023047022203 0ustar rootroot// dependencies: // * ajax.js: /*extern sajax_init_object, sajax_do_call */ // * wikibits.js: /*extern changeText, akeytt, hookEvent, jsMsg */ // These should have been initialized in the generated js /*extern wgAjaxWatch, wgPageName */ if(typeof wgAjaxWatch === "undefined" || !wgAjaxWatch) { var wgAjaxWatch = { watchMsg: "Watch", unwatchMsg: "Unwatch", watchingMsg: "Watching...", unwatchingMsg: "Unwatching..." }; } wgAjaxWatch.supported = true; // supported on current page and by browser wgAjaxWatch.watching = false; // currently watching page wgAjaxWatch.inprogress = false; // ajax request in progress wgAjaxWatch.timeoutID = null; // see wgAjaxWatch.ajaxCall wgAjaxWatch.watchLinks = []; // "watch"/"unwatch" links wgAjaxWatch.setLinkText = function(newText) { for (i = 0; i < wgAjaxWatch.watchLinks.length; i++) { changeText(wgAjaxWatch.watchLinks[i], newText); } }; wgAjaxWatch.setLinkID = function(newId) { // We can only set the first one wgAjaxWatch.watchLinks[0].setAttribute( 'id', newId ); akeytt(newId); // update tooltips for Monobook }; wgAjaxWatch.setHref = function( string ) { for( i = 0; i < wgAjaxWatch.watchLinks.length; i++ ) { if( string == 'watch' ) { wgAjaxWatch.watchLinks[i].href = wgAjaxWatch.watchLinks[i].href .replace( /&action=unwatch/, '&action=watch' ); } else if( string == 'unwatch' ) { wgAjaxWatch.watchLinks[i].href = wgAjaxWatch.watchLinks[i].href .replace( /&action=watch/, '&action=unwatch' ); } } } wgAjaxWatch.ajaxCall = function() { if(!wgAjaxWatch.supported) { return true; } else if (wgAjaxWatch.inprogress) { return false; } if(!wfSupportsAjax()) { // Lazy initialization so we don't toss up // ActiveX warnings on initial page load // for IE 6 users with security settings. wgAjaxWatch.supported = false; return true; } wgAjaxWatch.inprogress = true; wgAjaxWatch.setLinkText( wgAjaxWatch.watching ? wgAjaxWatch.unwatchingMsg : wgAjaxWatch.watchingMsg); sajax_do_call( "wfAjaxWatch", [wgPageName, (wgAjaxWatch.watching ? "u" : "w")], wgAjaxWatch.processResult ); // if the request isn't done in 10 seconds, allow user to try again wgAjaxWatch.timeoutID = window.setTimeout( function() { wgAjaxWatch.inprogress = false; }, 10000 ); return false; }; wgAjaxWatch.processResult = function(request) { if(!wgAjaxWatch.supported) { return; } var response = request.responseText; if( response.match(/^/) ) { wgAjaxWatch.watching = true; wgAjaxWatch.setLinkText(wgAjaxWatch.unwatchMsg); wgAjaxWatch.setLinkID("ca-unwatch"); wgAjaxWatch.setHref( 'unwatch' ); } else if( response.match(/^/) ) { wgAjaxWatch.watching = false; wgAjaxWatch.setLinkText(wgAjaxWatch.watchMsg); wgAjaxWatch.setLinkID("ca-watch"); wgAjaxWatch.setHref( 'watch' ); } else { // Either we got a error code or it just plain broke. window.location.href = wgAjaxWatch.watchLinks[0].href; return; } jsMsg( response.substr(4), 'watch' ); wgAjaxWatch.inprogress = false; if(wgAjaxWatch.timeoutID) { window.clearTimeout(wgAjaxWatch.timeoutID); } return; }; wgAjaxWatch.onLoad = function() { // This document structure hardcoding sucks. We should make a class and // toss all this out the window. var el1 = document.getElementById("ca-unwatch"); var el2 = null; if (!el1) { el1 = document.getElementById("mw-unwatch-link1"); el2 = document.getElementById("mw-unwatch-link2"); } if(el1) { wgAjaxWatch.watching = true; } else { wgAjaxWatch.watching = false; el1 = document.getElementById("ca-watch"); if (!el1) { el1 = document.getElementById("mw-watch-link1"); el2 = document.getElementById("mw-watch-link2"); } if(!el1) { wgAjaxWatch.supported = false; return; } } // The id can be either for the parent (Monobook-based) or the element // itself (non-Monobook) wgAjaxWatch.watchLinks.push( el1.tagName.toLowerCase() == "a" ? el1 : el1.firstChild ); if( el2 ) { wgAjaxWatch.watchLinks.push( el2 ); } // I couldn't get for (watchLink in wgAjaxWatch.watchLinks) to work, if // you can be my guest. for( i = 0; i < wgAjaxWatch.watchLinks.length; i++ ) { wgAjaxWatch.watchLinks[i].onclick = wgAjaxWatch.ajaxCall; } return; }; hookEvent("load", wgAjaxWatch.onLoad); /** * @return boolean whether the browser supports XMLHttpRequest */ function wfSupportsAjax() { var request = sajax_init_object(); var supportsAjax = request ? true : false; delete request; return supportsAjax; } python-box2d-2.0.2+svn20100109.244/doc/manual_files/prismaticJoint.gif0000644000000000000000000000437211130023047023364 0ustar rootrootGIF89a¥†Õ ððð000€€€@@@ÀÀÀÐÐÐ```   ¿¿¿ïïï???àààŸŸŸ___ßßß ÏÏÏpppOOOPPP°°°ooo///¯¯¯ÿÿÿÿÿÿ!ù ,¥†ÿ@pH,ȤrÉl:ŸÐ¤â­Z¯Ø¬ö L*ˆ­xL.—–AcÁ8Ìð¸|n@"’>žûÿ€N yzzŽ€ _ ˆ•š›[]–¢ œ¦§Mj ¢® ¨³´ uw‡¯¢µ¾šƒ…¹º®¿È~‘”ÄÄÉÓdž ¡ÏÙ ÔÞWª­Ùå }ßêL·xæïmoëóFÁ Îïï|ôü ËÍù~PĨŸ7kØ ÄdpZ¸q #~ ÕðW»aƪ8˾Œyq4õï#H‰ÆF:Bx²¥žh*=$ç²å¶n1ã\¬Éó\ºÿœc<ö쨘’C“î3Ê…€š„I‡dZÅĨX/e¢ Á†¬`)r}â‚I°=7ŽuR AF êZá6E®mb ÈnËpE4ߥÜËD€Ü€€Í Þ¥'Aƒ¼Ò/QàWb‚ 0P¨œ ‚3  ”„{ˆè ¼©yÉ„Ä10xá\¨&Ö¥0øÚõlÀh]m%.GŒüózVG 7xß¹(tˆ(ÁÍs$ŒVH}Íj=kÖd‡ÿ 9òŒKÏ!P—½[Áa˜_ `pÜd×y Û-ÐsåL¥_a64Úh hÿ‡ TÐ ^‚È ¤ØŸB l5!^¡µàx<‰õâeÕ“ê²Ü8D[háæô"¤}ɸcd€Ó’ 8ædKt€€ˆÀûå V=ª¡…!tŸú8àŒ<Ï|¤ÐÜ„Ãâïz+ˆÞ<8Á#Ñ…ãRÀhT ãƒ@4"Z¨@ ÆèÀ¢µ¾bA3‚ÒÈ•d€|²&ÐÄ ÿ‘‚Z„b ™ A{TI›nˆQ;:±ŽõÓâ±ÀÇ#,R3ƒó1"0û=‘i»g²L q²(Yãl‘ŠY,“ @£4`{ù£xjÈ ðWxƒ‡4dÉÈ9[LÀ¸@&À7 9 ¸)=¸³L´­‘›;&I8~À0ŽÏ€ ÇØ?^ö²‘ æø–±i MŒ§×ÀöMi°llÉ,g?vè£W` ƒ&Ôe"¥öÌÌÀ–§Þ2·FÞmÎÌD# ÐAŠ ”/K¢9|hGor »Xf@V% Bæ‚Èi8Ç•)£4ÝØ(ÏyH‘ŠÿùhÛ.™ dneo" §±Ô@@Å@€ÓÑY@°)P¡ hŒrPãca/FHYì¦åF0ªèM·'ÈzšCLÔ'½É®Á%$¸"9f1÷Ͳ–ÙÀÀØú¿»U›ÊR«é9n(ð­IðyØÛáµ%·lìªj$žÈ´±€ó*Zfxزʨ?ÄŸMß ´âo–%º’ÇçWÀ¢eYc—Ð1 5åðŽŸÀC¿å.¢Ä N6&# XçÀ»¸õXÒHFòqEØx¬kf£@`Æq"`™õ|Æfœ]QDV[™ýÿ*">óâ0HA×ù@}ôî$!åE …D³V¢= .b®2 ˜eˆÈ¯%îé¬Ñæ£=°*P¢Ép÷­ ®EåÅÔ6ç+ú@hŽsàH€8‰xO‚+» lUHwƒãl@ƒàs€Æ–ñJ$Éö¶¦ž«-Õlkªæº"¬¥zY³b`˜šƒÕs  LUHÖ¥r>6°±<VËùX€o©Ô_0 D›gz©™²Ø‰‘hÍ ŒßèZ8kÃÅ7š-<°€>ûÙÏu¶3|˜WaZ`€ˆNt°—ÂFC EŽt˜J[ºÎôý ÐæŽ| µ¨ÑH±R›ú]ŠN4£ÁGKšQ~N;python-box2d-2.0.2+svn20100109.244/Box2D/0000755000000000000000000000000011414467242015420 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Box2D-License.txt0000644000000000000000000000156611064106301020452 0ustar rootrootCopyright (c) 2006-2007 Erin Catto http://www.gphysics.com This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. python-box2d-2.0.2+svn20100109.244/Box2D/Box2D_pickling.i0000644000000000000000000007405311256532055020400 0ustar rootroot/* * Python SWIG interface file for Box2D (www.box2d.org) * * Copyright (c) 2008 kne / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %pythoncode %{ class b2PickleError (Exception): pass def _pickle_fix_value_load(lists, value): """ Returns the appropriate object (a b2Body, b2Shape, b2Joint, b2Controller) based on the indices in the passed-in dictionary. """ bodyList, jointList, controllerList=lists if not isinstance(value, dict): return value elif 'pickle_type' not in value: return value # Depending on the type, use the right list if value['pickle_type']=='b2Body': return bodyList[ value['body'] ] elif value['pickle_type']=='b2Shape': body = bodyList[ value['body'] ] shape = body.shapeList[ value['shape'] ] return shape elif value['pickle_type']=='b2Joint': return jointList[ value['joint'] ] elif value['pickle_type']=='b2Controller': return controllerList[ value['controller'] ] return value def _pickle_fix_value_save(lists, value): """ Fixes: b2Body, b2Shape, b2Joint, b2Controller In place of an unpicklable b2Body outside of a world, use a dictionary with an index to the appropriate place in the world. """ bodyList, jointList, controllerList=lists if isinstance(value, b2Body): value = { 'pickle_type' : 'b2Body', 'body' : bodyList.index(value) } elif isinstance(value, b2Shape): body = value.GetBody() shapeID = body.shapeList.index(value) value = { 'pickle_type' : 'b2Shape', 'body': bodyList.index(body), 'shape' : shapeID} elif isinstance(value, b2Joint): value = { 'pickle_type' : 'b2Joint', 'joint': jointList.index(value) } elif isinstance(value, b2Controller): value = { 'pickle_type' : 'b2Controller', 'controller' : controllerList.index(value)} return value def pickle_fix(world, var, func='save', lists=None): """ Fix variables so that they may be pickled (or loaded from a pickled state). You cannot save a b2Body by itself, but if passed in with the world, it's possible to pickle it. So, be sure to use this on your box2d-related variables before and after pickling. e.g., + Save: my_pickled_vars = box2d.pickle_fix(myworld, my_vars, 'save') pickle.dump([myworld, my_pickled_vars], open(fn, 'wb')) + Load world, my_pickled_vars = pickle.load(open(fn, 'rb')) myworld = world._pickle_finalize() my_vars=box2d.pickle_fix(myworld, my_pickled_vars, 'load') For an actual implementation of pickling, see the testbed (main test and test_pickle). """ if func=='save': fix_function=_pickle_fix_value_save elif func=='load': fix_function=_pickle_fix_value_load else: raise ValueError('Expected func in ("save", "load")') if not lists: # these lists are all created dynamically, so do this once lists=[world.bodyList, world.jointList, world.controllerList] if isinstance(var, (list, tuple)): # Create a new list/tuple and fix each item new_list=[pickle_fix(world, value, func, lists) for value in var] if isinstance(var, tuple): # If it was originally a tuple, make this new list a tuple new_list=tuple(new_list) return new_list elif isinstance(var, dict): if func=='load' and 'pickle_type' in var: # Loading a dictionary placeholder for an object return fix_function(lists, var) # Create a new dictionary and fix each item new_dict={} for var, value in list(var.items()): new_dict[var]=pickle_fix(world, value, func, lists) return new_dict else: # Not a dictionary/list, so it is probably just a normal value. # Fix and return it. ret= fix_function(lists, var) return ret # -- unpicklable object -- def no_pickle(self): raise b2PickleError('Cannot pickle this object. Pickle the typecasted object: object.getAsType()') # -- generic get and set state -- def _generic_setstate(self, dict): """ Takes each variable=value pair in the dictionary and sets the attributes based on them """ self.__init__() for key, value in dict.items(): setattr(self, key, value) def _generic_getstate(self, additional_ignore=[]): """ Returns a dictionary representation of self, with dict(var=value [, ...]) additional_ignore can be specified to ignore certain properties. """ ignore_properties = ['thisown', 'this', 'next', 'prev', 'world', 'coreVertices', 'normals'] if additional_ignore: ignore_properties += additional_ignore vars = [v for v in dir(self.__class__) if isinstance(getattr(self.__class__, v), property) and v not in ignore_properties] return dict((var, getattr(self, var)) for var in vars) # -- factory output -- (i.e., b2Body, def _pickle_factory_set(self, data): """ The factory output cannot be created just yet, so store the necessary information to create it later. """ self.__pickle_data__ = data # -- factory output finalizing (loading) def _pickle_finalize(self, world=None, body=None): """ Finalize one of the outputs that we previously set as a dictionary. """ if not hasattr(self, '__pickle_data__'): raise b2PickleError("Invalid object passed to _pickle_finalize") # At this point, 'self' is invalid on the SWIG-end of things. # __init__ has not been called, so it only exists on the Python-end. # The previously saved-data data = self.__pickle_data__ # These types are what are passed in: # create_function output input pairs = [ (lambda w,b,v: w.CreateBody(v) , b2Body , b2BodyDef), (lambda w,b,v: b.CreateShape(v), b2PolygonShape, b2PolygonDef), (lambda w,b,v: b.CreateShape(v), b2CircleShape , b2CircleDef), (lambda w,b,v: b.CreateShape(v), b2EdgeChainDef, b2EdgeChainDef), ] createfcn = None # Create a new instance of the definition so that it may re-create # the object. for fcn, output, input in pairs: if isinstance(self, output): self = eval(input()) createfcn=fcn break if not createfcn: raise b2PickleError("Invalid object passed to _pickle_finalize") # A few things exist that cannot be set in the definition and can only # be set after the object is created. Check for these and then set them # after if necessary. do_after_classes=(b2Body, b2Shape, list) do_after_props =['linearVelocity', 'angularVelocity', 'isSleeping'] finalize_after = [] if isinstance(self, (b2PolygonDef, b2EdgeChainDef)): # Polygon/edge shape. Set their vertices first, as normally they would # be put in the 'do after' section self.vertices = data['vertices'] del data['vertices'] for var in data: value = data[var] if isinstance(value, do_after_classes) or var in do_after_props: # Set these after creation finalize_after.append( (var, value) ) elif hasattr(self, var): setattr(self, var, value) # Create the actual object (not just the definition) self = createfcn(world, body, self) # If we just created a body, set that for the upcoming recursion. # Finalizing the shape will require that this be set. if isinstance(self, b2Body): body = self for var, value in finalize_after: if var == 'shapeList': # A shapelist is a special case, do it separately _pickle_finalize_shapelist(world, body, value) elif var == 'isSleeping': # Sleeping is only modifiable by functions, and as such is a special case if value: self.PutToSleep() else: self.WakeUp() elif hasattr(self, var): # The attribute exists, so set it. if hasattr(value, '_pickle_finalize'): # But first finalize it if necessary. value=_pickle_finalize(value,world,body) setattr(self, var, value) return self # -- custom handlers -- def _pickle_finalize_controller(data, world): """ Finalize a controller. It's mostly standard, just requires a custom bodyList. """ defn = globals()["b2%sControllerDef" % data['_type']] () bodyList = world.bodyList for var in data: value = data[var] if hasattr(defn, var): setattr(defn, var, value) # Create the controller controller = world.CreateController(defn) # And now add the bodies to it for body in data['bodyList']: try: real_body = bodyList[ int(body) ] except: raise b2PickleError('World not initialized properly; unable to create controller') controller.AddBody(real_body) return controller def _pickle_finalize_joint(data, world): """ Finalize a joint. The bodies and joints need to be retrieved from the world list in order to make the joint. """ defn = globals()["b2%sJointDef" % data['_type']] () body_names = ['body1' , 'body2' ] joint_names = ['joint1', 'joint2'] bodyList = world.bodyList jointList = world.jointList for var in data: value = data[var] if var=='localXAxis1': var = 'localAxis1' # single rename necessary if not hasattr(defn, var): continue if var in body_names: # Set the body based on the global body list try: value = bodyList[ int(value) ] except: raise b2PickleError('World not initialized properly; unable to create joint') elif var in joint_names: # Set the joint based on the global joint list try: value = jointList[ int(value) ] except: raise b2PickleError('World not initialized properly; unable to create joint') # Set the value setattr(defn, var, value) return world.CreateJoint(defn) def _pickle_finalize_shapelist(world, body, shapelist): """ Finalize the shape list for a body. Only reason this has to be implemented separately is because of the way edge chains are implemented. """ for s in shapelist: if isinstance(s, dict): # Special case, an edge shape. pickled as a # dictionary. Create a fake definition and finalize it. temp=b2EdgeChainDef() temp.__pickle_data__=s _pickle_finalize(temp, world, body) else: s._pickle_finalize(world, body) def _pickle_finalize_world(self): """ Finalize a b2World. """ if not hasattr(self, '__pickle_data__'): raise b2PickleError('Finalizing a world that was not loaded?') data = self.__pickle_data__ # Create the world. Only 3 parameters to deal with. world = b2World(data['worldAABB'], data['gravity'], data['doSleep']) # First, deal with the ground body. It cannot be taken care of as a # normal body since we do not create it; the constructor of the world # on the C++-side creates it. gb_data = data['groundBody'].__pickle_data__ # Finalize its shapelist _pickle_finalize_shapelist(world, world.groundBody, gb_data['shapeList']) # And then go through each variable, setting the properties for var in list(gb_data.keys()): value = gb_data[var] if isinstance(value, (b2Shape)) or var=='shapeList': pass elif hasattr(world.groundBody, var): try: setattr(world.groundBody, var, value) except AttributeError: pass # Finalize each body for body in data['bodyList']: body._pickle_finalize(world) # Finalize each joint for joint in data['jointList']: _pickle_finalize_joint(joint, world) # Finalize each controller for controller in data['controllerList']: _pickle_finalize_controller(controller, world) # And that is it. :) return world def _pickle_body_getstate(self): """ Everything is essentially generic_getstate, except for edge shape handling. TODO: I can see a possible issue in this if joints are used on an edge shape or a body with edge shapes and other shapes. The shape list order could be improperly recreated. We'll see if anything happens... """ def get_edge_vertices_and_shapes(shape): """ Determine whether or not the edge is a loop. Also, return each shape that this passes through. Then return the vertices. Returns is_loop, shapes, vertices """ vertices = [] shapes = [] edge = shape while edge: shapes.append(edge) vertices.append( edge.vertex1 ) last=edge.vertex2 # Go to the next edge edge=edge.next if edge==shape: # A loop return True, shapes, vertices # Not a loop vertices.append( last ) return False, shapes, vertices # Get all the basic attributes except for shapeList ret = _generic_getstate(self, ['shapeList']) # Now check each shape in the list ret['shapeList']=[] handled_edges = [] for shape in self.shapeList: if isinstance(shape, b2EdgeShape): if shape in handled_edges: # This edge was already added from another one # because they were linked together. continue is_loop, shapes, vertices=get_edge_vertices_and_shapes(shape) handled_edges.extend(shapes) # Create a dictionary for this edge shape # (to be finalized in _pickle_finalize_shapelist when loaded) shape_info = _generic_getstate(shape, ['vertices','length','coreVertex1','coreVertex2']) shape_info['isALoop'] =is_loop shape_info['vertices']=vertices ret['shapeList'].append(shape_info) else: # Regular shapes need no extra processing ret['shapeList'].append(shape) return ret def _pickle_get_b2world(self): """ Get the state of the world. """ # The basic properties first vars = ['worldAABB', 'gravity', 'doSleep', 'groundBody'] data=dict((var, getattr(self, var)) for var in vars) # Now the body list (excepting the ground body) data['bodyList']=self.bodyList[1:] # Add all joints, ensuring to downcast to the appropriate type jointList = [] for joint in self.jointList: joint=joint.getAsType() jointList.append( joint.__getstate__(self) ) data['jointList']=jointList # Add all controllers, ensuring to downcast to the appropriate type controllerList = [] for controller in self.controllerList: controller=controller.getAsType() controllerList.append( controller.__getstate__(self) ) data['controllerList']=controllerList return data def _pickle_get_controller(self, world=None): """ Get the state of a controller """ if not world: raise b2PickleError("Controllers can't be saved without the world itself") ignore_prop =['thisown', 'this', 'bodyList'] defn = globals()[ "%sDef" % self.__class__.__name__ ] # Take the available variables in the _definition_ # and then create a dictionary vars = [v for v in dir(defn) if isinstance(getattr(defn, v), property) and v not in ignore_prop] ret=dict((var, getattr(self, var)) for var in vars) # Set the type, so we know how to recreate it ret['_type'] = self.typeName() # Then use indices into the world body list to store # the bodies controlled by this controller main_bodyList = world.bodyList ctrl_bodyList = self.bodyList ret['bodyList']=[main_bodyList.index(body) for body in ctrl_bodyList] return ret def _pickle_get_joint(self, world=None): """ Get the state of a joint. """ if not world: raise b2PickleError("Joints can't be saved without the world itself") # Take the available variables in the _definition_ # and then create a dictionary ignore_prop =['thisown', 'this', 'world', 'type'] defn = globals()[ "%sDef" % self.__class__.__name__ ] vars = [v for v in dir(defn) if isinstance(getattr(defn, v), property) and v not in ignore_prop] # A single rename is necessary. If localAxis1 (definition) exists, # rename it to localXAxis1 (joint) if 'localAxis1' in vars: # prismatic, line joints vars.remove('localAxis1') vars.append('localXAxis1') ret=dict((var, getattr(self, var)) for var in vars) ret['_type'] = self.typeName() # Recreate the body/joint lists. bodyList = world.bodyList jointList= world.jointList for key, value in ret.items(): if isinstance(value, b2Body): ret[key]=bodyList.index(value) elif isinstance(value, b2Joint): ret[key]=jointList.index(value) return ret %} # These were originally set programmatically, which is perhaps cleaner, # but this will set every class up properly without any unnecessary code # execution %extend b2World { %pythoncode %{ __getstate__=_pickle_get_b2world __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_world %} } %extend b2PrismaticJoint { %pythoncode %{ __getstate__=_pickle_get_joint __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_joint %} } %extend b2ContactID { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ShapeDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2GravityController { %pythoncode %{ __getstate__=_pickle_get_controller __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_controller %} } %extend b2LineJointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Body { %pythoncode %{ __getstate__=_pickle_body_getstate __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize %} } %extend b2TensorDampingController { %pythoncode %{ __getstate__=_pickle_get_controller __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_controller %} } %extend b2ManifoldPoint { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Color { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2BodyDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Version { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Joint { %pythoncode %{ __getstate__=no_pickle __setstate__=_generic_setstate %} } %extend b2JointEdge { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactListener { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2StackEntry { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactManager { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Bound { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Segment { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2DebugDraw { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ConstantForceControllerDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Pair { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2RevoluteJoint { %pythoncode %{ __getstate__=_pickle_get_joint __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_joint %} } %extend b2BuoyancyController { %pythoncode %{ __getstate__=_pickle_get_controller __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_controller %} } %extend b2EdgeShape { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize %} } %extend b2PolygonDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2XForm { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2DistanceJoint { %pythoncode %{ __getstate__=_pickle_get_joint __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_joint %} } %extend b2Contact { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2EdgeChainDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Vec2 { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Vec3 { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2BoundaryListener { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2GravityControllerDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactFilter { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ConstantForceController { %pythoncode %{ __getstate__=_pickle_get_controller __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_controller %} } %extend b2PairCallback { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ConstantAccelControllerDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2MassData { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2BuoyancyControllerDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2AABB { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Mat22 { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactID_features { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactRegister { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Sweep { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Controller { %pythoncode %{ __getstate__=no_pickle __setstate__=_generic_setstate %} } %extend b2PulleyJoint { %pythoncode %{ __getstate__=_pickle_get_joint __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_joint %} } %extend b2BufferedPair { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2JointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2DestructionListener { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2CircleDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ControllerEdge { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2PolygonShape { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize %} } %extend b2Manifold { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2GearJoint { %pythoncode %{ __getstate__=_pickle_get_joint __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_joint %} } %extend b2BlockAllocator { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2FilterData { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2RevoluteJointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2MouseJointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2TensorDampingControllerDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Mat33 { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactPoint { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2OBB { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ControllerDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2TimeStep { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2PairManager { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2PulleyJointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactEdge { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2DistanceJointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ContactResult { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2ConstantAccelController { %pythoncode %{ __getstate__=_pickle_get_controller __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_controller %} } %extend b2StackAllocator { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2MouseJoint { %pythoncode %{ __getstate__=_pickle_get_joint __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_joint %} } %extend b2Proxy { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2BroadPhase { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2PrismaticJointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2CircleShape { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize %} } %extend b2LineJoint { %pythoncode %{ __getstate__=_pickle_get_joint __setstate__=_pickle_factory_set _pickle_finalize=_pickle_finalize_joint %} } %extend b2GearJointDef { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Jacobian { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2NullContact { %pythoncode %{ __getstate__=_generic_getstate __setstate__=_generic_setstate %} } %extend b2Shape { %pythoncode %{ __getstate__=no_pickle __setstate__=_generic_setstate %} } python-box2d-2.0.2+svn20100109.244/Box2D/Common/0000755000000000000000000000000011414467242016650 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Common/b2Settings.cpp0000644000000000000000000000267311064106301021373 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Settings.h" #include b2Version b2_version = {2, 0, 2}; int32 b2_byteCount = 0; // Memory allocators. Modify these to use your own allocator. void* b2Alloc(int32 size) { size += 4; b2_byteCount += size; char* bytes = (char*)malloc(size); *(int32*)bytes = size; return bytes + 4; } void b2Free(void* mem) { if (mem == NULL) { return; } char* bytes = (char*)mem; bytes -= 4; int32 size = *(int32*)bytes; b2Assert(b2_byteCount >= size); b2_byteCount -= size; free(bytes); } python-box2d-2.0.2+svn20100109.244/Box2D/Common/b2Settings.h0000644000000000000000000001427411130023047021037 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_SETTINGS_H #define B2_SETTINGS_H #include #include #ifdef MSVC #define B2_NOT_USED(x) x #else #define B2_NOT_USED(x) #endif #ifdef USE_ASSERTIONS #include class b2AssertException {}; #define b2Assert(A) if (!(A)) { PyErr_SetString(PyExc_AssertionError, #A); throw b2AssertException(); } #else #define b2Assert(A) assert(A) #endif // need to include NDS jtypes.h instead of // usual typedefs because NDS jtypes defines // them slightly differently, oh well. #ifdef TARGET_IS_NDS #include "jtypes.h" #else typedef signed char int8; typedef signed short int16; typedef signed int int32; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; #endif #ifdef TARGET_FLOAT32_IS_FIXED #include "Fixed.h" typedef Fixed float32; #define B2_FLT_MAX FIXED_MAX #define B2_FLT_EPSILON FIXED_EPSILON #define B2FORCE_SCALE(x) ((x)<<7) #define B2FORCE_INV_SCALE(x) ((x)>>7) #else typedef float float32; #define B2_FLT_MAX FLT_MAX #define B2_FLT_EPSILON FLT_EPSILON #define B2FORCE_SCALE(x) (x) #define B2FORCE_INV_SCALE(x) (x) #endif const float32 b2_pi = 3.14159265359f; /// @file /// Global tuning constants based on meters-kilograms-seconds (MKS) units. /// // Collision const int32 b2_maxManifoldPoints = 2; const int32 b2_maxPolygonVertices = 16; const int32 b2_maxProxies = 1024; // this must be a power of two const int32 b2_maxPairs = 8 * b2_maxProxies; // this must be a power of two // Dynamics /// A small length used as a collision and constraint tolerance. Usually it is /// chosen to be numerically significant, but visually insignificant. const float32 b2_linearSlop = 0.005f; // 0.5 cm /// A small angle used as a collision and constraint tolerance. Usually it is /// chosen to be numerically significant, but visually insignificant. const float32 b2_angularSlop = 2.0f / 180.0f * b2_pi; // 2 degrees /// Continuous collision detection (CCD) works with core, shrunken shapes. This is the /// amount by which shapes are automatically shrunk to work with CCD. This must be /// larger than b2_linearSlop. const float32 b2_toiSlop = 8.0f * b2_linearSlop; /// Maximum number of contacts to be handled to solve a TOI island. const int32 b2_maxTOIContactsPerIsland = 32; /// Maximum number of joints to be handled to solve a TOI island. const int32 b2_maxTOIJointsPerIsland = 32; /// A velocity threshold for elastic collisions. Any collision with a relative linear /// velocity below this threshold will be treated as inelastic. const float32 b2_velocityThreshold = 1.0f; // 1 m/s /// The maximum linear position correction used when solving constraints. This helps to /// prevent overshoot. const float32 b2_maxLinearCorrection = 0.2f; // 20 cm /// The maximum angular position correction used when solving constraints. This helps to /// prevent overshoot. const float32 b2_maxAngularCorrection = 8.0f / 180.0f * b2_pi; // 8 degrees /// The maximum linear velocity of a body. This limit is very large and is used /// to prevent numerical problems. You shouldn't need to adjust this. #ifdef TARGET_FLOAT32_IS_FIXED const float32 b2_maxLinearVelocity = 100.0f; #else const float32 b2_maxLinearVelocity = 200.0f; const float32 b2_maxLinearVelocitySquared = b2_maxLinearVelocity * b2_maxLinearVelocity; #endif /// The maximum angular velocity of a body. This limit is very large and is used /// to prevent numerical problems. You shouldn't need to adjust this. const float32 b2_maxAngularVelocity = 250.0f; #ifndef TARGET_FLOAT32_IS_FIXED const float32 b2_maxAngularVelocitySquared = b2_maxAngularVelocity * b2_maxAngularVelocity; #endif /// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so /// that overlap is removed in one time step. However using values close to 1 often lead /// to overshoot. const float32 b2_contactBaumgarte = 0.2f; // Sleep /// The time that a body must be still before it will go to sleep. const float32 b2_timeToSleep = 0.5f; // half a second /// A body cannot sleep if its linear velocity is above this tolerance. const float32 b2_linearSleepTolerance = 0.01f; // 1 cm/s /// A body cannot sleep if its angular velocity is above this tolerance. const float32 b2_angularSleepTolerance = 2.0f / 180.0f; // 2 degrees/s // Memory Allocation /// The current number of bytes allocated through b2Alloc. extern int32 b2_byteCount; /// Implement this function to use your own memory allocator. void* b2Alloc(int32 size); /// If you implement b2Alloc, you should also implement this function. void b2Free(void* mem); /// Version numbering scheme. /// See http://en.wikipedia.org/wiki/Software_versioning struct b2Version { int32 major; ///< significant changes int32 minor; ///< incremental changes int32 revision; ///< bug fixes }; /// Current version. extern b2Version b2_version; /// Friction mixing law. Feel free to customize this. inline float32 b2MixFriction(float32 friction1, float32 friction2) { return sqrtf(friction1 * friction2); } /// Restitution mixing law. Feel free to customize this. inline float32 b2MixRestitution(float32 restitution1, float32 restitution2) { return restitution1 > restitution2 ? restitution1 : restitution2; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Common/b2Math.h0000644000000000000000000003756211151025342020140 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_MATH_H #define B2_MATH_H #include "b2Settings.h" #ifdef TARGET_OS_IPHONE #include "math.h" #else #include #endif #include #include #include #ifdef TARGET_FLOAT32_IS_FIXED inline Fixed b2Min(const Fixed& a, const Fixed& b) { return a < b ? a : b; } inline Fixed b2Max(const Fixed& a, const Fixed& b) { return a > b ? a : b; } inline Fixed b2Clamp(Fixed a, Fixed low, Fixed high) { return b2Max(low, b2Min(a, high)); } inline bool b2IsValid(Fixed x) { B2_NOT_USED(x); return true; } #define b2Sqrt(x) sqrt(x) #define b2Atan2(y, x) atan2(y, x) #else /// This function is used to ensure that a floating point number is /// not a NaN or infinity. inline bool b2IsValid(float32 x) { #ifdef _MSC_VER return _finite(x) != 0; #else #ifdef TARGET_OS_IPHONE return isfinite(x); #else return finite(x) != 0; #endif #endif } /// This is a approximate yet fast inverse square-root. inline float32 b2InvSqrt(float32 x) { union { float32 x; int32 i; } convert; convert.x = x; float32 xhalf = 0.5f * x; convert.i = 0x5f3759df - (convert.i >> 1); x = convert.x; x = x * (1.5f - xhalf * x * x); return x; } #define b2Sqrt(x) sqrtf(x) #define b2Atan2(y, x) atan2f(y, x) #endif inline float32 b2Abs(float32 a) { return a > 0.0f ? a : -a; } /// A 2D column vector. struct b2Vec2 { /// Default constructor does nothing (for performance). b2Vec2() : x(0.0f), y(0.0f) {} /// Construct using coordinates. b2Vec2(float32 x, float32 y) : x(x), y(y) {} /// Set this vector to all zeros. void SetZero() { x = 0.0f; y = 0.0f; } /// Set this vector to some specified coordinates. void Set(float32 x_, float32 y_) { x = x_; y = y_; } /// Negate this vector. b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; } /// Add a vector to this vector. void operator += (const b2Vec2& v) { x += v.x; y += v.y; } /// Subtract a vector from this vector. void operator -= (const b2Vec2& v) { x -= v.x; y -= v.y; } /// Multiply this vector by a scalar. void operator *= (float32 a) { x *= a; y *= a; } /// Get the length of this vector (the norm). float32 Length() const { #ifdef TARGET_FLOAT32_IS_FIXED float est = b2Abs(x) + b2Abs(y); if(est == 0.0f) { return 0.0; } else if(est < 0.1) { return (1.0/256.0) * b2Vec2(x<<8, y<<8).Length(); } else if(est < 180.0f) { return b2Sqrt(x * x + y * y); } else { return 256.0 * (b2Vec2(x>>8, y>>8).Length()); } #else return b2Sqrt(x * x + y * y); #endif } /// Get the length squared. For performance, use this instead of /// b2Vec2::Length (if possible). float32 LengthSquared() const { return x * x + y * y; } /// Convert this vector into a unit vector. Returns the length. #ifdef TARGET_FLOAT32_IS_FIXED float32 Normalize() { float32 length = Length(); if (length < B2_FLT_EPSILON) { return 0.0f; } #ifdef NORMALIZE_BY_INVERT_MULTIPLY if (length < (1.0/16.0)) { x = x << 4; y = y << 4; return (1.0/16.0)*Normalize(); } else if(length > 16.0) { x = x >> 4; y = y >> 4; return 16.0*Normalize(); } float32 invLength = 1.0f / length; x *= invLength; y *= invLength; #else x /= length; y /= length; #endif return length; } #else float32 Normalize() { float32 length = Length(); if (length < B2_FLT_EPSILON) { return 0.0f; } float32 invLength = 1.0f / length; x *= invLength; y *= invLength; return length; } #endif /// Does this vector contain finite coordinates? bool IsValid() const { return b2IsValid(x) && b2IsValid(y); } float32 x, y; }; /// A 2D column vector with 3 elements. struct b2Vec3 { /// Default constructor does nothing (for performance). b2Vec3() {} /// Construct using coordinates. b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {} /// Set this vector to all zeros. void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; } /// Set this vector to some specified coordinates. void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; } /// Negate this vector. b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; } /// Add a vector to this vector. void operator += (const b2Vec3& v) { x += v.x; y += v.y; z += v.z; } /// Subtract a vector from this vector. void operator -= (const b2Vec3& v) { x -= v.x; y -= v.y; z -= v.z; } /// Multiply this vector by a scalar. void operator *= (float32 s) { x *= s; y *= s; z *= s; } float32 x, y, z; }; /// A 2-by-2 matrix. Stored in column-major order. struct b2Mat22 { /// The default constructor does nothing (for performance). b2Mat22() {} /// Construct this matrix using columns. b2Mat22(const b2Vec2& c1, const b2Vec2& c2) { col1 = c1; col2 = c2; } /// Construct this matrix using scalars. b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22) { col1.x = a11; col1.y = a21; col2.x = a12; col2.y = a22; } /// Construct this matrix using an angle. This matrix becomes /// an orthonormal rotation matrix. explicit b2Mat22(float32 angle) { // TODO_ERIN compute sin+cos together. float32 c = cosf(angle), s = sinf(angle); col1.x = c; col2.x = -s; col1.y = s; col2.y = c; } /// Initialize this matrix using columns. void Set(const b2Vec2& c1, const b2Vec2& c2) { col1 = c1; col2 = c2; } /// Initialize this matrix using an angle. This matrix becomes /// an orthonormal rotation matrix. void Set(float32 angle) { float32 c = cosf(angle), s = sinf(angle); col1.x = c; col2.x = -s; col1.y = s; col2.y = c; } /// Set this to the identity matrix. void SetIdentity() { col1.x = 1.0f; col2.x = 0.0f; col1.y = 0.0f; col2.y = 1.0f; } /// Set this matrix to all zeros. void SetZero() { col1.x = 0.0f; col2.x = 0.0f; col1.y = 0.0f; col2.y = 0.0f; } /// Extract the angle from this matrix (assumed to be /// a rotation matrix). float32 GetAngle() const { return b2Atan2(col1.y, col1.x); } #ifdef TARGET_FLOAT32_IS_FIXED /// Compute the inverse of this matrix, such that inv(A) * A = identity. b2Mat22 GetInverse() const { float32 a = col1.x, b = col2.x, c = col1.y, d = col2.y; float32 det = a * d - b * c; b2Mat22 B; int n = 0; if(b2Abs(det) <= (B2_FLT_EPSILON<<8)) { n = 3; a = a<= 16.0)? 4 : 0; b2Assert(det != 0.0f); det = float32(1<> n; B.col2.x = (-det * b) >> n; B.col1.y = (-det * c) >> n; B.col2.y = ( det * a) >> n; } return B; } // Solve A * x = b b2Vec2 Solve(const b2Vec2& b) const { float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y; float32 det = a11 * a22 - a12 * a21; int n = 0; b2Vec2 x; if(b2Abs(det) <= (B2_FLT_EPSILON<<8)) { n = 3; a11 = col1.x<= 16.0) ? 4 : 0; b2Assert(det != 0.0f); det = float32(1<> n; x.y = (det * (a11 * b.y - a21 * b.x)) >> n; } return x; } #else b2Mat22 GetInverse() const { float32 a = col1.x, b = col2.x, c = col1.y, d = col2.y; b2Mat22 B; float32 det = a * d - b * c; b2Assert(det != 0.0f); det = float32(1.0f) / det; B.col1.x = det * d; B.col2.x = -det * b; B.col1.y = -det * c; B.col2.y = det * a; return B; } /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec2 Solve(const b2Vec2& b) const { float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y; float32 det = a11 * a22 - a12 * a21; b2Assert(det != 0.0f); det = 1.0f / det; b2Vec2 x; x.x = det * (a22 * b.x - a12 * b.y); x.y = det * (a11 * b.y - a21 * b.x); return x; } #endif b2Vec2 col1, col2; }; /// A 3-by-3 matrix. Stored in column-major order. struct b2Mat33 { /// The default constructor does nothing (for performance). b2Mat33() {} /// Construct this matrix using columns. b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3) { col1 = c1; col2 = c2; col3 = c3; } /// Set this matrix to all zeros. void SetZero() { col1.SetZero(); col2.SetZero(); col3.SetZero(); } /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec3 Solve33(const b2Vec3& b) const; /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. Solve only the upper /// 2-by-2 matrix equation. b2Vec2 Solve22(const b2Vec2& b) const; b2Vec3 col1, col2, col3; }; /// A transform contains translation and rotation. It is used to represent /// the position and orientation of rigid frames. struct b2XForm { /// The default constructor does nothing (for performance). b2XForm() {} /// Initialize using a position vector and a rotation matrix. b2XForm(const b2Vec2& position, const b2Mat22& R) : position(position), R(R) {} /// Set this to the identity transform. void SetIdentity() { position.SetZero(); R.SetIdentity(); } b2Vec2 position; b2Mat22 R; }; /// This describes the motion of a body/shape for TOI computation. /// Shapes are defined with respect to the body origin, which may /// no coincide with the center of mass. However, to support dynamics /// we must interpolate the center of mass position. struct b2Sweep { /// Get the interpolated transform at a specific time. /// @param t the normalized time in [0,1]. void GetXForm(b2XForm* xf, float32 t) const; /// Advance the sweep forward, yielding a new initial state. /// @param t the new initial time. void Advance(float32 t); b2Vec2 localCenter; ///< local center of mass position b2Vec2 c0, c; ///< center world positions float32 a0, a; ///< world angles float32 t0; ///< time interval = [t0,1], where t0 is in [0,1] }; extern const b2Vec2 b2Vec2_zero; extern const b2Mat22 b2Mat22_identity; extern const b2XForm b2XForm_identity; /// Peform the dot product on two vectors. inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b) { return a.x * b.x + a.y * b.y; } /// Perform the cross product on two vectors. In 2D this produces a scalar. inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b) { return a.x * b.y - a.y * b.x; } /// Perform the cross product on a vector and a scalar. In 2D this produces /// a vector. inline b2Vec2 b2Cross(const b2Vec2& a, float32 s) { return b2Vec2(s * a.y, -s * a.x); } /// Perform the cross product on a scalar and a vector. In 2D this produces /// a vector. inline b2Vec2 b2Cross(float32 s, const b2Vec2& a) { return b2Vec2(-s * a.y, s * a.x); } /// Multiply a matrix times a vector. If a rotation matrix is provided, /// then this transforms the vector from one frame to another. inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v) { return b2Vec2(A.col1.x * v.x + A.col2.x * v.y, A.col1.y * v.x + A.col2.y * v.y); } /// Multiply a matrix transpose times a vector. If a rotation matrix is provided, /// then this transforms the vector from one frame to another (inverse transform). inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v) { return b2Vec2(b2Dot(v, A.col1), b2Dot(v, A.col2)); } /// Add two vectors component-wise. inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b) { return b2Vec2(a.x + b.x, a.y + b.y); } /// Subtract two vectors component-wise. inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b) { return b2Vec2(a.x - b.x, a.y - b.y); } inline b2Vec2 operator * (float32 s, const b2Vec2& a) { return b2Vec2(s * a.x, s * a.y); } inline bool operator == (const b2Vec2& a, const b2Vec2& b) { return a.x == b.x && a.y == b.y; } inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b) { b2Vec2 c = a - b; return c.Length(); } inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b) { b2Vec2 c = a - b; return b2Dot(c, c); } inline b2Vec3 operator * (float32 s, const b2Vec3& a) { return b2Vec3(s * a.x, s * a.y, s * a.z); } /// Add two vectors component-wise. inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b) { return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z); } /// Subtract two vectors component-wise. inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b) { return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z); } /// Perform the dot product on two vectors. inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } /// Perform the cross product on two vectors. inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b) { return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B) { return b2Mat22(A.col1 + B.col1, A.col2 + B.col2); } // A * B inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B) { return b2Mat22(b2Mul(A, B.col1), b2Mul(A, B.col2)); } // A^T * B inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B) { b2Vec2 c1(b2Dot(A.col1, B.col1), b2Dot(A.col2, B.col1)); b2Vec2 c2(b2Dot(A.col1, B.col2), b2Dot(A.col2, B.col2)); return b2Mat22(c1, c2); } /// Multiply a matrix times a vector. inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v) { return v.x * A.col1 + v.y * A.col2 + v.z * A.col3; } inline b2Vec2 b2Mul(const b2XForm& T, const b2Vec2& v) { return T.position + b2Mul(T.R, v); } inline b2Vec2 b2MulT(const b2XForm& T, const b2Vec2& v) { return b2MulT(T.R, v - T.position); } inline b2Vec2 b2Abs(const b2Vec2& a) { return b2Vec2(b2Abs(a.x), b2Abs(a.y)); } inline b2Mat22 b2Abs(const b2Mat22& A) { return b2Mat22(b2Abs(A.col1), b2Abs(A.col2)); } template inline T b2Min(T a, T b) { return a < b ? a : b; } inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b) { return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y)); } template inline T b2Max(T a, T b) { return a > b ? a : b; } inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b) { return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y)); } template inline T b2Clamp(T a, T low, T high) { return b2Max(low, b2Min(a, high)); } inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high) { return b2Max(low, b2Min(a, high)); } template inline void b2Swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } /// "Next Largest Power of 2 /// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm /// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with /// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next /// largest power of 2. For a 32-bit value:" inline uint32 b2NextPowerOfTwo(uint32 x) { x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return x + 1; } inline bool b2IsPowerOfTwo(uint32 x) { bool result = x > 0 && (x & (x - 1)) == 0; return result; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Common/Fixed.h0000644000000000000000000004421111064106301020045 0ustar rootroot/* Copyright (c) 2006 Henry Strickland & Ryan Seto 2007-2008 Tobias Weyand (modifications and extensions) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. (* http://www.opensource.org/licenses/mit-license.php *) */ #ifndef _FIXED_H_ #define _FIXED_H_ #include #ifdef TARGET_IS_NDS #include "nds.h" #endif #define FIXED_BP 16 #define FIXED_MAX ((1<<(32-FIXED_BP-1))-1) #define FIXED_MIN (-(1<<(32-FIXED_BP-1))) #define FIXED_EPSILON (Fixed(0.00007f)) #define G_1_DIV_PI 20861 class Fixed { private: int g; // the guts const static int BP= FIXED_BP; // how many low bits are right of Binary Point const static int BP2= BP*2; // how many low bits are right of Binary Point const static int BPhalf= BP/2; // how many low bits are right of Binary Point double STEP(); // smallest step we can represent // for private construction via guts enum FixedRaw { RAW }; Fixed(FixedRaw, int guts); public: Fixed(); Fixed(const Fixed &a); Fixed(float a); Fixed(double a); Fixed(int a); Fixed(long a); Fixed& operator =(const Fixed a); Fixed& operator =(float a); Fixed& operator =(double a); Fixed& operator =(int a); Fixed& operator =(long a); operator float(); operator double(); operator int(); operator long(); operator unsigned short(); operator float() const; Fixed operator +() const; Fixed operator -() const; Fixed operator +(const Fixed a) const; Fixed operator -(const Fixed a) const; #if 1 // more acurate, using long long Fixed operator *(const Fixed a) const; #else // faster, but with only half as many bits right of binary point Fixed operator *(const Fixed a) const; #endif Fixed operator /(const Fixed a) const; Fixed operator *(unsigned short a) const; Fixed operator *(int a) const; Fixed operator +(float a) const; Fixed operator -(float a) const; Fixed operator *(float a) const; Fixed operator /(float a) const; Fixed operator +(double a) const; Fixed operator -(double a) const; Fixed operator *(double a) const; Fixed operator /(double a) const; Fixed operator >>(int a) const; Fixed operator <<(int a) const; Fixed& operator +=(Fixed a); Fixed& operator -=(Fixed a); Fixed& operator *=(Fixed a); Fixed& operator /=(Fixed a); Fixed& operator +=(int a); Fixed& operator -=(int a); Fixed& operator *=(int a); Fixed& operator /=(int a); Fixed& operator +=(long a); Fixed& operator -=(long a); Fixed& operator *=(long a); Fixed& operator /=(long a); Fixed& operator +=(float a); Fixed& operator -=(float a); Fixed& operator *=(float a); Fixed& operator /=(float a); Fixed& operator +=(double a); Fixed& operator -=(double a); Fixed& operator *=(double a); Fixed& operator /=(double a); bool operator ==(const Fixed a) const; bool operator !=(const Fixed a) const; bool operator <=(const Fixed a) const; bool operator >=(const Fixed a) const; bool operator <(const Fixed a) const; bool operator >(const Fixed a) const; bool operator ==(float a) const; bool operator !=(float a) const; bool operator <=(float a) const; bool operator >=(float a) const; bool operator <(float a) const; bool operator >(float a) const; bool operator ==(double a) const; bool operator !=(double a) const; bool operator <=(double a) const; bool operator >=(double a) const; bool operator <(double a) const; bool operator >(double a) const; bool operator >(int a) const; bool operator <(int a) const; bool operator >=(int a) const; bool operator <=(int a) const; Fixed abs(); Fixed sqrt(); #ifdef TARGET_IS_NDS Fixed cosf(); Fixed sinf(); Fixed tanf(); #endif }; // // Implementation // inline double Fixed::STEP() { return 1.0 / (1<>BP; } inline Fixed::operator long() { return g>>BP; } //#pragma warning(disable: 4244) //HARDWIRE added pragma to prevent VS2005 compilation error inline Fixed::operator unsigned short() { return g>>BP; } inline Fixed::operator float() const { return g / (float)(1<> BP)); } #elif 0 // check for overflow and figure out where. Must specify -rdynamic in linker #include #include #include inline Fixed Fixed::operator *(const Fixed a) const { long long x = ((long long)g * (long long)a.g ); if(x > 0x7fffffffffffLL || x < -0x7fffffffffffLL) { printf("overflow"); void *array[2]; int nSize = backtrace(array, 2); char **symbols = backtrace_symbols(array, nSize); for(int i=0; i>BP)); } #else // faster, but with only half as many bits right of binary point inline Fixed Fixed::operator *(const Fixed a) const { return Fixed(RAW, (g>>BPhalf) * (a.g>>BPhalf) ); } #endif #ifdef TARGET_IS_NDS // Division using the DS's maths coprocessor inline Fixed Fixed::operator /(const Fixed a) const { //printf("%d %d\n", (long long)g << BP, a.g); return Fixed(RAW, int( div64((long long)g << BP, a.g) ) ); } #else inline Fixed Fixed::operator /(const Fixed a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(a.g)) >> BP) ); //return Fixed(RAW, int( (((long long)g << BP) / (long long)(a.g)) ) ); } #endif inline Fixed Fixed::operator *(unsigned short a) const { return operator*(Fixed(a)); } inline Fixed Fixed::operator *(int a) const { return operator*(Fixed(a)); } inline Fixed Fixed::operator +(float a) const { return Fixed(RAW, g + Fixed(a).g); } inline Fixed Fixed::operator -(float a) const { return Fixed(RAW, g - Fixed(a).g); } inline Fixed Fixed::operator *(float a) const { return Fixed(RAW, (g>>BPhalf) * (Fixed(a).g>>BPhalf) ); } //inline Fixed Fixed::operator /(float a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(Fixed(a).g)) >> BP) ); } inline Fixed Fixed::operator /(float a) const { return operator/(Fixed(a)); } inline Fixed Fixed::operator +(double a) const { return Fixed(RAW, g + Fixed(a).g); } inline Fixed Fixed::operator -(double a) const { return Fixed(RAW, g - Fixed(a).g); } inline Fixed Fixed::operator *(double a) const { return Fixed(RAW, (g>>BPhalf) * (Fixed(a).g>>BPhalf) ); } //inline Fixed Fixed::operator /(double a) const { return Fixed(RAW, int( (((long long)g << BP2) / (long long)(Fixed(a).g)) >> BP) ); } inline Fixed Fixed::operator /(double a) const { return operator/(Fixed(a)); } inline Fixed Fixed::operator >>(int a) const { return Fixed(RAW, g >> a); } inline Fixed Fixed::operator <<(int a) const { return Fixed(RAW, g << a); } inline Fixed& Fixed::operator +=(Fixed a) { return *this = *this + a; } inline Fixed& Fixed::operator -=(Fixed a) { return *this = *this - a; } inline Fixed& Fixed::operator *=(Fixed a) { return *this = *this * a; } //inline Fixed& Fixed::operator /=(Fixed a) { return *this = *this / a; } inline Fixed& Fixed::operator /=(Fixed a) { return *this = operator/(a); } inline Fixed& Fixed::operator +=(int a) { return *this = *this + (Fixed)a; } inline Fixed& Fixed::operator -=(int a) { return *this = *this - (Fixed)a; } inline Fixed& Fixed::operator *=(int a) { return *this = *this * (Fixed)a; } //inline Fixed& Fixed::operator /=(int a) { return *this = *this / (Fixed)a; } inline Fixed& Fixed::operator /=(int a) { return *this = operator/((Fixed)a); } inline Fixed& Fixed::operator +=(long a) { return *this = *this + (Fixed)a; } inline Fixed& Fixed::operator -=(long a) { return *this = *this - (Fixed)a; } inline Fixed& Fixed::operator *=(long a) { return *this = *this * (Fixed)a; } //inline Fixed& Fixed::operator /=(long a) { return *this = *this / (Fixed)a; } inline Fixed& Fixed::operator /=(long a) { return *this = operator/((Fixed)a); } inline Fixed& Fixed::operator +=(float a) { return *this = *this + a; } inline Fixed& Fixed::operator -=(float a) { return *this = *this - a; } inline Fixed& Fixed::operator *=(float a) { return *this = *this * a; } //inline Fixed& Fixed::operator /=(float a) { return *this = *this / a; } inline Fixed& Fixed::operator /=(float a) { return *this = operator/(a); } inline Fixed& Fixed::operator +=(double a) { return *this = *this + a; } inline Fixed& Fixed::operator -=(double a) { return *this = *this - a; } inline Fixed& Fixed::operator *=(double a) { return *this = *this * a; } //inline Fixed& Fixed::operator /=(double a) { return *this = *this / a; } inline Fixed& Fixed::operator /=(double a) { return *this = operator/(a); } inline Fixed operator +(int a, const Fixed b) { return Fixed(a)+b; } inline Fixed operator -(int a, const Fixed b) { return Fixed(a)-b; } inline Fixed operator *(int a, const Fixed b) { return Fixed(a)*b; } inline Fixed operator /(int a, const Fixed b) { return Fixed(a)/b; }; inline Fixed operator +(float a, const Fixed b) { return Fixed(a)+b; } inline Fixed operator -(float a, const Fixed b) { return Fixed(a)-b; } inline Fixed operator *(float a, const Fixed b) { return Fixed(a)*b; } inline Fixed operator /(float a, const Fixed b) { return Fixed(a)/b; } inline bool Fixed::operator ==(const Fixed a) const { return g == a.g; } inline bool Fixed::operator !=(const Fixed a) const { return g != a.g; } inline bool Fixed::operator <=(const Fixed a) const { return g <= a.g; } inline bool Fixed::operator >=(const Fixed a) const { return g >= a.g; } inline bool Fixed::operator <(const Fixed a) const { return g < a.g; } inline bool Fixed::operator >(const Fixed a) const { return g > a.g; } inline bool Fixed::operator ==(float a) const { return g == Fixed(a).g; } inline bool Fixed::operator !=(float a) const { return g != Fixed(a).g; } inline bool Fixed::operator <=(float a) const { return g <= Fixed(a).g; } inline bool Fixed::operator >=(float a) const { return g >= Fixed(a).g; } inline bool Fixed::operator <(float a) const { return g < Fixed(a).g; } inline bool Fixed::operator >(float a) const { return g > Fixed(a).g; } inline bool Fixed::operator ==(double a) const { return g == Fixed(a).g; } inline bool Fixed::operator !=(double a) const { return g != Fixed(a).g; } inline bool Fixed::operator <=(double a) const { return g <= Fixed(a).g; } inline bool Fixed::operator >=(double a) const { return g >= Fixed(a).g; } inline bool Fixed::operator <(double a) const { return g < Fixed(a).g; } inline bool Fixed::operator >(double a) const { return g > Fixed(a).g; } inline bool Fixed::operator >(int a) const { return g > Fixed(a).g; } inline bool Fixed::operator <(int a) const { return g < Fixed(a).g; } inline bool Fixed::operator >=(int a) const{ return g >= Fixed(a).g; }; inline bool Fixed::operator <=(int a) const{ return g <= Fixed(a).g; }; inline bool operator ==(float a, const Fixed b) { return Fixed(a) == b; } inline bool operator !=(float a, const Fixed b) { return Fixed(a) != b; } inline bool operator <=(float a, const Fixed b) { return Fixed(a) <= b; } inline bool operator >=(float a, const Fixed b) { return Fixed(a) >= b; } inline bool operator <(float a, const Fixed b) { return Fixed(a) < b; } inline bool operator >(float a, const Fixed b) { return Fixed(a) > b; } inline Fixed operator +(double a, const Fixed b) { return Fixed(a)+b; } inline Fixed operator -(double a, const Fixed b) { return Fixed(a)-b; } inline Fixed operator *(double a, const Fixed b) { return Fixed(a)*b; } inline Fixed operator /(double a, const Fixed b) { return Fixed(a)/b; } inline bool operator ==(double a, const Fixed b) { return Fixed(a) == b; } inline bool operator !=(double a, const Fixed b) { return Fixed(a) != b; } inline bool operator <=(double a, const Fixed b) { return Fixed(a) <= b; } inline bool operator >=(double a, const Fixed b) { return Fixed(a) >= b; } inline bool operator <(double a, const Fixed b) { return Fixed(a) < b; } inline bool operator >(double a, const Fixed b) { return Fixed(a) > b; } inline bool operator ==(int a, const Fixed b) { return Fixed(a) == b; } inline bool operator !=(int a, const Fixed b) { return Fixed(a) != b; } inline bool operator <=(int a, const Fixed b) { return Fixed(a) <= b; } inline bool operator >=(int a, const Fixed b) { return Fixed(a) >= b; } inline bool operator <(int a, const Fixed b) { return Fixed(a) < b; } inline bool operator >(int a, const Fixed b) { return Fixed(a) > b; } inline int& operator +=(int& a, const Fixed b) { a = (Fixed)a + b; return a; } inline int& operator -=(int& a, const Fixed b) { a = (Fixed)a - b; return a; } inline int& operator *=(int& a, const Fixed b) { a = (Fixed)a * b; return a; } inline int& operator /=(int& a, const Fixed b) { a = (Fixed)a / b; return a; } inline long& operator +=(long& a, const Fixed b) { a = (Fixed)a + b; return a; } inline long& operator -=(long& a, const Fixed b) { a = (Fixed)a - b; return a; } inline long& operator *=(long& a, const Fixed b) { a = (Fixed)a * b; return a; } inline long& operator /=(long& a, const Fixed b) { a = (Fixed)a / b; return a; } inline float& operator +=(float& a, const Fixed b) { a = a + b; return a; } inline float& operator -=(float& a, const Fixed b) { a = a - b; return a; } inline float& operator *=(float& a, const Fixed b) { a = a * b; return a; } inline float& operator /=(float& a, const Fixed b) { a = a / b; return a; } inline double& operator +=(double& a, const Fixed b) { a = a + b; return a; } inline double& operator -=(double& a, const Fixed b) { a = a - b; return a; } inline double& operator *=(double& a, const Fixed b) { a = a * b; return a; } inline double& operator /=(double& a, const Fixed b) { a = a / b; return a; } inline Fixed Fixed::abs() { return (g>0) ? Fixed(RAW, g) : Fixed(RAW, -g); } inline Fixed abs(Fixed f) { return f.abs(); } //inline Fixed atan2(Fixed a, Fixed b) { return atan2f((float) a, (float) b); } inline Fixed atan2(Fixed y, Fixed x) { Fixed abs_y = y.abs() + FIXED_EPSILON; // avoid 0/0 Fixed r, angle; if(x >= 0.0f) { r = (x - abs_y) / (x + abs_y); angle = 3.1415926/4.0; } else { r = (x + abs_y) / (abs_y - x); angle = 3.0*3.1415926/4.0; } angle += Fixed(0.1963) * (r * r * r) - Fixed(0.9817) * r; return (y < 0) ? -angle : angle; } #if TARGET_IS_NDS static inline long nds_sqrt64(long long a) { SQRT_CR = SQRT_64; while(SQRT_CR & SQRT_BUSY); SQRT_PARAM64 = a; while(SQRT_CR & SQRT_BUSY); return SQRT_RESULT32; } static inline int32 div6464(int64 num, int64 den) { DIV_CR = DIV_64_64; while(DIV_CR & DIV_BUSY); DIV_NUMERATOR64 = num; DIV_DENOMINATOR64 = den; while(DIV_CR & DIV_BUSY); return (DIV_RESULT32); } inline Fixed Fixed::sqrt() { return Fixed(RAW, nds_sqrt64(((long long)(g))<>= 2 ) { if ( ( left & -m ) > root ) left -= ( root += m ), root += m; root >>= 1; } return Fixed(RAW, root); } #endif inline Fixed sqrt(Fixed a) { return a.sqrt(); } inline Fixed sqrtf(Fixed a) { return a.sqrt(); } #endif #ifdef TARGET_IS_NDS // Use the libnds lookup tables for trigonometry functions inline Fixed Fixed::cosf() { int idx = (((long long)g*(long long)G_1_DIV_PI)>>24)%512; if(idx < 0) idx += 512; return Fixed(RAW, COS_bin[idx] << 4); } inline Fixed cosf(Fixed x) { return x.cosf(); } inline Fixed Fixed::sinf() { int idx = (((long long)g*(long long)G_1_DIV_PI)>>24)%512; if(idx < 0) idx += 512; return Fixed(RAW, SIN_bin[idx] << 4); } inline Fixed sinf(Fixed x) { return x.sinf(); } inline Fixed Fixed::tanf() { int idx = (((long long)g*(long long)G_1_DIV_PI)>>24)%512; if(idx < 0) idx += 512; return Fixed(RAW, TAN_bin[idx] << 4); } inline Fixed tanf(Fixed x) { return x.tanf(); } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Common/b2BlockAllocator.cpp0000644000000000000000000001172711064106301022466 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2BlockAllocator.h" #include #include #include #include int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = { 16, // 0 32, // 1 64, // 2 96, // 3 128, // 4 160, // 5 192, // 6 224, // 7 256, // 8 320, // 9 384, // 10 448, // 11 512, // 12 640, // 13 }; uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1]; bool b2BlockAllocator::s_blockSizeLookupInitialized; struct b2Chunk { int32 blockSize; b2Block* blocks; }; struct b2Block { b2Block* next; }; b2BlockAllocator::b2BlockAllocator() { b2Assert(b2_blockSizes < UCHAR_MAX); m_chunkSpace = b2_chunkArrayIncrement; m_chunkCount = 0; m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); memset(m_freeLists, 0, sizeof(m_freeLists)); if (s_blockSizeLookupInitialized == false) { int32 j = 0; for (int32 i = 1; i <= b2_maxBlockSize; ++i) { b2Assert(j < b2_blockSizes); if (i <= s_blockSizes[j]) { s_blockSizeLookup[i] = (uint8)j; } else { ++j; s_blockSizeLookup[i] = (uint8)j; } } s_blockSizeLookupInitialized = true; } } b2BlockAllocator::~b2BlockAllocator() { for (int32 i = 0; i < m_chunkCount; ++i) { b2Free(m_chunks[i].blocks); } b2Free(m_chunks); } void* b2BlockAllocator::Allocate(int32 size) { if (size == 0) return NULL; b2Assert(0 < size && size <= b2_maxBlockSize); int32 index = s_blockSizeLookup[size]; b2Assert(0 <= index && index < b2_blockSizes); if (m_freeLists[index]) { b2Block* block = m_freeLists[index]; m_freeLists[index] = block->next; return block; } else { if (m_chunkCount == m_chunkSpace) { b2Chunk* oldChunks = m_chunks; m_chunkSpace += b2_chunkArrayIncrement; m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk)); memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk)); memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk)); b2Free(oldChunks); } b2Chunk* chunk = m_chunks + m_chunkCount; chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize); #if defined(_DEBUG) memset(chunk->blocks, 0xcd, b2_chunkSize); #endif int32 blockSize = s_blockSizes[index]; chunk->blockSize = blockSize; int32 blockCount = b2_chunkSize / blockSize; b2Assert(blockCount * blockSize <= b2_chunkSize); for (int32 i = 0; i < blockCount - 1; ++i) { b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i); b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1)); block->next = next; } b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1)); last->next = NULL; m_freeLists[index] = chunk->blocks->next; ++m_chunkCount; return chunk->blocks; } } void b2BlockAllocator::Free(void* p, int32 size) { if (size == 0) { return; } b2Assert(0 < size && size <= b2_maxBlockSize); int32 index = s_blockSizeLookup[size]; b2Assert(0 <= index && index < b2_blockSizes); #ifdef _DEBUG // Verify the memory address and size is valid. int32 blockSize = s_blockSizes[index]; bool found = false; int32 gap = (int32)((int8*)&m_chunks->blocks - (int8*)m_chunks); for (int32 i = 0; i < m_chunkCount; ++i) { b2Chunk* chunk = m_chunks + i; if (chunk->blockSize != blockSize) { b2Assert( (int8*)p + blockSize <= (int8*)chunk->blocks || (int8*)chunk->blocks + b2_chunkSize + gap <= (int8*)p); } else { if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize) { found = true; } } } b2Assert(found); memset(p, 0xfd, blockSize); #endif b2Block* block = (b2Block*)p; block->next = m_freeLists[index]; m_freeLists[index] = block; } void b2BlockAllocator::Clear() { for (int32 i = 0; i < m_chunkCount; ++i) { b2Free(m_chunks[i].blocks); } m_chunkCount = 0; memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk)); memset(m_freeLists, 0, sizeof(m_freeLists)); } python-box2d-2.0.2+svn20100109.244/Box2D/Common/b2BlockAllocator.h0000644000000000000000000000344111064106301022125 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_BLOCK_ALLOCATOR_H #define B2_BLOCK_ALLOCATOR_H #include "b2Settings.h" const int32 b2_chunkSize = 4096; const int32 b2_maxBlockSize = 640; const int32 b2_blockSizes = 14; const int32 b2_chunkArrayIncrement = 128; struct b2Block; struct b2Chunk; // This is a small object allocator used for allocating small // objects that persist for more than one time step. // See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp class b2BlockAllocator { public: b2BlockAllocator(); ~b2BlockAllocator(); void* Allocate(int32 size); void Free(void* p, int32 size); void Clear(); private: b2Chunk* m_chunks; int32 m_chunkCount; int32 m_chunkSpace; b2Block* m_freeLists[b2_blockSizes]; static int32 s_blockSizes[b2_blockSizes]; static uint8 s_blockSizeLookup[b2_maxBlockSize + 1]; static bool s_blockSizeLookupInitialized; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Common/b2StackAllocator.h0000644000000000000000000000327211064106301022142 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_STACK_ALLOCATOR_H #define B2_STACK_ALLOCATOR_H #include "b2Settings.h" const int32 b2_stackSize = 100 * 1024; // 100k const int32 b2_maxStackEntries = 32; struct b2StackEntry { char* data; int32 size; bool usedMalloc; }; // This is a stack allocator used for fast per step allocations. // You must nest allocate/free pairs. The code will assert // if you try to interleave multiple allocate/free pairs. class b2StackAllocator { public: b2StackAllocator(); ~b2StackAllocator(); void* Allocate(int32 size); void Free(void* p); int32 GetMaxAllocation() const; private: char m_data[b2_stackSize]; int32 m_index; int32 m_allocation; int32 m_maxAllocation; b2StackEntry m_entries[b2_maxStackEntries]; int32 m_entryCount; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Common/b2Math.cpp0000644000000000000000000000507311064106301020461 0ustar rootroot/* * Copyright (c) 2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Math.h" const b2Vec2 b2Vec2_zero(0.0f, 0.0f); const b2Mat22 b2Mat22_identity(1.0f, 0.0f, 0.0f, 1.0f); const b2XForm b2XForm_identity(b2Vec2_zero, b2Mat22_identity); /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const { float32 det = b2Dot(col1, b2Cross(col2, col3)); b2Assert(det != 0.0f); det = 1.0f / det; b2Vec3 x; x.x = det * b2Dot(b, b2Cross(col2, col3)); x.y = det * b2Dot(col1, b2Cross(b, col3)); x.z = det * b2Dot(col1, b2Cross(col2, b)); return x; } /// Solve A * x = b, where b is a column vector. This is more efficient /// than computing the inverse in one-shot cases. b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const { float32 a11 = col1.x, a12 = col2.x, a21 = col1.y, a22 = col2.y; float32 det = a11 * a22 - a12 * a21; b2Assert(det != 0.0f); det = 1.0f / det; b2Vec2 x; x.x = det * (a22 * b.x - a12 * b.y); x.y = det * (a11 * b.y - a21 * b.x); return x; } void b2Sweep::GetXForm(b2XForm* xf, float32 t) const { // center = p + R * localCenter if (1.0f - t0 > B2_FLT_EPSILON) { float32 alpha = (t - t0) / (1.0f - t0); xf->position = (1.0f - alpha) * c0 + alpha * c; float32 angle = (1.0f - alpha) * a0 + alpha * a; xf->R.Set(angle); } else { xf->position = c; xf->R.Set(a); } // Shift to origin xf->position -= b2Mul(xf->R, localCenter); } void b2Sweep::Advance(float32 t) { if (t0 < t && 1.0f - t0 > B2_FLT_EPSILON) { float32 alpha = (t - t0) / (1.0f - t0); c0 = (1.0f - alpha) * c0 + alpha * c; a0 = (1.0f - alpha) * a0 + alpha * a; t0 = t; } } python-box2d-2.0.2+svn20100109.244/Box2D/Common/b2StackAllocator.cpp0000644000000000000000000000407511064106301022477 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2StackAllocator.h" #include "b2Math.h" b2StackAllocator::b2StackAllocator() { m_index = 0; m_allocation = 0; m_maxAllocation = 0; m_entryCount = 0; } b2StackAllocator::~b2StackAllocator() { b2Assert(m_index == 0); b2Assert(m_entryCount == 0); } void* b2StackAllocator::Allocate(int32 size) { b2Assert(m_entryCount < b2_maxStackEntries); b2StackEntry* entry = m_entries + m_entryCount; entry->size = size; if (m_index + size > b2_stackSize) { entry->data = (char*)b2Alloc(size); entry->usedMalloc = true; } else { entry->data = m_data + m_index; entry->usedMalloc = false; m_index += size; } m_allocation += size; m_maxAllocation = b2Max(m_maxAllocation, m_allocation); ++m_entryCount; return entry->data; } void b2StackAllocator::Free(void* p) { b2Assert(m_entryCount > 0); b2StackEntry* entry = m_entries + m_entryCount - 1; b2Assert(p == entry->data); if (entry->usedMalloc) { b2Free(p); } else { m_index -= entry->size; } m_allocation -= entry->size; --m_entryCount; p = NULL; } int32 b2StackAllocator::GetMaxAllocation() const { return m_maxAllocation; } python-box2d-2.0.2+svn20100109.244/Box2D/Common/jtypes.h0000644000000000000000000001011711064106301020322 0ustar rootroot/*--------------------------------------------------------------------------------- $Id: jtypes.h,v 1.17 2007/07/18 05:20:45 wntrmute Exp $ jtypes.h -- Common types (and a few useful macros) Copyright (C) 2005 Michael Noland (joat) Jason Rogers (dovoto) Dave Murphy (WinterMute) Chris Double (doublec) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. ---------------------------------------------------------------------------------*/ #ifndef NDS_JTYPES_INCLUDE #define NDS_JTYPES_INCLUDE //--------------------------------------------------------------------------------- #define PACKED __attribute__ ((packed)) #define packed_struct struct PACKED //--------------------------------------------------------------------------------- // libgba compatible section macros //--------------------------------------------------------------------------------- #define ITCM_CODE __attribute__((section(".itcm"), long_call)) #define DTCM_DATA __attribute__((section(".dtcm"))) #define DTCM_BSS __attribute__((section(".sbss"))) #define ALIGN(m) __attribute__((aligned (m))) #define PACKED __attribute__ ((packed)) #define packed_struct struct PACKED //--------------------------------------------------------------------------------- // These are linked to the bin2o macro in the Makefile //--------------------------------------------------------------------------------- #define GETRAW(name) (name) #define GETRAWSIZE(name) ((int)name##_size) #define GETRAWEND(name) ((int)name##_end) #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define BIT(n) (1 << (n)) // define libnds types in terms of stdint #include typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; typedef uint64_t uint64; typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; typedef int64_t int64; //typedef float float32; typedef double float64; typedef volatile uint8_t vuint8; typedef volatile uint16_t vuint16; typedef volatile uint32_t vuint32; typedef volatile uint64_t vuint64; typedef volatile int8_t vint8; typedef volatile int16_t vint16; typedef volatile int32_t vint32; typedef volatile int64_t vint64; typedef volatile float vfloat32; typedef volatile float64 vfloat64; typedef uint8_t byte; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; typedef volatile u8 vu8; typedef volatile u16 vu16; typedef volatile u32 vu32; typedef volatile u64 vu64; typedef volatile s8 vs8; typedef volatile s16 vs16; typedef volatile s32 vs32; typedef volatile s64 vs64; typedef struct touchPosition { int16 x; int16 y; int16 px; int16 py; int16 z1; int16 z2; } touchPosition; #ifndef __cplusplus /** C++ compatible bool for C */ typedef enum { false, true } bool; #endif // Handy function pointer typedefs typedef void ( * IntFn)(void); typedef void (* VoidFunctionPointer)(void); typedef void (* fp)(void); //--------------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------------- python-box2d-2.0.2+svn20100109.244/Box2D/Box2D.i0000644000000000000000000017147311256533347016531 0ustar rootroot/* * Python SWIG interface file for Box2D (www.box2d.org) * * Copyright (c) 2008 kne / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %module(directors="1") Box2D %{ #include "Box2D/Box2D.h" //Define these functions so that SWIG does not fail void b2BroadPhase::ValidatePairs() { } %} #ifdef SWIGPYTHON #ifdef USE_EXCEPTIONS // See Common/b2Settings.h also %include "exception.i" %exception { try { $action } catch(b2AssertException) { // error already set, pass it on to python } } #endif #pragma SWIG nowarn=314 // Add support for == and != in Python for shapes, joints, and bodies. %inline %{ bool __b2PythonJointPointerEquals__(b2Joint* a, b2Joint* b) { return a==b; } bool __b2PythonBodyPointerEquals__(b2Body* a, b2Body* b) { return a==b; } bool __b2PythonShapePointerEquals__(b2Shape* a, b2Shape* b) { return a==b; } bool __b2PythonControllerPointerEquals__(b2Controller* a, b2Controller* b) { return a==b; } %} %include "Box2D/Box2D_doxygen.i" %include "Box2D/Box2D_printing.i" %include "Box2D/Box2D_pickling.i" /* ---- features ---- */ //Autodoc puts the basic docstrings for each function %feature("autodoc", "1"); //Add callback support for the following classes: %feature("director") b2ContactListener; %feature("director") b2ContactFilter; %feature("director") b2BoundaryListener; %feature("director") b2DestructionListener; %feature("director") b2DebugDraw; // Director-exceptions are a result of callbacks that happen as a result to // the physics step, usually. So, catch those errors and report them back to Python. %exception b2World::Step { try { $action } catch (Swig::DirectorException) { SWIG_fail; } } /* ---- renames ---- */ //These operators do not work unless explicitly defined like this %rename(b2add) operator + (const b2Vec2& a, const b2Vec2& b); %rename(b2add) operator + (const b2Mat22& A, const b2Mat22& B); %rename(b2sub) operator - (const b2Vec2& a, const b2Vec2& b); %rename(b2mul) operator * (float32 s, const b2Vec2& a); %rename(b2equ) operator == (const b2Vec2& a, const b2Vec2& b); %rename(b2mul) operator * (float32 s, const b2Vec3& a); %rename(b2add) operator + (const b2Vec3& a, const b2Vec3& b); %rename(b2sub) operator - (const b2Vec3& a, const b2Vec3& b); //Since Python (apparently) requires __imul__ to return self, //these void operators will not do. So, rename them, then call them //with Python code, and return self. (see further down in b2Vec2) %rename(add_vector) b2Vec2::operator += (const b2Vec2& v); %rename(sub_vector) b2Vec2::operator -= (const b2Vec2& v); %rename(mul_float ) b2Vec2::operator *= (float32 a); %rename(_GetShapeList) b2Body::GetShapeList; //Modify these to return actual lists, not linked lists %rename(_GetBodyList) b2World::GetBodyList; %rename(_GetBodyList) b2Controller::GetBodyList; %rename(_GetJointList) b2World::GetJointList; %rename(_GetControllerList) b2World::GetControllerList; /* ---- handle userData ---- */ %include "Box2D/Box2D_userdata.i" /* ---- typemaps ---- */ %typemap(in) b2Vec2* self { int res1 = SWIG_ConvertPtr($input, (void**)&$1, SWIGTYPE_p_b2Vec2, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); } } //Resolve ambiguities in overloaded functions when you pass a tuple or list when //SWIG expects a b2Vec2 %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) b2Vec2*,b2Vec2& { $1 = (PyList_Check($input) || PyTuple_Check($input) || SWIG_CheckState(SWIG_ConvertPtr($input, 0, SWIGTYPE_p_b2Vec2, 0)) ) ? 1 : 0; } // Allow b2Vec2* arguments be passed in as tuples or lists %typemap(in) b2Vec2* (b2Vec2 temp) { //input - $input -> ($1_type) $1 $1_descriptor if (PyTuple_Check($input) || PyList_Check($input)) { int sz = (PyList_Check($input) ? PyList_Size($input) : PyTuple_Size($input)); if (sz != 2) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 2, got length %d", PyTuple_Size($input)); SWIG_fail; } int res1 = SWIG_AsVal_float(PySequence_GetItem($input, 0), &temp.x); if (!SWIG_IsOK(res1)) { PyErr_SetString(PyExc_TypeError,"Converting from sequence to b2Vec2, expected int/float arguments"); SWIG_fail; } res1 = SWIG_AsVal_float(PySequence_GetItem($input, 1), &temp.y); if (!SWIG_IsOK(res1)) { PyErr_SetString(PyExc_TypeError,"Converting from sequence to b2Vec2, expected int/float arguments"); SWIG_fail; } } else if ($input==Py_None) { temp.Set(0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); SWIG_fail; } temp =(b2Vec2&) *$1; } $1 = &temp; } // Allow b2Vec2& arguments be passed in as tuples or lists %typemap(in) b2Vec2& (b2Vec2 temp) { //input - $input -> ($1_type) $1 $1_descriptor if (PyTuple_Check($input) || PyList_Check($input)) { int sz = (PyList_Check($input) ? PyList_Size($input) : PyTuple_Size($input)); if (sz != 2) { PyErr_Format(PyExc_TypeError, "Expected tuple or list of length 2, got length %d", PyTuple_Size($input)); SWIG_fail; } int res1 = SWIG_AsVal_float(PySequence_GetItem($input, 0), &temp.x); if (!SWIG_IsOK(res1)) { PyErr_SetString(PyExc_TypeError,"Converting from sequence to b2Vec2, expected int/float arguments"); SWIG_fail; } res1 = SWIG_AsVal_float(PySequence_GetItem($input, 1), &temp.y); if (!SWIG_IsOK(res1)) { PyErr_SetString(PyExc_TypeError,"Converting from sequence to b2Vec2, expected int/float arguments"); SWIG_fail; } } else if ($input == Py_None) { temp.Set(0.0f,0.0f); } else { int res1 = SWIG_ConvertPtr($input, (void**)&$1, $1_descriptor, 0); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "$symname" "', argument " "$1_name"" of type '" "$1_type""'"); } temp =(b2Vec2&) *$1; } $1 = &temp; } //Allow access to void* types %typemap(in) void* { $1 = $input; Py_INCREF((PyObject*)$1); } %typemap(out) void* { if (!$1) $result=Py_None; else $result=(PyObject*)$1; Py_INCREF($result); } %typemap(directorin) b2Vec2* vertices { $input = PyTuple_New(vertexCount); PyObject* vertex; for (int i=0; i < vertexCount; i++) { vertex = PyTuple_New(2); PyTuple_SetItem(vertex, 0, PyFloat_FromDouble((float32)vertices[i].x)); PyTuple_SetItem(vertex, 1, PyFloat_FromDouble((float32)vertices[i].y)); PyTuple_SetItem($input, i, vertex); } } /* ---- ignores ---- */ /*Re-implement these inaccessible members on the Python side:*/ %ignore b2PolygonDef::vertices; %ignore b2EdgeChainDef::vertices; %ignore b2PolygonShape::vertices; %ignore b2PolygonShape::GetVertices; //Inaccessible %ignore b2PolygonShape::GetNormals; /* ---- extending classes ---- */ %extend b2World { public: PyObject* Raycast(const b2Segment& segment, int32 maxCount, bool solidShapes, PyObject* userData) { //returns tuple (shapecount, shapes) PyObject* ret=Py_None; b2Shape** shapes=new b2Shape* [maxCount]; if (!shapes) { PyErr_SetString(PyExc_MemoryError, "Insufficient memory"); return NULL; } if (userData==Py_None) { userData=NULL; } else { Py_INCREF(userData); } int32 num = $self->Raycast(segment, shapes, maxCount, solidShapes, (void*)userData); ret = PyTuple_New(2); PyObject* shapeList=PyTuple_New(num); PyObject* shape; for (int i=0; i < num; i++) { shape=SWIG_NewPointerObj(SWIG_as_voidptr(shapes[i]), SWIGTYPE_p_b2Shape, 0 ); PyTuple_SetItem(shapeList, i, shape); } PyTuple_SetItem(ret, 0, SWIG_From_int(num)); PyTuple_SetItem(ret, 1, shapeList); delete [] shapes; return ret; } PyObject* RaycastOne(const b2Segment& segment, bool solidShapes, PyObject* userData) { //returns tuple (float32 lambda, b2Vec2 normal, shape) PyObject* ret=Py_None; float32 lambda=1.0; b2Vec2* normal=new b2Vec2(0.0, 0.0); if (userData==Py_None) { userData=NULL; } else { Py_INCREF(userData); } b2Shape* shape = $self->RaycastOne(segment, &lambda, normal, solidShapes, (void*)userData); ret = PyTuple_New(3); PyTuple_SetItem(ret, 0, SWIG_From_float(lambda)); PyTuple_SetItem(ret, 1, SWIG_NewPointerObj(SWIG_as_voidptr(normal), SWIGTYPE_p_b2Vec2, 0) ); PyTuple_SetItem(ret, 2, SWIG_NewPointerObj(SWIG_as_voidptr(shape), SWIGTYPE_p_b2Shape, 0) ); return ret; } PyObject* Query(const b2AABB& aabb, uint32 maxCount) { // Returns tuple: (number of shapes, shapelist) PyObject* ret=Py_None; b2Shape** shapes=new b2Shape* [maxCount]; if (!shapes) { PyErr_SetString(PyExc_MemoryError, "Insufficient memory"); return NULL; } int32 num=$self->Query(aabb, shapes, maxCount); if (num < 0) num = 0; ret = PyTuple_New(2); PyObject* shapeList=PyTuple_New(num); PyObject* shape; for (int i=0; i < num; i++) { shape=SWIG_NewPointerObj(SWIG_as_voidptr(shapes[i]), SWIGTYPE_p_b2Shape, 0 ); PyTuple_SetItem(shapeList, i, shape); } PyTuple_SetItem(ret, 0, SWIG_From_int(num)); PyTuple_SetItem(ret, 1, shapeList); delete [] shapes; return ret; } %pythoncode %{ def GetJointList(self): """ Get a list of the joints in this world """ jointList = [] joint = self._GetJointList() while joint: jointList.append(joint.getAsType()) joint = joint.GetNext() jointList.reverse() # jointlist is in reverse order return jointList def GetBodyList(self): """ Get a list of the bodies in this world """ bodyList = [] body = self._GetBodyList() while body: bodyList.append(body) body = body.GetNext() bodyList.reverse() # bodylist is in reverse order return bodyList def GetControllerList(self): """ Get a list of the controllers in this world """ controllerList = [] controller = self._GetControllerList() while controller: controllerList.append(controller.getAsType()) controller = controller.GetNext() controllerList.reverse() # controllerlist is in reverse order return controllerList def __iter__(self): """ Iterates over the bodies in the world """ for body in self.bodyList: yield body gravity = property(GetGravity , SetGravity) jointList = property(GetJointList , None) bodyList = property(GetBodyList , None) groundBody= property(GetGroundBody, None) worldAABB = property(GetWorldAABB , None) doSleep = property(CanSleep , None) controllerList = property(GetControllerList, None) %} } %extend b2Shape { public: long __hash__() { return (long)self; } PyObject* TestSegment(const b2XForm& xf, const b2Segment& segment, float32 maxLambda) { int hit; float32 lambda=0.0f; b2Vec2 normal(0.0f ,0.0f); hit=(int)$self->TestSegment(xf, &lambda, &normal, segment, maxLambda); PyObject* normal_tuple=PyTuple_New(2); PyTuple_SetItem(normal_tuple, 0, SWIG_From_float(normal.x)); PyTuple_SetItem(normal_tuple, 1, SWIG_From_float(normal.y)); PyObject* ret=PyTuple_New(3); PyTuple_SetItem(ret, 0, SWIG_From_int(hit)); PyTuple_SetItem(ret, 1, SWIG_From_float(lambda)); PyTuple_SetItem(ret, 2, normal_tuple); return ret; } %pythoncode %{ filter = property(GetFilterData, SetFilterData) friction = property(GetFriction, SetFriction) restitution= property(GetRestitution, SetRestitution) density = property(GetDensity, SetDensity) isSensor = property(IsSensor, None) # for symmetry with defn + pickling __eq__ = b2ShapeCompare __ne__ = lambda self,other: not b2ShapeCompare(self,other) def typeName(self): types = { e_unknownShape : "Unknown", e_circleShape : "Circle", e_polygonShape : "Polygon", e_edgeShape : "Edge", e_shapeTypeCount: "ShapeType" } return types[self.GetType()] def getAsType(self): """Return a typecasted version of the shape""" return (getattr(self, "as%s" % self.typeName())) () %} b2CircleShape* asCircle() { if ($self->GetType()==e_circleShape) return (b2CircleShape*)$self; return NULL; } b2PolygonShape* asPolygon() { if ($self->GetType()==e_polygonShape) return (b2PolygonShape*)$self; return NULL; } b2EdgeShape* asEdge() { if ($self->GetType()==e_edgeShape) return (b2EdgeShape*)$self; return NULL; } } //Support using == on bodies, joints, and shapes %pythoncode %{ def b2ShapeCompare(a, b): if not isinstance(a, b2Shape) or not isinstance(b, b2Shape): return False return __b2PythonShapePointerEquals__(a, b) def b2BodyCompare(a, b): if not isinstance(a, b2Body) or not isinstance(b, b2Body): return False return __b2PythonBodyPointerEquals__(a, b) def b2JointCompare(a, b): if not isinstance(a, b2Joint) or not isinstance(b, b2Joint): return False return __b2PythonJointPointerEquals__(a, b) def b2ControllerCompare(a, b): if not isinstance(a, b2Controller) or not isinstance(b, b2Controller): return False return __b2PythonControllerPointerEquals__(a, b) %} // Clean up naming. We do not need m_* on the Python end. %rename(localAnchor) b2MouseJoint::m_localAnchor; %rename(target) b2MouseJoint::m_target; %rename(impulse) b2MouseJoint::m_impulse; %rename(mass) b2MouseJoint::m_mass; %rename(C) b2MouseJoint::m_C; %rename(maxForce) b2MouseJoint::m_maxForce; %rename(frequencyHz) b2MouseJoint::m_frequencyHz; %rename(dampingRatio)b2MouseJoint::m_dampingRatio; %rename(beta) b2MouseJoint::m_beta; %rename(gamma) b2MouseJoint::m_gamma; %extend b2MouseJoint { public: %pythoncode %{ %} } %rename(ground1) b2GearJoint::m_ground1; %rename(ground2) b2GearJoint::m_ground2; %rename(revolute1) b2GearJoint::m_revolute1; %rename(prismatic1) b2GearJoint::m_prismatic1; %rename(revolute2) b2GearJoint::m_revolute2; %rename(prismatic2) b2GearJoint::m_prismatic2; %rename(groundAnchor1) b2GearJoint::m_groundAnchor1; %rename(groundAnchor2) b2GearJoint::m_groundAnchor2; %rename(localAnchor1) b2GearJoint::m_localAnchor1; %rename(localAnchor2) b2GearJoint::m_localAnchor2; %rename(J) b2GearJoint::m_J; %rename(constant) b2GearJoint::m_constant; %rename(ratio) b2GearJoint::m_ratio; %rename(mass) b2GearJoint::m_mass; %rename(impulse) b2GearJoint::m_impulse; %extend b2GearJoint { public: %pythoncode %{ joint1 = property(lambda self: (self.revolute1 and self.revolute1) or self.prismatic1, None) joint2 = property(lambda self: (self.revolute2 and self.revolute2) or self.prismatic2, None) %} } %rename(localAnchor1) b2DistanceJoint::m_localAnchor1; %rename(localAnchor2) b2DistanceJoint::m_localAnchor2; %rename(u) b2DistanceJoint::m_u; %rename(frequencyHz) b2DistanceJoint::m_frequencyHz; %rename(dampingRatio) b2DistanceJoint::m_dampingRatio; %rename(gamma) b2DistanceJoint::m_gamma; %rename(bias) b2DistanceJoint::m_bias; %rename(impulse) b2DistanceJoint::m_impulse; %rename(mass) b2DistanceJoint::m_mass; %rename(length) b2DistanceJoint::m_length; %extend b2DistanceJoint { public: %pythoncode %{ %} } %rename(localAnchor1) b2PrismaticJoint::m_localAnchor1; %rename(localAnchor2) b2PrismaticJoint::m_localAnchor2; %rename(localXAxis1) b2PrismaticJoint::m_localXAxis1; %rename(localYAxis1) b2PrismaticJoint::m_localYAxis1; %rename(referenceAngle) b2PrismaticJoint::m_refAngle; // symmetry with defn %rename(axis) b2PrismaticJoint::m_axis; %rename(perp) b2PrismaticJoint::m_perp; %rename(s1) b2PrismaticJoint::m_s1; %rename(s2) b2PrismaticJoint::m_s2; %rename(a1) b2PrismaticJoint::m_a1; %rename(a2) b2PrismaticJoint::m_a2; %rename(K) b2PrismaticJoint::m_K; %rename(impulse) b2PrismaticJoint::m_impulse; %rename(motorMass) b2PrismaticJoint::m_motorMass; %rename(motorImpulse) b2PrismaticJoint::m_motorImpulse; %rename(lowerTranslation)b2PrismaticJoint::m_lowerTranslation; %rename(upperTranslation)b2PrismaticJoint::m_upperTranslation; %rename(maxMotorForce) b2PrismaticJoint::m_maxMotorForce; %rename(motorSpeed) b2PrismaticJoint::m_motorSpeed; %rename(enableLimit) b2PrismaticJoint::m_enableLimit; %rename(enableMotor) b2PrismaticJoint::m_enableMotor; %rename(limitState) b2PrismaticJoint::m_limitState; %extend b2PrismaticJoint { public: %pythoncode %{ %} } %rename(ground) b2PulleyJoint::m_ground; %rename(groundAnchor1) b2PulleyJoint::m_groundAnchor1; %rename(groundAnchor2) b2PulleyJoint::m_groundAnchor2; %rename(localAnchor1) b2PulleyJoint::m_localAnchor1; %rename(localAnchor2) b2PulleyJoint::m_localAnchor2; %rename(u1) b2PulleyJoint::m_u1; %rename(u2) b2PulleyJoint::m_u2; %rename(constant) b2PulleyJoint::m_constant; %rename(ratio) b2PulleyJoint::m_ratio; %rename(maxLength1) b2PulleyJoint::m_maxLength1; %rename(maxLength2) b2PulleyJoint::m_maxLength2; %rename(pulleyMass) b2PulleyJoint::m_pulleyMass; %rename(limitMass1) b2PulleyJoint::m_limitMass1; %rename(limitMass2) b2PulleyJoint::m_limitMass2; %rename(impulse) b2PulleyJoint::m_impulse; %rename(limitImpulse1) b2PulleyJoint::m_limitImpulse1; %rename(limitImpulse2) b2PulleyJoint::m_limitImpulse2; %rename(state) b2PulleyJoint::m_state; %rename(limitState1) b2PulleyJoint::m_limitState1; %rename(limitState2) b2PulleyJoint::m_limitState2; %extend b2PulleyJoint { public: %pythoncode %{ length1 = property(GetLength1, None) length2 = property(GetLength2, None) %} } %rename(localAnchor1) b2RevoluteJoint::m_localAnchor1; %rename(localAnchor2) b2RevoluteJoint::m_localAnchor2; %rename(impulse) b2RevoluteJoint::m_impulse; %rename(motorImpulse) b2RevoluteJoint::m_motorImpulse; %rename(mass) b2RevoluteJoint::m_mass; %rename(motorMass) b2RevoluteJoint::m_motorMass; %rename(enableMotor) b2RevoluteJoint::m_enableMotor; %rename(maxMotorTorque) b2RevoluteJoint::m_maxMotorTorque; %rename(motorSpeed) b2RevoluteJoint::m_motorSpeed; %rename(enableLimit) b2RevoluteJoint::m_enableLimit; %rename(referenceAngle) b2RevoluteJoint::m_referenceAngle; %rename(lowerAngle) b2RevoluteJoint::m_lowerAngle; %rename(upperAngle) b2RevoluteJoint::m_upperAngle; %rename(limitState) b2RevoluteJoint::m_limitState; %extend b2RevoluteJoint { public: %pythoncode %{ %} } %rename(localAnchor1) b2LineJoint::m_localAnchor1; %rename(localAnchor2) b2LineJoint::m_localAnchor2; %rename(localXAxis1) b2LineJoint::m_localXAxis1; %rename(localYAxis1) b2LineJoint::m_localYAxis1; %rename(axis) b2LineJoint::m_axis; %rename(perp) b2LineJoint::m_perp; %rename(s1) b2LineJoint::m_s1; %rename(s2) b2LineJoint::m_s2; %rename(a1) b2LineJoint::m_a1; %rename(a2) b2LineJoint::m_a2; %rename(K) b2LineJoint::m_K; %rename(impulse) b2LineJoint::m_impulse; %rename(motorMass) b2LineJoint::m_motorMass; %rename(motorImpulse) b2LineJoint::m_motorImpulse; %rename(lowerTranslation)b2LineJoint::m_lowerTranslation; %rename(upperTranslation)b2LineJoint::m_upperTranslation; %rename(maxMotorForce) b2LineJoint::m_maxMotorForce; %rename(motorSpeed) b2LineJoint::m_motorSpeed; %rename(enableLimit) b2LineJoint::m_enableLimit; %rename(enableMotor) b2LineJoint::m_enableMotor; %rename(limitState) b2LineJoint::m_limitState; %extend b2LineJoint { public: %pythoncode %{ %} } %include "Dynamics/Joints/b2Joint.h" %extend b2JointDef { public: %pythoncode %{ def typeName(self): """ Return the name of the joint from: Unknown, Mouse, Gear, Distance, Prismatic, Pulley, Revolute """ types = { e_unknownJoint : "Unknown", e_mouseJoint : "Mouse", e_gearJoint : "Gear", e_distanceJoint : "Distance", e_prismaticJoint: "Prismatic", e_pulleyJoint : "Pulley", e_revoluteJoint : "Revolute", e_lineJoint : "Line" } return types[self.type] %} } %extend b2Controller { long __hash__() { return (long)self; } %pythoncode %{ def typeName(self): """ Return the name of the controller from: Unknown, Buoyancy, ConstantAccel, ConstantForce, Gravity, TensorDamping """ types = { e_unknownController : 'Unknown', e_buoyancyController : 'Buoyancy', e_constantAccelController : 'ConstantAccel', e_constantForceController : 'ConstantForce', e_gravityController : 'Gravity', e_tensorDampingController : 'TensorDamping' } return types[self.GetType()] def getAsType(self): """ Return a typecasted version of the controller """ return (getattr(self, "_as%sController" % self.typeName())) () def GetBodyList(self): bodyList = [] c_edge = self._GetBodyList() while c_edge: bodyList.append(c_edge.body) c_edge = c_edge.nextBody bodyList.reverse() # bodylist is in reverse order return bodyList def __iter__(self): """ Iterates over the bodies in the controller """ for body in self.bodyList: yield body __eq__ = b2ControllerCompare __ne__ = lambda self,other: not b2ControllerCompare(self,other) type = property(GetType, None) bodyList = property(GetBodyList, None) %} b2BuoyancyController* _asBuoyancyController() { if ($self->GetType()==e_buoyancyController) return (b2BuoyancyController*)$self; return NULL; } b2ConstantAccelController* _asConstantAccelController() { if ($self->GetType()==e_constantAccelController) return (b2ConstantAccelController*)$self; return NULL; } b2ConstantForceController* _asConstantForceController() { if ($self->GetType()==e_constantForceController) return (b2ConstantForceController*)$self; return NULL; } b2GravityController* _asGravityController() { if ($self->GetType()==e_gravityController) return (b2GravityController*)$self; return NULL; } b2TensorDampingController* _asTensorDampingController() { if ($self->GetType()==e_tensorDampingController) return (b2TensorDampingController*)$self; return NULL; } } %extend b2Joint { public: long __hash__() { return (long)self; } %pythoncode %{ __eq__ = b2JointCompare __ne__ = lambda self,other: not b2JointCompare(self,other) type =property(GetType , None) body1 =property(GetBody1 , None) body2 =property(GetBody2 , None) collideConnected=property(GetCollideConnected, None) def typeName(self): """ Return the name of the joint from: Unknown, Mouse, Gear, Distance, Prismatic, Pulley, Revolute """ types = { e_unknownJoint : "Unknown", e_mouseJoint : "Mouse", e_gearJoint : "Gear", e_distanceJoint : "Distance", e_prismaticJoint: "Prismatic", e_pulleyJoint : "Pulley", e_revoluteJoint : "Revolute", e_lineJoint : "Line" } return types[self.GetType()] def getAsType(self): """ Return a typecasted version of the joint """ return (getattr(self, "as%sJoint" % self.typeName())) () %} b2MouseJoint* asMouseJoint() { if ($self->GetType()==e_mouseJoint) return (b2MouseJoint*)$self; return NULL; } b2GearJoint* asGearJoint() { if ($self->GetType()==e_gearJoint) return (b2GearJoint*)$self; return NULL; } b2DistanceJoint* asDistanceJoint() { if ($self->GetType()==e_distanceJoint) return (b2DistanceJoint*)$self; return NULL; } b2PrismaticJoint* asPrismaticJoint() { if ($self->GetType()==e_prismaticJoint) return (b2PrismaticJoint*)$self; return NULL; } b2PulleyJoint* asPulleyJoint() { if ($self->GetType()==e_pulleyJoint) return (b2PulleyJoint*)$self; return NULL; } b2RevoluteJoint* asRevoluteJoint() { if ($self->GetType()==e_revoluteJoint) return (b2RevoluteJoint*)$self; return NULL; } b2LineJoint* asLineJoint() { if ($self->GetType()==e_lineJoint) return (b2LineJoint*)$self; return NULL; } } %extend b2CircleShape { public: %pythoncode %{ __eq__ = b2ShapeCompare __ne__ = lambda self,other: not b2ShapeCompare(self,other) radius = property(GetRadius, None) localPosition = property(GetLocalPosition, None) %} } //Let python access all the vertices in the b2PolygonDef/Shape %extend b2PolygonShape { public: %pythoncode %{ __eq__ = b2ShapeCompare __ne__ = lambda self,other: not b2ShapeCompare(self,other) def __repr__(self): return "b2PolygonShape(vertices: %s count: %d)" % (self.getVertices_tuple(), self.GetVertexCount()) def getCoreVertices_tuple(self): """Returns all of the core vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.GetVertexCount()): vertices.append( (self.getCoreVertex(i).x, self.getCoreVertex(i).y ) ) return vertices def getCoreVertices_b2Vec2(self): """Returns all of the core vertices as a list of b2Vec2's [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.GetVertexCount()): vertices.append(self.getCoreVertex(i)) return vertices def getVertices_tuple(self): """Returns all of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.GetVertexCount()): vertices.append( (self.getVertex(i).x, self.getVertex(i).y ) ) return vertices def getVertices_b2Vec2(self): """Returns all of the vertices as a list of b2Vec2's [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.GetVertexCount()): vertices.append(self.getVertex(i)) return vertices def getNormals_tuple(self): """Returns all of the normals as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.GetVertexCount()): vertices.append( (self.getNormal(i).x, self.getNormal(i).y ) ) return vertices def getNormals_b2Vec2(self): """Returns all of the normals as a list of b2Vec2's [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.GetVertexCount()): vertices.append(self.getNormal(i)) return vertices def __iter__(self): """ Iterates over the vertices in the polygon """ for v in self.vertices: yield v vertices = property(getVertices_tuple, None) coreVertices = property(getCoreVertices_tuple, None) normals = property(getNormals_tuple, None) %} const b2Vec2* getVertex(uint16 vnum) { if (vnum >= b2_maxPolygonVertices || vnum >= self->GetVertexCount()) return NULL; return &( $self->GetVertices() [vnum] ); } const b2Vec2* getCoreVertex(uint16 vnum) { if (vnum >= b2_maxPolygonVertices || vnum >= self->GetVertexCount()) return NULL; return &( $self->GetCoreVertices() [vnum] ); } const b2Vec2* getNormal(uint16 vnum) { if (vnum >= b2_maxPolygonVertices || vnum >= self->GetVertexCount()) return NULL; return &( $self->GetNormals() [vnum] ); } } %extend b2EdgeChainDef { public: %pythoncode %{ def __repr__(self): return "b2EdgeDef(vertices: %s count: %d)" % (self.getVertices_tuple(), self.vertexCount) def __del__(self): """Cleans up by freeing the allocated vertex array""" super(b2EdgeChainDef, self).__del__() self._cleanUp() def getVertices_tuple(self): """Returns all of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.vertexCount): vertices.append( (self.getVertex(i).x, self.getVertex(i).y ) ) return vertices def getVertices_b2Vec2(self): """Returns all of the vertices as a list of b2Vec2's [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.vertexCount): vertices.append(self.getVertex(i)) return vertices def setVertices(self, vertices): """Sets all of the vertices given a tuple in the format ( (x1,y1), (x2,y2) ... (xN,yN) ) where each vertex is either a list/tuple/b2Vec2""" self._allocateVertices(len(vertices)) for i in range(0, self.vertexCount): self.setVertex(i, vertices[i]) setVertices_tuple = setVertices # pre 202b1 compatibility setVertices_b2Vec2 = setVertices # pre 202b1 compatibility vertices = property(getVertices_tuple, setVertices) %} void _cleanUp() { if ($self->vertexCount > 0 && $self->vertices) delete [] $self->vertices; $self->vertices = NULL; $self->vertexCount = 0; } void _allocateVertices(uint16 _count) { if ($self->vertexCount > 0 && $self->vertices) delete [] $self->vertices; $self->vertices = new b2Vec2 [_count]; if (!$self->vertices) { $self->vertexCount = 0; PyErr_SetString(PyExc_MemoryError, "Insufficient memory"); return; } $self->vertexCount = _count; } b2Vec2* getVertex(uint16 vnum) { if (vnum >= $self->vertexCount) return NULL; return &( $self->vertices[vnum] ); } void setVertex(uint16 vnum, b2Vec2& value) { if (vnum < $self->vertexCount) $self->vertices[vnum].Set(value.x, value.y); } void setVertex(uint16 vnum, float32 x, float32 y) { if (vnum < $self->vertexCount) $self->vertices[vnum].Set(x, y); } } %extend b2EdgeShape { %pythoncode %{ def GetVertices(self): vertices = [] edge = self while edge: vertices.append( edge.vertex1 ) last = edge.vertex2 edge=edge.next if edge==self: # a loop vertices.extend( [edge.vertex1, edge.vertex2] ) return vertices vertices.append( last ) return vertices length = property(GetLength, None) vertex1 = property(GetVertex1, None) vertex2 = property(GetVertex2, None) coreVertex1 = property(GetCoreVertex1, None) coreVertex2 = property(GetCoreVertex2, None) next = property(GetNextEdge, None) prev = property(GetPrevEdge, None) %} } %extend b2PolygonDef{ public: %pythoncode %{ def __repr__(self): return "b2PolygonDef(vertices: %s count: %d)" % (self.vertices, self.vertexCount) def checkValues(self): return b2CheckPolygonDef(self) def getVertices_tuple(self): """Returns all of the vertices as a list of tuples [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.vertexCount): vertices.append( (self.getVertex(i).x, self.getVertex(i).y ) ) return vertices def getVertices_b2Vec2(self): """Returns all of the vertices as a list of b2Vec2's [ (x1,y1), (x2,y2) ... (xN,yN) ]""" vertices = [] for i in range(0, self.vertexCount): vertices.append(self.getVertex(i)) return vertices def setVertices(self, vertices): """Sets all of the vertices given a tuple in the format ( (x1,y1), (x2,y2) ... (xN,yN) ) where each vertex is a list/tuple/b2Vec2""" if len(vertices) > b2_maxPolygonVertices: raise ValueError() self.vertexCount = len(vertices) for i in range(0, self.vertexCount): self.setVertex(i, vertices[i]) # possible on pyBox2D >= r2.0.2b1 setVertices_tuple = setVertices # pre 202b1 compatibility setVertices_b2Vec2 = setVertices # pre 202b1 compatibility vertices = property(getVertices_tuple, setVertices) %} b2Vec2* getVertex(uint16 vnum) { if (vnum >= b2_maxPolygonVertices || vnum >= self->vertexCount) return NULL; return &( $self->vertices[vnum] ); } void setVertex(uint16 vnum, b2Vec2& value) { if (vnum >= b2_maxPolygonVertices) return; $self->vertices[vnum].Set(value.x, value.y); } void setVertex(uint16 vnum, float32 x, float32 y) { if (vnum >= b2_maxPolygonVertices) return; $self->vertices[vnum].Set(x, y); } } %extend b2Color { %pythoncode %{ __iter__ = lambda self: iter((self.r, self.g, self.b)) %} } // Vector class %extend b2Vec2 { b2Vec2(b2Vec2& other) { return new b2Vec2(other.x, other.y); } %pythoncode %{ __iter__ = lambda self: iter( (self.x, self.y) ) def __repr__(self): return "b2Vec2(%g,%g)" % (self.x, self.y) def tuple(self): """ Return the vector as a tuple (x,y) """ return tuple(self) def fromTuple(self, tuple): """ *DEPRECATED* Set the vector to the values found in the tuple (x,y) You should use: value = b2Vec2(*tuple) """ self.x, self.y = tuple return self def copy(self): """ Return a copy of the vector. Remember that the following: a = b2Vec2() b = a Does not copy the vector itself, but b now refers to a. """ return b2Vec2(self.x, self.y) def __iadd__(self, other): self.add_vector(other) return self def __isub__(self, other): self.sub_vector(other) return self def __imul__(self, a): self.mul_float(a) return self def __idiv__(self, a): self.div_float(a) return self def dot(self, v): """ Dot product with v (list/tuple or b2Vec2) """ if isinstance(v, (list, tuple)): return self.x*v[0] + self.y*v[1] else: return self.x*v.x + self.y*v.y %} b2Vec2 __div__(float32 a) { //convenience function return b2Vec2($self->x / a, $self->y / a); } b2Vec2 __mul__(float32 a) { return b2Vec2($self->x * a, $self->y * a); } b2Vec2 __add__(b2Vec2* other) { return b2Vec2($self->x + other->x, $self->y + other->y); } b2Vec2 __sub__(b2Vec2* other) { return b2Vec2($self->x - other->x, $self->y - other->y); } b2Vec2 __rmul__(float32 a) { return b2Vec2($self->x * a, $self->y * a); } b2Vec2 __rdiv__(float32 a) { return b2Vec2($self->x / a, $self->y / a); } void div_float(float32 a) { self->x /= a; self->y /= a; } } %extend b2Body { long __hash__() { return (long)self; } %pythoncode %{ __eq__ = b2BodyCompare __ne__ = lambda self,other: not b2BodyCompare(self,other) def setAngle(self, angle): """ Set the angle without altering the position angle in radians. """ self.SetXForm(self.position, angle) def setPosition(self, position): """ Set the position without altering the angle """ self.SetXForm(position, self.GetAngle()) def getMassData(self): """ Get a b2MassData object that represents this b2Body NOTE: To just get the mass, use body.mass (body.GetMass()) """ ret = b2MassData() ret.mass = self.GetMass() ret.I = self.GetInertia() ret.center=self.GetLocalCenter() return ret def GetShapeList(self, asType=True): """ Get a list of the shapes in this body Defaults to returning the typecasted objects. e.g., if there is a b2CircleShape and a b2PolygonShape: GetShapeList(True) = [b2CircleShape, b2PolygonShape] GetShapeList(False)= [b2Shape, b2Shape] """ shapeList = [] shape = self._GetShapeList() while shape: if asType: shape=shape.getAsType() shapeList.append(shape) shape = shape.GetNext() shapeList.reverse() # shapelist is in reverse order return shapeList def __iter__(self): """ Iterates over the shapes in the body """ for shape in self.shapeList: yield shape massData = property(getMassData , SetMass) position = property(GetPosition , setPosition) angle = property(GetAngle , setAngle) linearDamping = property(GetLinearDamping , SetLinearDamping) angularDamping= property(GetAngularDamping , SetAngularDamping) allowSleep = property(IsAllowSleeping , AllowSleeping) isSleeping = property(IsSleeping , None) fixedRotation = property(IsFixedRotation , SetFixedRotation) isBullet = property(IsBullet , SetBullet) angularVelocity=property(GetAngularVelocity , SetAngularVelocity) linearVelocity =property(GetLinearVelocity , SetLinearVelocity) shapeList =property(GetShapeList , None) %} } %rename (__b2Distance__) b2Distance(b2Vec2* x1, b2Vec2* x2, const b2Shape* shape1, const b2XForm& xf1, const b2Shape* shape2, const b2XForm& xf2); %inline %{ //Add a b2Distance: // dist, x1, x2 = b2Distance(shape1, xf1, shape2, xf2) PyObject* b2Distance(const b2Shape* shape1, const b2XForm& xf1, const b2Shape* shape2, const b2XForm& xf2) { PyObject* ret=PyTuple_New(3); b2Vec2* x1=new b2Vec2; b2Vec2* x2=new b2Vec2; float dist=b2Distance(x1,x2,shape1,xf1,shape2,xf2); PyTuple_SetItem(ret, 0, SWIG_From_float(dist)); PyTuple_SetItem(ret, 1, SWIG_NewPointerObj(SWIG_as_voidptr(x1), SWIGTYPE_p_b2Vec2, 0 )); PyTuple_SetItem(ret, 2, SWIG_NewPointerObj(SWIG_as_voidptr(x2), SWIGTYPE_p_b2Vec2, 0 )); return ret; } %} /* Additional supporting C++ code */ %typemap(out) bool b2CheckPolygonDef(b2PolygonDef*) { if (!$1) SWIG_fail; else $result = SWIG_From_bool(static_cast< bool >($1)); } %feature("docstring") b2CheckPolygonDef " Checks the Polygon definition to see if upon creation it will cause an assertion. Raises ValueError if an assertion would be raised. b2PolygonDef* poly - the polygon definition bool additional_checks - whether or not to run additional checks Additional checking: usually only in DEBUG mode on the C++ code. While shapes that pass this test can be created without assertions, they will ultimately create unexpected behavior. It's recommended to _not_ use any polygon that fails this test. "; %feature("docstring") b2AABBOverlaps "Checks if two AABBs overlap, or if a point lies in an AABB b2AABBOverlaps(AABB1, [AABB2/point]) "; %inline %{ // Add some functions that might be commonly used bool b2AABBOverlaps(const b2AABB& aabb, const b2Vec2& point) { //If point is in aabb (including a small buffer around it), return true. if (point.x < (aabb.upperBound.x + B2_FLT_EPSILON) && point.x > (aabb.lowerBound.x - B2_FLT_EPSILON) && point.y < (aabb.upperBound.y + B2_FLT_EPSILON) && point.y > (aabb.lowerBound.y - B2_FLT_EPSILON)) return true; return false; } bool b2AABBOverlaps(const b2AABB& aabb, const b2AABB& aabb2) { //If aabb and aabb2 overlap, return true. (modified from b2BroadPhase::InRange) b2Vec2 d = b2Max(aabb.lowerBound - aabb2.upperBound, aabb2.lowerBound - aabb.upperBound); return b2Max(d.x, d.y) < 0.0f; } // Modified from the b2PolygonShape constructor // Should be as accurate as the original version b2Vec2 __b2ComputeCentroid(const b2Vec2* vs, int32 count) { b2Vec2 c; c.Set(0.0f, 0.0f); if (count < 3 || count >= b2_maxPolygonVertices) { PyErr_SetString(PyExc_ValueError, "Vertex count must be >= 3 and < b2_maxPolygonVertices"); return c; } float32 area = 0.0f; // pRef is the reference point for forming triangles. // It's location doesn't change the result (except for rounding error). b2Vec2 pRef(0.0f, 0.0f); const float32 inv3 = 1.0f / 3.0f; for (int32 i = 0; i < count; ++i) { // Triangle vertices. b2Vec2 p1 = pRef; b2Vec2 p2 = vs[i]; b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; b2Vec2 e1 = p2 - p1; b2Vec2 e2 = p3 - p1; float32 D = b2Cross(e1, e2); float32 triangleArea = 0.5f * D; area += triangleArea; // Area weighted centroid c += triangleArea * inv3 * (p1 + p2 + p3); } // Centroid if (area <= B2_FLT_EPSILON) { PyErr_SetString(PyExc_ValueError, "ComputeCentroid: area <= FLT_EPSILON"); return c; } c *= 1.0f / area; return c; } bool __b2ComputeOBB(b2OBB* obb, const b2Vec2* vs, int32 count) { if (count < 3 || count >= b2_maxPolygonVertices) { PyErr_SetString(PyExc_ValueError, "Vertex count must be >= 3 and < b2_maxPolygonVertices"); return false; } b2Vec2 p[b2_maxPolygonVertices + 1]; for (int32 i = 0; i < count; ++i) { p[i] = vs[i]; } p[count] = p[0]; float32 minArea = B2_FLT_MAX; for (int32 i = 1; i <= count; ++i) { b2Vec2 root = p[i-1]; b2Vec2 ux = p[i] - root; float32 length = ux.Normalize(); if (length <= B2_FLT_EPSILON) { PyErr_SetString(PyExc_ValueError, "ComputeOBB: length <= B2_FLT_EPSILON"); return false; } b2Vec2 uy(-ux.y, ux.x); b2Vec2 lower(B2_FLT_MAX, B2_FLT_MAX); b2Vec2 upper(-B2_FLT_MAX, -B2_FLT_MAX); for (int32 j = 0; j < count; ++j) { b2Vec2 d = p[j] - root; b2Vec2 r; r.x = b2Dot(ux, d); r.y = b2Dot(uy, d); lower = b2Min(lower, r); upper = b2Max(upper, r); } float32 area = (upper.x - lower.x) * (upper.y - lower.y); if (area < 0.95f * minArea) { minArea = area; obb->R.col1 = ux; obb->R.col2 = uy; b2Vec2 center = 0.5f * (lower + upper); obb->center = root + b2Mul(obb->R, center); obb->extents = 0.5f * (upper - lower); } } if (minArea >= B2_FLT_MAX) { PyErr_SetString(PyExc_ValueError, "ComputeOBB: minArea >= B2_FLT_MAX"); return false; } return true; } bool b2CheckPolygonDef(b2PolygonDef* poly, bool additional_checks=true) { // Get the vertices transformed into the body frame. if (poly->vertexCount < 3 || poly->vertexCount >= b2_maxPolygonVertices) { PyErr_SetString(PyExc_ValueError, "Vertex count must be >= 3 and < b2_maxPolygonVertices"); return false; } // Compute normals. Ensure the edges have non-zero length. b2Vec2 m_normals[b2_maxPolygonVertices]; for (int32 i = 0; i < poly->vertexCount; ++i) { int32 i1 = i; int32 i2 = i + 1 < poly->vertexCount ? i + 1 : 0; b2Vec2 edge = poly->vertices[i2] - poly->vertices[i1]; if (edge.LengthSquared() <= B2_FLT_EPSILON * B2_FLT_EPSILON) { PyErr_SetString(PyExc_ValueError, "edge.LengthSquared < FLT_EPSILON**2"); return false; } m_normals[i] = b2Cross(edge, 1.0f); m_normals[i].Normalize(); } // Compute the polygon centroid. b2Vec2 m_centroid = __b2ComputeCentroid(poly->vertices, poly->vertexCount); // Compute the oriented bounding box. b2OBB m_obb; __b2ComputeOBB(&m_obb, poly->vertices, poly->vertexCount); if (PyErr_Occurred()) return false; // Create core polygon shape by shifting edges inward. // Also compute the min/max radius for CCD. for (int32 i = 0; i < poly->vertexCount; ++i) { int32 i1 = i - 1 >= 0 ? i - 1 : poly->vertexCount - 1; int32 i2 = i; b2Vec2 n1 = m_normals[i1]; b2Vec2 n2 = m_normals[i2]; b2Vec2 v = poly->vertices[i] - m_centroid; b2Vec2 d; d.x = b2Dot(n1, v) - b2_toiSlop; d.y = b2Dot(n2, v) - b2_toiSlop; // Shifting the edge inward by b2_toiSlop should // not cause the plane to pass the centroid. // Your shape has a radius/extent less than b2_toiSlop. if (d.x < 0.0f) { PyErr_SetString(PyExc_ValueError, "Your shape has a radius/extent less than b2_toiSlop. (d.x < 0.0)"); return false; } else if (d.y < 0.0f) { PyErr_SetString(PyExc_ValueError, "Your shape has a radius/extent less than b2_toiSlop. (d.y < 0.0)"); return false; } b2Mat22 A; A.col1.x = n1.x; A.col2.x = n1.y; A.col1.y = n2.x; A.col2.y = n2.y; //m_coreVertices[i] = A.Solve(d) + m_centroid; } if (!additional_checks) return true; // Ensure the polygon is convex. for (int32 i = 0; i < poly->vertexCount; ++i) { for (int32 j = 0; j < poly->vertexCount; ++j) { // Do not check vertices on the current edge. if (j == i || j == (i + 1) % poly->vertexCount) continue; float32 s = b2Dot(m_normals[i], poly->vertices[j] - poly->vertices[i]); if (s >= -b2_linearSlop) { PyErr_SetString(PyExc_ValueError, "Your polygon is non-convex (it has an indentation), or it's too skinny"); return false; } } } // Ensure the polygon is counter-clockwise. for (int32 i = 1; i < poly->vertexCount; ++i) { float32 cross = b2Cross(m_normals[i-1], m_normals[i]); // Keep asinf happy. cross = b2Clamp(cross, -1.0f, 1.0f); float32 angle = asinf(cross); if (angle <= b2_angularSlop) { PyErr_SetString(PyExc_ValueError, "You have consecutive edges that are almost parallel on your polygon."); return false; } } return true; } /* As of Box2D SVN r191, these functions are no longer in b2Math.h, so re-add them here for backwards compatibility */ #define RAND_LIMIT 32767 // Random number in range [-1,1] float32 b2Random() { float32 r = (float32)(rand() & (RAND_LIMIT)); r /= RAND_LIMIT; r = 2.0f * r - 1.0f; return r; } /// Random floating point number in range [lo, hi] float32 b2Random(float32 lo, float32 hi) { float32 r = (float32)(rand() & (RAND_LIMIT)); r /= RAND_LIMIT; r = (hi - lo) * r + lo; return r; } %} /* Additional supporting Python code */ %pythoncode %{ B2_FLT_EPSILON = 1.192092896e-07 FLT_EPSILON = B2_FLT_EPSILON B2_FLT_MAX = 3.402823466e+38 cvars = ('b2_minPulleyLength','b2Contact_s_initialized','b2Contact_s_registers','b2_maxStackEntries','b2_stackSize', 'b2_chunkArrayIncrement','b2_blockSizes','b2_maxBlockSize','b2_chunkSize','b2_defaultFilter','b2BroadPhase_s_validate', 'b2_nullEdge','b2_invalid','b2_tableMask','b2_tableCapacity','b2_nullProxy','b2_nullPair','b2_nullFeature','b2XForm_identity', 'b2Mat22_identity','b2Vec2_zero','b2_version','b2_byteCount','b2_angularSleepTolerance','b2_linearSleepTolerance', 'b2_timeToSleep','b2_contactBaumgarte','b2_maxAngularVelocitySquared','b2_maxAngularVelocity','b2_maxLinearVelocitySquared', 'b2_maxLinearVelocity','b2_maxAngularCorrection','b2_maxLinearCorrection','b2_velocityThreshold','b2_maxTOIJointsPerIsland', 'b2_maxTOIContactsPerIsland','b2_toiSlop','b2_angularSlop','b2_linearSlop','b2_maxPairs','b2_maxProxies','b2_maxPolygonVertices', 'b2_maxManifoldPoints','b2_pi') def b2PythonComputeCentroid(pd): """ Computes the centroid of the polygon shape definition, pd. Raises ValueError on an invalid vertex count or a small area. Ported from the Box2D C++ code. """ count = pd.vertexCount if count < 3: raise ValueError("ComputeCentroid: vertex count < 3") c = b2Vec2(0.0, 0.0) area = 0.0 # pRef is the reference point for forming triangles. # It's location doesn't change the result (except for rounding error). pRef = b2Vec2(0.0, 0.0) inv3 = 1.0 / 3.0 for i in range(count): # Triangle vertices. p1 = pRef p2 = pd.getVertex(i) if i + 1 < count: p3 = pd.getVertex(i+1) else: p3 = pd.getVertex(0) e1 = p2 - p1 e2 = p3 - p1 D = b2Cross(e1, e2) triangleArea = 0.5 * D area += triangleArea # Area weighted centroid c += triangleArea * inv3 * (p1 + p2 + p3) # Centroid if area <= FLT_EPSILON: raise ValueError("ComputeCentroid: area <= FLT_EPSILON") return c / area %} /* Some final naming cleanups, for as of yet unused/unsupported classes */ //b2PairManager %rename(broadPhase) b2PairManager::m_broadPhase; %rename(callback) b2PairManager::m_callback; %rename(pairs) b2PairManager::m_pairs; %rename(freePair) b2PairManager::m_freePair; %rename(pairCount) b2PairManager::m_pairCount; %rename(pairBuffer) b2PairManager::m_pairBuffer; %rename(pairBufferCount) b2PairManager::m_pairBufferCount; %rename(hashTable) b2PairManager::m_hashTable; //b2BroadPhase %rename(pairManager) b2BroadPhase::m_pairManager; %rename(proxyPool) b2BroadPhase::m_proxyPool; %rename(freeProxy) b2BroadPhase::m_freeProxy; %rename(bounds) b2BroadPhase::m_bounds; %rename(queryResults) b2BroadPhase::m_queryResults; %rename(querySortKeys) b2BroadPhase::m_querySortKeys; %rename(queryResultCount) b2BroadPhase::m_queryResultCount; %rename(worldAABB) b2BroadPhase::m_worldAABB; %rename(quantizationFactor) b2BroadPhase::m_quantizationFactor; %rename(proxyCount) b2BroadPhase::m_proxyCount; %rename(timeStamp) b2BroadPhase::m_timeStamp; //b2Contact %rename(flags) b2Contact::m_flags; %rename(manifoldCount) b2Contact::m_manifoldCount; %rename(prev) b2Contact::m_prev; %rename(next) b2Contact::m_next; %rename(node1) b2Contact::m_node1; %rename(node2) b2Contact::m_node2; %rename(shape1) b2Contact::m_shape1; %rename(shape2) b2Contact::m_shape2; %rename(toi) b2Contact::m_toi; //b2ContactManager %rename(world) b2ContactManager::m_world; %rename(nullContact) b2ContactManager::m_nullContact; %rename(destroyImmediate) b2ContactManager::m_destroyImmediate; %include "Box2D/Box2D_deprecated.i" #endif %include "Box2D/Box2D.h" python-box2d-2.0.2+svn20100109.244/Box2D/Box2D_userdata.i0000644000000000000000000001513011144324535020375 0ustar rootroot/* * Python SWIG interface file for Box2D (www.box2d.org) * * Copyright (c) 2008 kne / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ /* Note: Given that we have a definition (b2BodyDef) that takes the userData, then passes it onto the factory output (b2Body) upon creation, it's necessary to intercept the CreateBody/Joint/Shape functions to increase the refcount for each of those functions. And upon being destroyed, the userData refcount must be decreased. */ %extend b2World { public: b2Body* CreateBody(b2BodyDef* defn) { b2Body* ret; if (defn) Py_XINCREF((PyObject*)defn->userData); ret=self->CreateBody(defn); return ret; } b2Joint* CreateJoint(b2JointDef* defn) { b2Joint* ret; if (defn) Py_XINCREF((PyObject*)defn->userData); ret=self->CreateJoint(defn); return ret; } void DestroyBody(b2Body* body) { Py_XDECREF((PyObject*)body->GetUserData()); self->DestroyBody(body); } void DestroyJoint(b2Joint* joint) { Py_XDECREF((PyObject*)joint->GetUserData()); self->DestroyJoint(joint); } } %extend b2Body { public: void DestroyShape(b2Shape* shape) { Py_XDECREF((PyObject*)shape->GetUserData()); self->DestroyShape(shape); } b2Shape* CreateShape(b2ShapeDef* defn) { b2Shape* ret; if (defn) Py_XINCREF((PyObject*)defn->userData); ret=self->CreateShape(defn); return ret; } PyObject* GetUserData() { PyObject* ret=(PyObject*)self->GetUserData(); if (!ret) ret=Py_None; Py_XINCREF(ret); return ret; } void SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->GetUserData()); Py_INCREF(data); self->SetUserData(data); } void ClearUserData() { Py_XDECREF((PyObject*)self->GetUserData()); self->SetUserData(NULL); } %pythoncode %{ userData = property(GetUserData, SetUserData) %} } %extend b2Joint { public: PyObject* GetUserData() { PyObject* ret=(PyObject*)self->GetUserData(); if (!ret) ret=Py_None; Py_XINCREF(ret); return ret; } void SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->GetUserData()); Py_INCREF(data); self->SetUserData(data); } void ClearUserData() { Py_XDECREF((PyObject*)self->GetUserData()); self->SetUserData(NULL); } %pythoncode %{ userData = property(GetUserData, SetUserData) %} } %extend b2Shape { public: PyObject* GetUserData() { PyObject* ret=(PyObject*)self->GetUserData(); if (!ret) ret=Py_None; Py_XINCREF(ret); return ret; } void SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->GetUserData()); Py_INCREF(data); self->SetUserData(data); } void ClearUserData() { Py_XDECREF((PyObject*)self->GetUserData()); self->SetUserData(NULL); } %pythoncode %{ userData = property(GetUserData, SetUserData) %} } //Allow access to userData in definitions, with proper destruction %extend b2JointDef { public: PyObject* GetUserData() { PyObject* ret; if (!self->userData) ret=Py_None; else ret=(PyObject*)self->userData; Py_INCREF((PyObject*)ret); return ret; } void SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->userData); Py_INCREF(data); self->userData=(void*)data; } void ClearUserData() { Py_XDECREF((PyObject*)self->userData); self->userData=NULL; } %pythoncode %{ userData = property(GetUserData, SetUserData) def __del__(self): self.ClearUserData() %} } %extend b2BodyDef { public: PyObject* GetUserData() { PyObject* ret; if (!self->userData) ret=Py_None; else ret=(PyObject*)self->userData; Py_INCREF((PyObject*)ret); return ret; } void SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->userData); Py_INCREF(data); self->userData=(void*)data; } void ClearUserData() { Py_XDECREF((PyObject*)self->userData); self->userData=NULL; } %pythoncode %{ userData = property(GetUserData, SetUserData) def __del__(self): self.ClearUserData() %} } %extend b2ShapeDef { public: PyObject* GetUserData() { PyObject* ret; if (!self->userData) ret=Py_None; else ret=(PyObject*)self->userData; Py_INCREF((PyObject*)ret); return ret; } void SetUserData(PyObject* data) { Py_XDECREF((PyObject*)self->userData); Py_INCREF(data); self->userData=(void*)data; } void ClearUserData() { Py_XDECREF((PyObject*)self->userData); self->userData=NULL; } %pythoncode %{ userData = property(GetUserData, SetUserData) def __del__(self): self.ClearUserData() %} } // These renames are intentionally below the above CreateBody, as they will rename the // original C++ versions and not the ones I have written. %ignore SetUserData; %ignore GetUserData; %ignore userData; %newobject b2World::CreateBody; %newobject b2World::CreateJoint; %newobject b2Body::CreateShape; %ignore b2World::CreateBody; %ignore b2World::CreateJoint; %ignore b2Body::CreateShape; %ignore b2World::DestroyBody; %ignore b2World::DestroyJoint; %ignore b2Body::DestroyShape; python-box2d-2.0.2+svn20100109.244/Box2D/pybox2d_license_header.txt0000644000000000000000000000213111151113531022542 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008-2009 Ken Lauer / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # python-box2d-2.0.2+svn20100109.244/Box2D/Box2D_doxygen.i0000644000000000000000000015427311143110234020242 0ustar rootroot%feature("docstring") b2AABB "An axis aligned bounding box."; %feature("docstring") b2AABB::IsValid "Verify that the bounds are sorted."; %feature("docstring") b2Body "A rigid body."; %feature("docstring") b2Body::CreateShape "Creates a shape and attach it to this body. Parameters: ----------- shapeDef: the shape definition. WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::DestroyShape "Destroy a shape. This removes the shape from the broad-phase and therefore destroys any contacts associated with this shape. All shapes attached to a body are implicitly destroyed when the body is destroyed. Parameters: ----------- shape: the shape to be removed. WARNING: This function is locked during callbacks."; %feature("docstring") b2Body::SetMass "Set the mass properties. Note that this changes the center of mass position. If you are not sure how to compute mass properties, use SetMassFromShapes. The inertia tensor is assumed to be relative to the center of mass. Parameters: ----------- massData: the mass properties."; %feature("docstring") b2Body::SetMassFromShapes "Compute the mass properties from the attached shapes. You typically call this after adding all the shapes. If you add or remove shapes later, you may want to call this again. Note that this changes the center of mass position."; %feature("docstring") b2Body::SetXForm "Set the position of the body's origin and rotation (radians). This breaks any contacts and wakes the other bodies. Parameters: ----------- position: the new world position of the body's origin (not necessarily the center of mass). angle: the new world rotation angle of the body in radians. false if the movement put a shape outside the world. In this case the body is automatically frozen."; %feature("docstring") b2Body::GetXForm "Get the body transform for the body's origin. the world transform of the body's origin."; %feature("docstring") b2Body::GetPosition "Get the world body origin position. the world position of the body's origin."; %feature("docstring") b2Body::GetAngle "Get the angle in radians. the current world rotation angle in radians."; %feature("docstring") b2Body::GetLinearDamping "Get the linear damping."; %feature("docstring") b2Body::GetAngularDamping "Get the angular damping."; %feature("docstring") b2Body::GetWorldCenter "Get the world position of the center of mass."; %feature("docstring") b2Body::GetLocalCenter "Get the local position of the center of mass."; %feature("docstring") b2Body::SetLinearVelocity "Set the linear velocity of the center of mass. Parameters: ----------- v: the new linear velocity of the center of mass."; %feature("docstring") b2Body::GetLinearVelocity "Get the linear velocity of the center of mass. the linear velocity of the center of mass."; %feature("docstring") b2Body::SetAngularVelocity "Set the angular velocity. Parameters: ----------- omega: the new angular velocity in radians/second."; %feature("docstring") b2Body::GetAngularVelocity "Get the angular velocity. the angular velocity in radians/second."; %feature("docstring") b2Body::ApplyForce "Apply a force at a world point. If the force is not applied at the center of mass, it will generate a torque and affect the angular velocity. This wakes up the body. Parameters: ----------- force: the world force vector, usually in Newtons (N). point: the world position of the point of application."; %feature("docstring") b2Body::ApplyTorque "Apply a torque. This affects the angular velocity without affecting the linear velocity of the center of mass. This wakes up the body. Parameters: ----------- torque: about the z-axis (out of the screen), usually in N-m."; %feature("docstring") b2Body::ApplyImpulse "Apply an impulse at a point. This immediately modifies the velocity. It also modifies the angular velocity if the point of application is not at the center of mass. This wakes up the body. Parameters: ----------- impulse: the world impulse vector, usually in N-seconds or kg-m/s. point: the world position of the point of application."; %feature("docstring") b2Body::GetMass "Get the total mass of the body. the mass, usually in kilograms (kg)."; %feature("docstring") b2Body::GetInertia "Get the central rotational inertia of the body. the rotational inertia, usually in kg-m^2."; %feature("docstring") b2Body::GetWorldPoint "Get the world coordinates of a point given the local coordinates. Parameters: ----------- localPoint: a point on the body measured relative the the body's origin. the same point expressed in world coordinates."; %feature("docstring") b2Body::GetWorldVector "Get the world coordinates of a vector given the local coordinates. Parameters: ----------- localVector: a vector fixed in the body. the same vector expressed in world coordinates."; %feature("docstring") b2Body::GetLocalPoint "Gets a local point relative to the body's origin given a world point. Parameters: ----------- a: point in world coordinates. the corresponding local point relative to the body's origin."; %feature("docstring") b2Body::GetLocalVector "Gets a local vector given a world vector. Parameters: ----------- a: vector in world coordinates. the corresponding local vector."; %feature("docstring") b2Body::GetLinearVelocityFromWorldPoint "Get the world linear velocity of a world point attached to this body. Parameters: ----------- a: point in world coordinates. the world velocity of a point."; %feature("docstring") b2Body::GetLinearVelocityFromLocalPoint "Get the world velocity of a local point. Parameters: ----------- a: point in local coordinates. the world velocity of a point."; %feature("docstring") b2Body::IsBullet "Is this body treated like a bullet for continuous collision detection?"; %feature("docstring") b2Body::SetBullet "Should this body be treated like a bullet for continuous collision detection?"; %feature("docstring") b2Body::IsStatic "Is this body static (immovable)?"; %feature("docstring") b2Body::IsDynamic "Is this body dynamic (movable)?"; %feature("docstring") b2Body::IsFrozen "Is this body frozen?"; %feature("docstring") b2Body::IsSleeping "Is this body sleeping (not simulating)."; %feature("docstring") b2Body::AllowSleeping "You can disable sleeping on this body."; %feature("docstring") b2Body::CanSleep "Get whether or not this body is allowed to sleep."; %feature("docstring") b2Body::IsRotationFixed "Get whether or not this body is allowed to rotate."; %feature("docstring") b2Body::WakeUp "Wake up this body so it will begin simulating."; %feature("docstring") b2Body::PutToSleep "Put this body to sleep so it will stop simulating. This also sets the velocity to zero."; %feature("docstring") b2Body::GetShapeList "Get the list of all shapes attached to this body."; %feature("docstring") b2Body::GetJointList "Get the list of all joints attached to this body."; %feature("docstring") b2Body::GetControllerList "Get the list of all controllers attached to this body."; %feature("docstring") b2Body::GetNext "Get the next body in the world's body list."; %feature("docstring") b2Body::GetUserData "Get the user data pointer that was provided in the body definition."; %feature("docstring") b2Body::SetUserData "Set the user data. Use this to store your application specific data."; %feature("docstring") b2Body::GetWorld "Get the parent world of this body."; %feature("docstring") b2BodyDef "A body definition holds all the data needed to construct a rigid body. You can safely re-use body definitions."; %feature("docstring") b2BodyDef::b2BodyDef "This constructor sets the body definition default values."; %feature("docstring") b2BoundaryListener "This is called when a body's shape passes outside of the world boundary."; %feature("docstring") b2BoundaryListener::Violation "This is called for each body that leaves the world boundary. WARNING: you can't modify the world inside this callback."; %feature("docstring") b2BuoyancyController "Calculates buoyancy forces for fluids in the form of a half plane."; %feature("docstring") b2BuoyancyController::Step " See: b2Controller.Step"; %feature("docstring") b2BuoyancyController::Draw " See: b2Controller.Draw"; %feature("docstring") b2BuoyancyControllerDef "This class is used to build buoyancy controllers."; %feature("docstring") b2CircleDef "This structure is used to build circle shapes."; %feature("docstring") b2CircleShape "A circle shape."; %feature("docstring") b2CircleShape::TestPoint " See: b2Shape.TestPoint"; %feature("docstring") b2CircleShape::TestSegment " See: b2Shape.TestSegment"; %feature("docstring") b2CircleShape::ComputeAABB " See: b2Shape.ComputeAABB"; %feature("docstring") b2CircleShape::ComputeSweptAABB " See: b2Shape.ComputeSweptAABB"; %feature("docstring") b2CircleShape::ComputeMass " See: b2Shape.ComputeMass"; %feature("docstring") b2CircleShape::ComputeSubmergedArea " See: b2Shape.ComputeSubmergedArea"; %feature("docstring") b2CircleShape::GetLocalPosition "Get the local position of this circle in its parent body."; %feature("docstring") b2CircleShape::GetRadius "Get the radius of this circle."; %feature("docstring") b2Color "Color for debug drawing. Each value has the range [0,1]."; %feature("docstring") b2ConstantAccelController "Applies a force every frame."; %feature("docstring") b2ConstantAccelController::Step " See: b2Controller.Step"; %feature("docstring") b2ConstantAccelControllerDef "This class is used to build constant acceleration controllers."; %feature("docstring") b2ConstantForceController "Applies a force every frame."; %feature("docstring") b2ConstantForceController::Step " See: b2Controller.Step"; %feature("docstring") b2ConstantForceControllerDef "This class is used to build constant force controllers."; %feature("docstring") b2Contact "The class manages contact between two shapes. A contact exists for each overlapping AABB in the broad-phase (except if filtered). Therefore a contact object may exist that has no contact points."; %feature("docstring") b2Contact::GetManifolds "Get the manifold array."; %feature("docstring") b2Contact::GetManifoldCount "Get the number of manifolds. This is 0 or 1 between convex shapes. This may be greater than 1 for convex-vs-concave shapes. Each manifold holds up to two contact points with a shared contact normal."; %feature("docstring") b2Contact::IsSolid "Is this contact solid? true if this contact should generate a response."; %feature("docstring") b2Contact::GetNext "Get the next contact in the world's contact list."; %feature("docstring") b2Contact::GetShape1 "Get the first shape in this contact."; %feature("docstring") b2Contact::GetShape2 "Get the second shape in this contact."; %feature("docstring") b2ContactEdge "A contact edge is used to connect bodies and contacts together in a contact graph where each body is a node and each contact is an edge. A contact edge belongs to a doubly linked list maintained in each attached body. Each contact has two contact nodes, one for each attached body."; %feature("docstring") b2ContactFilter "Implement this class to provide collision filtering. In other words, you can implement this class if you want finer control over contact creation."; %feature("docstring") b2ContactFilter::ShouldCollide "Return true if contact calculations should be performed between these two shapes. WARNING: for performance reasons this is only called when the AABBs begin to overlap."; %feature("docstring") b2ContactFilter::RayCollide "Return true if the given shape should be considered for ray intersection."; %feature("docstring") b2ContactID::Features "The features that intersect to form the contact point."; %feature("docstring") b2ContactListener "Implement this class to get collision results. You can use these results for things like sounds and game logic. You can also get contact results by traversing the contact lists after the time step. However, you might miss some contacts because continuous physics leads to sub-stepping. Additionally you may receive multiple callbacks for the same contact in a single time step. You should strive to make your callbacks efficient because there may be many callbacks per time step. WARNING: The contact separation is the last computed value. You cannot create/destroy Box2D entities inside these callbacks."; %feature("docstring") b2ContactListener::Add "Called when a contact point is added. This includes the geometry and the forces."; %feature("docstring") b2ContactListener::Persist "Called when a contact point persists. This includes the geometry and the forces."; %feature("docstring") b2ContactListener::Remove "Called when a contact point is removed. This includes the last computed geometry and forces."; %feature("docstring") b2ContactListener::Result "Called after a contact point is solved."; %feature("docstring") b2ContactPoint "This structure is used to report contact points."; %feature("docstring") b2ContactResult "This structure is used to report contact point results."; %feature("docstring") b2Controller "Base class for controllers. Controllers are a convience for encapsulating common per-step functionality."; %feature("docstring") b2Controller::Step "Controllers override this to implement per-step functionality."; %feature("docstring") b2Controller::Draw "Controllers override this to provide debug drawing."; %feature("docstring") b2Controller::AddBody "Adds a body to the controller list."; %feature("docstring") b2Controller::RemoveBody "Removes a body from the controller list."; %feature("docstring") b2Controller::Clear "Removes all bodies from the controller list."; %feature("docstring") b2Controller::GetType "Get the type of the controller."; %feature("docstring") b2Controller::GetNext "Get the next controller in the world's body list."; %feature("docstring") b2Controller::GetWorld "Get the parent world of this body."; %feature("docstring") b2Controller::GetBodyList "Get the attached body list."; %feature("docstring") b2ControllerEdge "A controller edge is used to connect bodies and controllers together in a bipartite graph."; %feature("docstring") b2DebugDraw "Implement and register this class with a b2Worldto provide debug drawing of physics entities in your game."; %feature("docstring") b2DebugDraw::SetFlags "Set the drawing flags."; %feature("docstring") b2DebugDraw::GetFlags "Get the drawing flags."; %feature("docstring") b2DebugDraw::AppendFlags "Append flags to the current flags."; %feature("docstring") b2DebugDraw::ClearFlags "Clear flags from the current flags."; %feature("docstring") b2DebugDraw::DrawPolygon "Draw a closed polygon provided in CCW order."; %feature("docstring") b2DebugDraw::DrawSolidPolygon "Draw a solid closed polygon provided in CCW order."; %feature("docstring") b2DebugDraw::DrawCircle "Draw a circle."; %feature("docstring") b2DebugDraw::DrawSolidCircle "Draw a solid circle."; %feature("docstring") b2DebugDraw::DrawSegment "Draw a line segment."; %feature("docstring") b2DebugDraw::DrawXForm "Draw a transform. Choose your own length scale. Parameters: ----------- xf: a transform."; %feature("docstring") b2DestructionListener "Joints and shapes are destroyed when their associated body is destroyed. Implement this listener so that you may nullify references to these joints and shapes."; %feature("docstring") b2DestructionListener::SayGoodbye "Called when any joint is about to be destroyed due to the destruction of one of its attached bodies."; %feature("docstring") b2DestructionListener::SayGoodbye "Called when any shape is about to be destroyed due to the destruction of its parent body."; %feature("docstring") b2DistanceJoint "A distance joint constrains two points on two bodies to remain at a fixed distance from each other. You can view this as a massless, rigid rod."; %feature("docstring") b2DistanceJoint::GetAnchor1 "Get the anchor point on body1 in world coordinates."; %feature("docstring") b2DistanceJoint::GetAnchor2 "Get the anchor point on body2 in world coordinates."; %feature("docstring") b2DistanceJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor."; %feature("docstring") b2DistanceJoint::GetReactionTorque "Get the reaction torque on body2."; %feature("docstring") b2DistanceJointDef "Distance joint definition. This requires defining an anchor point on both bodies and the non-zero length of the distance joint. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. This helps when saving and loading a game. WARNING: Do not use a zero or short length."; %feature("docstring") b2DistanceJointDef::Initialize "Initialize the bodies, anchors, and length using the world anchors."; %feature("docstring") b2EdgeChainDef "This structure is used to build edge shapes."; %feature("docstring") b2EdgeShape "The edge shape."; %feature("docstring") b2EdgeShape::TestPoint " See: b2Shape.TestPoint"; %feature("docstring") b2EdgeShape::TestSegment " See: b2Shape.TestSegment"; %feature("docstring") b2EdgeShape::ComputeAABB " See: b2Shape.ComputeAABB"; %feature("docstring") b2EdgeShape::ComputeSweptAABB " See: b2Shape.ComputeSweptAABB"; %feature("docstring") b2EdgeShape::ComputeMass " See: b2Shape.ComputeMass"; %feature("docstring") b2EdgeShape::ComputeSubmergedArea " WARNING: This only gives a consistent and sensible answer when when summed over a body only contains loops of edges See: b2Shape.ComputeSubmergedArea"; %feature("docstring") b2EdgeShape::GetLength "Linear distance from vertex1 to vertex2:."; %feature("docstring") b2EdgeShape::GetVertex1 "Local position of vertex in parent body."; %feature("docstring") b2EdgeShape::GetVertex2 "Local position of vertex in parent body."; %feature("docstring") b2EdgeShape::GetCoreVertex1 "\"Core\" vertex with TOI slop for b2Distance functions:"; %feature("docstring") b2EdgeShape::GetCoreVertex2 "\"Core\" vertex with TOI slop for b2Distance functions:"; %feature("docstring") b2EdgeShape::GetNormalVector "Perpendicular unit vector point, pointing from the solid side to the empty side:."; %feature("docstring") b2EdgeShape::GetDirectionVector "Parallel unit vector, pointing from vertex1 to vertex2:."; %feature("docstring") b2EdgeShape::GetNextEdge "Get the next edge in the chain."; %feature("docstring") b2EdgeShape::GetPrevEdge "Get the previous edge in the chain."; %feature("docstring") b2FilterData "This holds contact filtering data."; %feature("docstring") b2GearJoint "A gear joint is used to connect two joints together. Either joint can be a revolute or prismatic joint. You specify a gear ratio to bind the motions together: coordinate1 + ratio * coordinate2 = constant The ratio can be negative or positive. If one joint is a revolute joint and the other joint is a prismatic joint, then the ratio will have units of length or units of 1/length. WARNING: The revolute and prismatic joints must be attached to fixed bodies (which must be body1 on those joints)."; %feature("docstring") b2GearJoint::GetAnchor1 "Get the anchor point on body1 in world coordinates."; %feature("docstring") b2GearJoint::GetAnchor2 "Get the anchor point on body2 in world coordinates."; %feature("docstring") b2GearJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor."; %feature("docstring") b2GearJoint::GetReactionTorque "Get the reaction torque on body2."; %feature("docstring") b2GearJoint::GetRatio "Get the gear ratio."; %feature("docstring") b2GearJointDef "Gear joint definition. This definition requires two existing revolute or prismatic joints (any combination will work). The provided joints must attach a dynamic body to a static body."; %feature("docstring") b2GravityController "Applies simplified gravity between every pair of bodies."; %feature("docstring") b2GravityController::Step " See: b2Controller.Step"; %feature("docstring") b2GravityControllerDef "This class is used to build gravity controllers."; %feature("docstring") b2Joint "The base joint class. Joints are used to constraint two bodies together in various fashions. Some joints also feature limits and motors."; %feature("docstring") b2Joint::GetType "Get the type of the concrete joint."; %feature("docstring") b2Joint::GetBody1 "Get the first body attached to this joint."; %feature("docstring") b2Joint::GetBody2 "Get the second body attached to this joint."; %feature("docstring") b2Joint::GetAnchor1 "Get the anchor point on body1 in world coordinates."; %feature("docstring") b2Joint::GetAnchor2 "Get the anchor point on body2 in world coordinates."; %feature("docstring") b2Joint::GetReactionForce "Get the reaction force on body2 at the joint anchor."; %feature("docstring") b2Joint::GetReactionTorque "Get the reaction torque on body2."; %feature("docstring") b2Joint::GetNext "Get the next joint the world joint list."; %feature("docstring") b2Joint::GetUserData "Get the user data pointer."; %feature("docstring") b2Joint::SetUserData "Set the user data pointer."; %feature("docstring") b2Joint::GetCollideConnected "Get whether or not joint bodies can collide."; %feature("docstring") b2JointDef "Joint definitions are used to construct joints."; %feature("docstring") b2JointEdge "A joint edge is used to connect bodies and joints together in a joint graph where each body is a node and each joint is an edge. A joint edge belongs to a doubly linked list maintained in each attached body. Each joint has two joint nodes, one for each attached body."; %feature("docstring") b2LineJoint "A line joint. This joint provides one degree of freedom: translation along an axis fixed in body1. You can use a joint limit to restrict the range of motion and a joint motor to drive the motion or to model joint friction."; %feature("docstring") b2LineJoint::GetAnchor1 "Get the anchor point on body1 in world coordinates."; %feature("docstring") b2LineJoint::GetAnchor2 "Get the anchor point on body2 in world coordinates."; %feature("docstring") b2LineJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor."; %feature("docstring") b2LineJoint::GetReactionTorque "Get the reaction torque on body2."; %feature("docstring") b2LineJoint::GetJointTranslation "Get the current joint translation, usually in meters."; %feature("docstring") b2LineJoint::GetJointSpeed "Get the current joint translation speed, usually in meters per second."; %feature("docstring") b2LineJoint::IsLimitEnabled "Is the joint limit enabled?"; %feature("docstring") b2LineJoint::EnableLimit "Enable/disable the joint limit."; %feature("docstring") b2LineJoint::GetLowerLimit "Get the lower joint limit, usually in meters."; %feature("docstring") b2LineJoint::GetUpperLimit "Get the upper joint limit, usually in meters."; %feature("docstring") b2LineJoint::SetLimits "Set the joint limits, usually in meters."; %feature("docstring") b2LineJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2LineJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2LineJoint::SetMotorSpeed "Set the motor speed, usually in meters per second."; %feature("docstring") b2LineJoint::GetMotorSpeed "Get the motor speed, usually in meters per second."; %feature("docstring") b2LineJoint::SetMaxMotorForce "Set the maximum motor force, usually in N."; %feature("docstring") b2LineJoint::GetMotorForce "Get the current motor force, usually in N."; %feature("docstring") b2LineJointDef "Line joint definition. This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game."; %feature("docstring") b2LineJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; %feature("docstring") b2Manifold "A manifold for two touching convex shapes."; %feature("docstring") b2ManifoldPoint "A manifold point is a contact point belonging to a contact manifold. It holds details related to the geometry and dynamics of the contact points. The point is stored in local coordinates because CCD requires sub-stepping in which the separation is stale."; %feature("docstring") b2MassData "This holds the mass data computed for a shape."; %feature("docstring") b2Mat22 "A 2-by-2 matrix. Stored in column-major order."; %feature("docstring") b2Mat22::b2Mat22 "The default constructor does nothing (for performance)."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using columns."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using scalars."; %feature("docstring") b2Mat22::b2Mat22 "Construct this matrix using an angle. This matrix becomes an orthonormal rotation matrix."; %feature("docstring") b2Mat22::Set "Initialize this matrix using columns."; %feature("docstring") b2Mat22::Set "Initialize this matrix using an angle. This matrix becomes an orthonormal rotation matrix."; %feature("docstring") b2Mat22::SetIdentity "Set this to the identity matrix."; %feature("docstring") b2Mat22::SetZero "Set this matrix to all zeros."; %feature("docstring") b2Mat22::GetAngle "Extract the angle from this matrix (assumed to be a rotation matrix)."; %feature("docstring") b2Mat22::Solve "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; %feature("docstring") b2Mat33 "A 3-by-3 matrix. Stored in column-major order."; %feature("docstring") b2Mat33::b2Mat33 "The default constructor does nothing (for performance)."; %feature("docstring") b2Mat33::b2Mat33 "Construct this matrix using columns."; %feature("docstring") b2Mat33::SetZero "Set this matrix to all zeros."; %feature("docstring") b2Mat33::Solve33 "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases. Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; %feature("docstring") b2Mat33::Solve22 "Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases. Solve only the upper 2-by-2 matrix equation. Solve A * x = b, where b is a column vector. This is more efficient than computing the inverse in one-shot cases."; %feature("docstring") b2MouseJoint "A mouse joint is used to make a point on a body track a specified world point. This a soft constraint with a maximum force. This allows the constraint to stretch and without applying huge forces."; %feature("docstring") b2MouseJoint::GetAnchor1 "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetAnchor2 "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetReactionForce "Implements b2Joint."; %feature("docstring") b2MouseJoint::GetReactionTorque "Implements b2Joint."; %feature("docstring") b2MouseJoint::SetTarget "Use this to update the target point."; %feature("docstring") b2MouseJointDef "Mouse joint definition. This requires a world target point, tuning parameters, and the time step."; %feature("docstring") b2OBB "An oriented bounding box."; %feature("docstring") b2PolygonDef "Convex polygon. The vertices must be in CCW order for a right-handed coordinate system with the z-axis coming out of the screen."; %feature("docstring") b2PolygonDef::SetAsBox "Build vertices to represent an axis-aligned box. Parameters: ----------- hx: the half-width. hy: the half-height."; %feature("docstring") b2PolygonDef::SetAsBox "Build vertices to represent an oriented box. Parameters: ----------- hx: the half-width. hy: the half-height. center: the center of the box in local coordinates. angle: the rotation of the box in local coordinates."; %feature("docstring") b2PolygonShape "A convex polygon."; %feature("docstring") b2PolygonShape::TestPoint " See: b2Shape.TestPoint"; %feature("docstring") b2PolygonShape::TestSegment " See: b2Shape.TestSegment"; %feature("docstring") b2PolygonShape::ComputeAABB " See: b2Shape.ComputeAABB"; %feature("docstring") b2PolygonShape::ComputeSweptAABB " See: b2Shape.ComputeSweptAABB"; %feature("docstring") b2PolygonShape::ComputeMass " See: b2Shape.ComputeMass"; %feature("docstring") b2PolygonShape::ComputeSubmergedArea " See: b2Shape.ComputeSubmergedArea"; %feature("docstring") b2PolygonShape::GetOBB "Get the oriented bounding box relative to the parent body."; %feature("docstring") b2PolygonShape::GetCentroid "Get local centroid relative to the parent body."; %feature("docstring") b2PolygonShape::GetVertexCount "Get the vertex count."; %feature("docstring") b2PolygonShape::GetVertices "Get the vertices in local coordinates."; %feature("docstring") b2PolygonShape::GetCoreVertices "Get the core vertices in local coordinates. These vertices represent a smaller polygon that is used for time of impact computations."; %feature("docstring") b2PolygonShape::GetNormals "Get the edge normal vectors. There is one for each vertex."; %feature("docstring") b2PolygonShape::GetFirstVertex "Get the first vertex and apply the supplied transform."; %feature("docstring") b2PolygonShape::Centroid "Get the centroid and apply the supplied transform."; %feature("docstring") b2PolygonShape::Support "Get the support point in the given world direction. Use the supplied transform."; %feature("docstring") b2PrismaticJoint "A prismatic joint. This joint provides one degree of freedom: translation along an axis fixed in body1. Relative rotation is prevented. You can use a joint limit to restrict the range of motion and a joint motor to drive the motion or to model joint friction."; %feature("docstring") b2PrismaticJoint::GetAnchor1 "Get the anchor point on body1 in world coordinates."; %feature("docstring") b2PrismaticJoint::GetAnchor2 "Get the anchor point on body2 in world coordinates."; %feature("docstring") b2PrismaticJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor."; %feature("docstring") b2PrismaticJoint::GetReactionTorque "Get the reaction torque on body2."; %feature("docstring") b2PrismaticJoint::GetJointTranslation "Get the current joint translation, usually in meters."; %feature("docstring") b2PrismaticJoint::GetJointSpeed "Get the current joint translation speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::IsLimitEnabled "Is the joint limit enabled?"; %feature("docstring") b2PrismaticJoint::EnableLimit "Enable/disable the joint limit."; %feature("docstring") b2PrismaticJoint::GetLowerLimit "Get the lower joint limit, usually in meters."; %feature("docstring") b2PrismaticJoint::GetUpperLimit "Get the upper joint limit, usually in meters."; %feature("docstring") b2PrismaticJoint::SetLimits "Set the joint limits, usually in meters."; %feature("docstring") b2PrismaticJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2PrismaticJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2PrismaticJoint::SetMotorSpeed "Set the motor speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::GetMotorSpeed "Get the motor speed, usually in meters per second."; %feature("docstring") b2PrismaticJoint::SetMaxMotorForce "Set the maximum motor force, usually in N."; %feature("docstring") b2PrismaticJoint::GetMotorForce "Get the current motor force, usually in N."; %feature("docstring") b2PrismaticJointDef "Prismatic joint definition. This requires defining a line of motion using an axis and an anchor point. The definition uses local anchor points and a local axis so that the initial configuration can violate the constraint slightly. The joint translation is zero when the local anchor points coincide in world space. Using local anchors and a local axis helps when saving and loading a game."; %feature("docstring") b2PrismaticJointDef::Initialize "Initialize the bodies, anchors, axis, and reference angle using the world anchor and world axis."; %feature("docstring") b2PulleyJoint "The pulley joint is connected to two bodies and two fixed ground points. The pulley supports a ratio such that: length1 + ratio * length2 <= constant Yes, the force transmitted is scaled by the ratio. The pulley also enforces a maximum length limit on both sides. This is useful to prevent one side of the pulley hitting the top."; %feature("docstring") b2PulleyJoint::GetAnchor1 "Get the anchor point on body1 in world coordinates."; %feature("docstring") b2PulleyJoint::GetAnchor2 "Get the anchor point on body2 in world coordinates."; %feature("docstring") b2PulleyJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor."; %feature("docstring") b2PulleyJoint::GetReactionTorque "Get the reaction torque on body2."; %feature("docstring") b2PulleyJoint::GetGroundAnchor1 "Get the first ground anchor."; %feature("docstring") b2PulleyJoint::GetGroundAnchor2 "Get the second ground anchor."; %feature("docstring") b2PulleyJoint::GetLength1 "Get the current length of the segment attached to body1."; %feature("docstring") b2PulleyJoint::GetLength2 "Get the current length of the segment attached to body2."; %feature("docstring") b2PulleyJoint::GetRatio "Get the pulley ratio."; %feature("docstring") b2PulleyJointDef "Pulley joint definition. This requires two ground anchors, two dynamic body anchor points, max lengths for each side, and a pulley ratio."; %feature("docstring") b2PulleyJointDef::Initialize "Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors."; %feature("docstring") b2RevoluteJoint "A revolute joint constrains to bodies to share a common point while they are free to rotate about the point. The relative rotation about the shared point is the joint angle. You can limit the relative rotation with a joint limit that specifies a lower and upper angle. You can use a motor to drive the relative rotation about the shared point. A maximum motor torque is provided so that infinite forces are not generated."; %feature("docstring") b2RevoluteJoint::GetAnchor1 "Get the anchor point on body1 in world coordinates."; %feature("docstring") b2RevoluteJoint::GetAnchor2 "Get the anchor point on body2 in world coordinates."; %feature("docstring") b2RevoluteJoint::GetReactionForce "Get the reaction force on body2 at the joint anchor."; %feature("docstring") b2RevoluteJoint::GetReactionTorque "Get the reaction torque on body2."; %feature("docstring") b2RevoluteJoint::GetJointAngle "Get the current joint angle in radians."; %feature("docstring") b2RevoluteJoint::GetJointSpeed "Get the current joint angle speed in radians per second."; %feature("docstring") b2RevoluteJoint::IsLimitEnabled "Is the joint limit enabled?"; %feature("docstring") b2RevoluteJoint::EnableLimit "Enable/disable the joint limit."; %feature("docstring") b2RevoluteJoint::GetLowerLimit "Get the lower joint limit in radians."; %feature("docstring") b2RevoluteJoint::GetUpperLimit "Get the upper joint limit in radians."; %feature("docstring") b2RevoluteJoint::SetLimits "Set the joint limits in radians."; %feature("docstring") b2RevoluteJoint::IsMotorEnabled "Is the joint motor enabled?"; %feature("docstring") b2RevoluteJoint::EnableMotor "Enable/disable the joint motor."; %feature("docstring") b2RevoluteJoint::SetMotorSpeed "Set the motor speed in radians per second."; %feature("docstring") b2RevoluteJoint::GetMotorSpeed "Get the motor speed in radians per second."; %feature("docstring") b2RevoluteJoint::SetMaxMotorTorque "Set the maximum motor torque, usually in N-m."; %feature("docstring") b2RevoluteJoint::GetMotorTorque "Get the current motor torque, usually in N-m."; %feature("docstring") b2RevoluteJointDef "Revolute joint definition. This requires defining an anchor point where the bodies are joined. The definition uses local anchor points so that the initial configuration can violate the constraint slightly. You also need to specify the initial relative angle for joint limits. This helps when saving and loading a game. The local anchor points are measured from the body's origin rather than the center of mass because: 1. you might not know where the center of mass will be. 2. if you add/remove shapes from a body and recompute the mass, the joints will be broken."; %feature("docstring") b2RevoluteJointDef::Initialize "Initialize the bodies, anchors, and reference angle using the world anchor."; %feature("docstring") b2Segment "A line segment."; %feature("docstring") b2Segment::TestSegment "Ray cast against this segment with another segment."; %feature("docstring") b2Shape "A shape is used for collision detection. Shapes are created in b2World. You can use shape for collision detection before they are attached to the world. WARNING: you cannot reuse shapes."; %feature("docstring") b2Shape::GetType "Get the type of this shape. You can use this to down cast to the concrete shape. the shape type."; %feature("docstring") b2Shape::IsSensor "Is this shape a sensor (non-solid)? the true if the shape is a sensor."; %feature("docstring") b2Shape::SetFilterData "Set the contact filtering data. You must call b2World::Refilterto correct existing contacts/non-contacts."; %feature("docstring") b2Shape::GetFilterData "Get the contact filtering data."; %feature("docstring") b2Shape::GetBody "Get the parent body of this shape. This is NULL if the shape is not attached. the parent body."; %feature("docstring") b2Shape::GetNext "Get the next shape in the parent body's shape list. the next shape."; %feature("docstring") b2Shape::GetUserData "Get the user data that was assigned in the shape definition. Use this to store your application specific data."; %feature("docstring") b2Shape::SetUserData "Set the user data. Use this to store your application specific data."; %feature("docstring") b2Shape::TestPoint "Test a point for containment in this shape. This only works for convex shapes. Parameters: ----------- xf: the shape world transform. p: a point in world coordinates."; %feature("docstring") b2Shape::TestSegment "Perform a ray cast against this shape. Parameters: ----------- xf: the shape world transform. lambda: returns the hit fraction. You can use this to compute the contact point p = (1 - lambda) * segment.p1 + lambda * segment.p2. normal: returns the normal at the contact point. If there is no intersection, the normal is not set. segment: defines the begin and end point of the ray cast. maxLambda: a number typically in the range [0,1]."; %feature("docstring") b2Shape::ComputeAABB "Given a transform, compute the associated axis aligned bounding box for this shape. Parameters: ----------- aabb: returns the axis aligned box. xf: the world transform of the shape."; %feature("docstring") b2Shape::ComputeSweptAABB "Given two transforms, compute the associated swept axis aligned bounding box for this shape. Parameters: ----------- aabb: returns the axis aligned box. xf1: the starting shape world transform. xf2: the ending shape world transform."; %feature("docstring") b2Shape::ComputeMass "Compute the mass properties of this shape using its dimensions and density. The inertia tensor is computed about the local origin, not the centroid. Parameters: ----------- massData: returns the mass data for this shape."; %feature("docstring") b2Shape::ComputeSubmergedArea "Compute the volume and centroid of this shape intersected with a half plane Parameters: ----------- normal: the surface normal offset: the surface offset along normal xf: the shape transform c: returns the centroid the total volume less than offset along normal"; %feature("docstring") b2Shape::GetSweepRadius "Get the maximum radius about the parent body's center of mass."; %feature("docstring") b2Shape::GetFriction "Get the coefficient of friction."; %feature("docstring") b2Shape::SetFriction "Set the coefficient of friction."; %feature("docstring") b2Shape::GetRestitution "Get the coefficient of restitution."; %feature("docstring") b2Shape::SetRestitution "Set the coefficient of restitution."; %feature("docstring") b2Shape::GetDensity "Get the density of the shape."; %feature("docstring") b2Shape::SetDensity "Set the density of the shape."; %feature("docstring") b2ShapeDef "A shape definition is used to construct a shape. This class defines an abstract shape definition. You can reuse shape definitions safely."; %feature("docstring") b2ShapeDef::b2ShapeDef "The constructor sets the default shape definition values."; %feature("docstring") b2Sweep "This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin, which may no coincide with the center of mass. However, to support dynamics we must interpolate the center of mass position."; %feature("docstring") b2Sweep::GetXForm "Get the interpolated transform at a specific time. Parameters: ----------- t: the normalized time in [0,1]."; %feature("docstring") b2Sweep::Advance "Advance the sweep forward, yielding a new initial state. Parameters: ----------- t: the new initial time."; %feature("docstring") b2TensorDampingController "Applies top down linear damping to the controlled bodies The damping is calculated by multiplying velocity by a matrix in local co-ordinates."; %feature("docstring") b2TensorDampingController::Step " See: b2Controller.Step"; %feature("docstring") b2TensorDampingControllerDef "This class is used to build tensor damping controllers."; %feature("docstring") b2TensorDampingControllerDef::SetAxisAligned "Sets damping independantly along the x and y axes."; %feature("docstring") b2Vec2 "A 2D column vector."; %feature("docstring") b2Vec2::b2Vec2 "Default constructor does nothing (for performance)."; %feature("docstring") b2Vec2::b2Vec2 "Construct using coordinates."; %feature("docstring") b2Vec2::SetZero "Set this vector to all zeros."; %feature("docstring") b2Vec2::Set "Set this vector to some specified coordinates."; %feature("docstring") b2Vec2::Length "Get the length of this vector (the norm)."; %feature("docstring") b2Vec2::LengthSquared "Get the length squared. For performance, use this instead of b2Vec2::Length(if possible)."; %feature("docstring") b2Vec2::Normalize "Convert this vector into a unit vector. Returns the length."; %feature("docstring") b2Vec2::IsValid "Does this vector contain finite coordinates?"; %feature("docstring") b2Vec3 "A 2D column vector with 3 elements."; %feature("docstring") b2Vec3::b2Vec3 "Default constructor does nothing (for performance)."; %feature("docstring") b2Vec3::b2Vec3 "Construct using coordinates."; %feature("docstring") b2Vec3::SetZero "Set this vector to all zeros."; %feature("docstring") b2Vec3::Set "Set this vector to some specified coordinates."; %feature("docstring") b2Version "Version numbering scheme. See http://en.wikipedia.org/wiki/Software_versioning"; %feature("docstring") b2World "The world class manages all physics entities, dynamic simulation, and asynchronous queries. The world also contains efficient memory management facilities."; %feature("docstring") b2World::b2World "Construct a world object. Parameters: ----------- worldAABB: a bounding box that completely encompasses all your shapes. gravity: the world gravity vector. doSleep: improve performance by not simulating inactive bodies."; %feature("docstring") b2World::~b2World "Destruct the world. All physics entities are destroyed and all heap memory is released."; %feature("docstring") b2World::SetDestructionListener "Register a destruction listener."; %feature("docstring") b2World::SetBoundaryListener "Register a broad-phase boundary listener."; %feature("docstring") b2World::SetContactFilter "Register a contact filter to provide specific control over collision. Otherwise the default filter is used (b2_defaultFilter)."; %feature("docstring") b2World::SetContactListener "Register a contact event listener."; %feature("docstring") b2World::SetDebugDraw "Register a routine for debug drawing. The debug draw functions are called inside the b2World::Stepmethod, so make sure your renderer is ready to consume draw commands when you call Step()."; %feature("docstring") b2World::CreateBody "Create a rigid body given a definition. No reference to the definition is retained. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::DestroyBody "Destroy a rigid body given a definition. No reference to the definition is retained. This function is locked during callbacks. WARNING: This automatically deletes all associated shapes and joints. This function is locked during callbacks."; %feature("docstring") b2World::CreateJoint "Create a joint to constrain bodies together. No reference to the definition is retained. This may cause the connected bodies to cease colliding. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::DestroyJoint "Destroy a joint. This may cause the connected bodies to begin colliding. WARNING: This function is locked during callbacks."; %feature("docstring") b2World::CreateController "Add a controller to the world."; %feature("docstring") b2World::DestroyController "Removes a controller from the world."; %feature("docstring") b2World::GetGroundBody "The world provides a single static ground body with no collision shapes. You can use this to simplify the creation of joints and static shapes."; %feature("docstring") b2World::Step "Take a time step. This performs collision detection, integration, and constraint solution. Parameters: ----------- timeStep: the amount of time to simulate, this should not vary. velocityIterations: for the velocity constraint solver. positionIterations: for the position constraint solver."; %feature("docstring") b2World::Query "Query the world for all shapes that potentially overlap the provided AABB. You provide a shape pointer buffer of specified size. The number of shapes found is returned. Parameters: ----------- aabb: the query box. shapes: a user allocated shape pointer array of size maxCount (or greater). maxCount: the capacity of the shapes array. the number of shapes found in aabb."; %feature("docstring") b2World::Raycast "Query the world for all shapes that intersect a given segment. You provide a shape pointer buffer of specified size. The number of shapes found is returned, and the buffer is filled in order of intersection Parameters: ----------- segment: defines the begin and end point of the ray cast, from p1 to p2. Use b2Segment.Extend to create (semi-)infinite rays shapes: a user allocated shape pointer array of size maxCount (or greater). maxCount: the capacity of the shapes array solidShapes: determines if shapes that the ray starts in are counted as hits. userData: passed through the worlds contact filter, with method RayCollide. This can be used to filter valid shapes the number of shapes found"; %feature("docstring") b2World::RaycastOne "Performs a raycast as with Raycast, finding the first intersecting shape. Parameters: ----------- segment: defines the begin and end point of the ray cast, from p1 to p2. Use b2Segment.Extend to create (semi-)infinite rays lambda: returns the hit fraction. You can use this to compute the contact point p = (1 - lambda) * segment.p1 + lambda * segment.p2. normal: returns the normal at the contact point. If there is no intersection, the normal is not set. solidShapes: determines if shapes that the ray starts in are counted as hits. the colliding shape shape, or null if not found"; %feature("docstring") b2World::InRange "Check if the AABB is within the broadphase limits."; %feature("docstring") b2World::GetBodyList "Get the world body list. With the returned body, use b2Body::GetNextto get the next body in the world list. A NULL body indicates the end of the list. the head of the world body list."; %feature("docstring") b2World::GetJointList "Get the world joint list. With the returned joint, use b2Joint::GetNextto get the next joint in the world list. A NULL joint indicates the end of the list. the head of the world joint list."; %feature("docstring") b2World::GetControllerList "Get the world controller list. With the returned controller, use b2Controller::GetNextto get the next controller in the world list. A NULL controller indicates the end of the list. the head of the world controller list."; %feature("docstring") b2World::Refilter "Re-filter a shape. This re-runs contact filtering on a shape."; %feature("docstring") b2World::SetWarmStarting "Enable/disable warm starting. For testing."; %feature("docstring") b2World::SetContinuousPhysics "Enable/disable continuous physics. For testing."; %feature("docstring") b2World::Validate "Perform validation of internal data structures."; %feature("docstring") b2World::GetProxyCount "Get the number of broad-phase proxies."; %feature("docstring") b2World::GetPairCount "Get the number of broad-phase pairs."; %feature("docstring") b2World::GetBodyCount "Get the number of bodies."; %feature("docstring") b2World::GetJointCount "Get the number of joints."; %feature("docstring") b2World::GetContactCount "Get the number of contacts (each may have 0 or more contact points)."; %feature("docstring") b2World::GetControllerCount "Get the number of controllers."; %feature("docstring") b2World::SetGravity "Change the global gravity vector."; %feature("docstring") b2World::GetGravity "Get the global gravity vector."; %feature("docstring") b2World::GetWorldAABB "Get the world's AABB."; %feature("docstring") b2World::CanSleep "Whether or not bodies can sleep."; %feature("docstring") b2XForm "A transform contains translation and rotation. It is used to represent the position and orientation of rigid frames."; %feature("docstring") b2XForm::b2XForm "The default constructor does nothing (for performance)."; %feature("docstring") b2XForm::b2XForm "Initialize using a position vector and a rotation matrix."; %feature("docstring") b2XForm::SetIdentity "Set this to the identity transform."; %feature("docstring") b2CollideCircles "Compute the collision manifold between two circles."; %feature("docstring") b2CollidePolygonAndCircle "Compute the collision manifold between a polygon and a circle."; %feature("docstring") b2CollidePolygons "Compute the collision manifold between two circles."; %feature("docstring") b2CollideCircles "Compute the collision manifold between two circles."; %feature("docstring") b2CollidePolygonAndCircle "Compute the collision manifold between a polygon and a circle."; %feature("docstring") b2CollidePolygons "Compute the collision manifold between two circles."; %feature("docstring") b2Distance "Compute the distance between two shapes and the closest points. the distance between the shapes or zero if they are overlapped/touching."; %feature("docstring") b2TimeOfImpact "Compute the time when two shapes begin to touch or touch at a closer distance. WARNING: the sweeps must have the same time interval. the fraction between [0,1] in which the shapes first touch. fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch."; %feature("docstring") b2Distance "Compute the distance between two shapes and the closest points. the distance between the shapes or zero if they are overlapped/touching."; %feature("docstring") b2TimeOfImpact "Compute the time when two shapes begin to touch or touch at a closer distance. WARNING: the sweeps must have the same time interval. the fraction between [0,1] in which the shapes first touch. fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch."; %feature("docstring") b2IsValid "This function is used to ensure that a floating point number is not a NaN or infinity."; %feature("docstring") b2InvSqrt "This is a approximate yet fast inverse square-root."; %feature("docstring") b2Dot "Peform the dot product on two vectors."; %feature("docstring") b2Cross "Perform the cross product on two vectors. In 2D this produces a scalar."; %feature("docstring") b2Cross "Perform the cross product on a vector and a scalar. In 2D this produces a vector."; %feature("docstring") b2Cross "Perform the cross product on a scalar and a vector. In 2D this produces a vector."; %feature("docstring") b2Mul "Multiply a matrix times a vector. If a rotation matrix is provided, then this transforms the vector from one frame to another."; %feature("docstring") b2MulT "Multiply a matrix transpose times a vector. If a rotation matrix is provided, then this transforms the vector from one frame to another (inverse transform)."; %feature("docstring") b2Dot "Perform the dot product on two vectors."; %feature("docstring") b2Cross "Perform the cross product on two vectors."; %feature("docstring") b2Mul "Multiply a matrix times a vector."; %feature("docstring") b2Random "Random floating point number in range [lo, hi]. With no arguments, returns one in -1,1."; %feature("docstring") b2NextPowerOfTwo "\"Next Largest Power of 2 Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm that recursively \"folds\" the upper bits into the lower bits. This process yields a bit vector with the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next largest power of 2. For a 32-bit value:\""; %feature("docstring") b2Alloc "Implement this function to use your own memory allocator."; %feature("docstring") b2Free "If you implement b2Alloc, you should also implement this function."; %feature("docstring") b2Alloc "Implement this function to use your own memory allocator."; %feature("docstring") b2Free "If you implement b2Alloc, you should also implement this function."; %feature("docstring") b2MixFriction "Friction mixing law. Feel free to customize this."; %feature("docstring") b2MixRestitution "Restitution mixing law. Feel free to customize this."; python-box2d-2.0.2+svn20100109.244/Box2D/Collision/0000755000000000000000000000000011414467242017353 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2BroadPhase.h0000644000000000000000000001205211064106301021743 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_BROAD_PHASE_H #define B2_BROAD_PHASE_H /* This broad phase uses the Sweep and Prune algorithm as described in: Collision Detection in Interactive 3D Environments by Gino van den Bergen Also, some ideas, such as using integral values for fast compares comes from Bullet (http:/www.bulletphysics.com). */ #include "../Common/b2Settings.h" #include "b2Collision.h" #include "b2PairManager.h" #include #ifdef TARGET_FLOAT32_IS_FIXED #define B2BROADPHASE_MAX (USHRT_MAX/2) #else #define B2BROADPHASE_MAX USHRT_MAX #endif const uint16 b2_invalid = B2BROADPHASE_MAX; const uint16 b2_nullEdge = B2BROADPHASE_MAX; struct b2BoundValues; struct b2Bound { bool IsLower() const { return (value & 1) == 0; } bool IsUpper() const { return (value & 1) == 1; } uint16 value; uint16 proxyId; uint16 stabbingCount; }; struct b2Proxy { uint16 GetNext() const { return lowerBounds[0]; } void SetNext(uint16 next) { lowerBounds[0] = next; } bool IsValid() const { return overlapCount != b2_invalid; } uint16 lowerBounds[2], upperBounds[2]; uint16 overlapCount; uint16 timeStamp; void* userData; }; typedef float32 (*SortKeyFunc)(void* shape); class b2BroadPhase { public: b2BroadPhase(const b2AABB& worldAABB, b2PairCallback* callback); ~b2BroadPhase(); // Use this to see if your proxy is in range. If it is not in range, // it should be destroyed. Otherwise you may get O(m^2) pairs, where m // is the number of proxies that are out of range. bool InRange(const b2AABB& aabb) const; // Create and destroy proxies. These call Flush first. uint16 CreateProxy(const b2AABB& aabb, void* userData); void DestroyProxy(int32 proxyId); // Call MoveProxy as many times as you like, then when you are done // call Commit to finalized the proxy pairs (for your time step). void MoveProxy(int32 proxyId, const b2AABB& aabb); void Commit(); // Get a single proxy. Returns NULL if the id is invalid. b2Proxy* GetProxy(int32 proxyId); // Query an AABB for overlapping proxies, returns the user data and // the count, up to the supplied maximum count. int32 Query(const b2AABB& aabb, void** userData, int32 maxCount); // Query a segment for overlapping proxies, returns the user data and // the count, up to the supplied maximum count. // If sortKey is provided, then it is a function mapping from proxy userDatas to distances along the segment (between 0 & 1) // Then the returned proxies are sorted on that, before being truncated to maxCount // The sortKey of a proxy is assumed to be larger than the closest point inside the proxy along the segment, this allows for early exits // Proxies with a negative sortKey are discarded int32 QuerySegment(const b2Segment& segment, void** userData, int32 maxCount, SortKeyFunc sortKey); void Validate(); void ValidatePairs(); private: void ComputeBounds(uint16* lowerValues, uint16* upperValues, const b2AABB& aabb); bool TestOverlap(b2Proxy* p1, b2Proxy* p2); bool TestOverlap(const b2BoundValues& b, b2Proxy* p); void Query(int32* lowerIndex, int32* upperIndex, uint16 lowerValue, uint16 upperValue, b2Bound* bounds, int32 boundCount, int32 axis); void IncrementOverlapCount(int32 proxyId); void IncrementTimeStamp(); void AddProxyResult(uint16 proxyId, b2Proxy* proxy, int32 maxCount, SortKeyFunc sortKey); public: friend class b2PairManager; b2PairManager m_pairManager; b2Proxy m_proxyPool[b2_maxProxies]; uint16 m_freeProxy; b2Bound m_bounds[2][2*b2_maxProxies]; uint16 m_queryResults[b2_maxProxies]; float32 m_querySortKeys[b2_maxProxies]; int32 m_queryResultCount; b2AABB m_worldAABB; b2Vec2 m_quantizationFactor; int32 m_proxyCount; uint16 m_timeStamp; static bool s_validate; }; inline bool b2BroadPhase::InRange(const b2AABB& aabb) const { b2Vec2 d = b2Max(aabb.lowerBound - m_worldAABB.upperBound, m_worldAABB.lowerBound - aabb.upperBound); return b2Max(d.x, d.y) < 0.0f; } inline b2Proxy* b2BroadPhase::GetProxy(int32 proxyId) { if (proxyId == b2_nullProxy || m_proxyPool[proxyId].IsValid() == false) { return NULL; } return m_proxyPool + proxyId; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/0000755000000000000000000000000011414467242020576 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2EdgeShape.cpp0000644000000000000000000001225411130023047023341 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2EdgeShape.h" b2EdgeShape::b2EdgeShape(const b2Vec2& v1, const b2Vec2& v2, const b2ShapeDef* def) : b2Shape(def) { b2Assert(def->type == e_edgeShape); m_type = e_edgeShape; m_prevEdge = NULL; m_nextEdge = NULL; m_v1 = v1; m_v2 = v2; m_direction = m_v2 - m_v1; m_length = m_direction.Normalize(); m_normal.Set(m_direction.y, -m_direction.x); m_coreV1 = -b2_toiSlop * (m_normal - m_direction) + m_v1; m_coreV2 = -b2_toiSlop * (m_normal + m_direction) + m_v2; m_cornerDir1 = m_normal; m_cornerDir2 = -1.0f * m_normal; } void b2EdgeShape::UpdateSweepRadius(const b2Vec2& center) { // Update the sweep radius (maximum radius) as measured from // a local center point. b2Vec2 d = m_coreV1 - center; float32 d1 = b2Dot(d,d); d = m_coreV2 - center; float32 d2 = b2Dot(d,d); m_sweepRadius = b2Sqrt(d1 > d2 ? d1 : d2); } bool b2EdgeShape::TestPoint(const b2XForm& transform, const b2Vec2& p) const { B2_NOT_USED(transform); B2_NOT_USED(p); return false; } b2SegmentCollide b2EdgeShape::TestSegment(const b2XForm& transform, float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const { b2Vec2 r = segment.p2 - segment.p1; b2Vec2 v1 = b2Mul(transform, m_v1); b2Vec2 d = b2Mul(transform, m_v2) - v1; b2Vec2 n = b2Cross(d, 1.0f); const float32 k_slop = 100.0f * B2_FLT_EPSILON; float32 denom = -b2Dot(r, n); // Cull back facing collision and ignore parallel segments. if (denom > k_slop) { // Does the segment intersect the infinite line associated with this segment? b2Vec2 b = segment.p1 - v1; float32 a = b2Dot(b, n); if (0.0f <= a && a <= maxLambda * denom) { float32 mu2 = -r.x * b.y + r.y * b.x; // Does the segment intersect this segment? if (-k_slop * denom <= mu2 && mu2 <= denom * (1.0f + k_slop)) { a /= denom; n.Normalize(); *lambda = a; *normal = n; return e_hitCollide; } } } return e_missCollide; } void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2XForm& transform) const { b2Vec2 v1 = b2Mul(transform, m_v1); b2Vec2 v2 = b2Mul(transform, m_v2); aabb->lowerBound = b2Min(v1, v2); aabb->upperBound = b2Max(v1, v2); } void b2EdgeShape::ComputeSweptAABB(b2AABB* aabb, const b2XForm& transform1, const b2XForm& transform2) const { b2Vec2 v1 = b2Mul(transform1, m_v1); b2Vec2 v2 = b2Mul(transform1, m_v2); b2Vec2 v3 = b2Mul(transform2, m_v1); b2Vec2 v4 = b2Mul(transform2, m_v2); aabb->lowerBound = b2Min(b2Min(b2Min(v1, v2), v3), v4); aabb->upperBound = b2Max(b2Max(b2Max(v1, v2), v3), v4); } void b2EdgeShape::ComputeMass(b2MassData* massData) const { massData->mass = 0; massData->center = m_v1; // inertia about the local origin massData->I = 0; } b2Vec2 b2EdgeShape::Support(const b2XForm& xf, const b2Vec2& d) const { b2Vec2 v1 = b2Mul(xf, m_coreV1); b2Vec2 v2 = b2Mul(xf, m_coreV2); return b2Dot(v1, d) > b2Dot(v2, d) ? v1 : v2; } void b2EdgeShape::SetPrevEdge(b2EdgeShape* edge, const b2Vec2& core, const b2Vec2& cornerDir, bool convex) { m_prevEdge = edge; m_coreV1 = core; m_cornerDir1 = cornerDir; m_cornerConvex1 = convex; } void b2EdgeShape::SetNextEdge(b2EdgeShape* edge, const b2Vec2& core, const b2Vec2& cornerDir, bool convex) { m_nextEdge = edge; m_coreV2 = core; m_cornerDir2 = cornerDir; m_cornerConvex2 = convex; } float32 b2EdgeShape::ComputeSubmergedArea( const b2Vec2& normal, float32 offset, const b2XForm& xf, b2Vec2* c) const { //Note that v0 is independant of any details of the specific edge //We are relying on v0 being consistent between multiple edges of the same body b2Vec2 v0 = offset * normal; //b2Vec2 v0 = xf.position + (offset - b2Dot(normal, xf.position)) * normal; b2Vec2 v1 = b2Mul(xf, m_v1); b2Vec2 v2 = b2Mul(xf, m_v2); float32 d1 = b2Dot(normal, v1) - offset; float32 d2 = b2Dot(normal, v2) - offset; if(d1>0) { if(d2>0) { return 0; } else { v1 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2; } } else { if(d2>0) { v2 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2; } else { //Nothing } } // v0,v1,v2 represents a fully submerged triangle float32 k_inv3 = 1.0f / 3.0f; // Area weighted centroid *c = k_inv3 * (v0 + v1 + v2); b2Vec2 e1 = v1 - v0; b2Vec2 e2 = v2 - v0; return 0.5f * b2Cross(e1, e2); }python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2CircleShape.h0000644000000000000000000000522111077704466023364 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CIRCLE_SHAPE_H #define B2_CIRCLE_SHAPE_H #include "b2Shape.h" /// This structure is used to build circle shapes. struct b2CircleDef : public b2ShapeDef { b2CircleDef() { type = e_circleShape; localPosition.SetZero(); radius = 1.0f; } b2Vec2 localPosition; float32 radius; }; /// A circle shape. class b2CircleShape : public b2Shape { public: /// @see b2Shape::TestPoint bool TestPoint(const b2XForm& transform, const b2Vec2& p) const; /// @see b2Shape::TestSegment b2SegmentCollide TestSegment( const b2XForm& transform, float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const; /// @see b2Shape::ComputeAABB void ComputeAABB(b2AABB* aabb, const b2XForm& transform) const; /// @see b2Shape::ComputeSweptAABB void ComputeSweptAABB( b2AABB* aabb, const b2XForm& transform1, const b2XForm& transform2) const; /// @see b2Shape::ComputeMass void ComputeMass(b2MassData* massData) const; /// @see b2Shape::ComputeSubmergedArea float32 ComputeSubmergedArea( const b2Vec2& normal, float32 offset, const b2XForm& xf, b2Vec2* c) const; /// Get the local position of this circle in its parent body. const b2Vec2& GetLocalPosition() const; /// Get the radius of this circle. float32 GetRadius() const; private: friend class b2Shape; b2CircleShape(const b2ShapeDef* def); void UpdateSweepRadius(const b2Vec2& center); // Local position in parent body b2Vec2 m_localPosition; float32 m_radius; }; inline const b2Vec2& b2CircleShape::GetLocalPosition() const { return m_localPosition; } inline float32 b2CircleShape::GetRadius() const { return m_radius; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2Shape.h0000644000000000000000000002301211154056132022222 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_SHAPE_H #define B2_SHAPE_H #include "../../Common/b2Math.h" #include "../b2Collision.h" class b2BlockAllocator; class b2Body; class b2BroadPhase; /// This holds the mass data computed for a shape. struct b2MassData { /// The mass of the shape, usually in kilograms. float32 mass; /// The position of the shape's centroid relative to the shape's origin. b2Vec2 center; /// The rotational inertia of the shape. float32 I; }; /// This holds contact filtering data. struct b2FilterData { /// The collision category bits. Normally you would just set one bit. uint16 categoryBits; /// The collision mask bits. This states the categories that this /// shape would accept for collision. uint16 maskBits; /// Collision groups allow a certain group of objects to never collide (negative) /// or always collide (positive). Zero means no collision group. Non-zero group /// filtering always wins against the mask bits. int16 groupIndex; }; /// The various collision shape types supported by Box2D. enum b2ShapeType { e_unknownShape = -1, e_circleShape, e_polygonShape, e_edgeShape, e_shapeTypeCount, }; /// Return codes from TestSegment enum b2SegmentCollide { e_startsInsideCollide = -1, e_missCollide = 0, e_hitCollide = 1 }; /// A shape definition is used to construct a shape. This class defines an /// abstract shape definition. You can reuse shape definitions safely. struct b2ShapeDef { /// The constructor sets the default shape definition values. b2ShapeDef() { type = e_unknownShape; userData = NULL; friction = 0.2f; restitution = 0.0f; density = 0.0f; filter.categoryBits = 0x0001; filter.maskBits = 0xFFFF; filter.groupIndex = 0; isSensor = false; } virtual ~b2ShapeDef() {} /// Holds the shape type for down-casting. b2ShapeType type; /// Use this to store application specify shape data. void* userData; /// The shape's friction coefficient, usually in the range [0,1]. float32 friction; /// The shape's restitution (elasticity) usually in the range [0,1]. float32 restitution; /// The shape's density, usually in kg/m^2. float32 density; /// A sensor shape collects contact information but never generates a collision /// response. bool isSensor; /// Contact filtering data. b2FilterData filter; }; /// A shape is used for collision detection. Shapes are created in b2World. /// You can use shape for collision detection before they are attached to the world. /// @warning you cannot reuse shapes. class b2Shape { public: /// Get the type of this shape. You can use this to down cast to the concrete shape. /// @return the shape type. b2ShapeType GetType() const; /// Is this shape a sensor (non-solid)? /// @return the true if the shape is a sensor. bool IsSensor() const; /// Set if this shapes is a sensor. /// You must call b2World::Refilter to update existing contacts. void SetSensor(bool sensor); /// Set the contact filtering data. You must call b2World::Refilter to correct /// existing contacts/non-contacts. void SetFilterData(const b2FilterData& filter); /// Get the contact filtering data. const b2FilterData& GetFilterData() const; /// Get the parent body of this shape. This is NULL if the shape is not attached. /// @return the parent body. b2Body* GetBody(); /// Get the next shape in the parent body's shape list. /// @return the next shape. b2Shape* GetNext(); /// Get the user data that was assigned in the shape definition. Use this to /// store your application specific data. void* GetUserData(); /// Set the user data. Use this to store your application specific data. void SetUserData(void* data); /// Test a point for containment in this shape. This only works for convex shapes. /// @param xf the shape world transform. /// @param p a point in world coordinates. virtual bool TestPoint(const b2XForm& xf, const b2Vec2& p) const = 0; /// Perform a ray cast against this shape. /// @param xf the shape world transform. /// @param lambda returns the hit fraction. You can use this to compute the contact point /// p = (1 - lambda) * segment.p1 + lambda * segment.p2. /// @param normal returns the normal at the contact point. If there is no intersection, the normal /// is not set. /// @param segment defines the begin and end point of the ray cast. /// @param maxLambda a number typically in the range [0,1]. virtual b2SegmentCollide TestSegment( const b2XForm& xf, float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const = 0; /// Given a transform, compute the associated axis aligned bounding box for this shape. /// @param aabb returns the axis aligned box. /// @param xf the world transform of the shape. virtual void ComputeAABB(b2AABB* aabb, const b2XForm& xf) const = 0; /// Given two transforms, compute the associated swept axis aligned bounding box for this shape. /// @param aabb returns the axis aligned box. /// @param xf1 the starting shape world transform. /// @param xf2 the ending shape world transform. virtual void ComputeSweptAABB( b2AABB* aabb, const b2XForm& xf1, const b2XForm& xf2) const = 0; /// Compute the mass properties of this shape using its dimensions and density. /// The inertia tensor is computed about the local origin, not the centroid. /// @param massData returns the mass data for this shape. virtual void ComputeMass(b2MassData* massData) const = 0; /// Compute the volume and centroid of this shape intersected with a half plane /// @param normal the surface normal /// @param offset the surface offset along normal /// @param xf the shape transform /// @param c returns the centroid /// @return the total volume less than offset along normal virtual float32 ComputeSubmergedArea( const b2Vec2& normal, float32 offset, const b2XForm& xf, b2Vec2* c) const = 0; /// Get the maximum radius about the parent body's center of mass. float32 GetSweepRadius() const; /// Get the coefficient of friction. float32 GetFriction() const; /// Set the coefficient of friction. void SetFriction(float32 friction); /// Get the coefficient of restitution. float32 GetRestitution() const; /// Set the coefficient of restitution. void SetRestitution(float32 restitution); /// Get the density of the shape. float32 GetDensity() const; /// Set the density of the shape. void SetDensity(float32 density); protected: friend class b2Body; friend class b2World; static b2Shape* Create(const b2ShapeDef* def, b2BlockAllocator* allocator); static void Destroy(b2Shape* shape, b2BlockAllocator* allocator); b2Shape(const b2ShapeDef* def); virtual ~b2Shape(); void CreateProxy(b2BroadPhase* broadPhase, const b2XForm& xf); void DestroyProxy(b2BroadPhase* broadPhase); bool Synchronize(b2BroadPhase* broadPhase, const b2XForm& xf1, const b2XForm& xf2); void RefilterProxy(b2BroadPhase* broadPhase, const b2XForm& xf); virtual void UpdateSweepRadius(const b2Vec2& center) = 0; b2ShapeType m_type; b2Shape* m_next; b2Body* m_body; // Sweep radius relative to the parent body's center of mass. float32 m_sweepRadius; float32 m_density; float32 m_friction; float32 m_restitution; uint16 m_proxyId; b2FilterData m_filter; bool m_isSensor; void* m_userData; }; inline b2ShapeType b2Shape::GetType() const { return m_type; } inline bool b2Shape::IsSensor() const { return m_isSensor; } inline void b2Shape::SetSensor(bool sensor) { m_isSensor = sensor; } inline void b2Shape::SetFilterData(const b2FilterData& filter) { m_filter = filter; } inline const b2FilterData& b2Shape::GetFilterData() const { return m_filter; } inline void* b2Shape::GetUserData() { return m_userData; } inline void b2Shape::SetUserData(void* data) { m_userData = data; } inline b2Body* b2Shape::GetBody() { return m_body; } inline b2Shape* b2Shape::GetNext() { return m_next; } inline float32 b2Shape::GetSweepRadius() const { return m_sweepRadius; } inline float32 b2Shape::GetFriction() const { return m_friction; } inline void b2Shape::SetFriction(float32 friction) { m_friction = friction; } inline float32 b2Shape::GetRestitution() const { return m_restitution; } inline void b2Shape::SetRestitution(float32 restitution) { m_restitution = restitution; } inline float32 b2Shape::GetDensity() const { return m_density; } inline void b2Shape::SetDensity(float32 density) { m_density = density; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2EdgeShape.h0000644000000000000000000001253411135222025023011 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_EDGE_SHAPE_H #define B2_EDGE_SHAPE_H #include "b2Shape.h" /// This structure is used to build edge shapes. struct b2EdgeChainDef : public b2ShapeDef { b2EdgeChainDef() { type = e_edgeShape; vertexCount = 0; isALoop = true; vertices = NULL; } /// The vertices in local coordinates. You must manage the memory /// of this array on your own, outside of Box2D. b2Vec2* vertices; /// The number of vertices in the chain. int32 vertexCount; /// Whether to create an extra edge between the first and last vertices: bool isALoop; }; /// The edge shape. class b2EdgeShape : public b2Shape { public: /// @see b2Shape::TestPoint bool TestPoint(const b2XForm& transform, const b2Vec2& p) const; /// @see b2Shape::TestSegment b2SegmentCollide TestSegment( const b2XForm& transform, float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const; /// @see b2Shape::ComputeAABB void ComputeAABB(b2AABB* aabb, const b2XForm& transform) const; /// @see b2Shape::ComputeSweptAABB void ComputeSweptAABB( b2AABB* aabb, const b2XForm& transform1, const b2XForm& transform2) const; /// @see b2Shape::ComputeMass void ComputeMass(b2MassData* massData) const; /// @warning This only gives a consistent and sensible answer when when summed over a body only contains loops of edges /// @see b2Shape::ComputeSubmergedArea float32 ComputeSubmergedArea( const b2Vec2& normal, float32 offset, const b2XForm& xf, b2Vec2* c) const; /// Linear distance from vertex1 to vertex2: float32 GetLength() const; /// Local position of vertex in parent body const b2Vec2& GetVertex1() const; /// Local position of vertex in parent body const b2Vec2& GetVertex2() const; /// "Core" vertex with TOI slop for b2Distance functions: const b2Vec2& GetCoreVertex1() const; /// "Core" vertex with TOI slop for b2Distance functions: const b2Vec2& GetCoreVertex2() const; /// Perpendicular unit vector point, pointing from the solid side to the empty side: const b2Vec2& GetNormalVector() const; /// Parallel unit vector, pointing from vertex1 to vertex2: const b2Vec2& GetDirectionVector() const; const b2Vec2& GetCorner1Vector() const; const b2Vec2& GetCorner2Vector() const; bool Corner1IsConvex() const; bool Corner2IsConvex() const; b2Vec2 GetFirstVertex(const b2XForm& xf) const; b2Vec2 Support(const b2XForm& xf, const b2Vec2& d) const; /// Get the next edge in the chain. b2EdgeShape* GetNextEdge() const; /// Get the previous edge in the chain. b2EdgeShape* GetPrevEdge() const; void SetPrevEdge(b2EdgeShape* edge, const b2Vec2& core, const b2Vec2& cornerDir, bool convex); void SetNextEdge(b2EdgeShape* edge, const b2Vec2& core, const b2Vec2& cornerDir, bool convex); private: friend class b2Shape; friend class b2Body; b2EdgeShape(const b2Vec2& v1, const b2Vec2& v2, const b2ShapeDef* def); void UpdateSweepRadius(const b2Vec2& center); b2Vec2 m_v1; b2Vec2 m_v2; b2Vec2 m_coreV1; b2Vec2 m_coreV2; float32 m_length; b2Vec2 m_normal; b2Vec2 m_direction; // Unit vector halfway between m_direction and m_prevEdge.m_direction: b2Vec2 m_cornerDir1; // Unit vector halfway between m_direction and m_nextEdge.m_direction: b2Vec2 m_cornerDir2; bool m_cornerConvex1; bool m_cornerConvex2; b2EdgeShape* m_nextEdge; b2EdgeShape* m_prevEdge; }; inline float32 b2EdgeShape::GetLength() const { return m_length; } inline const b2Vec2& b2EdgeShape::GetVertex1() const { return m_v1; } inline const b2Vec2& b2EdgeShape::GetVertex2() const { return m_v2; } inline const b2Vec2& b2EdgeShape::GetCoreVertex1() const { return m_coreV1; } inline const b2Vec2& b2EdgeShape::GetCoreVertex2() const { return m_coreV2; } inline const b2Vec2& b2EdgeShape::GetNormalVector() const { return m_normal; } inline const b2Vec2& b2EdgeShape::GetDirectionVector() const { return m_direction; } inline const b2Vec2& b2EdgeShape::GetCorner1Vector() const { return m_cornerDir1; } inline const b2Vec2& b2EdgeShape::GetCorner2Vector() const { return m_cornerDir2; } inline b2EdgeShape* b2EdgeShape::GetNextEdge() const { return m_nextEdge; } inline b2EdgeShape* b2EdgeShape::GetPrevEdge() const { return m_prevEdge; } inline b2Vec2 b2EdgeShape::GetFirstVertex(const b2XForm& xf) const { return b2Mul(xf, m_coreV1); } inline bool b2EdgeShape::Corner1IsConvex() const { return m_cornerConvex1; } inline bool b2EdgeShape::Corner2IsConvex() const { return m_cornerConvex2; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2PolygonShape.cpp0000644000000000000000000003511511077704466024152 0ustar rootroot /* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2PolygonShape.h" void b2PolygonDef::SetAsBox(float32 hx, float32 hy) { vertexCount = 4; vertices[0].Set(-hx, -hy); vertices[1].Set( hx, -hy); vertices[2].Set( hx, hy); vertices[3].Set(-hx, hy); } void b2PolygonDef::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle) { SetAsBox(hx, hy); b2XForm xf; xf.position = center; xf.R.Set(angle); for (int32 i = 0; i < vertexCount; ++i) { vertices[i] = b2Mul(xf, vertices[i]); } } static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count) { b2Assert(count >= 3); b2Vec2 c; c.Set(0.0f, 0.0f); float32 area = 0.0f; // pRef is the reference point for forming triangles. // It's location doesn't change the result (except for rounding error). b2Vec2 pRef(0.0f, 0.0f); #if 0 // This code would put the reference point inside the polygon. for (int32 i = 0; i < count; ++i) { pRef += vs[i]; } pRef *= 1.0f / count; #endif const float32 inv3 = 1.0f / 3.0f; for (int32 i = 0; i < count; ++i) { // Triangle vertices. b2Vec2 p1 = pRef; b2Vec2 p2 = vs[i]; b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0]; b2Vec2 e1 = p2 - p1; b2Vec2 e2 = p3 - p1; float32 D = b2Cross(e1, e2); float32 triangleArea = 0.5f * D; area += triangleArea; // Area weighted centroid c += triangleArea * inv3 * (p1 + p2 + p3); } // Centroid b2Assert(area > B2_FLT_EPSILON); c *= 1.0f / area; return c; } // http://www.geometrictools.com/Documentation/MinimumAreaRectangle.pdf static void ComputeOBB(b2OBB* obb, const b2Vec2* vs, int32 count) { b2Assert(count <= b2_maxPolygonVertices); b2Vec2 p[b2_maxPolygonVertices + 1]; for (int32 i = 0; i < count; ++i) { p[i] = vs[i]; } p[count] = p[0]; float32 minArea = B2_FLT_MAX; for (int32 i = 1; i <= count; ++i) { b2Vec2 root = p[i-1]; b2Vec2 ux = p[i] - root; float32 length = ux.Normalize(); b2Assert(length > B2_FLT_EPSILON); b2Vec2 uy(-ux.y, ux.x); b2Vec2 lower(B2_FLT_MAX, B2_FLT_MAX); b2Vec2 upper(-B2_FLT_MAX, -B2_FLT_MAX); for (int32 j = 0; j < count; ++j) { b2Vec2 d = p[j] - root; b2Vec2 r; r.x = b2Dot(ux, d); r.y = b2Dot(uy, d); lower = b2Min(lower, r); upper = b2Max(upper, r); } float32 area = (upper.x - lower.x) * (upper.y - lower.y); if (area < 0.95f * minArea) { minArea = area; obb->R.col1 = ux; obb->R.col2 = uy; b2Vec2 center = 0.5f * (lower + upper); obb->center = root + b2Mul(obb->R, center); obb->extents = 0.5f * (upper - lower); } } b2Assert(minArea < B2_FLT_MAX); } b2PolygonShape::b2PolygonShape(const b2ShapeDef* def) : b2Shape(def) { b2Assert(def->type == e_polygonShape); m_type = e_polygonShape; const b2PolygonDef* poly = (const b2PolygonDef*)def; // Get the vertices transformed into the body frame. m_vertexCount = poly->vertexCount; b2Assert(3 <= m_vertexCount && m_vertexCount <= b2_maxPolygonVertices); // Copy vertices. for (int32 i = 0; i < m_vertexCount; ++i) { m_vertices[i] = poly->vertices[i]; } // Compute normals. Ensure the edges have non-zero length. for (int32 i = 0; i < m_vertexCount; ++i) { int32 i1 = i; int32 i2 = i + 1 < m_vertexCount ? i + 1 : 0; b2Vec2 edge = m_vertices[i2] - m_vertices[i1]; b2Assert(edge.LengthSquared() > B2_FLT_EPSILON * B2_FLT_EPSILON); m_normals[i] = b2Cross(edge, 1.0f); m_normals[i].Normalize(); } #ifdef _DEBUG // Ensure the polygon is convex. for (int32 i = 0; i < m_vertexCount; ++i) { for (int32 j = 0; j < m_vertexCount; ++j) { // Don't check vertices on the current edge. if (j == i || j == (i + 1) % m_vertexCount) { continue; } // Your polygon is non-convex (it has an indentation). // Or your polygon is too skinny. float32 s = b2Dot(m_normals[i], m_vertices[j] - m_vertices[i]); b2Assert(s < -b2_linearSlop); } } // Ensure the polygon is counter-clockwise. for (int32 i = 1; i < m_vertexCount; ++i) { float32 cross = b2Cross(m_normals[i-1], m_normals[i]); // Keep asinf happy. cross = b2Clamp(cross, -1.0f, 1.0f); // You have consecutive edges that are almost parallel on your polygon. float32 angle = asinf(cross); b2Assert(angle > b2_angularSlop); } #endif // Compute the polygon centroid. m_centroid = ComputeCentroid(poly->vertices, poly->vertexCount); // Compute the oriented bounding box. ComputeOBB(&m_obb, m_vertices, m_vertexCount); // Create core polygon shape by shifting edges inward. // Also compute the min/max radius for CCD. for (int32 i = 0; i < m_vertexCount; ++i) { int32 i1 = i - 1 >= 0 ? i - 1 : m_vertexCount - 1; int32 i2 = i; b2Vec2 n1 = m_normals[i1]; b2Vec2 n2 = m_normals[i2]; b2Vec2 v = m_vertices[i] - m_centroid;; b2Vec2 d; d.x = b2Dot(n1, v) - b2_toiSlop; d.y = b2Dot(n2, v) - b2_toiSlop; // Shifting the edge inward by b2_toiSlop should // not cause the plane to pass the centroid. // Your shape has a radius/extent less than b2_toiSlop. b2Assert(d.x >= 0.0f); b2Assert(d.y >= 0.0f); b2Mat22 A; A.col1.x = n1.x; A.col2.x = n1.y; A.col1.y = n2.x; A.col2.y = n2.y; m_coreVertices[i] = A.Solve(d) + m_centroid; } } void b2PolygonShape::UpdateSweepRadius(const b2Vec2& center) { // Update the sweep radius (maximum radius) as measured from // a local center point. m_sweepRadius = 0.0f; for (int32 i = 0; i < m_vertexCount; ++i) { b2Vec2 d = m_coreVertices[i] - center; m_sweepRadius = b2Max(m_sweepRadius, d.Length()); } } bool b2PolygonShape::TestPoint(const b2XForm& xf, const b2Vec2& p) const { b2Vec2 pLocal = b2MulT(xf.R, p - xf.position); for (int32 i = 0; i < m_vertexCount; ++i) { float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]); if (dot > 0.0f) { return false; } } return true; } b2SegmentCollide b2PolygonShape::TestSegment( const b2XForm& xf, float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const { float32 lower = 0.0f, upper = maxLambda; b2Vec2 p1 = b2MulT(xf.R, segment.p1 - xf.position); b2Vec2 p2 = b2MulT(xf.R, segment.p2 - xf.position); b2Vec2 d = p2 - p1; int32 index = -1; for (int32 i = 0; i < m_vertexCount; ++i) { // p = p1 + a * d // dot(normal, p - v) = 0 // dot(normal, p1 - v) + a * dot(normal, d) = 0 float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1); float32 denominator = b2Dot(m_normals[i], d); if (denominator == 0.0f) { if (numerator < 0.0f) { return e_missCollide; } } else { // Note: we want this predicate without division: // lower < numerator / denominator, where denominator < 0 // Since denominator < 0, we have to flip the inequality: // lower < numerator / denominator <==> denominator * lower > numerator. if (denominator < 0.0f && numerator < lower * denominator) { // Increase lower. // The segment enters this half-space. lower = numerator / denominator; index = i; } else if (denominator > 0.0f && numerator < upper * denominator) { // Decrease upper. // The segment exits this half-space. upper = numerator / denominator; } } if (upper < lower) { return e_missCollide; } } b2Assert(0.0f <= lower && lower <= maxLambda); if (index >= 0) { *lambda = lower; *normal = b2Mul(xf.R, m_normals[index]); return e_hitCollide; } *lambda = 0; return e_startsInsideCollide; } void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2XForm& xf) const { b2Mat22 R = b2Mul(xf.R, m_obb.R); b2Mat22 absR = b2Abs(R); b2Vec2 h = b2Mul(absR, m_obb.extents); b2Vec2 position = xf.position + b2Mul(xf.R, m_obb.center); aabb->lowerBound = position - h; aabb->upperBound = position + h; } void b2PolygonShape::ComputeSweptAABB(b2AABB* aabb, const b2XForm& transform1, const b2XForm& transform2) const { b2AABB aabb1, aabb2; ComputeAABB(&aabb1, transform1); ComputeAABB(&aabb2, transform2); aabb->lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound); aabb->upperBound = b2Max(aabb1.upperBound, aabb2.upperBound); } void b2PolygonShape::ComputeMass(b2MassData* massData) const { // Polygon mass, centroid, and inertia. // Let rho be the polygon density in mass per unit area. // Then: // mass = rho * int(dA) // centroid.x = (1/mass) * rho * int(x * dA) // centroid.y = (1/mass) * rho * int(y * dA) // I = rho * int((x*x + y*y) * dA) // // We can compute these integrals by summing all the integrals // for each triangle of the polygon. To evaluate the integral // for a single triangle, we make a change of variables to // the (u,v) coordinates of the triangle: // x = x0 + e1x * u + e2x * v // y = y0 + e1y * u + e2y * v // where 0 <= u && 0 <= v && u + v <= 1. // // We integrate u from [0,1-v] and then v from [0,1]. // We also need to use the Jacobian of the transformation: // D = cross(e1, e2) // // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3) // // The rest of the derivation is handled by computer algebra. b2Assert(m_vertexCount >= 3); b2Vec2 center; center.Set(0.0f, 0.0f); float32 area = 0.0f; float32 I = 0.0f; // pRef is the reference point for forming triangles. // It's location doesn't change the result (except for rounding error). b2Vec2 pRef(0.0f, 0.0f); #if 0 // This code would put the reference point inside the polygon. for (int32 i = 0; i < m_vertexCount; ++i) { pRef += m_vertices[i]; } pRef *= 1.0f / count; #endif const float32 k_inv3 = 1.0f / 3.0f; for (int32 i = 0; i < m_vertexCount; ++i) { // Triangle vertices. b2Vec2 p1 = pRef; b2Vec2 p2 = m_vertices[i]; b2Vec2 p3 = i + 1 < m_vertexCount ? m_vertices[i+1] : m_vertices[0]; b2Vec2 e1 = p2 - p1; b2Vec2 e2 = p3 - p1; float32 D = b2Cross(e1, e2); float32 triangleArea = 0.5f * D; area += triangleArea; // Area weighted centroid center += triangleArea * k_inv3 * (p1 + p2 + p3); float32 px = p1.x, py = p1.y; float32 ex1 = e1.x, ey1 = e1.y; float32 ex2 = e2.x, ey2 = e2.y; float32 intx2 = k_inv3 * (0.25f * (ex1*ex1 + ex2*ex1 + ex2*ex2) + (px*ex1 + px*ex2)) + 0.5f*px*px; float32 inty2 = k_inv3 * (0.25f * (ey1*ey1 + ey2*ey1 + ey2*ey2) + (py*ey1 + py*ey2)) + 0.5f*py*py; I += D * (intx2 + inty2); } // Total mass massData->mass = m_density * area; // Center of mass b2Assert(area > B2_FLT_EPSILON); center *= 1.0f / area; massData->center = center; // Inertia tensor relative to the local origin. massData->I = m_density * I; } float32 b2PolygonShape::ComputeSubmergedArea( const b2Vec2& normal, float32 offset, const b2XForm& xf, b2Vec2* c) const { //Transform plane into shape co-ordinates b2Vec2 normalL = b2MulT(xf.R,normal); float32 offsetL = offset - b2Dot(normal,xf.position); float32 depths[b2_maxPolygonVertices]; int32 diveCount = 0; int32 intoIndex = -1; int32 outoIndex = -1; bool lastSubmerged = false; int32 i; for(i=0;i0){ if(isSubmerged){ if(!lastSubmerged){ intoIndex = i-1; diveCount++; } }else{ if(lastSubmerged){ outoIndex = i-1; diveCount++; } } } lastSubmerged = isSubmerged; } switch(diveCount){ case 0: if(lastSubmerged){ //Completely submerged b2MassData md; ComputeMass(&md); *c = b2Mul(xf,md.center); return md.mass/m_density; }else{ //Completely dry return 0; } break; case 1: if(intoIndex==-1){ intoIndex = m_vertexCount-1; }else{ outoIndex = m_vertexCount-1; } break; } int32 intoIndex2 = (intoIndex+1)%m_vertexCount; int32 outoIndex2 = (outoIndex+1)%m_vertexCount; float32 intoLambda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]); float32 outoLambda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]); b2Vec2 intoVec( m_vertices[intoIndex].x*(1-intoLambda)+m_vertices[intoIndex2].x*intoLambda, m_vertices[intoIndex].y*(1-intoLambda)+m_vertices[intoIndex2].y*intoLambda); b2Vec2 outoVec( m_vertices[outoIndex].x*(1-outoLambda)+m_vertices[outoIndex2].x*outoLambda, m_vertices[outoIndex].y*(1-outoLambda)+m_vertices[outoIndex2].y*outoLambda); //Initialize accumulator float32 area = 0; b2Vec2 center(0,0); b2Vec2 p2 = m_vertices[intoIndex2]; b2Vec2 p3; float32 k_inv3 = 1.0f / 3.0f; //An awkward loop from intoIndex2+1 to outIndex2 i = intoIndex2; while(i!=outoIndex2){ i=(i+1)%m_vertexCount; if(i==outoIndex2) p3 = outoVec; else p3 = m_vertices[i]; //Add the triangle formed by intoVec,p2,p3 { b2Vec2 e1 = p2 - intoVec; b2Vec2 e2 = p3 - intoVec; float32 D = b2Cross(e1, e2); float32 triangleArea = 0.5f * D; area += triangleArea; // Area weighted centroid center += triangleArea * k_inv3 * (intoVec + p2 + p3); } // p2=p3; } //Normalize and transform centroid center *= 1.0f/area; *c = b2Mul(xf,center); return area; } b2Vec2 b2PolygonShape::Centroid(const b2XForm& xf) const { return b2Mul(xf, m_centroid); } b2Vec2 b2PolygonShape::Support(const b2XForm& xf, const b2Vec2& d) const { b2Vec2 dLocal = b2MulT(xf.R, d); int32 bestIndex = 0; float32 bestValue = b2Dot(m_coreVertices[0], dLocal); for (int32 i = 1; i < m_vertexCount; ++i) { float32 value = b2Dot(m_coreVertices[i], dLocal); if (value > bestValue) { bestIndex = i; bestValue = value; } } return b2Mul(xf, m_coreVertices[bestIndex]); } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2CircleShape.cpp0000644000000000000000000001120411130023047023670 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2CircleShape.h" b2CircleShape::b2CircleShape(const b2ShapeDef* def) : b2Shape(def) { b2Assert(def->type == e_circleShape); const b2CircleDef* circleDef = (const b2CircleDef*)def; m_type = e_circleShape; m_localPosition = circleDef->localPosition; m_radius = circleDef->radius; } void b2CircleShape::UpdateSweepRadius(const b2Vec2& center) { // Update the sweep radius (maximum radius) as measured from // a local center point. b2Vec2 d = m_localPosition - center; m_sweepRadius = d.Length() + m_radius - b2_toiSlop; } bool b2CircleShape::TestPoint(const b2XForm& transform, const b2Vec2& p) const { b2Vec2 center = transform.position + b2Mul(transform.R, m_localPosition); b2Vec2 d = p - center; return b2Dot(d, d) <= m_radius * m_radius; } // Collision Detection in Interactive 3D Environments by Gino van den Bergen // From Section 3.1.2 // x = s + a * r // norm(x) = radius b2SegmentCollide b2CircleShape::TestSegment(const b2XForm& transform, float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const { b2Vec2 position = transform.position + b2Mul(transform.R, m_localPosition); b2Vec2 s = segment.p1 - position; float32 b = b2Dot(s, s) - m_radius * m_radius; // Does the segment start inside the circle? if (b < 0.0f) { *lambda = 0; return e_startsInsideCollide; } // Solve quadratic equation. b2Vec2 r = segment.p2 - segment.p1; float32 c = b2Dot(s, r); float32 rr = b2Dot(r, r); float32 sigma = c * c - rr * b; // Check for negative discriminant and short segment. if (sigma < 0.0f || rr < B2_FLT_EPSILON) { return e_missCollide; } // Find the point of intersection of the line with the circle. float32 a = -(c + b2Sqrt(sigma)); // Is the intersection point on the segment? if (0.0f <= a && a <= maxLambda * rr) { a /= rr; *lambda = a; *normal = s + a * r; normal->Normalize(); return e_hitCollide; } return e_missCollide; } void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2XForm& transform) const { b2Vec2 p = transform.position + b2Mul(transform.R, m_localPosition); aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius); aabb->upperBound.Set(p.x + m_radius, p.y + m_radius); } void b2CircleShape::ComputeSweptAABB(b2AABB* aabb, const b2XForm& transform1, const b2XForm& transform2) const { b2Vec2 p1 = transform1.position + b2Mul(transform1.R, m_localPosition); b2Vec2 p2 = transform2.position + b2Mul(transform2.R, m_localPosition); b2Vec2 lower = b2Min(p1, p2); b2Vec2 upper = b2Max(p1, p2); aabb->lowerBound.Set(lower.x - m_radius, lower.y - m_radius); aabb->upperBound.Set(upper.x + m_radius, upper.y + m_radius); } void b2CircleShape::ComputeMass(b2MassData* massData) const { massData->mass = m_density * b2_pi * m_radius * m_radius; massData->center = m_localPosition; // inertia about the local origin massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_localPosition, m_localPosition)); } float32 b2CircleShape::ComputeSubmergedArea( const b2Vec2& normal, float32 offset, const b2XForm& xf, b2Vec2* c) const { b2Vec2 p = b2Mul(xf,m_localPosition); float32 l = -(b2Dot(normal,p) - offset); if(l<-m_radius+B2_FLT_EPSILON){ //Completely dry return 0; } if(l>m_radius){ //Completely wet *c = p; return b2_pi*m_radius*m_radius; } //Magic float32 r2 = m_radius*m_radius; float32 l2 = l*l; //TODO: write b2Sqrt to handle fixed point case. float32 area = r2 * (asin(l/m_radius) + b2_pi/2.0f)+ l * b2Sqrt(r2 - l2); float32 com = -2.0f/3.0f*pow(r2-l2,1.5f)/area; c->x = p.x + normal.x * com; c->y = p.y + normal.y * com; return area; } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2Shape.cpp0000644000000000000000000000770411077704466022605 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Shape.h" #include "b2CircleShape.h" #include "b2PolygonShape.h" #include "b2EdgeShape.h" #include "../b2Collision.h" #include "../b2BroadPhase.h" #include "../../Common/b2BlockAllocator.h" #include b2Shape* b2Shape::Create(const b2ShapeDef* def, b2BlockAllocator* allocator) { switch (def->type) { case e_circleShape: { void* mem = allocator->Allocate(sizeof(b2CircleShape)); return new (mem) b2CircleShape(def); } case e_polygonShape: { void* mem = allocator->Allocate(sizeof(b2PolygonShape)); return new (mem) b2PolygonShape(def); } default: b2Assert(false); return NULL; } } void b2Shape::Destroy(b2Shape* s, b2BlockAllocator* allocator) { b2EdgeShape* edge; switch (s->GetType()) { case e_circleShape: s->~b2Shape(); allocator->Free(s, sizeof(b2CircleShape)); break; case e_polygonShape: s->~b2Shape(); allocator->Free(s, sizeof(b2PolygonShape)); break; case e_edgeShape: edge = (b2EdgeShape*) s; if (edge->m_nextEdge != NULL) edge->m_nextEdge->m_prevEdge = NULL; if (edge->m_prevEdge != NULL) edge->m_prevEdge->m_nextEdge = NULL; s->~b2Shape(); allocator->Free(s, sizeof(b2EdgeShape)); break; default: b2Assert(false); } } b2Shape::b2Shape(const b2ShapeDef* def) { m_userData = def->userData; m_friction = def->friction; m_restitution = def->restitution; m_density = def->density; m_body = NULL; m_sweepRadius = 0.0f; m_next = NULL; m_proxyId = b2_nullProxy; m_filter = def->filter; m_isSensor = def->isSensor; } b2Shape::~b2Shape() { b2Assert(m_proxyId == b2_nullProxy); } void b2Shape::CreateProxy(b2BroadPhase* broadPhase, const b2XForm& transform) { b2Assert(m_proxyId == b2_nullProxy); b2AABB aabb; ComputeAABB(&aabb, transform); bool inRange = broadPhase->InRange(aabb); // You are creating a shape outside the world box. b2Assert(inRange); if (inRange) { m_proxyId = broadPhase->CreateProxy(aabb, this); } else { m_proxyId = b2_nullProxy; } } void b2Shape::DestroyProxy(b2BroadPhase* broadPhase) { if (m_proxyId != b2_nullProxy) { broadPhase->DestroyProxy(m_proxyId); m_proxyId = b2_nullProxy; } } bool b2Shape::Synchronize(b2BroadPhase* broadPhase, const b2XForm& transform1, const b2XForm& transform2) { if (m_proxyId == b2_nullProxy) { return false; } // Compute an AABB that covers the swept shape (may miss some rotation effect). b2AABB aabb; ComputeSweptAABB(&aabb, transform1, transform2); if (broadPhase->InRange(aabb)) { broadPhase->MoveProxy(m_proxyId, aabb); return true; } else { return false; } } void b2Shape::RefilterProxy(b2BroadPhase* broadPhase, const b2XForm& transform) { if (m_proxyId == b2_nullProxy) { return; } broadPhase->DestroyProxy(m_proxyId); b2AABB aabb; ComputeAABB(&aabb, transform); bool inRange = broadPhase->InRange(aabb); if (inRange) { m_proxyId = broadPhase->CreateProxy(aabb, this); } else { m_proxyId = b2_nullProxy; } } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/Shapes/b2PolygonShape.h0000644000000000000000000001130011077704466023605 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_POLYGON_SHAPE_H #define B2_POLYGON_SHAPE_H #include "b2Shape.h" /// Convex polygon. The vertices must be in CCW order for a right-handed /// coordinate system with the z-axis coming out of the screen. struct b2PolygonDef : public b2ShapeDef { b2PolygonDef() { type = e_polygonShape; vertexCount = 0; } /// Build vertices to represent an axis-aligned box. /// @param hx the half-width. /// @param hy the half-height. void SetAsBox(float32 hx, float32 hy); /// Build vertices to represent an oriented box. /// @param hx the half-width. /// @param hy the half-height. /// @param center the center of the box in local coordinates. /// @param angle the rotation of the box in local coordinates. void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle); /// The polygon vertices in local coordinates. b2Vec2 vertices[b2_maxPolygonVertices]; /// The number of polygon vertices. int32 vertexCount; }; /// A convex polygon. class b2PolygonShape : public b2Shape { public: /// @see b2Shape::TestPoint bool TestPoint(const b2XForm& transform, const b2Vec2& p) const; /// @see b2Shape::TestSegment b2SegmentCollide TestSegment( const b2XForm& transform, float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const; /// @see b2Shape::ComputeAABB void ComputeAABB(b2AABB* aabb, const b2XForm& transform) const; /// @see b2Shape::ComputeSweptAABB void ComputeSweptAABB( b2AABB* aabb, const b2XForm& transform1, const b2XForm& transform2) const; /// @see b2Shape::ComputeMass void ComputeMass(b2MassData* massData) const; /// @see b2Shape::ComputeSubmergedArea float32 ComputeSubmergedArea( const b2Vec2& normal, float32 offset, const b2XForm& xf, b2Vec2* c) const; /// Get the oriented bounding box relative to the parent body. const b2OBB& GetOBB() const; /// Get local centroid relative to the parent body. const b2Vec2& GetCentroid() const; /// Get the vertex count. int32 GetVertexCount() const; /// Get the vertices in local coordinates. const b2Vec2* GetVertices() const; /// Get the core vertices in local coordinates. These vertices /// represent a smaller polygon that is used for time of impact /// computations. const b2Vec2* GetCoreVertices() const; /// Get the edge normal vectors. There is one for each vertex. const b2Vec2* GetNormals() const; /// Get the first vertex and apply the supplied transform. b2Vec2 GetFirstVertex(const b2XForm& xf) const; /// Get the centroid and apply the supplied transform. b2Vec2 Centroid(const b2XForm& xf) const; /// Get the support point in the given world direction. /// Use the supplied transform. b2Vec2 Support(const b2XForm& xf, const b2Vec2& d) const; private: friend class b2Shape; b2PolygonShape(const b2ShapeDef* def); void UpdateSweepRadius(const b2Vec2& center); // Local position of the polygon centroid. b2Vec2 m_centroid; b2OBB m_obb; b2Vec2 m_vertices[b2_maxPolygonVertices]; b2Vec2 m_normals[b2_maxPolygonVertices]; b2Vec2 m_coreVertices[b2_maxPolygonVertices]; int32 m_vertexCount; }; inline b2Vec2 b2PolygonShape::GetFirstVertex(const b2XForm& xf) const { return b2Mul(xf, m_coreVertices[0]); } inline const b2OBB& b2PolygonShape::GetOBB() const { return m_obb; } inline const b2Vec2& b2PolygonShape::GetCentroid() const { return m_centroid; } inline int32 b2PolygonShape::GetVertexCount() const { return m_vertexCount; } inline const b2Vec2* b2PolygonShape::GetVertices() const { return m_vertices; } inline const b2Vec2* b2PolygonShape::GetCoreVertices() const { return m_coreVertices; } inline const b2Vec2* b2PolygonShape::GetNormals() const { return m_normals; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2TimeOfImpact.cpp0000644000000000000000000000642511064106301022616 0ustar rootroot/* * Copyright (c) 2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Collision.h" #include "Shapes/b2Shape.h" // This algorithm uses conservative advancement to compute the time of // impact (TOI) of two shapes. // Refs: Bullet, Young Kim float32 b2TimeOfImpact(const b2Shape* shape1, const b2Sweep& sweep1, const b2Shape* shape2, const b2Sweep& sweep2) { float32 r1 = shape1->GetSweepRadius(); float32 r2 = shape2->GetSweepRadius(); b2Assert(sweep1.t0 == sweep2.t0); b2Assert(1.0f - sweep1.t0 > B2_FLT_EPSILON); float32 t0 = sweep1.t0; b2Vec2 v1 = sweep1.c - sweep1.c0; b2Vec2 v2 = sweep2.c - sweep2.c0; float32 omega1 = sweep1.a - sweep1.a0; float32 omega2 = sweep2.a - sweep2.a0; float32 alpha = 0.0f; b2Vec2 p1, p2; const int32 k_maxIterations = 20; // TODO_ERIN b2Settings int32 iter = 0; b2Vec2 normal = b2Vec2_zero; float32 distance = 0.0f; float32 targetDistance = 0.0f; for(;;) { float32 t = (1.0f - alpha) * t0 + alpha; b2XForm xf1, xf2; sweep1.GetXForm(&xf1, t); sweep2.GetXForm(&xf2, t); // Get the distance between shapes. distance = b2Distance(&p1, &p2, shape1, xf1, shape2, xf2); if (iter == 0) { // Compute a reasonable target distance to give some breathing room // for conservative advancement. if (distance > 2.0f * b2_toiSlop) { targetDistance = 1.5f * b2_toiSlop; } else { targetDistance = b2Max(0.05f * b2_toiSlop, distance - 0.5f * b2_toiSlop); } } if (distance - targetDistance < 0.05f * b2_toiSlop || iter == k_maxIterations) { break; } normal = p2 - p1; normal.Normalize(); // Compute upper bound on remaining movement. float32 approachVelocityBound = b2Dot(normal, v1 - v2) + b2Abs(omega1) * r1 + b2Abs(omega2) * r2; if (b2Abs(approachVelocityBound) < B2_FLT_EPSILON) { alpha = 1.0f; break; } // Get the conservative time increment. Don't advance all the way. float32 dAlpha = (distance - targetDistance) / approachVelocityBound; //float32 dt = (distance - 0.5f * b2_linearSlop) / approachVelocityBound; float32 newAlpha = alpha + dAlpha; // The shapes may be moving apart or a safe distance apart. if (newAlpha < 0.0f || 1.0f < newAlpha) { alpha = 1.0f; break; } // Ensure significant advancement. if (newAlpha < (1.0f + 100.0f * B2_FLT_EPSILON) * alpha) { break; } alpha = newAlpha; ++iter; } return alpha; } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2BroadPhase.cpp0000644000000000000000000006025011132275372022314 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2BroadPhase.h" #include #include // Notes: // - we use bound arrays instead of linked lists for cache coherence. // - we use quantized integral values for fast compares. // - we use short indices rather than pointers to save memory. // - we use a stabbing count for fast overlap queries (less than order N). // - we also use a time stamp on each proxy to speed up the registration of // overlap query results. // - where possible, we compare bound indices instead of values to reduce // cache misses (TODO_ERIN). // - no broadphase is perfect and neither is this one: it is not great for huge // worlds (use a multi-SAP instead), it is not great for large objects. bool b2BroadPhase::s_validate = false; struct b2BoundValues { uint16 lowerValues[2]; uint16 upperValues[2]; }; static int32 BinarySearch(b2Bound* bounds, int32 count, uint16 value) { int32 low = 0; int32 high = count - 1; while (low <= high) { int32 mid = (low + high) >> 1; if (bounds[mid].value > value) { high = mid - 1; } else if (bounds[mid].value < value) { low = mid + 1; } else { return (uint16)mid; } } return low; } b2BroadPhase::b2BroadPhase(const b2AABB& worldAABB, b2PairCallback* callback) { m_pairManager.Initialize(this, callback); b2Assert(worldAABB.IsValid()); m_worldAABB = worldAABB; m_proxyCount = 0; b2Vec2 d = worldAABB.upperBound - worldAABB.lowerBound; m_quantizationFactor.x = float32(B2BROADPHASE_MAX) / d.x; m_quantizationFactor.y = float32(B2BROADPHASE_MAX) / d.y; for (uint16 i = 0; i < b2_maxProxies - 1; ++i) { m_proxyPool[i].SetNext(i + 1); m_proxyPool[i].timeStamp = 0; m_proxyPool[i].overlapCount = b2_invalid; m_proxyPool[i].userData = NULL; } m_proxyPool[b2_maxProxies-1].SetNext(b2_nullProxy); m_proxyPool[b2_maxProxies-1].timeStamp = 0; m_proxyPool[b2_maxProxies-1].overlapCount = b2_invalid; m_proxyPool[b2_maxProxies-1].userData = NULL; m_freeProxy = 0; m_timeStamp = 1; m_queryResultCount = 0; } b2BroadPhase::~b2BroadPhase() { } // This one is only used for validation. bool b2BroadPhase::TestOverlap(b2Proxy* p1, b2Proxy* p2) { for (int32 axis = 0; axis < 2; ++axis) { b2Bound* bounds = m_bounds[axis]; b2Assert(p1->lowerBounds[axis] < 2 * m_proxyCount); b2Assert(p1->upperBounds[axis] < 2 * m_proxyCount); b2Assert(p2->lowerBounds[axis] < 2 * m_proxyCount); b2Assert(p2->upperBounds[axis] < 2 * m_proxyCount); if (bounds[p1->lowerBounds[axis]].value > bounds[p2->upperBounds[axis]].value) return false; if (bounds[p1->upperBounds[axis]].value < bounds[p2->lowerBounds[axis]].value) return false; } return true; } bool b2BroadPhase::TestOverlap(const b2BoundValues& b, b2Proxy* p) { for (int32 axis = 0; axis < 2; ++axis) { b2Bound* bounds = m_bounds[axis]; b2Assert(p->lowerBounds[axis] < 2 * m_proxyCount); b2Assert(p->upperBounds[axis] < 2 * m_proxyCount); if (b.lowerValues[axis] > bounds[p->upperBounds[axis]].value) return false; if (b.upperValues[axis] < bounds[p->lowerBounds[axis]].value) return false; } return true; } void b2BroadPhase::ComputeBounds(uint16* lowerValues, uint16* upperValues, const b2AABB& aabb) { b2Assert(aabb.upperBound.x >= aabb.lowerBound.x); b2Assert(aabb.upperBound.y >= aabb.lowerBound.y); b2Vec2 minVertex = b2Clamp(aabb.lowerBound, m_worldAABB.lowerBound, m_worldAABB.upperBound); b2Vec2 maxVertex = b2Clamp(aabb.upperBound, m_worldAABB.lowerBound, m_worldAABB.upperBound); // Bump lower bounds downs and upper bounds up. This ensures correct sorting of // lower/upper bounds that would have equal values. // TODO_ERIN implement fast float to uint16 conversion. lowerValues[0] = (uint16)(m_quantizationFactor.x * (minVertex.x - m_worldAABB.lowerBound.x)) & (B2BROADPHASE_MAX - 1); upperValues[0] = (uint16)(m_quantizationFactor.x * (maxVertex.x - m_worldAABB.lowerBound.x)) | 1; lowerValues[1] = (uint16)(m_quantizationFactor.y * (minVertex.y - m_worldAABB.lowerBound.y)) & (B2BROADPHASE_MAX - 1); upperValues[1] = (uint16)(m_quantizationFactor.y * (maxVertex.y - m_worldAABB.lowerBound.y)) | 1; } void b2BroadPhase::IncrementTimeStamp() { if (m_timeStamp == B2BROADPHASE_MAX) { for (uint16 i = 0; i < b2_maxProxies; ++i) { m_proxyPool[i].timeStamp = 0; } m_timeStamp = 1; } else { ++m_timeStamp; } } void b2BroadPhase::IncrementOverlapCount(int32 proxyId) { b2Proxy* proxy = m_proxyPool + proxyId; if (proxy->timeStamp < m_timeStamp) { proxy->timeStamp = m_timeStamp; proxy->overlapCount = 1; } else { proxy->overlapCount = 2; b2Assert(m_queryResultCount < b2_maxProxies); m_queryResults[m_queryResultCount] = (uint16)proxyId; ++m_queryResultCount; } } void b2BroadPhase::Query(int32* lowerQueryOut, int32* upperQueryOut, uint16 lowerValue, uint16 upperValue, b2Bound* bounds, int32 boundCount, int32 axis) { int32 lowerQuery = BinarySearch(bounds, boundCount, lowerValue); int32 upperQuery = BinarySearch(bounds, boundCount, upperValue); // Easy case: lowerQuery <= lowerIndex(i) < upperQuery // Solution: search query range for min bounds. for (int32 i = lowerQuery; i < upperQuery; ++i) { if (bounds[i].IsLower()) { IncrementOverlapCount(bounds[i].proxyId); } } // Hard case: lowerIndex(i) < lowerQuery < upperIndex(i) // Solution: use the stabbing count to search down the bound array. if (lowerQuery > 0) { int32 i = lowerQuery - 1; int32 s = bounds[i].stabbingCount; // Find the s overlaps. while (s) { b2Assert(i >= 0); if (bounds[i].IsLower()) { b2Proxy* proxy = m_proxyPool + bounds[i].proxyId; if (lowerQuery <= proxy->upperBounds[axis]) { IncrementOverlapCount(bounds[i].proxyId); --s; } } --i; } } *lowerQueryOut = lowerQuery; *upperQueryOut = upperQuery; } uint16 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData) { b2Assert(m_proxyCount < b2_maxProxies); b2Assert(m_freeProxy != b2_nullProxy); uint16 proxyId = m_freeProxy; b2Proxy* proxy = m_proxyPool + proxyId; m_freeProxy = proxy->GetNext(); proxy->overlapCount = 0; proxy->userData = userData; int32 boundCount = 2 * m_proxyCount; uint16 lowerValues[2], upperValues[2]; ComputeBounds(lowerValues, upperValues, aabb); for (int32 axis = 0; axis < 2; ++axis) { b2Bound* bounds = m_bounds[axis]; int32 lowerIndex, upperIndex; Query(&lowerIndex, &upperIndex, lowerValues[axis], upperValues[axis], bounds, boundCount, axis); memmove(bounds + upperIndex + 2, bounds + upperIndex, (boundCount - upperIndex) * sizeof(b2Bound)); memmove(bounds + lowerIndex + 1, bounds + lowerIndex, (upperIndex - lowerIndex) * sizeof(b2Bound)); // The upper index has increased because of the lower bound insertion. ++upperIndex; // Copy in the new bounds. bounds[lowerIndex].value = lowerValues[axis]; bounds[lowerIndex].proxyId = proxyId; bounds[upperIndex].value = upperValues[axis]; bounds[upperIndex].proxyId = proxyId; bounds[lowerIndex].stabbingCount = lowerIndex == 0 ? 0 : bounds[lowerIndex-1].stabbingCount; bounds[upperIndex].stabbingCount = bounds[upperIndex-1].stabbingCount; // Adjust the stabbing count between the new bounds. for (int32 index = lowerIndex; index < upperIndex; ++index) { ++bounds[index].stabbingCount; } // Adjust the all the affected bound indices. for (int32 index = lowerIndex; index < boundCount + 2; ++index) { b2Proxy* proxy = m_proxyPool + bounds[index].proxyId; if (bounds[index].IsLower()) { proxy->lowerBounds[axis] = (uint16)index; } else { proxy->upperBounds[axis] = (uint16)index; } } } ++m_proxyCount; b2Assert(m_queryResultCount < b2_maxProxies); // Create pairs if the AABB is in range. for (int32 i = 0; i < m_queryResultCount; ++i) { b2Assert(m_queryResults[i] < b2_maxProxies); b2Assert(m_proxyPool[m_queryResults[i]].IsValid()); m_pairManager.AddBufferedPair(proxyId, m_queryResults[i]); } m_pairManager.Commit(); if (s_validate) { Validate(); } // Prepare for next query. m_queryResultCount = 0; IncrementTimeStamp(); return proxyId; } void b2BroadPhase::DestroyProxy(int32 proxyId) { b2Assert(0 < m_proxyCount && m_proxyCount <= b2_maxProxies); b2Proxy* proxy = m_proxyPool + proxyId; b2Assert(proxy->IsValid()); int32 boundCount = 2 * m_proxyCount; for (int32 axis = 0; axis < 2; ++axis) { b2Bound* bounds = m_bounds[axis]; int32 lowerIndex = proxy->lowerBounds[axis]; int32 upperIndex = proxy->upperBounds[axis]; uint16 lowerValue = bounds[lowerIndex].value; uint16 upperValue = bounds[upperIndex].value; memmove(bounds + lowerIndex, bounds + lowerIndex + 1, (upperIndex - lowerIndex - 1) * sizeof(b2Bound)); memmove(bounds + upperIndex-1, bounds + upperIndex + 1, (boundCount - upperIndex - 1) * sizeof(b2Bound)); // Fix bound indices. for (int32 index = lowerIndex; index < boundCount - 2; ++index) { b2Proxy* proxy = m_proxyPool + bounds[index].proxyId; if (bounds[index].IsLower()) { proxy->lowerBounds[axis] = (uint16)index; } else { proxy->upperBounds[axis] = (uint16)index; } } // Fix stabbing count. for (int32 index = lowerIndex; index < upperIndex - 1; ++index) { --bounds[index].stabbingCount; } // Query for pairs to be removed. lowerIndex and upperIndex are not needed. Query(&lowerIndex, &upperIndex, lowerValue, upperValue, bounds, boundCount - 2, axis); } b2Assert(m_queryResultCount < b2_maxProxies); for (int32 i = 0; i < m_queryResultCount; ++i) { b2Assert(m_proxyPool[m_queryResults[i]].IsValid()); m_pairManager.RemoveBufferedPair(proxyId, m_queryResults[i]); } m_pairManager.Commit(); // Prepare for next query. m_queryResultCount = 0; IncrementTimeStamp(); // Return the proxy to the pool. proxy->userData = NULL; proxy->overlapCount = b2_invalid; proxy->lowerBounds[0] = b2_invalid; proxy->lowerBounds[1] = b2_invalid; proxy->upperBounds[0] = b2_invalid; proxy->upperBounds[1] = b2_invalid; proxy->SetNext(m_freeProxy); m_freeProxy = (uint16)proxyId; --m_proxyCount; if (s_validate) { Validate(); } } void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb) { if (proxyId == b2_nullProxy || b2_maxProxies <= proxyId) { b2Assert(false); return; } if (aabb.IsValid() == false) { b2Assert(false); return; } int32 boundCount = 2 * m_proxyCount; b2Proxy* proxy = m_proxyPool + proxyId; // Get new bound values b2BoundValues newValues; ComputeBounds(newValues.lowerValues, newValues.upperValues, aabb); // Get old bound values b2BoundValues oldValues; for (int32 axis = 0; axis < 2; ++axis) { oldValues.lowerValues[axis] = m_bounds[axis][proxy->lowerBounds[axis]].value; oldValues.upperValues[axis] = m_bounds[axis][proxy->upperBounds[axis]].value; } for (int32 axis = 0; axis < 2; ++axis) { b2Bound* bounds = m_bounds[axis]; int32 lowerIndex = proxy->lowerBounds[axis]; int32 upperIndex = proxy->upperBounds[axis]; uint16 lowerValue = newValues.lowerValues[axis]; uint16 upperValue = newValues.upperValues[axis]; int32 deltaLower = lowerValue - bounds[lowerIndex].value; int32 deltaUpper = upperValue - bounds[upperIndex].value; bounds[lowerIndex].value = lowerValue; bounds[upperIndex].value = upperValue; // // Expanding adds overlaps // // Should we move the lower bound down? if (deltaLower < 0) { int32 index = lowerIndex; while (index > 0 && lowerValue < bounds[index-1].value) { b2Bound* bound = bounds + index; b2Bound* prevBound = bound - 1; int32 prevProxyId = prevBound->proxyId; b2Proxy* prevProxy = m_proxyPool + prevBound->proxyId; ++prevBound->stabbingCount; if (prevBound->IsUpper() == true) { if (TestOverlap(newValues, prevProxy)) { m_pairManager.AddBufferedPair(proxyId, prevProxyId); } ++prevProxy->upperBounds[axis]; ++bound->stabbingCount; } else { ++prevProxy->lowerBounds[axis]; --bound->stabbingCount; } --proxy->lowerBounds[axis]; b2Swap(*bound, *prevBound); --index; } } // Should we move the upper bound up? if (deltaUpper > 0) { int32 index = upperIndex; while (index < boundCount-1 && bounds[index+1].value <= upperValue) { b2Bound* bound = bounds + index; b2Bound* nextBound = bound + 1; int32 nextProxyId = nextBound->proxyId; b2Proxy* nextProxy = m_proxyPool + nextProxyId; ++nextBound->stabbingCount; if (nextBound->IsLower() == true) { if (TestOverlap(newValues, nextProxy)) { m_pairManager.AddBufferedPair(proxyId, nextProxyId); } --nextProxy->lowerBounds[axis]; ++bound->stabbingCount; } else { --nextProxy->upperBounds[axis]; --bound->stabbingCount; } ++proxy->upperBounds[axis]; b2Swap(*bound, *nextBound); ++index; } } // // Shrinking removes overlaps // // Should we move the lower bound up? if (deltaLower > 0) { int32 index = lowerIndex; while (index < boundCount-1 && bounds[index+1].value <= lowerValue) { b2Bound* bound = bounds + index; b2Bound* nextBound = bound + 1; int32 nextProxyId = nextBound->proxyId; b2Proxy* nextProxy = m_proxyPool + nextProxyId; --nextBound->stabbingCount; if (nextBound->IsUpper()) { if (TestOverlap(oldValues, nextProxy)) { m_pairManager.RemoveBufferedPair(proxyId, nextProxyId); } --nextProxy->upperBounds[axis]; --bound->stabbingCount; } else { --nextProxy->lowerBounds[axis]; ++bound->stabbingCount; } ++proxy->lowerBounds[axis]; b2Swap(*bound, *nextBound); ++index; } } // Should we move the upper bound down? if (deltaUpper < 0) { int32 index = upperIndex; while (index > 0 && upperValue < bounds[index-1].value) { b2Bound* bound = bounds + index; b2Bound* prevBound = bound - 1; int32 prevProxyId = prevBound->proxyId; b2Proxy* prevProxy = m_proxyPool + prevProxyId; --prevBound->stabbingCount; if (prevBound->IsLower() == true) { if (TestOverlap(oldValues, prevProxy)) { m_pairManager.RemoveBufferedPair(proxyId, prevProxyId); } ++prevProxy->lowerBounds[axis]; --bound->stabbingCount; } else { ++prevProxy->upperBounds[axis]; ++bound->stabbingCount; } --proxy->upperBounds[axis]; b2Swap(*bound, *prevBound); --index; } } } if (s_validate) { Validate(); } } void b2BroadPhase::Commit() { m_pairManager.Commit(); } int32 b2BroadPhase::Query(const b2AABB& aabb, void** userData, int32 maxCount) { uint16 lowerValues[2]; uint16 upperValues[2]; ComputeBounds(lowerValues, upperValues, aabb); int32 lowerIndex, upperIndex; Query(&lowerIndex, &upperIndex, lowerValues[0], upperValues[0], m_bounds[0], 2*m_proxyCount, 0); Query(&lowerIndex, &upperIndex, lowerValues[1], upperValues[1], m_bounds[1], 2*m_proxyCount, 1); b2Assert(m_queryResultCount < b2_maxProxies); int32 count = 0; for (int32 i = 0; i < m_queryResultCount && count < maxCount; ++i, ++count) { b2Assert(m_queryResults[i] < b2_maxProxies); b2Proxy* proxy = m_proxyPool + m_queryResults[i]; b2Assert(proxy->IsValid()); userData[i] = proxy->userData; } // Prepare for next query. m_queryResultCount = 0; IncrementTimeStamp(); return count; } void b2BroadPhase::Validate() { for (int32 axis = 0; axis < 2; ++axis) { b2Bound* bounds = m_bounds[axis]; int32 boundCount = 2 * m_proxyCount; uint16 stabbingCount = 0; for (int32 i = 0; i < boundCount; ++i) { b2Bound* bound = bounds + i; b2Assert(i == 0 || bounds[i-1].value <= bound->value); b2Assert(bound->proxyId != b2_nullProxy); b2Assert(m_proxyPool[bound->proxyId].IsValid()); if (bound->IsLower() == true) { b2Assert(m_proxyPool[bound->proxyId].lowerBounds[axis] == i); ++stabbingCount; } else { b2Assert(m_proxyPool[bound->proxyId].upperBounds[axis] == i); --stabbingCount; } b2Assert(bound->stabbingCount == stabbingCount); } } } int32 b2BroadPhase::QuerySegment(const b2Segment& segment, void** userData, int32 maxCount, SortKeyFunc sortKey) { float32 maxLambda = 1; float32 dx = (segment.p2.x-segment.p1.x)*m_quantizationFactor.x; float32 dy = (segment.p2.y-segment.p1.y)*m_quantizationFactor.y; int32 sx = dx<-B2_FLT_EPSILON ? -1 : (dx>B2_FLT_EPSILON ? 1 : 0); int32 sy = dy<-B2_FLT_EPSILON ? -1 : (dy>B2_FLT_EPSILON ? 1 : 0); b2Assert(sx!=0||sy!=0); float32 p1x = (segment.p1.x-m_worldAABB.lowerBound.x)*m_quantizationFactor.x; float32 p1y = (segment.p1.y-m_worldAABB.lowerBound.y)*m_quantizationFactor.y; uint16 startValues[2]; uint16 startValues2[2]; int32 xIndex; int32 yIndex; uint16 proxyId; b2Proxy* proxy; // TODO_ERIN implement fast float to uint16 conversion. startValues[0] = (uint16)(p1x) & (B2BROADPHASE_MAX - 1); startValues2[0] = (uint16)(p1x) | 1; startValues[1] = (uint16)(p1y) & (B2BROADPHASE_MAX - 1); startValues2[1] = (uint16)(p1y) | 1; //First deal with all the proxies that contain segment.p1 int32 lowerIndex; int32 upperIndex; Query(&lowerIndex,&upperIndex,startValues[0],startValues2[0],m_bounds[0],2*m_proxyCount,0); if(sx>=0) xIndex = upperIndex-1; else xIndex = lowerIndex; Query(&lowerIndex,&upperIndex,startValues[1],startValues2[1],m_bounds[1],2*m_proxyCount,1); if(sy>=0) yIndex = upperIndex-1; else yIndex = lowerIndex; //If we are using sortKey, then sort what we have so far, filtering negative keys if(sortKey) { //Fill keys for(int32 i=0;i=0):(a>b&&b>=0)) { m_querySortKeys[i+1] = a; m_querySortKeys[i] = b; uint16 tempValue = m_queryResults[i+1]; m_queryResults[i+1] = m_queryResults[i]; m_queryResults[i] = tempValue; i--; if(i==-1) i=1; } else { i++; } } //Skim off negative values while(m_queryResultCount>0 && m_querySortKeys[m_queryResultCount-1]<0) m_queryResultCount--; } //Now work through the rest of the segment for (;;) { float32 xProgress = 0; float32 yProgress = 0; //Move on to the next bound xIndex += sx>=0?1:-1; if(xIndex<0||xIndex>=m_proxyCount*2) break; if(sx!=0) xProgress = ((float32)m_bounds[0][xIndex].value-p1x)/dx; //Move on to the next bound yIndex += sy>=0?1:-1; if(yIndex<0||yIndex>=m_proxyCount*2) break; if(sy!=0) yProgress = ((float32)m_bounds[1][yIndex].value-p1y)/dy; for(;;) { if(sy==0||(sx!=0&&xProgressmaxLambda) break; //Check that we are entering a proxy, not leaving if(sx>0?m_bounds[0][xIndex].IsLower():m_bounds[0][xIndex].IsUpper()){ //Check the other axis of the proxy proxyId = m_bounds[0][xIndex].proxyId; proxy = m_proxyPool+proxyId; if(sy>=0) { if(proxy->lowerBounds[1]<=yIndex-1&&proxy->upperBounds[1]>=yIndex) { //Add the proxy if(sortKey) { AddProxyResult(proxyId,proxy,maxCount,sortKey); } else { m_queryResults[m_queryResultCount] = proxyId; ++m_queryResultCount; } } } else { if(proxy->lowerBounds[1]<=yIndex&&proxy->upperBounds[1]>=yIndex+1) { //Add the proxy if(sortKey) { AddProxyResult(proxyId,proxy,maxCount,sortKey); } else { m_queryResults[m_queryResultCount] = proxyId; ++m_queryResultCount; } } } } //Early out if(sortKey && m_queryResultCount==maxCount && m_queryResultCount>0 && xProgress>m_querySortKeys[m_queryResultCount-1]) break; //Move on to the next bound if(sx>0) { xIndex++; if(xIndex==m_proxyCount*2) break; } else { xIndex--; if(xIndex<0) break; } xProgress = ((float32)m_bounds[0][xIndex].value - p1x) / dx; } else { if(yProgress>maxLambda) break; //Check that we are entering a proxy, not leaving if(sy>0?m_bounds[1][yIndex].IsLower():m_bounds[1][yIndex].IsUpper()){ //Check the other axis of the proxy proxyId = m_bounds[1][yIndex].proxyId; proxy = m_proxyPool+proxyId; if(sx>=0) { if(proxy->lowerBounds[0]<=xIndex-1&&proxy->upperBounds[0]>=xIndex) { //Add the proxy if(sortKey) { AddProxyResult(proxyId,proxy,maxCount,sortKey); } else { m_queryResults[m_queryResultCount] = proxyId; ++m_queryResultCount; } } } else { if(proxy->lowerBounds[0]<=xIndex&&proxy->upperBounds[0]>=xIndex+1) { //Add the proxy if(sortKey) { AddProxyResult(proxyId,proxy,maxCount,sortKey); } else { m_queryResults[m_queryResultCount] = proxyId; ++m_queryResultCount; } } } } //Early out if(sortKey && m_queryResultCount==maxCount && m_queryResultCount>0 && yProgress>m_querySortKeys[m_queryResultCount-1]) break; //Move on to the next bound if(sy>0) { yIndex++; if(yIndex==m_proxyCount*2) break; } else { yIndex--; if(yIndex<0) break; } yProgress = ((float32)m_bounds[1][yIndex].value - p1y) / dy; } } break; } int32 count = 0; for(int32 i=0;i < m_queryResultCount && countIsValid()); userData[i] = proxy->userData; } // Prepare for next query. m_queryResultCount = 0; IncrementTimeStamp(); return count; } void b2BroadPhase::AddProxyResult(uint16 proxyId, b2Proxy* proxy, int32 maxCount, SortKeyFunc sortKey) { float32 key = sortKey(proxy->userData); //Filter proxies on positive keys if(key<0) return; //Merge the new key into the sorted list. //float32* p = std::lower_bound(m_querySortKeys,m_querySortKeys+m_queryResultCount,key); float32* p = m_querySortKeys; while(*pi;--j){ m_querySortKeys[j] = m_querySortKeys[j-1]; m_queryResults[j] = m_queryResults[j-1]; } m_querySortKeys[i] = key; m_queryResults[i] = proxyId; m_queryResultCount++; } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2Distance.cpp0000644000000000000000000002564711077704466022062 0ustar rootroot/* * Copyright (c) 2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Collision.h" #include "Shapes/b2CircleShape.h" #include "Shapes/b2PolygonShape.h" #include "Shapes/b2EdgeShape.h" int32 g_GJK_Iterations = 0; // GJK using Voronoi regions (Christer Ericson) and region selection // optimizations (Casey Muratori). // The origin is either in the region of points[1] or in the edge region. The origin is // not in region of points[0] because that is the old point. static int32 ProcessTwo(b2Vec2* x1, b2Vec2* x2, b2Vec2* p1s, b2Vec2* p2s, b2Vec2* points) { // If in point[1] region b2Vec2 r = -points[1]; b2Vec2 d = points[0] - points[1]; float32 length = d.Normalize(); float32 lambda = b2Dot(r, d); if (lambda <= 0.0f || length < B2_FLT_EPSILON) { // The simplex is reduced to a point. *x1 = p1s[1]; *x2 = p2s[1]; p1s[0] = p1s[1]; p2s[0] = p2s[1]; points[0] = points[1]; return 1; } // Else in edge region lambda /= length; *x1 = p1s[1] + lambda * (p1s[0] - p1s[1]); *x2 = p2s[1] + lambda * (p2s[0] - p2s[1]); return 2; } // Possible regions: // - points[2] // - edge points[0]-points[2] // - edge points[1]-points[2] // - inside the triangle static int32 ProcessThree(b2Vec2* x1, b2Vec2* x2, b2Vec2* p1s, b2Vec2* p2s, b2Vec2* points) { b2Vec2 a = points[0]; b2Vec2 b = points[1]; b2Vec2 c = points[2]; b2Vec2 ab = b - a; b2Vec2 ac = c - a; b2Vec2 bc = c - b; float32 sn = -b2Dot(a, ab), sd = b2Dot(b, ab); float32 tn = -b2Dot(a, ac), td = b2Dot(c, ac); float32 un = -b2Dot(b, bc), ud = b2Dot(c, bc); // In vertex c region? if (td <= 0.0f && ud <= 0.0f) { // Single point *x1 = p1s[2]; *x2 = p2s[2]; p1s[0] = p1s[2]; p2s[0] = p2s[2]; points[0] = points[2]; return 1; } // Should not be in vertex a or b region. B2_NOT_USED(sd); B2_NOT_USED(sn); b2Assert(sn > 0.0f || tn > 0.0f); b2Assert(sd > 0.0f || un > 0.0f); float32 n = b2Cross(ab, ac); #ifdef TARGET_FLOAT32_IS_FIXED n = (n < 0.0)? -1.0 : ((n > 0.0)? 1.0 : 0.0); #endif // Should not be in edge ab region. float32 vc = n * b2Cross(a, b); b2Assert(vc > 0.0f || sn > 0.0f || sd > 0.0f); // In edge bc region? float32 va = n * b2Cross(b, c); if (va <= 0.0f && un >= 0.0f && ud >= 0.0f && (un+ud) > 0.0f) { b2Assert(un + ud > 0.0f); float32 lambda = un / (un + ud); *x1 = p1s[1] + lambda * (p1s[2] - p1s[1]); *x2 = p2s[1] + lambda * (p2s[2] - p2s[1]); p1s[0] = p1s[2]; p2s[0] = p2s[2]; points[0] = points[2]; return 2; } // In edge ac region? float32 vb = n * b2Cross(c, a); if (vb <= 0.0f && tn >= 0.0f && td >= 0.0f && (tn+td) > 0.0f) { b2Assert(tn + td > 0.0f); float32 lambda = tn / (tn + td); *x1 = p1s[0] + lambda * (p1s[2] - p1s[0]); *x2 = p2s[0] + lambda * (p2s[2] - p2s[0]); p1s[1] = p1s[2]; p2s[1] = p2s[2]; points[1] = points[2]; return 2; } // Inside the triangle, compute barycentric coordinates float32 denom = va + vb + vc; b2Assert(denom > 0.0f); denom = 1.0f / denom; #ifdef TARGET_FLOAT32_IS_FIXED *x1 = denom * (va * p1s[0] + vb * p1s[1] + vc * p1s[2]); *x2 = denom * (va * p2s[0] + vb * p2s[1] + vc * p2s[2]); #else float32 u = va * denom; float32 v = vb * denom; float32 w = 1.0f - u - v; *x1 = u * p1s[0] + v * p1s[1] + w * p1s[2]; *x2 = u * p2s[0] + v * p2s[1] + w * p2s[2]; #endif return 3; } static bool InPoints(const b2Vec2& w, const b2Vec2* points, int32 pointCount) { const float32 k_tolerance = 100.0f * B2_FLT_EPSILON; for (int32 i = 0; i < pointCount; ++i) { b2Vec2 d = b2Abs(w - points[i]); b2Vec2 m = b2Max(b2Abs(w), b2Abs(points[i])); if (d.x < k_tolerance * (m.x + 1.0f) && d.y < k_tolerance * (m.y + 1.0f)) { return true; } } return false; } template float32 DistanceGeneric(b2Vec2* x1, b2Vec2* x2, const T1* shape1, const b2XForm& xf1, const T2* shape2, const b2XForm& xf2) { b2Vec2 p1s[3], p2s[3]; b2Vec2 points[3]; int32 pointCount = 0; *x1 = shape1->GetFirstVertex(xf1); *x2 = shape2->GetFirstVertex(xf2); float32 vSqr = 0.0f; const int32 maxIterations = 20; for (int32 iter = 0; iter < maxIterations; ++iter) { b2Vec2 v = *x2 - *x1; b2Vec2 w1 = shape1->Support(xf1, v); b2Vec2 w2 = shape2->Support(xf2, -v); vSqr = b2Dot(v, v); b2Vec2 w = w2 - w1; float32 vw = b2Dot(v, w); if (vSqr - vw <= 0.01f * vSqr || InPoints(w, points, pointCount)) // or w in points { if (pointCount == 0) { *x1 = w1; *x2 = w2; } g_GJK_Iterations = iter; return b2Sqrt(vSqr); } switch (pointCount) { case 0: p1s[0] = w1; p2s[0] = w2; points[0] = w; *x1 = p1s[0]; *x2 = p2s[0]; ++pointCount; break; case 1: p1s[1] = w1; p2s[1] = w2; points[1] = w; pointCount = ProcessTwo(x1, x2, p1s, p2s, points); break; case 2: p1s[2] = w1; p2s[2] = w2; points[2] = w; pointCount = ProcessThree(x1, x2, p1s, p2s, points); break; } // If we have three points, then the origin is in the corresponding triangle. if (pointCount == 3) { g_GJK_Iterations = iter; return 0.0f; } float32 maxSqr = -B2_FLT_MAX; for (int32 i = 0; i < pointCount; ++i) { maxSqr = b2Max(maxSqr, b2Dot(points[i], points[i])); } #ifdef TARGET_FLOAT32_IS_FIXED if (pointCount == 3 || vSqr <= 5.0*B2_FLT_EPSILON * maxSqr) #else if (vSqr <= 100.0f * B2_FLT_EPSILON * maxSqr) #endif { g_GJK_Iterations = iter; v = *x2 - *x1; vSqr = b2Dot(v, v); return b2Sqrt(vSqr); } } g_GJK_Iterations = maxIterations; return b2Sqrt(vSqr); } static float32 DistanceCC( b2Vec2* x1, b2Vec2* x2, const b2CircleShape* circle1, const b2XForm& xf1, const b2CircleShape* circle2, const b2XForm& xf2) { b2Vec2 p1 = b2Mul(xf1, circle1->GetLocalPosition()); b2Vec2 p2 = b2Mul(xf2, circle2->GetLocalPosition()); b2Vec2 d = p2 - p1; float32 dSqr = b2Dot(d, d); float32 r1 = circle1->GetRadius() - b2_toiSlop; float32 r2 = circle2->GetRadius() - b2_toiSlop; float32 r = r1 + r2; if (dSqr > r * r) { float32 dLen = d.Normalize(); float32 distance = dLen - r; *x1 = p1 + r1 * d; *x2 = p2 - r2 * d; return distance; } else if (dSqr > B2_FLT_EPSILON * B2_FLT_EPSILON) { d.Normalize(); *x1 = p1 + r1 * d; *x2 = *x1; return 0.0f; } *x1 = p1; *x2 = *x1; return 0.0f; } static float32 DistanceEdgeCircle( b2Vec2* x1, b2Vec2* x2, const b2EdgeShape* edge, const b2XForm& xf1, const b2CircleShape* circle, const b2XForm& xf2) { b2Vec2 vWorld; b2Vec2 d; float32 dSqr; float32 dLen; float32 r = circle->GetRadius() - b2_toiSlop; b2Vec2 cWorld = b2Mul(xf2, circle->GetLocalPosition()); b2Vec2 cLocal = b2MulT(xf1, cWorld); float32 dirDist = b2Dot(cLocal - edge->GetCoreVertex1(), edge->GetDirectionVector()); if (dirDist <= 0.0f) { vWorld = b2Mul(xf1, edge->GetCoreVertex1()); } else if (dirDist >= edge->GetLength()) { vWorld = b2Mul(xf1, edge->GetCoreVertex2()); } else { *x1 = b2Mul(xf1, edge->GetCoreVertex1() + dirDist * edge->GetDirectionVector()); dLen = b2Dot(cLocal - edge->GetCoreVertex1(), edge->GetNormalVector()); if (dLen < 0.0f) { if (dLen < -r) { *x2 = b2Mul(xf1, cLocal + r * edge->GetNormalVector()); return -dLen - r; } else { *x2 = *x1; return 0.0f; } } else { if (dLen > r) { *x2 = b2Mul(xf1, cLocal - r * edge->GetNormalVector()); return dLen - r; } else { *x2 = *x1; return 0.0f; } } } *x1 = vWorld; d = cWorld - vWorld; dSqr = b2Dot(d, d); if (dSqr > r * r) { dLen = d.Normalize(); *x2 = cWorld - r * d; return dLen - r; } else { *x2 = vWorld; return 0.0f; } } // This is used for polygon-vs-circle distance. struct Point { b2Vec2 Support(const b2XForm&, const b2Vec2&) const { return p; } b2Vec2 GetFirstVertex(const b2XForm&) const { return p; } b2Vec2 p; }; // GJK is more robust with polygon-vs-point than polygon-vs-circle. // So we convert polygon-vs-circle to polygon-vs-point. static float32 DistancePC( b2Vec2* x1, b2Vec2* x2, const b2PolygonShape* polygon, const b2XForm& xf1, const b2CircleShape* circle, const b2XForm& xf2) { Point point; point.p = b2Mul(xf2, circle->GetLocalPosition()); float32 distance = DistanceGeneric(x1, x2, polygon, xf1, &point, b2XForm_identity); float32 r = circle->GetRadius() - b2_toiSlop; if (distance > r) { distance -= r; b2Vec2 d = *x2 - *x1; d.Normalize(); *x2 -= r * d; } else { distance = 0.0f; *x2 = *x1; } return distance; } float32 b2Distance(b2Vec2* x1, b2Vec2* x2, const b2Shape* shape1, const b2XForm& xf1, const b2Shape* shape2, const b2XForm& xf2) { b2ShapeType type1 = shape1->GetType(); b2ShapeType type2 = shape2->GetType(); if (type1 == e_circleShape && type2 == e_circleShape) { return DistanceCC(x1, x2, (b2CircleShape*)shape1, xf1, (b2CircleShape*)shape2, xf2); } if (type1 == e_polygonShape && type2 == e_circleShape) { return DistancePC(x1, x2, (b2PolygonShape*)shape1, xf1, (b2CircleShape*)shape2, xf2); } if (type1 == e_circleShape && type2 == e_polygonShape) { return DistancePC(x2, x1, (b2PolygonShape*)shape2, xf2, (b2CircleShape*)shape1, xf1); } if (type1 == e_polygonShape && type2 == e_polygonShape) { return DistanceGeneric(x1, x2, (b2PolygonShape*)shape1, xf1, (b2PolygonShape*)shape2, xf2); } if (type1 == e_edgeShape && type2 == e_circleShape) { return DistanceEdgeCircle(x1, x2, (b2EdgeShape*)shape1, xf1, (b2CircleShape*)shape2, xf2); } if (type1 == e_circleShape && type2 == e_edgeShape) { return DistanceEdgeCircle(x2, x1, (b2EdgeShape*)shape2, xf2, (b2CircleShape*)shape1, xf1); } if (type1 == e_polygonShape && type2 == e_edgeShape) { return DistanceGeneric(x2, x1, (b2EdgeShape*)shape2, xf2, (b2PolygonShape*)shape1, xf1); } if (type1 == e_edgeShape && type2 == e_polygonShape) { return DistanceGeneric(x1, x2, (b2EdgeShape*)shape1, xf1, (b2PolygonShape*)shape2, xf2); } return 0.0f; } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2CollideCircle.cpp0000644000000000000000000001203111064106301022760 0ustar rootroot/* * Copyright (c) 2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Collision.h" #include "Shapes/b2CircleShape.h" #include "Shapes/b2PolygonShape.h" void b2CollideCircles( b2Manifold* manifold, const b2CircleShape* circle1, const b2XForm& xf1, const b2CircleShape* circle2, const b2XForm& xf2) { manifold->pointCount = 0; b2Vec2 p1 = b2Mul(xf1, circle1->GetLocalPosition()); b2Vec2 p2 = b2Mul(xf2, circle2->GetLocalPosition()); b2Vec2 d = p2 - p1; float32 distSqr = b2Dot(d, d); float32 r1 = circle1->GetRadius(); float32 r2 = circle2->GetRadius(); float32 radiusSum = r1 + r2; if (distSqr > radiusSum * radiusSum) { return; } float32 separation; if (distSqr < B2_FLT_EPSILON) { separation = -radiusSum; manifold->normal.Set(0.0f, 1.0f); } else { float32 dist = b2Sqrt(distSqr); separation = dist - radiusSum; float32 a = 1.0f / dist; manifold->normal.x = a * d.x; manifold->normal.y = a * d.y; } manifold->pointCount = 1; manifold->points[0].id.key = 0; manifold->points[0].separation = separation; p1 += r1 * manifold->normal; p2 -= r2 * manifold->normal; b2Vec2 p = 0.5f * (p1 + p2); manifold->points[0].localPoint1 = b2MulT(xf1, p); manifold->points[0].localPoint2 = b2MulT(xf2, p); } void b2CollidePolygonAndCircle( b2Manifold* manifold, const b2PolygonShape* polygon, const b2XForm& xf1, const b2CircleShape* circle, const b2XForm& xf2) { manifold->pointCount = 0; // Compute circle position in the frame of the polygon. b2Vec2 c = b2Mul(xf2, circle->GetLocalPosition()); b2Vec2 cLocal = b2MulT(xf1, c); // Find the min separating edge. int32 normalIndex = 0; float32 separation = -B2_FLT_MAX; float32 radius = circle->GetRadius(); int32 vertexCount = polygon->GetVertexCount(); const b2Vec2* vertices = polygon->GetVertices(); const b2Vec2* normals = polygon->GetNormals(); for (int32 i = 0; i < vertexCount; ++i) { float32 s = b2Dot(normals[i], cLocal - vertices[i]); if (s > radius) { // Early out. return; } if (s > separation) { separation = s; normalIndex = i; } } // If the center is inside the polygon ... if (separation < B2_FLT_EPSILON) { manifold->pointCount = 1; manifold->normal = b2Mul(xf1.R, normals[normalIndex]); manifold->points[0].id.features.incidentEdge = (uint8)normalIndex; manifold->points[0].id.features.incidentVertex = b2_nullFeature; manifold->points[0].id.features.referenceEdge = 0; manifold->points[0].id.features.flip = 0; b2Vec2 position = c - radius * manifold->normal; manifold->points[0].localPoint1 = b2MulT(xf1, position); manifold->points[0].localPoint2 = b2MulT(xf2, position); manifold->points[0].separation = separation - radius; return; } // Project the circle center onto the edge segment. int32 vertIndex1 = normalIndex; int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; b2Vec2 e = vertices[vertIndex2] - vertices[vertIndex1]; float32 length = e.Normalize(); b2Assert(length > B2_FLT_EPSILON); // Project the center onto the edge. float32 u = b2Dot(cLocal - vertices[vertIndex1], e); b2Vec2 p; if (u <= 0.0f) { p = vertices[vertIndex1]; manifold->points[0].id.features.incidentEdge = b2_nullFeature; manifold->points[0].id.features.incidentVertex = (uint8)vertIndex1; } else if (u >= length) { p = vertices[vertIndex2]; manifold->points[0].id.features.incidentEdge = b2_nullFeature; manifold->points[0].id.features.incidentVertex = (uint8)vertIndex2; } else { p = vertices[vertIndex1] + u * e; manifold->points[0].id.features.incidentEdge = (uint8)normalIndex; manifold->points[0].id.features.incidentVertex = b2_nullFeature; } b2Vec2 d = cLocal - p; float32 dist = d.Normalize(); if (dist > radius) { return; } manifold->pointCount = 1; manifold->normal = b2Mul(xf1.R, d); b2Vec2 position = c - radius * manifold->normal; manifold->points[0].localPoint1 = b2MulT(xf1, position); manifold->points[0].localPoint2 = b2MulT(xf2, position); manifold->points[0].separation = dist - radius; manifold->points[0].id.features.referenceEdge = 0; manifold->points[0].id.features.flip = 0; } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2Collision.cpp0000644000000000000000000000442111064106301022222 0ustar rootroot/* * Copyright (c) 2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Collision.h" // Collision Detection in Interactive 3D Environments by Gino van den Bergen // From Section 3.4.1 // x = mu1 * p1 + mu2 * p2 // mu1 + mu2 = 1 && mu1 >= 0 && mu2 >= 0 // mu1 = 1 - mu2; // x = (1 - mu2) * p1 + mu2 * p2 // = p1 + mu2 * (p2 - p1) // x = s + a * r (s := start, r := end - start) // s + a * r = p1 + mu2 * d (d := p2 - p1) // -a * r + mu2 * d = b (b := s - p1) // [-r d] * [a; mu2] = b // Cramer's rule: // denom = det[-r d] // a = det[b d] / denom // mu2 = det[-r b] / denom bool b2Segment::TestSegment(float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const { b2Vec2 s = segment.p1; b2Vec2 r = segment.p2 - s; b2Vec2 d = p2 - p1; b2Vec2 n = b2Cross(d, 1.0f); const float32 k_slop = 100.0f * B2_FLT_EPSILON; float32 denom = -b2Dot(r, n); // Cull back facing collision and ignore parallel segments. if (denom > k_slop) { // Does the segment intersect the infinite line associated with this segment? b2Vec2 b = s - p1; float32 a = b2Dot(b, n); if (0.0f <= a && a <= maxLambda * denom) { float32 mu2 = -r.x * b.y + r.y * b.x; // Does the segment intersect this segment? if (-k_slop * denom <= mu2 && mu2 <= denom * (1.0f + k_slop)) { a /= denom; n.Normalize(); *lambda = a; *normal = n; return true; } } } return false; } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2PairManager.h0000644000000000000000000000702111064106301022121 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ // The pair manager is used by the broad-phase to quickly add/remove/find pairs // of overlapping proxies. It is based closely on code provided by Pierre Terdiman. // http://www.codercorner.com/IncrementalSAP.txt #ifndef B2_PAIR_MANAGER_H #define B2_PAIR_MANAGER_H #include "../Common/b2Settings.h" #include "../Common/b2Math.h" #include class b2BroadPhase; struct b2Proxy; const uint16 b2_nullPair = USHRT_MAX; const uint16 b2_nullProxy = USHRT_MAX; const int32 b2_tableCapacity = b2_maxPairs; // must be a power of two const int32 b2_tableMask = b2_tableCapacity - 1; struct b2Pair { enum { e_pairBuffered = 0x0001, e_pairRemoved = 0x0002, e_pairFinal = 0x0004, }; void SetBuffered() { status |= e_pairBuffered; } void ClearBuffered() { status &= ~e_pairBuffered; } bool IsBuffered() { return (status & e_pairBuffered) == e_pairBuffered; } void SetRemoved() { status |= e_pairRemoved; } void ClearRemoved() { status &= ~e_pairRemoved; } bool IsRemoved() { return (status & e_pairRemoved) == e_pairRemoved; } void SetFinal() { status |= e_pairFinal; } bool IsFinal() { return (status & e_pairFinal) == e_pairFinal; } void* userData; uint16 proxyId1; uint16 proxyId2; uint16 next; uint16 status; }; struct b2BufferedPair { uint16 proxyId1; uint16 proxyId2; }; class b2PairCallback { public: virtual ~b2PairCallback() {} // This should return the new pair user data. It is ok if the // user data is null. virtual void* PairAdded(void* proxyUserData1, void* proxyUserData2) = 0; // This should free the pair's user data. In extreme circumstances, it is possible // this will be called with null pairUserData because the pair never existed. virtual void PairRemoved(void* proxyUserData1, void* proxyUserData2, void* pairUserData) = 0; }; class b2PairManager { public: b2PairManager(); void Initialize(b2BroadPhase* broadPhase, b2PairCallback* callback); void AddBufferedPair(int32 proxyId1, int32 proxyId2); void RemoveBufferedPair(int32 proxyId1, int32 proxyId2); void Commit(); private: b2Pair* Find(int32 proxyId1, int32 proxyId2); b2Pair* Find(int32 proxyId1, int32 proxyId2, uint32 hashValue); b2Pair* AddPair(int32 proxyId1, int32 proxyId2); void* RemovePair(int32 proxyId1, int32 proxyId2); void ValidateBuffer(); void ValidateTable(); public: b2BroadPhase *m_broadPhase; b2PairCallback *m_callback; b2Pair m_pairs[b2_maxPairs]; uint16 m_freePair; int32 m_pairCount; b2BufferedPair m_pairBuffer[b2_maxPairs]; int32 m_pairBufferCount; uint16 m_hashTable[b2_tableCapacity]; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2PairManager.cpp0000644000000000000000000002460011064106301022456 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2PairManager.h" #include "b2BroadPhase.h" #include // Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm // This assumes proxyId1 and proxyId2 are 16-bit. inline uint32 Hash(uint32 proxyId1, uint32 proxyId2) { uint32 key = (proxyId2 << 16) | proxyId1; key = ~key + (key << 15); key = key ^ (key >> 12); key = key + (key << 2); key = key ^ (key >> 4); key = key * 2057; key = key ^ (key >> 16); return key; } inline bool Equals(const b2Pair& pair, int32 proxyId1, int32 proxyId2) { return pair.proxyId1 == proxyId1 && pair.proxyId2 == proxyId2; } inline bool Equals(const b2BufferedPair& pair1, const b2BufferedPair& pair2) { return pair1.proxyId1 == pair2.proxyId1 && pair1.proxyId2 == pair2.proxyId2; } // For sorting. inline bool operator < (const b2BufferedPair& pair1, const b2BufferedPair& pair2) { if (pair1.proxyId1 < pair2.proxyId1) { return true; } if (pair1.proxyId1 == pair2.proxyId1) { return pair1.proxyId2 < pair2.proxyId2; } return false; } b2PairManager::b2PairManager() { b2Assert(b2IsPowerOfTwo(b2_tableCapacity) == true); b2Assert(b2_tableCapacity >= b2_maxPairs); for (int32 i = 0; i < b2_tableCapacity; ++i) { m_hashTable[i] = b2_nullPair; } m_freePair = 0; for (int32 i = 0; i < b2_maxPairs; ++i) { m_pairs[i].proxyId1 = b2_nullProxy; m_pairs[i].proxyId2 = b2_nullProxy; m_pairs[i].userData = NULL; m_pairs[i].status = 0; m_pairs[i].next = uint16(i + 1); } m_pairs[b2_maxPairs-1].next = b2_nullPair; m_pairCount = 0; m_pairBufferCount = 0; } void b2PairManager::Initialize(b2BroadPhase* broadPhase, b2PairCallback* callback) { m_broadPhase = broadPhase; m_callback = callback; } b2Pair* b2PairManager::Find(int32 proxyId1, int32 proxyId2, uint32 hash) { int32 index = m_hashTable[hash]; while (index != b2_nullPair && Equals(m_pairs[index], proxyId1, proxyId2) == false) { index = m_pairs[index].next; } if (index == b2_nullPair) { return NULL; } b2Assert(index < b2_maxPairs); return m_pairs + index; } b2Pair* b2PairManager::Find(int32 proxyId1, int32 proxyId2) { if (proxyId1 > proxyId2) b2Swap(proxyId1, proxyId2); int32 hash = Hash(proxyId1, proxyId2) & b2_tableMask; return Find(proxyId1, proxyId2, hash); } // Returns existing pair or creates a new one. b2Pair* b2PairManager::AddPair(int32 proxyId1, int32 proxyId2) { if (proxyId1 > proxyId2) b2Swap(proxyId1, proxyId2); int32 hash = Hash(proxyId1, proxyId2) & b2_tableMask; b2Pair* pair = Find(proxyId1, proxyId2, hash); if (pair != NULL) { return pair; } b2Assert(m_pairCount < b2_maxPairs && m_freePair != b2_nullPair); uint16 pairIndex = m_freePair; pair = m_pairs + pairIndex; m_freePair = pair->next; pair->proxyId1 = (uint16)proxyId1; pair->proxyId2 = (uint16)proxyId2; pair->status = 0; pair->userData = NULL; pair->next = m_hashTable[hash]; m_hashTable[hash] = pairIndex; ++m_pairCount; return pair; } // Removes a pair. The pair must exist. void* b2PairManager::RemovePair(int32 proxyId1, int32 proxyId2) { b2Assert(m_pairCount > 0); if (proxyId1 > proxyId2) b2Swap(proxyId1, proxyId2); int32 hash = Hash(proxyId1, proxyId2) & b2_tableMask; uint16* node = &m_hashTable[hash]; while (*node != b2_nullPair) { if (Equals(m_pairs[*node], proxyId1, proxyId2)) { uint16 index = *node; *node = m_pairs[*node].next; b2Pair* pair = m_pairs + index; void* userData = pair->userData; // Scrub pair->next = m_freePair; pair->proxyId1 = b2_nullProxy; pair->proxyId2 = b2_nullProxy; pair->userData = NULL; pair->status = 0; m_freePair = index; --m_pairCount; return userData; } else { node = &m_pairs[*node].next; } } b2Assert(false); return NULL; } /* As proxies are created and moved, many pairs are created and destroyed. Even worse, the same pair may be added and removed multiple times in a single time step of the physics engine. To reduce traffic in the pair manager, we try to avoid destroying pairs in the pair manager until the end of the physics step. This is done by buffering all the RemovePair requests. AddPair requests are processed immediately because we need the hash table entry for quick lookup. All user user callbacks are delayed until the buffered pairs are confirmed in Commit. This is very important because the user callbacks may be very expensive and client logic may be harmed if pairs are added and removed within the same time step. Buffer a pair for addition. We may add a pair that is not in the pair manager or pair buffer. We may add a pair that is already in the pair manager and pair buffer. If the added pair is not a new pair, then it must be in the pair buffer (because RemovePair was called). */ void b2PairManager::AddBufferedPair(int32 id1, int32 id2) { b2Assert(id1 != b2_nullProxy && id2 != b2_nullProxy); b2Assert(m_pairBufferCount < b2_maxPairs); b2Pair* pair = AddPair(id1, id2); // If this pair is not in the pair buffer ... if (pair->IsBuffered() == false) { // This must be a newly added pair. b2Assert(pair->IsFinal() == false); // Add it to the pair buffer. pair->SetBuffered(); m_pairBuffer[m_pairBufferCount].proxyId1 = pair->proxyId1; m_pairBuffer[m_pairBufferCount].proxyId2 = pair->proxyId2; ++m_pairBufferCount; b2Assert(m_pairBufferCount <= m_pairCount); } // Confirm this pair for the subsequent call to Commit. pair->ClearRemoved(); if (b2BroadPhase::s_validate) { ValidateBuffer(); } } // Buffer a pair for removal. void b2PairManager::RemoveBufferedPair(int32 id1, int32 id2) { b2Assert(id1 != b2_nullProxy && id2 != b2_nullProxy); b2Assert(m_pairBufferCount < b2_maxPairs); b2Pair* pair = Find(id1, id2); if (pair == NULL) { // The pair never existed. This is legal (due to collision filtering). return; } // If this pair is not in the pair buffer ... if (pair->IsBuffered() == false) { // This must be an old pair. b2Assert(pair->IsFinal() == true); pair->SetBuffered(); m_pairBuffer[m_pairBufferCount].proxyId1 = pair->proxyId1; m_pairBuffer[m_pairBufferCount].proxyId2 = pair->proxyId2; ++m_pairBufferCount; b2Assert(m_pairBufferCount <= m_pairCount); } pair->SetRemoved(); if (b2BroadPhase::s_validate) { ValidateBuffer(); } } void b2PairManager::Commit() { int32 removeCount = 0; b2Proxy* proxies = m_broadPhase->m_proxyPool; for (int32 i = 0; i < m_pairBufferCount; ++i) { b2Pair* pair = Find(m_pairBuffer[i].proxyId1, m_pairBuffer[i].proxyId2); b2Assert(pair->IsBuffered()); pair->ClearBuffered(); b2Assert(pair->proxyId1 < b2_maxProxies && pair->proxyId2 < b2_maxProxies); b2Proxy* proxy1 = proxies + pair->proxyId1; b2Proxy* proxy2 = proxies + pair->proxyId2; b2Assert(proxy1->IsValid()); b2Assert(proxy2->IsValid()); if (pair->IsRemoved()) { // It is possible a pair was added then removed before a commit. Therefore, // we should be careful not to tell the user the pair was removed when the // the user didn't receive a matching add. if (pair->IsFinal() == true) { m_callback->PairRemoved(proxy1->userData, proxy2->userData, pair->userData); } // Store the ids so we can actually remove the pair below. m_pairBuffer[removeCount].proxyId1 = pair->proxyId1; m_pairBuffer[removeCount].proxyId2 = pair->proxyId2; ++removeCount; } else { b2Assert(m_broadPhase->TestOverlap(proxy1, proxy2) == true); if (pair->IsFinal() == false) { pair->userData = m_callback->PairAdded(proxy1->userData, proxy2->userData); pair->SetFinal(); } } } for (int32 i = 0; i < removeCount; ++i) { RemovePair(m_pairBuffer[i].proxyId1, m_pairBuffer[i].proxyId2); } m_pairBufferCount = 0; if (b2BroadPhase::s_validate) { ValidateTable(); } } void b2PairManager::ValidateBuffer() { #ifdef _DEBUG b2Assert(m_pairBufferCount <= m_pairCount); std::sort(m_pairBuffer, m_pairBuffer + m_pairBufferCount); for (int32 i = 0; i < m_pairBufferCount; ++i) { if (i > 0) { b2Assert(Equals(m_pairBuffer[i], m_pairBuffer[i-1]) == false); } b2Pair* pair = Find(m_pairBuffer[i].proxyId1, m_pairBuffer[i].proxyId2); b2Assert(pair->IsBuffered()); b2Assert(pair->proxyId1 != pair->proxyId2); b2Assert(pair->proxyId1 < b2_maxProxies); b2Assert(pair->proxyId2 < b2_maxProxies); b2Proxy* proxy1 = m_broadPhase->m_proxyPool + pair->proxyId1; b2Proxy* proxy2 = m_broadPhase->m_proxyPool + pair->proxyId2; b2Assert(proxy1->IsValid() == true); b2Assert(proxy2->IsValid() == true); } #endif } void b2PairManager::ValidateTable() { #ifdef _DEBUG for (int32 i = 0; i < b2_tableCapacity; ++i) { uint16 index = m_hashTable[i]; while (index != b2_nullPair) { b2Pair* pair = m_pairs + index; b2Assert(pair->IsBuffered() == false); b2Assert(pair->IsFinal() == true); b2Assert(pair->IsRemoved() == false); b2Assert(pair->proxyId1 != pair->proxyId2); b2Assert(pair->proxyId1 < b2_maxProxies); b2Assert(pair->proxyId2 < b2_maxProxies); b2Proxy* proxy1 = m_broadPhase->m_proxyPool + pair->proxyId1; b2Proxy* proxy2 = m_broadPhase->m_proxyPool + pair->proxyId2; b2Assert(proxy1->IsValid() == true); b2Assert(proxy2->IsValid() == true); b2Assert(m_broadPhase->TestOverlap(proxy1, proxy2) == true); index = pair->next; } } #endif } python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2Collision.h0000644000000000000000000001261611073705020021677 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_COLLISION_H #define B2_COLLISION_H #include "../Common/b2Math.h" #include /// @file /// Structures and functions used for computing contact points, distance /// queries, and TOI queries. class b2Shape; class b2CircleShape; class b2PolygonShape; class b2EdgeShape; const uint8 b2_nullFeature = UCHAR_MAX; /// Contact ids to facilitate warm starting. union b2ContactID { /// The features that intersect to form the contact point struct Features { uint8 referenceEdge; ///< The edge that defines the outward contact normal. uint8 incidentEdge; ///< The edge most anti-parallel to the reference edge. uint8 incidentVertex; ///< The vertex (0 or 1) on the incident edge that was clipped. uint8 flip; ///< A value of 1 indicates that the reference edge is on shape2. } features; uint32 key; ///< Used to quickly compare contact ids. }; /// A manifold point is a contact point belonging to a contact /// manifold. It holds details related to the geometry and dynamics /// of the contact points. /// The point is stored in local coordinates because CCD /// requires sub-stepping in which the separation is stale. struct b2ManifoldPoint { b2Vec2 localPoint1; ///< local position of the contact point in body1 b2Vec2 localPoint2; ///< local position of the contact point in body2 float32 separation; ///< the separation of the shapes along the normal vector float32 normalImpulse; ///< the non-penetration impulse float32 tangentImpulse; ///< the friction impulse b2ContactID id; ///< uniquely identifies a contact point between two shapes }; /// A manifold for two touching convex shapes. struct b2Manifold { b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact b2Vec2 normal; ///< the shared unit normal vector int32 pointCount; ///< the number of manifold points }; /// A line segment. struct b2Segment { /// Ray cast against this segment with another segment. bool TestSegment(float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda) const; b2Vec2 p1; ///< the starting point b2Vec2 p2; ///< the ending point }; /// An axis aligned bounding box. struct b2AABB { /// Verify that the bounds are sorted. bool IsValid() const; b2Vec2 lowerBound; ///< the lower vertex b2Vec2 upperBound; ///< the upper vertex }; /// An oriented bounding box. struct b2OBB { b2Mat22 R; ///< the rotation matrix b2Vec2 center; ///< the local centroid b2Vec2 extents; ///< the half-widths }; /// Compute the collision manifold between two circles. void b2CollideCircles(b2Manifold* manifold, const b2CircleShape* circle1, const b2XForm& xf1, const b2CircleShape* circle2, const b2XForm& xf2); /// Compute the collision manifold between a polygon and a circle. void b2CollidePolygonAndCircle(b2Manifold* manifold, const b2PolygonShape* polygon, const b2XForm& xf1, const b2CircleShape* circle, const b2XForm& xf2); /// Compute the collision manifold between two circles. void b2CollidePolygons(b2Manifold* manifold, const b2PolygonShape* polygon1, const b2XForm& xf1, const b2PolygonShape* polygon2, const b2XForm& xf2); /// Compute the distance between two shapes and the closest points. /// @return the distance between the shapes or zero if they are overlapped/touching. float32 b2Distance(b2Vec2* x1, b2Vec2* x2, const b2Shape* shape1, const b2XForm& xf1, const b2Shape* shape2, const b2XForm& xf2); /// Compute the time when two shapes begin to touch or touch at a closer distance. /// @warning the sweeps must have the same time interval. /// @return the fraction between [0,1] in which the shapes first touch. /// fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch. float32 b2TimeOfImpact(const b2Shape* shape1, const b2Sweep& sweep1, const b2Shape* shape2, const b2Sweep& sweep2); // ---------------- Inline Functions ------------------------------------------ inline bool b2AABB::IsValid() const { b2Vec2 d = upperBound - lowerBound; bool valid = d.x >= 0.0f && d.y >= 0.0f; valid = valid && lowerBound.IsValid() && upperBound.IsValid(); return valid; } inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) { b2Vec2 d1, d2; d1 = b.lowerBound - a.upperBound; d2 = a.lowerBound - b.upperBound; if (d1.x > 0.0f || d1.y > 0.0f) return false; if (d2.x > 0.0f || d2.y > 0.0f) return false; return true; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Collision/b2CollidePoly.cpp0000644000000000000000000002263011064106301022510 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Collision.h" #include "Shapes/b2PolygonShape.h" struct ClipVertex { b2Vec2 v; b2ContactID id; }; static int32 ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2], const b2Vec2& normal, float32 offset) { // Start with no output points int32 numOut = 0; // Calculate the distance of end points to the line float32 distance0 = b2Dot(normal, vIn[0].v) - offset; float32 distance1 = b2Dot(normal, vIn[1].v) - offset; // If the points are behind the plane if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; // If the points are on different sides of the plane if (distance0 * distance1 < 0.0f) { // Find intersection point of edge and plane float32 interp = distance0 / (distance0 - distance1); vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); if (distance0 > 0.0f) { vOut[numOut].id = vIn[0].id; } else { vOut[numOut].id = vIn[1].id; } ++numOut; } return numOut; } // Find the separation between poly1 and poly2 for a give edge normal on poly1. static float32 EdgeSeparation(const b2PolygonShape* poly1, const b2XForm& xf1, int32 edge1, const b2PolygonShape* poly2, const b2XForm& xf2) { int32 count1 = poly1->GetVertexCount(); const b2Vec2* vertices1 = poly1->GetVertices(); const b2Vec2* normals1 = poly1->GetNormals(); int32 count2 = poly2->GetVertexCount(); const b2Vec2* vertices2 = poly2->GetVertices(); b2Assert(0 <= edge1 && edge1 < count1); // Convert normal from poly1's frame into poly2's frame. b2Vec2 normal1World = b2Mul(xf1.R, normals1[edge1]); b2Vec2 normal1 = b2MulT(xf2.R, normal1World); // Find support vertex on poly2 for -normal. int32 index = 0; float32 minDot = B2_FLT_MAX; for (int32 i = 0; i < count2; ++i) { float32 dot = b2Dot(vertices2[i], normal1); if (dot < minDot) { minDot = dot; index = i; } } b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]); b2Vec2 v2 = b2Mul(xf2, vertices2[index]); float32 separation = b2Dot(v2 - v1, normal1World); return separation; } // Find the max separation between poly1 and poly2 using edge normals from poly1. static float32 FindMaxSeparation(int32* edgeIndex, const b2PolygonShape* poly1, const b2XForm& xf1, const b2PolygonShape* poly2, const b2XForm& xf2) { int32 count1 = poly1->GetVertexCount(); const b2Vec2* normals1 = poly1->GetNormals(); // Vector pointing from the centroid of poly1 to the centroid of poly2. b2Vec2 d = b2Mul(xf2, poly2->GetCentroid()) - b2Mul(xf1, poly1->GetCentroid()); b2Vec2 dLocal1 = b2MulT(xf1.R, d); // Find edge normal on poly1 that has the largest projection onto d. int32 edge = 0; float32 maxDot = -B2_FLT_MAX; for (int32 i = 0; i < count1; ++i) { float32 dot = b2Dot(normals1[i], dLocal1); if (dot > maxDot) { maxDot = dot; edge = i; } } // Get the separation for the edge normal. float32 s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); if (s > 0.0f) { return s; } // Check the separation for the previous edge normal. int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; float32 sPrev = EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); if (sPrev > 0.0f) { return sPrev; } // Check the separation for the next edge normal. int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0; float32 sNext = EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); if (sNext > 0.0f) { return sNext; } // Find the best edge and the search direction. int32 bestEdge; float32 bestSeparation; int32 increment; if (sPrev > s && sPrev > sNext) { increment = -1; bestEdge = prevEdge; bestSeparation = sPrev; } else if (sNext > s) { increment = 1; bestEdge = nextEdge; bestSeparation = sNext; } else { *edgeIndex = edge; return s; } // Perform a local search for the best edge normal. for ( ; ; ) { if (increment == -1) edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; else edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); if (s > 0.0f) { return s; } if (s > bestSeparation) { bestEdge = edge; bestSeparation = s; } else { break; } } *edgeIndex = bestEdge; return bestSeparation; } static void FindIncidentEdge(ClipVertex c[2], const b2PolygonShape* poly1, const b2XForm& xf1, int32 edge1, const b2PolygonShape* poly2, const b2XForm& xf2) { int32 count1 = poly1->GetVertexCount(); const b2Vec2* normals1 = poly1->GetNormals(); int32 count2 = poly2->GetVertexCount(); const b2Vec2* vertices2 = poly2->GetVertices(); const b2Vec2* normals2 = poly2->GetNormals(); b2Assert(0 <= edge1 && edge1 < count1); // Get the normal of the reference edge in poly2's frame. b2Vec2 normal1 = b2MulT(xf2.R, b2Mul(xf1.R, normals1[edge1])); // Find the incident edge on poly2. int32 index = 0; float32 minDot = B2_FLT_MAX; for (int32 i = 0; i < count2; ++i) { float32 dot = b2Dot(normal1, normals2[i]); if (dot < minDot) { minDot = dot; index = i; } } // Build the clip vertices for the incident edge. int32 i1 = index; int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0; c[0].v = b2Mul(xf2, vertices2[i1]); c[0].id.features.referenceEdge = (uint8)edge1; c[0].id.features.incidentEdge = (uint8)i1; c[0].id.features.incidentVertex = 0; c[1].v = b2Mul(xf2, vertices2[i2]); c[1].id.features.referenceEdge = (uint8)edge1; c[1].id.features.incidentEdge = (uint8)i2; c[1].id.features.incidentVertex = 1; } // Find edge normal of max separation on A - return if separating axis is found // Find edge normal of max separation on B - return if separation axis is found // Choose reference edge as min(minA, minB) // Find incident edge // Clip // The normal points from 1 to 2 void b2CollidePolygons(b2Manifold* manifold, const b2PolygonShape* polyA, const b2XForm& xfA, const b2PolygonShape* polyB, const b2XForm& xfB) { manifold->pointCount = 0; int32 edgeA = 0; float32 separationA = FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); if (separationA > 0.0f) return; int32 edgeB = 0; float32 separationB = FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); if (separationB > 0.0f) return; const b2PolygonShape* poly1; // reference poly const b2PolygonShape* poly2; // incident poly b2XForm xf1, xf2; int32 edge1; // reference edge uint8 flip; const float32 k_relativeTol = 0.98f; const float32 k_absoluteTol = 0.001f; // TODO_ERIN use "radius" of poly for absolute tolerance. if (separationB > k_relativeTol * separationA + k_absoluteTol) { poly1 = polyB; poly2 = polyA; xf1 = xfB; xf2 = xfA; edge1 = edgeB; flip = 1; } else { poly1 = polyA; poly2 = polyB; xf1 = xfA; xf2 = xfB; edge1 = edgeA; flip = 0; } ClipVertex incidentEdge[2]; FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); int32 count1 = poly1->GetVertexCount(); const b2Vec2* vertices1 = poly1->GetVertices(); b2Vec2 v11 = vertices1[edge1]; b2Vec2 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0]; b2Vec2 dv = v12 - v11; b2Vec2 sideNormal = b2Mul(xf1.R, v12 - v11); sideNormal.Normalize(); b2Vec2 frontNormal = b2Cross(sideNormal, 1.0f); v11 = b2Mul(xf1, v11); v12 = b2Mul(xf1, v12); float32 frontOffset = b2Dot(frontNormal, v11); float32 sideOffset1 = -b2Dot(sideNormal, v11); float32 sideOffset2 = b2Dot(sideNormal, v12); // Clip incident edge against extruded edge1 side edges. ClipVertex clipPoints1[2]; ClipVertex clipPoints2[2]; int np; // Clip to box side 1 np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, sideOffset1); if (np < 2) return; // Clip to negative box side 1 np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2); if (np < 2) { return; } // Now clipPoints2 contains the clipped points. manifold->normal = flip ? -frontNormal : frontNormal; int32 pointCount = 0; for (int32 i = 0; i < b2_maxManifoldPoints; ++i) { float32 separation = b2Dot(frontNormal, clipPoints2[i].v) - frontOffset; if (separation <= 0.0f) { b2ManifoldPoint* cp = manifold->points + pointCount; cp->separation = separation; cp->localPoint1 = b2MulT(xfA, clipPoints2[i].v); cp->localPoint2 = b2MulT(xfB, clipPoints2[i].v); cp->id = clipPoints2[i].id; cp->id.features.flip = flip; ++pointCount; } } manifold->pointCount = pointCount;} python-box2d-2.0.2+svn20100109.244/Box2D/Box2D.h0000644000000000000000000000426411077704466016524 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef BOX2D_H #define BOX2D_H /** \mainpage Box2D API Documentation \section intro_sec Getting Started For tutorials please see http://www.box2d.org/manual.html For discussion please visit http://www.box2d.org/forum */ // These include files constitute the main Box2D API #include "Common/b2Settings.h" #include "Collision/Shapes/b2CircleShape.h" #include "Collision/Shapes/b2PolygonShape.h" #include "Collision/Shapes/b2EdgeShape.h" #include "Collision/b2BroadPhase.h" #include "Dynamics/b2WorldCallbacks.h" #include "Dynamics/b2World.h" #include "Dynamics/b2Body.h" #include "Dynamics/Controllers/b2BuoyancyController.h" #include "Dynamics/Controllers/b2ConstantAccelController.h" #include "Dynamics/Controllers/b2ConstantForceController.h" #include "Dynamics/Controllers/b2Controller.h" #include "Dynamics/Controllers/b2GravityController.h" #include "Dynamics/Controllers/b2TensorDampingController.h" #include "Dynamics/Contacts/b2Contact.h" #include "Dynamics/Joints/b2DistanceJoint.h" #include "Dynamics/Joints/b2GearJoint.h" #include "Dynamics/Joints/b2LineJoint.h" #include "Dynamics/Joints/b2MouseJoint.h" #include "Dynamics/Joints/b2PrismaticJoint.h" #include "Dynamics/Joints/b2PulleyJoint.h" #include "Dynamics/Joints/b2RevoluteJoint.h" #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/0000755000000000000000000000000011414467241017166 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2Body.h0000644000000000000000000004342211154057363020466 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_BODY_H #define B2_BODY_H #include "../Common/b2Math.h" #include "../Collision/Shapes/b2Shape.h" #include "Joints/b2Joint.h" #include "Controllers/b2Controller.h" #include class b2Joint; class b2Contact; class b2Controller; class b2World; struct b2JointEdge; struct b2ContactEdge; struct b2ControllerEdge; /// A body definition holds all the data needed to construct a rigid body. /// You can safely re-use body definitions. struct b2BodyDef { /// This constructor sets the body definition default values. b2BodyDef() { massData.center.SetZero(); massData.mass = 0.0f; massData.I = 0.0f; userData = NULL; position.Set(0.0f, 0.0f); angle = 0.0f; linearDamping = 0.0f; angularDamping = 0.0f; allowSleep = true; isSleeping = false; fixedRotation = false; isBullet = false; } /// You can use this to initialized the mass properties of the body. /// If you prefer, you can set the mass properties after the shapes /// have been added using b2Body::SetMassFromShapes. b2MassData massData; /// Use this to store application specific body data. void* userData; /// The world position of the body. Avoid creating bodies at the origin /// since this can lead to many overlapping shapes. b2Vec2 position; /// The world angle of the body in radians. float32 angle; /// Linear damping is use to reduce the linear velocity. The damping parameter /// can be larger than 1.0f but the damping effect becomes sensitive to the /// time step when the damping parameter is large. float32 linearDamping; /// Angular damping is use to reduce the angular velocity. The damping parameter /// can be larger than 1.0f but the damping effect becomes sensitive to the /// time step when the damping parameter is large. float32 angularDamping; /// Set this flag to false if this body should never fall asleep. Note that /// this increases CPU usage. bool allowSleep; /// Is this body initially sleeping? bool isSleeping; /// Should this body be prevented from rotating? Useful for characters. bool fixedRotation; /// Is this a fast moving body that should be prevented from tunneling through /// other moving bodies? Note that all bodies are prevented from tunneling through /// static bodies. /// @warning You should use this flag sparingly since it increases processing time. bool isBullet; }; /// A rigid body. class b2Body { public: /// Creates a shape and attach it to this body. /// @param shapeDef the shape definition. /// @warning This function is locked during callbacks. b2Shape* CreateShape(const b2ShapeDef* shapeDef); /// Destroy a shape. This removes the shape from the broad-phase and /// therefore destroys any contacts associated with this shape. All shapes /// attached to a body are implicitly destroyed when the body is destroyed. /// @param shape the shape to be removed. /// @warning This function is locked during callbacks. void DestroyShape(b2Shape* shape); /// Set the mass properties. Note that this changes the center of mass position. /// If you are not sure how to compute mass properties, use SetMassFromShapes. /// The inertia tensor is assumed to be relative to the center of mass. /// @param massData the mass properties. void SetMass(const b2MassData* massData); /// Compute the mass properties from the attached shapes. You typically call this /// after adding all the shapes. If you add or remove shapes later, you may want /// to call this again. Note that this changes the center of mass position. void SetMassFromShapes(); /// Set the position of the body's origin and rotation (radians). /// This breaks any contacts and wakes the other bodies. /// @param position the new world position of the body's origin (not necessarily /// the center of mass). /// @param angle the new world rotation angle of the body in radians. /// @return false if the movement put a shape outside the world. In this case the /// body is automatically frozen. bool SetXForm(const b2Vec2& position, float32 angle); /// Get the body transform for the body's origin. /// @return the world transform of the body's origin. const b2XForm& GetXForm() const; /// Get the world body origin position. /// @return the world position of the body's origin. const b2Vec2& GetPosition() const; /// Get the angle in radians. /// @return the current world rotation angle in radians. float32 GetAngle() const; /// Get the world position of the center of mass. const b2Vec2& GetWorldCenter() const; /// Get the local position of the center of mass. const b2Vec2& GetLocalCenter() const; /// Set the linear velocity of the center of mass. /// @param v the new linear velocity of the center of mass. void SetLinearVelocity(const b2Vec2& v); /// Get the linear velocity of the center of mass. /// @return the linear velocity of the center of mass. b2Vec2 GetLinearVelocity() const; /// Set the angular velocity. /// @param omega the new angular velocity in radians/second. void SetAngularVelocity(float32 omega); /// Get the angular velocity. /// @return the angular velocity in radians/second. float32 GetAngularVelocity() const; /// Apply a force at a world point. If the force is not /// applied at the center of mass, it will generate a torque and /// affect the angular velocity. This wakes up the body. /// @param force the world force vector, usually in Newtons (N). /// @param point the world position of the point of application. void ApplyForce(const b2Vec2& force, const b2Vec2& point); /// Apply a torque. This affects the angular velocity /// without affecting the linear velocity of the center of mass. /// This wakes up the body. /// @param torque about the z-axis (out of the screen), usually in N-m. void ApplyTorque(float32 torque); /// Apply an impulse at a point. This immediately modifies the velocity. /// It also modifies the angular velocity if the point of application /// is not at the center of mass. This wakes up the body. /// @param impulse the world impulse vector, usually in N-seconds or kg-m/s. /// @param point the world position of the point of application. void ApplyImpulse(const b2Vec2& impulse, const b2Vec2& point); /// Get the total mass of the body. /// @return the mass, usually in kilograms (kg). float32 GetMass() const; /// Get the central rotational inertia of the body. /// @return the rotational inertia, usually in kg-m^2. float32 GetInertia() const; /// Get the world coordinates of a point given the local coordinates. /// @param localPoint a point on the body measured relative the the body's origin. /// @return the same point expressed in world coordinates. b2Vec2 GetWorldPoint(const b2Vec2& localPoint) const; /// Get the world coordinates of a vector given the local coordinates. /// @param localVector a vector fixed in the body. /// @return the same vector expressed in world coordinates. b2Vec2 GetWorldVector(const b2Vec2& localVector) const; /// Gets a local point relative to the body's origin given a world point. /// @param a point in world coordinates. /// @return the corresponding local point relative to the body's origin. b2Vec2 GetLocalPoint(const b2Vec2& worldPoint) const; /// Gets a local vector given a world vector. /// @param a vector in world coordinates. /// @return the corresponding local vector. b2Vec2 GetLocalVector(const b2Vec2& worldVector) const; /// Get the world linear velocity of a world point attached to this body. /// @param a point in world coordinates. /// @return the world velocity of a point. b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const; /// Get the world velocity of a local point. /// @param a point in local coordinates. /// @return the world velocity of a point. b2Vec2 GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const; /// Get the linear damping of the body. float32 GetLinearDamping() const; /// Set the linear damping of the body. void SetLinearDamping(float32 linearDamping); /// Get the angular damping of the body. float32 GetAngularDamping() const; /// Set the angular damping of the body. void SetAngularDamping(float32 angularDamping); /// Is this body treated like a bullet for continuous collision detection? bool IsBullet() const; /// Should this body be treated like a bullet for continuous collision detection? void SetBullet(bool flag); /// Is this body prevented from rotating. bool IsFixedRotation() const; /// Set if this body is prevented from rotating. void SetFixedRotation(bool fixed); /// Is this body static (immovable)? bool IsStatic() const; /// Make this body static (immovable). /// Use SetMass and SetMassFromShapes to make bodies dynamic. void SetStatic(); /// Is this body dynamic (movable)? bool IsDynamic() const; /// Is this body frozen? bool IsFrozen() const; /// Is this body sleeping (not simulating). bool IsSleeping() const; /// Is this body allowed to sleep bool IsAllowSleeping() const; /// You can disable sleeping on this body. void AllowSleeping(bool flag); /// Wake up this body so it will begin simulating. void WakeUp(); /// Put this body to sleep so it will stop simulating. /// This also sets the velocity to zero. void PutToSleep(); /// Get the list of all shapes attached to this body. b2Shape* GetShapeList(); /// Get the list of all joints attached to this body. b2JointEdge* GetJointList(); /// Get the list of all controllers attached to this body. b2ControllerEdge* GetControllerList(); /// Get the next body in the world's body list. b2Body* GetNext(); /// Get the user data pointer that was provided in the body definition. void* GetUserData(); /// Set the user data. Use this to store your application specific data. void SetUserData(void* data); /// Get the parent world of this body. b2World* GetWorld(); private: friend class b2World; friend class b2Island; friend class b2ContactManager; friend class b2ContactSolver; friend class b2DistanceJoint; friend class b2GearJoint; friend class b2LineJoint; friend class b2MouseJoint; friend class b2PrismaticJoint; friend class b2PulleyJoint; friend class b2RevoluteJoint; friend class b2Controller; // m_flags enum { e_frozenFlag = 0x0002, e_islandFlag = 0x0004, e_sleepFlag = 0x0008, e_allowSleepFlag = 0x0010, e_bulletFlag = 0x0020, e_fixedRotationFlag = 0x0040, }; // m_type enum { e_staticType, e_dynamicType, e_maxTypes, }; b2Body(const b2BodyDef* bd, b2World* world); ~b2Body(); bool SynchronizeShapes(); void SynchronizeTransform(); // This is used to prevent connected bodies from colliding. // It may lie, depending on the collideConnected flag. bool IsConnected(const b2Body* other) const; void Advance(float32 t); uint16 m_flags; int16 m_type; int32 m_islandIndex; b2XForm m_xf; // the body origin transform b2Sweep m_sweep; // the swept motion for CCD b2Vec2 m_linearVelocity; float32 m_angularVelocity; b2Vec2 m_force; float32 m_torque; b2World* m_world; b2Body* m_prev; b2Body* m_next; b2Shape* m_shapeList; int32 m_shapeCount; b2JointEdge* m_jointList; b2ContactEdge* m_contactList; b2ControllerEdge* m_controllerList; float32 m_mass, m_invMass; float32 m_I, m_invI; float32 m_linearDamping; float32 m_angularDamping; float32 m_sleepTime; void* m_userData; }; inline const b2XForm& b2Body::GetXForm() const { return m_xf; } inline const b2Vec2& b2Body::GetPosition() const { return m_xf.position; } inline float32 b2Body::GetAngle() const { return m_sweep.a; } inline const b2Vec2& b2Body::GetWorldCenter() const { return m_sweep.c; } inline const b2Vec2& b2Body::GetLocalCenter() const { return m_sweep.localCenter; } inline void b2Body::SetLinearVelocity(const b2Vec2& v) { m_linearVelocity = v; } inline b2Vec2 b2Body::GetLinearVelocity() const { return m_linearVelocity; } inline void b2Body::SetAngularVelocity(float32 w) { m_angularVelocity = w; } inline float32 b2Body::GetAngularVelocity() const { return m_angularVelocity; } inline float32 b2Body::GetMass() const { return m_mass; } inline float32 b2Body::GetInertia() const { return m_I; } inline b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint) const { return b2Mul(m_xf, localPoint); } inline b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector) const { return b2Mul(m_xf.R, localVector); } inline b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint) const { return b2MulT(m_xf, worldPoint); } inline b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector) const { return b2MulT(m_xf.R, worldVector); } inline b2Vec2 b2Body::GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const { return m_linearVelocity + b2Cross(m_angularVelocity, worldPoint - m_sweep.c); } inline b2Vec2 b2Body::GetLinearVelocityFromLocalPoint(const b2Vec2& localPoint) const { return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); } inline float32 b2Body::GetLinearDamping() const { return m_linearDamping; } inline void b2Body::SetLinearDamping(float32 linearDamping) { m_linearDamping = linearDamping; } inline float32 b2Body::GetAngularDamping() const { return m_angularDamping; } inline void b2Body::SetAngularDamping(float32 angularDamping) { m_angularDamping = angularDamping; } inline bool b2Body::IsBullet() const { return (m_flags & e_bulletFlag) == e_bulletFlag; } inline void b2Body::SetBullet(bool flag) { if (flag) { m_flags |= e_bulletFlag; } else { m_flags &= ~e_bulletFlag; } } inline bool b2Body::IsFixedRotation() const { return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag; } inline void b2Body::SetFixedRotation(bool fixed) { if(fixed) { m_angularVelocity = 0.0f; m_invI = 0.0f; m_flags |= e_fixedRotationFlag; } else { if(m_I > 0.0f) { // Recover m_invI from m_I. m_invI = 1.0f / m_I; m_flags &= e_fixedRotationFlag; } // TODO: Else what? } } inline bool b2Body::IsStatic() const { return m_type == e_staticType; } inline void b2Body::SetStatic() { if(m_type == e_staticType) return; m_mass = 0.0; m_invMass = 0.0f; m_I = 0.0f; m_invI = 0.0f; m_type = e_staticType; for (b2Shape* s = m_shapeList; s; s = s->m_next) { s->RefilterProxy(m_world->m_broadPhase, m_xf); } } inline bool b2Body::IsDynamic() const { return m_type == e_dynamicType; } inline bool b2Body::IsFrozen() const { return (m_flags & e_frozenFlag) == e_frozenFlag; } inline bool b2Body::IsSleeping() const { return (m_flags & e_sleepFlag) == e_sleepFlag; } inline bool b2Body::IsAllowSleeping() const { return (m_flags & e_allowSleepFlag) == e_allowSleepFlag; } inline void b2Body::AllowSleeping(bool flag) { if (flag) { m_flags |= e_allowSleepFlag; } else { m_flags &= ~e_allowSleepFlag; WakeUp(); } } inline void b2Body::WakeUp() { m_flags &= ~e_sleepFlag; m_sleepTime = 0.0f; } inline void b2Body::PutToSleep() { m_flags |= e_sleepFlag; m_sleepTime = 0.0f; m_linearVelocity.SetZero(); m_angularVelocity = 0.0f; m_force.SetZero(); m_torque = 0.0f; } inline b2Shape* b2Body::GetShapeList() { return m_shapeList; } inline b2JointEdge* b2Body::GetJointList() { return m_jointList; } inline b2ControllerEdge* b2Body::GetControllerList() { return m_controllerList; } inline b2Body* b2Body::GetNext() { return m_next; } inline void* b2Body::GetUserData() { return m_userData; } inline void b2Body::SetUserData(void* data) { m_userData = data; } inline bool b2Body::IsConnected(const b2Body* other) const { for (b2JointEdge* jn = m_jointList; jn; jn = jn->next) { if (jn->other == other) return jn->joint->m_collideConnected == false; } return false; } inline void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point) { if (IsSleeping()) { WakeUp(); } m_force += force; m_torque += b2Cross(point - m_sweep.c, force); } inline void b2Body::ApplyTorque(float32 torque) { if (IsSleeping()) { WakeUp(); } m_torque += torque; } inline void b2Body::ApplyImpulse(const b2Vec2& impulse, const b2Vec2& point) { if (IsSleeping()) { WakeUp(); } m_linearVelocity += m_invMass * impulse; m_angularVelocity += m_invI * b2Cross(point - m_sweep.c, impulse); } inline void b2Body::SynchronizeTransform() { m_xf.R.Set(m_sweep.a); m_xf.position = m_sweep.c - b2Mul(m_xf.R, m_sweep.localCenter); } inline void b2Body::Advance(float32 t) { // Advance to the new safe time. m_sweep.Advance(t); m_sweep.c = m_sweep.c0; m_sweep.a = m_sweep.a0; SynchronizeTransform(); } inline b2World* b2Body::GetWorld() { return m_world; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2Island.h0000644000000000000000000000470011064106301020762 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_ISLAND_H #define B2_ISLAND_H #include "../Common/b2Math.h" #include "b2Body.h" class b2Contact; class b2Joint; class b2StackAllocator; class b2ContactListener; struct b2ContactConstraint; struct b2TimeStep; struct b2Position { b2Vec2 x; float32 a; }; struct b2Velocity { b2Vec2 v; float32 w; }; class b2Island { public: b2Island(int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, b2StackAllocator* allocator, b2ContactListener* listener); ~b2Island(); void Clear() { m_bodyCount = 0; m_contactCount = 0; m_jointCount = 0; } void Solve(const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep); void SolveTOI(b2TimeStep& subStep); void Add(b2Body* body) { b2Assert(m_bodyCount < m_bodyCapacity); body->m_islandIndex = m_bodyCount; m_bodies[m_bodyCount++] = body; } void Add(b2Contact* contact) { b2Assert(m_contactCount < m_contactCapacity); m_contacts[m_contactCount++] = contact; } void Add(b2Joint* joint) { b2Assert(m_jointCount < m_jointCapacity); m_joints[m_jointCount++] = joint; } void Report(b2ContactConstraint* constraints); b2StackAllocator* m_allocator; b2ContactListener* m_listener; b2Body** m_bodies; b2Contact** m_contacts; b2Joint** m_joints; b2Position* m_positions; b2Velocity* m_velocities; int32 m_bodyCount; int32 m_jointCount; int32 m_contactCount; int32 m_bodyCapacity; int32 m_contactCapacity; int32 m_jointCapacity; int32 m_positionIterationCount; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2WorldCallbacks.h0000644000000000000000000001401611077704466022464 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_WORLD_CALLBACKS_H #define B2_WORLD_CALLBACKS_H #include "../Common/b2Settings.h" struct b2Vec2; struct b2XForm; class b2Shape; class b2Body; class b2Joint; class b2Contact; struct b2ContactPoint; struct b2ContactResult; /// Joints and shapes are destroyed when their associated /// body is destroyed. Implement this listener so that you /// may nullify references to these joints and shapes. class b2DestructionListener { public: virtual ~b2DestructionListener() {} /// Called when any joint is about to be destroyed due /// to the destruction of one of its attached bodies. virtual void SayGoodbye(b2Joint* joint) = 0; /// Called when any shape is about to be destroyed due /// to the destruction of its parent body. virtual void SayGoodbye(b2Shape* shape) = 0; }; /// This is called when a body's shape passes outside of the world boundary. class b2BoundaryListener { public: virtual ~b2BoundaryListener() {} /// This is called for each body that leaves the world boundary. /// @warning you can't modify the world inside this callback. virtual void Violation(b2Body* body) = 0; }; /// Implement this class to provide collision filtering. In other words, you can implement /// this class if you want finer control over contact creation. class b2ContactFilter { public: virtual ~b2ContactFilter() {} /// Return true if contact calculations should be performed between these two shapes. /// @warning for performance reasons this is only called when the AABBs begin to overlap. virtual bool ShouldCollide(b2Shape* shape1, b2Shape* shape2); /// Return true if the given shape should be considered for ray intersection virtual bool RayCollide(void* userData, b2Shape* b2Shape); }; /// The default contact filter. extern b2ContactFilter b2_defaultFilter; /// Implement this class to get collision results. You can use these results for /// things like sounds and game logic. You can also get contact results by /// traversing the contact lists after the time step. However, you might miss /// some contacts because continuous physics leads to sub-stepping. /// Additionally you may receive multiple callbacks for the same contact in a /// single time step. /// You should strive to make your callbacks efficient because there may be /// many callbacks per time step. /// @warning The contact separation is the last computed value. /// @warning You cannot create/destroy Box2D entities inside these callbacks. class b2ContactListener { public: virtual ~b2ContactListener() {} /// Called when a contact point is added. This includes the geometry /// and the forces. virtual void Add(const b2ContactPoint* point) { B2_NOT_USED(point); } /// Called when a contact point persists. This includes the geometry /// and the forces. virtual void Persist(const b2ContactPoint* point) { B2_NOT_USED(point); } /// Called when a contact point is removed. This includes the last /// computed geometry and forces. virtual void Remove(const b2ContactPoint* point) { B2_NOT_USED(point); } /// Called after a contact point is solved. virtual void Result(const b2ContactResult* point) { B2_NOT_USED(point); } }; /// Color for debug drawing. Each value has the range [0,1]. struct b2Color { b2Color() {} b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {} float32 r, g, b; }; /// Implement and register this class with a b2World to provide debug drawing of physics /// entities in your game. class b2DebugDraw { public: b2DebugDraw(); virtual ~b2DebugDraw() {} enum { e_shapeBit = 0x0001, ///< draw shapes e_jointBit = 0x0002, ///< draw joint connections e_coreShapeBit = 0x0004, ///< draw core (TOI) shapes e_aabbBit = 0x0008, ///< draw axis aligned bounding boxes e_obbBit = 0x0010, ///< draw oriented bounding boxes e_pairBit = 0x0020, ///< draw broad-phase pairs e_centerOfMassBit = 0x0040, ///< draw center of mass frame e_controllerBit = 0x0080, ///< draw controllers }; /// Set the drawing flags. void SetFlags(uint32 flags); /// Get the drawing flags. uint32 GetFlags() const; /// Append flags to the current flags. void AppendFlags(uint32 flags); /// Clear flags from the current flags. void ClearFlags(uint32 flags); /// Draw a closed polygon provided in CCW order. virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; /// Draw a solid closed polygon provided in CCW order. virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0; /// Draw a circle. virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0; /// Draw a solid circle. virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0; /// Draw a line segment. virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0; /// Draw a transform. Choose your own length scale. /// @param xf a transform. virtual void DrawXForm(const b2XForm& xf) = 0; protected: uint32 m_drawFlags; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/0000755000000000000000000000000011414467241021474 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2TensorDampingController.h0000644000000000000000000000523211130023047026674 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_TENSORDAMPINGCONTROLLER_H #define B2_TENSORDAMPINGCONTROLLER_H #include "b2Controller.h" class b2TensorDampingControllerDef; /// Applies top down linear damping to the controlled bodies /// The damping is calculated by multiplying velocity by a matrix in local co-ordinates. class b2TensorDampingController : public b2Controller{ public: /// Tensor to use in damping model b2Mat22 T; /*Some examples (matrixes in format (row1; row2) ) (-a 0;0 -a) Standard isotropic damping with strength a (0 a;-a 0) Electron in fixed field - a force at right angles to velocity with proportional magnitude (-a 0;0 -b) Differing x and y damping. Useful e.g. for top-down wheels. */ //By the way, tensor in this case just means matrix, don't let the terminology get you down. /// Set this to a positive number to clamp the maximum amount of damping done. float32 maxTimestep; // Typically one wants maxTimestep to be 1/(max eigenvalue of T), so that damping will never cause something to reverse direction /// @see b2Controller::Step void Step(const b2TimeStep& step); protected: void Destroy(b2BlockAllocator* allocator); private: friend class b2TensorDampingControllerDef; b2TensorDampingController(const b2TensorDampingControllerDef* def); }; /// This class is used to build tensor damping controllers class b2TensorDampingControllerDef : public b2ControllerDef { public: /// Tensor to use in damping model b2Mat22 T; /// Set this to a positive number to clamp the maximum amount of damping done. float32 maxTimestep; /// Sets damping independantly along the x and y axes void SetAxisAligned(float32 xDamping,float32 yDamping); private: b2TensorDampingController* Create(b2BlockAllocator* allocator); }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2Controller.h0000644000000000000000000001001211135222025024173 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CONTROLLER_H #define B2_CONTROLLER_H #include "../../Dynamics/b2World.h" #include "../../Dynamics/b2Body.h" class b2Body; class b2World; class b2Controller; /// The various controller types supported by Box2D. enum b2ControllerType { e_unknownController = -1, e_buoyancyController, e_constantAccelController, e_constantForceController, e_gravityController, e_tensorDampingController, }; /// A controller edge is used to connect bodies and controllers together /// in a bipartite graph. struct b2ControllerEdge { b2Controller* controller; ///< provides quick access to other end of this edge. b2Body* body; ///< the body b2ControllerEdge* prevBody; ///< the previous controller edge in the controllers's joint list b2ControllerEdge* nextBody; ///< the next controller edge in the controllers's joint list b2ControllerEdge* prevController; ///< the previous controller edge in the body's joint list b2ControllerEdge* nextController; ///< the next controller edge in the body's joint list }; class b2ControllerDef; /// Base class for controllers. Controllers are a convience for encapsulating common /// per-step functionality. class b2Controller { public: virtual ~b2Controller(); /// Controllers override this to implement per-step functionality. virtual void Step(const b2TimeStep& step) = 0; /// Controllers override this to provide debug drawing. virtual void Draw(b2DebugDraw *debugDraw) {B2_NOT_USED(debugDraw);}; /// Adds a body to the controller list. void AddBody(b2Body* body); /// Removes a body from the controller list. void RemoveBody(b2Body* body); /// Removes all bodies from the controller list. void Clear(); /// Get the type of the controller b2ControllerType GetType(); /// Get the next controller in the world's body list. b2Controller* GetNext(); /// Get the parent world of this body. b2World* GetWorld(); /// Get the attached body list b2ControllerEdge* GetBodyList(); protected: friend class b2World; b2World* m_world; b2ControllerEdge* m_bodyList; int32 m_bodyCount; b2ControllerType m_type; b2Controller(const b2ControllerDef* def): m_world(NULL), m_bodyList(NULL), m_bodyCount(0), m_type(e_unknownController), m_prev(NULL), m_next(NULL) { B2_NOT_USED(def); } virtual void Destroy(b2BlockAllocator* allocator) = 0; private: b2Controller* m_prev; b2Controller* m_next; static void Destroy(b2Controller* controller, b2BlockAllocator* allocator); }; class b2ControllerDef { public: virtual ~b2ControllerDef() {}; private: friend class b2World; virtual b2Controller* Create(b2BlockAllocator* allocator) = 0; }; inline b2Controller* b2Controller::GetNext() { return m_next; } inline b2World* b2Controller::GetWorld() { return m_world; } inline b2ControllerEdge* b2Controller::GetBodyList() { return m_bodyList; } inline void b2Controller::Destroy(b2Controller* controller, b2BlockAllocator* allocator) { controller->Destroy(allocator); } inline b2ControllerType b2Controller::GetType() { return m_type; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2TensorDampingController.cpp0000644000000000000000000000452511135222025027235 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2TensorDampingController.h" b2TensorDampingController::b2TensorDampingController(const b2TensorDampingControllerDef* def) : b2Controller(def) { T = def->T; maxTimestep = def->maxTimestep; m_type = e_tensorDampingController; } void b2TensorDampingController::Step(const b2TimeStep& step) { float32 timestep = step.dt; if(timestep<=B2_FLT_EPSILON) return; if(timestep>maxTimestep && maxTimestep>0) timestep = maxTimestep; for(b2ControllerEdge *i=m_bodyList;i;i=i->nextBody){ b2Body* body = i->body; if(body->IsSleeping()) continue; b2Vec2 damping = body->GetWorldVector( b2Mul(T, body->GetLocalVector( body->GetLinearVelocity() ) ) ); body->SetLinearVelocity(body->GetLinearVelocity() + timestep * damping); } } void b2TensorDampingControllerDef::SetAxisAligned(float32 xDamping, float32 yDamping) { T.col1.x = -xDamping; T.col1.y = 0; T.col2.x = 0; T.col2.y = -yDamping; if(xDamping>0 || yDamping>0){ maxTimestep = 1/b2Max(xDamping,yDamping); }else{ maxTimestep = 0; } } void b2TensorDampingController::Destroy(b2BlockAllocator* allocator) { allocator->Free(this, sizeof(b2TensorDampingController)); } b2TensorDampingController* b2TensorDampingControllerDef::Create(b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2TensorDampingController)); return new (mem) b2TensorDampingController(this); }python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2BuoyancyController.h0000644000000000000000000000624711130023047025722 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_BUOYANCYCONTROLLER_H #define B2_BUOYANCYCONTROLLER_H #include "b2Controller.h" class b2BuoyancyControllerDef; /// Calculates buoyancy forces for fluids in the form of a half plane. class b2BuoyancyController : public b2Controller{ public: /// The outer surface normal b2Vec2 normal; /// The height of the fluid surface along the normal float32 offset; /// The fluid density float32 density; /// Fluid velocity, for drag calculations b2Vec2 velocity; /// Linear drag co-efficient float32 linearDrag; /// Linear drag co-efficient float32 angularDrag; /// If false, bodies are assumed to be uniformly dense, otherwise use the shapes densities bool useDensity; //False by default to prevent a gotcha /// If true, gravity is taken from the world instead of the gravity parameter. bool useWorldGravity; /// Gravity vector, if the world's gravity is not used b2Vec2 gravity; /// @see b2Controller::Step void Step(const b2TimeStep& step); /// @see b2Controller::Draw void Draw(b2DebugDraw *debugDraw); protected: void Destroy(b2BlockAllocator* allocator); private: friend class b2BuoyancyControllerDef; b2BuoyancyController(const b2BuoyancyControllerDef* def); }; /// This class is used to build buoyancy controllers class b2BuoyancyControllerDef : public b2ControllerDef { public: /// The outer surface normal b2Vec2 normal; /// The height of the fluid surface along the normal float32 offset; /// The fluid density float32 density; /// Fluid velocity, for drag calculations b2Vec2 velocity; /// Linear drag co-efficient float32 linearDrag; /// Linear drag co-efficient float32 angularDrag; /// If false, bodies are assumed to be uniformly dense, otherwise use the shapes densities bool useDensity; //False by default to prevent a gotcha /// If true, gravity is taken from the world instead of the gravity parameter. bool useWorldGravity; /// Gravity vector, if the world's gravity is not used b2Vec2 gravity; b2BuoyancyControllerDef(): normal(0,1), offset(0), density(0), velocity(0,0), linearDrag(0), angularDrag(0), useDensity(false), useWorldGravity(true), gravity(0,0) { } private: b2BuoyancyController* Create(b2BlockAllocator* allocator); }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2GravityController.cpp0000644000000000000000000000506511144075331026116 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2GravityController.h" b2GravityController::b2GravityController(const b2GravityControllerDef* def) : b2Controller(def) { G = def->G; invSqr = def->invSqr; m_type = e_gravityController; } void b2GravityController::Step(const b2TimeStep& step) { B2_NOT_USED(step); if(invSqr){ for(b2ControllerEdge *i=m_bodyList;i;i=i->nextBody){ b2Body* body1 = i->body; for(b2ControllerEdge *j=m_bodyList;j!=i;j=j->nextBody){ b2Body* body2 = j->body; b2Vec2 d = body2->GetWorldCenter() - body1->GetWorldCenter(); float32 r2 = d.LengthSquared(); if(r2 < B2_FLT_EPSILON) continue; b2Vec2 f = G / r2 / sqrt(r2) * body1->GetMass() * body2->GetMass() * d; body1->ApplyForce(f , body1->GetWorldCenter()); body2->ApplyForce(-1.0f*f, body2->GetWorldCenter()); } } }else{ for(b2ControllerEdge *i=m_bodyList;i;i=i->nextBody){ b2Body* body1 = i->body; for(b2ControllerEdge *j=m_bodyList;j!=i;j=j->nextBody){ b2Body* body2 = j->body; b2Vec2 d = body2->GetWorldCenter() - body1->GetWorldCenter(); float32 r2 = d.LengthSquared(); if(r2 < B2_FLT_EPSILON) continue; b2Vec2 f = G / r2 * body1->GetMass() * body2->GetMass() * d; body1->ApplyForce(f , body1->GetWorldCenter()); body2->ApplyForce(-1.0f*f, body2->GetWorldCenter()); } } } } void b2GravityController::Destroy(b2BlockAllocator* allocator) { allocator->Free(this, sizeof(b2GravityController)); } b2GravityController* b2GravityControllerDef::Create(b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2GravityController)); return new (mem) b2GravityController(this); } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2ConstantAccelController.h0000644000000000000000000000330211130023047026637 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CONSTANTACCELCONTROLLER_H #define B2_CONSTANTACCELCONTROLLER_H #include "b2Controller.h" class b2ConstantAccelControllerDef; /// Applies a force every frame class b2ConstantAccelController : public b2Controller{ public: /// The force to apply b2Vec2 A; /// @see b2Controller::Step void Step(const b2TimeStep& step); protected: void Destroy(b2BlockAllocator* allocator); private: friend class b2ConstantAccelControllerDef; b2ConstantAccelController(const b2ConstantAccelControllerDef* def); }; /// This class is used to build constant acceleration controllers class b2ConstantAccelControllerDef : public b2ControllerDef { public: /// The force to apply b2Vec2 A; private: b2ConstantAccelController* Create(b2BlockAllocator* allocator); }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2ConstantForceController.h0000644000000000000000000000327311130023047026675 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CONSTANTFORCECONTROLLER_H #define B2_CONSTANTFORCECONTROLLER_H #include "b2Controller.h" class b2ConstantForceControllerDef; /// Applies a force every frame class b2ConstantForceController : public b2Controller { public: /// The force to apply b2Vec2 F; /// @see b2Controller::Step void Step(const b2TimeStep& step); protected: void Destroy(b2BlockAllocator* allocator); private: friend class b2ConstantForceControllerDef; b2ConstantForceController(const b2ConstantForceControllerDef* def); }; /// This class is used to build constant force controllers class b2ConstantForceControllerDef : public b2ControllerDef { public: /// The force to apply b2Vec2 F; private: b2ConstantForceController* Create(b2BlockAllocator* allocator); }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2GravityController.h0000644000000000000000000000356611130023047025557 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_GRAVITYCONTROLLER_H #define B2_GRAVITYCONTROLLER_H #include "b2Controller.h" class b2GravityControllerDef; /// Applies simplified gravity between every pair of bodies class b2GravityController : public b2Controller{ public: /// Specifies the strength of the gravitiation force float32 G; /// If true, gravity is proportional to r^-2, otherwise r^-1 bool invSqr; /// @see b2Controller::Step void Step(const b2TimeStep& step); protected: void Destroy(b2BlockAllocator* allocator); private: friend class b2GravityControllerDef; b2GravityController(const b2GravityControllerDef* def); }; /// This class is used to build gravity controllers class b2GravityControllerDef : public b2ControllerDef { public: /// Specifies the strength of the gravitiation force float32 G; /// If true, gravity is proportional to r^-2, otherwise r^-1 bool invSqr; private: b2GravityController* Create(b2BlockAllocator* allocator); }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2ConstantForceController.cpp0000644000000000000000000000334211135222025027227 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2ConstantForceController.h" b2ConstantForceController::b2ConstantForceController(const b2ConstantForceControllerDef* def) : b2Controller(def) { F = def->F; m_type = e_constantForceController; } void b2ConstantForceController::Step(const b2TimeStep& step) { B2_NOT_USED(step); for(b2ControllerEdge *i=m_bodyList;i;i=i->nextBody){ b2Body* body = i->body; if(body->IsSleeping()) continue; body->ApplyForce(F,body->GetWorldCenter()); } } void b2ConstantForceController::Destroy(b2BlockAllocator* allocator) { allocator->Free(this, sizeof(b2ConstantForceController)); } b2ConstantForceController* b2ConstantForceControllerDef::Create(b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2ConstantForceController)); return new (mem) b2ConstantForceController(this); }python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2Controller.cpp0000644000000000000000000000635511130023047024543 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Controller.h" #include "../../Common/b2BlockAllocator.h" b2Controller::~b2Controller() { //Remove attached bodies Clear(); } void b2Controller::AddBody(b2Body* body) { void* mem = m_world->m_blockAllocator.Allocate(sizeof(b2ControllerEdge)); b2ControllerEdge* edge = new (mem) b2ControllerEdge; edge->body = body; edge->controller = this; //Add edge to controller list edge->nextBody = m_bodyList; edge->prevBody = NULL; if(m_bodyList) m_bodyList->prevBody = edge; m_bodyList = edge; ++m_bodyCount; //Add edge to body list edge->nextController = body->m_controllerList; edge->prevController = NULL; if(body->m_controllerList) body->m_controllerList->prevController = edge; body->m_controllerList = edge; } void b2Controller::RemoveBody(b2Body* body) { //Assert that the controller is not empty b2Assert(m_bodyCount>0); //Find the corresponding edge b2ControllerEdge* edge = m_bodyList; while(edge && edge->body!=body) edge = edge->nextBody; //Assert that we are removing a body that is currently attached to the controller b2Assert(edge!=NULL); //Remove edge from controller list if(edge->prevBody) edge->prevBody->nextBody = edge->nextBody; if(edge->nextBody) edge->nextBody->prevBody = edge->prevBody; if(edge == m_bodyList) m_bodyList = edge->nextBody; --m_bodyCount; //Remove edge from body list if(edge->prevController) edge->prevController->nextController = edge->nextController; if(edge->nextController) edge->nextController->prevController = edge->prevController; if(edge == body->m_controllerList) body->m_controllerList = edge->nextController; //Free the edge m_world->m_blockAllocator.Free(edge, sizeof(b2ControllerEdge)); } void b2Controller::Clear(){ while(m_bodyList) { b2ControllerEdge* edge = m_bodyList; //Remove edge from controller list m_bodyList = edge->nextBody; //Remove edge from body list if(edge->prevController) edge->prevController->nextController = edge->nextController; if(edge->nextController) edge->nextController->prevController = edge->prevController; if(edge == edge->body->m_controllerList) edge->body->m_controllerList = edge->nextController; //Free the edge m_world->m_blockAllocator.Free(edge, sizeof(b2ControllerEdge)); } m_bodyCount = 0; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2BuoyancyController.cpp0000644000000000000000000000706511135222025026256 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2BuoyancyController.h" b2BuoyancyController::b2BuoyancyController(const b2BuoyancyControllerDef* def) : b2Controller(def) { normal = def->normal; offset = def->offset; density = def->density; velocity = def->velocity; linearDrag = def->linearDrag; angularDrag = def->angularDrag; useDensity = def->useDensity; useWorldGravity = def->useWorldGravity; gravity = def->gravity; m_type = e_buoyancyController; } void b2BuoyancyController::Step(const b2TimeStep& step) { B2_NOT_USED(step); if(!m_bodyList) return; if(useWorldGravity){ gravity = m_world->GetGravity(); } for(b2ControllerEdge *i=m_bodyList;i;i=i->nextBody){ b2Body* body = i->body; if(body->IsSleeping()){ //Buoyancy force is just a function of position, //so unlike most forces, it is safe to ignore sleeping bodes continue; } b2Vec2 areac(0,0); b2Vec2 massc(0,0); float32 area = 0; float32 mass = 0; for(b2Shape* shape=body->GetShapeList();shape;shape=shape->GetNext()){ b2Vec2 sc(0,0); float32 sarea = shape->ComputeSubmergedArea(normal,offset,body->GetXForm(),&sc); area += sarea; areac.x += sarea * sc.x; areac.y += sarea * sc.y; float shapeDensity = 0; if(useDensity){ //TODO: Expose density publicly shapeDensity=shape->GetDensity(); }else{ shapeDensity = 1; } mass += sarea*shapeDensity; massc.x += sarea * sc.x * shapeDensity; massc.y += sarea * sc.y * shapeDensity; } areac.x/=area; areac.y/=area; b2Vec2 localCentroid = b2MulT(body->GetXForm(),areac); massc.x/=mass; massc.y/=mass; if(areaApplyForce(buoyancyForce,massc); //Linear drag b2Vec2 dragForce = body->GetLinearVelocityFromWorldPoint(areac) - velocity; dragForce *= -linearDrag*area; body->ApplyForce(dragForce,areac); //Angular drag //TODO: Something that makes more physical sense? body->ApplyTorque(-body->GetInertia()/body->GetMass()*area*body->GetAngularVelocity()*angularDrag); } } void b2BuoyancyController::Draw(b2DebugDraw *debugDraw) { float32 r = 1000; b2Vec2 p1 = offset * normal + b2Cross(normal, r); b2Vec2 p2 = offset * normal - b2Cross(normal, r); b2Color color(0,0,0.8f); debugDraw->DrawSegment(p1, p2, color); } void b2BuoyancyController::Destroy(b2BlockAllocator* allocator) { allocator->Free(this, sizeof(b2BuoyancyController)); } b2BuoyancyController* b2BuoyancyControllerDef::Create(b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2BuoyancyController)); return new (mem) b2BuoyancyController(this); }python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Controllers/b2ConstantAccelController.cpp0000644000000000000000000000334011135222025027176 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2ConstantAccelController.h" b2ConstantAccelController::b2ConstantAccelController(const b2ConstantAccelControllerDef* def) : b2Controller(def) { A = def->A; m_type = e_constantAccelController; } void b2ConstantAccelController::Step(const b2TimeStep& step) { for(b2ControllerEdge *i=m_bodyList;i;i=i->nextBody){ b2Body* body = i->body; if(body->IsSleeping()) continue; body->SetLinearVelocity(body->GetLinearVelocity()+step.dt*A); } } void b2ConstantAccelController::Destroy(b2BlockAllocator* allocator) { allocator->Free(this, sizeof(b2ConstantAccelController)); } b2ConstantAccelController* b2ConstantAccelControllerDef::Create(b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2ConstantAccelController)); return new (mem) b2ConstantAccelController(this); }python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/0000755000000000000000000000000011414467242020745 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2NullContact.h0000644000000000000000000000226711064106301023562 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_NULL_CONTACT_H #define B2_NULL_CONTACT_H #include "../../Common/b2Math.h" #include "b2Contact.h" class b2NullContact : public b2Contact { public: b2NullContact() {} void Evaluate(b2ContactListener*) {} b2Manifold* GetManifolds() { return NULL; } }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2PolyContact.h0000644000000000000000000000267411064106301023575 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef POLYCONTACT_H #define POLYCONTACT_H #include "b2Contact.h" class b2BlockAllocator; class b2PolygonContact : public b2Contact { public: static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2PolygonContact(b2Shape* shape1, b2Shape* shape2); ~b2PolygonContact() {} void Evaluate(b2ContactListener* listener); b2Manifold* GetManifolds() { return &m_manifold; } b2Manifold m_manifold; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2CircleContact.h0000644000000000000000000000301311064106301024037 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef CIRCLE_CONTACT_H #define CIRCLE_CONTACT_H #include "../../Common/b2Math.h" #include "../../Collision/b2Collision.h" #include "b2Contact.h" class b2BlockAllocator; class b2CircleContact : public b2Contact { public: static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2CircleContact(b2Shape* shape1, b2Shape* shape2); ~b2CircleContact() {} void Evaluate(b2ContactListener* listener); b2Manifold* GetManifolds() { return &m_manifold; } b2Manifold m_manifold; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2ContactSolver.cpp0000644000000000000000000005212411065735647024500 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2ContactSolver.h" #include "b2Contact.h" #include "../b2Body.h" #include "../b2World.h" #include "../../Common/b2StackAllocator.h" #define B2_DEBUG_SOLVER 0 b2ContactSolver::b2ContactSolver(const b2TimeStep& step, b2Contact** contacts, int32 contactCount, b2StackAllocator* allocator) { m_step = step; m_allocator = allocator; m_constraintCount = 0; for (int32 i = 0; i < contactCount; ++i) { b2Assert(contacts[i]->IsSolid()); m_constraintCount += contacts[i]->GetManifoldCount(); } m_constraints = (b2ContactConstraint*)m_allocator->Allocate(m_constraintCount * sizeof(b2ContactConstraint)); int32 count = 0; for (int32 i = 0; i < contactCount; ++i) { b2Contact* contact = contacts[i]; b2Shape* shape1 = contact->m_shape1; b2Shape* shape2 = contact->m_shape2; b2Body* b1 = shape1->GetBody(); b2Body* b2 = shape2->GetBody(); int32 manifoldCount = contact->GetManifoldCount(); b2Manifold* manifolds = contact->GetManifolds(); float32 friction = b2MixFriction(shape1->GetFriction(), shape2->GetFriction()); float32 restitution = b2MixRestitution(shape1->GetRestitution(), shape2->GetRestitution()); b2Vec2 v1 = b1->m_linearVelocity; b2Vec2 v2 = b2->m_linearVelocity; float32 w1 = b1->m_angularVelocity; float32 w2 = b2->m_angularVelocity; for (int32 j = 0; j < manifoldCount; ++j) { b2Manifold* manifold = manifolds + j; b2Assert(manifold->pointCount > 0); const b2Vec2 normal = manifold->normal; b2Assert(count < m_constraintCount); b2ContactConstraint* cc = m_constraints + count; cc->body1 = b1; cc->body2 = b2; cc->manifold = manifold; cc->normal = normal; cc->pointCount = manifold->pointCount; cc->friction = friction; cc->restitution = restitution; for (int32 k = 0; k < cc->pointCount; ++k) { b2ManifoldPoint* cp = manifold->points + k; b2ContactConstraintPoint* ccp = cc->points + k; ccp->normalImpulse = cp->normalImpulse; ccp->tangentImpulse = cp->tangentImpulse; ccp->separation = cp->separation; ccp->localAnchor1 = cp->localPoint1; ccp->localAnchor2 = cp->localPoint2; ccp->r1 = b2Mul(b1->GetXForm().R, cp->localPoint1 - b1->GetLocalCenter()); ccp->r2 = b2Mul(b2->GetXForm().R, cp->localPoint2 - b2->GetLocalCenter()); float32 rn1 = b2Cross(ccp->r1, normal); float32 rn2 = b2Cross(ccp->r2, normal); rn1 *= rn1; rn2 *= rn2; float32 kNormal = b1->m_invMass + b2->m_invMass + b1->m_invI * rn1 + b2->m_invI * rn2; b2Assert(kNormal > B2_FLT_EPSILON); ccp->normalMass = 1.0f / kNormal; float32 kEqualized = b1->m_mass * b1->m_invMass + b2->m_mass * b2->m_invMass; kEqualized += b1->m_mass * b1->m_invI * rn1 + b2->m_mass * b2->m_invI * rn2; b2Assert(kEqualized > B2_FLT_EPSILON); ccp->equalizedMass = 1.0f / kEqualized; b2Vec2 tangent = b2Cross(normal, 1.0f); float32 rt1 = b2Cross(ccp->r1, tangent); float32 rt2 = b2Cross(ccp->r2, tangent); rt1 *= rt1; rt2 *= rt2; float32 kTangent = b1->m_invMass + b2->m_invMass + b1->m_invI * rt1 + b2->m_invI * rt2; b2Assert(kTangent > B2_FLT_EPSILON); ccp->tangentMass = 1.0f / kTangent; // Setup a velocity bias for restitution. ccp->velocityBias = 0.0f; if (ccp->separation > 0.0f) { ccp->velocityBias = -step.inv_dt * ccp->separation; // TODO_ERIN b2TimeStep } else { float32 vRel = b2Dot(cc->normal, v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1)); if (vRel < -b2_velocityThreshold) { ccp->velocityBias = -cc->restitution * vRel; } } } // If we have two points, then prepare the block solver. if (cc->pointCount == 2) { b2ContactConstraintPoint* ccp1 = cc->points + 0; b2ContactConstraintPoint* ccp2 = cc->points + 1; float32 invMass1 = b1->m_invMass; float32 invI1 = b1->m_invI; float32 invMass2 = b2->m_invMass; float32 invI2 = b2->m_invI; float32 rn11 = b2Cross(ccp1->r1, normal); float32 rn12 = b2Cross(ccp1->r2, normal); float32 rn21 = b2Cross(ccp2->r1, normal); float32 rn22 = b2Cross(ccp2->r2, normal); float32 k11 = invMass1 + invMass2 + invI1 * rn11 * rn11 + invI2 * rn12 * rn12; float32 k22 = invMass1 + invMass2 + invI1 * rn21 * rn21 + invI2 * rn22 * rn22; float32 k12 = invMass1 + invMass2 + invI1 * rn11 * rn21 + invI2 * rn12 * rn22; // Ensure a reasonable condition number. const float32 k_maxConditionNumber = 100.0f; if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) { // K is safe to invert. cc->K.col1.Set(k11, k12); cc->K.col2.Set(k12, k22); cc->normalMass = cc->K.GetInverse(); } else { // The constraints are redundant, just use one. // TODO_ERIN use deepest? cc->pointCount = 1; } } ++count; } } b2Assert(count == m_constraintCount); } b2ContactSolver::~b2ContactSolver() { m_allocator->Free(m_constraints); } void b2ContactSolver::InitVelocityConstraints(const b2TimeStep& step) { // Warm start. for (int32 i = 0; i < m_constraintCount; ++i) { b2ContactConstraint* c = m_constraints + i; b2Body* b1 = c->body1; b2Body* b2 = c->body2; float32 invMass1 = b1->m_invMass; float32 invI1 = b1->m_invI; float32 invMass2 = b2->m_invMass; float32 invI2 = b2->m_invI; b2Vec2 normal = c->normal; b2Vec2 tangent = b2Cross(normal, 1.0f); if (step.warmStarting) { for (int32 j = 0; j < c->pointCount; ++j) { b2ContactConstraintPoint* ccp = c->points + j; ccp->normalImpulse *= step.dtRatio; ccp->tangentImpulse *= step.dtRatio; b2Vec2 P = ccp->normalImpulse * normal + ccp->tangentImpulse * tangent; b1->m_angularVelocity -= invI1 * b2Cross(ccp->r1, P); b1->m_linearVelocity -= invMass1 * P; b2->m_angularVelocity += invI2 * b2Cross(ccp->r2, P); b2->m_linearVelocity += invMass2 * P; } } else { for (int32 j = 0; j < c->pointCount; ++j) { b2ContactConstraintPoint* ccp = c->points + j; ccp->normalImpulse = 0.0f; ccp->tangentImpulse = 0.0f; } } } } void b2ContactSolver::SolveVelocityConstraints() { for (int32 i = 0; i < m_constraintCount; ++i) { b2ContactConstraint* c = m_constraints + i; b2Body* b1 = c->body1; b2Body* b2 = c->body2; float32 w1 = b1->m_angularVelocity; float32 w2 = b2->m_angularVelocity; b2Vec2 v1 = b1->m_linearVelocity; b2Vec2 v2 = b2->m_linearVelocity; float32 invMass1 = b1->m_invMass; float32 invI1 = b1->m_invI; float32 invMass2 = b2->m_invMass; float32 invI2 = b2->m_invI; b2Vec2 normal = c->normal; b2Vec2 tangent = b2Cross(normal, 1.0f); float32 friction = c->friction; b2Assert(c->pointCount == 1 || c->pointCount == 2); // Solve normal constraints if (c->pointCount == 1) { b2ContactConstraintPoint* ccp = c->points + 0; // Relative velocity at contact b2Vec2 dv = v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1); // Compute normal impulse float32 vn = b2Dot(dv, normal); float32 lambda = -ccp->normalMass * (vn - ccp->velocityBias); // b2Clamp the accumulated impulse float32 newImpulse = b2Max(ccp->normalImpulse + lambda, 0.0f); lambda = newImpulse - ccp->normalImpulse; // Apply contact impulse b2Vec2 P = lambda * normal; v1 -= invMass1 * P; w1 -= invI1 * b2Cross(ccp->r1, P); v2 += invMass2 * P; w2 += invI2 * b2Cross(ccp->r2, P); ccp->normalImpulse = newImpulse; } else { // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite). // Build the mini LCP for this contact patch // // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2 // // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n ) // b = vn_0 - velocityBias // // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid // solution that satisfies the problem is chosen. // // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i). // // Substitute: // // x = x' - a // // Plug into above equation: // // vn = A * x + b // = A * (x' - a) + b // = A * x' + b - A * a // = A * x' + b' // b' = b - A * a; b2ContactConstraintPoint* cp1 = c->points + 0; b2ContactConstraintPoint* cp2 = c->points + 1; b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse); b2Assert(a.x >= 0.0f && a.y >= 0.0f); // Relative velocity at contact b2Vec2 dv1 = v2 + b2Cross(w2, cp1->r2) - v1 - b2Cross(w1, cp1->r1); b2Vec2 dv2 = v2 + b2Cross(w2, cp2->r2) - v1 - b2Cross(w1, cp2->r1); // Compute normal velocity float32 vn1 = b2Dot(dv1, normal); float32 vn2 = b2Dot(dv2, normal); b2Vec2 b; b.x = vn1 - cp1->velocityBias; b.y = vn2 - cp2->velocityBias; b -= b2Mul(c->K, a); const float32 k_errorTol = 1e-3f; B2_NOT_USED(k_errorTol); for (;;) { // // Case 1: vn = 0 // // 0 = A * x' + b' // // Solve for x': // // x' = - inv(A) * b' // b2Vec2 x = - b2Mul(c->normalMass, b); if (x.x >= 0.0f && x.y >= 0.0f) { // Resubstitute for the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; v1 -= invMass1 * (P1 + P2); w1 -= invI1 * (b2Cross(cp1->r1, P1) + b2Cross(cp2->r1, P2)); v2 += invMass2 * (P1 + P2); w2 += invI2 * (b2Cross(cp1->r2, P1) + b2Cross(cp2->r2, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = v2 + b2Cross(w2, cp1->r2) - v1 - b2Cross(w1, cp1->r1); dv2 = v2 + b2Cross(w2, cp2->r2) - v1 - b2Cross(w1, cp2->r1); // Compute normal velocity vn1 = b2Dot(dv1, normal); vn2 = b2Dot(dv2, normal); b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); #endif break; } // // Case 2: vn1 = 0 and x2 = 0 // // 0 = a11 * x1' + a12 * 0 + b1' // vn2 = a21 * x1' + a22 * 0 + b2' // x.x = - cp1->normalMass * b.x; x.y = 0.0f; vn1 = 0.0f; vn2 = c->K.col1.y * x.x + b.y; if (x.x >= 0.0f && vn2 >= 0.0f) { // Resubstitute for the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; v1 -= invMass1 * (P1 + P2); w1 -= invI1 * (b2Cross(cp1->r1, P1) + b2Cross(cp2->r1, P2)); v2 += invMass2 * (P1 + P2); w2 += invI2 * (b2Cross(cp1->r2, P1) + b2Cross(cp2->r2, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = v2 + b2Cross(w2, cp1->r2) - v1 - b2Cross(w1, cp1->r1); // Compute normal velocity vn1 = b2Dot(dv1, normal); b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol); #endif break; } // // Case 3: w2 = 0 and x1 = 0 // // vn1 = a11 * 0 + a12 * x2' + b1' // 0 = a21 * 0 + a22 * x2' + b2' // x.x = 0.0f; x.y = - cp2->normalMass * b.y; vn1 = c->K.col2.x * x.y + b.x; vn2 = 0.0f; if (x.y >= 0.0f && vn1 >= 0.0f) { // Resubstitute for the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; v1 -= invMass1 * (P1 + P2); w1 -= invI1 * (b2Cross(cp1->r1, P1) + b2Cross(cp2->r1, P2)); v2 += invMass2 * (P1 + P2); w2 += invI2 * (b2Cross(cp1->r2, P1) + b2Cross(cp2->r2, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; #if B2_DEBUG_SOLVER == 1 // Postconditions dv2 = v2 + b2Cross(w2, cp2->r2) - v1 - b2Cross(w1, cp2->r1); // Compute normal velocity vn2 = b2Dot(dv2, normal); b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol); #endif break; } // // Case 4: x1 = 0 and x2 = 0 // // vn1 = b1 // vn2 = b2; x.x = 0.0f; x.y = 0.0f; vn1 = b.x; vn2 = b.y; if (vn1 >= 0.0f && vn2 >= 0.0f ) { // Resubstitute for the incremental impulse b2Vec2 d = x - a; // Apply incremental impulse b2Vec2 P1 = d.x * normal; b2Vec2 P2 = d.y * normal; v1 -= invMass1 * (P1 + P2); w1 -= invI1 * (b2Cross(cp1->r1, P1) + b2Cross(cp2->r1, P2)); v2 += invMass2 * (P1 + P2); w2 += invI2 * (b2Cross(cp1->r2, P1) + b2Cross(cp2->r2, P2)); // Accumulate cp1->normalImpulse = x.x; cp2->normalImpulse = x.y; break; } // No solution, give up. This is hit sometimes, but it doesn't seem to matter. break; } } // Solve tangent constraints for (int32 j = 0; j < c->pointCount; ++j) { b2ContactConstraintPoint* ccp = c->points + j; // Relative velocity at contact b2Vec2 dv = v2 + b2Cross(w2, ccp->r2) - v1 - b2Cross(w1, ccp->r1); // Compute tangent force float32 vt = b2Dot(dv, tangent); float32 lambda = ccp->tangentMass * (-vt); // b2Clamp the accumulated force float32 maxFriction = friction * ccp->normalImpulse; float32 newImpulse = b2Clamp(ccp->tangentImpulse + lambda, -maxFriction, maxFriction); lambda = newImpulse - ccp->tangentImpulse; // Apply contact impulse b2Vec2 P = lambda * tangent; v1 -= invMass1 * P; w1 -= invI1 * b2Cross(ccp->r1, P); v2 += invMass2 * P; w2 += invI2 * b2Cross(ccp->r2, P); ccp->tangentImpulse = newImpulse; } b1->m_linearVelocity = v1; b1->m_angularVelocity = w1; b2->m_linearVelocity = v2; b2->m_angularVelocity = w2; } } void b2ContactSolver::FinalizeVelocityConstraints() { for (int32 i = 0; i < m_constraintCount; ++i) { b2ContactConstraint* c = m_constraints + i; b2Manifold* m = c->manifold; for (int32 j = 0; j < c->pointCount; ++j) { m->points[j].normalImpulse = c->points[j].normalImpulse; m->points[j].tangentImpulse = c->points[j].tangentImpulse; } } } #if 1 // Sequential solver. bool b2ContactSolver::SolvePositionConstraints(float32 baumgarte) { float32 minSeparation = 0.0f; for (int32 i = 0; i < m_constraintCount; ++i) { b2ContactConstraint* c = m_constraints + i; b2Body* b1 = c->body1; b2Body* b2 = c->body2; float32 invMass1 = b1->m_mass * b1->m_invMass; float32 invI1 = b1->m_mass * b1->m_invI; float32 invMass2 = b2->m_mass * b2->m_invMass; float32 invI2 = b2->m_mass * b2->m_invI; b2Vec2 normal = c->normal; // Solver normal constraints for (int32 j = 0; j < c->pointCount; ++j) { b2ContactConstraintPoint* ccp = c->points + j; b2Vec2 r1 = b2Mul(b1->GetXForm().R, ccp->localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, ccp->localAnchor2 - b2->GetLocalCenter()); b2Vec2 p1 = b1->m_sweep.c + r1; b2Vec2 p2 = b2->m_sweep.c + r2; b2Vec2 dp = p2 - p1; // Approximate the current separation. float32 separation = b2Dot(dp, normal) + ccp->separation; // Track max constraint error. minSeparation = b2Min(minSeparation, separation); // Prevent large corrections and allow slop. float32 C = baumgarte * b2Clamp(separation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); // Compute normal impulse float32 impulse = -ccp->equalizedMass * C; b2Vec2 P = impulse * normal; b1->m_sweep.c -= invMass1 * P; b1->m_sweep.a -= invI1 * b2Cross(r1, P); b1->SynchronizeTransform(); b2->m_sweep.c += invMass2 * P; b2->m_sweep.a += invI2 * b2Cross(r2, P); b2->SynchronizeTransform(); } } // We can't expect minSpeparation >= -b2_linearSlop because we don't // push the separation above -b2_linearSlop. return minSeparation >= -1.5f * b2_linearSlop; } #else // Block solver. Doesn't seem that great. void b2ContactSolver::SolvePositionConstraints(float32 baumgarte) { for (int32 i = 0; i < m_constraintCount; ++i) { b2ContactConstraint* c = m_constraints + i; b2Body* b1 = c->body1; b2Body* b2 = c->body2; float32 invMass1 = b1->m_mass * b1->m_invMass; float32 invI1 = b1->m_mass * b1->m_invI; float32 invMass2 = b2->m_mass * b2->m_invMass; float32 invI2 = b2->m_mass * b2->m_invI; b2Vec2 normal = c->normal; bool singlePoint = c->pointCount == 1; if (c->pointCount == 2) { b2ContactConstraintPoint* ccp1 = c->points + 0; b2ContactConstraintPoint* ccp2 = c->points + 1; b2Vec2 r11 = b2Mul(b1->GetXForm().R, ccp1->localAnchor1 - b1->GetLocalCenter()); b2Vec2 r12 = b2Mul(b2->GetXForm().R, ccp1->localAnchor2 - b2->GetLocalCenter()); b2Vec2 r21 = b2Mul(b1->GetXForm().R, ccp2->localAnchor1 - b1->GetLocalCenter()); b2Vec2 r22 = b2Mul(b2->GetXForm().R, ccp2->localAnchor2 - b2->GetLocalCenter()); b2Vec2 p11 = b1->m_sweep.c + r11; b2Vec2 p12 = b2->m_sweep.c + r12; b2Vec2 dp1 = p12 - p11; b2Vec2 p21 = b1->m_sweep.c + r21; b2Vec2 p22 = b2->m_sweep.c + r22; b2Vec2 dp2 = p22 - p21; float32 rn11 = b2Cross(r11, normal); float32 rn12 = b2Cross(r12, normal); float32 rn21 = b2Cross(r21, normal); float32 rn22 = b2Cross(r22, normal); float32 k11 = invMass1 + invMass2 + invI1 * rn11 * rn11 + invI2 * rn12 * rn12; float32 k22 = invMass1 + invMass2 + invI1 * rn21 * rn21 + invI2 * rn22 * rn22; float32 k12 = invMass1 + invMass2 + invI1 * rn11 * rn21 + invI2 * rn12 * rn22; // Ensure a reasonable condition number. const float32 k_maxConditionNumber = 100.0f; if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) { b2Mat22 K; K.col1.Set(k11, k12); K.col2.Set(k12, k22); float32 separation1 = b2Dot(dp1, normal) + ccp1->separation; float32 separation2 = b2Dot(dp2, normal) + ccp2->separation; b2Vec2 C; C.x = baumgarte * (separation1 + b2_linearSlop); C.y = baumgarte * (separation2 + b2_linearSlop); b2Vec2 f = K.Solve(-C); if (f.x < 0.0f && f.y < 0.0f) { f.SetZero(); } else if (f.x < 0.0f) { f.x = 0.0f; f.y = -C.y / k22; } else if (f.y < 0.0f) { f.x = -C.x / k11; f.y = 0.0f; } b2Vec2 P1 = f.x * normal; b2Vec2 P2 = f.y * normal; b1->m_sweep.c -= invMass1 * (P1 + P2); b1->m_sweep.a -= invI1 * (b2Cross(r11, P1) + b2Cross(r21, P2)); b1->SynchronizeTransform(); b2->m_sweep.c += invMass2 * (P1 + P2); b2->m_sweep.a += invI2 * (b2Cross(r12, P1) + b2Cross(r22, P2)); b2->SynchronizeTransform(); } else { // The constraints are linearly dependent, so just use the first one. // This my cause a problem if the deepest one is ignored. singlePoint = true; } } if (singlePoint) { b2ContactConstraintPoint* ccp = c->points + 0; b2Vec2 r1 = b2Mul(b1->GetXForm().R, ccp->localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, ccp->localAnchor2 - b2->GetLocalCenter()); b2Vec2 p1 = b1->m_sweep.c + r1; b2Vec2 p2 = b2->m_sweep.c + r2; b2Vec2 dp = p2 - p1; // Approximate the current separation. float32 separation = b2Dot(dp, normal) + ccp->separation; // Prevent large corrections and allow slop. float32 C = baumgarte * b2Clamp(separation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); // Compute normal impulse float32 impulse = -ccp->equalizedMass * C; b2Vec2 P = impulse * normal; b1->m_sweep.c -= invMass1 * P; b1->m_sweep.a -= invI1 * b2Cross(r1, P); b1->SynchronizeTransform(); b2->m_sweep.c += invMass2 * P; b2->m_sweep.a += invI2 * b2Cross(r2, P); b2->SynchronizeTransform(); } } } #endifpython-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2PolyAndCircleContact.cpp0000644000000000000000000001120111065735647025705 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2PolyAndCircleContact.h" #include "../b2Body.h" #include "../b2WorldCallbacks.h" #include "../../Common/b2BlockAllocator.h" #include #include b2Contact* b2PolyAndCircleContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2PolyAndCircleContact)); return new (mem) b2PolyAndCircleContact(shape1, shape2); } void b2PolyAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2PolyAndCircleContact*)contact)->~b2PolyAndCircleContact(); allocator->Free(contact, sizeof(b2PolyAndCircleContact)); } b2PolyAndCircleContact::b2PolyAndCircleContact(b2Shape* s1, b2Shape* s2) : b2Contact(s1, s2) { b2Assert(m_shape1->GetType() == e_polygonShape); b2Assert(m_shape2->GetType() == e_circleShape); m_manifold.pointCount = 0; } void b2PolyAndCircleContact::Evaluate(b2ContactListener* listener) { b2Body* b1 = m_shape1->GetBody(); b2Body* b2 = m_shape2->GetBody(); b2Manifold m0; memcpy(&m0, &m_manifold, sizeof(b2Manifold)); b2CollidePolygonAndCircle(&m_manifold, (b2PolygonShape*)m_shape1, b1->GetXForm(), (b2CircleShape*)m_shape2, b2->GetXForm()); bool persisted[b2_maxManifoldPoints] = {false, false}; b2ContactPoint cp; cp.shape1 = m_shape1; cp.shape2 = m_shape2; cp.friction = b2MixFriction(m_shape1->GetFriction(), m_shape2->GetFriction()); cp.restitution = b2MixRestitution(m_shape1->GetRestitution(), m_shape2->GetRestitution()); // Match contact ids to facilitate warm starting. if (m_manifold.pointCount > 0) { // Match old contact ids to new contact ids and copy the // stored impulses to warm start the solver. for (int32 i = 0; i < m_manifold.pointCount; ++i) { b2ManifoldPoint* mp = m_manifold.points + i; mp->normalImpulse = 0.0f; mp->tangentImpulse = 0.0f; bool found = false; b2ContactID id = mp->id; for (int32 j = 0; j < m0.pointCount; ++j) { if (persisted[j] == true) { continue; } b2ManifoldPoint* mp0 = m0.points + j; if (mp0->id.key == id.key) { persisted[j] = true; mp->normalImpulse = mp0->normalImpulse; mp->tangentImpulse = mp0->tangentImpulse; // A persistent point. found = true; // Report persistent point. if (listener != NULL) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = id; listener->Persist(&cp); } break; } } // Report added point. if (found == false && listener != NULL) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = id; listener->Add(&cp); } } m_manifoldCount = 1; } else { m_manifoldCount = 0; } if (listener == NULL) { return; } // Report removed points. for (int32 i = 0; i < m0.pointCount; ++i) { if (persisted[i]) { continue; } b2ManifoldPoint* mp0 = m0.points + i; cp.position = b1->GetWorldPoint(mp0->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2); cp.velocity = v2 - v1; cp.normal = m0.normal; cp.separation = mp0->separation; cp.id = mp0->id; listener->Remove(&cp); } } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2PolyAndCircleContact.h0000644000000000000000000000274611064106301025342 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef POLY_AND_CIRCLE_CONTACT_H #define POLY_AND_CIRCLE_CONTACT_H #include "b2Contact.h" class b2BlockAllocator; class b2PolyAndCircleContact : public b2Contact { public: static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2PolyAndCircleContact(b2Shape* shape1, b2Shape* shape2); ~b2PolyAndCircleContact() {} void Evaluate(b2ContactListener* listener); b2Manifold* GetManifolds() { return &m_manifold; } b2Manifold m_manifold; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h0000644000000000000000000000350111130023047025250 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef EDGE_AND_CIRCLE_CONTACT_H #define EDGE_AND_CIRCLE_CONTACT_H #include "../../Common/b2Math.h" #include "../../Collision/b2Collision.h" #include "../../Collision/Shapes/b2EdgeShape.h" #include "../../Collision/Shapes/b2CircleShape.h" #include "b2Contact.h" class b2BlockAllocator; class b2EdgeAndCircleContact : public b2Contact { public: static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2EdgeAndCircleContact(b2Shape* shape1, b2Shape* shape2); ~b2EdgeAndCircleContact() {} void Evaluate(b2ContactListener* listener); void b2CollideEdgeAndCircle(b2Manifold* manifold, const b2EdgeShape* edge, const b2XForm& xf1, const b2CircleShape* circle, const b2XForm& xf2); b2Manifold* GetManifolds() { return &m_manifold; } b2Manifold m_manifold; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2Contact.h0000644000000000000000000001311011065735647022742 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef CONTACT_H #define CONTACT_H #include "../../Common/b2Math.h" #include "../../Collision/b2Collision.h" #include "../../Collision/Shapes/b2Shape.h" class b2Body; class b2Contact; class b2World; class b2BlockAllocator; class b2StackAllocator; class b2ContactListener; typedef b2Contact* b2ContactCreateFcn(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); typedef void b2ContactDestroyFcn(b2Contact* contact, b2BlockAllocator* allocator); struct b2ContactRegister { b2ContactCreateFcn* createFcn; b2ContactDestroyFcn* destroyFcn; bool primary; }; /// A contact edge is used to connect bodies and contacts together /// in a contact graph where each body is a node and each contact /// is an edge. A contact edge belongs to a doubly linked list /// maintained in each attached body. Each contact has two contact /// nodes, one for each attached body. struct b2ContactEdge { b2Body* other; ///< provides quick access to the other body attached. b2Contact* contact; ///< the contact b2ContactEdge* prev; ///< the previous contact edge in the body's contact list b2ContactEdge* next; ///< the next contact edge in the body's contact list }; /// This structure is used to report contact points. struct b2ContactPoint { b2Shape* shape1; ///< the first shape b2Shape* shape2; ///< the second shape b2Vec2 position; ///< position in world coordinates b2Vec2 velocity; ///< velocity of point on body2 relative to point on body1 (pre-solver) b2Vec2 normal; ///< points from shape1 to shape2 float32 separation; ///< the separation is negative when shapes are touching float32 friction; ///< the combined friction coefficient float32 restitution; ///< the combined restitution coefficient b2ContactID id; ///< the contact id identifies the features in contact }; /// This structure is used to report contact point results. struct b2ContactResult { b2Shape* shape1; ///< the first shape b2Shape* shape2; ///< the second shape b2Vec2 position; ///< position in world coordinates b2Vec2 normal; ///< points from shape1 to shape2 float32 normalImpulse; ///< the normal impulse applied to body2 float32 tangentImpulse; ///< the tangent impulse applied to body2 b2ContactID id; ///< the contact id identifies the features in contact }; /// The class manages contact between two shapes. A contact exists for each overlapping /// AABB in the broad-phase (except if filtered). Therefore a contact object may exist /// that has no contact points. class b2Contact { public: /// Get the manifold array. virtual b2Manifold* GetManifolds() = 0; /// Get the number of manifolds. This is 0 or 1 between convex shapes. /// This may be greater than 1 for convex-vs-concave shapes. Each /// manifold holds up to two contact points with a shared contact normal. int32 GetManifoldCount() const; /// Is this contact solid? /// @return true if this contact should generate a response. bool IsSolid() const; /// Get the next contact in the world's contact list. b2Contact* GetNext(); /// Get the first shape in this contact. b2Shape* GetShape1(); /// Get the second shape in this contact. b2Shape* GetShape2(); //--------------- Internals Below ------------------- public: // m_flags enum { e_nonSolidFlag = 0x0001, e_slowFlag = 0x0002, e_islandFlag = 0x0004, e_toiFlag = 0x0008, }; static void AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destroyFcn, b2ShapeType type1, b2ShapeType type2); static void InitializeRegisters(); static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2Contact() : m_shape1(NULL), m_shape2(NULL) {} b2Contact(b2Shape* shape1, b2Shape* shape2); virtual ~b2Contact() {} void Update(b2ContactListener* listener); virtual void Evaluate(b2ContactListener* listener) = 0; static b2ContactRegister s_registers[e_shapeTypeCount][e_shapeTypeCount]; static bool s_initialized; uint32 m_flags; int32 m_manifoldCount; // World pool and list pointers. b2Contact* m_prev; b2Contact* m_next; // Nodes for connecting bodies. b2ContactEdge m_node1; b2ContactEdge m_node2; b2Shape* m_shape1; b2Shape* m_shape2; float32 m_toi; }; inline int32 b2Contact::GetManifoldCount() const { return m_manifoldCount; } inline bool b2Contact::IsSolid() const { return (m_flags & e_nonSolidFlag) == 0; } inline b2Contact* b2Contact::GetNext() { return m_next; } inline b2Shape* b2Contact::GetShape1() { return m_shape1; } inline b2Shape* b2Contact::GetShape2() { return m_shape2; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2PolyAndEdgeContact.h0000644000000000000000000000320011073705020024772 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef POLY_AND_EDGE_CONTACT_H #define POLY_AND_EDGE_CONTACT_H #include "b2Contact.h" class b2BlockAllocator; class b2PolyAndEdgeContact : public b2Contact { public: static b2Contact* Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator); static void Destroy(b2Contact* contact, b2BlockAllocator* allocator); b2PolyAndEdgeContact(b2Shape* shape1, b2Shape* shape2); ~b2PolyAndEdgeContact() {} void Evaluate(b2ContactListener* listener); void b2CollidePolyAndEdge(b2Manifold* manifold, const b2PolygonShape* poly, const b2XForm& xf1, const b2EdgeShape* edge, const b2XForm& xf2); b2Manifold* GetManifolds() { return &m_manifold; } b2Manifold m_manifold; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2ContactSolver.h0000644000000000000000000000421611064106301024116 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef CONTACT_SOLVER_H #define CONTACT_SOLVER_H #include "../../Common/b2Math.h" #include "../../Collision/b2Collision.h" #include "../b2World.h" class b2Contact; class b2Body; class b2Island; class b2StackAllocator; struct b2ContactConstraintPoint { b2Vec2 localAnchor1; b2Vec2 localAnchor2; b2Vec2 r1; b2Vec2 r2; float32 normalImpulse; float32 tangentImpulse; float32 normalMass; float32 tangentMass; float32 equalizedMass; float32 separation; float32 velocityBias; }; struct b2ContactConstraint { b2ContactConstraintPoint points[b2_maxManifoldPoints]; b2Vec2 normal; b2Mat22 normalMass; b2Mat22 K; b2Manifold* manifold; b2Body* body1; b2Body* body2; float32 friction; float32 restitution; int32 pointCount; }; class b2ContactSolver { public: b2ContactSolver(const b2TimeStep& step, b2Contact** contacts, int32 contactCount, b2StackAllocator* allocator); ~b2ContactSolver(); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(); void FinalizeVelocityConstraints(); bool SolvePositionConstraints(float32 baumgarte); b2TimeStep m_step; b2StackAllocator* m_allocator; b2ContactConstraint* m_constraints; int m_constraintCount; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.cpp0000644000000000000000000001324111130023047025605 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2EdgeAndCircleContact.h" #include "../b2Body.h" #include "../b2WorldCallbacks.h" #include "../../Common/b2BlockAllocator.h" #include "../../Collision/Shapes/b2EdgeShape.h" #include #include b2Contact* b2EdgeAndCircleContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact)); return new (mem) b2EdgeAndCircleContact(shape1, shape2); } void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact(); allocator->Free(contact, sizeof(b2EdgeAndCircleContact)); } b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Shape* s1, b2Shape* s2) : b2Contact(s1, s2) { b2Assert(m_shape1->GetType() == e_edgeShape); b2Assert(m_shape2->GetType() == e_circleShape); m_manifold.pointCount = 0; m_manifold.points[0].normalImpulse = 0.0f; m_manifold.points[0].tangentImpulse = 0.0f; } void b2EdgeAndCircleContact::Evaluate(b2ContactListener* listener) { b2Body* b1 = m_shape1->GetBody(); b2Body* b2 = m_shape2->GetBody(); b2Manifold m0; memcpy(&m0, &m_manifold, sizeof(b2Manifold)); b2CollideEdgeAndCircle(&m_manifold, (b2EdgeShape*)m_shape1, b1->GetXForm(), (b2CircleShape*)m_shape2, b2->GetXForm()); b2ContactPoint cp; cp.shape1 = m_shape1; cp.shape2 = m_shape2; cp.friction = b2MixFriction(m_shape1->GetFriction(), m_shape2->GetFriction()); cp.restitution = b2MixRestitution(m_shape1->GetRestitution(), m_shape2->GetRestitution()); if (m_manifold.pointCount > 0) { m_manifoldCount = 1; b2ManifoldPoint* mp = m_manifold.points + 0; if (m0.pointCount == 0) { mp->normalImpulse = 0.0f; mp->tangentImpulse = 0.0f; if (listener) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = mp->id; listener->Add(&cp); } } else { b2ManifoldPoint* mp0 = m0.points + 0; mp->normalImpulse = mp0->normalImpulse; mp->tangentImpulse = mp0->tangentImpulse; if (listener) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = mp->id; listener->Persist(&cp); } } } else { m_manifoldCount = 0; if (m0.pointCount > 0 && listener) { b2ManifoldPoint* mp0 = m0.points + 0; cp.position = b1->GetWorldPoint(mp0->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2); cp.velocity = v2 - v1; cp.normal = m0.normal; cp.separation = mp0->separation; cp.id = mp0->id; listener->Remove(&cp); } } } void b2EdgeAndCircleContact::b2CollideEdgeAndCircle(b2Manifold* manifold, const b2EdgeShape* edge, const b2XForm& xf1, const b2CircleShape* circle, const b2XForm& xf2) { manifold->pointCount = 0; b2Vec2 d; b2Vec2 c = b2Mul(xf2, circle->GetLocalPosition()); b2Vec2 cLocal = b2MulT(xf1, c); b2Vec2 n = edge->GetNormalVector(); b2Vec2 v1 = edge->GetVertex1(); b2Vec2 v2 = edge->GetVertex2(); float32 radius = circle->GetRadius(); float32 separation; float32 dirDist = b2Dot((cLocal - v1), edge->GetDirectionVector()); if (dirDist <= 0) { d = cLocal - v1; if (b2Dot(d, edge->GetCorner1Vector()) < 0) { return; } d = c - b2Mul(xf1, v1); } else if (dirDist >= edge->GetLength()) { d = cLocal - v2; if (b2Dot(d, edge->GetCorner2Vector()) > 0) { return; } d = c - b2Mul(xf1, v2); } else { separation = b2Dot(cLocal - v1, n); if (separation > radius || separation < -radius) { return; } separation -= radius; manifold->normal = b2Mul(xf1.R, n); manifold->pointCount = 1; manifold->points[0].id.key = 0; manifold->points[0].separation = separation; c = c - radius * manifold->normal; manifold->points[0].localPoint1 = b2MulT(xf1, c); manifold->points[0].localPoint2 = b2MulT(xf2, c); return; } float32 distSqr = b2Dot(d,d); if (distSqr > radius * radius) { return; } if (distSqr < B2_FLT_EPSILON) { separation = -radius; manifold->normal = b2Mul(xf1.R, n); } else { separation = d.Normalize() - radius; manifold->normal = d; } manifold->pointCount = 1; manifold->points[0].id.key = 0; manifold->points[0].separation = separation; c = c - radius * manifold->normal; manifold->points[0].localPoint1 = b2MulT(xf1, c); manifold->points[0].localPoint2 = b2MulT(xf2, c); } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2Contact.cpp0000644000000000000000000001173211130023047023256 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Contact.h" #include "b2CircleContact.h" #include "b2PolyAndCircleContact.h" #include "b2PolyContact.h" #include "b2EdgeAndCircleContact.h" #include "b2PolyAndEdgeContact.h" #include "b2ContactSolver.h" #include "../../Collision/b2Collision.h" #include "../../Collision/Shapes/b2Shape.h" #include "../../Common/b2BlockAllocator.h" #include "../../Dynamics/b2World.h" #include "../../Dynamics/b2Body.h" b2ContactRegister b2Contact::s_registers[e_shapeTypeCount][e_shapeTypeCount]; bool b2Contact::s_initialized = false; void b2Contact::InitializeRegisters() { AddType(b2CircleContact::Create, b2CircleContact::Destroy, e_circleShape, e_circleShape); AddType(b2PolyAndCircleContact::Create, b2PolyAndCircleContact::Destroy, e_polygonShape, e_circleShape); AddType(b2PolygonContact::Create, b2PolygonContact::Destroy, e_polygonShape, e_polygonShape); AddType(b2EdgeAndCircleContact::Create, b2EdgeAndCircleContact::Destroy, e_edgeShape, e_circleShape); AddType(b2PolyAndEdgeContact::Create, b2PolyAndEdgeContact::Destroy, e_polygonShape, e_edgeShape); } void b2Contact::AddType(b2ContactCreateFcn* createFcn, b2ContactDestroyFcn* destoryFcn, b2ShapeType type1, b2ShapeType type2) { b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount); b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount); s_registers[type1][type2].createFcn = createFcn; s_registers[type1][type2].destroyFcn = destoryFcn; s_registers[type1][type2].primary = true; if (type1 != type2) { s_registers[type2][type1].createFcn = createFcn; s_registers[type2][type1].destroyFcn = destoryFcn; s_registers[type2][type1].primary = false; } } b2Contact* b2Contact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator) { if (s_initialized == false) { InitializeRegisters(); s_initialized = true; } b2ShapeType type1 = shape1->GetType(); b2ShapeType type2 = shape2->GetType(); b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount); b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount); b2ContactCreateFcn* createFcn = s_registers[type1][type2].createFcn; if (createFcn) { if (s_registers[type1][type2].primary) { return createFcn(shape1, shape2, allocator); } else { b2Contact* c = createFcn(shape2, shape1, allocator); for (int32 i = 0; i < c->GetManifoldCount(); ++i) { b2Manifold* m = c->GetManifolds() + i; m->normal = -m->normal; } return c; } } else { return NULL; } } void b2Contact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { b2Assert(s_initialized == true); if (contact->GetManifoldCount() > 0) { contact->GetShape1()->GetBody()->WakeUp(); contact->GetShape2()->GetBody()->WakeUp(); } b2ShapeType type1 = contact->GetShape1()->GetType(); b2ShapeType type2 = contact->GetShape2()->GetType(); b2Assert(e_unknownShape < type1 && type1 < e_shapeTypeCount); b2Assert(e_unknownShape < type2 && type2 < e_shapeTypeCount); b2ContactDestroyFcn* destroyFcn = s_registers[type1][type2].destroyFcn; destroyFcn(contact, allocator); } b2Contact::b2Contact(b2Shape* s1, b2Shape* s2) { m_flags = 0; if (s1->IsSensor() || s2->IsSensor()) { m_flags |= e_nonSolidFlag; } m_shape1 = s1; m_shape2 = s2; m_manifoldCount = 0; m_prev = NULL; m_next = NULL; m_node1.contact = NULL; m_node1.prev = NULL; m_node1.next = NULL; m_node1.other = NULL; m_node2.contact = NULL; m_node2.prev = NULL; m_node2.next = NULL; m_node2.other = NULL; } void b2Contact::Update(b2ContactListener* listener) { int32 oldCount = GetManifoldCount(); Evaluate(listener); int32 newCount = GetManifoldCount(); b2Body* body1 = m_shape1->GetBody(); b2Body* body2 = m_shape2->GetBody(); if (newCount == 0 && oldCount > 0) { body1->WakeUp(); body2->WakeUp(); } // Slow contacts don't generate TOI events. if (body1->IsStatic() || body1->IsBullet() || body2->IsStatic() || body2->IsBullet()) { m_flags &= ~e_slowFlag; } else { m_flags |= e_slowFlag; } } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2CircleContact.cpp0000644000000000000000000000757611065735647024442 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2CircleContact.h" #include "../b2Body.h" #include "../b2WorldCallbacks.h" #include "../../Common/b2BlockAllocator.h" #include #include b2Contact* b2CircleContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2CircleContact)); return new (mem) b2CircleContact(shape1, shape2); } void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2CircleContact*)contact)->~b2CircleContact(); allocator->Free(contact, sizeof(b2CircleContact)); } b2CircleContact::b2CircleContact(b2Shape* s1, b2Shape* s2) : b2Contact(s1, s2) { b2Assert(m_shape1->GetType() == e_circleShape); b2Assert(m_shape2->GetType() == e_circleShape); m_manifold.pointCount = 0; m_manifold.points[0].normalImpulse = 0.0f; m_manifold.points[0].tangentImpulse = 0.0f; } void b2CircleContact::Evaluate(b2ContactListener* listener) { b2Body* b1 = m_shape1->GetBody(); b2Body* b2 = m_shape2->GetBody(); b2Manifold m0; memcpy(&m0, &m_manifold, sizeof(b2Manifold)); b2CollideCircles(&m_manifold, (b2CircleShape*)m_shape1, b1->GetXForm(), (b2CircleShape*)m_shape2, b2->GetXForm()); b2ContactPoint cp; cp.shape1 = m_shape1; cp.shape2 = m_shape2; cp.friction = b2MixFriction(m_shape1->GetFriction(), m_shape2->GetFriction()); cp.restitution = b2MixRestitution(m_shape1->GetRestitution(), m_shape2->GetRestitution()); if (m_manifold.pointCount > 0) { m_manifoldCount = 1; b2ManifoldPoint* mp = m_manifold.points + 0; if (m0.pointCount == 0) { mp->normalImpulse = 0.0f; mp->tangentImpulse = 0.0f; if (listener) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = mp->id; listener->Add(&cp); } } else { b2ManifoldPoint* mp0 = m0.points + 0; mp->normalImpulse = mp0->normalImpulse; mp->tangentImpulse = mp0->tangentImpulse; if (listener) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = mp->id; listener->Persist(&cp); } } } else { m_manifoldCount = 0; if (m0.pointCount > 0 && listener) { b2ManifoldPoint* mp0 = m0.points + 0; cp.position = b1->GetWorldPoint(mp0->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2); cp.velocity = v2 - v1; cp.normal = m0.normal; cp.separation = mp0->separation; cp.id = mp0->id; listener->Remove(&cp); } } } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2PolyAndEdgeContact.cpp0000644000000000000000000003134311130023047025332 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2PolyAndEdgeContact.h" #include "../b2Body.h" #include "../b2WorldCallbacks.h" #include "../../Common/b2BlockAllocator.h" #include "../../Collision/Shapes/b2EdgeShape.h" #include "../../Collision/Shapes/b2PolygonShape.h" #include #include b2Contact* b2PolyAndEdgeContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2PolyAndEdgeContact)); return new (mem) b2PolyAndEdgeContact(shape1, shape2); } void b2PolyAndEdgeContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2PolyAndEdgeContact*)contact)->~b2PolyAndEdgeContact(); allocator->Free(contact, sizeof(b2PolyAndEdgeContact)); } b2PolyAndEdgeContact::b2PolyAndEdgeContact(b2Shape* s1, b2Shape* s2) : b2Contact(s1, s2) { b2Assert(m_shape1->GetType() == e_polygonShape); b2Assert(m_shape2->GetType() == e_edgeShape); m_manifold.pointCount = 0; } void b2PolyAndEdgeContact::Evaluate(b2ContactListener* listener) { b2Body* b1 = m_shape1->GetBody(); b2Body* b2 = m_shape2->GetBody(); b2Manifold m0; memcpy(&m0, &m_manifold, sizeof(b2Manifold)); b2CollidePolyAndEdge(&m_manifold, (b2PolygonShape*)m_shape1, b1->GetXForm(), (b2EdgeShape*)m_shape2, b2->GetXForm()); bool persisted[b2_maxManifoldPoints] = {false, false}; b2ContactPoint cp; cp.shape1 = m_shape1; cp.shape2 = m_shape2; cp.friction = b2MixFriction(m_shape1->GetFriction(), m_shape2->GetFriction()); cp.restitution = b2MixRestitution(m_shape1->GetRestitution(), m_shape2->GetRestitution()); // Match contact ids to facilitate warm starting. if (m_manifold.pointCount > 0) { // Match old contact ids to new contact ids and copy the // stored impulses to warm start the solver. for (int32 i = 0; i < m_manifold.pointCount; ++i) { b2ManifoldPoint* mp = m_manifold.points + i; mp->normalImpulse = 0.0f; mp->tangentImpulse = 0.0f; bool found = false; b2ContactID id = mp->id; for (int32 j = 0; j < m0.pointCount; ++j) { if (persisted[j] == true) { continue; } b2ManifoldPoint* mp0 = m0.points + j; if (mp0->id.key == id.key) { persisted[j] = true; mp->normalImpulse = mp0->normalImpulse; mp->tangentImpulse = mp0->tangentImpulse; // A persistent point. found = true; // Report persistent point. if (listener != NULL) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = id; listener->Persist(&cp); } break; } } // Report added point. if (found == false && listener != NULL) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = id; listener->Add(&cp); } } m_manifoldCount = 1; } else { m_manifoldCount = 0; } if (listener == NULL) { return; } // Report removed points. for (int32 i = 0; i < m0.pointCount; ++i) { if (persisted[i]) { continue; } b2ManifoldPoint* mp0 = m0.points + i; cp.position = b1->GetWorldPoint(mp0->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2); cp.velocity = v2 - v1; cp.normal = m0.normal; cp.separation = mp0->separation; cp.id = mp0->id; listener->Remove(&cp); } } void b2PolyAndEdgeContact::b2CollidePolyAndEdge(b2Manifold* manifold, const b2PolygonShape* polygon, const b2XForm& xf1, const b2EdgeShape* edge, const b2XForm& xf2) { manifold->pointCount = 0; b2Vec2 v1 = b2Mul(xf2, edge->GetVertex1()); b2Vec2 v2 = b2Mul(xf2, edge->GetVertex2()); b2Vec2 n = b2Mul(xf2.R, edge->GetNormalVector()); b2Vec2 v1Local = b2MulT(xf1, v1); b2Vec2 v2Local = b2MulT(xf1, v2); b2Vec2 nLocal = b2MulT(xf1.R, n); float32 separation1; int32 separationIndex1 = -1; // which normal on the poly found the shallowest depth? float32 separationMax1 = -B2_FLT_MAX; // the shallowest depth of edge in poly float32 separation2; int32 separationIndex2 = -1; // which normal on the poly found the shallowest depth? float32 separationMax2 = -B2_FLT_MAX; // the shallowest depth of edge in poly float32 separationMax = -B2_FLT_MAX; // the shallowest depth of edge in poly bool separationV1 = false; // is the shallowest depth from edge's v1 or v2 vertex? int32 separationIndex = -1; // which normal on the poly found the shallowest depth? int32 vertexCount = polygon->GetVertexCount(); const b2Vec2* vertices = polygon->GetVertices(); const b2Vec2* normals = polygon->GetNormals(); int32 enterStartIndex = -1; // the last poly vertex above the edge int32 enterEndIndex = -1; // the first poly vertex below the edge int32 exitStartIndex = -1; // the last poly vertex below the edge int32 exitEndIndex = -1; // the first poly vertex above the edge //int32 deepestIndex; // the "N" in the following variables refers to the edge's normal. // these are projections of poly vertices along the edge's normal, // a.k.a. they are the separation of the poly from the edge. float32 prevSepN = 0.0f; float32 nextSepN = 0.0f; float32 enterSepN = 0.0f; // the depth of enterEndIndex under the edge (stored as a separation, so it's negative) float32 exitSepN = 0.0f; // the depth of exitStartIndex under the edge (stored as a separation, so it's negative) float32 deepestSepN = B2_FLT_MAX; // the depth of the deepest poly vertex under the end (stored as a separation, so it's negative) // for each poly normal, get the edge's depth into the poly. // for each poly vertex, get the vertex's depth into the edge. // use these calculations to define the remaining variables declared above. prevSepN = b2Dot(vertices[vertexCount-1] - v1Local, nLocal); for (int32 i = 0; i < vertexCount; i++) { separation1 = b2Dot(v1Local - vertices[i], normals[i]); separation2 = b2Dot(v2Local - vertices[i], normals[i]); if (separation2 < separation1) { if (separation2 > separationMax) { separationMax = separation2; separationV1 = false; separationIndex = i; } } else { if (separation1 > separationMax) { separationMax = separation1; separationV1 = true; separationIndex = i; } } if (separation1 > separationMax1) { separationMax1 = separation1; separationIndex1 = i; } if (separation2 > separationMax2) { separationMax2 = separation2; separationIndex2 = i; } nextSepN = b2Dot(vertices[i] - v1Local, nLocal); if (nextSepN >= 0.0f && prevSepN < 0.0f) { exitStartIndex = (i == 0) ? vertexCount-1 : i-1; exitEndIndex = i; exitSepN = prevSepN; } else if (nextSepN < 0.0f && prevSepN >= 0.0f) { enterStartIndex = (i == 0) ? vertexCount-1 : i-1; enterEndIndex = i; enterSepN = nextSepN; } if (nextSepN < deepestSepN) { deepestSepN = nextSepN; //deepestIndex = i; } prevSepN = nextSepN; } if (enterStartIndex == -1) { // poly is entirely below or entirely above edge, return with no contact: return; } if (separationMax > 0.0f) { // poly is laterally disjoint with edge, return with no contact: return; } // if the poly is near a convex corner on the edge if ((separationV1 && edge->Corner1IsConvex()) || (!separationV1 && edge->Corner2IsConvex())) { // if shallowest depth was from edge into poly, // use the edge's vertex as the contact point: if (separationMax > deepestSepN + b2_linearSlop) { // if -normal angle is closer to adjacent edge than this edge, // let the adjacent edge handle it and return with no contact: if (separationV1) { if (b2Dot(normals[separationIndex1], b2MulT(xf1.R, b2Mul(xf2.R, edge->GetCorner1Vector()))) >= 0.0f) { return; } } else { if (b2Dot(normals[separationIndex2], b2MulT(xf1.R, b2Mul(xf2.R, edge->GetCorner2Vector()))) <= 0.0f) { return; } } manifold->pointCount = 1; manifold->normal = b2Mul(xf1.R, normals[separationIndex]); manifold->points[0].separation = separationMax; manifold->points[0].id.features.incidentEdge = (uint8)separationIndex; manifold->points[0].id.features.incidentVertex = b2_nullFeature; manifold->points[0].id.features.referenceEdge = 0; manifold->points[0].id.features.flip = 0; if (separationV1) { manifold->points[0].localPoint1 = v1Local; manifold->points[0].localPoint2 = edge->GetVertex1(); } else { manifold->points[0].localPoint1 = v2Local; manifold->points[0].localPoint2 = edge->GetVertex2(); } return; } } // We're going to use the edge's normal now. manifold->normal = (-1.0f) * n; // Check whether we only need one contact point. if (enterEndIndex == exitStartIndex) { manifold->pointCount = 1; manifold->points[0].id.features.incidentEdge = (uint8)enterEndIndex; manifold->points[0].id.features.incidentVertex = b2_nullFeature; manifold->points[0].id.features.referenceEdge = 0; manifold->points[0].id.features.flip = 0; manifold->points[0].localPoint1 = vertices[enterEndIndex]; manifold->points[0].localPoint2 = b2MulT(xf2, b2Mul(xf1, vertices[enterEndIndex])); manifold->points[0].separation = enterSepN; return; } manifold->pointCount = 2; // dirLocal should be the edge's direction vector, but in the frame of the polygon. b2Vec2 dirLocal = b2Cross(nLocal, -1.0f); // TODO: figure out why this optimization didn't work //b2Vec2 dirLocal = b2MulT(xf1.R, b2Mul(xf2.R, edge->GetDirectionVector())); float32 dirProj1 = b2Dot(dirLocal, vertices[enterEndIndex] - v1Local); float32 dirProj2; // The contact resolution is more robust if the two manifold points are // adjacent to each other on the polygon. So pick the first two poly // vertices that are under the edge: exitEndIndex = (enterEndIndex == vertexCount - 1) ? 0 : enterEndIndex + 1; if (exitEndIndex != exitStartIndex) { exitStartIndex = exitEndIndex; exitSepN = b2Dot(nLocal, vertices[exitStartIndex] - v1Local); } dirProj2 = b2Dot(dirLocal, vertices[exitStartIndex] - v1Local); manifold->points[0].id.features.incidentEdge = (uint8)enterEndIndex; manifold->points[0].id.features.incidentVertex = b2_nullFeature; manifold->points[0].id.features.referenceEdge = 0; manifold->points[0].id.features.flip = 0; if (dirProj1 > edge->GetLength()) { manifold->points[0].localPoint1 = v2Local; manifold->points[0].localPoint2 = edge->GetVertex2(); float32 ratio = (edge->GetLength() - dirProj2) / (dirProj1 - dirProj2); if (ratio > 100.0f * B2_FLT_EPSILON && ratio < 1.0f) { manifold->points[0].separation = exitSepN * (1.0f - ratio) + enterSepN * ratio; } else { manifold->points[0].separation = enterSepN; } } else { manifold->points[0].localPoint1 = vertices[enterEndIndex]; manifold->points[0].localPoint2 = b2MulT(xf2, b2Mul(xf1, vertices[enterEndIndex])); manifold->points[0].separation = enterSepN; } manifold->points[1].id.features.incidentEdge = (uint8)exitStartIndex; manifold->points[1].id.features.incidentVertex = b2_nullFeature; manifold->points[1].id.features.referenceEdge = 0; manifold->points[1].id.features.flip = 0; if (dirProj2 < 0.0f) { manifold->points[1].localPoint1 = v1Local; manifold->points[1].localPoint2 = edge->GetVertex1(); float32 ratio = (-dirProj1) / (dirProj2 - dirProj1); if (ratio > 100.0f * B2_FLT_EPSILON && ratio < 1.0f) { manifold->points[1].separation = enterSepN * (1.0f - ratio) + exitSepN * ratio; } else { manifold->points[1].separation = exitSepN; } } else { manifold->points[1].localPoint1 = vertices[exitStartIndex]; manifold->points[1].localPoint2 = b2MulT(xf2, b2Mul(xf1, vertices[exitStartIndex])); manifold->points[1].separation = exitSepN; } } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Contacts/b2PolyContact.cpp0000644000000000000000000001111111065735647024140 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2PolyContact.h" #include "../b2Body.h" #include "../b2WorldCallbacks.h" #include "../../Common/b2BlockAllocator.h" #include #include #include b2Contact* b2PolygonContact::Create(b2Shape* shape1, b2Shape* shape2, b2BlockAllocator* allocator) { void* mem = allocator->Allocate(sizeof(b2PolygonContact)); return new (mem) b2PolygonContact(shape1, shape2); } void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator) { ((b2PolygonContact*)contact)->~b2PolygonContact(); allocator->Free(contact, sizeof(b2PolygonContact)); } b2PolygonContact::b2PolygonContact(b2Shape* s1, b2Shape* s2) : b2Contact(s1, s2) { b2Assert(m_shape1->GetType() == e_polygonShape); b2Assert(m_shape2->GetType() == e_polygonShape); m_manifold.pointCount = 0; } void b2PolygonContact::Evaluate(b2ContactListener* listener) { b2Body* b1 = m_shape1->GetBody(); b2Body* b2 = m_shape2->GetBody(); b2Manifold m0; memcpy(&m0, &m_manifold, sizeof(b2Manifold)); b2CollidePolygons(&m_manifold, (b2PolygonShape*)m_shape1, b1->GetXForm(), (b2PolygonShape*)m_shape2, b2->GetXForm()); bool persisted[b2_maxManifoldPoints] = {false, false}; b2ContactPoint cp; cp.shape1 = m_shape1; cp.shape2 = m_shape2; cp.friction = b2MixFriction(m_shape1->GetFriction(), m_shape2->GetFriction()); cp.restitution = b2MixRestitution(m_shape1->GetRestitution(), m_shape2->GetRestitution()); // Match contact ids to facilitate warm starting. if (m_manifold.pointCount > 0) { // Match old contact ids to new contact ids and copy the // stored impulses to warm start the solver. for (int32 i = 0; i < m_manifold.pointCount; ++i) { b2ManifoldPoint* mp = m_manifold.points + i; mp->normalImpulse = 0.0f; mp->tangentImpulse = 0.0f; bool found = false; b2ContactID id = mp->id; for (int32 j = 0; j < m0.pointCount; ++j) { if (persisted[j] == true) { continue; } b2ManifoldPoint* mp0 = m0.points + j; if (mp0->id.key == id.key) { persisted[j] = true; mp->normalImpulse = mp0->normalImpulse; mp->tangentImpulse = mp0->tangentImpulse; // A persistent point. found = true; // Report persistent point. if (listener != NULL) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = id; listener->Persist(&cp); } break; } } // Report added point. if (found == false && listener != NULL) { cp.position = b1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.normal = m_manifold.normal; cp.separation = mp->separation; cp.id = id; listener->Add(&cp); } } m_manifoldCount = 1; } else { m_manifoldCount = 0; } if (listener == NULL) { return; } // Report removed points. for (int32 i = 0; i < m0.pointCount; ++i) { if (persisted[i]) { continue; } b2ManifoldPoint* mp0 = m0.points + i; cp.position = b1->GetWorldPoint(mp0->localPoint1); b2Vec2 v1 = b1->GetLinearVelocityFromLocalPoint(mp0->localPoint1); b2Vec2 v2 = b2->GetLinearVelocityFromLocalPoint(mp0->localPoint2); cp.velocity = v2 - v1; cp.normal = m0.normal; cp.separation = mp0->separation; cp.id = mp0->id; listener->Remove(&cp); } } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2Island.cpp0000644000000000000000000003612111130023047021316 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Island.h" #include "b2Body.h" #include "b2World.h" #include "Contacts/b2Contact.h" #include "Contacts/b2ContactSolver.h" #include "Joints/b2Joint.h" #include "../Common/b2StackAllocator.h" /* Position Correction Notes ========================= I tried the several algorithms for position correction of the 2D revolute joint. I looked at these systems: - simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s. - suspension bridge with 30 1m long planks of length 1m. - multi-link chain with 30 1m long links. Here are the algorithms: Baumgarte - A fraction of the position error is added to the velocity error. There is no separate position solver. Pseudo Velocities - After the velocity solver and position integration, the position error, Jacobian, and effective mass are recomputed. Then the velocity constraints are solved with pseudo velocities and a fraction of the position error is added to the pseudo velocity error. The pseudo velocities are initialized to zero and there is no warm-starting. After the position solver, the pseudo velocities are added to the positions. This is also called the First Order World method or the Position LCP method. Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the position error is re-computed for each constraint and the positions are updated after the constraint is solved. The radius vectors (aka Jacobians) are re-computed too (otherwise the algorithm has horrible instability). The pseudo velocity states are not needed because they are effectively zero at the beginning of each iteration. Since we have the current position error, we allow the iterations to terminate early if the error becomes smaller than b2_linearSlop. Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed each time a constraint is solved. Here are the results: Baumgarte - this is the cheapest algorithm but it has some stability problems, especially with the bridge. The chain links separate easily close to the root and they jitter as they struggle to pull together. This is one of the most common methods in the field. The big drawback is that the position correction artificially affects the momentum, thus leading to instabilities and false bounce. I used a bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller factor makes joints and contacts more spongy. Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is stable. However, joints still separate with large angular velocities. Drag the simple pendulum in a circle quickly and the joint will separate. The chain separates easily and does not recover. I used a bias factor of 0.2. A larger value lead to the bridge collapsing when a heavy cube drops on it. Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo Velocities, but in other ways it is worse. The bridge and chain are much more stable, but the simple pendulum goes unstable at high angular velocities. Full NGS - stable in all tests. The joints display good stiffness. The bridge still sags, but this is better than infinite forces. Recommendations Pseudo Velocities are not really worthwhile because the bridge and chain cannot recover from joint separation. In other cases the benefit over Baumgarte is small. Modified NGS is not a robust method for the revolute joint due to the violent instability seen in the simple pendulum. Perhaps it is viable with other constraint types, especially scalar constraints where the effective mass is a scalar. This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities and is very fast. I don't think we can escape Baumgarte, especially in highly demanding cases where high constraint fidelity is not needed. Full NGS is robust and easy on the eyes. I recommend this as an option for higher fidelity simulation and certainly for suspension bridges and long chains. Full NGS might be a good choice for ragdolls, especially motorized ragdolls where joint separation can be problematic. The number of NGS iterations can be reduced for better performance without harming robustness much. Each joint in a can be handled differently in the position solver. So I recommend a system where the user can select the algorithm on a per joint basis. I would probably default to the slower Full NGS and let the user select the faster Baumgarte method in performance critical scenarios. */ /* Cache Performance The Box2D solvers are dominated by cache misses. Data structures are designed to increase the number of cache hits. Much of misses are due to random access to body data. The constraint structures are iterated over linearly, which leads to few cache misses. The bodies are not accessed during iteration. Instead read only data, such as the mass values are stored with the constraints. The mutable data are the constraint impulses and the bodies velocities/positions. The impulses are held inside the constraint structures. The body velocities/positions are held in compact, temporary arrays to increase the number of cache hits. Linear and angular velocity are stored in a single array since multiple arrays lead to multiple misses. */ /* 2D Rotation R = [cos(theta) -sin(theta)] [sin(theta) cos(theta) ] thetaDot = omega Let q1 = cos(theta), q2 = sin(theta). R = [q1 -q2] [q2 q1] q1Dot = -thetaDot * q2 q2Dot = thetaDot * q1 q1_new = q1_old - dt * w * q2 q2_new = q2_old + dt * w * q1 then normalize. This might be faster than computing sin+cos. However, we can compute sin+cos of the same angle fast. */ b2Island::b2Island( int32 bodyCapacity, int32 contactCapacity, int32 jointCapacity, b2StackAllocator* allocator, b2ContactListener* listener) { m_bodyCapacity = bodyCapacity; m_contactCapacity = contactCapacity; m_jointCapacity = jointCapacity; m_bodyCount = 0; m_contactCount = 0; m_jointCount = 0; m_allocator = allocator; m_listener = listener; m_bodies = (b2Body**)m_allocator->Allocate(bodyCapacity * sizeof(b2Body*)); m_contacts = (b2Contact**)m_allocator->Allocate(contactCapacity * sizeof(b2Contact*)); m_joints = (b2Joint**)m_allocator->Allocate(jointCapacity * sizeof(b2Joint*)); m_velocities = (b2Velocity*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Velocity)); m_positions = (b2Position*)m_allocator->Allocate(m_bodyCapacity * sizeof(b2Position)); } b2Island::~b2Island() { // Warning: the order should reverse the constructor order. m_allocator->Free(m_positions); m_allocator->Free(m_velocities); m_allocator->Free(m_joints); m_allocator->Free(m_contacts); m_allocator->Free(m_bodies); } void b2Island::Solve(const b2TimeStep& step, const b2Vec2& gravity, bool allowSleep) { // Integrate velocities and apply damping. for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; if (b->IsStatic()) continue; // Integrate velocities. b->m_linearVelocity += step.dt * (gravity + b->m_invMass * b->m_force); b->m_angularVelocity += step.dt * b->m_invI * b->m_torque; // Reset forces. b->m_force.Set(0.0f, 0.0f); b->m_torque = 0.0f; // Apply damping. // ODE: dv/dt + c * v = 0 // Solution: v(t) = v0 * exp(-c * t) // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt) // v2 = exp(-c * dt) * v1 // Taylor expansion: // v2 = (1.0f - c * dt) * v1 b->m_linearVelocity *= b2Clamp(1.0f - step.dt * b->m_linearDamping, 0.0f, 1.0f); b->m_angularVelocity *= b2Clamp(1.0f - step.dt * b->m_angularDamping, 0.0f, 1.0f); // Check for large velocities. #ifdef TARGET_FLOAT32_IS_FIXED // Fixed point code written this way to prevent // overflows, float code is optimized for speed float32 vMagnitude = b->m_linearVelocity.Length(); if(vMagnitude > b2_maxLinearVelocity) { b->m_linearVelocity *= b2_maxLinearVelocity/vMagnitude; } b->m_angularVelocity = b2Clamp(b->m_angularVelocity, -b2_maxAngularVelocity, b2_maxAngularVelocity); #else if (b2Dot(b->m_linearVelocity, b->m_linearVelocity) > b2_maxLinearVelocitySquared) { b->m_linearVelocity.Normalize(); b->m_linearVelocity *= b2_maxLinearVelocity; } if (b->m_angularVelocity * b->m_angularVelocity > b2_maxAngularVelocitySquared) { if (b->m_angularVelocity < 0.0f) { b->m_angularVelocity = -b2_maxAngularVelocity; } else { b->m_angularVelocity = b2_maxAngularVelocity; } } #endif } b2ContactSolver contactSolver(step, m_contacts, m_contactCount, m_allocator); // Initialize velocity constraints. contactSolver.InitVelocityConstraints(step); for (int32 i = 0; i < m_jointCount; ++i) { m_joints[i]->InitVelocityConstraints(step); } // Solve velocity constraints. for (int32 i = 0; i < step.velocityIterations; ++i) { for (int32 j = 0; j < m_jointCount; ++j) { m_joints[j]->SolveVelocityConstraints(step); } contactSolver.SolveVelocityConstraints(); } // Post-solve (store impulses for warm starting). contactSolver.FinalizeVelocityConstraints(); // Integrate positions. for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; if (b->IsStatic()) continue; // Store positions for continuous collision. b->m_sweep.c0 = b->m_sweep.c; b->m_sweep.a0 = b->m_sweep.a; // Integrate b->m_sweep.c += step.dt * b->m_linearVelocity; b->m_sweep.a += step.dt * b->m_angularVelocity; // Compute new transform b->SynchronizeTransform(); // Note: shapes are synchronized later. } // Iterate over constraints. for (int32 i = 0; i < step.positionIterations; ++i) { bool contactsOkay = contactSolver.SolvePositionConstraints(b2_contactBaumgarte); bool jointsOkay = true; for (int32 i = 0; i < m_jointCount; ++i) { bool jointOkay = m_joints[i]->SolvePositionConstraints(b2_contactBaumgarte); jointsOkay = jointsOkay && jointOkay; } if (contactsOkay && jointsOkay) { // Exit early if the position errors are small. break; } } Report(contactSolver.m_constraints); if (allowSleep) { float32 minSleepTime = B2_FLT_MAX; #ifndef TARGET_FLOAT32_IS_FIXED const float32 linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance; const float32 angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance; #endif for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; if (b->m_invMass == 0.0f) { continue; } if ((b->m_flags & b2Body::e_allowSleepFlag) == 0) { b->m_sleepTime = 0.0f; minSleepTime = 0.0f; } if ((b->m_flags & b2Body::e_allowSleepFlag) == 0 || #ifdef TARGET_FLOAT32_IS_FIXED b2Abs(b->m_angularVelocity) > b2_angularSleepTolerance || b2Abs(b->m_linearVelocity.x) > b2_linearSleepTolerance || b2Abs(b->m_linearVelocity.y) > b2_linearSleepTolerance) #else b->m_angularVelocity * b->m_angularVelocity > angTolSqr || b2Dot(b->m_linearVelocity, b->m_linearVelocity) > linTolSqr) #endif { b->m_sleepTime = 0.0f; minSleepTime = 0.0f; } else { b->m_sleepTime += step.dt; minSleepTime = b2Min(minSleepTime, b->m_sleepTime); } } if (minSleepTime >= b2_timeToSleep) { for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; b->m_flags |= b2Body::e_sleepFlag; b->m_linearVelocity = b2Vec2_zero; b->m_angularVelocity = 0.0f; } } } } void b2Island::SolveTOI(b2TimeStep& subStep) { b2ContactSolver contactSolver(subStep, m_contacts, m_contactCount, m_allocator); // No warm starting needed for TOI contact events. // Warm starting for joints is off for now, but we need to // call this function to compute Jacobians. for (int32 i = 0; i < m_jointCount; ++i) { m_joints[i]->InitVelocityConstraints(subStep); } // Solve velocity constraints. for (int32 i = 0; i < subStep.velocityIterations; ++i) { contactSolver.SolveVelocityConstraints(); for (int32 j = 0; j < m_jointCount; ++j) { m_joints[j]->SolveVelocityConstraints(subStep); } } // Don't store the TOI contact forces for warm starting // because they can be quite large. // Integrate positions. for (int32 i = 0; i < m_bodyCount; ++i) { b2Body* b = m_bodies[i]; if (b->IsStatic()) continue; // Store positions for continuous collision. b->m_sweep.c0 = b->m_sweep.c; b->m_sweep.a0 = b->m_sweep.a; // Integrate b->m_sweep.c += subStep.dt * b->m_linearVelocity; b->m_sweep.a += subStep.dt * b->m_angularVelocity; // Compute new transform b->SynchronizeTransform(); // Note: shapes are synchronized later. } // Solve position constraints. const float32 k_toiBaumgarte = 0.75f; for (int32 i = 0; i < subStep.positionIterations; ++i) { bool contactsOkay = contactSolver.SolvePositionConstraints(k_toiBaumgarte); bool jointsOkay = true; for (int32 j = 0; j < m_jointCount; ++j) { bool jointOkay = m_joints[j]->SolvePositionConstraints(k_toiBaumgarte); jointsOkay = jointsOkay && jointOkay; } if (contactsOkay && jointsOkay) { break; } } Report(contactSolver.m_constraints); } void b2Island::Report(b2ContactConstraint* constraints) { if (m_listener == NULL) { return; } for (int32 i = 0; i < m_contactCount; ++i) { b2Contact* c = m_contacts[i]; b2ContactConstraint* cc = constraints + i; b2ContactResult cr; cr.shape1 = c->GetShape1(); cr.shape2 = c->GetShape2(); b2Body* b1 = cr.shape1->GetBody(); int32 manifoldCount = c->GetManifoldCount(); b2Manifold* manifolds = c->GetManifolds(); for (int32 j = 0; j < manifoldCount; ++j) { b2Manifold* manifold = manifolds + j; cr.normal = manifold->normal; for (int32 k = 0; k < manifold->pointCount; ++k) { b2ManifoldPoint* point = manifold->points + k; b2ContactConstraintPoint* ccp = cc->points + k; cr.position = b1->GetWorldPoint(point->localPoint1); // TOI constraint results are not stored, so get // the result from the constraint. cr.normalImpulse = ccp->normalImpulse; cr.tangentImpulse = ccp->tangentImpulse; cr.id = point->id; m_listener->Result(&cr); } } } } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2Body.cpp0000644000000000000000000002344311154057363021022 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Body.h" #include "b2World.h" #include "Joints/b2Joint.h" #include "../Collision/Shapes/b2Shape.h" #include "../Collision/Shapes/b2EdgeShape.h" b2Body::b2Body(const b2BodyDef* bd, b2World* world) { b2Assert(world->m_lock == false); m_flags = 0; if (bd->isBullet) { m_flags |= e_bulletFlag; } if (bd->fixedRotation) { m_flags |= e_fixedRotationFlag; } if (bd->allowSleep) { m_flags |= e_allowSleepFlag; } if (bd->isSleeping) { m_flags |= e_sleepFlag; } m_world = world; m_xf.position = bd->position; m_xf.R.Set(bd->angle); m_sweep.localCenter = bd->massData.center; m_sweep.t0 = 1.0f; m_sweep.a0 = m_sweep.a = bd->angle; m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); m_jointList = NULL; m_contactList = NULL; m_controllerList = NULL; m_prev = NULL; m_next = NULL; m_linearDamping = bd->linearDamping; m_angularDamping = bd->angularDamping; m_force.Set(0.0f, 0.0f); m_torque = 0.0f; m_linearVelocity.SetZero(); m_angularVelocity = 0.0f; m_sleepTime = 0.0f; m_invMass = 0.0f; m_I = 0.0f; m_invI = 0.0f; m_mass = bd->massData.mass; if (m_mass > 0.0f) { m_invMass = 1.0f / m_mass; } m_I = bd->massData.I; if (m_I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) { m_invI = 1.0f / m_I; } if (m_invMass == 0.0f && m_invI == 0.0f) { m_type = e_staticType; } else { m_type = e_dynamicType; } m_userData = bd->userData; m_shapeList = NULL; m_shapeCount = 0; } b2Body::~b2Body() { b2Assert(m_world->m_lock == false); // shapes and joints are destroyed in b2World::Destroy } float32 connectEdges(b2EdgeShape * const & s1, b2EdgeShape * const & s2, float32 angle1) { float32 angle2 = b2Atan2(s2->GetDirectionVector().y, s2->GetDirectionVector().x); b2Vec2 core = tanf((angle2 - angle1) * 0.5f) * s2->GetDirectionVector(); core = b2_toiSlop * (core - s2->GetNormalVector()) + s2->GetVertex1(); b2Vec2 cornerDir = s1->GetDirectionVector() + s2->GetDirectionVector(); cornerDir.Normalize(); bool convex = b2Dot(s1->GetDirectionVector(), s2->GetNormalVector()) > 0.0f; s1->SetNextEdge(s2, core, cornerDir, convex); s2->SetPrevEdge(s1, core, cornerDir, convex); return angle2; } b2Shape* b2Body::CreateShape(const b2ShapeDef* def) { b2Assert(m_world->m_lock == false); if (m_world->m_lock == true) { return NULL; } // TODO: Decide on a better place to initialize edgeShapes. (b2Shape::Create() can't // return more than one shape to add to parent body... maybe it should add // shapes directly to the body instead of returning them?) if (def->type == e_edgeShape) { const b2EdgeChainDef* edgeDef = (const b2EdgeChainDef*)def; b2Vec2 v1; b2Vec2 v2; int i; if (edgeDef->isALoop) { v1 = edgeDef->vertices[edgeDef->vertexCount-1]; i = 0; } else { v1 = edgeDef->vertices[0]; i = 1; } b2EdgeShape* s0 = NULL; b2EdgeShape* s1 = NULL; b2EdgeShape* s2 = NULL; float32 angle = 0.0f; for (; i < edgeDef->vertexCount; i++) { v2 = edgeDef->vertices[i]; void* mem = m_world->m_blockAllocator.Allocate(sizeof(b2EdgeShape)); s2 = new (mem) b2EdgeShape(v1, v2, def); s2->m_next = m_shapeList; m_shapeList = s2; ++m_shapeCount; s2->m_body = this; s2->CreateProxy(m_world->m_broadPhase, m_xf); s2->UpdateSweepRadius(m_sweep.localCenter); if (s1 == NULL) { s0 = s2; angle = b2Atan2(s2->GetDirectionVector().y, s2->GetDirectionVector().x); } else { angle = connectEdges(s1, s2, angle); } s1 = s2; v1 = v2; } if (edgeDef->isALoop) connectEdges(s1, s0, angle); return s0; } b2Shape* s = b2Shape::Create(def, &m_world->m_blockAllocator); s->m_next = m_shapeList; m_shapeList = s; ++m_shapeCount; s->m_body = this; // Add the shape to the world's broad-phase. s->CreateProxy(m_world->m_broadPhase, m_xf); // Compute the sweep radius for CCD. s->UpdateSweepRadius(m_sweep.localCenter); return s; } void b2Body::DestroyShape(b2Shape* s) { b2Assert(m_world->m_lock == false); if (m_world->m_lock == true) { return; } b2Assert(s->GetBody() == this); s->DestroyProxy(m_world->m_broadPhase); b2Assert(m_shapeCount > 0); b2Shape** node = &m_shapeList; bool found = false; while (*node != NULL) { if (*node == s) { *node = s->m_next; found = true; break; } node = &(*node)->m_next; } // You tried to remove a shape that is not attached to this body. b2Assert(found); s->m_body = NULL; s->m_next = NULL; --m_shapeCount; b2Shape::Destroy(s, &m_world->m_blockAllocator); } // TODO_ERIN adjust linear velocity and torque to account for movement of center. void b2Body::SetMass(const b2MassData* massData) { b2Assert(m_world->m_lock == false); if (m_world->m_lock == true) { return; } m_invMass = 0.0f; m_I = 0.0f; m_invI = 0.0f; m_mass = massData->mass; if (m_mass > 0.0f) { m_invMass = 1.0f / m_mass; } m_I = massData->I; if (m_I > 0.0f && (m_flags & b2Body::e_fixedRotationFlag) == 0) { m_invI = 1.0f / m_I; } // Move center of mass. m_sweep.localCenter = massData->center; m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); // Update the sweep radii of all child shapes. for (b2Shape* s = m_shapeList; s; s = s->m_next) { s->UpdateSweepRadius(m_sweep.localCenter); } int16 oldType = m_type; if (m_invMass == 0.0f && m_invI == 0.0f) { m_type = e_staticType; } else { m_type = e_dynamicType; } // If the body type changed, we need to refilter the broad-phase proxies. if (oldType != m_type) { for (b2Shape* s = m_shapeList; s; s = s->m_next) { s->RefilterProxy(m_world->m_broadPhase, m_xf); } } } // TODO_ERIN adjust linear velocity and torque to account for movement of center. void b2Body::SetMassFromShapes() { b2Assert(m_world->m_lock == false); if (m_world->m_lock == true) { return; } // Compute mass data from shapes. Each shape has its own density. m_mass = 0.0f; m_invMass = 0.0f; m_I = 0.0f; m_invI = 0.0f; b2Vec2 center = b2Vec2_zero; for (b2Shape* s = m_shapeList; s; s = s->m_next) { b2MassData massData; s->ComputeMass(&massData); m_mass += massData.mass; center += massData.mass * massData.center; m_I += massData.I; } // Compute center of mass, and shift the origin to the COM. if (m_mass > 0.0f) { m_invMass = 1.0f / m_mass; center *= m_invMass; } if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) { // Center the inertia about the center of mass. m_I -= m_mass * b2Dot(center, center); b2Assert(m_I > 0.0f); m_invI = 1.0f / m_I; } else { m_I = 0.0f; m_invI = 0.0f; } // Move center of mass. m_sweep.localCenter = center; m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); // Update the sweep radii of all child shapes. for (b2Shape* s = m_shapeList; s; s = s->m_next) { s->UpdateSweepRadius(m_sweep.localCenter); } int16 oldType = m_type; if (m_invMass == 0.0f && m_invI == 0.0f) { m_type = e_staticType; } else { m_type = e_dynamicType; } // If the body type changed, we need to refilter the broad-phase proxies. if (oldType != m_type) { for (b2Shape* s = m_shapeList; s; s = s->m_next) { s->RefilterProxy(m_world->m_broadPhase, m_xf); } } } bool b2Body::SetXForm(const b2Vec2& position, float32 angle) { b2Assert(m_world->m_lock == false); if (m_world->m_lock == true) { return true; } if (IsFrozen()) { return false; } m_xf.R.Set(angle); m_xf.position = position; m_sweep.c0 = m_sweep.c = b2Mul(m_xf, m_sweep.localCenter); m_sweep.a0 = m_sweep.a = angle; bool freeze = false; for (b2Shape* s = m_shapeList; s; s = s->m_next) { bool inRange = s->Synchronize(m_world->m_broadPhase, m_xf, m_xf); if (inRange == false) { freeze = true; break; } } if (freeze == true) { m_flags |= e_frozenFlag; m_linearVelocity.SetZero(); m_angularVelocity = 0.0f; for (b2Shape* s = m_shapeList; s; s = s->m_next) { s->DestroyProxy(m_world->m_broadPhase); } // Failure return false; } // Success m_world->m_broadPhase->Commit(); return true; } bool b2Body::SynchronizeShapes() { b2XForm xf1; xf1.R.Set(m_sweep.a0); xf1.position = m_sweep.c0 - b2Mul(xf1.R, m_sweep.localCenter); bool inRange = true; for (b2Shape* s = m_shapeList; s; s = s->m_next) { inRange = s->Synchronize(m_world->m_broadPhase, xf1, m_xf); if (inRange == false) { break; } } if (inRange == false) { m_flags |= e_frozenFlag; m_linearVelocity.SetZero(); m_angularVelocity = 0.0f; for (b2Shape* s = m_shapeList; s; s = s->m_next) { s->DestroyProxy(m_world->m_broadPhase); } // Failure return false; } // Success return true; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/0000755000000000000000000000000011414467241020434 5ustar rootrootpython-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2MouseJoint.h0000644000000000000000000000566411064106301023124 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_MOUSE_JOINT_H #define B2_MOUSE_JOINT_H #include "b2Joint.h" /// Mouse joint definition. This requires a world target point, /// tuning parameters, and the time step. struct b2MouseJointDef : public b2JointDef { b2MouseJointDef() { type = e_mouseJoint; target.Set(0.0f, 0.0f); maxForce = 0.0f; frequencyHz = 5.0f; dampingRatio = 0.7f; } /// The initial world target point. This is assumed /// to coincide with the body anchor initially. b2Vec2 target; /// The maximum constraint force that can be exerted /// to move the candidate body. Usually you will express /// as some multiple of the weight (multiplier * mass * gravity). float32 maxForce; /// The response speed. float32 frequencyHz; /// The damping ratio. 0 = no damping, 1 = critical damping. float32 dampingRatio; }; /// A mouse joint is used to make a point on a body track a /// specified world point. This a soft constraint with a maximum /// force. This allows the constraint to stretch and without /// applying huge forces. class b2MouseJoint : public b2Joint { public: /// Implements b2Joint. b2Vec2 GetAnchor1() const; /// Implements b2Joint. b2Vec2 GetAnchor2() const; /// Implements b2Joint. b2Vec2 GetReactionForce(float32 inv_dt) const; /// Implements b2Joint. float32 GetReactionTorque(float32 inv_dt) const; /// Use this to update the target point. void SetTarget(const b2Vec2& target); //--------------- Internals Below ------------------- b2MouseJoint(const b2MouseJointDef* def); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(const b2TimeStep& step); bool SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); return true; } b2Vec2 m_localAnchor; b2Vec2 m_target; b2Vec2 m_impulse; b2Mat22 m_mass; // effective mass for point-to-point constraint. b2Vec2 m_C; // position error float32 m_maxForce; float32 m_frequencyHz; float32 m_dampingRatio; float32 m_beta; float32 m_gamma; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2DistanceJoint.h0000644000000000000000000000601411064106301023554 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_DISTANCE_JOINT_H #define B2_DISTANCE_JOINT_H #include "b2Joint.h" /// Distance joint definition. This requires defining an /// anchor point on both bodies and the non-zero length of the /// distance joint. The definition uses local anchor points /// so that the initial configuration can violate the constraint /// slightly. This helps when saving and loading a game. /// @warning Do not use a zero or short length. struct b2DistanceJointDef : public b2JointDef { b2DistanceJointDef() { type = e_distanceJoint; localAnchor1.Set(0.0f, 0.0f); localAnchor2.Set(0.0f, 0.0f); length = 1.0f; frequencyHz = 0.0f; dampingRatio = 0.0f; } /// Initialize the bodies, anchors, and length using the world /// anchors. void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor1, const b2Vec2& anchor2); /// The local anchor point relative to body1's origin. b2Vec2 localAnchor1; /// The local anchor point relative to body2's origin. b2Vec2 localAnchor2; /// The equilibrium length between the anchor points. float32 length; /// The response speed. float32 frequencyHz; /// The damping ratio. 0 = no damping, 1 = critical damping. float32 dampingRatio; }; /// A distance joint constrains two points on two bodies /// to remain at a fixed distance from each other. You can view /// this as a massless, rigid rod. class b2DistanceJoint : public b2Joint { public: b2Vec2 GetAnchor1() const; b2Vec2 GetAnchor2() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; //--------------- Internals Below ------------------- b2DistanceJoint(const b2DistanceJointDef* data); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(const b2TimeStep& step); bool SolvePositionConstraints(float32 baumgarte); b2Vec2 m_localAnchor1; b2Vec2 m_localAnchor2; b2Vec2 m_u; float32 m_frequencyHz; float32 m_dampingRatio; float32 m_gamma; float32 m_bias; float32 m_impulse; float32 m_mass; // effective mass for the constraint. float32 m_length; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2PulleyJoint.h0000644000000000000000000001053211064106301023274 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_PULLEY_JOINT_H #define B2_PULLEY_JOINT_H #include "b2Joint.h" const float32 b2_minPulleyLength = 2.0f; /// Pulley joint definition. This requires two ground anchors, /// two dynamic body anchor points, max lengths for each side, /// and a pulley ratio. struct b2PulleyJointDef : public b2JointDef { b2PulleyJointDef() { type = e_pulleyJoint; groundAnchor1.Set(-1.0f, 1.0f); groundAnchor2.Set(1.0f, 1.0f); localAnchor1.Set(-1.0f, 0.0f); localAnchor2.Set(1.0f, 0.0f); length1 = 0.0f; maxLength1 = 0.0f; length2 = 0.0f; maxLength2 = 0.0f; ratio = 1.0f; collideConnected = true; } /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors. void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& groundAnchor1, const b2Vec2& groundAnchor2, const b2Vec2& anchor1, const b2Vec2& anchor2, float32 ratio); /// The first ground anchor in world coordinates. This point never moves. b2Vec2 groundAnchor1; /// The second ground anchor in world coordinates. This point never moves. b2Vec2 groundAnchor2; /// The local anchor point relative to body1's origin. b2Vec2 localAnchor1; /// The local anchor point relative to body2's origin. b2Vec2 localAnchor2; /// The a reference length for the segment attached to body1. float32 length1; /// The maximum length of the segment attached to body1. float32 maxLength1; /// The a reference length for the segment attached to body2. float32 length2; /// The maximum length of the segment attached to body2. float32 maxLength2; /// The pulley ratio, used to simulate a block-and-tackle. float32 ratio; }; /// The pulley joint is connected to two bodies and two fixed ground points. /// The pulley supports a ratio such that: /// length1 + ratio * length2 <= constant /// Yes, the force transmitted is scaled by the ratio. /// The pulley also enforces a maximum length limit on both sides. This is /// useful to prevent one side of the pulley hitting the top. class b2PulleyJoint : public b2Joint { public: b2Vec2 GetAnchor1() const; b2Vec2 GetAnchor2() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Get the first ground anchor. b2Vec2 GetGroundAnchor1() const; /// Get the second ground anchor. b2Vec2 GetGroundAnchor2() const; /// Get the current length of the segment attached to body1. float32 GetLength1() const; /// Get the current length of the segment attached to body2. float32 GetLength2() const; /// Get the pulley ratio. float32 GetRatio() const; //--------------- Internals Below ------------------- b2PulleyJoint(const b2PulleyJointDef* data); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(const b2TimeStep& step); bool SolvePositionConstraints(float32 baumgarte); b2Body* m_ground; b2Vec2 m_groundAnchor1; b2Vec2 m_groundAnchor2; b2Vec2 m_localAnchor1; b2Vec2 m_localAnchor2; b2Vec2 m_u1; b2Vec2 m_u2; float32 m_constant; float32 m_ratio; float32 m_maxLength1; float32 m_maxLength2; // Effective masses float32 m_pulleyMass; float32 m_limitMass1; float32 m_limitMass2; // Impulses for accumulation/warm starting. float32 m_impulse; float32 m_limitImpulse1; float32 m_limitImpulse2; b2LimitState m_state; b2LimitState m_limitState1; b2LimitState m_limitState2; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2MouseJoint.cpp0000644000000000000000000001042011064106301023441 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2MouseJoint.h" #include "../b2Body.h" #include "../b2World.h" // p = attached point, m = mouse point // C = p - m // Cdot = v // = v + cross(w, r) // J = [I r_skew] // Identity used: // w k % (rx i + ry j) = w * (-ry i + rx j) b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def) : b2Joint(def) { m_target = def->target; m_localAnchor = b2MulT(m_body2->GetXForm(), m_target); m_maxForce = def->maxForce; m_impulse.SetZero(); m_frequencyHz = def->frequencyHz; m_dampingRatio = def->dampingRatio; m_beta = 0.0f; m_gamma = 0.0f; } void b2MouseJoint::SetTarget(const b2Vec2& target) { if (m_body2->IsSleeping()) { m_body2->WakeUp(); } m_target = target; } void b2MouseJoint::InitVelocityConstraints(const b2TimeStep& step) { b2Body* b = m_body2; float32 mass = b->GetMass(); // Frequency float32 omega = 2.0f * b2_pi * m_frequencyHz; // Damping coefficient float32 d = 2.0f * mass * m_dampingRatio * omega; // Spring stiffness float32 k = mass * (omega * omega); // magic formulas // gamma has units of inverse mass. // beta has units of inverse time. b2Assert(d + step.dt * k > B2_FLT_EPSILON); m_gamma = 1.0f / (step.dt * (d + step.dt * k)); m_beta = step.dt * k * m_gamma; // Compute the effective mass matrix. b2Vec2 r = b2Mul(b->GetXForm().R, m_localAnchor - b->GetLocalCenter()); // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)] // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y] // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x] float32 invMass = b->m_invMass; float32 invI = b->m_invI; b2Mat22 K1; K1.col1.x = invMass; K1.col2.x = 0.0f; K1.col1.y = 0.0f; K1.col2.y = invMass; b2Mat22 K2; K2.col1.x = invI * r.y * r.y; K2.col2.x = -invI * r.x * r.y; K2.col1.y = -invI * r.x * r.y; K2.col2.y = invI * r.x * r.x; b2Mat22 K = K1 + K2; K.col1.x += m_gamma; K.col2.y += m_gamma; m_mass = K.GetInverse(); m_C = b->m_sweep.c + r - m_target; // Cheat with some damping b->m_angularVelocity *= 0.98f; // Warm starting. m_impulse *= step.dtRatio; b->m_linearVelocity += invMass * m_impulse; b->m_angularVelocity += invI * b2Cross(r, m_impulse); } void b2MouseJoint::SolveVelocityConstraints(const b2TimeStep& step) { b2Body* b = m_body2; b2Vec2 r = b2Mul(b->GetXForm().R, m_localAnchor - b->GetLocalCenter()); // Cdot = v + cross(w, r) b2Vec2 Cdot = b->m_linearVelocity + b2Cross(b->m_angularVelocity, r); b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_beta * m_C + m_gamma * m_impulse)); b2Vec2 oldImpulse = m_impulse; m_impulse += impulse; float32 maxImpulse = step.dt * m_maxForce; if (m_impulse.LengthSquared() > maxImpulse * maxImpulse) { m_impulse *= maxImpulse / m_impulse.Length(); } impulse = m_impulse - oldImpulse; b->m_linearVelocity += b->m_invMass * impulse; b->m_angularVelocity += b->m_invI * b2Cross(r, impulse); } b2Vec2 b2MouseJoint::GetAnchor1() const { return m_target; } b2Vec2 b2MouseJoint::GetAnchor2() const { return m_body2->GetWorldPoint(m_localAnchor); } b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * m_impulse; } float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * 0.0f; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2Joint.cpp0000644000000000000000000000713111064106301022435 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2Joint.h" #include "b2DistanceJoint.h" #include "b2LineJoint.h" #include "b2MouseJoint.h" #include "b2RevoluteJoint.h" #include "b2PrismaticJoint.h" #include "b2PulleyJoint.h" #include "b2GearJoint.h" #include "../b2Body.h" #include "../b2World.h" #include "../../Common/b2BlockAllocator.h" #include "../../Collision/b2BroadPhase.h" #include b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator) { b2Joint* joint = NULL; switch (def->type) { case e_distanceJoint: { void* mem = allocator->Allocate(sizeof(b2DistanceJoint)); joint = new (mem) b2DistanceJoint((b2DistanceJointDef*)def); } break; case e_mouseJoint: { void* mem = allocator->Allocate(sizeof(b2MouseJoint)); joint = new (mem) b2MouseJoint((b2MouseJointDef*)def); } break; case e_prismaticJoint: { void* mem = allocator->Allocate(sizeof(b2PrismaticJoint)); joint = new (mem) b2PrismaticJoint((b2PrismaticJointDef*)def); } break; case e_revoluteJoint: { void* mem = allocator->Allocate(sizeof(b2RevoluteJoint)); joint = new (mem) b2RevoluteJoint((b2RevoluteJointDef*)def); } break; case e_pulleyJoint: { void* mem = allocator->Allocate(sizeof(b2PulleyJoint)); joint = new (mem) b2PulleyJoint((b2PulleyJointDef*)def); } break; case e_gearJoint: { void* mem = allocator->Allocate(sizeof(b2GearJoint)); joint = new (mem) b2GearJoint((b2GearJointDef*)def); } break; case e_lineJoint: { void* mem = allocator->Allocate(sizeof(b2LineJoint)); joint = new (mem) b2LineJoint((b2LineJointDef*)def); } break; default: b2Assert(false); break; } return joint; } void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator) { joint->~b2Joint(); switch (joint->m_type) { case e_distanceJoint: allocator->Free(joint, sizeof(b2DistanceJoint)); break; case e_mouseJoint: allocator->Free(joint, sizeof(b2MouseJoint)); break; case e_prismaticJoint: allocator->Free(joint, sizeof(b2PrismaticJoint)); break; case e_revoluteJoint: allocator->Free(joint, sizeof(b2RevoluteJoint)); break; case e_pulleyJoint: allocator->Free(joint, sizeof(b2PulleyJoint)); break; case e_gearJoint: allocator->Free(joint, sizeof(b2GearJoint)); break; case e_lineJoint: allocator->Free(joint, sizeof(b2LineJoint)); break; default: b2Assert(false); break; } } b2Joint::b2Joint(const b2JointDef* def) { m_type = def->type; m_prev = NULL; m_next = NULL; m_body1 = def->body1; m_body2 = def->body2; m_collideConnected = def->collideConnected; m_islandFlag = false; m_userData = def->userData; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2RevoluteJoint.cpp0000644000000000000000000003070211130023047024162 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2RevoluteJoint.h" #include "../b2Body.h" #include "../b2World.h" #include "../b2Island.h" // Point-to-point constraint // C = p2 - p1 // Cdot = v2 - v1 // = v2 + cross(w2, r2) - v1 - cross(w1, r1) // J = [-I -r1_skew I r2_skew ] // Identity used: // w k % (rx i + ry j) = w * (-ry i + rx j) // Motor constraint // Cdot = w2 - w1 // J = [0 0 -1 0 0 1] // K = invI1 + invI2 void b2RevoluteJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor) { body1 = b1; body2 = b2; localAnchor1 = body1->GetLocalPoint(anchor); localAnchor2 = body2->GetLocalPoint(anchor); referenceAngle = body2->GetAngle() - body1->GetAngle(); } b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def) : b2Joint(def) { m_localAnchor1 = def->localAnchor1; m_localAnchor2 = def->localAnchor2; m_referenceAngle = def->referenceAngle; m_impulse.SetZero(); m_motorImpulse = 0.0f; m_lowerAngle = def->lowerAngle; m_upperAngle = def->upperAngle; m_maxMotorTorque = def->maxMotorTorque; m_motorSpeed = def->motorSpeed; m_enableLimit = def->enableLimit; m_enableMotor = def->enableMotor; m_limitState = e_inactiveLimit; } void b2RevoluteJoint::InitVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; if (m_enableMotor || m_enableLimit) { // You cannot create a rotation limit between bodies that // both have fixed rotation. b2Assert(b1->m_invI > 0.0f || b2->m_invI > 0.0f); } // Compute the effective mass matrix. b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); // J = [-I -r1_skew I r2_skew] // [ 0 -1 0 1] // r_skew = [-ry; rx] // Matlab // K = [ m1+r1y^2*i1+m2+r2y^2*i2, -r1y*i1*r1x-r2y*i2*r2x, -r1y*i1-r2y*i2] // [ -r1y*i1*r1x-r2y*i2*r2x, m1+r1x^2*i1+m2+r2x^2*i2, r1x*i1+r2x*i2] // [ -r1y*i1-r2y*i2, r1x*i1+r2x*i2, i1+i2] float32 m1 = b1->m_invMass, m2 = b2->m_invMass; float32 i1 = b1->m_invI, i2 = b2->m_invI; m_mass.col1.x = m1 + m2 + r1.y * r1.y * i1 + r2.y * r2.y * i2; m_mass.col2.x = -r1.y * r1.x * i1 - r2.y * r2.x * i2; m_mass.col3.x = -r1.y * i1 - r2.y * i2; m_mass.col1.y = m_mass.col2.x; m_mass.col2.y = m1 + m2 + r1.x * r1.x * i1 + r2.x * r2.x * i2; m_mass.col3.y = r1.x * i1 + r2.x * i2; m_mass.col1.z = m_mass.col3.x; m_mass.col2.z = m_mass.col3.y; m_mass.col3.z = i1 + i2; m_motorMass = 1.0f / (i1 + i2); if (m_enableMotor == false) { m_motorImpulse = 0.0f; } if (m_enableLimit) { float32 jointAngle = b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle; if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop) { m_limitState = e_equalLimits; } else if (jointAngle <= m_lowerAngle) { if (m_limitState != e_atLowerLimit) { m_impulse.z = 0.0f; } m_limitState = e_atLowerLimit; } else if (jointAngle >= m_upperAngle) { if (m_limitState != e_atUpperLimit) { m_impulse.z = 0.0f; } m_limitState = e_atUpperLimit; } else { m_limitState = e_inactiveLimit; m_impulse.z = 0.0f; } } else { m_limitState = e_inactiveLimit; } if (step.warmStarting) { // Scale impulses to support a variable time step. m_impulse *= step.dtRatio; m_motorImpulse *= step.dtRatio; b2Vec2 P(m_impulse.x, m_impulse.y); b1->m_linearVelocity -= m1 * P; b1->m_angularVelocity -= i1 * (b2Cross(r1, P) + m_motorImpulse + m_impulse.z); b2->m_linearVelocity += m2 * P; b2->m_angularVelocity += i2 * (b2Cross(r2, P) + m_motorImpulse + m_impulse.z); } else { m_impulse.SetZero(); m_motorImpulse = 0.0f; } } void b2RevoluteJoint::SolveVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 v1 = b1->m_linearVelocity; float32 w1 = b1->m_angularVelocity; b2Vec2 v2 = b2->m_linearVelocity; float32 w2 = b2->m_angularVelocity; float32 m1 = b1->m_invMass, m2 = b2->m_invMass; float32 i1 = b1->m_invI, i2 = b2->m_invI; // Solve motor constraint. if (m_enableMotor && m_limitState != e_equalLimits) { float32 Cdot = w2 - w1 - m_motorSpeed; float32 impulse = m_motorMass * (-Cdot); float32 oldImpulse = m_motorImpulse; float32 maxImpulse = step.dt * m_maxMotorTorque; m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; w1 -= i1 * impulse; w2 += i2 * impulse; } // Solve limit constraint. if (m_enableLimit && m_limitState != e_inactiveLimit) { b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); // Solve point-to-point constraint b2Vec2 Cdot1 = v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1); float32 Cdot2 = w2 - w1; b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); b2Vec3 impulse = m_mass.Solve33(-Cdot); if (m_limitState == e_equalLimits) { m_impulse += impulse; } else if (m_limitState == e_atLowerLimit) { float32 newImpulse = m_impulse.z + impulse.z; if (newImpulse < 0.0f) { b2Vec2 reduced = m_mass.Solve22(-Cdot1); impulse.x = reduced.x; impulse.y = reduced.y; impulse.z = -m_impulse.z; m_impulse.x += reduced.x; m_impulse.y += reduced.y; m_impulse.z = 0.0f; } } else if (m_limitState == e_atUpperLimit) { float32 newImpulse = m_impulse.z + impulse.z; if (newImpulse > 0.0f) { b2Vec2 reduced = m_mass.Solve22(-Cdot1); impulse.x = reduced.x; impulse.y = reduced.y; impulse.z = -m_impulse.z; m_impulse.x += reduced.x; m_impulse.y += reduced.y; m_impulse.z = 0.0f; } } b2Vec2 P(impulse.x, impulse.y); v1 -= m1 * P; w1 -= i1 * (b2Cross(r1, P) + impulse.z); v2 += m2 * P; w2 += i2 * (b2Cross(r2, P) + impulse.z); } else { b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); // Solve point-to-point constraint b2Vec2 Cdot = v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1); b2Vec2 impulse = m_mass.Solve22(-Cdot); m_impulse.x += impulse.x; m_impulse.y += impulse.y; v1 -= m1 * impulse; w1 -= i1 * b2Cross(r1, impulse); v2 += m2 * impulse; w2 += i2 * b2Cross(r2, impulse); } b1->m_linearVelocity = v1; b1->m_angularVelocity = w1; b2->m_linearVelocity = v2; b2->m_angularVelocity = w2; } bool b2RevoluteJoint::SolvePositionConstraints(float32 baumgarte) { // TODO_ERIN block solve with limit. B2_NOT_USED(baumgarte); b2Body* b1 = m_body1; b2Body* b2 = m_body2; float32 angularError = 0.0f; float32 positionError = 0.0f; // Solve angular limit constraint. if (m_enableLimit && m_limitState != e_inactiveLimit) { float32 angle = b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle; float32 limitImpulse = 0.0f; if (m_limitState == e_equalLimits) { // Prevent large angular corrections float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection); limitImpulse = -m_motorMass * C; angularError = b2Abs(C); } else if (m_limitState == e_atLowerLimit) { float32 C = angle - m_lowerAngle; angularError = -C; // Prevent large angular corrections and allow some slop. C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f); limitImpulse = -m_motorMass * C; } else if (m_limitState == e_atUpperLimit) { float32 C = angle - m_upperAngle; angularError = C; // Prevent large angular corrections and allow some slop. C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection); limitImpulse = -m_motorMass * C; } b1->m_sweep.a -= b1->m_invI * limitImpulse; b2->m_sweep.a += b2->m_invI * limitImpulse; b1->SynchronizeTransform(); b2->SynchronizeTransform(); } // Solve point-to-point constraint. { b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); b2Vec2 C = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; positionError = C.Length(); float32 invMass1 = b1->m_invMass, invMass2 = b2->m_invMass; float32 invI1 = b1->m_invI, invI2 = b2->m_invI; // Handle large detachment. const float32 k_allowedStretch = 10.0f * b2_linearSlop; if (C.LengthSquared() > k_allowedStretch * k_allowedStretch) { // Use a particle solution (no rotation). b2Vec2 u = C; u.Normalize(); float32 k = invMass1 + invMass2; b2Assert(k > B2_FLT_EPSILON); float32 m = 1.0f / k; b2Vec2 impulse = m * (-C); const float32 k_beta = 0.5f; b1->m_sweep.c -= k_beta * invMass1 * impulse; b2->m_sweep.c += k_beta * invMass2 * impulse; C = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; } b2Mat22 K1; K1.col1.x = invMass1 + invMass2; K1.col2.x = 0.0f; K1.col1.y = 0.0f; K1.col2.y = invMass1 + invMass2; b2Mat22 K2; K2.col1.x = invI1 * r1.y * r1.y; K2.col2.x = -invI1 * r1.x * r1.y; K2.col1.y = -invI1 * r1.x * r1.y; K2.col2.y = invI1 * r1.x * r1.x; b2Mat22 K3; K3.col1.x = invI2 * r2.y * r2.y; K3.col2.x = -invI2 * r2.x * r2.y; K3.col1.y = -invI2 * r2.x * r2.y; K3.col2.y = invI2 * r2.x * r2.x; b2Mat22 K = K1 + K2 + K3; b2Vec2 impulse = K.Solve(-C); b1->m_sweep.c -= b1->m_invMass * impulse; b1->m_sweep.a -= b1->m_invI * b2Cross(r1, impulse); b2->m_sweep.c += b2->m_invMass * impulse; b2->m_sweep.a += b2->m_invI * b2Cross(r2, impulse); b1->SynchronizeTransform(); b2->SynchronizeTransform(); } return positionError <= b2_linearSlop && angularError <= b2_angularSlop; } b2Vec2 b2RevoluteJoint::GetAnchor1() const { return m_body1->GetWorldPoint(m_localAnchor1); } b2Vec2 b2RevoluteJoint::GetAnchor2() const { return m_body2->GetWorldPoint(m_localAnchor2); } b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 P(m_impulse.x, m_impulse.y); return inv_dt * P; } float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_impulse.z; } float32 b2RevoluteJoint::GetJointAngle() const { b2Body* b1 = m_body1; b2Body* b2 = m_body2; return b2->m_sweep.a - b1->m_sweep.a - m_referenceAngle; } float32 b2RevoluteJoint::GetJointSpeed() const { b2Body* b1 = m_body1; b2Body* b2 = m_body2; return b2->m_angularVelocity - b1->m_angularVelocity; } bool b2RevoluteJoint::IsMotorEnabled() const { return m_enableMotor; } void b2RevoluteJoint::EnableMotor(bool flag) { m_body1->WakeUp(); m_body2->WakeUp(); m_enableMotor = flag; } float32 b2RevoluteJoint::GetMotorTorque() const { return m_motorImpulse; } void b2RevoluteJoint::SetMotorSpeed(float32 speed) { m_body1->WakeUp(); m_body2->WakeUp(); m_motorSpeed = speed; } void b2RevoluteJoint::SetMaxMotorTorque(float32 torque) { m_body1->WakeUp(); m_body2->WakeUp(); m_maxMotorTorque = torque; } bool b2RevoluteJoint::IsLimitEnabled() const { return m_enableLimit; } void b2RevoluteJoint::EnableLimit(bool flag) { m_body1->WakeUp(); m_body2->WakeUp(); m_enableLimit = flag; } float32 b2RevoluteJoint::GetLowerLimit() const { return m_lowerAngle; } float32 b2RevoluteJoint::GetUpperLimit() const { return m_upperAngle; } void b2RevoluteJoint::SetLimits(float32 lower, float32 upper) { b2Assert(lower <= upper); m_body1->WakeUp(); m_body2->WakeUp(); m_lowerAngle = lower; m_upperAngle = upper; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2Joint.h0000644000000000000000000001376711133714741022130 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef JOINT_H #define JOINT_H #include "../../Common/b2Math.h" class b2Body; class b2Joint; struct b2TimeStep; class b2BlockAllocator; enum b2JointType { e_unknownJoint, e_revoluteJoint, e_prismaticJoint, e_distanceJoint, e_pulleyJoint, e_mouseJoint, e_gearJoint, e_lineJoint }; enum b2LimitState { e_inactiveLimit, e_atLowerLimit, e_atUpperLimit, e_equalLimits }; struct b2Jacobian { b2Vec2 linear1; float32 angular1; b2Vec2 linear2; float32 angular2; void SetZero(); void Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2); float32 Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2); }; /// A joint edge is used to connect bodies and joints together /// in a joint graph where each body is a node and each joint /// is an edge. A joint edge belongs to a doubly linked list /// maintained in each attached body. Each joint has two joint /// nodes, one for each attached body. struct b2JointEdge { b2Body* other; ///< provides quick access to the other body attached. b2Joint* joint; ///< the joint b2JointEdge* prev; ///< the previous joint edge in the body's joint list b2JointEdge* next; ///< the next joint edge in the body's joint list }; /// Joint definitions are used to construct joints. struct b2JointDef { b2JointDef() { type = e_unknownJoint; userData = NULL; body1 = NULL; body2 = NULL; collideConnected = false; } /// The joint type is set automatically for concrete joint types. b2JointType type; /// Use this to attach application specific data to your joints. void* userData; /// The first attached body. b2Body* body1; /// The second attached body. b2Body* body2; /// Set this flag to true if the attached bodies should collide. bool collideConnected; }; /// The base joint class. Joints are used to constraint two bodies together in /// various fashions. Some joints also feature limits and motors. class b2Joint { public: /// Get the type of the concrete joint. b2JointType GetType() const; /// Get the first body attached to this joint. b2Body* GetBody1(); /// Get the second body attached to this joint. b2Body* GetBody2(); /// Get the anchor point on body1 in world coordinates. virtual b2Vec2 GetAnchor1() const = 0; /// Get the anchor point on body2 in world coordinates. virtual b2Vec2 GetAnchor2() const = 0; /// Get the reaction force on body2 at the joint anchor. virtual b2Vec2 GetReactionForce(float32 inv_dt) const = 0; /// Get the reaction torque on body2. virtual float32 GetReactionTorque(float32 inv_dt) const = 0; /// Get the next joint the world joint list. b2Joint* GetNext(); /// Get the user data pointer. void* GetUserData(); /// Set the user data pointer. void SetUserData(void* data); /// Get whether or not joint bodies can collide bool GetCollideConnected(); //--------------- Internals Below ------------------- protected: friend class b2World; friend class b2Body; friend class b2Island; static b2Joint* Create(const b2JointDef* def, b2BlockAllocator* allocator); static void Destroy(b2Joint* joint, b2BlockAllocator* allocator); b2Joint(const b2JointDef* def); virtual ~b2Joint() {} virtual void InitVelocityConstraints(const b2TimeStep& step) = 0; virtual void SolveVelocityConstraints(const b2TimeStep& step) = 0; // This returns true if the position errors are within tolerance. virtual bool SolvePositionConstraints(float32 baumgarte) = 0; void ComputeXForm(b2XForm* xf, const b2Vec2& center, const b2Vec2& localCenter, float32 angle) const; b2JointType m_type; b2Joint* m_prev; b2Joint* m_next; b2JointEdge m_node1; b2JointEdge m_node2; b2Body* m_body1; b2Body* m_body2; bool m_islandFlag; bool m_collideConnected; void* m_userData; // Cache here per time step to reduce cache misses. b2Vec2 m_localCenter1, m_localCenter2; float32 m_invMass1, m_invI1; float32 m_invMass2, m_invI2; }; inline void b2Jacobian::SetZero() { linear1.SetZero(); angular1 = 0.0f; linear2.SetZero(); angular2 = 0.0f; } inline void b2Jacobian::Set(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2) { linear1 = x1; angular1 = a1; linear2 = x2; angular2 = a2; } inline float32 b2Jacobian::Compute(const b2Vec2& x1, float32 a1, const b2Vec2& x2, float32 a2) { return b2Dot(linear1, x1) + angular1 * a1 + b2Dot(linear2, x2) + angular2 * a2; } inline b2JointType b2Joint::GetType() const { return m_type; } inline b2Body* b2Joint::GetBody1() { return m_body1; } inline b2Body* b2Joint::GetBody2() { return m_body2; } inline b2Joint* b2Joint::GetNext() { return m_next; } inline void* b2Joint::GetUserData() { return m_userData; } inline void b2Joint::SetUserData(void* data) { m_userData = data; } inline bool b2Joint::GetCollideConnected() { return m_collideConnected; } inline void b2Joint::ComputeXForm(b2XForm* xf, const b2Vec2& center, const b2Vec2& localCenter, float32 angle) const { xf->R.Set(angle); xf->position = center - b2Mul(xf->R, localCenter); } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2LineJoint.cpp0000644000000000000000000003442511130023047023252 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2LineJoint.h" #include "../b2Body.h" #include "../b2World.h" // Linear constraint (point-to-line) // d = p2 - p1 = x2 + r2 - x1 - r1 // C = dot(perp, d) // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) // = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] // // K = J * invM * JT // // J = [-a -s1 a s2] // a = perp // s1 = cross(d + r1, a) = cross(p2 - x1, a) // s2 = cross(r2, a) = cross(p2 - x2, a) // Motor/Limit linear constraint // C = dot(ax1, d) // Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] // Block Solver // We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even // when the mass has poor distribution (leading to large torques about the joint anchor points). // // The Jacobian has 3 rows: // J = [-uT -s1 uT s2] // linear // [-vT -a1 vT a2] // limit // // u = perp // v = axis // s1 = cross(d + r1, u), s2 = cross(r2, u) // a1 = cross(d + r1, v), a2 = cross(r2, v) // M * (v2 - v1) = JT * df // J * v2 = bias // // v2 = v1 + invM * JT * df // J * (v1 + invM * JT * df) = bias // K * df = bias - J * v1 = -Cdot // K = J * invM * JT // Cdot = J * v1 - bias // // Now solve for f2. // df = f2 - f1 // K * (f2 - f1) = -Cdot // f2 = invK * (-Cdot) + f1 // // Clamp accumulated limit impulse. // lower: f2(2) = max(f2(2), 0) // upper: f2(2) = min(f2(2), 0) // // Solve for correct f2(1) // K(1,1) * f2(1) = -Cdot(1) - K(1,2) * f2(2) + K(1,1:2) * f1 // = -Cdot(1) - K(1,2) * f2(2) + K(1,1) * f1(1) + K(1,2) * f1(2) // K(1,1) * f2(1) = -Cdot(1) - K(1,2) * (f2(2) - f1(2)) + K(1,1) * f1(1) // f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1) // // Now compute impulse to be applied: // df = f2 - f1 void b2LineJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis) { body1 = b1; body2 = b2; localAnchor1 = body1->GetLocalPoint(anchor); localAnchor2 = body2->GetLocalPoint(anchor); localAxis1 = body1->GetLocalVector(axis); } b2LineJoint::b2LineJoint(const b2LineJointDef* def) : b2Joint(def) { m_localAnchor1 = def->localAnchor1; m_localAnchor2 = def->localAnchor2; m_localXAxis1 = def->localAxis1; m_localYAxis1 = b2Cross(1.0f, m_localXAxis1); m_impulse.SetZero(); m_motorMass = 0.0; m_motorImpulse = 0.0f; m_lowerTranslation = def->lowerTranslation; m_upperTranslation = def->upperTranslation; m_maxMotorForce = B2FORCE_INV_SCALE(def->maxMotorForce); m_motorSpeed = def->motorSpeed; m_enableLimit = def->enableLimit; m_enableMotor = def->enableMotor; m_limitState = e_inactiveLimit; m_axis.SetZero(); m_perp.SetZero(); } void b2LineJoint::InitVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; m_localCenter1 = b1->GetLocalCenter(); m_localCenter2 = b2->GetLocalCenter(); b2XForm xf1 = b1->GetXForm(); b2XForm xf2 = b2->GetXForm(); // Compute the effective masses. b2Vec2 r1 = b2Mul(xf1.R, m_localAnchor1 - m_localCenter1); b2Vec2 r2 = b2Mul(xf2.R, m_localAnchor2 - m_localCenter2); b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; m_invMass1 = b1->m_invMass; m_invI1 = b1->m_invI; m_invMass2 = b2->m_invMass; m_invI2 = b2->m_invI; // Compute motor Jacobian and effective mass. { m_axis = b2Mul(xf1.R, m_localXAxis1); m_a1 = b2Cross(d + r1, m_axis); m_a2 = b2Cross(r2, m_axis); m_motorMass = m_invMass1 + m_invMass2 + m_invI1 * m_a1 * m_a1 + m_invI2 * m_a2 * m_a2; b2Assert(m_motorMass > B2_FLT_EPSILON); m_motorMass = 1.0f / m_motorMass; } // Prismatic constraint. { m_perp = b2Mul(xf1.R, m_localYAxis1); m_s1 = b2Cross(d + r1, m_perp); m_s2 = b2Cross(r2, m_perp); float32 m1 = m_invMass1, m2 = m_invMass2; float32 i1 = m_invI1, i2 = m_invI2; float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; float32 k12 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2; float32 k22 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2; m_K.col1.Set(k11, k12); m_K.col2.Set(k12, k22); } // Compute motor and limit terms. if (m_enableLimit) { float32 jointTranslation = b2Dot(m_axis, d); if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) { m_limitState = e_equalLimits; } else if (jointTranslation <= m_lowerTranslation) { if (m_limitState != e_atLowerLimit) { m_limitState = e_atLowerLimit; m_impulse.y = 0.0f; } } else if (jointTranslation >= m_upperTranslation) { if (m_limitState != e_atUpperLimit) { m_limitState = e_atUpperLimit; m_impulse.y = 0.0f; } } else { m_limitState = e_inactiveLimit; m_impulse.y = 0.0f; } } else { m_limitState = e_inactiveLimit; } if (m_enableMotor == false) { m_motorImpulse = 0.0f; } if (step.warmStarting) { // Account for variable time step. m_impulse *= step.dtRatio; m_motorImpulse *= step.dtRatio; b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.y) * m_axis; float32 L1 = m_impulse.x * m_s1 + (m_motorImpulse + m_impulse.y) * m_a1; float32 L2 = m_impulse.x * m_s2 + (m_motorImpulse + m_impulse.y) * m_a2; b1->m_linearVelocity -= m_invMass1 * P; b1->m_angularVelocity -= m_invI1 * L1; b2->m_linearVelocity += m_invMass2 * P; b2->m_angularVelocity += m_invI2 * L2; } else { m_impulse.SetZero(); m_motorImpulse = 0.0f; } } void b2LineJoint::SolveVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 v1 = b1->m_linearVelocity; float32 w1 = b1->m_angularVelocity; b2Vec2 v2 = b2->m_linearVelocity; float32 w2 = b2->m_angularVelocity; // Solve linear motor constraint. if (m_enableMotor && m_limitState != e_equalLimits) { float32 Cdot = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1; float32 impulse = m_motorMass * (m_motorSpeed - Cdot); float32 oldImpulse = m_motorImpulse; float32 maxImpulse = step.dt * m_maxMotorForce; m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; b2Vec2 P = impulse * m_axis; float32 L1 = impulse * m_a1; float32 L2 = impulse * m_a2; v1 -= m_invMass1 * P; w1 -= m_invI1 * L1; v2 += m_invMass2 * P; w2 += m_invI2 * L2; } float32 Cdot1 = b2Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1; if (m_enableLimit && m_limitState != e_inactiveLimit) { // Solve prismatic and limit constraint in block form. float32 Cdot2 = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1; b2Vec2 Cdot(Cdot1, Cdot2); b2Vec2 f1 = m_impulse; b2Vec2 df = m_K.Solve(-Cdot); m_impulse += df; if (m_limitState == e_atLowerLimit) { m_impulse.y = b2Max(m_impulse.y, 0.0f); } else if (m_limitState == e_atUpperLimit) { m_impulse.y = b2Min(m_impulse.y, 0.0f); } // f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1) float32 b = -Cdot1 - (m_impulse.y - f1.y) * m_K.col2.x; float32 f2r = b / m_K.col1.x + f1.x; m_impulse.x = f2r; df = m_impulse - f1; b2Vec2 P = df.x * m_perp + df.y * m_axis; float32 L1 = df.x * m_s1 + df.y * m_a1; float32 L2 = df.x * m_s2 + df.y * m_a2; v1 -= m_invMass1 * P; w1 -= m_invI1 * L1; v2 += m_invMass2 * P; w2 += m_invI2 * L2; } else { // Limit is inactive, just solve the prismatic constraint in block form. float32 df = (-Cdot1) / m_K.col1.x; m_impulse.x += df; b2Vec2 P = df * m_perp; float32 L1 = df * m_s1; float32 L2 = df * m_s2; v1 -= m_invMass1 * P; w1 -= m_invI1 * L1; v2 += m_invMass2 * P; w2 += m_invI2 * L2; } b1->m_linearVelocity = v1; b1->m_angularVelocity = w1; b2->m_linearVelocity = v2; b2->m_angularVelocity = w2; } bool b2LineJoint::SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 c1 = b1->m_sweep.c; float32 a1 = b1->m_sweep.a; b2Vec2 c2 = b2->m_sweep.c; float32 a2 = b2->m_sweep.a; // Solve linear limit constraint. float32 linearError = 0.0f, angularError = 0.0f; bool active = false; float32 C2 = 0.0f; b2Mat22 R1(a1), R2(a2); b2Vec2 r1 = b2Mul(R1, m_localAnchor1 - m_localCenter1); b2Vec2 r2 = b2Mul(R2, m_localAnchor2 - m_localCenter2); b2Vec2 d = c2 + r2 - c1 - r1; if (m_enableLimit) { m_axis = b2Mul(R1, m_localXAxis1); m_a1 = b2Cross(d + r1, m_axis); m_a2 = b2Cross(r2, m_axis); float32 translation = b2Dot(m_axis, d); if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) { // Prevent large angular corrections C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); linearError = b2Abs(translation); active = true; } else if (translation <= m_lowerTranslation) { // Prevent large linear corrections and allow some slop. C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); linearError = m_lowerTranslation - translation; active = true; } else if (translation >= m_upperTranslation) { // Prevent large linear corrections and allow some slop. C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); linearError = translation - m_upperTranslation; active = true; } } m_perp = b2Mul(R1, m_localYAxis1); m_s1 = b2Cross(d + r1, m_perp); m_s2 = b2Cross(r2, m_perp); b2Vec2 impulse; float32 C1; C1 = b2Dot(m_perp, d); linearError = b2Max(linearError, b2Abs(C1)); angularError = 0.0f; if (active) { float32 m1 = m_invMass1, m2 = m_invMass2; float32 i1 = m_invI1, i2 = m_invI2; float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; float32 k12 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2; float32 k22 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2; m_K.col1.Set(k11, k12); m_K.col2.Set(k12, k22); b2Vec2 C; C.x = C1; C.y = C2; impulse = m_K.Solve(-C); } else { float32 m1 = m_invMass1, m2 = m_invMass2; float32 i1 = m_invI1, i2 = m_invI2; float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; float32 impulse1 = (-C1) / k11; impulse.x = impulse1; impulse.y = 0.0f; } b2Vec2 P = impulse.x * m_perp + impulse.y * m_axis; float32 L1 = impulse.x * m_s1 + impulse.y * m_a1; float32 L2 = impulse.x * m_s2 + impulse.y * m_a2; c1 -= m_invMass1 * P; a1 -= m_invI1 * L1; c2 += m_invMass2 * P; a2 += m_invI2 * L2; // TODO_ERIN remove need for this. b1->m_sweep.c = c1; b1->m_sweep.a = a1; b2->m_sweep.c = c2; b2->m_sweep.a = a2; b1->SynchronizeTransform(); b2->SynchronizeTransform(); return linearError <= b2_linearSlop && angularError <= b2_angularSlop; } b2Vec2 b2LineJoint::GetAnchor1() const { return m_body1->GetWorldPoint(m_localAnchor1); } b2Vec2 b2LineJoint::GetAnchor2() const { return m_body2->GetWorldPoint(m_localAnchor2); } b2Vec2 b2LineJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.y) * m_axis); } float32 b2LineJoint::GetReactionTorque(float32 inv_dt) const { B2_NOT_USED(inv_dt); return 0.0f; } float32 b2LineJoint::GetJointTranslation() const { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1); b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2); b2Vec2 d = p2 - p1; b2Vec2 axis = b1->GetWorldVector(m_localXAxis1); float32 translation = b2Dot(d, axis); return translation; } float32 b2LineJoint::GetJointSpeed() const { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); b2Vec2 p1 = b1->m_sweep.c + r1; b2Vec2 p2 = b2->m_sweep.c + r2; b2Vec2 d = p2 - p1; b2Vec2 axis = b1->GetWorldVector(m_localXAxis1); b2Vec2 v1 = b1->m_linearVelocity; b2Vec2 v2 = b2->m_linearVelocity; float32 w1 = b1->m_angularVelocity; float32 w2 = b2->m_angularVelocity; float32 speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1)); return speed; } bool b2LineJoint::IsLimitEnabled() const { return m_enableLimit; } void b2LineJoint::EnableLimit(bool flag) { m_body1->WakeUp(); m_body2->WakeUp(); m_enableLimit = flag; } float32 b2LineJoint::GetLowerLimit() const { return m_lowerTranslation; } float32 b2LineJoint::GetUpperLimit() const { return m_upperTranslation; } void b2LineJoint::SetLimits(float32 lower, float32 upper) { b2Assert(lower <= upper); m_body1->WakeUp(); m_body2->WakeUp(); m_lowerTranslation = lower; m_upperTranslation = upper; } bool b2LineJoint::IsMotorEnabled() const { return m_enableMotor; } void b2LineJoint::EnableMotor(bool flag) { m_body1->WakeUp(); m_body2->WakeUp(); m_enableMotor = flag; } void b2LineJoint::SetMotorSpeed(float32 speed) { m_body1->WakeUp(); m_body2->WakeUp(); m_motorSpeed = speed; } void b2LineJoint::SetMaxMotorForce(float32 force) { m_body1->WakeUp(); m_body2->WakeUp(); m_maxMotorForce = B2FORCE_SCALE(float32(1.0))*force; } float32 b2LineJoint::GetMotorForce() const { return m_motorImpulse; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2RevoluteJoint.h0000644000000000000000000001250611130023047023631 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_REVOLUTE_JOINT_H #define B2_REVOLUTE_JOINT_H #include "b2Joint.h" /// Revolute joint definition. This requires defining an /// anchor point where the bodies are joined. The definition /// uses local anchor points so that the initial configuration /// can violate the constraint slightly. You also need to /// specify the initial relative angle for joint limits. This /// helps when saving and loading a game. /// The local anchor points are measured from the body's origin /// rather than the center of mass because: /// 1. you might not know where the center of mass will be. /// 2. if you add/remove shapes from a body and recompute the mass, /// the joints will be broken. struct b2RevoluteJointDef : public b2JointDef { b2RevoluteJointDef() { type = e_revoluteJoint; localAnchor1.Set(0.0f, 0.0f); localAnchor2.Set(0.0f, 0.0f); referenceAngle = 0.0f; lowerAngle = 0.0f; upperAngle = 0.0f; maxMotorTorque = 0.0f; motorSpeed = 0.0f; enableLimit = false; enableMotor = false; } /// Initialize the bodies, anchors, and reference angle using the world /// anchor. void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor); /// The local anchor point relative to body1's origin. b2Vec2 localAnchor1; /// The local anchor point relative to body2's origin. b2Vec2 localAnchor2; /// The body2 angle minus body1 angle in the reference state (radians). float32 referenceAngle; /// A flag to enable joint limits. bool enableLimit; /// The lower angle for the joint limit (radians). float32 lowerAngle; /// The upper angle for the joint limit (radians). float32 upperAngle; /// A flag to enable the joint motor. bool enableMotor; /// The desired motor speed. Usually in radians per second. float32 motorSpeed; /// The maximum motor torque used to achieve the desired motor speed. /// Usually in N-m. float32 maxMotorTorque; }; /// A revolute joint constrains to bodies to share a common point while they /// are free to rotate about the point. The relative rotation about the shared /// point is the joint angle. You can limit the relative rotation with /// a joint limit that specifies a lower and upper angle. You can use a motor /// to drive the relative rotation about the shared point. A maximum motor torque /// is provided so that infinite forces are not generated. class b2RevoluteJoint : public b2Joint { public: b2Vec2 GetAnchor1() const; b2Vec2 GetAnchor2() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Get the current joint angle in radians. float32 GetJointAngle() const; /// Get the current joint angle speed in radians per second. float32 GetJointSpeed() const; /// Is the joint limit enabled? bool IsLimitEnabled() const; /// Enable/disable the joint limit. void EnableLimit(bool flag); /// Get the lower joint limit in radians. float32 GetLowerLimit() const; /// Get the upper joint limit in radians. float32 GetUpperLimit() const; /// Set the joint limits in radians. void SetLimits(float32 lower, float32 upper); /// Is the joint motor enabled? bool IsMotorEnabled() const; /// Enable/disable the joint motor. void EnableMotor(bool flag); /// Set the motor speed in radians per second. void SetMotorSpeed(float32 speed); /// Get the motor speed in radians per second. float32 GetMotorSpeed() const; /// Set the maximum motor torque, usually in N-m. void SetMaxMotorTorque(float32 torque); /// Get the current motor torque, usually in N-m. float32 GetMotorTorque() const; //--------------- Internals Below ------------------- b2RevoluteJoint(const b2RevoluteJointDef* def); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(const b2TimeStep& step); bool SolvePositionConstraints(float32 baumgarte); b2Vec2 m_localAnchor1; // relative b2Vec2 m_localAnchor2; b2Vec3 m_impulse; float32 m_motorImpulse; b2Mat33 m_mass; // effective mass for point-to-point constraint. float32 m_motorMass; // effective mass for motor/limit angular constraint. bool m_enableMotor; float32 m_maxMotorTorque; float32 m_motorSpeed; bool m_enableLimit; float32 m_referenceAngle; float32 m_lowerAngle; float32 m_upperAngle; b2LimitState m_limitState; }; inline float32 b2RevoluteJoint::GetMotorSpeed() const { return m_motorSpeed; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2LineJoint.h0000644000000000000000000001171411064106301022714 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_LINE_JOINT_H #define B2_LINE_JOINT_H #include "b2Joint.h" /// Line joint definition. This requires defining a line of /// motion using an axis and an anchor point. The definition uses local /// anchor points and a local axis so that the initial configuration /// can violate the constraint slightly. The joint translation is zero /// when the local anchor points coincide in world space. Using local /// anchors and a local axis helps when saving and loading a game. struct b2LineJointDef : public b2JointDef { b2LineJointDef() { type = e_lineJoint; localAnchor1.SetZero(); localAnchor2.SetZero(); localAxis1.Set(1.0f, 0.0f); enableLimit = false; lowerTranslation = 0.0f; upperTranslation = 0.0f; enableMotor = false; maxMotorForce = 0.0f; motorSpeed = 0.0f; } /// Initialize the bodies, anchors, axis, and reference angle using the world /// anchor and world axis. void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor, const b2Vec2& axis); /// The local anchor point relative to body1's origin. b2Vec2 localAnchor1; /// The local anchor point relative to body2's origin. b2Vec2 localAnchor2; /// The local translation axis in body1. b2Vec2 localAxis1; /// Enable/disable the joint limit. bool enableLimit; /// The lower translation limit, usually in meters. float32 lowerTranslation; /// The upper translation limit, usually in meters. float32 upperTranslation; /// Enable/disable the joint motor. bool enableMotor; /// The maximum motor torque, usually in N-m. float32 maxMotorForce; /// The desired motor speed in radians per second. float32 motorSpeed; }; /// A line joint. This joint provides one degree of freedom: translation /// along an axis fixed in body1. You can use a joint limit to restrict /// the range of motion and a joint motor to drive the motion or to /// model joint friction. class b2LineJoint : public b2Joint { public: b2Vec2 GetAnchor1() const; b2Vec2 GetAnchor2() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Get the current joint translation, usually in meters. float32 GetJointTranslation() const; /// Get the current joint translation speed, usually in meters per second. float32 GetJointSpeed() const; /// Is the joint limit enabled? bool IsLimitEnabled() const; /// Enable/disable the joint limit. void EnableLimit(bool flag); /// Get the lower joint limit, usually in meters. float32 GetLowerLimit() const; /// Get the upper joint limit, usually in meters. float32 GetUpperLimit() const; /// Set the joint limits, usually in meters. void SetLimits(float32 lower, float32 upper); /// Is the joint motor enabled? bool IsMotorEnabled() const; /// Enable/disable the joint motor. void EnableMotor(bool flag); /// Set the motor speed, usually in meters per second. void SetMotorSpeed(float32 speed); /// Get the motor speed, usually in meters per second. float32 GetMotorSpeed() const; /// Set the maximum motor force, usually in N. void SetMaxMotorForce(float32 force); /// Get the current motor force, usually in N. float32 GetMotorForce() const; //--------------- Internals Below ------------------- b2LineJoint(const b2LineJointDef* def); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(const b2TimeStep& step); bool SolvePositionConstraints(float32 baumgarte); b2Vec2 m_localAnchor1; b2Vec2 m_localAnchor2; b2Vec2 m_localXAxis1; b2Vec2 m_localYAxis1; b2Vec2 m_axis, m_perp; float32 m_s1, m_s2; float32 m_a1, m_a2; b2Mat22 m_K; b2Vec2 m_impulse; float32 m_motorMass; // effective mass for motor/limit translational constraint. float32 m_motorImpulse; float32 m_lowerTranslation; float32 m_upperTranslation; float32 m_maxMotorForce; float32 m_motorSpeed; bool m_enableLimit; bool m_enableMotor; b2LimitState m_limitState; }; inline float32 b2LineJoint::GetMotorSpeed() const { return m_motorSpeed; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2PrismaticJoint.h0000644000000000000000000001227311064106301023761 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_PRISMATIC_JOINT_H #define B2_PRISMATIC_JOINT_H #include "b2Joint.h" /// Prismatic joint definition. This requires defining a line of /// motion using an axis and an anchor point. The definition uses local /// anchor points and a local axis so that the initial configuration /// can violate the constraint slightly. The joint translation is zero /// when the local anchor points coincide in world space. Using local /// anchors and a local axis helps when saving and loading a game. struct b2PrismaticJointDef : public b2JointDef { b2PrismaticJointDef() { type = e_prismaticJoint; localAnchor1.SetZero(); localAnchor2.SetZero(); localAxis1.Set(1.0f, 0.0f); referenceAngle = 0.0f; enableLimit = false; lowerTranslation = 0.0f; upperTranslation = 0.0f; enableMotor = false; maxMotorForce = 0.0f; motorSpeed = 0.0f; } /// Initialize the bodies, anchors, axis, and reference angle using the world /// anchor and world axis. void Initialize(b2Body* body1, b2Body* body2, const b2Vec2& anchor, const b2Vec2& axis); /// The local anchor point relative to body1's origin. b2Vec2 localAnchor1; /// The local anchor point relative to body2's origin. b2Vec2 localAnchor2; /// The local translation axis in body1. b2Vec2 localAxis1; /// The constrained angle between the bodies: body2_angle - body1_angle. float32 referenceAngle; /// Enable/disable the joint limit. bool enableLimit; /// The lower translation limit, usually in meters. float32 lowerTranslation; /// The upper translation limit, usually in meters. float32 upperTranslation; /// Enable/disable the joint motor. bool enableMotor; /// The maximum motor torque, usually in N-m. float32 maxMotorForce; /// The desired motor speed in radians per second. float32 motorSpeed; }; /// A prismatic joint. This joint provides one degree of freedom: translation /// along an axis fixed in body1. Relative rotation is prevented. You can /// use a joint limit to restrict the range of motion and a joint motor to /// drive the motion or to model joint friction. class b2PrismaticJoint : public b2Joint { public: b2Vec2 GetAnchor1() const; b2Vec2 GetAnchor2() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Get the current joint translation, usually in meters. float32 GetJointTranslation() const; /// Get the current joint translation speed, usually in meters per second. float32 GetJointSpeed() const; /// Is the joint limit enabled? bool IsLimitEnabled() const; /// Enable/disable the joint limit. void EnableLimit(bool flag); /// Get the lower joint limit, usually in meters. float32 GetLowerLimit() const; /// Get the upper joint limit, usually in meters. float32 GetUpperLimit() const; /// Set the joint limits, usually in meters. void SetLimits(float32 lower, float32 upper); /// Is the joint motor enabled? bool IsMotorEnabled() const; /// Enable/disable the joint motor. void EnableMotor(bool flag); /// Set the motor speed, usually in meters per second. void SetMotorSpeed(float32 speed); /// Get the motor speed, usually in meters per second. float32 GetMotorSpeed() const; /// Set the maximum motor force, usually in N. void SetMaxMotorForce(float32 force); /// Get the current motor force, usually in N. float32 GetMotorForce() const; //--------------- Internals Below ------------------- b2PrismaticJoint(const b2PrismaticJointDef* def); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(const b2TimeStep& step); bool SolvePositionConstraints(float32 baumgarte); b2Vec2 m_localAnchor1; b2Vec2 m_localAnchor2; b2Vec2 m_localXAxis1; b2Vec2 m_localYAxis1; float32 m_refAngle; b2Vec2 m_axis, m_perp; float32 m_s1, m_s2; float32 m_a1, m_a2; b2Mat33 m_K; b2Vec3 m_impulse; float32 m_motorMass; // effective mass for motor/limit translational constraint. float32 m_motorImpulse; float32 m_lowerTranslation; float32 m_upperTranslation; float32 m_maxMotorForce; float32 m_motorSpeed; bool m_enableLimit; bool m_enableMotor; b2LimitState m_limitState; }; inline float32 b2PrismaticJoint::GetMotorSpeed() const { return m_motorSpeed; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2DistanceJoint.cpp0000644000000000000000000001356011064106301024113 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2DistanceJoint.h" #include "../b2Body.h" #include "../b2World.h" // 1-D constrained system // m (v2 - v1) = lambda // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass. // x2 = x1 + h * v2 // 1-D mass-damper-spring system // m (v2 - v1) + h * d * v2 + h * k * // C = norm(p2 - p1) - L // u = (p2 - p1) / norm(p2 - p1) // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1)) // J = [-u -cross(r1, u) u cross(r2, u)] // K = J * invM * JT // = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2 void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor1, const b2Vec2& anchor2) { body1 = b1; body2 = b2; localAnchor1 = body1->GetLocalPoint(anchor1); localAnchor2 = body2->GetLocalPoint(anchor2); b2Vec2 d = anchor2 - anchor1; length = d.Length(); } b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) : b2Joint(def) { m_localAnchor1 = def->localAnchor1; m_localAnchor2 = def->localAnchor2; m_length = def->length; m_frequencyHz = def->frequencyHz; m_dampingRatio = def->dampingRatio; m_impulse = 0.0f; m_gamma = 0.0f; m_bias = 0.0f; } void b2DistanceJoint::InitVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; // Compute the effective mass matrix. b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); m_u = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; // Handle singularity. float32 length = m_u.Length(); if (length > b2_linearSlop) { m_u *= 1.0f / length; } else { m_u.Set(0.0f, 0.0f); } float32 cr1u = b2Cross(r1, m_u); float32 cr2u = b2Cross(r2, m_u); float32 invMass = b1->m_invMass + b1->m_invI * cr1u * cr1u + b2->m_invMass + b2->m_invI * cr2u * cr2u; b2Assert(invMass > B2_FLT_EPSILON); m_mass = 1.0f / invMass; if (m_frequencyHz > 0.0f) { float32 C = length - m_length; // Frequency float32 omega = 2.0f * b2_pi * m_frequencyHz; // Damping coefficient float32 d = 2.0f * m_mass * m_dampingRatio * omega; // Spring stiffness float32 k = m_mass * omega * omega; // magic formulas m_gamma = 1.0f / (step.dt * (d + step.dt * k)); m_bias = C * step.dt * k * m_gamma; m_mass = 1.0f / (invMass + m_gamma); } if (step.warmStarting) { // Scale the impulse to support a variable time step. m_impulse *= step.dtRatio; b2Vec2 P = m_impulse * m_u; b1->m_linearVelocity -= b1->m_invMass * P; b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P); b2->m_linearVelocity += b2->m_invMass * P; b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P); } else { m_impulse = 0.0f; } } void b2DistanceJoint::SolveVelocityConstraints(const b2TimeStep& step) { B2_NOT_USED(step); b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); // Cdot = dot(u, v + cross(w, r)) b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1); b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2); float32 Cdot = b2Dot(m_u, v2 - v1); float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); m_impulse += impulse; b2Vec2 P = impulse * m_u; b1->m_linearVelocity -= b1->m_invMass * P; b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P); b2->m_linearVelocity += b2->m_invMass * P; b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P); } bool b2DistanceJoint::SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); if (m_frequencyHz > 0.0f) { // There is no position correction for soft distance constraints. return true; } b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; float32 length = d.Normalize(); float32 C = length - m_length; C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); float32 impulse = -m_mass * C; m_u = d; b2Vec2 P = impulse * m_u; b1->m_sweep.c -= b1->m_invMass * P; b1->m_sweep.a -= b1->m_invI * b2Cross(r1, P); b2->m_sweep.c += b2->m_invMass * P; b2->m_sweep.a += b2->m_invI * b2Cross(r2, P); b1->SynchronizeTransform(); b2->SynchronizeTransform(); return b2Abs(C) < b2_linearSlop; } b2Vec2 b2DistanceJoint::GetAnchor1() const { return m_body1->GetWorldPoint(m_localAnchor1); } b2Vec2 b2DistanceJoint::GetAnchor2() const { return m_body2->GetWorldPoint(m_localAnchor2); } b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 F = (inv_dt * m_impulse) * m_u; return F; } float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const { B2_NOT_USED(inv_dt); return 0.0f; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2GearJoint.h0000644000000000000000000000627611064106301022712 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_GEAR_JOINT_H #define B2_GEAR_JOINT_H #include "b2Joint.h" class b2RevoluteJoint; class b2PrismaticJoint; /// Gear joint definition. This definition requires two existing /// revolute or prismatic joints (any combination will work). /// The provided joints must attach a dynamic body to a static body. struct b2GearJointDef : public b2JointDef { b2GearJointDef() { type = e_gearJoint; joint1 = NULL; joint2 = NULL; ratio = 1.0f; } /// The first revolute/prismatic joint attached to the gear joint. b2Joint* joint1; /// The second revolute/prismatic joint attached to the gear joint. b2Joint* joint2; /// The gear ratio. /// @see b2GearJoint for explanation. float32 ratio; }; /// A gear joint is used to connect two joints together. Either joint /// can be a revolute or prismatic joint. You specify a gear ratio /// to bind the motions together: /// coordinate1 + ratio * coordinate2 = constant /// The ratio can be negative or positive. If one joint is a revolute joint /// and the other joint is a prismatic joint, then the ratio will have units /// of length or units of 1/length. /// @warning The revolute and prismatic joints must be attached to /// fixed bodies (which must be body1 on those joints). class b2GearJoint : public b2Joint { public: b2Vec2 GetAnchor1() const; b2Vec2 GetAnchor2() const; b2Vec2 GetReactionForce(float32 inv_dt) const; float32 GetReactionTorque(float32 inv_dt) const; /// Get the gear ratio. float32 GetRatio() const; //--------------- Internals Below ------------------- b2GearJoint(const b2GearJointDef* data); void InitVelocityConstraints(const b2TimeStep& step); void SolveVelocityConstraints(const b2TimeStep& step); bool SolvePositionConstraints(float32 baumgarte); b2Body* m_ground1; b2Body* m_ground2; // One of these is NULL. b2RevoluteJoint* m_revolute1; b2PrismaticJoint* m_prismatic1; // One of these is NULL. b2RevoluteJoint* m_revolute2; b2PrismaticJoint* m_prismatic2; b2Vec2 m_groundAnchor1; b2Vec2 m_groundAnchor2; b2Vec2 m_localAnchor1; b2Vec2 m_localAnchor2; b2Jacobian m_J; float32 m_constant; float32 m_ratio; // Effective mass float32 m_mass; // Impulse for accumulation/warm starting. float32 m_impulse; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2PulleyJoint.cpp0000644000000000000000000002630611064106301023635 0ustar rootroot/* * Copyright (c) 2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2PulleyJoint.h" #include "../b2Body.h" #include "../b2World.h" // Pulley: // length1 = norm(p1 - s1) // length2 = norm(p2 - s2) // C0 = (length1 + ratio * length2)_initial // C = C0 - (length1 + ratio * length2) >= 0 // u1 = (p1 - s1) / norm(p1 - s1) // u2 = (p2 - s2) / norm(p2 - s2) // Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) // J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] // K = J * invM * JT // = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) // // Limit: // C = maxLength - length // u = (p - s) / norm(p - s) // Cdot = -dot(u, v + cross(w, r)) // K = invMass + invI * cross(r, u)^2 // 0 <= impulse void b2PulleyJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& ga1, const b2Vec2& ga2, const b2Vec2& anchor1, const b2Vec2& anchor2, float32 r) { body1 = b1; body2 = b2; groundAnchor1 = ga1; groundAnchor2 = ga2; localAnchor1 = body1->GetLocalPoint(anchor1); localAnchor2 = body2->GetLocalPoint(anchor2); b2Vec2 d1 = anchor1 - ga1; length1 = d1.Length(); b2Vec2 d2 = anchor2 - ga2; length2 = d2.Length(); ratio = r; b2Assert(ratio > B2_FLT_EPSILON); float32 C = length1 + ratio * length2; maxLength1 = C - ratio * b2_minPulleyLength; maxLength2 = (C - b2_minPulleyLength) / ratio; } b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) : b2Joint(def) { m_ground = m_body1->GetWorld()->GetGroundBody(); m_groundAnchor1 = def->groundAnchor1 - m_ground->GetXForm().position; m_groundAnchor2 = def->groundAnchor2 - m_ground->GetXForm().position; m_localAnchor1 = def->localAnchor1; m_localAnchor2 = def->localAnchor2; b2Assert(def->ratio != 0.0f); m_ratio = def->ratio; m_constant = def->length1 + m_ratio * def->length2; m_maxLength1 = b2Min(def->maxLength1, m_constant - m_ratio * b2_minPulleyLength); m_maxLength2 = b2Min(def->maxLength2, (m_constant - b2_minPulleyLength) / m_ratio); m_impulse = 0.0f; m_limitImpulse1 = 0.0f; m_limitImpulse2 = 0.0f; } void b2PulleyJoint::InitVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); b2Vec2 p1 = b1->m_sweep.c + r1; b2Vec2 p2 = b2->m_sweep.c + r2; b2Vec2 s1 = m_ground->GetXForm().position + m_groundAnchor1; b2Vec2 s2 = m_ground->GetXForm().position + m_groundAnchor2; // Get the pulley axes. m_u1 = p1 - s1; m_u2 = p2 - s2; float32 length1 = m_u1.Length(); float32 length2 = m_u2.Length(); if (length1 > b2_linearSlop) { m_u1 *= 1.0f / length1; } else { m_u1.SetZero(); } if (length2 > b2_linearSlop) { m_u2 *= 1.0f / length2; } else { m_u2.SetZero(); } float32 C = m_constant - length1 - m_ratio * length2; if (C > 0.0f) { m_state = e_inactiveLimit; m_impulse = 0.0f; } else { m_state = e_atUpperLimit; } if (length1 < m_maxLength1) { m_limitState1 = e_inactiveLimit; m_limitImpulse1 = 0.0f; } else { m_limitState1 = e_atUpperLimit; } if (length2 < m_maxLength2) { m_limitState2 = e_inactiveLimit; m_limitImpulse2 = 0.0f; } else { m_limitState2 = e_atUpperLimit; } // Compute effective mass. float32 cr1u1 = b2Cross(r1, m_u1); float32 cr2u2 = b2Cross(r2, m_u2); m_limitMass1 = b1->m_invMass + b1->m_invI * cr1u1 * cr1u1; m_limitMass2 = b2->m_invMass + b2->m_invI * cr2u2 * cr2u2; m_pulleyMass = m_limitMass1 + m_ratio * m_ratio * m_limitMass2; b2Assert(m_limitMass1 > B2_FLT_EPSILON); b2Assert(m_limitMass2 > B2_FLT_EPSILON); b2Assert(m_pulleyMass > B2_FLT_EPSILON); m_limitMass1 = 1.0f / m_limitMass1; m_limitMass2 = 1.0f / m_limitMass2; m_pulleyMass = 1.0f / m_pulleyMass; if (step.warmStarting) { // Scale impulses to support variable time steps. m_impulse *= step.dtRatio; m_limitImpulse1 *= step.dtRatio; m_limitImpulse2 *= step.dtRatio; // Warm starting. b2Vec2 P1 = -(m_impulse + m_limitImpulse1) * m_u1; b2Vec2 P2 = (-m_ratio * m_impulse - m_limitImpulse2) * m_u2; b1->m_linearVelocity += b1->m_invMass * P1; b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1); b2->m_linearVelocity += b2->m_invMass * P2; b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2); } else { m_impulse = 0.0f; m_limitImpulse1 = 0.0f; m_limitImpulse2 = 0.0f; } } void b2PulleyJoint::SolveVelocityConstraints(const b2TimeStep& step) { B2_NOT_USED(step); b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); if (m_state == e_atUpperLimit) { b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1); b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2); float32 Cdot = -b2Dot(m_u1, v1) - m_ratio * b2Dot(m_u2, v2); float32 impulse = m_pulleyMass * (-Cdot); float32 oldImpulse = m_impulse; m_impulse = b2Max(0.0f, m_impulse + impulse); impulse = m_impulse - oldImpulse; b2Vec2 P1 = -impulse * m_u1; b2Vec2 P2 = -m_ratio * impulse * m_u2; b1->m_linearVelocity += b1->m_invMass * P1; b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1); b2->m_linearVelocity += b2->m_invMass * P2; b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2); } if (m_limitState1 == e_atUpperLimit) { b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1); float32 Cdot = -b2Dot(m_u1, v1); float32 impulse = -m_limitMass1 * Cdot; float32 oldImpulse = m_limitImpulse1; m_limitImpulse1 = b2Max(0.0f, m_limitImpulse1 + impulse); impulse = m_limitImpulse1 - oldImpulse; b2Vec2 P1 = -impulse * m_u1; b1->m_linearVelocity += b1->m_invMass * P1; b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1); } if (m_limitState2 == e_atUpperLimit) { b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2); float32 Cdot = -b2Dot(m_u2, v2); float32 impulse = -m_limitMass2 * Cdot; float32 oldImpulse = m_limitImpulse2; m_limitImpulse2 = b2Max(0.0f, m_limitImpulse2 + impulse); impulse = m_limitImpulse2 - oldImpulse; b2Vec2 P2 = -impulse * m_u2; b2->m_linearVelocity += b2->m_invMass * P2; b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2); } } bool b2PulleyJoint::SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 s1 = m_ground->GetXForm().position + m_groundAnchor1; b2Vec2 s2 = m_ground->GetXForm().position + m_groundAnchor2; float32 linearError = 0.0f; if (m_state == e_atUpperLimit) { b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); b2Vec2 p1 = b1->m_sweep.c + r1; b2Vec2 p2 = b2->m_sweep.c + r2; // Get the pulley axes. m_u1 = p1 - s1; m_u2 = p2 - s2; float32 length1 = m_u1.Length(); float32 length2 = m_u2.Length(); if (length1 > b2_linearSlop) { m_u1 *= 1.0f / length1; } else { m_u1.SetZero(); } if (length2 > b2_linearSlop) { m_u2 *= 1.0f / length2; } else { m_u2.SetZero(); } float32 C = m_constant - length1 - m_ratio * length2; linearError = b2Max(linearError, -C); C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); float32 impulse = -m_pulleyMass * C; b2Vec2 P1 = -impulse * m_u1; b2Vec2 P2 = -m_ratio * impulse * m_u2; b1->m_sweep.c += b1->m_invMass * P1; b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1); b2->m_sweep.c += b2->m_invMass * P2; b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2); b1->SynchronizeTransform(); b2->SynchronizeTransform(); } if (m_limitState1 == e_atUpperLimit) { b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 p1 = b1->m_sweep.c + r1; m_u1 = p1 - s1; float32 length1 = m_u1.Length(); if (length1 > b2_linearSlop) { m_u1 *= 1.0f / length1; } else { m_u1.SetZero(); } float32 C = m_maxLength1 - length1; linearError = b2Max(linearError, -C); C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); float32 impulse = -m_limitMass1 * C; b2Vec2 P1 = -impulse * m_u1; b1->m_sweep.c += b1->m_invMass * P1; b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1); b1->SynchronizeTransform(); } if (m_limitState2 == e_atUpperLimit) { b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); b2Vec2 p2 = b2->m_sweep.c + r2; m_u2 = p2 - s2; float32 length2 = m_u2.Length(); if (length2 > b2_linearSlop) { m_u2 *= 1.0f / length2; } else { m_u2.SetZero(); } float32 C = m_maxLength2 - length2; linearError = b2Max(linearError, -C); C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); float32 impulse = -m_limitMass2 * C; b2Vec2 P2 = -impulse * m_u2; b2->m_sweep.c += b2->m_invMass * P2; b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2); b2->SynchronizeTransform(); } return linearError < b2_linearSlop; } b2Vec2 b2PulleyJoint::GetAnchor1() const { return m_body1->GetWorldPoint(m_localAnchor1); } b2Vec2 b2PulleyJoint::GetAnchor2() const { return m_body2->GetWorldPoint(m_localAnchor2); } b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const { b2Vec2 P = m_impulse * m_u2; return inv_dt * P; } float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const { B2_NOT_USED(inv_dt); return 0.0f; } b2Vec2 b2PulleyJoint::GetGroundAnchor1() const { return m_ground->GetXForm().position + m_groundAnchor1; } b2Vec2 b2PulleyJoint::GetGroundAnchor2() const { return m_ground->GetXForm().position + m_groundAnchor2; } float32 b2PulleyJoint::GetLength1() const { b2Vec2 p = m_body1->GetWorldPoint(m_localAnchor1); b2Vec2 s = m_ground->GetXForm().position + m_groundAnchor1; b2Vec2 d = p - s; return d.Length(); } float32 b2PulleyJoint::GetLength2() const { b2Vec2 p = m_body2->GetWorldPoint(m_localAnchor2); b2Vec2 s = m_ground->GetXForm().position + m_groundAnchor2; b2Vec2 d = p - s; return d.Length(); } float32 b2PulleyJoint::GetRatio() const { return m_ratio; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2PrismaticJoint.cpp0000644000000000000000000003707211130023047024317 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2PrismaticJoint.h" #include "../b2Body.h" #include "../b2World.h" // Linear constraint (point-to-line) // d = p2 - p1 = x2 + r2 - x1 - r1 // C = dot(perp, d) // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) // = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] // // Angular constraint // C = a2 - a1 + a_initial // Cdot = w2 - w1 // J = [0 0 -1 0 0 1] // // K = J * invM * JT // // J = [-a -s1 a s2] // [0 -1 0 1] // a = perp // s1 = cross(d + r1, a) = cross(p2 - x1, a) // s2 = cross(r2, a) = cross(p2 - x2, a) // Motor/Limit linear constraint // C = dot(ax1, d) // Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] // Block Solver // We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even // when the mass has poor distribution (leading to large torques about the joint anchor points). // // The Jacobian has 3 rows: // J = [-uT -s1 uT s2] // linear // [0 -1 0 1] // angular // [-vT -a1 vT a2] // limit // // u = perp // v = axis // s1 = cross(d + r1, u), s2 = cross(r2, u) // a1 = cross(d + r1, v), a2 = cross(r2, v) // M * (v2 - v1) = JT * df // J * v2 = bias // // v2 = v1 + invM * JT * df // J * (v1 + invM * JT * df) = bias // K * df = bias - J * v1 = -Cdot // K = J * invM * JT // Cdot = J * v1 - bias // // Now solve for f2. // df = f2 - f1 // K * (f2 - f1) = -Cdot // f2 = invK * (-Cdot) + f1 // // Clamp accumulated limit impulse. // lower: f2(3) = max(f2(3), 0) // upper: f2(3) = min(f2(3), 0) // // Solve for correct f2(1:2) // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 // = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) // // Now compute impulse to be applied: // df = f2 - f1 void b2PrismaticJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis) { body1 = b1; body2 = b2; localAnchor1 = body1->GetLocalPoint(anchor); localAnchor2 = body2->GetLocalPoint(anchor); localAxis1 = body1->GetLocalVector(axis); referenceAngle = body2->GetAngle() - body1->GetAngle(); } b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) : b2Joint(def) { m_localAnchor1 = def->localAnchor1; m_localAnchor2 = def->localAnchor2; m_localXAxis1 = def->localAxis1; m_localYAxis1 = b2Cross(1.0f, m_localXAxis1); m_refAngle = def->referenceAngle; m_impulse.SetZero(); m_motorMass = 0.0; m_motorImpulse = 0.0f; m_lowerTranslation = def->lowerTranslation; m_upperTranslation = def->upperTranslation; m_maxMotorForce = B2FORCE_INV_SCALE(def->maxMotorForce); m_motorSpeed = def->motorSpeed; m_enableLimit = def->enableLimit; m_enableMotor = def->enableMotor; m_limitState = e_inactiveLimit; m_axis.SetZero(); m_perp.SetZero(); } void b2PrismaticJoint::InitVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; // You cannot create a prismatic joint between bodies that // both have fixed rotation. b2Assert(b1->m_invI > 0.0f || b2->m_invI > 0.0f); m_localCenter1 = b1->GetLocalCenter(); m_localCenter2 = b2->GetLocalCenter(); b2XForm xf1 = b1->GetXForm(); b2XForm xf2 = b2->GetXForm(); // Compute the effective masses. b2Vec2 r1 = b2Mul(xf1.R, m_localAnchor1 - m_localCenter1); b2Vec2 r2 = b2Mul(xf2.R, m_localAnchor2 - m_localCenter2); b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; m_invMass1 = b1->m_invMass; m_invI1 = b1->m_invI; m_invMass2 = b2->m_invMass; m_invI2 = b2->m_invI; // Compute motor Jacobian and effective mass. { m_axis = b2Mul(xf1.R, m_localXAxis1); m_a1 = b2Cross(d + r1, m_axis); m_a2 = b2Cross(r2, m_axis); m_motorMass = m_invMass1 + m_invMass2 + m_invI1 * m_a1 * m_a1 + m_invI2 * m_a2 * m_a2; b2Assert(m_motorMass > B2_FLT_EPSILON); m_motorMass = 1.0f / m_motorMass; } // Prismatic constraint. { m_perp = b2Mul(xf1.R, m_localYAxis1); m_s1 = b2Cross(d + r1, m_perp); m_s2 = b2Cross(r2, m_perp); float32 m1 = m_invMass1, m2 = m_invMass2; float32 i1 = m_invI1, i2 = m_invI2; float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; float32 k12 = i1 * m_s1 + i2 * m_s2; float32 k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2; float32 k22 = i1 + i2; float32 k23 = i1 * m_a1 + i2 * m_a2; float32 k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2; m_K.col1.Set(k11, k12, k13); m_K.col2.Set(k12, k22, k23); m_K.col3.Set(k13, k23, k33); } // Compute motor and limit terms. if (m_enableLimit) { float32 jointTranslation = b2Dot(m_axis, d); if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) { m_limitState = e_equalLimits; } else if (jointTranslation <= m_lowerTranslation) { if (m_limitState != e_atLowerLimit) { m_limitState = e_atLowerLimit; m_impulse.z = 0.0f; } } else if (jointTranslation >= m_upperTranslation) { if (m_limitState != e_atUpperLimit) { m_limitState = e_atUpperLimit; m_impulse.z = 0.0f; } } else { m_limitState = e_inactiveLimit; m_impulse.z = 0.0f; } } else { m_limitState = e_inactiveLimit; } if (m_enableMotor == false) { m_motorImpulse = 0.0f; } if (step.warmStarting) { // Account for variable time step. m_impulse *= step.dtRatio; m_motorImpulse *= step.dtRatio; b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; float32 L1 = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; float32 L2 = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; b1->m_linearVelocity -= m_invMass1 * P; b1->m_angularVelocity -= m_invI1 * L1; b2->m_linearVelocity += m_invMass2 * P; b2->m_angularVelocity += m_invI2 * L2; } else { m_impulse.SetZero(); m_motorImpulse = 0.0f; } } void b2PrismaticJoint::SolveVelocityConstraints(const b2TimeStep& step) { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 v1 = b1->m_linearVelocity; float32 w1 = b1->m_angularVelocity; b2Vec2 v2 = b2->m_linearVelocity; float32 w2 = b2->m_angularVelocity; // Solve linear motor constraint. if (m_enableMotor && m_limitState != e_equalLimits) { float32 Cdot = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1; float32 impulse = m_motorMass * (m_motorSpeed - Cdot); float32 oldImpulse = m_motorImpulse; float32 maxImpulse = step.dt * m_maxMotorForce; m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; b2Vec2 P = impulse * m_axis; float32 L1 = impulse * m_a1; float32 L2 = impulse * m_a2; v1 -= m_invMass1 * P; w1 -= m_invI1 * L1; v2 += m_invMass2 * P; w2 += m_invI2 * L2; } b2Vec2 Cdot1; Cdot1.x = b2Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1; Cdot1.y = w2 - w1; if (m_enableLimit && m_limitState != e_inactiveLimit) { // Solve prismatic and limit constraint in block form. float32 Cdot2; Cdot2 = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1; b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); b2Vec3 f1 = m_impulse; b2Vec3 df = m_K.Solve33(-Cdot); m_impulse += df; if (m_limitState == e_atLowerLimit) { m_impulse.z = b2Max(m_impulse.z, 0.0f); } else if (m_limitState == e_atUpperLimit) { m_impulse.z = b2Min(m_impulse.z, 0.0f); } // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.col3.x, m_K.col3.y); b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); m_impulse.x = f2r.x; m_impulse.y = f2r.y; df = m_impulse - f1; b2Vec2 P = df.x * m_perp + df.z * m_axis; float32 L1 = df.x * m_s1 + df.y + df.z * m_a1; float32 L2 = df.x * m_s2 + df.y + df.z * m_a2; v1 -= m_invMass1 * P; w1 -= m_invI1 * L1; v2 += m_invMass2 * P; w2 += m_invI2 * L2; } else { // Limit is inactive, just solve the prismatic constraint in block form. b2Vec2 df = m_K.Solve22(-Cdot1); m_impulse.x += df.x; m_impulse.y += df.y; b2Vec2 P = df.x * m_perp; float32 L1 = df.x * m_s1 + df.y; float32 L2 = df.x * m_s2 + df.y; v1 -= m_invMass1 * P; w1 -= m_invI1 * L1; v2 += m_invMass2 * P; w2 += m_invI2 * L2; } b1->m_linearVelocity = v1; b1->m_angularVelocity = w1; b2->m_linearVelocity = v2; b2->m_angularVelocity = w2; } bool b2PrismaticJoint::SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 c1 = b1->m_sweep.c; float32 a1 = b1->m_sweep.a; b2Vec2 c2 = b2->m_sweep.c; float32 a2 = b2->m_sweep.a; // Solve linear limit constraint. float32 linearError = 0.0f, angularError = 0.0f; bool active = false; float32 C2 = 0.0f; b2Mat22 R1(a1), R2(a2); b2Vec2 r1 = b2Mul(R1, m_localAnchor1 - m_localCenter1); b2Vec2 r2 = b2Mul(R2, m_localAnchor2 - m_localCenter2); b2Vec2 d = c2 + r2 - c1 - r1; if (m_enableLimit) { m_axis = b2Mul(R1, m_localXAxis1); m_a1 = b2Cross(d + r1, m_axis); m_a2 = b2Cross(r2, m_axis); float32 translation = b2Dot(m_axis, d); if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) { // Prevent large angular corrections C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); linearError = b2Abs(translation); active = true; } else if (translation <= m_lowerTranslation) { // Prevent large linear corrections and allow some slop. C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); linearError = m_lowerTranslation - translation; active = true; } else if (translation >= m_upperTranslation) { // Prevent large linear corrections and allow some slop. C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); linearError = translation - m_upperTranslation; active = true; } } m_perp = b2Mul(R1, m_localYAxis1); m_s1 = b2Cross(d + r1, m_perp); m_s2 = b2Cross(r2, m_perp); b2Vec3 impulse; b2Vec2 C1; C1.x = b2Dot(m_perp, d); C1.y = a2 - a1 - m_refAngle; linearError = b2Max(linearError, b2Abs(C1.x)); angularError = b2Abs(C1.y); if (active) { float32 m1 = m_invMass1, m2 = m_invMass2; float32 i1 = m_invI1, i2 = m_invI2; float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; float32 k12 = i1 * m_s1 + i2 * m_s2; float32 k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2; float32 k22 = i1 + i2; float32 k23 = i1 * m_a1 + i2 * m_a2; float32 k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2; m_K.col1.Set(k11, k12, k13); m_K.col2.Set(k12, k22, k23); m_K.col3.Set(k13, k23, k33); b2Vec3 C; C.x = C1.x; C.y = C1.y; C.z = C2; impulse = m_K.Solve33(-C); } else { float32 m1 = m_invMass1, m2 = m_invMass2; float32 i1 = m_invI1, i2 = m_invI2; float32 k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; float32 k12 = i1 * m_s1 + i2 * m_s2; float32 k22 = i1 + i2; m_K.col1.Set(k11, k12, 0.0f); m_K.col2.Set(k12, k22, 0.0f); b2Vec2 impulse1 = m_K.Solve22(-C1); impulse.x = impulse1.x; impulse.y = impulse1.y; impulse.z = 0.0f; } b2Vec2 P = impulse.x * m_perp + impulse.z * m_axis; float32 L1 = impulse.x * m_s1 + impulse.y + impulse.z * m_a1; float32 L2 = impulse.x * m_s2 + impulse.y + impulse.z * m_a2; c1 -= m_invMass1 * P; a1 -= m_invI1 * L1; c2 += m_invMass2 * P; a2 += m_invI2 * L2; // TODO_ERIN remove need for this. b1->m_sweep.c = c1; b1->m_sweep.a = a1; b2->m_sweep.c = c2; b2->m_sweep.a = a2; b1->SynchronizeTransform(); b2->SynchronizeTransform(); return linearError <= b2_linearSlop && angularError <= b2_angularSlop; } b2Vec2 b2PrismaticJoint::GetAnchor1() const { return m_body1->GetWorldPoint(m_localAnchor1); } b2Vec2 b2PrismaticJoint::GetAnchor2() const { return m_body2->GetWorldPoint(m_localAnchor2); } b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const { return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); } float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const { return inv_dt * m_impulse.y; } float32 b2PrismaticJoint::GetJointTranslation() const { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1); b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2); b2Vec2 d = p2 - p1; b2Vec2 axis = b1->GetWorldVector(m_localXAxis1); float32 translation = b2Dot(d, axis); return translation; } float32 b2PrismaticJoint::GetJointSpeed() const { b2Body* b1 = m_body1; b2Body* b2 = m_body2; b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); b2Vec2 p1 = b1->m_sweep.c + r1; b2Vec2 p2 = b2->m_sweep.c + r2; b2Vec2 d = p2 - p1; b2Vec2 axis = b1->GetWorldVector(m_localXAxis1); b2Vec2 v1 = b1->m_linearVelocity; b2Vec2 v2 = b2->m_linearVelocity; float32 w1 = b1->m_angularVelocity; float32 w2 = b2->m_angularVelocity; float32 speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1)); return speed; } bool b2PrismaticJoint::IsLimitEnabled() const { return m_enableLimit; } void b2PrismaticJoint::EnableLimit(bool flag) { m_body1->WakeUp(); m_body2->WakeUp(); m_enableLimit = flag; } float32 b2PrismaticJoint::GetLowerLimit() const { return m_lowerTranslation; } float32 b2PrismaticJoint::GetUpperLimit() const { return m_upperTranslation; } void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) { b2Assert(lower <= upper); m_body1->WakeUp(); m_body2->WakeUp(); m_lowerTranslation = lower; m_upperTranslation = upper; } bool b2PrismaticJoint::IsMotorEnabled() const { return m_enableMotor; } void b2PrismaticJoint::EnableMotor(bool flag) { m_body1->WakeUp(); m_body2->WakeUp(); m_enableMotor = flag; } void b2PrismaticJoint::SetMotorSpeed(float32 speed) { m_body1->WakeUp(); m_body2->WakeUp(); m_motorSpeed = speed; } void b2PrismaticJoint::SetMaxMotorForce(float32 force) { m_body1->WakeUp(); m_body2->WakeUp(); m_maxMotorForce = B2FORCE_SCALE(float32(1.0))*force; } float32 b2PrismaticJoint::GetMotorForce() const { return m_motorImpulse; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/Joints/b2GearJoint.cpp0000644000000000000000000001560311064106301023237 0ustar rootroot/* * Copyright (c) 2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2GearJoint.h" #include "b2RevoluteJoint.h" #include "b2PrismaticJoint.h" #include "../b2Body.h" #include "../b2World.h" // Gear Joint: // C0 = (coordinate1 + ratio * coordinate2)_initial // C = C0 - (cordinate1 + ratio * coordinate2) = 0 // Cdot = -(Cdot1 + ratio * Cdot2) // J = -[J1 ratio * J2] // K = J * invM * JT // = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T // // Revolute: // coordinate = rotation // Cdot = angularVelocity // J = [0 0 1] // K = J * invM * JT = invI // // Prismatic: // coordinate = dot(p - pg, ug) // Cdot = dot(v + cross(w, r), ug) // J = [ug cross(r, ug)] // K = J * invM * JT = invMass + invI * cross(r, ug)^2 b2GearJoint::b2GearJoint(const b2GearJointDef* def) : b2Joint(def) { b2JointType type1 = def->joint1->GetType(); b2JointType type2 = def->joint2->GetType(); b2Assert(type1 == e_revoluteJoint || type1 == e_prismaticJoint); b2Assert(type2 == e_revoluteJoint || type2 == e_prismaticJoint); b2Assert(def->joint1->GetBody1()->IsStatic()); b2Assert(def->joint2->GetBody1()->IsStatic()); m_revolute1 = NULL; m_prismatic1 = NULL; m_revolute2 = NULL; m_prismatic2 = NULL; float32 coordinate1, coordinate2; m_ground1 = def->joint1->GetBody1(); m_body1 = def->joint1->GetBody2(); if (type1 == e_revoluteJoint) { m_revolute1 = (b2RevoluteJoint*)def->joint1; m_groundAnchor1 = m_revolute1->m_localAnchor1; m_localAnchor1 = m_revolute1->m_localAnchor2; coordinate1 = m_revolute1->GetJointAngle(); } else { m_prismatic1 = (b2PrismaticJoint*)def->joint1; m_groundAnchor1 = m_prismatic1->m_localAnchor1; m_localAnchor1 = m_prismatic1->m_localAnchor2; coordinate1 = m_prismatic1->GetJointTranslation(); } m_ground2 = def->joint2->GetBody1(); m_body2 = def->joint2->GetBody2(); if (type2 == e_revoluteJoint) { m_revolute2 = (b2RevoluteJoint*)def->joint2; m_groundAnchor2 = m_revolute2->m_localAnchor1; m_localAnchor2 = m_revolute2->m_localAnchor2; coordinate2 = m_revolute2->GetJointAngle(); } else { m_prismatic2 = (b2PrismaticJoint*)def->joint2; m_groundAnchor2 = m_prismatic2->m_localAnchor1; m_localAnchor2 = m_prismatic2->m_localAnchor2; coordinate2 = m_prismatic2->GetJointTranslation(); } m_ratio = def->ratio; m_constant = coordinate1 + m_ratio * coordinate2; m_impulse = 0.0f; } void b2GearJoint::InitVelocityConstraints(const b2TimeStep& step) { b2Body* g1 = m_ground1; b2Body* g2 = m_ground2; b2Body* b1 = m_body1; b2Body* b2 = m_body2; float32 K = 0.0f; m_J.SetZero(); if (m_revolute1) { m_J.angular1 = -1.0f; K += b1->m_invI; } else { b2Vec2 ug = b2Mul(g1->GetXForm().R, m_prismatic1->m_localXAxis1); b2Vec2 r = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter()); float32 crug = b2Cross(r, ug); m_J.linear1 = -ug; m_J.angular1 = -crug; K += b1->m_invMass + b1->m_invI * crug * crug; } if (m_revolute2) { m_J.angular2 = -m_ratio; K += m_ratio * m_ratio * b2->m_invI; } else { b2Vec2 ug = b2Mul(g2->GetXForm().R, m_prismatic2->m_localXAxis1); b2Vec2 r = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter()); float32 crug = b2Cross(r, ug); m_J.linear2 = -m_ratio * ug; m_J.angular2 = -m_ratio * crug; K += m_ratio * m_ratio * (b2->m_invMass + b2->m_invI * crug * crug); } // Compute effective mass. b2Assert(K > 0.0f); m_mass = 1.0f / K; if (step.warmStarting) { // Warm starting. b1->m_linearVelocity += b1->m_invMass * m_impulse * m_J.linear1; b1->m_angularVelocity += b1->m_invI * m_impulse * m_J.angular1; b2->m_linearVelocity += b2->m_invMass * m_impulse * m_J.linear2; b2->m_angularVelocity += b2->m_invI * m_impulse * m_J.angular2; } else { m_impulse = 0.0f; } } void b2GearJoint::SolveVelocityConstraints(const b2TimeStep& step) { B2_NOT_USED(step); b2Body* b1 = m_body1; b2Body* b2 = m_body2; float32 Cdot = m_J.Compute( b1->m_linearVelocity, b1->m_angularVelocity, b2->m_linearVelocity, b2->m_angularVelocity); float32 impulse = m_mass * (-Cdot); m_impulse += impulse; b1->m_linearVelocity += b1->m_invMass * impulse * m_J.linear1; b1->m_angularVelocity += b1->m_invI * impulse * m_J.angular1; b2->m_linearVelocity += b2->m_invMass * impulse * m_J.linear2; b2->m_angularVelocity += b2->m_invI * impulse * m_J.angular2; } bool b2GearJoint::SolvePositionConstraints(float32 baumgarte) { B2_NOT_USED(baumgarte); float32 linearError = 0.0f; b2Body* b1 = m_body1; b2Body* b2 = m_body2; float32 coordinate1, coordinate2; if (m_revolute1) { coordinate1 = m_revolute1->GetJointAngle(); } else { coordinate1 = m_prismatic1->GetJointTranslation(); } if (m_revolute2) { coordinate2 = m_revolute2->GetJointAngle(); } else { coordinate2 = m_prismatic2->GetJointTranslation(); } float32 C = m_constant - (coordinate1 + m_ratio * coordinate2); float32 impulse = m_mass * (-C); b1->m_sweep.c += b1->m_invMass * impulse * m_J.linear1; b1->m_sweep.a += b1->m_invI * impulse * m_J.angular1; b2->m_sweep.c += b2->m_invMass * impulse * m_J.linear2; b2->m_sweep.a += b2->m_invI * impulse * m_J.angular2; b1->SynchronizeTransform(); b2->SynchronizeTransform(); // TODO_ERIN not implemented return linearError < b2_linearSlop; } b2Vec2 b2GearJoint::GetAnchor1() const { return m_body1->GetWorldPoint(m_localAnchor1); } b2Vec2 b2GearJoint::GetAnchor2() const { return m_body2->GetWorldPoint(m_localAnchor2); } b2Vec2 b2GearJoint::GetReactionForce(float32 inv_dt) const { // TODO_ERIN not tested b2Vec2 P = m_impulse * m_J.linear2; return inv_dt * P; } float32 b2GearJoint::GetReactionTorque(float32 inv_dt) const { // TODO_ERIN not tested b2Vec2 r = b2Mul(m_body2->GetXForm().R, m_localAnchor2 - m_body2->GetLocalCenter()); b2Vec2 P = m_impulse * m_J.linear2; float32 L = m_impulse * m_J.angular2 - b2Cross(r, P); return inv_dt * L; } float32 b2GearJoint::GetRatio() const { return m_ratio; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2ContactManager.h0000644000000000000000000000331111064106301022433 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_CONTACT_MANAGER_H #define B2_CONTACT_MANAGER_H #include "../Collision/b2BroadPhase.h" #include "../Dynamics/Contacts/b2NullContact.h" class b2World; class b2Contact; struct b2TimeStep; // Delegate of b2World. class b2ContactManager : public b2PairCallback { public: b2ContactManager() : m_world(NULL), m_destroyImmediate(false) {} // Implements PairCallback void* PairAdded(void* proxyUserData1, void* proxyUserData2); // Implements PairCallback void PairRemoved(void* proxyUserData1, void* proxyUserData2, void* pairUserData); void Destroy(b2Contact* c); void Collide(); b2World* m_world; // This lets us provide broadphase proxy pair user data for // contacts that shouldn't exist. b2NullContact m_nullContact; bool m_destroyImmediate; }; #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2World.cpp0000644000000000000000000007544711130023047021211 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2World.h" #include "b2Body.h" #include "b2Island.h" #include "Joints/b2PulleyJoint.h" #include "Contacts/b2Contact.h" #include "Contacts/b2ContactSolver.h" #include "../Collision/b2Collision.h" #include "../Collision/Shapes/b2CircleShape.h" #include "../Collision/Shapes/b2PolygonShape.h" #include "../Collision/Shapes/b2EdgeShape.h" #include b2World::b2World(const b2AABB& worldAABB, const b2Vec2& gravity, bool doSleep) { m_destructionListener = NULL; m_boundaryListener = NULL; m_contactFilter = &b2_defaultFilter; m_contactListener = NULL; m_debugDraw = NULL; m_bodyList = NULL; m_contactList = NULL; m_jointList = NULL; m_controllerList = NULL; m_bodyCount = 0; m_contactCount = 0; m_jointCount = 0; m_controllerCount = 0; m_warmStarting = true; m_continuousPhysics = true; m_allowSleep = doSleep; m_gravity = gravity; m_lock = false; m_inv_dt0 = 0.0f; m_contactManager.m_world = this; void* mem = b2Alloc(sizeof(b2BroadPhase)); m_broadPhase = new (mem) b2BroadPhase(worldAABB, &m_contactManager); b2BodyDef bd; m_groundBody = CreateBody(&bd); } b2World::~b2World() { DestroyBody(m_groundBody); m_broadPhase->~b2BroadPhase(); b2Free(m_broadPhase); } void b2World::SetDestructionListener(b2DestructionListener* listener) { m_destructionListener = listener; } void b2World::SetBoundaryListener(b2BoundaryListener* listener) { m_boundaryListener = listener; } void b2World::SetContactFilter(b2ContactFilter* filter) { m_contactFilter = filter; } void b2World::SetContactListener(b2ContactListener* listener) { m_contactListener = listener; } void b2World::SetDebugDraw(b2DebugDraw* debugDraw) { m_debugDraw = debugDraw; } b2Body* b2World::CreateBody(const b2BodyDef* def) { b2Assert(m_lock == false); if (m_lock == true) { return NULL; } void* mem = m_blockAllocator.Allocate(sizeof(b2Body)); b2Body* b = new (mem) b2Body(def, this); // Add to world doubly linked list. b->m_prev = NULL; b->m_next = m_bodyList; if (m_bodyList) { m_bodyList->m_prev = b; } m_bodyList = b; ++m_bodyCount; return b; } void b2World::DestroyBody(b2Body* b) { b2Assert(m_bodyCount > 0); b2Assert(m_lock == false); if (m_lock == true) { return; } // Delete the attached joints. b2JointEdge* jn = b->m_jointList; while (jn) { b2JointEdge* jn0 = jn; jn = jn->next; if (m_destructionListener) { m_destructionListener->SayGoodbye(jn0->joint); } DestroyJoint(jn0->joint); } //Detach controllers attached to this body b2ControllerEdge* ce = b->m_controllerList; while(ce) { b2ControllerEdge* ce0 = ce; ce = ce->nextController; ce0->controller->RemoveBody(b); } // Delete the attached shapes. This destroys broad-phase // proxies and pairs, leading to the destruction of contacts. b2Shape* s = b->m_shapeList; while (s) { b2Shape* s0 = s; s = s->m_next; if (m_destructionListener) { m_destructionListener->SayGoodbye(s0); } s0->DestroyProxy(m_broadPhase); b2Shape::Destroy(s0, &m_blockAllocator); } // Remove world body list. if (b->m_prev) { b->m_prev->m_next = b->m_next; } if (b->m_next) { b->m_next->m_prev = b->m_prev; } if (b == m_bodyList) { m_bodyList = b->m_next; } --m_bodyCount; b->~b2Body(); m_blockAllocator.Free(b, sizeof(b2Body)); } b2Joint* b2World::CreateJoint(const b2JointDef* def) { b2Assert(m_lock == false); b2Joint* j = b2Joint::Create(def, &m_blockAllocator); // Connect to the world list. j->m_prev = NULL; j->m_next = m_jointList; if (m_jointList) { m_jointList->m_prev = j; } m_jointList = j; ++m_jointCount; // Connect to the bodies' doubly linked lists. j->m_node1.joint = j; j->m_node1.other = j->m_body2; j->m_node1.prev = NULL; j->m_node1.next = j->m_body1->m_jointList; if (j->m_body1->m_jointList) j->m_body1->m_jointList->prev = &j->m_node1; j->m_body1->m_jointList = &j->m_node1; j->m_node2.joint = j; j->m_node2.other = j->m_body1; j->m_node2.prev = NULL; j->m_node2.next = j->m_body2->m_jointList; if (j->m_body2->m_jointList) j->m_body2->m_jointList->prev = &j->m_node2; j->m_body2->m_jointList = &j->m_node2; // If the joint prevents collisions, then reset collision filtering. if (def->collideConnected == false) { // Reset the proxies on the body with the minimum number of shapes. b2Body* b = def->body1->m_shapeCount < def->body2->m_shapeCount ? def->body1 : def->body2; for (b2Shape* s = b->m_shapeList; s; s = s->m_next) { s->RefilterProxy(m_broadPhase, b->GetXForm()); } } return j; } void b2World::DestroyJoint(b2Joint* j) { b2Assert(m_lock == false); bool collideConnected = j->m_collideConnected; // Remove from the doubly linked list. if (j->m_prev) { j->m_prev->m_next = j->m_next; } if (j->m_next) { j->m_next->m_prev = j->m_prev; } if (j == m_jointList) { m_jointList = j->m_next; } // Disconnect from island graph. b2Body* body1 = j->m_body1; b2Body* body2 = j->m_body2; // Wake up connected bodies. body1->WakeUp(); body2->WakeUp(); // Remove from body 1. if (j->m_node1.prev) { j->m_node1.prev->next = j->m_node1.next; } if (j->m_node1.next) { j->m_node1.next->prev = j->m_node1.prev; } if (&j->m_node1 == body1->m_jointList) { body1->m_jointList = j->m_node1.next; } j->m_node1.prev = NULL; j->m_node1.next = NULL; // Remove from body 2 if (j->m_node2.prev) { j->m_node2.prev->next = j->m_node2.next; } if (j->m_node2.next) { j->m_node2.next->prev = j->m_node2.prev; } if (&j->m_node2 == body2->m_jointList) { body2->m_jointList = j->m_node2.next; } j->m_node2.prev = NULL; j->m_node2.next = NULL; b2Joint::Destroy(j, &m_blockAllocator); b2Assert(m_jointCount > 0); --m_jointCount; // If the joint prevents collisions, then reset collision filtering. if (collideConnected == false) { // Reset the proxies on the body with the minimum number of shapes. b2Body* b = body1->m_shapeCount < body2->m_shapeCount ? body1 : body2; for (b2Shape* s = b->m_shapeList; s; s = s->m_next) { s->RefilterProxy(m_broadPhase, b->GetXForm()); } } } b2Controller* b2World::CreateController(b2ControllerDef* def) { b2Controller* controller = def->Create(&m_blockAllocator); controller->m_next = m_controllerList; controller->m_prev = NULL; if(m_controllerList) m_controllerList->m_prev = controller; m_controllerList = controller; ++m_controllerCount; controller->m_world = this; return controller; } void b2World::DestroyController(b2Controller* controller) { b2Assert(m_controllerCount>0); if(controller->m_next) controller->m_next->m_prev = controller->m_prev; if(controller->m_prev) controller->m_prev->m_next = controller->m_next; if(controller == m_controllerList) m_controllerList = controller->m_next; --m_controllerCount; b2Controller::Destroy(controller, &m_blockAllocator); } void b2World::Refilter(b2Shape* shape) { b2Assert(m_lock == false); shape->RefilterProxy(m_broadPhase, shape->GetBody()->GetXForm()); } // Find islands, integrate and solve constraints, solve position constraints void b2World::Solve(const b2TimeStep& step) { // Step all controlls for(b2Controller* controller = m_controllerList;controller;controller=controller->m_next) { controller->Step(step); } // Size the island for the worst case. b2Island island(m_bodyCount, m_contactCount, m_jointCount, &m_stackAllocator, m_contactListener); // Clear all the island flags. for (b2Body* b = m_bodyList; b; b = b->m_next) { b->m_flags &= ~b2Body::e_islandFlag; } for (b2Contact* c = m_contactList; c; c = c->m_next) { c->m_flags &= ~b2Contact::e_islandFlag; } for (b2Joint* j = m_jointList; j; j = j->m_next) { j->m_islandFlag = false; } // Build and simulate all awake islands. int32 stackSize = m_bodyCount; b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*)); for (b2Body* seed = m_bodyList; seed; seed = seed->m_next) { if (seed->m_flags & (b2Body::e_islandFlag | b2Body::e_sleepFlag | b2Body::e_frozenFlag)) { continue; } if (seed->IsStatic()) { continue; } // Reset island and stack. island.Clear(); int32 stackCount = 0; stack[stackCount++] = seed; seed->m_flags |= b2Body::e_islandFlag; // Perform a depth first search (DFS) on the constraint graph. while (stackCount > 0) { // Grab the next body off the stack and add it to the island. b2Body* b = stack[--stackCount]; island.Add(b); // Make sure the body is awake. b->m_flags &= ~b2Body::e_sleepFlag; // To keep islands as small as possible, we don't // propagate islands across static bodies. if (b->IsStatic()) { continue; } // Search all contacts connected to this body. for (b2ContactEdge* cn = b->m_contactList; cn; cn = cn->next) { // Has this contact already been added to an island? if (cn->contact->m_flags & (b2Contact::e_islandFlag | b2Contact::e_nonSolidFlag)) { continue; } // Is this contact touching? if (cn->contact->GetManifoldCount() == 0) { continue; } island.Add(cn->contact); cn->contact->m_flags |= b2Contact::e_islandFlag; b2Body* other = cn->other; // Was the other body already added to this island? if (other->m_flags & b2Body::e_islandFlag) { continue; } b2Assert(stackCount < stackSize); stack[stackCount++] = other; other->m_flags |= b2Body::e_islandFlag; } // Search all joints connect to this body. for (b2JointEdge* jn = b->m_jointList; jn; jn = jn->next) { if (jn->joint->m_islandFlag == true) { continue; } island.Add(jn->joint); jn->joint->m_islandFlag = true; b2Body* other = jn->other; if (other->m_flags & b2Body::e_islandFlag) { continue; } b2Assert(stackCount < stackSize); stack[stackCount++] = other; other->m_flags |= b2Body::e_islandFlag; } } island.Solve(step, m_gravity, m_allowSleep); // Post solve cleanup. for (int32 i = 0; i < island.m_bodyCount; ++i) { // Allow static bodies to participate in other islands. b2Body* b = island.m_bodies[i]; if (b->IsStatic()) { b->m_flags &= ~b2Body::e_islandFlag; } } } m_stackAllocator.Free(stack); // Synchronize shapes, check for out of range bodies. for (b2Body* b = m_bodyList; b; b = b->GetNext()) { if (b->m_flags & (b2Body::e_sleepFlag | b2Body::e_frozenFlag)) { continue; } if (b->IsStatic()) { continue; } // Update shapes (for broad-phase). If the shapes go out of // the world AABB then shapes and contacts may be destroyed, // including contacts that are bool inRange = b->SynchronizeShapes(); // Did the body's shapes leave the world? if (inRange == false && m_boundaryListener != NULL) { m_boundaryListener->Violation(b); } } // Commit shape proxy movements to the broad-phase so that new contacts are created. // Also, some contacts can be destroyed. m_broadPhase->Commit(); } // Find TOI contacts and solve them. void b2World::SolveTOI(const b2TimeStep& step) { // Reserve an island and a queue for TOI island solution. b2Island island(m_bodyCount, b2_maxTOIContactsPerIsland, b2_maxTOIJointsPerIsland, &m_stackAllocator, m_contactListener); //Simple one pass queue //Relies on the fact that we're only making one pass //through and each body can only be pushed/popped once. //To push: // queue[queueStart+queueSize++] = newElement; //To pop: // poppedElement = queue[queueStart++]; // --queueSize; int32 queueCapacity = m_bodyCount; b2Body** queue = (b2Body**)m_stackAllocator.Allocate(queueCapacity* sizeof(b2Body*)); for (b2Body* b = m_bodyList; b; b = b->m_next) { b->m_flags &= ~b2Body::e_islandFlag; b->m_sweep.t0 = 0.0f; } for (b2Contact* c = m_contactList; c; c = c->m_next) { // Invalidate TOI c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); } for (b2Joint* j = m_jointList; j; j = j->m_next) { j->m_islandFlag = false; } // Find TOI events and solve them. for (;;) { // Find the first TOI. b2Contact* minContact = NULL; float32 minTOI = 1.0f; for (b2Contact* c = m_contactList; c; c = c->m_next) { if (c->m_flags & (b2Contact::e_slowFlag | b2Contact::e_nonSolidFlag)) { continue; } // TODO_ERIN keep a counter on the contact, only respond to M TOIs per contact. float32 toi = 1.0f; if (c->m_flags & b2Contact::e_toiFlag) { // This contact has a valid cached TOI. toi = c->m_toi; } else { // Compute the TOI for this contact. b2Shape* s1 = c->GetShape1(); b2Shape* s2 = c->GetShape2(); b2Body* b1 = s1->GetBody(); b2Body* b2 = s2->GetBody(); if ((b1->IsStatic() || b1->IsSleeping()) && (b2->IsStatic() || b2->IsSleeping())) { continue; } // Put the sweeps onto the same time interval. float32 t0 = b1->m_sweep.t0; if (b1->m_sweep.t0 < b2->m_sweep.t0) { t0 = b2->m_sweep.t0; b1->m_sweep.Advance(t0); } else if (b2->m_sweep.t0 < b1->m_sweep.t0) { t0 = b1->m_sweep.t0; b2->m_sweep.Advance(t0); } b2Assert(t0 < 1.0f); // Compute the time of impact. toi = b2TimeOfImpact(c->m_shape1, b1->m_sweep, c->m_shape2, b2->m_sweep); b2Assert(0.0f <= toi && toi <= 1.0f); // If the TOI is in range ... if (0.0f < toi && toi < 1.0f) { // Interpolate on the actual range. toi = b2Min((1.0f - toi) * t0 + toi, 1.0f); } c->m_toi = toi; c->m_flags |= b2Contact::e_toiFlag; } if (B2_FLT_EPSILON < toi && toi < minTOI) { // This is the minimum TOI found so far. minContact = c; minTOI = toi; } } if (minContact == NULL || 1.0f - 100.0f * B2_FLT_EPSILON < minTOI) { // No more TOI events. Done! break; } // Advance the bodies to the TOI. b2Shape* s1 = minContact->GetShape1(); b2Shape* s2 = minContact->GetShape2(); b2Body* b1 = s1->GetBody(); b2Body* b2 = s2->GetBody(); b1->Advance(minTOI); b2->Advance(minTOI); // The TOI contact likely has some new contact points. minContact->Update(m_contactListener); minContact->m_flags &= ~b2Contact::e_toiFlag; if (minContact->GetManifoldCount() == 0) { // This shouldn't happen. Numerical error? //b2Assert(false); continue; } // Build the TOI island. We need a dynamic seed. b2Body* seed = b1; if (seed->IsStatic()) { seed = b2; } // Reset island and queue. island.Clear(); int32 queueStart = 0; // starting index for queue int32 queueSize = 0; // elements in queue queue[queueStart + queueSize++] = seed; seed->m_flags |= b2Body::e_islandFlag; // Perform a breadth first search (BFS) on the contact/joint graph. while (queueSize > 0) { // Grab the next body off the stack and add it to the island. b2Body* b = queue[queueStart++]; --queueSize; island.Add(b); // Make sure the body is awake. b->m_flags &= ~b2Body::e_sleepFlag; // To keep islands as small as possible, we don't // propagate islands across static bodies. if (b->IsStatic()) { continue; } // Search all contacts connected to this body. for (b2ContactEdge* cEdge = b->m_contactList; cEdge; cEdge = cEdge->next) { // Does the TOI island still have space for contacts? if (island.m_contactCount == island.m_contactCapacity) { continue; } // Has this contact already been added to an island? Skip slow or non-solid contacts. if (cEdge->contact->m_flags & (b2Contact::e_islandFlag | b2Contact::e_slowFlag | b2Contact::e_nonSolidFlag)) { continue; } // Is this contact touching? For performance we are not updating this contact. if (cEdge->contact->GetManifoldCount() == 0) { continue; } island.Add(cEdge->contact); cEdge->contact->m_flags |= b2Contact::e_islandFlag; // Update other body. b2Body* other = cEdge->other; // Was the other body already added to this island? if (other->m_flags & b2Body::e_islandFlag) { continue; } // March forward, this can do no harm since this is the min TOI. if (other->IsStatic() == false) { other->Advance(minTOI); other->WakeUp(); } b2Assert(queueStart + queueSize < queueCapacity); queue[queueStart + queueSize] = other; ++queueSize; other->m_flags |= b2Body::e_islandFlag; } for (b2JointEdge* jEdge = b->m_jointList; jEdge; jEdge = jEdge->next) { if (island.m_jointCount == island.m_jointCapacity) { continue; } if (jEdge->joint->m_islandFlag == true) { continue; } island.Add(jEdge->joint); jEdge->joint->m_islandFlag = true; b2Body* other = jEdge->other; if (other->m_flags & b2Body::e_islandFlag) { continue; } if (!other->IsStatic()) { other->Advance(minTOI); other->WakeUp(); } b2Assert(queueStart + queueSize < queueCapacity); queue[queueStart + queueSize] = other; ++queueSize; other->m_flags |= b2Body::e_islandFlag; } } b2TimeStep subStep; subStep.warmStarting = false; subStep.dt = (1.0f - minTOI) * step.dt; subStep.inv_dt = 1.0f / subStep.dt; subStep.dtRatio = 0.0f; subStep.velocityIterations = step.velocityIterations; subStep.positionIterations = step.positionIterations; island.SolveTOI(subStep); // Post solve cleanup. for (int32 i = 0; i < island.m_bodyCount; ++i) { // Allow bodies to participate in future TOI islands. b2Body* b = island.m_bodies[i]; b->m_flags &= ~b2Body::e_islandFlag; if (b->m_flags & (b2Body::e_sleepFlag | b2Body::e_frozenFlag)) { continue; } if (b->IsStatic()) { continue; } // Update shapes (for broad-phase). If the shapes go out of // the world AABB then shapes and contacts may be destroyed, // including contacts that are bool inRange = b->SynchronizeShapes(); // Did the body's shapes leave the world? if (inRange == false && m_boundaryListener != NULL) { m_boundaryListener->Violation(b); } // Invalidate all contact TOIs associated with this body. Some of these // may not be in the island because they were not touching. for (b2ContactEdge* cn = b->m_contactList; cn; cn = cn->next) { cn->contact->m_flags &= ~b2Contact::e_toiFlag; } } for (int32 i = 0; i < island.m_contactCount; ++i) { // Allow contacts to participate in future TOI islands. b2Contact* c = island.m_contacts[i]; c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag); } for (int32 i = 0; i < island.m_jointCount; ++i) { // Allow joints to participate in future TOI islands. b2Joint* j = island.m_joints[i]; j->m_islandFlag = false; } // Commit shape proxy movements to the broad-phase so that new contacts are created. // Also, some contacts can be destroyed. m_broadPhase->Commit(); } m_stackAllocator.Free(queue); } void b2World::Step(float32 dt, int32 velocityIterations, int32 positionIterations) { m_lock = true; b2TimeStep step; step.dt = dt; step.velocityIterations = velocityIterations; step.positionIterations = positionIterations; if (dt > 0.0f) { step.inv_dt = 1.0f / dt; } else { step.inv_dt = 0.0f; } step.dtRatio = m_inv_dt0 * dt; step.warmStarting = m_warmStarting; // Update contacts. m_contactManager.Collide(); // Integrate velocities, solve velocity constraints, and integrate positions. if (step.dt > 0.0f) { Solve(step); } // Handle TOI events. if (m_continuousPhysics && step.dt > 0.0f) { SolveTOI(step); } // Draw debug information. DrawDebugData(); m_inv_dt0 = step.inv_dt; m_lock = false; } int32 b2World::Query(const b2AABB& aabb, b2Shape** shapes, int32 maxCount) { void** results = (void**)m_stackAllocator.Allocate(maxCount * sizeof(void*)); int32 count = m_broadPhase->Query(aabb, results, maxCount); for (int32 i = 0; i < count; ++i) { shapes[i] = (b2Shape*)results[i]; } m_stackAllocator.Free(results); return count; } int32 b2World::Raycast(const b2Segment& segment, b2Shape** shapes, int32 maxCount, bool solidShapes, void* userData) { m_raycastSegment = &segment; m_raycastUserData = userData; m_raycastSolidShape = solidShapes; void** results = (void**)m_stackAllocator.Allocate(maxCount * sizeof(void*)); int32 count = m_broadPhase->QuerySegment(segment,results,maxCount, &RaycastSortKey); for (int32 i = 0; i < count; ++i) { shapes[i] = (b2Shape*)results[i]; } m_stackAllocator.Free(results); return count; } b2Shape* b2World::RaycastOne(const b2Segment& segment, float32* lambda, b2Vec2* normal, bool solidShapes, void* userData) { int32 maxCount = 1; b2Shape* shape; int32 count = Raycast(segment, &shape, maxCount, solidShapes, userData); if(count==0) return NULL; b2Assert(count==1); //Redundantly do TestSegment a second time, as the previous one's results are inaccessible const b2XForm xf = shape->GetBody()->GetXForm(); shape->TestSegment(xf, lambda, normal,segment,1); //We already know it returns true return shape; } void b2World::DrawShape(b2Shape* shape, const b2XForm& xf, const b2Color& color, bool core) { b2Color coreColor(0.9f, 0.6f, 0.6f); switch (shape->GetType()) { case e_circleShape: { b2CircleShape* circle = (b2CircleShape*)shape; b2Vec2 center = b2Mul(xf, circle->GetLocalPosition()); float32 radius = circle->GetRadius(); b2Vec2 axis = xf.R.col1; m_debugDraw->DrawSolidCircle(center, radius, axis, color); if (core) { m_debugDraw->DrawCircle(center, radius - b2_toiSlop, coreColor); } } break; case e_polygonShape: { b2PolygonShape* poly = (b2PolygonShape*)shape; int32 vertexCount = poly->GetVertexCount(); const b2Vec2* localVertices = poly->GetVertices(); b2Assert(vertexCount <= b2_maxPolygonVertices); b2Vec2 vertices[b2_maxPolygonVertices]; for (int32 i = 0; i < vertexCount; ++i) { vertices[i] = b2Mul(xf, localVertices[i]); } m_debugDraw->DrawSolidPolygon(vertices, vertexCount, color); if (core) { const b2Vec2* localCoreVertices = poly->GetCoreVertices(); for (int32 i = 0; i < vertexCount; ++i) { vertices[i] = b2Mul(xf, localCoreVertices[i]); } m_debugDraw->DrawPolygon(vertices, vertexCount, coreColor); } } break; case e_edgeShape: { b2EdgeShape* edge = (b2EdgeShape*)shape; m_debugDraw->DrawSegment(b2Mul(xf, edge->GetVertex1()), b2Mul(xf, edge->GetVertex2()), color); if (core) { m_debugDraw->DrawSegment(b2Mul(xf, edge->GetCoreVertex1()), b2Mul(xf, edge->GetCoreVertex2()), coreColor); } } break; } } void b2World::DrawJoint(b2Joint* joint) { b2Body* b1 = joint->GetBody1(); b2Body* b2 = joint->GetBody2(); const b2XForm& xf1 = b1->GetXForm(); const b2XForm& xf2 = b2->GetXForm(); b2Vec2 x1 = xf1.position; b2Vec2 x2 = xf2.position; b2Vec2 p1 = joint->GetAnchor1(); b2Vec2 p2 = joint->GetAnchor2(); b2Color color(0.5f, 0.8f, 0.8f); switch (joint->GetType()) { case e_distanceJoint: m_debugDraw->DrawSegment(p1, p2, color); break; case e_pulleyJoint: { b2PulleyJoint* pulley = (b2PulleyJoint*)joint; b2Vec2 s1 = pulley->GetGroundAnchor1(); b2Vec2 s2 = pulley->GetGroundAnchor2(); m_debugDraw->DrawSegment(s1, p1, color); m_debugDraw->DrawSegment(s2, p2, color); m_debugDraw->DrawSegment(s1, s2, color); } break; case e_mouseJoint: // don't draw this break; default: m_debugDraw->DrawSegment(x1, p1, color); m_debugDraw->DrawSegment(p1, p2, color); m_debugDraw->DrawSegment(x2, p2, color); } } void b2World::DrawDebugData() { if (m_debugDraw == NULL) { return; } uint32 flags = m_debugDraw->GetFlags(); if (flags & b2DebugDraw::e_shapeBit) { bool core = (flags & b2DebugDraw::e_coreShapeBit) == b2DebugDraw::e_coreShapeBit; for (b2Body* b = m_bodyList; b; b = b->GetNext()) { const b2XForm& xf = b->GetXForm(); for (b2Shape* s = b->GetShapeList(); s; s = s->GetNext()) { if (b->IsStatic()) { DrawShape(s, xf, b2Color(0.5f, 0.9f, 0.5f), core); } else if (b->IsSleeping()) { DrawShape(s, xf, b2Color(0.5f, 0.5f, 0.9f), core); } else { DrawShape(s, xf, b2Color(0.9f, 0.9f, 0.9f), core); } } } } if (flags & b2DebugDraw::e_jointBit) { for (b2Joint* j = m_jointList; j; j = j->GetNext()) { if (j->GetType() != e_mouseJoint) { DrawJoint(j); } } } if (flags & b2DebugDraw::e_controllerBit) { for (b2Controller* c = m_controllerList; c; c= c->GetNext()) { c->Draw(m_debugDraw); } } if (flags & b2DebugDraw::e_pairBit) { b2BroadPhase* bp = m_broadPhase; b2Vec2 invQ; invQ.Set(1.0f / bp->m_quantizationFactor.x, 1.0f / bp->m_quantizationFactor.y); b2Color color(0.9f, 0.9f, 0.3f); for (int32 i = 0; i < b2_tableCapacity; ++i) { uint16 index = bp->m_pairManager.m_hashTable[i]; while (index != b2_nullPair) { b2Pair* pair = bp->m_pairManager.m_pairs + index; b2Proxy* p1 = bp->m_proxyPool + pair->proxyId1; b2Proxy* p2 = bp->m_proxyPool + pair->proxyId2; b2AABB b1, b2; b1.lowerBound.x = bp->m_worldAABB.lowerBound.x + invQ.x * bp->m_bounds[0][p1->lowerBounds[0]].value; b1.lowerBound.y = bp->m_worldAABB.lowerBound.y + invQ.y * bp->m_bounds[1][p1->lowerBounds[1]].value; b1.upperBound.x = bp->m_worldAABB.lowerBound.x + invQ.x * bp->m_bounds[0][p1->upperBounds[0]].value; b1.upperBound.y = bp->m_worldAABB.lowerBound.y + invQ.y * bp->m_bounds[1][p1->upperBounds[1]].value; b2.lowerBound.x = bp->m_worldAABB.lowerBound.x + invQ.x * bp->m_bounds[0][p2->lowerBounds[0]].value; b2.lowerBound.y = bp->m_worldAABB.lowerBound.y + invQ.y * bp->m_bounds[1][p2->lowerBounds[1]].value; b2.upperBound.x = bp->m_worldAABB.lowerBound.x + invQ.x * bp->m_bounds[0][p2->upperBounds[0]].value; b2.upperBound.y = bp->m_worldAABB.lowerBound.y + invQ.y * bp->m_bounds[1][p2->upperBounds[1]].value; b2Vec2 x1 = 0.5f * (b1.lowerBound + b1.upperBound); b2Vec2 x2 = 0.5f * (b2.lowerBound + b2.upperBound); m_debugDraw->DrawSegment(x1, x2, color); index = pair->next; } } } if (flags & b2DebugDraw::e_aabbBit) { b2BroadPhase* bp = m_broadPhase; b2Vec2 worldLower = bp->m_worldAABB.lowerBound; b2Vec2 worldUpper = bp->m_worldAABB.upperBound; b2Vec2 invQ; invQ.Set(1.0f / bp->m_quantizationFactor.x, 1.0f / bp->m_quantizationFactor.y); b2Color color(0.9f, 0.3f, 0.9f); for (int32 i = 0; i < b2_maxProxies; ++i) { b2Proxy* p = bp->m_proxyPool + i; if (p->IsValid() == false) { continue; } b2AABB b; b.lowerBound.x = worldLower.x + invQ.x * bp->m_bounds[0][p->lowerBounds[0]].value; b.lowerBound.y = worldLower.y + invQ.y * bp->m_bounds[1][p->lowerBounds[1]].value; b.upperBound.x = worldLower.x + invQ.x * bp->m_bounds[0][p->upperBounds[0]].value; b.upperBound.y = worldLower.y + invQ.y * bp->m_bounds[1][p->upperBounds[1]].value; b2Vec2 vs[4]; vs[0].Set(b.lowerBound.x, b.lowerBound.y); vs[1].Set(b.upperBound.x, b.lowerBound.y); vs[2].Set(b.upperBound.x, b.upperBound.y); vs[3].Set(b.lowerBound.x, b.upperBound.y); m_debugDraw->DrawPolygon(vs, 4, color); } b2Vec2 vs[4]; vs[0].Set(worldLower.x, worldLower.y); vs[1].Set(worldUpper.x, worldLower.y); vs[2].Set(worldUpper.x, worldUpper.y); vs[3].Set(worldLower.x, worldUpper.y); m_debugDraw->DrawPolygon(vs, 4, b2Color(0.3f, 0.9f, 0.9f)); } if (flags & b2DebugDraw::e_obbBit) { b2Color color(0.5f, 0.3f, 0.5f); for (b2Body* b = m_bodyList; b; b = b->GetNext()) { const b2XForm& xf = b->GetXForm(); for (b2Shape* s = b->GetShapeList(); s; s = s->GetNext()) { if (s->GetType() != e_polygonShape) { continue; } b2PolygonShape* poly = (b2PolygonShape*)s; const b2OBB& obb = poly->GetOBB(); b2Vec2 h = obb.extents; b2Vec2 vs[4]; vs[0].Set(-h.x, -h.y); vs[1].Set( h.x, -h.y); vs[2].Set( h.x, h.y); vs[3].Set(-h.x, h.y); for (int32 i = 0; i < 4; ++i) { vs[i] = obb.center + b2Mul(obb.R, vs[i]); vs[i] = b2Mul(xf, vs[i]); } m_debugDraw->DrawPolygon(vs, 4, color); } } } if (flags & b2DebugDraw::e_centerOfMassBit) { for (b2Body* b = m_bodyList; b; b = b->GetNext()) { b2XForm xf = b->GetXForm(); xf.position = b->GetWorldCenter(); m_debugDraw->DrawXForm(xf); } } } void b2World::Validate() { m_broadPhase->Validate(); } int32 b2World::GetProxyCount() const { return m_broadPhase->m_proxyCount; } int32 b2World::GetPairCount() const { return m_broadPhase->m_pairManager.m_pairCount; } bool b2World::InRange(const b2AABB& aabb) const { return m_broadPhase->InRange(aabb); } float32 b2World::RaycastSortKey(void* data) { b2Shape* shape = (b2Shape*)data; b2Body* body = shape->GetBody(); b2World* world = body->GetWorld(); const b2XForm xf = body->GetXForm(); if(world->m_contactFilter && !world->m_contactFilter->RayCollide(world->m_raycastUserData,shape)) return -1; float32 lambda; b2SegmentCollide collide = shape->TestSegment(xf, &lambda, &world->m_raycastNormal, *world->m_raycastSegment,1); if(world->m_raycastSolidShape && collide==e_missCollide) return -1; if(!world->m_raycastSolidShape && collide!=e_hitCollide) return -1; return lambda; }python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2World.h0000644000000000000000000002523611133714741020660 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #ifndef B2_WORLD_H #define B2_WORLD_H #include "../Common/b2Math.h" #include "../Common/b2BlockAllocator.h" #include "../Common/b2StackAllocator.h" #include "b2ContactManager.h" #include "b2WorldCallbacks.h" struct b2AABB; struct b2ShapeDef; struct b2BodyDef; struct b2JointDef; class b2Body; class b2Joint; class b2Shape; class b2Contact; class b2BroadPhase; class b2Controller; class b2ControllerDef; struct b2TimeStep { float32 dt; // time step float32 inv_dt; // inverse time step (0 if dt == 0). float32 dtRatio; // dt * inv_dt0 int32 velocityIterations; int32 positionIterations; bool warmStarting; }; /// The world class manages all physics entities, dynamic simulation, /// and asynchronous queries. The world also contains efficient memory /// management facilities. class b2World { public: /// Construct a world object. /// @param worldAABB a bounding box that completely encompasses all your shapes. /// @param gravity the world gravity vector. /// @param doSleep improve performance by not simulating inactive bodies. b2World(const b2AABB& worldAABB, const b2Vec2& gravity, bool doSleep); /// Destruct the world. All physics entities are destroyed and all heap memory is released. ~b2World(); /// Register a destruction listener. void SetDestructionListener(b2DestructionListener* listener); /// Register a broad-phase boundary listener. void SetBoundaryListener(b2BoundaryListener* listener); /// Register a contact filter to provide specific control over collision. /// Otherwise the default filter is used (b2_defaultFilter). void SetContactFilter(b2ContactFilter* filter); /// Register a contact event listener void SetContactListener(b2ContactListener* listener); /// Register a routine for debug drawing. The debug draw functions are called /// inside the b2World::Step method, so make sure your renderer is ready to /// consume draw commands when you call Step(). void SetDebugDraw(b2DebugDraw* debugDraw); /// Create a rigid body given a definition. No reference to the definition /// is retained. /// @warning This function is locked during callbacks. b2Body* CreateBody(const b2BodyDef* def); /// Destroy a rigid body given a definition. No reference to the definition /// is retained. This function is locked during callbacks. /// @warning This automatically deletes all associated shapes and joints. /// @warning This function is locked during callbacks. void DestroyBody(b2Body* body); /// Create a joint to constrain bodies together. No reference to the definition /// is retained. This may cause the connected bodies to cease colliding. /// @warning This function is locked during callbacks. b2Joint* CreateJoint(const b2JointDef* def); /// Destroy a joint. This may cause the connected bodies to begin colliding. /// @warning This function is locked during callbacks. void DestroyJoint(b2Joint* joint); /// Add a controller to the world. b2Controller* CreateController(b2ControllerDef* def); /// Removes a controller from the world. void DestroyController(b2Controller* controller); /// The world provides a single static ground body with no collision shapes. /// You can use this to simplify the creation of joints and static shapes. b2Body* GetGroundBody(); /// Take a time step. This performs collision detection, integration, /// and constraint solution. /// @param timeStep the amount of time to simulate, this should not vary. /// @param velocityIterations for the velocity constraint solver. /// @param positionIterations for the position constraint solver. void Step(float32 timeStep, int32 velocityIterations, int32 positionIterations); /// Query the world for all shapes that potentially overlap the /// provided AABB. You provide a shape pointer buffer of specified /// size. The number of shapes found is returned. /// @param aabb the query box. /// @param shapes a user allocated shape pointer array of size maxCount (or greater). /// @param maxCount the capacity of the shapes array. /// @return the number of shapes found in aabb. int32 Query(const b2AABB& aabb, b2Shape** shapes, int32 maxCount); /// Query the world for all shapes that intersect a given segment. You provide a shap /// pointer buffer of specified size. The number of shapes found is returned, and the buffer /// is filled in order of intersection /// @param segment defines the begin and end point of the ray cast, from p1 to p2. /// Use b2Segment.Extend to create (semi-)infinite rays /// @param shapes a user allocated shape pointer array of size maxCount (or greater). /// @param maxCount the capacity of the shapes array /// @param solidShapes determines if shapes that the ray starts in are counted as hits. /// @param userData passed through the worlds contact filter, with method RayCollide. This can be used to filter valid shapes /// @returns the number of shapes found int32 Raycast(const b2Segment& segment, b2Shape** shapes, int32 maxCount, bool solidShapes, void* userData); /// Performs a raycast as with Raycast, finding the first intersecting shape. /// @param segment defines the begin and end point of the ray cast, from p1 to p2. /// Use b2Segment.Extend to create (semi-)infinite rays /// @param lambda returns the hit fraction. You can use this to compute the contact point /// p = (1 - lambda) * segment.p1 + lambda * segment.p2. /// @param normal returns the normal at the contact point. If there is no intersection, the normal /// is not set. /// @param solidShapes determines if shapes that the ray starts in are counted as hits. /// @returns the colliding shape shape, or null if not found b2Shape* RaycastOne(const b2Segment& segment, float32* lambda, b2Vec2* normal, bool solidShapes, void* userData); /// Check if the AABB is within the broadphase limits. bool InRange(const b2AABB& aabb) const; /// Get the world body list. With the returned body, use b2Body::GetNext to get /// the next body in the world list. A NULL body indicates the end of the list. /// @return the head of the world body list. b2Body* GetBodyList(); /// Get the world joint list. With the returned joint, use b2Joint::GetNext to get /// the next joint in the world list. A NULL joint indicates the end of the list. /// @return the head of the world joint list. b2Joint* GetJointList(); /// Get the world controller list. With the returned controller, use b2Controller::GetNext to get /// the next controller in the world list. A NULL controller indicates the end of the list. /// @return the head of the world controller list. b2Controller* GetControllerList(); /// Re-filter a shape. This re-runs contact filtering on a shape. void Refilter(b2Shape* shape); /// Enable/disable warm starting. For testing. void SetWarmStarting(bool flag) { m_warmStarting = flag; } /// Enable/disable continuous physics. For testing. void SetContinuousPhysics(bool flag) { m_continuousPhysics = flag; } /// Perform validation of internal data structures. void Validate(); /// Get the number of broad-phase proxies. int32 GetProxyCount() const; /// Get the number of broad-phase pairs. int32 GetPairCount() const; /// Get the number of bodies. int32 GetBodyCount() const; /// Get the number of joints. int32 GetJointCount() const; /// Get the number of contacts (each may have 0 or more contact points). int32 GetContactCount() const; /// Get the number of controllers. int32 GetControllerCount() const; /// Change the global gravity vector. void SetGravity(const b2Vec2& gravity); /// Get the global gravity vector. b2Vec2 GetGravity() const; /// Get the world's AABB b2AABB GetWorldAABB() const; /// Whether or not bodies can sleep bool CanSleep() const; private: friend class b2Body; friend class b2ContactManager; friend class b2Controller; void Solve(const b2TimeStep& step); void SolveTOI(const b2TimeStep& step); void DrawJoint(b2Joint* joint); void DrawShape(b2Shape* shape, const b2XForm& xf, const b2Color& color, bool core); void DrawDebugData(); //Is it safe to pass private static function pointers? static float32 RaycastSortKey(void* shape); b2BlockAllocator m_blockAllocator; b2StackAllocator m_stackAllocator; bool m_lock; b2BroadPhase* m_broadPhase; b2ContactManager m_contactManager; b2Body* m_bodyList; b2Joint* m_jointList; b2Controller* m_controllerList; b2Vec2 m_raycastNormal; void* m_raycastUserData; const b2Segment* m_raycastSegment; bool m_raycastSolidShape; // Do not access b2Contact* m_contactList; int32 m_bodyCount; int32 m_contactCount; int32 m_jointCount; int32 m_controllerCount; b2Vec2 m_gravity; bool m_allowSleep; b2Body* m_groundBody; b2DestructionListener* m_destructionListener; b2BoundaryListener* m_boundaryListener; b2ContactFilter* m_contactFilter; b2ContactListener* m_contactListener; b2DebugDraw* m_debugDraw; // This is used to compute the time step ratio to // support a variable time step. float32 m_inv_dt0; // This is for debugging the solver. bool m_warmStarting; // This is for debugging the solver. bool m_continuousPhysics; }; inline b2Body* b2World::GetGroundBody() { return m_groundBody; } inline b2Body* b2World::GetBodyList() { return m_bodyList; } inline b2Joint* b2World::GetJointList() { return m_jointList; } inline b2Controller* b2World::GetControllerList() { return m_controllerList; } inline int32 b2World::GetBodyCount() const { return m_bodyCount; } inline int32 b2World::GetJointCount() const { return m_jointCount; } inline int32 b2World::GetContactCount() const { return m_contactCount; } inline int32 b2World::GetControllerCount() const { return m_controllerCount; } inline void b2World::SetGravity(const b2Vec2& gravity) { m_gravity = gravity; } inline b2Vec2 b2World::GetGravity() const { return m_gravity; } inline b2AABB b2World::GetWorldAABB() const { return m_broadPhase->m_worldAABB; } inline bool b2World::CanSleep() const { return m_allowSleep; } #endif python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2WorldCallbacks.cpp0000644000000000000000000000431211064106301022771 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2WorldCallbacks.h" #include "../Collision/Shapes/b2Shape.h" b2ContactFilter b2_defaultFilter; // Return true if contact calculations should be performed between these two shapes. // If you implement your own collision filter you may want to build from this implementation. bool b2ContactFilter::ShouldCollide(b2Shape* shape1, b2Shape* shape2) { const b2FilterData& filter1 = shape1->GetFilterData(); const b2FilterData& filter2 = shape2->GetFilterData(); if (filter1.groupIndex == filter2.groupIndex && filter1.groupIndex != 0) { return filter1.groupIndex > 0; } bool collide = (filter1.maskBits & filter2.categoryBits) != 0 && (filter1.categoryBits & filter2.maskBits) != 0; return collide; } bool b2ContactFilter::RayCollide(void* userData, b2Shape* shape) { //By default, cast userData as a shape, and then collide if the shapes would collide if(!userData) return true; return ShouldCollide((b2Shape*)userData,shape); } b2DebugDraw::b2DebugDraw() { m_drawFlags = 0; } void b2DebugDraw::SetFlags(uint32 flags) { m_drawFlags = flags; } uint32 b2DebugDraw::GetFlags() const { return m_drawFlags; } void b2DebugDraw::AppendFlags(uint32 flags) { m_drawFlags |= flags; } void b2DebugDraw::ClearFlags(uint32 flags) { m_drawFlags &= ~flags; } python-box2d-2.0.2+svn20100109.244/Box2D/Dynamics/b2ContactManager.cpp0000644000000000000000000001370111065735647023020 0ustar rootroot/* * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "b2ContactManager.h" #include "b2World.h" #include "b2Body.h" // This is a callback from the broadphase when two AABB proxies begin // to overlap. We create a b2Contact to manage the narrow phase. void* b2ContactManager::PairAdded(void* proxyUserData1, void* proxyUserData2) { b2Shape* shape1 = (b2Shape*)proxyUserData1; b2Shape* shape2 = (b2Shape*)proxyUserData2; b2Body* body1 = shape1->GetBody(); b2Body* body2 = shape2->GetBody(); if (body1->IsStatic() && body2->IsStatic()) { return &m_nullContact; } if (shape1->GetBody() == shape2->GetBody()) { return &m_nullContact; } if (body2->IsConnected(body1)) { return &m_nullContact; } if (m_world->m_contactFilter != NULL && m_world->m_contactFilter->ShouldCollide(shape1, shape2) == false) { return &m_nullContact; } // Call the factory. b2Contact* c = b2Contact::Create(shape1, shape2, &m_world->m_blockAllocator); if (c == NULL) { return &m_nullContact; } // Contact creation may swap shapes. shape1 = c->GetShape1(); shape2 = c->GetShape2(); body1 = shape1->GetBody(); body2 = shape2->GetBody(); // Insert into the world. c->m_prev = NULL; c->m_next = m_world->m_contactList; if (m_world->m_contactList != NULL) { m_world->m_contactList->m_prev = c; } m_world->m_contactList = c; // Connect to island graph. // Connect to body 1 c->m_node1.contact = c; c->m_node1.other = body2; c->m_node1.prev = NULL; c->m_node1.next = body1->m_contactList; if (body1->m_contactList != NULL) { body1->m_contactList->prev = &c->m_node1; } body1->m_contactList = &c->m_node1; // Connect to body 2 c->m_node2.contact = c; c->m_node2.other = body1; c->m_node2.prev = NULL; c->m_node2.next = body2->m_contactList; if (body2->m_contactList != NULL) { body2->m_contactList->prev = &c->m_node2; } body2->m_contactList = &c->m_node2; ++m_world->m_contactCount; return c; } // This is a callback from the broadphase when two AABB proxies cease // to overlap. We retire the b2Contact. void b2ContactManager::PairRemoved(void* proxyUserData1, void* proxyUserData2, void* pairUserData) { B2_NOT_USED(proxyUserData1); B2_NOT_USED(proxyUserData2); if (pairUserData == NULL) { return; } b2Contact* c = (b2Contact*)pairUserData; if (c == &m_nullContact) { return; } // An attached body is being destroyed, we must destroy this contact // immediately to avoid orphaned shape pointers. Destroy(c); } void b2ContactManager::Destroy(b2Contact* c) { b2Shape* shape1 = c->GetShape1(); b2Shape* shape2 = c->GetShape2(); b2Body* body1 = shape1->GetBody(); b2Body* body2 = shape2->GetBody(); b2ContactPoint cp; cp.shape1 = shape1; cp.shape2 = shape2; cp.friction = b2MixFriction(shape1->GetFriction(), shape2->GetFriction()); cp.restitution = b2MixRestitution(shape1->GetRestitution(), shape2->GetRestitution()); // Inform the user that this contact is ending. int32 manifoldCount = c->GetManifoldCount(); if (manifoldCount > 0 && m_world->m_contactListener) { b2Manifold* manifolds = c->GetManifolds(); for (int32 i = 0; i < manifoldCount; ++i) { b2Manifold* manifold = manifolds + i; cp.normal = manifold->normal; for (int32 j = 0; j < manifold->pointCount; ++j) { b2ManifoldPoint* mp = manifold->points + j; cp.position = body1->GetWorldPoint(mp->localPoint1); b2Vec2 v1 = body1->GetLinearVelocityFromLocalPoint(mp->localPoint1); b2Vec2 v2 = body2->GetLinearVelocityFromLocalPoint(mp->localPoint2); cp.velocity = v2 - v1; cp.separation = mp->separation; cp.id = mp->id; m_world->m_contactListener->Remove(&cp); } } } // Remove from the world. if (c->m_prev) { c->m_prev->m_next = c->m_next; } if (c->m_next) { c->m_next->m_prev = c->m_prev; } if (c == m_world->m_contactList) { m_world->m_contactList = c->m_next; } // Remove from body 1 if (c->m_node1.prev) { c->m_node1.prev->next = c->m_node1.next; } if (c->m_node1.next) { c->m_node1.next->prev = c->m_node1.prev; } if (&c->m_node1 == body1->m_contactList) { body1->m_contactList = c->m_node1.next; } // Remove from body 2 if (c->m_node2.prev) { c->m_node2.prev->next = c->m_node2.next; } if (c->m_node2.next) { c->m_node2.next->prev = c->m_node2.prev; } if (&c->m_node2 == body2->m_contactList) { body2->m_contactList = c->m_node2.next; } // Call the factory. b2Contact::Destroy(c, &m_world->m_blockAllocator); --m_world->m_contactCount; } // This is the top level collision call for the time step. Here // all the narrow phase collision is processed for the world // contact list. void b2ContactManager::Collide() { // Update awake contacts. for (b2Contact* c = m_world->m_contactList; c; c = c->GetNext()) { b2Body* body1 = c->GetShape1()->GetBody(); b2Body* body2 = c->GetShape2()->GetBody(); if (body1->IsSleeping() && body2->IsSleeping()) { continue; } c->Update(m_world->m_contactListener); } } python-box2d-2.0.2+svn20100109.244/Box2D/Makefile0000644000000000000000000000424211130023047017044 0ustar rootrootTARGETS= Gen/float/libbox2d.a CXXFLAGS+= -g -O2 SOURCES = \ ./Dynamics/b2Body.cpp \ ./Dynamics/b2Island.cpp \ ./Dynamics/b2World.cpp \ ./Dynamics/b2ContactManager.cpp \ ./Dynamics/Contacts/b2Contact.cpp \ ./Dynamics/Contacts/b2PolyContact.cpp \ ./Dynamics/Contacts/b2CircleContact.cpp \ ./Dynamics/Contacts/b2PolyAndCircleContact.cpp \ ./Dynamics/Contacts/b2EdgeAndCircleContact.cpp \ ./Dynamics/Contacts/b2PolyAndEdgeContact.cpp \ ./Dynamics/Contacts/b2ContactSolver.cpp \ ./Dynamics/Controllers/b2BuoyancyController.cpp \ ./Dynamics/Controllers/b2ConstantAccelController.cpp \ ./Dynamics/Controllers/b2ConstantForceController.cpp \ ./Dynamics/Controllers/b2Controller.cpp \ ./Dynamics/Controllers/b2GravityController.cpp \ ./Dynamics/Controllers/b2TensorDampingController.cpp \ ./Dynamics/b2WorldCallbacks.cpp \ ./Dynamics/Joints/b2MouseJoint.cpp \ ./Dynamics/Joints/b2PulleyJoint.cpp \ ./Dynamics/Joints/b2Joint.cpp \ ./Dynamics/Joints/b2RevoluteJoint.cpp \ ./Dynamics/Joints/b2PrismaticJoint.cpp \ ./Dynamics/Joints/b2DistanceJoint.cpp \ ./Dynamics/Joints/b2GearJoint.cpp \ ./Dynamics/Joints/b2LineJoint.cpp \ ./Common/b2StackAllocator.cpp \ ./Common/b2Math.cpp \ ./Common/b2BlockAllocator.cpp \ ./Common/b2Settings.cpp \ ./Collision/b2Collision.cpp \ ./Collision/b2Distance.cpp \ ./Collision/Shapes/b2Shape.cpp \ ./Collision/Shapes/b2CircleShape.cpp \ ./Collision/Shapes/b2PolygonShape.cpp \ ./Collision/Shapes/b2EdgeShape.cpp \ ./Collision/b2TimeOfImpact.cpp \ ./Collision/b2PairManager.cpp \ ./Collision/b2CollidePoly.cpp \ ./Collision/b2CollideCircle.cpp \ ./Collision/b2BroadPhase.cpp # ./Contrib/b2Polygon.cpp \ # ./Contrib/b2Triangle.cpp ifneq ($(INCLUDE_DEPENDENCIES),yes) all: @make --no-print-directory INCLUDE_DEPENDENCIES=yes $(TARGETS) .PHONY: clean clean: rm -rf Gen else -include $(addprefix Gen/float/,$(SOURCES:.cpp=.d)) #-include $(addprefix Gen/fixed/,$(SOURCES:.cpp=.d)) endif Gen/float/%.o: %.cpp @mkdir -p $(dir $@) c++ $(CXXFLAGS) -c -o $@ $< Gen/float/libbox2d.a: $(addprefix Gen/float/,$(SOURCES:.cpp=.o)) ar cr $@ $^ ranlib $@ Gen/float/%.d: %.cpp @mkdir -p $(dir $@) c++ -MM -MT $(@:.d=.o) $(CXXFLAGS) -o $@ $< python-box2d-2.0.2+svn20100109.244/Box2D/Box2D_deprecated.i0000644000000000000000000002037711256532055020700 0ustar rootroot/* * Python SWIG interface file for Box2D (www.box2d.org) * * Copyright (c) 2008 kne / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %feature("docstring") collideCircleParticle "For liquid simulation. Checks if a particle would collide with the specified circle. "; %feature("docstring") b2CollidePolyParticle "For liquid simulation. Checks if a particle would collide with the specified polygon. "; %inline %{ PyObject* collideCircleParticle(b2CircleShape* circle, const b2Vec2& ppos) { //out bCollides, b2Vec2 penetration, b2Vec2 penetrationNormal //Ported to C from Blaze (D) PyObject* ret=PyTuple_New(3); PyTuple_SetItem(ret, 0, SWIG_From_bool(false)); PyTuple_SetItem(ret, 1, SWIG_From_bool(false)); PyTuple_SetItem(ret, 2, SWIG_From_bool(false)); b2XForm xf1 = circle->GetBody()->GetXForm(); b2Vec2 p1 = b2Mul(xf1, circle->GetLocalPosition()); b2Vec2 p2 = ppos; b2Vec2 d = p2 - p1; float32 distSqr = b2Dot(d, d); float32 r1 = circle->GetRadius(); float32 r2 = 0.0f; float32 radiusSum = r1 + r2; if (distSqr > radiusSum * radiusSum) { return ret; // false } b2Vec2* normal=new b2Vec2(); float32 separation; if (distSqr < B2_FLT_EPSILON) { separation = -radiusSum; normal->Set(0.0f, 1.0f); } else { float32 dist = sqrt(distSqr); separation = dist - radiusSum; float32 a = 1.0f / dist; normal->x = a * d.x; normal->y = a * d.y; } b2Vec2* penetration=new b2Vec2(); penetration->x = normal->x * separation; penetration->y = normal->y * separation; PyTuple_SetItem(ret, 0, SWIG_From_bool(true)); PyTuple_SetItem(ret, 1, SWIG_NewPointerObj(SWIG_as_voidptr(penetration), SWIGTYPE_p_b2Vec2, 0) ); PyTuple_SetItem(ret, 2, SWIG_NewPointerObj(SWIG_as_voidptr(normal), SWIGTYPE_p_b2Vec2, 0) ); return ret; } PyObject* b2CollidePolyParticle(b2PolygonShape* polygon, const b2Vec2& ppos, float32 pradius) { //out bCollides, b2Vec2 penetration, b2Vec2 penetrationNormal //Ported to C from Blaze (D) PyObject* ret=PyTuple_New(3); PyTuple_SetItem(ret, 0, SWIG_From_bool(false)); PyTuple_SetItem(ret, 1, SWIG_From_bool(false)); PyTuple_SetItem(ret, 2, SWIG_From_bool(false)); const b2XForm xf1 = polygon->GetBody()->GetXForm(); b2XForm xf2; xf2.position = ppos; // Compute circle position in the frame of the polygon. b2Vec2 c = b2Mul(xf2, b2Vec2_zero); b2Vec2 cLocal = b2MulT(xf1, c); // Find the min separating edge. int normalIndex = 0; float32 separation = -B2_FLT_MAX; float32 radius = pradius; b2Vec2* penetration=new b2Vec2(); int vertexCount = polygon->GetVertexCount(); const b2Vec2* vertices = polygon->GetVertices(); const b2Vec2* normals = polygon->GetNormals(); for (int i = 0; i < vertexCount; ++i) { float32 s = b2Dot(normals[i], cLocal - vertices[i]); if (s > radius) { // Early out. return ret; // false } if (s > separation) { separation = s; normalIndex = i; } } // If the center is inside the polygon ... if (separation < B2_FLT_MAX) { b2Vec2 temp = b2Mul(xf1.R, normals[normalIndex]); b2Vec2* penetrationNormal=new b2Vec2(temp); separation = separation - radius; penetration->x = separation * penetrationNormal->x; penetration->y = separation * penetrationNormal->y; PyTuple_SetItem(ret, 0, SWIG_From_bool(true)); PyTuple_SetItem(ret, 1, SWIG_NewPointerObj(SWIG_as_voidptr(penetration), SWIGTYPE_p_b2Vec2, 0) ); PyTuple_SetItem(ret, 2, SWIG_NewPointerObj(SWIG_as_voidptr(penetrationNormal), SWIGTYPE_p_b2Vec2, 0) ); return ret; } // Project the circle center onto the edge segment. int vertIndex1 = normalIndex; int vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0; b2Vec2 e = vertices[vertIndex2] - vertices[vertIndex1]; float32 length = e.Normalize(); //assert(length > float.epsilon); // Project the center onto the edge. float32 u = b2Dot(cLocal - vertices[vertIndex1], e); b2Vec2 p; if (u <= 0.0f) { p = vertices[vertIndex1]; } else if (u >= length) { p = vertices[vertIndex2]; } else { p = vertices[vertIndex1] + u * e; } b2Vec2 d = cLocal - p; float32 dist = d.Normalize(); if (dist > radius) { return ret; //false } b2Vec2 temp = b2Mul(xf1.R, d); b2Vec2* penetrationNormal=new b2Vec2(temp); separation = dist - radius; penetration->x = separation * penetrationNormal->x; penetration->y = separation * penetrationNormal->y; PyTuple_SetItem(ret, 0, SWIG_From_bool(true)); PyTuple_SetItem(ret, 1, SWIG_NewPointerObj(SWIG_as_voidptr(penetration), SWIGTYPE_p_b2Vec2, 0) ); PyTuple_SetItem(ret, 2, SWIG_NewPointerObj(SWIG_as_voidptr(penetrationNormal), SWIGTYPE_p_b2Vec2, 0) ); return ret; } %} %pythoncode %{ def b2PythonCheckPolygonDef(pd): """ Checks the Polygon definition to see if upon creation it will cause an assertion. Raises ValueError if an assertion would be raised. Ported from the Box2D C++ code for CreateShape(). The C++ version is now included as it's more accurate, please use b2CheckPolygonDef instead. """ if pd.vertexCount < 3 or pd.vertexCount >= b2_maxPolygonVertices: raise ValueError("Invalid vertexCount") threshold = FLT_EPSILON * FLT_EPSILON verts = pd.getVertices_b2Vec2() normals = [] v0 = verts[0] for i in range(pd.vertexCount): if i == pd.vertexCount-1: v1 = verts[0] else: v1 = verts[i+1] edge=v1 - v0 if edge.LengthSquared() < threshold: raise ValueError("edge.LengthSquared < FLT_EPSILON**2" ) normals.append( b2Cross(edge, 1.0) ) normals[-1].Normalize() v0=v1 centroid = b2PythonComputeCentroid(pd) d=b2Vec2() for i in range(pd.vertexCount): i1 = i - 1 if i1 < 0: i1 = pd.vertexCount - 1 i2 = i n1 = normals[i1] n2 = normals[i2] v = verts[i] - centroid d.x = b2Dot(n1, v) - b2_toiSlop d.y = b2Dot(n2, v) - b2_toiSlop # Shifting the edge inward by b2_toiSlop should # not cause the plane to pass the centroid. # Your shape has a radius/extent less than b2_toiSlop. if d.x < 0.0 or d.y <= 0.0: raise ValueError("Your shape has a radius/extent less than b2_toiSlop.") A = b2Mat22() A.col1.x = n1.x; A.col2.x = n1.y A.col1.y = n2.x; A.col2.y = n2.y #coreVertices[i] = A.Solve(d) + m_centroid return True %} python-box2d-2.0.2+svn20100109.244/Box2D/Box2D_printing.i0000644000000000000000000011301311156056674020427 0ustar rootroot/* * Python SWIG interface file for Box2D (www.box2d.org) * * Copyright (c) 2008 kne / sirkne at gmail dot com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ %extend b2AABB { %pythoncode %{ def __repr__(self): return """b2AABB( lowerBound = %s, upperBound = %s, IsValid() = %s)"""% tuple(str(a) for a in\ (self.lowerBound,self.upperBound,self.IsValid())) %} } %extend b2BlockAllocator { %pythoncode %{ def __repr__(self): return "b2BlockAllocator()" %} } %extend b2Body { %pythoncode %{ def __repr__(self): return """b2Body( allowSleep = %s, angle = %s, angularDamping = %s, angularVelocity = %s, fixedRotation = %s, isBullet = %s, isSleeping = %s, linearDamping = %s, linearVelocity = %s, massData = %s, position = %s, userData = %s, GetInertia() = %s, GetLocalCenter() = %s, GetMass() = %s, GetWorldCenter() = %s, GetXForm() = %s, IsBullet() = %s, IsDynamic() = %s, IsFrozen() = %s, IsFixedRotation() = %s, IsSleeping() = %s, IsStatic() = %s)"""% tuple(str(a) for a in\ (self.allowSleep,self.angle,self.angularDamping,self.angularVelocity,self.fixedRotation,self.isBullet,self.isSleeping,self.linearDamping,self.linearVelocity,self.massData,self.position,self.userData,self.GetInertia(),self.GetLocalCenter(),self.GetMass(),self.GetWorldCenter(),self.GetXForm(),self.IsBullet(),self.IsDynamic(),self.IsFrozen(),self.IsFixedRotation(),self.IsSleeping(),self.IsStatic())) %} } %extend b2BodyDef { %pythoncode %{ def __repr__(self): return """b2BodyDef( allowSleep = %s, angle = %s, angularDamping = %s, fixedRotation = %s, isBullet = %s, isSleeping = %s, linearDamping = %s, massData = %s, position = %s, userData = %s)"""% tuple(str(a) for a in\ (self.allowSleep,self.angle,self.angularDamping,self.fixedRotation,self.isBullet,self.isSleeping,self.linearDamping,self.massData,self.position,self.userData)) %} } %extend b2Bound { %pythoncode %{ def __repr__(self): return """b2Bound( proxyId = %s, stabbingCount = %s, value = %s, IsLower() = %s, IsUpper() = %s)"""% tuple(str(a) for a in\ (self.proxyId,self.stabbingCount,self.value,self.IsLower(),self.IsUpper())) %} } %extend b2BoundaryListener { %pythoncode %{ def __repr__(self): return "b2BoundaryListener()" %} } %extend b2BroadPhase { %pythoncode %{ def __repr__(self): return """b2BroadPhase( bounds = %s, freeProxy = %s, pairManager = %s, proxyCount = %s, proxyPool = %s, quantizationFactor = %s, queryResultCount = %s, queryResults = %s, querySortKeys = %s, s_validate = %s, timeStamp = %s, worldAABB = %s)"""% tuple(str(a) for a in\ (self.bounds,self.freeProxy,self.pairManager,self.proxyCount,self.proxyPool,self.quantizationFactor,self.queryResultCount,self.queryResults,self.querySortKeys,self.s_validate,self.timeStamp,self.worldAABB)) %} } %extend b2BufferedPair { %pythoncode %{ def __repr__(self): return """b2BufferedPair( proxyId1 = %s, proxyId2 = %s)"""% tuple(str(a) for a in\ (self.proxyId1,self.proxyId2)) %} } %extend b2BuoyancyController { %pythoncode %{ def __repr__(self): return """b2BuoyancyController( angularDrag = %s, density = %s, gravity = %s, linearDrag = %s, normal = %s, offset = %s, useDensity = %s, useWorldGravity = %s, velocity = %s)"""% tuple(str(a) for a in\ (self.angularDrag,self.density,self.gravity,self.linearDrag,self.normal,self.offset,self.useDensity,self.useWorldGravity,self.velocity)) %} } %extend b2BuoyancyControllerDef { %pythoncode %{ def __repr__(self): return """b2BuoyancyControllerDef( angularDrag = %s, density = %s, gravity = %s, linearDrag = %s, normal = %s, offset = %s, useDensity = %s, useWorldGravity = %s, velocity = %s)"""% tuple(str(a) for a in\ (self.angularDrag,self.density,self.gravity,self.linearDrag,self.normal,self.offset,self.useDensity,self.useWorldGravity,self.velocity)) %} } %extend b2CircleDef { %pythoncode %{ def __repr__(self): return """b2CircleDef( density = %s, filter = %s, friction = %s, isSensor = %s, localPosition = %s, radius = %s, restitution = %s, type = %s, userData = %s)"""% tuple(str(a) for a in\ (self.density,self.filter,self.friction,self.isSensor,self.localPosition,self.radius,self.restitution,self.type,self.userData)) %} } %extend b2CircleShape { %pythoncode %{ def __repr__(self): return """b2CircleShape( density = %s, filter = %s, friction = %s, localPosition = %s, radius = %s, restitution = %s, userData = %s, GetBody() = %s, GetFilterData() = %s, GetSweepRadius() = %s, GetType() = %s, IsSensor() = %s)"""% tuple(str(a) for a in\ (self.density,self.filter,self.friction,self.localPosition,self.radius,self.restitution,self.userData,self.GetBody(),self.GetFilterData(),self.GetSweepRadius(),self.GetType(),self.IsSensor())) %} } %extend b2Color { %pythoncode %{ def __repr__(self): return """b2Color( b = %s, g = %s, r = %s)"""% tuple(str(a) for a in\ (self.b,self.g,self.r)) %} } %extend b2ConstantAccelController { %pythoncode %{ def __repr__(self): return """b2ConstantAccelController( A = %s)"""% tuple(str(a) for a in\ (self.A)) %} } %extend b2ConstantAccelControllerDef { %pythoncode %{ def __repr__(self): return """b2ConstantAccelControllerDef( A = %s)"""% tuple(str(a) for a in\ (self.A)) %} } %extend b2ConstantForceController { %pythoncode %{ def __repr__(self): return """b2ConstantForceController( F = %s)"""% tuple(str(a) for a in\ (self.F)) %} } %extend b2ConstantForceControllerDef { %pythoncode %{ def __repr__(self): return """b2ConstantForceControllerDef( F = %s)"""% tuple(str(a) for a in\ (self.F)) %} } %extend b2Contact { %pythoncode %{ def __repr__(self): return """b2Contact( flags = %s, manifoldCount = %s, node1 = %s, node2 = %s, s_initialized = %s, s_registers = %s, shape1 = %s, shape2 = %s, toi = %s, GetManifolds() = %s, IsSolid() = %s, e_islandFlag = %s, e_nonSolidFlag = %s, e_slowFlag = %s, e_toiFlag = %s)"""% tuple(str(a) for a in\ (self.flags,self.manifoldCount,self.node1,self.node2,self.s_initialized,self.s_registers,self.shape1,self.shape2,self.toi,self.GetManifolds(),self.IsSolid(),self.e_islandFlag,self.e_nonSolidFlag,self.e_slowFlag,self.e_toiFlag)) %} } %extend b2ContactEdge { %pythoncode %{ def __repr__(self): return """b2ContactEdge( contact = %s, other = %s)"""% tuple(str(a) for a in\ (self.contact,self.other)) %} } %extend b2ContactFilter { %pythoncode %{ def __repr__(self): return "b2ContactFilter()" %} } %extend b2ContactID { %pythoncode %{ def __repr__(self): return """b2ContactID( features = %s, key = %s)"""% tuple(str(a) for a in\ (self.features,self.key)) %} } %extend b2ContactID_features { %pythoncode %{ def __repr__(self): return """b2ContactID_features( flip = %s, incidentEdge = %s, incidentVertex = %s, referenceEdge = %s)"""% tuple(str(a) for a in\ (self.flip,self.incidentEdge,self.incidentVertex,self.referenceEdge)) %} } %extend b2ContactListener { %pythoncode %{ def __repr__(self): return "b2ContactListener()" %} } %extend b2ContactManager { %pythoncode %{ def __repr__(self): return """b2ContactManager( destroyImmediate = %s, nullContact = %s, world = %s)"""% tuple(str(a) for a in\ (self.destroyImmediate,self.nullContact,self.world)) %} } %extend b2ContactPoint { %pythoncode %{ def __repr__(self): return """b2ContactPoint( friction = %s, id = %s, normal = %s, position = %s, restitution = %s, separation = %s, shape1 = %s, shape2 = %s, velocity = %s)"""% tuple(str(a) for a in\ (self.friction,self.id,self.normal,self.position,self.restitution,self.separation,self.shape1,self.shape2,self.velocity)) %} } %extend b2ContactRegister { %pythoncode %{ def __repr__(self): return """b2ContactRegister( createFcn = %s, destroyFcn = %s, primary = %s)"""% tuple(str(a) for a in\ (self.createFcn,self.destroyFcn,self.primary)) %} } %extend b2ContactResult { %pythoncode %{ def __repr__(self): return """b2ContactResult( id = %s, normal = %s, normalImpulse = %s, position = %s, shape1 = %s, shape2 = %s, tangentImpulse = %s)"""% tuple(str(a) for a in\ (self.id,self.normal,self.normalImpulse,self.position,self.shape1,self.shape2,self.tangentImpulse)) %} } %extend b2Controller { %pythoncode %{ def __repr__(self): return "b2Controller()" %} } %extend b2ControllerDef { %pythoncode %{ def __repr__(self): return "b2ControllerDef()" %} } %extend b2ControllerEdge { %pythoncode %{ def __repr__(self): return """b2ControllerEdge( body = %s, controller = %s)"""% tuple(str(a) for a in\ (self.body,self.controller)) %} } %extend b2DebugDraw { %pythoncode %{ def __repr__(self): return """b2DebugDraw( GetFlags() = %s, e_aabbBit = %s, e_centerOfMassBit = %s, e_controllerBit = %s, e_coreShapeBit = %s, e_jointBit = %s, e_obbBit = %s, e_pairBit = %s, e_shapeBit = %s)"""% tuple(str(a) for a in\ (self.GetFlags(),self.e_aabbBit,self.e_centerOfMassBit,self.e_controllerBit,self.e_coreShapeBit,self.e_jointBit,self.e_obbBit,self.e_pairBit,self.e_shapeBit)) %} } %extend b2DestructionListener { %pythoncode %{ def __repr__(self): return "b2DestructionListener()" %} } %extend b2DistanceJoint { %pythoncode %{ def __repr__(self): return """b2DistanceJoint( bias = %s, body1 = %s, body2 = %s, collideConnected = %s, dampingRatio = %s, frequencyHz = %s, gamma = %s, impulse = %s, length = %s, localAnchor1 = %s, localAnchor2 = %s, mass = %s, type = %s, u = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s)"""% tuple(str(a) for a in\ (self.bias,self.body1,self.body2,self.collideConnected,self.dampingRatio,self.frequencyHz,self.gamma,self.impulse,self.length,self.localAnchor1,self.localAnchor2,self.mass,self.type,self.u,self.userData,self.GetAnchor1(),self.GetAnchor2())) %} } %extend b2DistanceJointDef { %pythoncode %{ def __repr__(self): return """b2DistanceJointDef( body1 = %s, body2 = %s, collideConnected = %s, dampingRatio = %s, frequencyHz = %s, length = %s, localAnchor1 = %s, localAnchor2 = %s, type = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.dampingRatio,self.frequencyHz,self.length,self.localAnchor1,self.localAnchor2,self.type,self.userData)) %} } %extend b2EdgeChainDef { %pythoncode %{ def __repr__(self): return """b2EdgeChainDef( density = %s, filter = %s, friction = %s, isALoop = %s, isSensor = %s, restitution = %s, type = %s, userData = %s, vertexCount = %s, vertices = %s)"""% tuple(str(a) for a in\ (self.density,self.filter,self.friction,self.isALoop,self.isSensor,self.restitution,self.type,self.userData,self.vertexCount,self.vertices)) %} } %extend b2EdgeShape { %pythoncode %{ def __repr__(self): return """b2EdgeShape( density = %s, filter = %s, friction = %s, restitution = %s, userData = %s, GetBody() = %s, GetCoreVertex1() = %s, GetCoreVertex2() = %s, GetCorner1Vector() = %s, GetCorner2Vector() = %s, GetDirectionVector() = %s, GetFilterData() = %s, GetLength() = %s, GetNormalVector() = %s, GetSweepRadius() = %s, GetType() = %s, GetVertex1() = %s, GetVertex2() = %s, IsSensor() = %s)"""% tuple(str(a) for a in\ (self.density,self.filter,self.friction,self.restitution,self.userData,self.GetBody(),self.GetCoreVertex1(),self.GetCoreVertex2(),self.GetCorner1Vector(),self.GetCorner2Vector(),self.GetDirectionVector(),self.GetFilterData(),self.GetLength(),self.GetNormalVector(),self.GetSweepRadius(),self.GetType(),self.GetVertex1(),self.GetVertex2(),self.IsSensor())) %} } %extend b2FilterData { %pythoncode %{ def __repr__(self): return """b2FilterData( categoryBits = %s, groupIndex = %s, maskBits = %s)"""% tuple(str(a) for a in\ (self.categoryBits,self.groupIndex,self.maskBits)) %} } %extend b2GearJoint { %pythoncode %{ def __repr__(self): return """b2GearJoint( J = %s, body1 = %s, body2 = %s, collideConnected = %s, constant = %s, ground1 = %s, ground2 = %s, groundAnchor1 = %s, groundAnchor2 = %s, impulse = %s, joint1 = %s, joint2 = %s, localAnchor1 = %s, localAnchor2 = %s, mass = %s, prismatic1 = %s, prismatic2 = %s, ratio = %s, revolute1 = %s, revolute2 = %s, type = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s)"""% tuple(str(a) for a in\ (self.J,self.body1,self.body2,self.collideConnected,self.constant,self.ground1,self.ground2,self.groundAnchor1,self.groundAnchor2,self.impulse,self.joint1,self.joint2,self.localAnchor1,self.localAnchor2,self.mass,self.prismatic1,self.prismatic2,self.ratio,self.revolute1,self.revolute2,self.type,self.userData,self.GetAnchor1(),self.GetAnchor2())) %} } %extend b2GearJointDef { %pythoncode %{ def __repr__(self): return """b2GearJointDef( body1 = %s, body2 = %s, collideConnected = %s, joint1 = %s, joint2 = %s, ratio = %s, type = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.joint1,self.joint2,self.ratio,self.type,self.userData)) %} } %extend b2GravityController { %pythoncode %{ def __repr__(self): return """b2GravityController( G = %s, invSqr = %s)"""% tuple(str(a) for a in\ (self.G,self.invSqr)) %} } %extend b2GravityControllerDef { %pythoncode %{ def __repr__(self): return """b2GravityControllerDef( G = %s, invSqr = %s)"""% tuple(str(a) for a in\ (self.G,self.invSqr)) %} } %extend b2Jacobian { %pythoncode %{ def __repr__(self): return """b2Jacobian( angular1 = %s, angular2 = %s, linear1 = %s, linear2 = %s)"""% tuple(str(a) for a in\ (self.angular1,self.angular2,self.linear1,self.linear2)) %} } %extend b2Joint { %pythoncode %{ def __repr__(self): return """b2Joint( body1 = %s, body2 = %s, collideConnected = %s, type = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.type,self.userData,self.GetAnchor1(),self.GetAnchor2())) %} } %extend b2JointDef { %pythoncode %{ def __repr__(self): return """b2JointDef( body1 = %s, body2 = %s, collideConnected = %s, type = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.type,self.userData)) %} } %extend b2JointEdge { %pythoncode %{ def __repr__(self): return """b2JointEdge( joint = %s, other = %s)"""% tuple(str(a) for a in\ (self.joint,self.other)) %} } %extend b2LineJoint { %pythoncode %{ def __repr__(self): return """b2LineJoint( K = %s, a1 = %s, a2 = %s, axis = %s, body1 = %s, body2 = %s, collideConnected = %s, enableLimit = %s, enableMotor = %s, impulse = %s, limitState = %s, localAnchor1 = %s, localAnchor2 = %s, localXAxis1 = %s, localYAxis1 = %s, lowerTranslation = %s, maxMotorForce = %s, motorImpulse = %s, motorMass = %s, motorSpeed = %s, perp = %s, s1 = %s, s2 = %s, type = %s, upperTranslation = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s, GetJointSpeed() = %s, GetJointTranslation() = %s, GetLowerLimit() = %s, GetMotorForce() = %s, GetUpperLimit() = %s, IsLimitEnabled() = %s, IsMotorEnabled() = %s)"""% tuple(str(a) for a in\ (self.K,self.a1,self.a2,self.axis,self.body1,self.body2,self.collideConnected,self.enableLimit,self.enableMotor,self.impulse,self.limitState,self.localAnchor1,self.localAnchor2,self.localXAxis1,self.localYAxis1,self.lowerTranslation,self.maxMotorForce,self.motorImpulse,self.motorMass,self.motorSpeed,self.perp,self.s1,self.s2,self.type,self.upperTranslation,self.userData,self.GetAnchor1(),self.GetAnchor2(),self.GetJointSpeed(),self.GetJointTranslation(),self.GetLowerLimit(),self.GetMotorForce(),self.GetUpperLimit(),self.IsLimitEnabled(),self.IsMotorEnabled())) %} } %extend b2LineJointDef { %pythoncode %{ def __repr__(self): return """b2LineJointDef( body1 = %s, body2 = %s, collideConnected = %s, enableLimit = %s, enableMotor = %s, localAnchor1 = %s, localAnchor2 = %s, localAxis1 = %s, lowerTranslation = %s, maxMotorForce = %s, motorSpeed = %s, type = %s, upperTranslation = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.enableLimit,self.enableMotor,self.localAnchor1,self.localAnchor2,self.localAxis1,self.lowerTranslation,self.maxMotorForce,self.motorSpeed,self.type,self.upperTranslation,self.userData)) %} } %extend b2Manifold { %pythoncode %{ def __repr__(self): return """b2Manifold( normal = %s, pointCount = %s, points = %s)"""% tuple(str(a) for a in\ (self.normal,self.pointCount,self.points)) %} } %extend b2ManifoldPoint { %pythoncode %{ def __repr__(self): return """b2ManifoldPoint( id = %s, localPoint1 = %s, localPoint2 = %s, normalImpulse = %s, separation = %s, tangentImpulse = %s)"""% tuple(str(a) for a in\ (self.id,self.localPoint1,self.localPoint2,self.normalImpulse,self.separation,self.tangentImpulse)) %} } %extend b2MassData { %pythoncode %{ def __repr__(self): return """b2MassData( I = %s, center = %s, mass = %s)"""% tuple(str(a) for a in\ (self.I,self.center,self.mass)) %} } %extend b2Mat22 { %pythoncode %{ def __repr__(self): return """b2Mat22( col1 = %s, col2 = %s, GetAngle() = %s)"""% tuple(str(a) for a in\ (self.col1,self.col2,self.GetAngle())) %} } %extend b2Mat33 { %pythoncode %{ def __repr__(self): return """b2Mat33( col1 = %s, col2 = %s, col3 = %s)"""% tuple(str(a) for a in\ (self.col1,self.col2,self.col3)) %} } %extend b2MouseJoint { %pythoncode %{ def __repr__(self): return """b2MouseJoint( C = %s, beta = %s, body1 = %s, body2 = %s, collideConnected = %s, dampingRatio = %s, frequencyHz = %s, gamma = %s, impulse = %s, localAnchor = %s, mass = %s, maxForce = %s, target = %s, type = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s)"""% tuple(str(a) for a in\ (self.C,self.beta,self.body1,self.body2,self.collideConnected,self.dampingRatio,self.frequencyHz,self.gamma,self.impulse,self.localAnchor,self.mass,self.maxForce,self.target,self.type,self.userData,self.GetAnchor1(),self.GetAnchor2())) %} } %extend b2MouseJointDef { %pythoncode %{ def __repr__(self): return """b2MouseJointDef( body1 = %s, body2 = %s, collideConnected = %s, dampingRatio = %s, frequencyHz = %s, maxForce = %s, target = %s, type = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.dampingRatio,self.frequencyHz,self.maxForce,self.target,self.type,self.userData)) %} } %extend b2NullContact { %pythoncode %{ def __repr__(self): return """b2NullContact( flags = %s, manifoldCount = %s, node1 = %s, node2 = %s, s_initialized = %s, s_registers = %s, shape1 = %s, shape2 = %s, toi = %s, GetManifolds() = %s, IsSolid() = %s, e_islandFlag = %s, e_nonSolidFlag = %s, e_slowFlag = %s, e_toiFlag = %s)"""% tuple(str(a) for a in\ (self.flags,self.manifoldCount,self.node1,self.node2,self.s_initialized,self.s_registers,self.shape1,self.shape2,self.toi,self.GetManifolds(),self.IsSolid(),self.e_islandFlag,self.e_nonSolidFlag,self.e_slowFlag,self.e_toiFlag)) %} } %extend b2OBB { %pythoncode %{ def __repr__(self): return """b2OBB( R = %s, center = %s, extents = %s)"""% tuple(str(a) for a in\ (self.R,self.center,self.extents)) %} } %extend b2Pair { %pythoncode %{ def __repr__(self): return """b2Pair( proxyId1 = %s, proxyId2 = %s, status = %s, userData = %s, IsBuffered() = %s, IsFinal() = %s, IsRemoved() = %s, e_pairBuffered = %s, e_pairFinal = %s, e_pairRemoved = %s)"""% tuple(str(a) for a in\ (self.proxyId1,self.proxyId2,self.status,self.userData,self.IsBuffered(),self.IsFinal(),self.IsRemoved(),self.e_pairBuffered,self.e_pairFinal,self.e_pairRemoved)) %} } %extend b2PairCallback { %pythoncode %{ def __repr__(self): return "b2PairCallback()" %} } %extend b2PairManager { %pythoncode %{ def __repr__(self): return """b2PairManager( broadPhase = %s, callback = %s, freePair = %s, hashTable = %s, pairBuffer = %s, pairBufferCount = %s, pairCount = %s, pairs = %s)"""% tuple(str(a) for a in\ (self.broadPhase,self.callback,self.freePair,self.hashTable,self.pairBuffer,self.pairBufferCount,self.pairCount,self.pairs)) %} } %extend b2PolygonDef { %pythoncode %{ def __repr__(self): return """b2PolygonDef( density = %s, filter = %s, friction = %s, isSensor = %s, restitution = %s, type = %s, userData = %s, vertexCount = %s, vertices = %s)"""% tuple(str(a) for a in\ (self.density,self.filter,self.friction,self.isSensor,self.restitution,self.type,self.userData,self.vertexCount,self.vertices)) %} } %extend b2PolygonShape { %pythoncode %{ def __repr__(self): return """b2PolygonShape( coreVertices = %s, density = %s, filter = %s, friction = %s, normals = %s, restitution = %s, userData = %s, vertices = %s, GetBody() = %s, GetCentroid() = %s, GetFilterData() = %s, GetOBB() = %s, GetSweepRadius() = %s, GetType() = %s, GetVertexCount() = %s, IsSensor() = %s)"""% tuple(str(a) for a in\ (self.coreVertices,self.density,self.filter,self.friction,self.normals,self.restitution,self.userData,self.vertices,self.GetBody(),self.GetCentroid(),self.GetFilterData(),self.GetOBB(),self.GetSweepRadius(),self.GetType(),self.GetVertexCount(),self.IsSensor())) %} } %extend b2PrismaticJoint { %pythoncode %{ def __repr__(self): return """b2PrismaticJoint( K = %s, a1 = %s, a2 = %s, axis = %s, body1 = %s, body2 = %s, collideConnected = %s, enableLimit = %s, enableMotor = %s, impulse = %s, limitState = %s, localAnchor1 = %s, localAnchor2 = %s, localXAxis1 = %s, localYAxis1 = %s, lowerTranslation = %s, maxMotorForce = %s, motorImpulse = %s, motorMass = %s, motorSpeed = %s, perp = %s, referenceAngle = %s, s1 = %s, s2 = %s, type = %s, upperTranslation = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s, GetJointSpeed() = %s, GetJointTranslation() = %s, GetLowerLimit() = %s, GetMotorForce() = %s, GetUpperLimit() = %s, IsLimitEnabled() = %s, IsMotorEnabled() = %s)"""% tuple(str(a) for a in\ (self.K,self.a1,self.a2,self.axis,self.body1,self.body2,self.collideConnected,self.enableLimit,self.enableMotor,self.impulse,self.limitState,self.localAnchor1,self.localAnchor2,self.localXAxis1,self.localYAxis1,self.lowerTranslation,self.maxMotorForce,self.motorImpulse,self.motorMass,self.motorSpeed,self.perp,self.referenceAngle,self.s1,self.s2,self.type,self.upperTranslation,self.userData,self.GetAnchor1(),self.GetAnchor2(),self.GetJointSpeed(),self.GetJointTranslation(),self.GetLowerLimit(),self.GetMotorForce(),self.GetUpperLimit(),self.IsLimitEnabled(),self.IsMotorEnabled())) %} } %extend b2PrismaticJointDef { %pythoncode %{ def __repr__(self): return """b2PrismaticJointDef( body1 = %s, body2 = %s, collideConnected = %s, enableLimit = %s, enableMotor = %s, localAnchor1 = %s, localAnchor2 = %s, localAxis1 = %s, lowerTranslation = %s, maxMotorForce = %s, motorSpeed = %s, referenceAngle = %s, type = %s, upperTranslation = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.enableLimit,self.enableMotor,self.localAnchor1,self.localAnchor2,self.localAxis1,self.lowerTranslation,self.maxMotorForce,self.motorSpeed,self.referenceAngle,self.type,self.upperTranslation,self.userData)) %} } %extend b2Proxy { %pythoncode %{ def __repr__(self): return """b2Proxy( lowerBounds = %s, overlapCount = %s, timeStamp = %s, upperBounds = %s, userData = %s, IsValid() = %s)"""% tuple(str(a) for a in\ (self.lowerBounds,self.overlapCount,self.timeStamp,self.upperBounds,self.userData,self.IsValid())) %} } %extend b2PulleyJoint { %pythoncode %{ def __repr__(self): return """b2PulleyJoint( body1 = %s, body2 = %s, collideConnected = %s, constant = %s, ground = %s, groundAnchor1 = %s, groundAnchor2 = %s, impulse = %s, length1 = %s, length2 = %s, limitImpulse1 = %s, limitImpulse2 = %s, limitMass1 = %s, limitMass2 = %s, limitState1 = %s, limitState2 = %s, localAnchor1 = %s, localAnchor2 = %s, maxLength1 = %s, maxLength2 = %s, pulleyMass = %s, ratio = %s, state = %s, type = %s, u1 = %s, u2 = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.constant,self.ground,self.groundAnchor1,self.groundAnchor2,self.impulse,self.length1,self.length2,self.limitImpulse1,self.limitImpulse2,self.limitMass1,self.limitMass2,self.limitState1,self.limitState2,self.localAnchor1,self.localAnchor2,self.maxLength1,self.maxLength2,self.pulleyMass,self.ratio,self.state,self.type,self.u1,self.u2,self.userData,self.GetAnchor1(),self.GetAnchor2())) %} } %extend b2PulleyJointDef { %pythoncode %{ def __repr__(self): return """b2PulleyJointDef( body1 = %s, body2 = %s, collideConnected = %s, groundAnchor1 = %s, groundAnchor2 = %s, length1 = %s, length2 = %s, localAnchor1 = %s, localAnchor2 = %s, maxLength1 = %s, maxLength2 = %s, ratio = %s, type = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.groundAnchor1,self.groundAnchor2,self.length1,self.length2,self.localAnchor1,self.localAnchor2,self.maxLength1,self.maxLength2,self.ratio,self.type,self.userData)) %} } %extend b2RevoluteJoint { %pythoncode %{ def __repr__(self): return """b2RevoluteJoint( body1 = %s, body2 = %s, collideConnected = %s, enableLimit = %s, enableMotor = %s, impulse = %s, limitState = %s, localAnchor1 = %s, localAnchor2 = %s, lowerAngle = %s, mass = %s, maxMotorTorque = %s, motorImpulse = %s, motorMass = %s, motorSpeed = %s, referenceAngle = %s, type = %s, upperAngle = %s, userData = %s, GetAnchor1() = %s, GetAnchor2() = %s, GetJointAngle() = %s, GetJointSpeed() = %s, GetLowerLimit() = %s, GetMotorTorque() = %s, GetUpperLimit() = %s, IsLimitEnabled() = %s, IsMotorEnabled() = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.enableLimit,self.enableMotor,self.impulse,self.limitState,self.localAnchor1,self.localAnchor2,self.lowerAngle,self.mass,self.maxMotorTorque,self.motorImpulse,self.motorMass,self.motorSpeed,self.referenceAngle,self.type,self.upperAngle,self.userData,self.GetAnchor1(),self.GetAnchor2(),self.GetJointAngle(),self.GetJointSpeed(),self.GetLowerLimit(),self.GetMotorTorque(),self.GetUpperLimit(),self.IsLimitEnabled(),self.IsMotorEnabled())) %} } %extend b2RevoluteJointDef { %pythoncode %{ def __repr__(self): return """b2RevoluteJointDef( body1 = %s, body2 = %s, collideConnected = %s, enableLimit = %s, enableMotor = %s, localAnchor1 = %s, localAnchor2 = %s, lowerAngle = %s, maxMotorTorque = %s, motorSpeed = %s, referenceAngle = %s, type = %s, upperAngle = %s, userData = %s)"""% tuple(str(a) for a in\ (self.body1,self.body2,self.collideConnected,self.enableLimit,self.enableMotor,self.localAnchor1,self.localAnchor2,self.lowerAngle,self.maxMotorTorque,self.motorSpeed,self.referenceAngle,self.type,self.upperAngle,self.userData)) %} } %extend b2Segment { %pythoncode %{ def __repr__(self): return """b2Segment( p1 = %s, p2 = %s)"""% tuple(str(a) for a in\ (self.p1,self.p2)) %} } %extend b2Shape { %pythoncode %{ def __repr__(self): return """b2Shape( density = %s, filter = %s, friction = %s, restitution = %s, userData = %s, GetBody() = %s, GetFilterData() = %s, GetSweepRadius() = %s, GetType() = %s, IsSensor() = %s)"""% tuple(str(a) for a in\ (self.density,self.filter,self.friction,self.restitution,self.userData,self.GetBody(),self.GetFilterData(),self.GetSweepRadius(),self.GetType(),self.IsSensor())) %} } %extend b2ShapeDef { %pythoncode %{ def __repr__(self): return """b2ShapeDef( density = %s, filter = %s, friction = %s, isSensor = %s, restitution = %s, type = %s, userData = %s)"""% tuple(str(a) for a in\ (self.density,self.filter,self.friction,self.isSensor,self.restitution,self.type,self.userData)) %} } %extend b2StackAllocator { %pythoncode %{ def __repr__(self): return """b2StackAllocator( GetMaxAllocation() = %s)"""% tuple(str(a) for a in\ (self.GetMaxAllocation())) %} } %extend b2StackEntry { %pythoncode %{ def __repr__(self): return """b2StackEntry( data = %s, size = %s, usedMalloc = %s)"""% tuple(str(a) for a in\ (self.data,self.size,self.usedMalloc)) %} } %extend b2Sweep { %pythoncode %{ def __repr__(self): return """b2Sweep( a = %s, a0 = %s, c = %s, c0 = %s, localCenter = %s, t0 = %s)"""% tuple(str(a) for a in\ (self.a,self.a0,self.c,self.c0,self.localCenter,self.t0)) %} } %extend b2TensorDampingController { %pythoncode %{ def __repr__(self): return """b2TensorDampingController( T = %s, maxTimestep = %s)"""% tuple(str(a) for a in\ (self.T,self.maxTimestep)) %} } %extend b2TensorDampingControllerDef { %pythoncode %{ def __repr__(self): return """b2TensorDampingControllerDef( T = %s, maxTimestep = %s)"""% tuple(str(a) for a in\ (self.T,self.maxTimestep)) %} } %extend b2TimeStep { %pythoncode %{ def __repr__(self): return """b2TimeStep( dt = %s, dtRatio = %s, inv_dt = %s, positionIterations = %s, velocityIterations = %s, warmStarting = %s)"""% tuple(str(a) for a in\ (self.dt,self.dtRatio,self.inv_dt,self.positionIterations,self.velocityIterations,self.warmStarting)) %} } %extend b2Vec2 { %pythoncode %{ def __repr__(self): return """b2Vec2( x = %s, y = %s, IsValid() = %s)"""% tuple(str(a) for a in\ (self.x,self.y,self.IsValid())) %} } %extend b2Vec3 { %pythoncode %{ def __repr__(self): return """b2Vec3( x = %s, y = %s, z = %s)"""% tuple(str(a) for a in\ (self.x,self.y,self.z)) %} } %extend b2Version { %pythoncode %{ def __repr__(self): return """b2Version( major = %s, minor = %s, revision = %s)"""% tuple(str(a) for a in\ (self.major,self.minor,self.revision)) %} } %extend b2World { %pythoncode %{ def __repr__(self): return """b2World( doSleep = %s, gravity = %s, groundBody = %s, worldAABB = %s, GetBodyCount() = %s, GetContactCount() = %s, GetControllerCount() = %s, GetJointCount() = %s, GetPairCount() = %s, GetProxyCount() = %s)"""% tuple(str(a) for a in\ (self.doSleep,self.gravity,self.groundBody,self.worldAABB,self.GetBodyCount(),self.GetContactCount(),self.GetControllerCount(),self.GetJointCount(),self.GetPairCount(),self.GetProxyCount())) %} } %extend b2XForm { %pythoncode %{ def __repr__(self): return """b2XForm( R = %s, position = %s)"""% tuple(str(a) for a in\ (self.R,self.position)) %} } python-box2d-2.0.2+svn20100109.244/__init__.py0000644000000000000000000000225211154051203016577 0ustar rootroot#!/usr/bin/python # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com # Python version Copyright (c) 2008-2009 Ken Lauer / sirkne at gmail dot com # # Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com) # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # from Box2D import * __version__ = '2.0.2b1' __version_info__ = (2,0,2,1)