From da351cb11c9cc0a36492c9f50fa993afb4465c3b Mon Sep 17 00:00:00 2001 From: Brian Jordan Date: Fri, 10 Jul 2009 13:04:31 +0000 Subject: Upgraded to elements 12, pybox2d 2.0.2b1 --- (limited to 'elements/add_objects.py') diff --git a/elements/add_objects.py b/elements/add_objects.py deleted file mode 100644 index 3842b75..0000000 --- a/elements/add_objects.py +++ /dev/null @@ -1,598 +0,0 @@ -""" -This file is part of the 'Elements' Project -Elements is a 2D Physics API for Python (supporting Box2D2) - -Copyright (C) 2008, The Elements Team, - -Home: http://elements.linuxuser.at -IRC: #elements on irc.freenode.org - -Code: http://www.assembla.com/wiki/show/elements - svn co http://svn2.assembla.com/svn/elements - -License: GPLv3 | See LICENSE for the full text -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 3 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, see . -""" -from locals import * -from elements import box2d - -# Imports -from math import pi -from math import sqrt -from math import asin - -import tools_poly - -class Add: - element_count = 0 - - def __init__(self, parent): - self.parent = parent - - def ground(self): - """ Add a static ground to the scene - - Return: box2d.b2Body - """ - return self._rect((-10.0, 0.0), 50.0, 0.1, dynamic=False) - - def triangle(self, pos, sidelength, dynamic=True, density=1.0, restitution=0.16, friction=0.5, screenCoord=True): - """ Add a triangle | pos & a in the current input unit system (meters or pixels) - - Parameters: - pos .... position (x,y) - sidelength ...... sidelength - other .. see [physics parameters] - - Return: box2d.b2Body - """ - vertices = [(-sidelength, 0.0), (sidelength, 0.0), (0.0, 2*sidelength)] - return self.poly(pos, vertices, dynamic, density, restitution, friction, screenCoord) - - def ball(self, pos, radius, dynamic=True, density=1.0, restitution=0.16, friction=0.5, screenCoord=True): - """ Add a dynamic ball at pos after correcting the positions and legths to the internal - meter system if neccessary (if INPUT_PIXELS), then call self._add_ball(...) - - Parameters: - pos ..... position (x,y) - radius .. circle radius - other ... see [physics parameters] - - Return: box2d.b2Body - """ - # Bring coordinates into the world coordinate system (flip, camera offset, ...) - if screenCoord: x, y = self.parent.to_world(pos) - else: x, y = pos - - - if self.parent.input == INPUT_PIXELS: - x /= self.parent.ppm - y /= self.parent.ppm - radius /= self.parent.ppm - - return self._ball((x,y), radius, dynamic, density, restitution, friction) - - def _ball(self, pos, radius, dynamic=True, density=1.0, restitution=0.16, friction=0.5): - # Add a ball without correcting any settings - # meaning, pos and vertices are in meters - # Define the body - x, y = pos - bodyDef = box2d.b2BodyDef() - bodyDef.position.Set(x, y) - bodyDef.sleepFlag = True -# bodyDef.allowSleep(True) - - userData = { 'color' : self.parent.get_color() } - bodyDef.userData = userData - - # Create the Body - if not dynamic: - density = 0 - - body = self.parent.world.CreateBody(bodyDef) - - self.parent.element_count += 1 - - # Add a shape to the Body - circleDef = box2d.b2CircleDef() - circleDef.density = density - circleDef.radius = radius - circleDef.restitution = restitution - circleDef.friction = friction - - body.CreateShape(circleDef) - body.SetMassFromShapes(); - - return body - - def rect(self, pos, width, height, angle=0, dynamic=True, density=1.0, restitution=0.16, friction=0.5, screenCoord=True): - """ Add a dynamic rectangle with input unit according to self.input (INPUT_PIXELS or INPUT_METERS) - Correcting the positions to meters and calling self._add_rect() - - Parameters: - pos ..... position (x,y) - width ....... horizontal line - height ....... vertical line - angle ........ in degrees (0 .. 360) - other ... see [physics parameters] - - Return: box2d.b2Body - """ - # Bring coordinates into the world coordinate system (flip, camera offset, ...) - if screenCoord: x, y = self.parent.to_world(pos) - else: x, y = pos - - # If required, translate pixel -> meters - if self.parent.input == INPUT_PIXELS: - x /= self.parent.ppm - y /= self.parent.ppm - width /= self.parent.ppm - height /= self.parent.ppm - - # grad -> radians - angle = (angle * pi) / 180 - - return self._rect((x,y), width, height, angle, dynamic, density, restitution, friction) - - - def wall(self, pos1, pos2, width=5, density=1.0, restitution=0.16, friction=0.5, screenCoord=True): - """ Add a static rectangle between two arbitrary points with input unit according to self.input - (INPUT_PIXELS or INPUT_METERS) Correcting the positions to meters and calling self._add_rect() - - Return: box2d.b2Body - """ - if width < 5: width = 5 - - if (pos1[0] < pos2[0]): - x1, y1 = pos1 - x2, y2 = pos2 - else: - x1, y1 = pos2 - x2, y2 = pos1 - - # Bring coordinates into the world coordinate system (flip, camera offset, ...) - if screenCoord: - x1, y1 = self.parent.to_world((x1, y1)) - x2, y2 = self.parent.to_world((x2, y2)) - - # If required, translate pixel -> meters - if self.parent.input == INPUT_PIXELS: - x1 /= self.parent.ppm - y1 /= self.parent.ppm - x2 /= self.parent.ppm - y2 /= self.parent.ppm - width /= self.parent.ppm - - length = sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) )*0.5 - - if width > 0: - halfX = x1 + (x2-x1)*0.5 - halfY = y1 + (y2-y1)*0.5 - - angle = asin( (y2-halfY)/length ) - return self._rect((halfX, halfY), length, width, angle, False, density, restitution, friction) - - def _rect(self, pos, width, height, angle=0, dynamic=True, density=1.0, restitution=0.16, friction=0.5): - # Add a rect without correcting any settings - # meaning, pos and vertices are in meters - # angle is now in radians ((degrees * pi) / 180)) - x, y = pos - bodyDef = box2d.b2BodyDef() - bodyDef.position.Set(x, y) - - userData = { 'color' : self.parent.get_color() } - bodyDef.userData = userData - - # Create the Body - if not dynamic: - density = 0 - - bodyDef.sleepFlag = True - - body = self.parent.world.CreateBody(bodyDef) - - self.parent.element_count += 1 - - # Add a shape to the Body - boxDef = box2d.b2PolygonDef() - - boxDef.SetAsBox(width, height, box2d.b2Vec2(0,0), angle) - boxDef.density = density - boxDef.restitution = restitution - boxDef.friction = friction - body.CreateShape(boxDef) - - body.SetMassFromShapes() - - return body - - def poly(self, pos, vertices, dynamic=True, density=1.0, restitution=0.16, friction=0.5, screenCoord=True): - """ Add a dynamic polygon, which has the vertices arranged around the poly's center at pos - Correcting the positions to meters if INPUT_PIXELS, and calling self._add_poly() - - Parameters: - pos ....... position (x,y) - vertices .. vertices arranged around the center - other ... see [physics parameters] - - Return: box2d.b2Body - """ - # Bring coordinates into the world coordinate system (flip, camera offset, ...) - if screenCoord: x, y = self.parent.to_world(pos) - else: x, y = pos - - # If required, translate pixel -> meters - if self.parent.input == INPUT_PIXELS: - # translate pixel -> meters - x /= self.parent.ppm - y /= self.parent.ppm - - # Translate vertices from pixels to meters - v_new = [] - for v in vertices: - vx, vy = v - v_new.append((vx/self.parent.ppm, vy/self.parent.ppm)) - vertices = v_new - - return self._poly((x,y), vertices, dynamic, density, restitution, friction) - - def _poly(self, pos, vertices, dynamic=True, density=1.0, restitution=0.16, friction=0.5): - # add a centered poly at pos without correcting any settings - # meaning, pos and vertices are in meters - x, y = pos - bodyDef = box2d.b2BodyDef() - bodyDef.position.Set(x, y) - bodyDef.sleepFlag = True - - userData = { 'color' : self.parent.get_color() } - bodyDef.userData = userData - - # Create the Body - if not dynamic: - density = 0 - - body = self.parent.world.CreateBody(bodyDef) - - self.parent.element_count += 1 - - # Add a shape to the Body - polyDef = box2d.b2PolygonDef() - polyDef.vertexCount = len(vertices) - for i in range(len(vertices)): - vx, vy = vertices[i] - polyDef.setVertex(i, box2d.b2Vec2(vx, vy)) - - polyDef.density = density - polyDef.restitution = restitution - polyDef.friction = friction - - body.CreateShape(polyDef) - body.SetMassFromShapes() - - return body - - def concavePoly(self, vertices, dynamic=True, density=1.0, restitution=0.16, friction=0.5, screenCoord=True): - # 1. Step: Reduce - # Detect if the polygon is closed or open - if vertices[0] != vertices[-1]: - is_closed = False - else: - is_closed = True - - # Continue reducing the vertecs - x, y = c = tools_poly.calc_center(vertices) - vertices = tools_poly.poly_center_vertices(vertices) - - # Bring coordinates into the world coordinate system (flip, camera offset, ...) - if screenCoord: x, y = self.parent.to_world(c) - else: x, y = c - - # If required, translate pixel -> meters - if self.parent.input == INPUT_PIXELS: - # translate pixel -> meters - x /= self.parent.ppm - y /= self.parent.ppm - - # Let's add the body - bodyDef = box2d.b2BodyDef() - bodyDef.position.Set(x, y) - bodyDef.sleepFlag = True - - userData = { 'color' : self.parent.get_color() } - bodyDef.userData = userData - - # Create the Body - if not dynamic: - density = 0 - - body = self.parent.world.CreateBody(bodyDef) - - self.parent.element_count += 1 - - # Create the reusable Box2D polygon and circle definitions - polyDef = box2d.b2PolygonDef() - polyDef.vertexCount = 4 # rectangle - polyDef.density = density - polyDef.restitution = restitution - polyDef.friction = friction - - circleDef = box2d.b2CircleDef() - circleDef.density = density - circleDef.radius = 0.086 - circleDef.restitution = restitution - circleDef.friction = friction - - # Set the scale factor - factor = 8.0 - - v2 = box2d.b2Vec2().fromTuple(vertices[0]) - for v in vertices[1:]: - v1 = v2.copy() - v2 = box2d.b2Vec2().fromTuple(v) - - vdir = v2-v1 # (v2x-v1x, v2y-v1y) - vdir.Normalize() - - # we need a little size for the end part - vn = box2d.b2Vec2(-vdir.y*factor, vdir.x*factor) - - v = [ v1+vn, v1-vn, v2-vn, v2+vn ] - - # Create a line (rect) for each part of the polygon, - # and attach it to the body - for i in range(len(v)): - polyDef.setVertex(i, v[i] / self.parent.ppm) - - if not tools_poly.checkDef(polyDef): - print "concavePoly: Created an invalid polygon!" - return [], 0 - - body.CreateShape(polyDef) - - # Now add a circle to the points between the rects - # to avoid sharp edges and gaps - if not is_closed and v2.tuple() == vertices[-1]: - # Don't add a circle at the end - break - - circleDef.localPosition = v2 / self.parent.ppm - body.CreateShape(circleDef) - - # Now, all shapes have been attached - body.SetMassFromShapes() - - # Return hard and soft reduced vertices - return body - - def complexPoly(self, vertices, dynamic=True, density=1.0, restitution=0.16, friction=0.5): - # 1. Step: Reduce - # 2. Step: See if start and end are close, if so then close the polygon - # 3. Step: Detect if convex or concave - # 4. Step: Start self.convexPoly or self.concavePoly - vertices, is_convex = tools_poly.reduce_poly_by_angle(vertices) - #print "->", is_convex - - # If start and endpoints are close to each other, close polygon - x1, y1 = vertices[0] - x2, y2 = vertices[-1] - dx = x2 - x1 - dy = y2 - y1 - l = sqrt((dx*dx)+(dy*dy)) - - if l < 50: - vertices[-1] = vertices[0] - else: - # Never convex if open (we decide so :) - is_convex = False - - if tools_poly.is_line(vertices): - # Lines shall be drawn by self.concavePoly(...) - print "is line" - is_convex = False - - if is_convex: - print "convex" - return self.convexPoly(vertices, dynamic, density, restitution, friction), vertices - else: - print "concave" - return self.concavePoly(vertices, dynamic, density, restitution, friction), vertices - - - def convexPoly(self, vertices, dynamic=True, density=1.0, restitution=0.16, friction=0.5): - """ Add a complex polygon with vertices in absolute positions (meters or pixels, according - to INPUT_PIXELS or INPUT_METERS). This function does the reduction and convec hulling - of the poly, and calls add_poly(...) - - Parameters: - vertices .. absolute vertices positions - other ..... see [physics parameters] - - Return: box2d.b2Body - """ - # NOTE: Box2D has a maximum poly vertex count, defined in Common/box2d.b2Settings.h (box2d.b2_maxPolygonVertices) - # We need to make sure, that we reach that by reducing the poly with increased tolerance - # Reduce Polygon - tolerance = 10 #5 - v_new = vertices - while len(v_new) > box2d.b2_maxPolygonVertices: - tolerance += 1 - v_new = tools_poly.reduce_poly(vertices, tolerance) - - print "convexPoly: Polygon reduced from %i to %i vertices | tolerance: %i" % (len(vertices), len(v_new), tolerance) - vertices = v_new - - # So poly should be alright now - # Continue reducing the vertecs - vertices_orig_reduced = vertices - vertices = tools_poly.poly_center_vertices(vertices) - - vertices = tools_poly.convex_hull(vertices) - - if len(vertices) < 3: - return - - # Define the body - x, y = c = tools_poly.calc_center(vertices_orig_reduced) - return self.poly((x,y), vertices, dynamic, density, restitution, friction) - - def to_b2vec(self,pt): - pt = self.parent.to_world(pt) - ptx, pty = pt - ptx /= self.parent.ppm - pty /= self.parent.ppm - pt = box2d.b2Vec2(ptx, pty) - return pt - # Alex Levenson's added joint methods: - def distanceJoint(self,b1,b2,p1,p2): - # Distance Joint - p1 = self.to_b2vec(p1) - p2 = self.to_b2vec(p2) - - jointDef = box2d.b2DistanceJointDef() - jointDef.Initialize(b1, b2, p1, p2) - jointDef.collideConnected = True - self.parent.world.CreateJoint(jointDef) - - def fixedJoint(self, *args): - if len(args) == 2: - # Fixed Joint to the Background, don't assume the center of the body - b1 = self.parent.world.GetGroundBody() - b2 = args[0] - p1 = self.to_b2vec(args[1]) - - jointDef = box2d.b2RevoluteJointDef() - jointDef.Initialize(b1, b2, p1) - self.parent.world.CreateJoint(jointDef) - elif len(args) == 1: - # Fixed Joint to the Background, assume the center of the body - b1 = self.parent.world.GetGroundBody() - b2 = args[0] - p1 = b2.GetWorldCenter() - - jointDef = box2d.b2RevoluteJointDef() - jointDef.Initialize(b1, b2, p1) - - self.parent.world.CreateJoint(jointDef) - - def revoluteJoint(self,b1,b2,p1): - # revolute joint between to bodies - p1 = self.to_b2vec(p1) - - jointDef = box2d.b2RevoluteJointDef() - jointDef.Initialize(b1, b2, p1) - - self.parent.world.CreateJoint(jointDef) - - # prismatic joint + pully not fully functional at this point - def prismaticJoint(self,b1,b2,Axis=(0.0,1.0),lower=-2,upper=2): - jointDef = box2d.b2PrismaticJointDef() - worldAxis = box2d.b2Vec2(Axis[0],Axis[1]) - jointDef.Initialize(b1, b2, b1.GetWorldCenter(), worldAxis) - jointDef.lowerTranslation = lower - jointDef.upperTranslation = upper - jointDef.enableLimit = True - - self.parent.world.CreateJoint(jointDef) - - def pully(self,b1,b2,p1,p2,g1,g2,ratio=1.0,maxLength1=5,maxLength2=5): - p1 = self.to_b2vec(p1) - p2 = self.to_b2vec(p2) - g1 = self.to_b2vec(g1) - g2 = self.to_b2vec(g2) - - jointDef = box2d.b2PulleyJointDef() - jointDef.Initialize(b1, b2, g1, g2, p1, p2, ratio) - jointDef.maxLength1 = maxLength1 - jointDef.maxLength2 = maxLength2 - - self.parent.world.CreateJoint(jointDef) - - def motor(self, body,pt,torque=900,speed=-10): - # Fixed Joint to the Background with a motor on it - b1 = self.parent.world.GetGroundBody() - pt = self.to_b2vec(pt) - - jointDef = box2d.b2RevoluteJointDef() - jointDef.Initialize(b1, body, pt) - jointDef.maxMotorTorque = torque - jointDef.motorSpeed = speed - jointDef.enableMotor = True - self.parent.world.CreateJoint(jointDef) - #def jointMotor(self,b1,b2,p1,speed): - # p1 = self.tob2vec(p1) - # jointDef = box2d.b2RevoluteJointDef() - # jointDef.Initialize(b1, b2, p1) - # jointDef. - # - def joint(self, *args): - print "* Add Joint:", args - - if len(args) == 4: - # Distance Joint - b1, b2, p1, p2 = args - - p1 = self.parent.to_world(p1) - p2 = self.parent.to_world(p2) - - p1x, p1y = p1 - p2x, p2y = p2 - - p1x /= self.parent.ppm - p1y /= self.parent.ppm - p2x /= self.parent.ppm - p2y /= self.parent.ppm - - p1 = box2d.b2Vec2(p1x, p1y) - p2 = box2d.b2Vec2(p2x, p2y) - - jointDef = box2d.b2DistanceJointDef() - jointDef.Initialize(b1, b2, p1, p2) - jointDef.collideConnected = True - - self.parent.world.CreateJoint(jointDef) - - elif len(args) == 3: - # Revolute Joint - pass - - elif len(args) == 1: - # Fixed Joint to the Background, assume the center of the body - b1 = self.parent.world.GetGroundBody() - b2 = args[0] - p1 = b2.GetWorldCenter() - - jointDef = box2d.b2RevoluteJointDef() - jointDef.Initialize(b1, b2, p1) - - self.parent.world.CreateJoint(jointDef) - - def mouseJoint(self, body, pos): - pos = self.parent.to_world(pos) - x, y = pos - x /= self.parent.ppm - y /= self.parent.ppm - - mj = box2d.b2MouseJointDef() - mj.body1 = self.parent.world.GetGroundBody() - mj.body2 = body - mj.target = box2d.b2Vec2(x, y) - mj.maxForce = 100.0 * body.GetMass() # give humans POWER! - self.parent.mouseJoint = self.parent.world.CreateJoint(mj).getAsType() - body.WakeUp() - - def remove_mouseJoint(self): - if self.parent.mouseJoint: - self.parent.world.DestroyJoint(self.parent.mouseJoint) - self.parent.mouseJoint = None - -- cgit v0.9.1