From 8ba9d4ae100be129b255230790149f488032fa3c Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Fri, 07 Mar 2014 19:44:11 +0000 Subject: elements cleanup --- (limited to 'elements/elements.py') diff --git a/elements/elements.py b/elements/elements.py index 4033688..06d43cc 100644 --- a/elements/elements.py +++ b/elements/elements.py @@ -9,7 +9,7 @@ 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 + 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 @@ -23,9 +23,9 @@ 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 . +along with this program. If not, see . """ -__version__= '0.11' +__version__ = '0.11' __contact__ = '' # Load Box2D @@ -34,8 +34,8 @@ try: except: print 'Could not load the pybox2d library (Box2D).' print 'Please run "setup.py install" to install the dependencies.' - print - print 'Alternatively, recompile pybox2d for your system and python version.' + print + print 'Or recompile pybox2d for your system and python version.' print "See http://code.google.com/p/pybox2d" exit() @@ -53,90 +53,97 @@ import callbacks import camera # Main Class + + class Elements: """The class which handles all interaction with the box2d engine """ # Settings - run_physics =True # Can pause the simulation - element_count =0 # Element Count - renderer =None # Drawing class (from drawing.py) - input =INPUT_PIXELS # Default Input in Pixels! (can change to INPUT_METERS) - line_width =0 # Line Width in Pixels (0 for fill) - listener =None - - screen_offset = (0, 0) # Offset screen from world coordinate system (x, y) [meter5] - screen_offset_pixel = (0, 0) # Offset screen from world coordinate system (x, y) [pixel] - + run_physics = True # Can pause the simulation + element_count = 0 # Element Count + renderer = None # Drawing class (from drawing.py) + # Default Input in Pixels! (can change to INPUT_METERS) + input_unit = INPUT_PIXELS + line_width = 0 # Line Width in Pixels (0 for fill) + listener = None + + # Offset screen from world coordinate system (x, y) [meter5] + screen_offset = (0, 0) + # Offset screen from world coordinate system (x, y) [pixel] + screen_offset_pixel = (0, 0) + # The internal coordination system is y+=up, x+=right # But it's possible to change the input coords to something else, # they will then be translated on input - inputAxis_x_left = False # positive to the right by default - inputAxis_y_down = True # positive to up by default + inputAxis_x_left = False # positive to the right by default + inputAxis_y_down = True # positive to up by default mouseJoint = None - def __init__(self, screen_size, gravity=(0.0,-9.0), ppm=100.0, renderer='pygame'): + def __init__(self, screen_size, gravity=(0.0, -9.0), ppm=100.0, + renderer='pygame'): """ Init the world with boundaries and gravity, and init colors. - + Parameters: screen_size .. (w, h) -- screen size in pixels [int] gravity ...... (x, y) in m/s^2 [float] default: (0.0, -9.0) ppm .......... pixels per meter [float] default: 100.0 - renderer ..... which drawing method to use (str) default: 'pygame' + renderer ..... which drawing method to use (str) default: + 'pygame' Return: class Elements() """ self.set_screenSize(screen_size) self.set_drawingMethod(renderer) - + # Create Subclasses self.add = add_objects.Add(self) self.callbacks = callbacks.CallbackHandler(self) self.camera = camera.Camera(self) - + # Set Boundaries - self.worldAABB=box2d.b2AABB() + self.worldAABB = box2d.b2AABB() self.worldAABB.lowerBound = (-100.0, -100.0) self.worldAABB.upperBound = (100.0, 100.0) - + # Gravity + Bodies will sleep on outside self.gravity = gravity self.doSleep = True - + # Create the World self.world = box2d.b2World(self.worldAABB, self.gravity, self.doSleep) - # Init Colors + # Init Colors self.init_colors() - + # Set Pixels per Meter self.ppm = ppm - def set_inputUnit(self, input): + def set_inputUnit(self, input_unit): """ Change the input unit to either meter or pixels - + Parameters: input ... INPUT_METERS or INPUT_PIXELS - + Return: - """ - self.input = input - + self.input_unit = input_unit + def set_inputAxisOrigin(self, left=True, top=False): """ Change the origin of the input coordinate system axis - + Parameters: left ... True or False -- x = 0 is at the left? top .... True or False -- y = 0 is at the top? - + Return: - - """ + """ self.inputAxis_x_left = not left self.inputAxis_y_down = top def set_drawingMethod(self, m, *kw): """ Set a drawing method (from drawing.py) - + Parameters: m .... 'pygame' or 'cairo' *kw .. keywords to pass to the initializer of the drawing method @@ -144,86 +151,89 @@ class Elements: Return: True if ok, False if no method identifier m found """ try: - self.renderer = getattr(drawing, "draw_%s" % m) (*kw) + self.renderer = getattr(drawing, "draw_%s" % m)(*kw) return True except AttributeError: return False - + def set_screenSize(self, size): """ Set the current screen size - - Parameters: + + Parameters: size ... (int(width), int(height)) in pixels - + Return: - """ self.display_width, self.display_height = size def init_colors(self): """ Init self.colors with a fix set of hex colors - - Return: - + + Return: - """ self.fixed_color = None self.cur_color = 0 self.colors = [ - "#737934", "#729a55", "#040404", "#1d4e29", "#ae5004", "#615c57", - "#6795ce", "#203d61", "#8f932b" + "#737934", "#729a55", "#040404", "#1d4e29", "#ae5004", "#615c57", + "#6795ce", "#203d61", "#8f932b" ] shuffle(self.colors) def set_color(self, clr): - """ Set a fixed color for all future Elements (until reset_color() is called) - - Parameters: + """ Set a fixed color for all future Elements (until reset_color() + is called) + + Parameters: clr ... Hex '#123123' or RGB ((r), (g), (b)) - + Return: - """ self.fixed_color = clr - + def reset_color(self): """ All Elements from now on will be drawn in random colors - - Return: - + + Return: - """ self.fixed_color = None def get_color(self): - """ Get a color - either the fixed one or the next from self.colors - - Return: clr = ((R), (G), (B)) + """ Get a color - either the fixed one or the next from self.colors + + Return: clr = ((R), (G), (B)) """ - if self.fixed_color != None: + if self.fixed_color is not None: return self.fixed_color - - if self.cur_color == len(self.colors): + + if self.cur_color == len(self.colors): self.cur_color = 0 shuffle(self.colors) - + clr = self.colors[self.cur_color] if clr[0] == "#": clr = tools.hex2rgb(clr) - + self.cur_color += 1 return clr - + def update(self, fps=50.0, vel_iterations=10, pos_iterations=8): """ Update the physics, if not paused (self.run_physics) - + Parameters: fps ............. fps with which the physics engine shall work - vel_iterations .. velocity substeps per step for smoother simulation - pos_iterations .. position substeps per step for smoother simulation - + vel_iterations .. velocity substeps per step for smoother + simulation + pos_iterations .. position substeps per step for smoother + simulation + Return: - """ if self.run_physics: self.world.Step(1.0 / fps, vel_iterations, pos_iterations) def translate_coord(self, point): - """ Flips the coordinates in another coordinate system orientation, if necessary - (screen <> world coordinate system) + """ Flips the coordinates in another coordinate system orientation, + if necessary (screen <> world coordinate system) """ x, y = point @@ -232,46 +242,49 @@ class Elements: if self.inputAxis_y_down: y = self.display_height - y - + return (x, y) - + def translate_coords(self, pointlist): - """ Flips the coordinates in another coordinate system orientation, if necessary - (screen <> world coordinate system) - """ - p_out = [] + """Flips the coordinates in another coordinate system orientation, if + necessary (screen <> world coordinate system) + """ + p_out = [] for p in pointlist: p_out.append(self.translate_coord(p)) return p_out def to_world(self, pos): - """ Transfers a coordinate from the screen to the world coordinate system (pixels) + """ Transfers a coordinate from the screen to the world + coordinate system (pixels) + - Change to the right axis orientation - Include the offset: screen -- world coordinate system - - Include the scale factor (Screen coordinate system might have a scale factor) + - Include the scale factor (Screen coordinate system might have + a scale factor) """ dx, dy = self.screen_offset_pixel - + x = pos[0] / self.camera.scale_factor y = pos[1] / self.camera.scale_factor - + x, y = self.translate_coord((round(x), round(y))) - return (x+dx, y+dy) - + return(x + dx, y + dy) + def to_screen(self, pos): - """ Transfers a coordinate from the world to the screen coordinate system (pixels) - and by the screen offset + """Transfers a coordinate from the world to the screen coordinate + system (pixels) and by the screen offset """ dx, dy = self.screen_offset_pixel x = pos[0] - dx y = pos[1] - dy - + sx, sy = self.translate_coord((x, y)) return (sx * self.camera.scale_factor, sy * self.camera.scale_factor) - + def meter_to_screen(self, i): return i * self.ppm * self.camera.scale_factor - + def get_bodies_at_pos(self, search_point, include_static=False, area=0.01): """ Check if given point (screen coordinates) is inside any body. If yes, return all found bodies, if not found return False @@ -280,11 +293,11 @@ class Elements: sx /= self.ppm sy /= self.ppm - f = area/self.camera.scale_factor + f = area / self.camera.scale_factor - AABB=box2d.b2AABB() - AABB.lowerBound = (sx-f, sy-f) - AABB.upperBound = (sx+f, sy+f) + AABB = box2d.b2AABB() + AABB.lowerBound = (sx - f, sy - f) + AABB.upperBound = (sx + f, sy + f) amount, shapes = self.world.Query(AABB, 2) @@ -297,101 +310,110 @@ class Elements: if not include_static: if body.IsStatic() or body.GetMass() == 0.0: continue - + if s.TestPoint(body.GetXForm(), (sx, sy)): bodylist.append(body) return bodylist - + def draw(self): """ If a drawing method is specified, this function passes the objects to the module in pixels. - + Return: True if the objects were successfully drawn False if the renderer was not set or another error occurred """ self.callbacks.start(CALLBACK_DRAWING_START) - - # No need to run through the loop if there's no way to draw - if not self.renderer: + + # No need to run through the loop if there's no way to draw + if not self.renderer: return False if self.camera.track_body: # Get Body Center - p1 = self.camera.track_body.GetWorldCenter() - + p1 = self.camera.track_body.GetWorldCenter() + # Center the Camera There, False = Don't stop the tracking - self.camera.center(self.to_screen((p1.x*self.ppm, p1.y*self.ppm)), stopTrack=False) - + self.camera.center(self.to_screen((p1.x * self.ppm, + p1.y * self.ppm)), + stopTrack=False) + # Walk through all known elements self.renderer.start_drawing() - + for body in self.world.bodyList: xform = body.GetXForm() shape = body.GetShapeList() angle = body.GetAngle() - + if shape: userdata = body.GetUserData() - clr = userdata['color'] - - for shape in body.shapeList: + if 'color' in userdata: + clr = userdata['color'] + else: + clr = self.colors[0] + + for shape in body.shapeList: type = shape.GetType() - + if type == box2d.e_circleShape: position = box2d.b2Mul(xform, shape.GetLocalPosition()) - - pos = self.to_screen((position.x*self.ppm, position.y*self.ppm)) - self.renderer.draw_circle(clr, pos, self.meter_to_screen(shape.radius), angle) + + pos = self.to_screen((position.x * self.ppm, + position.y * self.ppm)) + + self.renderer.draw_circle( + clr, pos, self.meter_to_screen(shape.radius), angle) elif type == box2d.e_polygonShape: points = [] for v in shape.vertices: pt = box2d.b2Mul(xform, v) - x, y = self.to_screen((pt.x*self.ppm, pt.y*self.ppm)) + x, y = self.to_screen((pt.x * self.ppm, + pt.y * self.ppm)) points.append([x, y]) self.renderer.draw_polygon(clr, points) - + else: - print " unknown shape type:%d" % shape.GetType() - + print "unknown shape type:%d" % shape.GetType() for joint in self.world.jointList: p2 = joint.GetAnchor1() - p2 = self.to_screen((p2.x*self.ppm, p2.y*self.ppm)) - + p2 = self.to_screen((p2.x * self.ppm, p2.y * self.ppm)) + p1 = joint.GetAnchor2() - p1 = self.to_screen((p1.x*self.ppm, p1.y*self.ppm)) - + p1 = self.to_screen((p1.x * self.ppm, p1.y * self.ppm)) + if p1 == p2: - self.renderer.draw_circle((255,255,255), p1, 2, 0) + self.renderer.draw_circle((255, 255, 255), p1, 2, 0) else: - self.renderer.draw_lines((0,0,0), False, [p1, p2], 3) + self.renderer.draw_lines((0, 0, 0), False, [p1, p2], 3) self.callbacks.start(CALLBACK_DRAWING_END) self.renderer.after_drawing() - - return True + return True def mouse_move(self, pos): pos = self.to_world(pos) x, y = pos x /= self.ppm y /= self.ppm - + if self.mouseJoint: - self.mouseJoint.SetTarget((x,y)) + self.mouseJoint.SetTarget((x, y)) def pickle_save(self, fn, additional_vars={}): import cPickle as pickle self.add.remove_mouseJoint() - + if not additional_vars and hasattr(self, '_pickle_vars'): - additional_vars=dict((var, getattr(self, var)) for var in 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')] + save_values = [self.world, box2d.pickle_fix(self.world, + additional_vars, 'save')] try: pickle.dump(save_values, open(fn, 'wb')) @@ -411,13 +433,13 @@ class Elements: try: world, variables = pickle.load(open(fn, 'rb')) world = world._pickle_finalize() - variables = box2d.pickle_fix(world, variables, 'load') + variables = box2d.pickle_fix(world, variables, 'load') except Exception, s: print 'Error while loading world: ', s return - + self.world = world - + if set_vars: # reset the additional saved variables: for var, value in variables.items(): @@ -461,7 +483,8 @@ class Elements: if shapename == "b2CircleShape": modelshape['type'] = 'circle' modelshape['radius'] = shape.radius - modelshape['localPosition'] = shape.localPosition.tuple() + modelshape['localPosition'] = \ + shape.localPosition.tuple() if shapename == "b2PolygonShape": modelshape['type'] = 'polygon' modelshape['vertices'] = shape.vertices @@ -528,19 +551,19 @@ class Elements: def json_load(self, path, serialized=False): import json - self.world.GetGroundBody().userData = {"saveid" : 0} + self.world.GetGroundBody().userData = {"saveid": 0} f = open(path, 'r') worldmodel = json.loads(f.read()) f.close() - #clean world + # clean world for joint in self.world.GetJointList(): self.world.DestroyJoint(joint) for body in self.world.GetBodyList(): if body != self.world.GetGroundBody(): self.world.DestroyBody(body) - #load bodys + # load bodies for body in worldmodel['bodylist']: bodyDef = box2d.b2BodyDef() bodyDef.position = body['position'] @@ -550,7 +573,7 @@ class Elements: #_logger.debug(newBody) newBody.angularVelocity = body['angularVelocity'] newBody.linearVelocity = body['linearVelocity'] - if body.has_key('shapes'): + if 'shapes' in body: for shape in body['shapes']: if shape['type'] == 'polygon': polyDef = box2d.b2PolygonDef() @@ -565,7 +588,7 @@ class Elements: circleDef.density = shape['density'] circleDef.restitution = shape['restitution'] circleDef.friction = shape['friction'] - circleDef.localPosition = shape['localPosition'] + circleDef.localPosition = shape['localPosition'] newBody.CreateShape(circleDef) newBody.SetMassFromShapes() @@ -577,7 +600,7 @@ class Elements: body2 = self.getBodyWithSaveId(joint['body2']) anch2 = joint['anchor2'] jointDef.collideConnected = joint['collideConnected'] - jointDef.Initialize(body1,body2,anch1,anch2) + jointDef.Initialize(body1, body2, anch1, anch2) jointDef.SetUserData(joint['userData']) self.world.CreateJoint(jointDef) if joint['type'] == 'revolute': @@ -585,7 +608,7 @@ class Elements: body1 = self.getBodyWithSaveId(joint['body1']) body2 = self.getBodyWithSaveId(joint['body2']) anchor = joint['anchor'] - jointDef.Initialize(body1,body2,anchor) + jointDef.Initialize(body1, body2, anchor) jointDef.SetUserData(joint['userData']) jointDef.enableMotor = joint['enableMotor'] jointDef.motorSpeed = joint['motorSpeed'] @@ -594,17 +617,17 @@ class Elements: self.additional_vars = {} addvars = {} - for (k,v) in worldmodel['additional_vars'].items(): + for (k, v) in worldmodel['additional_vars'].items(): addvars[k] = v if serialized and 'trackinfo' in addvars: trackinfo = addvars['trackinfo'] for key, info in trackinfo.iteritems(): if not info[3]: - addvars['trackinfo'][key][0] = \ - self.getBodyWithSaveId(info[0]) - addvars['trackinfo'][key][1] = \ - self.getBodyWithSaveId(info[1]) + addvars['trackinfo'][key][0] = \ + self.getBodyWithSaveId(info[0]) + addvars['trackinfo'][key][1] = \ + self.getBodyWithSaveId(info[1]) else: addvars['trackinfo'][key][0] = None addvars['trackinfo'][key][1] = None @@ -612,9 +635,9 @@ class Elements: self.additional_vars = addvars for body in self.world.GetBodyList(): - del body.userData['saveid'] #remove temporary data + del body.userData['saveid'] # remove temporary data - def getBodyWithSaveId(self,saveid): + def getBodyWithSaveId(self, saveid): for body in self.world.GetBodyList(): if body.userData['saveid'] == saveid: return body -- cgit v0.9.1