Commit edddcb8b authored by Ahmad Reza Cheraghi's avatar Ahmad Reza Cheraghi
Browse files

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

3d swarm sim - no vis fix

See merge request !11
parents 05a8706a d94fddf8
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
.idea/*
.idea*
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6.2 (/usr/local/bin/python3.6)" 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$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.6.2 (/usr/local/bin/python3.6)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/docs/source/_templates" />
</list>
</option>
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>
\ No newline at end of file
......@@ -4,7 +4,7 @@
seedvalue = 12
## Maximum round number in swarm-world, 0 = infinite
max_round = 10
max_round = 1000
## 1/True = Call of particles in randmom order
## 0/False = Call of particles in added order in scenario
......@@ -26,9 +26,9 @@ 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
......@@ -36,38 +36,43 @@ gui = default_gui
;# 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
;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
;particle_model_file = 3d_particle.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
;
# 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)
particle_scaling = (1.0, 1.0, 1.0)
tile_color = (0.3, 0.3, 0.8, 1.0)
tile_scaling = (1.0, 1.0, 1.0)
location_color = (0.3, 0.8, 0.3, 1.0)
location_scaling = (1.2, 1.2, 1.2)
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)
......@@ -75,7 +80,7 @@ center_color = (1.0, 0.0, 0.0, 0.5)
# background (rgb)
background_color = (1.0, 1.0, 1.0)
# color of grid lines (rgba)
line_color = (0.0, 0.0, 0.0, 1.0)
line_color = (0.0, 0.0, 0.0, 0.5)
# 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
......@@ -85,9 +90,9 @@ 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
show_coordinates = False
# flag for showing the center of the grid
show_center = False
show_center = True
# camera focus color
focus_color = (1.0, 1.0, 1.0, 0.5)
# show camera focus
......@@ -127,12 +132,17 @@ particle_mm_size = 2
tile_mm_size = 2
[File]
##Examples##
#marking (rasenmaeher) algorithm in 3D
;scenario = marking_3d_scenario
;solution = marking_3d_local
##Moving
#scenario = lonely_particle
scenario = n_particle_in_line
solution = random_walk
#scenario = n_particle_in_line
#solution = random_walk
#solution = triangular_round_walk
#solution = random_walk_with_take_and_drop
......@@ -148,6 +158,7 @@ solution = random_walk
#scenario = two_particles_tiles_markers
#solution = read_write
#scenario = test_interfaces
#solution = test_all_the_interfaces
scenario = test_interfaces
solution = test_all_the_interfaces
from abc import ABC, abstractmethod
import numpy as np
class Grid(ABC):
......@@ -195,3 +196,33 @@ class Grid(ABC):
current_ns = tmp
return current_ns
def get_nearest_direction(self, position, target):
"""
calculates the best/nearest direction for going from position to target.
its a general formula, there are/should be better solutions for specific grids!
calculates the angles of the target-position vector to the directions
and returns the direction with minimal angle
:param position: the starting position
:param target: the target position
:return: direction (float, float, float)
"""
v = (target[0]-position[0], target[1] - position[1], target[2] - position[2])
v_length = np.sqrt((v[0]*v[0])+(v[1]*v[1])+(v[2]*v[2]))
s = self.get_scaling()
best = None
best_angle = 0
for d in self.get_directions_list():
sd = (d[0]*s[0], d[1]*s[1], d[2]*s[2])
d_length = np.sqrt((sd[0]*sd[0])+(sd[1]*sd[1])+(sd[2]*sd[2]))
if d_length*v_length != 0:
angle = np.arccos((v[0]*sd[0]+v[1]*sd[1]+v[2]*sd[2])/(d_length * v_length))
if best is None:
best = d
best_angle = angle
else:
if angle < best_angle:
best_angle = angle
best = d
return best
......@@ -97,8 +97,16 @@ def sim_tab(vis, world):
world.reset()
reset_button.clicked.connect(reset_sim)
save_scenario_button = QPushButton("save Scenario")
def save_scenario():
world.save_scenario()
save_scenario_button.clicked.connect(save_scenario)
layout.addWidget(screenshot_button, alignment=Qt.AlignBaseline)
layout.addWidget(reset_button, alignment=Qt.AlignBaseline)
layout.addWidget(save_scenario_button, alignment=Qt.AlignBaseline)
layout.addStretch(0)
layout.addWidget(start_stop_button, alignment=Qt.AlignBaseline)
tab.setLayout(layout)
......@@ -115,7 +123,7 @@ def get_rps_slider(vis):
vis.set_rounds_per_second(value)
desc.setText("rounds per second (%d) : " % vis.get_rounds_per_second())
hbox.addWidget(create_slider(10, 2, 60, 1, vis.get_rounds_per_second(), set_rps), alignment=Qt.AlignBaseline)
hbox.addWidget(create_slider(10, 2, 120, 1, vis.get_rounds_per_second(), set_rps), alignment=Qt.AlignBaseline)
return hbox
......@@ -139,7 +147,6 @@ def vis_tab(vis: Visualization):
def grid_tab(vis: Visualization):
tab = QTabBar()
layout = QVBoxLayout()
layout.addLayout(get_grid_width_slider(vis))
layout.addLayout(get_grid_lines_scale_slider(vis))
layout.addLayout(get_grid_coordinates_scale_slider(vis))
layout.addLayout(get_show_checkboxes(vis))
......@@ -199,12 +206,13 @@ def get_particle_scaler(vis):
new_scaling = (current_scaling[0], current_scaling[1], value/10.0)
vis.set_particle_scaling(new_scaling)
current_scaling = vis.get_particle_scaling()
x_desc = QLabel("x scale:")
y_desc = QLabel("y scale:")
z_desc = QLabel("z scale:")
x_scaler = create_slider(2, 2, 20, 1, 10, x_scaler_change)
y_scaler = create_slider(2, 2, 20, 1, 10, y_scaler_change)
z_scaler = create_slider(2, 2, 20, 1, 10, z_scaler_change)
x_scaler = create_slider(2, 2, 20, 1, current_scaling[0]*10, x_scaler_change)
y_scaler = create_slider(2, 2, 20, 1, current_scaling[0]*10, y_scaler_change)
z_scaler = create_slider(2, 2, 20, 1, current_scaling[0]*10, z_scaler_change)
hbox1 = QHBoxLayout()
hbox1.addWidget(x_desc, alignment=Qt.AlignBaseline)
......@@ -245,12 +253,13 @@ def get_tile_scaler(vis):
new_scaling = (current_scaling[0], current_scaling[1], value/10.0)
vis.set_tile_scaling(new_scaling)
current_scaling = vis.get_tile_scaling()
x_desc = QLabel("x scale:")
y_desc = QLabel("y scale:")
z_desc = QLabel("z scale:")
x_scaler = create_slider(2, 2, 20, 1, 10, x_scaler_change)
y_scaler = create_slider(2, 2, 20, 1, 10, y_scaler_change)
z_scaler = create_slider(2, 2, 20, 1, 10, z_scaler_change)
x_scaler = create_slider(2, 2, 20, 1, current_scaling[0]*10, x_scaler_change)
y_scaler = create_slider(2, 2, 20, 1, current_scaling[1]*10, y_scaler_change)
z_scaler = create_slider(2, 2, 20, 1, current_scaling[2]*10, z_scaler_change)
hbox1 = QHBoxLayout()
hbox1.addWidget(x_desc, alignment=Qt.AlignBaseline)
......@@ -291,12 +300,13 @@ def get_location_scaler(vis):
new_scaling = (current_scaling[0], current_scaling[1], value/10.0)
vis.set_location_scaling(new_scaling)
current_scaling = vis.get_location_scaling()
x_desc = QLabel("x scale:")
y_desc = QLabel("y scale:")
z_desc = QLabel("z scale:")
x_scaler = create_slider(2, 2, 20, 1, 10, x_scaler_change)
y_scaler = create_slider(2, 2, 20, 1, 10, y_scaler_change)
z_scaler = create_slider(2, 2, 20, 1, 10, z_scaler_change)
x_scaler = create_slider(2, 2, 20, 1, current_scaling[0]*10, x_scaler_change)
y_scaler = create_slider(2, 2, 20, 1, current_scaling[1]*10, y_scaler_change)
z_scaler = create_slider(2, 2, 20, 1, current_scaling[2]*10, z_scaler_change)
hbox1 = QHBoxLayout()
hbox1.addWidget(x_desc, alignment=Qt.AlignBaseline)
......@@ -447,20 +457,6 @@ def get_color_picker(vis):
return vbox
def get_grid_width_slider(vis):
hbox = QVBoxLayout()
desc = QLabel("grid width (%d):" % vis.get_grid_line_width())
hbox.addWidget(desc, alignment=Qt.AlignBaseline)
def set_gw(value):
vis.set_grid_line_width(value)
desc.setText("grid width (%d):" % value)
hbox.addWidget(create_slider(1, 2, glGetFloatv(GL_LINE_WIDTH_RANGE)[1], 1, vis.get_grid_line_width(), set_gw),
alignment=Qt.AlignBaseline)
return hbox
def get_render_distance_slider(vis):
vbox = QVBoxLayout()
desc = QLabel("render distance (%d):" % vis.get_render_distance())
......
......@@ -43,6 +43,9 @@ class ConfigData:
self.particle_color = make_tuple(config.get("Visualization", "particle_color"))
self.tile_color = make_tuple(config.get("Visualization", "tile_color"))
self.location_color = make_tuple(config.get("Visualization", "location_color"))
self.particle_scaling = make_tuple(config.get("Visualization", "particle_scaling"))
self.tile_scaling = make_tuple(config.get("Visualization", "tile_scaling"))
self.location_scaling = make_tuple(config.get("Visualization", "location_scaling"))
self.grid_color = make_tuple(config.get("Visualization", "grid_color"))
self.cursor_color = make_tuple(config.get("Visualization", "cursor_color"))
self.background_color = make_tuple(config.get("Visualization", "background_color"))
......
......@@ -11,4 +11,5 @@ class Location(matter.Matter):
def set_color(self, color):
super().set_color(color)
self.world.vis.location_changed(self)
if self.world.vis is not None:
self.world.vis.location_changed(self)
......@@ -85,7 +85,7 @@ class Matter:
def delete_memeory_with(self, key):
del self._memory[key]
def delete_whole_memeory(self):
def delete_whole_memory(self):
self._memory.clear()
def get_id(self):
......
......@@ -95,7 +95,8 @@ class Particle(matter.Matter):
del self.world.particle_map_coordinates[self.coordinates]
self.coordinates = direction_coord
self.world.particle_map_coordinates[self.coordinates] = self
self.world.vis.particle_changed(self)
if self.world.vis is not None:
self.world.vis.particle_changed(self)
logging.info("particle %s successfully moved to %s", str(self.get_id()), direction)
self.world.csv_round.update_metrics(steps=1)
self.csv_particle_writer.write_particle(steps=1)
......@@ -107,10 +108,12 @@ class Particle(matter.Matter):
def check_for_carried_tile_or_particle(self):
if self.carried_tile is not None:
self.carried_tile.coordinates = self.coordinates
self.world.vis.tile_changed(self.carried_tile)
if self.world.vis is not None:
self.world.vis.tile_changed(self.carried_tile)
elif self.carried_particle is not None:
self.carried_particle.coordinates = self.coordinates
self.world.vis.particle_changed(self.carried_particle)
if self.world.vis is not None:
self.world.vis.particle_changed(self.carried_particle)
def check_within_border(self, direction, direction_coord):
if self.world.config_data.border == 1 and \
......@@ -384,7 +387,8 @@ class Particle(matter.Matter):
del self.world.particle_map_coordinates[self.coordinates]
self.__isCarried = True
self.coordinates = coordinates
self.world.vis.particle_changed(self)
if self.world.vis is not None:
self.world.vis.particle_changed(self)
return True
else:
return False
......@@ -399,7 +403,8 @@ class Particle(matter.Matter):
self.coordinates = coordinates
self.world.particle_map_coordinates[coordinates] = self
self.__isCarried = False
self.world.vis.particle_changed(self)
if self.world.vis is not None:
self.world.vis.particle_changed(self)
def create_tile(self):
"""
......@@ -561,7 +566,8 @@ class Particle(matter.Matter):
if self.carried_tile.take():
logging.info("Tile with tile id %s has been taken", str(tile_id))
self.carried_tile.coordinates = self.coordinates
self.world.vis.tile_changed(self.carried_tile)
if self.world.vis is not None:
self.world.vis.tile_changed(self.carried_tile)
self.world.csv_round.update_metrics(tiles_taken=1)
self.csv_particle_writer.write_particle(tiles_taken=1)
return True
......@@ -821,7 +827,8 @@ class Particle(matter.Matter):
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)
if self.world.vis is not None:
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
......@@ -922,7 +929,8 @@ class Particle(matter.Matter):
if self.world.grid.are_valid_coordinates(new_coordinates):
particle.coordinates = new_coordinates
self.world.particle_map_coordinates[new_coordinates] = particle
self.world.vis.particle_changed(particle)
if self.world.vis is not None:
self.world.vis.particle_changed(particle)
return True
else:
return False
......@@ -1060,4 +1068,5 @@ class Particle(matter.Matter):
def set_color(self, color):
super().set_color(color)
self.world.vis.particle_changed(self)
if self.world.vis is not None:
self.world.vis.particle_changed(self)
......@@ -39,7 +39,8 @@ class Tile(matter.Matter):
if self.coordinates in self.world.tile_map_coordinates:
del self.world.tile_map_coordinates[self.coordinates]
self.__isCarried = True
self.world.vis.tile_changed(self)
if self.world.vis is not None:
self.world.vis.tile_changed(self)
return True
else:
return False
......@@ -54,8 +55,10 @@ class Tile(matter.Matter):
self.coordinates = coordinates
self.world.tile_map_coordinates[self.coordinates] = self
self.__isCarried = False
self.world.vis.tile_changed(self)
if self.world.vis is not None:
self.world.vis.tile_changed(self)
def set_color(self, color):
super().set_color(color)
self.world.vis.tile_changed(self)
if self.world.vis is not None:
self.world.vis.tile_changed(self)
......@@ -9,7 +9,6 @@ import time
from lib.visualization.camera import Camera
from lib.visualization.utils import LoadingWindow
import OpenGL.GL as GL
def close(_):
exit(0)
......@@ -202,7 +201,6 @@ class Visualization:
self._wait_while_not_running()
time_elapsed = time.perf_counter() - round_start_timestamp
def remove_particle(self, particle):
"""
removes a particle from the visualization.
......@@ -383,12 +381,14 @@ class Visualization:
def set_show_center(self, show_center: bool):
self._viewer.show_center = show_center
self._viewer.glDraw()
def get_show_focus(self):
return self._viewer.show_focus
def set_show_focus(self, show_focus: bool):
self._viewer.show_focus = show_focus
self._viewer.glDraw()
def take_screenshot(self):
self._viewer.take_screenshot()
......@@ -402,18 +402,21 @@ class Visualization:
def set_particle_scaling(self, scaling):
self._viewer.programs["particle"].set_model_scaling(scaling)
self._viewer.glDraw()
def get_tile_scaling(self):
return self._viewer.programs["tile"].get_model_scaling()
def set_tile_scaling(self, scaling):
self._viewer.programs["tile"].set_model_scaling(scaling)
self._viewer.glDraw()
def get_location_scaling(self):
return self._viewer.programs["location"].get_model_scaling()
def set_location_scaling(self, scaling):
self._viewer.programs["location"].set_model_scaling(scaling)
self._viewer.glDraw()
def set_on_cursor_click_matter_type(self, matter_type):
if matter_type == 'tile' or matter_type == 'particle' or matter_type == 'location':
......
......@@ -20,7 +20,11 @@ class OGLWidget(QtOpenGL.QGLWidget):
:param world: the world class
:param camera: a camera for the visualization
"""
super(OGLWidget, self).__init__()
fmt = QtOpenGL.QGLFormat()
fmt.setVersion(3, 3)
fmt.setProfile(QtOpenGL.QGLFormat.CoreProfile)
fmt.setSampleBuffers(True)
super(OGLWidget, self).__init__(fmt)
self.debug = False
self.world = world
......@@ -118,20 +122,23 @@ class OGLWidget(QtOpenGL.QGLWidget):
# 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.glEnable(GL.GL_LINE_SMOOTH)
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())
self.programs["particle"].set_model_scaling(self.world.config_data.particle_scaling)
self.programs["tile"] = OffsetColorCarryProgram(self.world.config_data.tile_model_file)
self.programs["tile"].set_world_scaling(self.world.grid.get_scaling())
self.programs["tile"].set_model_scaling(self.world.config_data.tile_scaling)
self.programs["location"] = OffsetColorProgram(self.world.config_data.location_model_file)
self.programs["location"].set_world_scaling(self.world.grid.get_scaling())
self.programs["location"].set_model_scaling(self.world.config_data.location_scaling)
self.programs["grid"] = GridProgram(self.world.grid, self.world.config_data.line_color,
self.world.config_data.coordinates_color,
......@@ -246,7 +253,7 @@ class OGLWidget(QtOpenGL.QGLWidget):
"""
The main Draw Method.
All drawing calls originate here.
It will be called only when a new frame is needed. No new data -> no new frame
It will be called only when a new frame is needed. No change -> no new frame
:return:
"""
# clear the screen
......@@ -254,8 +261,8 @@ class OGLWidget(QtOpenGL.QGLWidget):
# draw
self.programs["particle"].draw()
self.programs["tile"].draw()
self.programs["location"].draw()
self.programs["tile"].draw()
self.programs["grid"].draw()
# center
......
This diff is collapsed.
#version 110
#version 330
varying vec4 v_color;
in vec4 v_color;
out vec4 FragColor;
void main() {
gl_FragColor = v_color;
FragColor = v_color;
}
// vertex shader for the GridProgram
#version 110
#version 330
// position vector of location model or direction line VBO 0
attribute vec3 position;
in vec3 position;
// normal vector of location model face VBO 0
attribute vec3 normal;
in vec3 normal;
// offsets of the model (location & lines) VBO 1
attribute vec3 offset;
in vec3 offset;
//projection matrix
uniform mat4 projection;
......@@ -35,7 +33,7 @@ uniform bool drawing_lines;
// varying color for fragment shader
varying vec4 v_color;
out vec4 v_color;
void main(void)
{
if(drawing_lines){
......
// vertex shader for the OffsetColorCarryProgram
#version 110
#version 330
// VBO 0 - per vertex
// vector of a face
attribute vec3 position;
in vec3 position;
// normal vector of the vector/face
attribute vec3 normal;
in vec3 normal;
// VBO 1 - per instance - position offset of the model
attribute vec3 offset;