Commit 6b938a03 authored by Ahmad Reza Cheraghi's avatar Ahmad Reza Cheraghi
Browse files

Merge branch '3D-swarm-sim' into 'master'

3d swarm sim

See merge request !10
parents eb1c00fc a68c1bf2
......@@ -3,5 +3,5 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6.2 (/usr/bin/python3.6)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
......
......@@ -13,7 +13,15 @@ For Linux:
3. sudo pip3 install pandas
4. sudo pip3 install pyglet
4. sudo pip3 install PyOpenGL
5. sudo pip3 install Pillow
6. sudo pip3 install PyQt5
for older Systems (e.g. Ubuntu 14.04) install the PyQt5 version 5.10.1
6. sudo pip3 install PyQt5==5.10.1
- install Gnuplot:
......@@ -41,7 +49,9 @@ For Windows/Linux/MacOs:
1. pip3
2. numpy
3. pandas
4. pyglet
4. PyOpenGL
5. Pillow
6. PyQt5 (in version 5.10.1 for older Systems like Ubuntu 14.04)
- press Okey
- wait until everything is installed
- chose Run->swarm-sim.py
......
......@@ -3,21 +3,105 @@
## Different number creates a different random sequence
seedvalue = 12
## Maximum round number in swarm-world
max_round = 100
# Visualization 1 = On, 0 = Off
visualization = 1
## Maximum round number in swarm-world, 0 = infinite
max_round = 0
## 1 = Call of particles in randmom order
## 0 = Call of particles in added order in scenario
particle_random_order = True
## Viewing window size in pixels
window_size_x = 600
window_size_y = 800
window_size_x = 1920
window_size_y = 1080
[Visualization]
# Visualization 1 = On, 0 = Off
visualization = 1
#gui
gui = default_gui
# Grid Configs. uncomment your choice!
;# Quadratic Grid grid default configs:
;grid_class = QuadraticGrid
;# .obj (Wavefront) filenames in lib/visualization/models
;particle_model_file = 2d_particle.obj
;tile_model_file = 2d_quad_tile.obj
;location_model_file = 2d_location.obj
;grid_size = 1000
;# 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
;# 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
;
;# 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)
tile_color = (0.3, 0.3, 0.8, 1.0)
location_color = (0.3, 0.8, 0.3, 1.0)
grid_color = (0.0, 0.0, 0.0, 1.0)
cursor_color = (0.5, 0.5, 0.5, 0.5)
center_color = (1.0, 0.0, 0.0, 0.5)
# background (rgb)
background_color = (0.8, 0.8, 0.8)
# color of grid lines (rgba)
line_color = (0.0, 0.0, 0.0, 1.0)
# length/scaling of the grid lines (max should be 1,1,1)
line_scaling = (1.0, 1.0, 1.0)
# flag for showing the lines
show_lines = True
# color of grid coordinates (rgba)
coordinates_color = (0.0, 0.0, 0.0, 1.0)
# size/scaling of the coordinate model. wouldn't make it bigger than 0.2, 0.2, 0.2
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 = False
# camera focus color
focus_color = (1.0, 1.0, 1.0, 0.5)
# show camera focus
show_focus = False
# Camera init values
look_at = (0.0, 0.0, 0.0)
phi = -90
theta = 0
radius = 10
fov = 40
cursor_offset = -10
render_distance = 1000
[World]
## False = Unlimited world size
## True = limited world size
border = False
......@@ -28,7 +112,7 @@ size_x = 2000.0
size_y = 2000.0
## Maximum number of particles that can be created while simulating
max_particles = 10000
max_particles = 100000000
[Matter]
## with memory (mm) limitation 1=Yes 0=No
......@@ -36,37 +120,11 @@ memory_limitation = False
## mm size in quantity
## Works only with memory_limitation flag set on 1
marker_mm_size = 2
location_mm_size = 2
particle_mm_size = 2
tile_mm_size = 2
[File]
##Examples##
##Moving
#scenario = lonely_particle
#scenario = n_particle_in_line
#solution = random_walk
#solution = round_walk
## Creating and Deleting
#scenario = lonely_particle
#solution = create_delete
## Take and Drop
#scenario = between_particle_one_tile_particle
#solution= take_drop_aims
## Read and Write
#scenario = two_particles_tiles_markers
#solution = read_write
## Scanning for matters
#scenario = particles_tiles_markers_ring
#solution= scanning_for_all_aims
## All interfaces
scenario = test_interfaces
#scenario = hexagon_border
solution = test_all_the_interfaces
from grids.Grid import Grid
class CCPGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"LEFT_UP": (-1.0, 1.0, 0.0),
"FORWARD_UP": (0.0, 1.0, 1.0),
"RIGHT_UP": (1.0, 1.0, 0.0),
"BACK_UP": (0.0, 1.0, -1.0),
"LEFT_FORWARD": (-1.0, 0.0, 1.0),
"RIGHT_FORWARD": (1.0, 0.0, 1.0),
"RIGHT_BACK": (1.0, 0.0, -1.0),
"LEFT_BACK": (-1.0, 0.0, -1.0),
"LEFT_DOWN": (-1.0, -1.0, 0.0),
"FORWARD_DOWN": (0.0, -1.0, 1.0),
"RIGHT_DOWN": (1.0, -1.0, 0.0),
"BACK_DOWN": (0.0, -1.0, -1.0)}
def get_box(self, width):
locations = []
for x in range(-int(width / 2), int(width / 2)):
for y in range(-int(width / 2), int(width / 2)):
for z in range(-int(width / 2), int(width / 2)):
if self.are_valid_coordinates((x, y, z)):
locations.append((x, y, z))
return locations
def are_valid_coordinates(self, coordinates):
x = coordinates[0]
y = coordinates[1]
z = coordinates[2]
if y % 2.0 == 0:
if x % 2.0 == z % 2.0 == 0 or x % 2.0 == z % 2.0 == 1:
return True
else:
if x % 2.0 == 1 and z % 2.0 == 0 or x % 2.0 == 0 and z % 2.0 == 1:
return True
return False
def get_nearest_valid_coordinates(self, coordinates):
x = round(coordinates[0])
y = round(coordinates[1])
z = round(coordinates[2])
if y % 2.0 == 0:
if x % 2.0 != z % 2.0:
z = z + 1
else:
if x % 2.0 == z % 2.0:
z = z + 1
return x, y, z
def get_dimension_count(self):
return 3
def get_distance(self, start, end):
dx = abs(start[0] - end[0])
dy = abs(start[1] - end[1])
dz = abs(start[2] - end[2])
if dy > dx + dz:
return dy
if dx > dy + dz:
return dx
if dz > dx + dy:
return dz
return (dx + dy + dz) / 2.0
def get_center(self):
return 0, 0, 0
from grids.Grid import Grid
class CubicGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"LEFT": (-1, 0, 0),
"RIGHT": (1, 0, 0),
"UP": (0, 1, 0),
"DOWN": (0, -1, 0),
"FORWARD": (0, 0, 1),
"BACK": (0, 0, -1)}
def get_box(self, width):
locations = []
for x in range(int(-width / 2), int(width / 2)):
for y in range(int(-width / 2), int(width / 2)):
for z in range(int(-width / 2), int(width / 2)):
locations.append((x, y, z))
return locations
def are_valid_coordinates(self, coordinates):
if coordinates[0] % 1 == 0 and coordinates[1] % 1 == 0 and coordinates[2] % 1 == 0:
return True
else:
return False
def get_nearest_valid_coordinates(self, coordinates):
return (round(coordinates[0]),
round(coordinates[1]),
round(coordinates[2]))
def get_dimension_count(self):
return 3
def get_distance(self, start, end):
return abs(start[0] - end[0]) + abs(start[1] - end[1]) + abs(start[2] - end[2])
def get_center(self):
return 0, 0, 0
from abc import ABC, abstractmethod
class Grid(ABC):
@property
@abstractmethod
def size(self):
pass
@property
@abstractmethod
def directions(self):
pass
@abstractmethod
def are_valid_coordinates(self, coordinates):
"""
checks if given coordinates are valid for this grid
:param coordinates: (float, float, float)
:return: true = coordinates are valid, false = coordinates invalid
"""
pass
@abstractmethod
def get_nearest_valid_coordinates(self, coordinates):
"""
calculates the nearest valid coordinates to given coordinates
:param coordinates: (float, float, float)
:return: valid coordinates
"""
pass
def get_directions_dictionary(self):
"""
returns a dictionary of the directions, with direction names (string) as keys
and the direction vectors (3d tuple) as values
:return: dictionary with - 'string: (float, float,float)'
"""
return self.directions
def get_directions_list(self):
"""
returns a list of the direction vectors
:return: list of 3d tuples - '(float, float, float)'
"""
return list(self.directions.values())
def get_directions_names(self):
"""
returns a list of direction names
:return: list of strings
"""
return list(self.directions.keys())
def get_lines(self):
"""
FOR VISUALIZATION!
calculates line data in this grids directions for the visualization.
output is a list of start and end points. the start point is always the center of this grid and the end points
are the directions but only half in length
:return: list of vectors, [(sx,sy,sz), (ex,ey,ez), (sx,sy,sz), (ea,eb,ec), ...]
"""
lines = []
for d in self.get_directions_list():
lines.append(self.get_center())
hd = (d[0] * 0.5, d[1] * 0.5, d[2] * 0.5)
lines.append(hd)
return lines
@abstractmethod
def get_box(self, width):
"""
calculates all valid coordinates in a box
:return: list of 3d coordinates: [(x_start_l0, y_start_l0), (x_end_l0, y_end_l0), (x_start_l1, y_start_l1), ...)
"""
pass
@abstractmethod
def get_dimension_count(self):
"""
returns the amount of dimensions
:return: integer, amount of dimensions (3 or 2 presumably)
"""
pass
@abstractmethod
def get_distance(self, start, end):
"""
the metric or distance function for this grid
:param start: coordinates, (float, float, float) tuple, start of path
:param end: coordinates, (float, float, float) tuple, end of path
:return: integer, minimal amount of steps between start and end
"""
pass
@staticmethod
def get_coordinates_in_direction(position, direction):
"""
calculates a new position from current position and direction
:param position: coordinates, (float, float, float) tuple, current position
:param direction: coordinates, (float, float, float) tuple, direction
:return: coordinates, (float, float, float) tuple, new position
"""
new_pos = []
for i in range(len(position)):
new_pos.append(position[i]+direction[i])
return tuple(new_pos)
def get_center(self):
"""
returns the center of the grid. usually (0,0,0)
:return: coordinates, (float, float, float) tuple
"""
return 0.0, 0.0, 0.0
def get_scaling(self):
"""
returns the x,y,z scaling for the visualization. usually (1,1,1) = no scaling
:return: x,y,z scaling values: float, float, float
"""
return 1.0, 1.0, 1.0
def get_adjacent_coordinates(self, coordinates):
"""
calculates a set of adjacent coordinates of the given coordinates
:param coordinates: the coordinates of which the neighboring coordinates should be calculated
:return: a set of coordinates
"""
n = set()
for d in self.get_directions_list():
n.add(self.get_coordinates_in_direction(coordinates, d))
return n
def _get_adjacent_coordinates_not_in_set(self, coordinates, not_in_set):
"""
the same as 'get_neighboring_coordinates', but doesn't return coordinates which are in the given 'not_in_set'.
:param coordinates: the coordinates of which the neighboring coordinates should be calculated
:param not_in_set: set of coordinates, which should not be included in the result
:return: a set of coordinates
"""
result = set()
for d in self.get_directions_list():
n = self.get_coordinates_in_direction(coordinates, d)
if n not in not_in_set:
result.add(n)
return result
def get_n_sphere(self, coordinates, radius):
"""
calculates the n-sphere of this grid
:param coordinates: center of the circle/sphere
:param radius: radius of the circle/sphere
:return: set of coordinates
"""
result = set()
ns = self.get_adjacent_coordinates(coordinates)
current_ns = ns
result.update(ns)
for i in range(radius):
tmp = set()
for n in current_ns:
ns = self._get_adjacent_coordinates_not_in_set(n, result)
tmp.update(ns)
result.update(ns)
current_ns = tmp
return result
def get_n_sphere_border(self, coordinates, radius):
"""
calculates the border of an n-sphere around the center with the given radius
:param coordinates: center of the ring
:param radius: radius of the ring
:return: set of coordinates
"""
if radius == 0:
r = set()
r.add(coordinates)
return r
seen = set()
ns = self.get_adjacent_coordinates(coordinates)
current_ns = ns
seen.update(ns)
seen.add(coordinates)
for i in range(radius-1):
tmp = set()
for n in current_ns:
ns = self._get_adjacent_coordinates_not_in_set(n, seen)
seen.update(ns)
tmp.update(ns)
current_ns = tmp
return current_ns
from grids.Grid import Grid
class QuadraticGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"LEFT": (-1, 0, 0),
"RIGHT": (1, 0, 0),
"UP": (0, 1, 0),
"DOWN": (0, -1, 0)}
def get_box(self, width):
locations = []
for x in range(int(-width / 2), int(width / 2)):
for y in range(int(-width / 2), int(width / 2)):
locations.append((x, y, 0.0))
return locations
def are_valid_coordinates(self, coordinates):
if coordinates[0] % 1 == 0 and coordinates[1] % 1 == 0:
return True
else:
return False
def get_nearest_valid_coordinates(self, coordinates):
return (round(coordinates[0]),
round(coordinates[1]), 0.0)
def get_dimension_count(self):
return 2
def get_distance(self, start, end):
return abs(start[0] - end[0]) + abs(start[1] - end[1])
def get_center(self):
return 0, 0, 0
import math
from grids.Grid import Grid
class TriangularGrid(Grid):
def __init__(self, size):
super().__init__()
self._size = size
@property
def size(self):
return self._size
@property
def directions(self):
return {"NE": (0.5, 1, 0),
"E": (1, 0, 0),
"SE": (0.5, -1, 0),
"SW": (-0.5, -1, 0),
"W": (-1, 0, 0),
"NW": (-0.5, 1, 0)}
def get_box(self, width):
locs = []
for y in range(-int(width/2),int(width/2)):
for x in range(-int(width / 2), int(width / 2)):
if y % 2 == 0:
locs.append((x, y, 0.0))
else:
locs.append((x+0.5, y, 0.0))
return locs
def are_valid_coordinates(self, coordinates):
if not coordinates[2] == 0.0:
return False
if coordinates[1] % 2.0 == 0.0: