Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 6ca2703c authored by REINKE Chris's avatar REINKE Chris
Browse files

v0.0.9

- refactored the gui: has different colors schemes, shows realtime factor, debug mode, shows more info about objects
parent 33ef3485
No related branches found
No related tags found
No related merge requests found
......@@ -6,7 +6,7 @@ import numpy as np
def run_scenario_01():
world_config = {
'visible_area': [[-5., 10.],[-5., 5.]],
'visible_area': [[-10., 10.], [-10., 10.]],
'objects': [
{'type': 'Wall', 'id': 1, 'position': [6., 0], 'orientation': 0., 'length': 10.},
{'type': 'Wall', 'id': 2, 'position': [-6., 0], 'orientation': 0., 'length': 10.},
......
......@@ -16,7 +16,7 @@ def main():
age_min = 0
age_max = 99
world_config = {
'visible_area': [[-5., 10.],[-5., 5.]],
'visible_area': [[-10., 10.], [-10., 10.]],
'objects': [
{'type': 'Wall', 'id': 1, 'position': [6., 0], 'orientation': 0., 'length': 10.},
{'type': 'Wall', 'id': 2, 'position': [-6., 0], 'orientation': 0., 'length': 10.},
......@@ -63,7 +63,7 @@ def main():
ari_robot = simulation.objects[50]
# ari_robot.navigation.set_go_towards_human(30)
# ari_robot.navigation.set_human_look_at(30)
ari_robot.navigation.set_go_towards_position([-4., 3.], 0.)
#ari_robot.navigation.set_go_towards_position([-4., 3.], 0.)
group_1 = sim.scripts.GroupNavigation()
simulation.add_script(group_1, id=1001)
......
......@@ -10,7 +10,7 @@ if __name__ == '__main__':
# create an empty room
simulation = mpi_sim.Simulation(
visible_area=[[-5., 10.], [-5., 5.]],
visible_area=[[-10., 10.], [-10., 10.]],
objects=[
{'type': 'Wall', 'position': [6., 0], 'orientation': 0., 'length': 10.},
{'type': 'Wall', 'position': [-6., 0], 'orientation': 0., 'length': 10.},
......
......@@ -65,7 +65,7 @@ class GroupDiscussionScript(mpi_sim.Script):
# create an empty room
simulation = mpi_sim.Simulation(
visible_area = [[-10., 10.],[-10., 10.]],
visible_area = [[0., 10.], [0., 10.]],
objects = [
{'type': 'Wall', 'position': [6., 3.], 'orientation': 0., 'length': 6.}, # east
{'type': 'Wall', 'position': [0., 3.], 'orientation': 0., 'length': 6.}, # west
......
......@@ -22,4 +22,4 @@ from mpi_sim.utils.attrdict import combine_dicts
# import the module library last, so that it can find all other modules in the mpi_sim to load them
import mpi_sim.core.module_library
__version__ = '0.0.8'
__version__ = '0.0.9'
import mpi_sim as sim
import Box2D
from Box2D import (b2ContactListener, b2GetPointStates)
from mpi_sim.utils.box2d_utils import fwDestructionListener
from Box2D import b2ContactListener, b2GetPointStates, b2DestructionListener, b2Fixture, b2Joint
from time import time
class fwDestructionListener(b2DestructionListener):
"""
The destruction listener callback:
"SayGoodbye" is called when a joint or shape is deleted.
"""
def __init__(self, test, **kwargs):
super(fwDestructionListener, self).__init__(**kwargs)
self.test = test
def SayGoodbye(self, obj):
if isinstance(obj, b2Joint):
self.test.JointDestroyed(obj)
elif isinstance(obj, b2Fixture):
self.test.FixtureDestroyed(obj)
class Box2DSimulation(b2ContactListener):
@staticmethod
......@@ -51,10 +68,6 @@ class Box2DSimulation(b2ContactListener):
# TODO: is a ground body needed ?
self.groundbody = self.world.CreateBody(userData={'name': 'ground'})
# Keep track of the pressed keys
# TODO: remove pressed keys from the simulation and let the gui directly communicate with the agents if it wants to control them
self.pressed_keys = set()
def set_reset_point(self):
pass
......@@ -65,9 +78,6 @@ class Box2DSimulation(b2ContactListener):
self.using_contacts = False
self.n_steps = 0
# TODO: is this needed?
self.mouseJoint = None
def step(self, step_length):
self.n_steps += 1
......
This diff is collapsed.
from Box2D import (b2DestructionListener, b2QueryCallback, b2Fixture, b2Joint, b2Vec2, b2_dynamicBody, b2DrawExtended)
import pygame
try:
from Box2D.examples.pgu import gui
except:
raise ImportError('Unable to load PGU')
from Box2D import b2Vec2
import numpy as np
class fwDestructionListener(b2DestructionListener):
"""
The destruction listener callback:
"SayGoodbye" is called when a joint or shape is deleted.
"""
def __init__(self, test, **kwargs):
super(fwDestructionListener, self).__init__(**kwargs)
self.test = test
def SayGoodbye(self, obj):
if isinstance(obj, b2Joint):
if self.test.mouseJoint == obj:
self.test.mouseJoint = None
else:
self.test.JointDestroyed(obj)
elif isinstance(obj, b2Fixture):
self.test.FixtureDestroyed(obj)
class Keys(object):
pass
class fwQueryCallback(b2QueryCallback):
def __init__(self, p):
super(fwQueryCallback, self).__init__()
self.point = p
self.fixture = None
def ReportFixture(self, fixture):
body = fixture.body
if body.type == b2_dynamicBody:
inside = fixture.TestPoint(self.point)
if inside:
self.fixture = fixture
# We found the object, so stop the query
return False
# Continue the query
return True
class PygameDraw(b2DrawExtended):
"""
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.
"""
surface = None
axisScale = 10.0
def __init__(self, test=None, **kwargs):
b2DrawExtended.__init__(self, **kwargs)
self.flipX = False
self.flipY = True
self.convertVertices = True
self.test = test
def StartDraw(self):
self.zoom = self.test.viewZoom
self.center = self.test.viewCenter
self.offset = self.test.viewOffset
self.screenSize = self.test.screenSize
def EndDraw(self):
pass
def DrawPoint(self, p, size, color):
"""
Draw a single point at point p given a pixel size and color.
"""
self.DrawCircle(p, size / self.zoom, color, drawwidth=0)
def DrawAABB(self, aabb, color):
"""
Draw a wireframe around the AABB with the given color.
"""
points = [(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.
"""
pygame.draw.aaline(self.surface, color.bytes, p1, p2)
def DrawTransform(self, xf):
"""
Draw the transform xf on the screen
"""
p1 = xf.position
p2 = self.to_screen(p1 + self.axisScale * xf.R.x_axis)
p3 = self.to_screen(p1 + self.axisScale * xf.R.y_axis)
p1 = self.to_screen(p1)
pygame.draw.aaline(self.surface, (255, 0, 0), p1, p2)
pygame.draw.aaline(self.surface, (0, 255, 0), p1, p3)
def DrawCircle(self, center, radius, color, drawwidth=1):
"""
Draw a wireframe circle given the center, radius, axis of orientation
and color.
"""
radius *= self.zoom
if radius < 1:
radius = 1
else:
radius = int(radius)
pygame.draw.circle(self.surface, color.bytes,
center, radius, drawwidth)
def DrawSolidCircle(self, center, radius, axis, color):
"""
Draw a solid circle given the center, radius, axis of orientation and
color.
"""
radius *= self.zoom
if radius < 1:
radius = 1
else:
radius = int(radius)
pygame.draw.circle(self.surface, (color / 2).bytes + [127],
center, radius, 0)
pygame.draw.circle(self.surface, color.bytes, center, radius, 1)
# pygame.draw.aaline(self.surface, (255, 0, 0), center,
# (center[0] - radius * axis[0],
# center[1] + radius * axis[1]))
def DrawPolygon(self, vertices, color):
"""
Draw a wireframe polygon given the screen vertices with the specified color.
"""
if not vertices:
return
if len(vertices) == 2:
pygame.draw.aaline(self.surface, color.bytes,
vertices[0], vertices)
else:
pygame.draw.polygon(self.surface, color.bytes, vertices, 1)
def DrawSolidPolygon(self, vertices, color):
"""
Draw a filled polygon given the screen vertices with the specified color.
"""
if not vertices:
return
if len(vertices) == 2:
pygame.draw.aaline(self.surface, color.bytes,
vertices[0], vertices[1])
else:
pygame.draw.polygon(
self.surface, (color / 2).bytes + [127], vertices, 0)
pygame.draw.polygon(self.surface, color.bytes, vertices, 1)
# the to_screen conversions are done in C with b2DrawExtended, leading to
# an increase in fps.
# You can also use the base b2Draw and implement these yourself, as the
# b2DrawExtended is implemented:
# def to_screen(self, point):
# """
# Convert from world to screen coordinates.
# In the class instance, we store a zoom factor, an offset indicating where
# the view extents start at, and the screen size (in pixels).
# """
# x=(point.x * self.zoom)-self.offset.x
# if self.flipX:
# x = self.screenSize.x - x
# y=(point.y * self.zoom)-self.offset.y
# if self.flipY:
# y = self.screenSize.y-y
# return (x, y)
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.
"""
form = None
def __init__(self,settings, **params):
# The framework GUI is just basically a HTML-like table
# There are 2 columns right-aligned on the screen
gui.Table.__init__(self,**params)
self.form=gui.Form()
fg = (255,255,255)
# "Toggle menu"
self.tr()
self.td(gui.Label("F1: Toggle Menu",color=(255,0,0)),align=1,colspan=2)
for slider in settings.sliders:
# "Slider title"
self.tr()
self.td(gui.Label(slider['text'],color=fg),align=1,colspan=2)
# Create the slider
self.tr()
e = gui.HSlider(getattr(settings, slider['name']),slider['min'],slider['max'],size=20,width=100,height=16,name=slider['name'])
self.td(e,colspan=2,align=1)
# Add each of the checkboxes.
for text, variable in settings.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 settings.checkboxes:
if not variable: continue
if hasattr(settings, variable):
self.form[variable].value = getattr(settings, variable)
# Now do the sliders
for slider in settings.sliders:
name=slider['name']
self.form[name].value=getattr(settings, name)
def updateSettings(self, settings):
"""
Change all of the settings based on the current state of the GUI.
"""
for text, variable in settings.checkboxes:
if variable:
setattr(settings, variable, self.form[variable].value)
# Now do the sliders
for slider in settings.sliders:
name=slider['name']
setattr(settings, name, int(self.form[name].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
# TODO: identify which of these functions can be removed, as they are not used
def update_turn(keys, desired_ang_speed, max_speed):
......@@ -381,8 +121,6 @@ def closest_node(node, nodes):
return np.argmin(dist_2)
def calc_linear_velocity_from_forward_velocity(desired_forward_velocity, box2d_body):
# find the current speed in the forward direction
current_forward_normal = box2d_body.GetWorldVector((0, 1))
......
......@@ -341,55 +341,63 @@ def as_list(x):
return x
def object_filter(obj, objects=None, ids=None, types=None, properties=None):
def object_filter(obj, filter=None, **kwargs):
default_filter = mpi_sim.AttrDict(
objects = [],
ids = [],
types = [],
properties = [],
)
filter = mpi_sim.combine_dicts(kwargs, filter, default_filter)
# if no filters are given, then object is ok
if not objects and not ids and not types and not properties:
if not filter.objects and not filter.ids and not filter.types and not filter.properties:
return True
# make sure, that all inputs are lists
if objects is None:
objects = []
elif isinstance(objects, mpi_sim.Object):
objects = [objects]
elif not isinstance(objects, list):
if filter.objects is None:
filter.objects = []
elif isinstance(filter.objects, mpi_sim.Object):
filter.objects = [filter.objects]
elif not isinstance(filter.objects, list):
raise ValueError('Argument objects must be either None, Object, or a list of Objects!')
if ids is None:
ids = []
elif isinstance(ids, int):
ids = [ids]
elif not isinstance(ids, list):
if filter.ids is None:
filter.ids = []
elif isinstance(filter.ids, int):
filter.ids = [filter.ids]
elif not isinstance(filter.ids, list):
raise ValueError('Argument ids must be either None, int, or a list of ints!')
if types is None:
types = []
elif inspect.isclass(types):
types = [types]
elif not isinstance(types, list):
if filter.types is None:
filter.types = []
elif inspect.isclass(filter.types):
filter.types = [filter.types]
elif not isinstance(filter.types, list):
raise ValueError('Argument types must be either None, class, or a list of classes!')
if properties is None:
properties = []
elif isinstance(properties, str):
properties = [properties]
elif not isinstance(properties, list):
if filter.properties is None:
filter.properties = []
elif isinstance(filter.properties, str):
filter.properties = [filter.properties]
elif not isinstance(filter.properties, list):
raise ValueError('Argument properties must be either None, string, or a list of strings!')
# check if condition holds
if objects and obj in objects:
if filter.objects and obj in filter.objects:
return True
if ids and obj.id in ids:
if filter.ids and obj.id in filter.ids:
return True
if types and isinstance(obj, tuple(types)):
if filter.types and isinstance(obj, tuple(filter.types)):
return True
if properties:
for prop in properties:
if filter.properties:
for prop in filter.properties:
if prop in obj.properties:
return True
......
# Multi-Agent Interaction Simulator
Version 0.0.8 (15.12.2022)
Version 0.0.9 (17.12.2022)
Simulator for multi-agent interaction scenarios in a 2D environment.
......
[metadata]
name = mpi_sim
version = 0.0.8
version = 0.0.9
[options]
packages = find:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment