Commit a68c1bf2 authored by Karol Actun's avatar Karol Actun
Browse files

added all original scenarios and solutions (and modified them, because some...

added all original scenarios and solutions (and modified them, because some functions changed) + bug fixes
parent 03a6f9f4
......@@ -3,7 +3,7 @@
## Different number creates a different random sequence
seedvalue = 12
## Maximum round number in swarm-world, 0 = infinit
## Maximum round number in swarm-world, 0 = infinite
max_round = 0
## 1 = Call of particles in randmom order
......@@ -31,35 +31,36 @@ gui = default_gui
;tile_model_file = 2d_quad_tile.obj
;location_model_file = 2d_location.obj
;grid_size = 1000
; end of Quadratic grid configs
;# end of Quadratic grid configs
;# Triangular grid default configs:
;grid_class = TriangularGrid
;# .obj (Wavefront) filenames in lib/visualization/models
;particle_model_file = 2d_particle.obj
;tile_model_file = 2d_hex_tile.obj
;location_model_file = 2d_location.obj
;grid_size = 100
; end of Triangular grid configs
# Triangular grid default configs:
grid_class = TriangularGrid
# .obj (Wavefront) filenames in lib/visualization/models
particle_model_file = 2d_particle.obj
tile_model_file = 2d_hex_tile.obj
location_model_file = 2d_location.obj
grid_size = 100
# end of Triangular grid configs
;
;# cubic grid default configs:
;grid_class = CubicGrid
;particle_model_file = 3d_particle_low_poly.obj
;tile_model_file = 3d_cube_tile.obj
;location_model_file = 3d_location.obj
;grid_size = 10
; end of cubic grid configs
;# end of cubic grid configs
# ccp grid default configs:
grid_class = CCPGrid
particle_model_file = 3d_particle.obj
tile_model_file = 3d_ccp_tile.obj
location_model_file = 3d_location.obj
grid_size = 10
# end of ccp grid configs
;
;# ccp grid default configs:
;grid_class = CCPGrid
;particle_model_file = 3d_particle.obj
;tile_model_file = 3d_ccp_tile.obj
;location_model_file = 3d_location.obj
;grid_size = 10
;# end of ccp grid configs
;
# matter default colors (rgba)
particle_color = (0.8, 0.3, 0.3, 1.0)
......@@ -84,11 +85,11 @@ coordinates_scaling = (0.05, 0.05, 0.05)
# flag for showing the coordinate models
show_coordinates = True
# flag for showing the center of the grid
show_center = True
show_center = False
# camera focus color
focus_color = (1.0, 1.0, 1.0, 0.5)
# show camera focus
show_focus = True
show_focus = False
# Camera init values
look_at = (0.0, 0.0, 0.0)
......@@ -124,6 +125,6 @@ particle_mm_size = 2
tile_mm_size = 2
[File]
scenario = lonely_particle
solution = random_walk_with_take_and_drop
scenario = test_interfaces
solution = test_all_the_interfaces
......@@ -171,7 +171,7 @@ def get_matter_combo(vis):
combo.setCurrentIndex(1)
def on_change(value):
print(value)
vis.set_on_cursor_click_matter_type(value)
combo.currentTextChanged.connect(on_change)
......
......@@ -95,7 +95,7 @@ class Matter:
"""
return self.__id
def set_color(self, color):
def set_color(self, color: tuple):
"""
Sets the matter color
......
......@@ -274,7 +274,7 @@ class Particle(matter.Matter):
"""
within_hop_list = []
for i in range(1, hop + 1):
for i in range(hop + 1):
in_list = self.scan_for_matters_in(matter_type, i)
if in_list is not None:
within_hop_list.extend(in_list)
......@@ -302,7 +302,8 @@ class Particle(matter.Matter):
elif matter_type == "locations":
scanned_list = scan_in(self.world.location_map_coordinates, self.coordinates, hop, self.world.grid)
else:
scanned_list = scan_in(self.world.particle_map_coordinates, self.coordinates, hop, self.world.grid)
scanned_list = []
scanned_list.extend(scan_in(self.world.particle_map_coordinates, self.coordinates, hop, self.world.grid))
scanned_list.extend(scan_in(self.world.tile_map_coordinates, self.coordinates, hop, self.world.grid))
scanned_list.extend(scan_in(self.world.location_map_coordinates, self.coordinates, hop, self.world.grid))
return scanned_list
......@@ -456,7 +457,7 @@ class Particle(matter.Matter):
if self.world.grid.are_valid_coordinates(coordinates):
logging.info("Going to create a tile on position %s" % str(coordinates))
if self.world.add_tile(coordinates):
self.world.tile_map_coordinates[coordinates, coordinates[1]].created = True
self.world.tile_map_coordinates[coordinates].created = True
self.world.new_tile_flag = True
self.csv_particle_writer.write_particle(tile_created=1)
self.world.csv_round.update_tiles_num(len(self.world.get_tiles_list()))
......@@ -713,7 +714,7 @@ class Particle(matter.Matter):
logging.info("Going to create a particle on position %s" % str(coordinates))
new_particle = self.world.add_particle(coordinates)
if new_particle:
self.world.particle_map_coordinates[coordinates[0], coordinates[1]].created = True
self.world.particle_map_coordinates[coordinates].created = True
logging.info("Created particle on coordinates %s" % str(coordinates))
self.world.csv_round.update_particle_num(len(self.world.get_particle_list()))
self.world.csv_round.update_metrics(particle_created=1)
......@@ -784,20 +785,23 @@ class Particle(matter.Matter):
:param coordinates
:return: True: Deleting successful; False: Deleting unsuccessful
"""
if coordinates is not None:
if self.world.grid.are_valid_coordinates(coordinates):
if self.world.remove_particle_on(coordinates):
logging.info("Deleted particle with particle on coordinates %s" % str(coordinates))
self.csv_particle_writer.write_particle(particle_deleted=1)
return True
else:
logging.info("Could not delet particle on coordinates %s" % str(coordinates))
return False
else:
return False
if coordinates is None:
logging.info("coordinates are 'None'...")
return False
if not self.world.grid.are_valid_coordinates(coordinates):
logging.info("invalid coordinates")
return False
if self.world.remove_particle_on(coordinates):
logging.info("Deleted particle with particle on coordinates %s" % str(coordinates))
self.csv_particle_writer.write_particle(particle_deleted=1)
return True
else:
logging.info("Could not delete particle on coordinates %s" % str(coordinates))
return False
def take_particle_with(self, particle_id):
"""
Takes a particle with a given tile id
......@@ -805,24 +809,27 @@ class Particle(matter.Matter):
:param particle_id: The id of the particle that should be taken
:return: True: successful taken; False: unsuccessful taken
"""
if self.carried_tile is None and self.carried_particle is None:
if particle_id in self.world.get_particle_map_id():
logging.info("particle with particle id %s is in the world" % str(particle_id))
self.carried_particle = self.world.particle_map_id[particle_id]
if self.carried_particle.take_me(self.coordinates):
logging.info("particle with particle id %s has been taken" % str(particle_id))
self.carried_particle.coordinates = self.coordinates
self.world.vis.particle_changed(self.carried_particle)
self.world.csv_round.update_metrics(particles_taken=1)
self.csv_particle_writer.write_particle(particles_taken=1)
return True
else:
logging.info("particle with particle id %s could not be taken" % str(particle_id))
return False
else:
logging.info("particle with particle id %s is not in the world" % str(particle_id))
if self.carried_tile is not None or self.carried_particle is not None:
logging.info("particle %s is already carrying a particle or a tile" % str(self.get_id()))
return False
if particle_id not in self.world.get_particle_map_id():
logging.info("particle with particle id %s is not in the world" % str(particle_id))
return False
self.carried_particle = self.world.particle_map_id[particle_id]
if self.carried_particle.take_me(self.coordinates):
logging.info("particle with particle id %s has been taken" % str(particle_id))
self.carried_particle.coordinates = self.coordinates
self.world.vis.particle_changed(self.carried_particle)
self.world.csv_round.update_metrics(particles_taken=1)
self.csv_particle_writer.write_particle(particles_taken=1)
return True
else:
logging.info("particle cannot taken because particle is carrieng either a particle or a tile")
self.carried_particle = None
logging.info("particle with particle id %s could not be taken" % str(particle_id))
return False
def take_particle_on(self, coordinates):
"""
......@@ -832,14 +839,14 @@ class Particle(matter.Matter):
:return: True: Successful taken; False: Cannot be taken or wrong Coordinates
"""
if self.world.grid.are_valid_coordinates(coordinates):
if coordinates in self.world.particle_map_coordinates:
return self.take_particle_with(self.world.particle_map_coordinates[coordinates].get_id())
else:
logging.info("Particle is not in the world")
return False
if not self.world.grid.are_valid_coordinates(coordinates):
logging.info("Coordinates are invalid")
return False
if coordinates in self.world.particle_map_coordinates:
return self.take_particle_with(self.world.particle_map_coordinates[coordinates].get_id())
else:
logging.info("Coordinates are wrong")
logging.info("There is no particle on %s" % str(coordinates))
return False
def take_particle_in(self, direction):
......@@ -900,7 +907,7 @@ class Particle(matter.Matter):
else:
logging.info("invalid coordinates")
else:
logging.info("drop_particle_on: Wrong Inputs")
logging.info("drop_particle_on: coordinates are 'None' or not carrying a particle")
return False
def update_particle_coordinates(self, particle, new_coordinates):
......
......@@ -26,15 +26,26 @@ def eprint(*args, sep=' ', end='\n'):
def get_coordinates_in_direction(coordinates, direction):
"""
Returns the coordination data of the pointed directions
Returns the coordinates data of the pointed directions
:param coordinates: particles actual staying coordination
:param direction: The direction. Options: E, SE, SW, W, NW, or NE
:return: The coordinaiton of the pointed directions
:return: The coordinates of the pointed directions
"""
return coordinates[0] + direction[0], coordinates[1] + direction[1], coordinates[2] + direction[2]
def get_multiple_steps_in_direction(start, direction, steps):
"""
returns coordinates of the point from the start variable in x steps in the given direction
:param start: the starting point
:param direction: the direction
:param steps: the amount of steps
:return: coordinates (float, float, float)
"""
return start[0] + (direction[0] * steps), start[1] + (direction[1] * steps), start[2] + (direction[2] * steps)
def scan_in(matter_map: dict, center, hop, grid):
result = []
n_sphere_border = grid.get_n_sphere_border(center, hop)
......@@ -66,3 +77,4 @@ def create_matter_in_line(world, start, direction, amount, matter_type='particle
print("create_matter_in_line: unknown type (allowed: particle, tile or location")
return
current_position = get_coordinates_in_direction(current_position, direction)
......@@ -9,6 +9,7 @@ import time
from lib.visualization.camera import Camera
from lib.visualization.utils import LoadingWindow
import OpenGL.GL as GL
def close(_):
exit(0)
......@@ -30,7 +31,7 @@ class Visualization:
self._viewer = None
self._gui = None
self._splitter = None
self.light_rotation = True
self.light_rotation = False
# create the QApplication
self._app = QApplication([])
......@@ -184,7 +185,7 @@ class Visualization:
:param round_start_timestamp: timestamp of the start of the round.
:return:
"""
# draw scene
# update and draw scene
self._viewer.update_data()
self._viewer.glDraw()
# waiting until simulation starts
......@@ -193,13 +194,17 @@ class Visualization:
time_elapsed = time.perf_counter() - round_start_timestamp
# sleeping time - max 1/120 for a responsive GUI
sleep_time = min(1.0 / 120, (1.0 / self._rounds_per_second) / 10.0)
while time_elapsed < 1 / self._rounds_per_second:
max_wait_time = 1 / self._rounds_per_second
while time_elapsed < max_wait_time:
# waiting for 1/100 of the round_time
time.sleep(sleep_time)
# check if still running... if not wait (important for low rounds_per_second values)
self._wait_while_not_running()
time_elapsed = time.perf_counter() - round_start_timestamp
GL.glFinish()
end = time.perf_counter_ns()
def remove_particle(self, particle):
"""
removes a particle from the visualization.
......@@ -350,9 +355,7 @@ class Visualization:
return self._viewer.programs["grid"].get_model_scaling()
def set_grid_coordinates_scaling(self, scaling):
print(2)
self._viewer.programs["grid"].set_model_scaling(scaling)
print(2)
self._viewer.glDraw()
def get_render_distance(self):
......@@ -412,4 +415,9 @@ class Visualization:
return self._viewer.programs["location"].get_model_scaling()
def set_location_scaling(self, scaling):
self._viewer.programs["location"].set_model_scaling(scaling)
\ No newline at end of file
self._viewer.programs["location"].set_model_scaling(scaling)
def set_on_cursor_click_matter_type(self, matter_type):
if matter_type == 'tile' or matter_type == 'particle' or matter_type == 'location':
self._viewer.cursor_type = matter_type
self._viewer.update_cursor_data()
import inspect
import OpenGL.GL as gl
import OpenGL.GL as GL
from PIL import Image
from PyQt5 import QtOpenGL, QtGui, QtCore
......@@ -20,11 +20,6 @@ class OGLWidget(QtOpenGL.QGLWidget):
:param world: the world class
:param camera: a camera for the visualization
"""
# fmt = QtOpenGL.QGLFormat()
# fmt.setVersion(3, 3)
# # needs to be in compatibility profile, because of glLineWidth
# fmt.setProfile(QtOpenGL.QGLFormat.CompatibilityProfile)
# fmt.setSampleBuffers(True)
super(OGLWidget, self).__init__()
self.debug = False
......@@ -41,6 +36,7 @@ class OGLWidget(QtOpenGL.QGLWidget):
self.rotation_sensitivity = 5
self.zoom_sensitivity = 100
self.cursor_zoom_sensitivity = 200
self.cursor_type = 'tile'
self.camera = camera
......@@ -120,27 +116,22 @@ class OGLWidget(QtOpenGL.QGLWidget):
:return:
"""
# set global openGL settings
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glEnable(gl.GL_BLEND)
gl.glEnable(gl.GL_LINE_SMOOTH)
gl.glEnable(gl.GL_CULL_FACE)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
gl.glClearColor(*self.background, 1.0)
print(1)
GL.glEnable(GL.GL_DEPTH_TEST)
GL.glEnable(GL.GL_BLEND)
GL.glEnable(GL.GL_LINE_SMOOTH)
GL.glEnable(GL.GL_CULL_FACE)
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
GL.glClearColor(*self.background, 1.0)
# initialize the openGL programs
self.programs["particle"] = OffsetColorCarryProgram(self.world.config_data.particle_model_file)
self.programs["particle"].set_world_scaling(self.world.grid.get_scaling())
print(1)
self.programs["tile"] = OffsetColorCarryProgram(self.world.config_data.tile_model_file)
self.programs["tile"].set_world_scaling(self.world.grid.get_scaling())
print(1)
self.programs["location"] = OffsetColorProgram(self.world.config_data.location_model_file)
print(1)
self.programs["location"].set_world_scaling(self.world.grid.get_scaling())
print(1)
self.programs["grid"] = GridProgram(self.world.grid, self.world.config_data.line_color,
self.world.config_data.coordinates_color,
......@@ -168,11 +159,24 @@ class OGLWidget(QtOpenGL.QGLWidget):
self.programs["focus"].update_offsets(self.camera.get_look_at())
self.programs["focus"].update_colors(self.world.config_data.focus_color)
self.programs["cursor"] = OffsetColorProgram(self.world.config_data.tile_model_file)
self.programs["cursor"].set_world_scaling(self.world.grid.get_scaling())
self.programs["cursor"].set_model_scaling((1.1, 1.1, 1.1))
self.programs["center"].update_offsets([0.0, 0.0, 0.0])
self.programs["cursor"].update_colors(self.world.config_data.cursor_color)
# cursor programs.. loading in the init, so on change it doesnt has to be loaded again
self.programs["cursor_tile"] = OffsetColorProgram(self.world.config_data.tile_model_file)
self.programs["cursor_tile"].set_world_scaling(self.world.grid.get_scaling())
self.programs["cursor_tile"].set_model_scaling((1.1, 1.1, 1.1))
self.programs["cursor_tile"].update_offsets([0.0, 0.0, 0.0])
self.programs["cursor_tile"].update_colors(self.world.config_data.cursor_color)
self.programs["cursor_particle"] = OffsetColorProgram(self.world.config_data.particle_model_file)
self.programs["cursor_particle"].set_world_scaling(self.world.grid.get_scaling())
self.programs["cursor_particle"].set_model_scaling((1.1, 1.1, 1.1))
self.programs["cursor_particle"].update_offsets([0.0, 0.0, 0.0])
self.programs["cursor_particle"].update_colors(self.world.config_data.cursor_color)
self.programs["cursor_location"] = OffsetColorProgram(self.world.config_data.location_model_file)
self.programs["cursor_location"].set_world_scaling(self.world.grid.get_scaling())
self.programs["cursor_location"].set_model_scaling((1.1, 1.1, 1.1))
self.programs["cursor_location"].update_offsets([0.0, 0.0, 0.0])
self.programs["cursor_location"].update_colors(self.world.config_data.cursor_color)
def resizeGL(self, width, height):
"""
......@@ -188,7 +192,7 @@ class OGLWidget(QtOpenGL.QGLWidget):
self.camera.set_viewport(width, height)
# set the openGL viewport
gl.glViewport(0, 0, width, height)
GL.glViewport(0, 0, width, height)
# update matrices
self.update_scene()
......@@ -225,7 +229,9 @@ class OGLWidget(QtOpenGL.QGLWidget):
updates the position of the cursor
:return:
"""
self.programs["cursor"].update_offsets(self.world.grid.get_nearest_valid_coordinates(self.camera.cursor_position))
# updating only the current cursor program
self.programs["cursor_"+self.cursor_type].update_offsets(
self.world.grid.get_nearest_valid_coordinates(self.camera.cursor_position))
def rotate_light(self, angle):
"""
......@@ -244,7 +250,7 @@ class OGLWidget(QtOpenGL.QGLWidget):
:return:
"""
# clear the screen
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
# draw
self.programs["particle"].draw()
......@@ -258,7 +264,7 @@ class OGLWidget(QtOpenGL.QGLWidget):
# cursor
if self.ctrl:
self.programs["cursor"].draw()
self.programs["cursor_"+self.cursor_type].draw()
if self.show_focus:
self.programs["focus"].draw()
......@@ -273,10 +279,21 @@ class OGLWidget(QtOpenGL.QGLWidget):
# starting dragging
if self.ctrl and int(a0.buttons()) & QtCore.Qt.LeftButton:
nl = self.world.grid.get_nearest_valid_coordinates(self.camera.cursor_position)
if nl in self.world.tile_map_coordinates:
self.world.remove_tile_on(nl)
else:
self.world.add_tile(nl)
if self.cursor_type == 'tile':
if nl in self.world.tile_map_coordinates:
self.world.remove_tile_on(nl)
else:
self.world.add_tile(nl)
if self.cursor_type == 'particle':
if nl in self.world.particle_map_coordinates:
self.world.remove_particle_on(nl)
else:
self.world.add_particle(nl)
if self.cursor_type == 'location':
if nl in self.world.location_map_coordinates:
self.world.remove_location_on(nl)
else:
self.world.add_location(nl)
self.update_data()
self.glDraw()
else:
......@@ -401,8 +418,8 @@ class OGLWidget(QtOpenGL.QGLWidget):
takes a screenshot of the OpenGLWidget. saves it with a random name in the screenshots folder.
:return:
"""
gl.glReadBuffer(gl.GL_FRONT)
pixels = gl.glReadPixels(0, 0, self.width(), self.height(), gl.GL_RGB, gl.GL_UNSIGNED_BYTE)
GL.glReadBuffer(GL.GL_FRONT)
pixels = GL.glReadPixels(0, 0, self.width(), self.height(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE)
i = Image.frombytes('RGB', (self.width(), self.height()), pixels, 'raw')
import os
if os.path.exists("screenshots") and os.path.isdir("screenshots"):
......@@ -412,5 +429,5 @@ class OGLWidget(QtOpenGL.QGLWidget):
"Please create it in the running directory before taking screenshots.")
def set_background_color(self, color):
gl.glClearColor(*color, 1.0)
GL.glClearColor(*color, 1.0)
self.glDraw()
......@@ -384,7 +384,7 @@ class World:
:return: True: Successful removed; False: Unsuccessful
"""
if coordinates in self.particle_map_coordinates:
return self.remove_particle(self.particle_map_coordinates[coordinates])
return self.remove_particle(self.particle_map_coordinates[coordinates].get_id())
else:
return False
......
......@@ -5,4 +5,4 @@ import random
def scenario(world):
amount = 10
direction = random.choice(world.grid.get_directions_list())
create_matter_in_line(world, world.grid.get_center(), direction, amount, 'particle')
create_matter_in_line(world, world.grid.get_center(), direction, amount, 'location')
"""
A world is created that has particles formated in a ring structure that is up to 5 hops big
"""
def scenario(world):
world.add_particle(world.grid.get_center())
particle_ring = world.grid.get_n_sphere_border((0, 0, 0), 1)
tile_ring = world.grid.get_n_sphere_border((0, 0, 0), 3)
location_ring = world.grid.get_n_sphere_border((0, 0, 0), 5)
for p in particle_ring:
world.add_particle(p)
for t in tile_ring:
world.add_tile(t)
for l in location_ring:
world.add_location(l)
from lib.swarm_sim_header import get_coordinates_in_direction, get_multiple_steps_in_direction
def scenario(world):
dirs = world.grid.get_directions_list()
world.add_particle(world.grid.get_center(), color=(1.0, 0.0, 0.0, 1.0))
tile_pos = get_coordinates_in_direction(world.grid.get_center(), dirs[0])
world.add_tile(tile_pos)
loc_pos = get_coordinates_in_direction(tile_pos, dirs[1])
world.add_location(loc_pos)
# 1st ring
ring1 = world.grid.get_n_sphere_border(world.grid.get_center(), 1)
for m in ring1:
world.add_particle(m, color=(0.2, 0.2, 0.2, 1.0))
# 2nd ring
ring2 = world.grid.get_n_sphere_border(world.grid.get_center(), 2)
for m in ring2:
world.add_particle(m, color=(0.5, 0.5, 0.5, 1.0))
tile_pos1 = get_multiple_steps_in_direction(world.grid.get_center(), dirs[0], 4)
tile_pos2 = get_multiple_steps_in_direction(tile_pos1, dirs[1], 2)
tile_pos3 = get_multiple_steps_in_direction(tile_pos2, dirs[2], 2)
tile_pos4 = get_multiple_steps_in_direction(tile_pos3, dirs[3], 2)
world.add_tile(tile_pos1)
world.add_tile(tile_pos2)
world.add_tile(tile_pos3)
world.add_tile(tile_pos4)
"""
A world is created that has two particles, two markers, and two tiles.