init
This commit is contained in:
+4
-176
@@ -1,176 +1,4 @@
|
|||||||
# ---> Python
|
/output/
|
||||||
# Byte-compiled / optimized / DLL files
|
/venv/
|
||||||
__pycache__/
|
/.idea/
|
||||||
*.py[cod]
|
*.avi
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
cover/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
.pybuilder/
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
|
||||||
# .python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# UV
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
||||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
||||||
# commonly ignored for libraries.
|
|
||||||
#uv.lock
|
|
||||||
|
|
||||||
# poetry
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
||||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
||||||
# commonly ignored for libraries.
|
|
||||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
||||||
#poetry.lock
|
|
||||||
|
|
||||||
# pdm
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
||||||
#pdm.lock
|
|
||||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
||||||
# in version control.
|
|
||||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
||||||
.pdm.toml
|
|
||||||
.pdm-python
|
|
||||||
.pdm-build/
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
# pytype static type analyzer
|
|
||||||
.pytype/
|
|
||||||
|
|
||||||
# Cython debug symbols
|
|
||||||
cython_debug/
|
|
||||||
|
|
||||||
# PyCharm
|
|
||||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
||||||
#.idea/
|
|
||||||
|
|
||||||
# Ruff stuff:
|
|
||||||
.ruff_cache/
|
|
||||||
|
|
||||||
# PyPI configuration file
|
|
||||||
.pypirc
|
|
||||||
|
|
||||||
|
|||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
from math import log, ceil
|
||||||
|
from operator import itemgetter
|
||||||
|
from classes import *
|
||||||
|
|
||||||
|
class SolvingAlgorithm:
|
||||||
|
def __init__(self,space,gMngr:GarageManager):
|
||||||
|
self.space:MetricSpace = space
|
||||||
|
self.garageManager:GarageManager = gMngr
|
||||||
|
self.amountTraveled = 0
|
||||||
|
|
||||||
|
def getGarageForCar(self,car:Point):
|
||||||
|
garages:List[Garage] = list(self.garageManager.garages)
|
||||||
|
garages = sorted(garages,key=lambda g: self.space.distancefunction.apply(car,g))
|
||||||
|
|
||||||
|
for g in garages:
|
||||||
|
if self.garageManager.is_full(g):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
g.cars_parked.append(g)
|
||||||
|
self.amountTraveled += self.space.distancefunction.apply(car,g)
|
||||||
|
return g
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class MST():
|
||||||
|
@classmethod
|
||||||
|
def _helper_getListInPointset(self, pointesets:List[List[Point]] , point:tuple):
|
||||||
|
for li in pointesets:
|
||||||
|
if point in li:
|
||||||
|
return li
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, points:set, distancefunction: DistanceFunction,space:MetricSpace, powerTWO = False,mst_visualize=True):
|
||||||
|
self.points = points
|
||||||
|
self.distancefunction = distancefunction
|
||||||
|
|
||||||
|
all_edges = []
|
||||||
|
for i in self.points:
|
||||||
|
for j in self.points:
|
||||||
|
if not i == j:
|
||||||
|
if not (j,i, distancefunction.apply(i,j)) in all_edges:
|
||||||
|
all_edges.append((i,j, distancefunction.apply(i,j)))
|
||||||
|
|
||||||
|
all_edges = sorted(all_edges,key=itemgetter(2))
|
||||||
|
|
||||||
|
minimal_edges = [] # edge is represented by (i,j, distance/Weight)
|
||||||
|
pointSets:List[List[Point]] = []
|
||||||
|
for p in self.points:
|
||||||
|
pointSets.append([p])
|
||||||
|
|
||||||
|
visualisations =[]
|
||||||
|
for edge in all_edges:
|
||||||
|
if len(pointSets) <= 1: break
|
||||||
|
li0 = MST._helper_getListInPointset(pointSets,edge[0])
|
||||||
|
li1 = MST._helper_getListInPointset(pointSets,edge[1])
|
||||||
|
|
||||||
|
if not( li0 == li1):
|
||||||
|
minimal_edges.append(edge)
|
||||||
|
|
||||||
|
li_new = li0 + li1
|
||||||
|
pointSets.remove(li0)
|
||||||
|
pointSets.remove(li1)
|
||||||
|
pointSets.append( li_new)
|
||||||
|
|
||||||
|
if (mst_visualize):
|
||||||
|
a= frameGenerator.point_to_pixel_center(space,edge[0])
|
||||||
|
b= frameGenerator.point_to_pixel_center(space,edge[1])
|
||||||
|
data = [ a[0], a[1], b[0], b [1], (23,64,96,100)]
|
||||||
|
visualisations.append(RenderTask(RenderTaskType.LINE,"mst",data))
|
||||||
|
RenderTaskStack.add_single_frame_render(RenderTaskFrame(visualisations.copy()))
|
||||||
|
|
||||||
|
if(powerTWO):
|
||||||
|
for x in range(len(minimal_edges)):
|
||||||
|
c_edge = minimal_edges[x]
|
||||||
|
c_edge = ( c_edge[0], c_edge[1], 2**ceil(log(c_edge[2],2)) )
|
||||||
|
minimal_edges[x] = c_edge
|
||||||
|
|
||||||
|
if (mst_visualize):
|
||||||
|
RenderTaskStack.add_single_frame_render(RenderTaskFrame(visualisations.copy(),True))
|
||||||
|
|
||||||
|
self.minimalEdges: List[tuple[Point,Point,float]] = minimal_edges
|
||||||
|
|
||||||
|
def _dfs_recursive(self, tree, start, visited =[]):
|
||||||
|
# due tue MST property,
|
||||||
|
tour = []
|
||||||
|
|
||||||
|
for edge in tree:# go throug all edges and recursively walk down all that lead to new places, on return add back edge
|
||||||
|
if edge[0] == start and edge[1] not in visited:
|
||||||
|
tour.append(edge)
|
||||||
|
visited.append(start) # visited only needs to be carried in for a node downwards but not upwards, since this is a MST
|
||||||
|
data = self._dfs_recursive(tree,edge[1],visited)
|
||||||
|
tour+= data # add subtree
|
||||||
|
tour.append((edge[1],edge[0],edge[2])) #append reversed edge
|
||||||
|
|
||||||
|
return tour
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_dfs_eulerwalk(self,start:Point, level= 0):
|
||||||
|
directionalEdges = []
|
||||||
|
for min_edge in self.minimalEdges:
|
||||||
|
i,j,dist = min_edge
|
||||||
|
if dist > 2**level: continue
|
||||||
|
directionalEdges.append((i,j,dist))
|
||||||
|
directionalEdges.append((j,i,dist))
|
||||||
|
|
||||||
|
# create walk with dfs
|
||||||
|
walk:List[tuple[Point,Point,float]] = self._dfs_recursive(directionalEdges,start)
|
||||||
|
|
||||||
|
return walk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AlgorithmA(SolvingAlgorithm):
|
||||||
|
def __init__(self, space:MetricSpace, gMngr: GarageManager):
|
||||||
|
super().__init__(space, gMngr)
|
||||||
|
gar_set = set(gMngr.garages)
|
||||||
|
self.mst = MST(gar_set,space.distancefunction,space,True)
|
||||||
|
|
||||||
|
def getGarageForCar(self, car: Point):
|
||||||
|
|
||||||
|
return super().getGarageForCar(car)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+493
@@ -0,0 +1,493 @@
|
|||||||
|
import typing
|
||||||
|
import builtins
|
||||||
|
import math
|
||||||
|
from enum import Enum
|
||||||
|
from math import fabs
|
||||||
|
|
||||||
|
from PIL import Image, ImageFilter
|
||||||
|
import os
|
||||||
|
|
||||||
|
from typing import NamedTuple, List
|
||||||
|
|
||||||
|
DIRECTORY = os.path.dirname(os.path.abspath(__file__))+"/"
|
||||||
|
PLOT_EMPTY = Image.open(DIRECTORY+"sprites/emptySprite.png").convert("RGBA")
|
||||||
|
PLOT_GARAGE = Image.open(DIRECTORY+"sprites/Park.png").convert("RGBA")
|
||||||
|
PLOT_CAR = Image.open(DIRECTORY+"sprites/car.png").convert("RGBA")
|
||||||
|
PLOT_GARAGE_CAR = Image.open(DIRECTORY+"sprites/CarOnPark.png").convert("RGBA")
|
||||||
|
OUTPUT_DIR = DIRECTORY + "output/"
|
||||||
|
|
||||||
|
FULL_GARAGE_COLOR = (1,0.5,0.5,1)
|
||||||
|
full_garage_sprite = PLOT_GARAGE.copy()
|
||||||
|
r,g,b,a = full_garage_sprite.split()
|
||||||
|
r = r.point(lambda i: i * FULL_GARAGE_COLOR[0])
|
||||||
|
g = g.point(lambda i: i * FULL_GARAGE_COLOR[1])
|
||||||
|
b = b.point(lambda i: i * FULL_GARAGE_COLOR[2])
|
||||||
|
a = a.point(lambda i: i * FULL_GARAGE_COLOR[3])
|
||||||
|
full_garage_sprite = Image.merge("RGBA",(r,g,b,a))
|
||||||
|
|
||||||
|
class RenderTaskType(Enum):
|
||||||
|
LINE = 1 # data [x,y,x2,y2,color(r,g,b,a)]
|
||||||
|
|
||||||
|
class RenderTask():
|
||||||
|
def __init__(self, type: RenderTaskType, name:str , data :list):
|
||||||
|
self.type = type
|
||||||
|
self.name = name
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
class RenderTaskFrame:
|
||||||
|
def __init__(self,tasks:List[RenderTask],become_permanent:bool = False, become_temp:bool = False):
|
||||||
|
self.tasks:List[RenderTask] = tasks
|
||||||
|
self.become_permanent:bool = become_permanent
|
||||||
|
self.become_temp:bool = become_temp
|
||||||
|
|
||||||
|
class RenderTaskStack:
|
||||||
|
_Tasks:List[RenderTask] = []
|
||||||
|
_TempStack:List[RenderTask] = []
|
||||||
|
_SingleFrameRenderTaskList: List[RenderTaskFrame] = []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def has_frame():
|
||||||
|
return len(RenderTaskStack._SingleFrameRenderTaskList) >0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_all():
|
||||||
|
RenderTaskStack._Tasks = []
|
||||||
|
RenderTaskStack._TempStack = []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_temp(task:RenderTask):
|
||||||
|
RenderTaskStack._TempStack.append(task)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_temps(tasks:List[RenderTask]):
|
||||||
|
RenderTaskStack._TempStack += tasks
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_temp():
|
||||||
|
RenderTaskStack._TempStack = []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_permanent( task: RenderTask):
|
||||||
|
RenderTaskStack._Tasks.append(task)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_permanents(task: List[RenderTask]):
|
||||||
|
RenderTaskStack._Tasks+=task
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_single_frame_render(frame: RenderTaskFrame):
|
||||||
|
RenderTaskStack._SingleFrameRenderTaskList.append(frame)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def pop_single_frame_render()->RenderTaskFrame:
|
||||||
|
return RenderTaskStack._SingleFrameRenderTaskList.pop(0)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_permanents():
|
||||||
|
return RenderTaskStack._Tasks.copy()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_temps():
|
||||||
|
return RenderTaskStack._TempStack.copy()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# füge alle kanten in eine set hinzu, sorte dis liste bei distance und pick die kürzesten die nen neuen knoten hinzufügen
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Linedrawer():
|
||||||
|
@staticmethod
|
||||||
|
def plotLineLow(x0, y0, x1, y1):
|
||||||
|
dx = x1 - x0
|
||||||
|
dy = y1 - y0
|
||||||
|
yi = 1
|
||||||
|
if dy < 0:
|
||||||
|
yi = -1
|
||||||
|
dy = -dy
|
||||||
|
D = (2 * dy) - dx
|
||||||
|
y = y0
|
||||||
|
|
||||||
|
points = []
|
||||||
|
for x in range( x0,x1):
|
||||||
|
points.append((x, y+1))
|
||||||
|
if D > 0:
|
||||||
|
y = y + yi
|
||||||
|
D = D + (2 * (dy - dx))
|
||||||
|
else:
|
||||||
|
D = D + 2*dy
|
||||||
|
|
||||||
|
return points
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def plotLineHigh(x0, y0, x1, y1):
|
||||||
|
dx = x1 - x0
|
||||||
|
dy = y1 - y0
|
||||||
|
xi = 1
|
||||||
|
if dx < 0:
|
||||||
|
xi = -1
|
||||||
|
dx = -dx
|
||||||
|
D = (2 * dx) - dy
|
||||||
|
x = x0
|
||||||
|
points = []
|
||||||
|
for y in range(y0, y1):
|
||||||
|
points.append((x, y+1))
|
||||||
|
if D > 0:
|
||||||
|
x = x + xi
|
||||||
|
D = D + (2 * (dx - dy))
|
||||||
|
else:
|
||||||
|
D = D + 2*dx
|
||||||
|
|
||||||
|
return points
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
## bresenhams line algo #########
|
||||||
|
def plotLine(x0, y0, x1, y1):
|
||||||
|
if abs(y1 - y0) < abs(x1 - x0):
|
||||||
|
if x0 > x1:
|
||||||
|
return Linedrawer.plotLineLow(x1, y1, x0, y0)
|
||||||
|
else:
|
||||||
|
return Linedrawer.plotLineLow(x0, y0, x1, y1)
|
||||||
|
else:
|
||||||
|
if y0 > y1:
|
||||||
|
return Linedrawer.plotLineHigh(x1, y1, x0, y0)
|
||||||
|
else:
|
||||||
|
return Linedrawer.plotLineHigh(x0, y0, x1, y1)
|
||||||
|
|
||||||
|
#################
|
||||||
|
@staticmethod
|
||||||
|
def draw_line_between_points(img:Image, x1,y1,x2,y2,color = (255,255,255))-> Image:
|
||||||
|
if(x1==x2 and y1 == y2):
|
||||||
|
x1+=10
|
||||||
|
x2-=10
|
||||||
|
pixels = img.load() # create the pixel map
|
||||||
|
|
||||||
|
print((x1,y1,x2,y2))
|
||||||
|
points = Linedrawer.plotLine(x1,y1,x2,y2)
|
||||||
|
|
||||||
|
for pt in points:
|
||||||
|
if pt[0] >= 0 and pt[0] <img.size[0] and pt[1] >= 0 and pt[1] <img.size[1]:
|
||||||
|
pixels[pt[0],pt[1]] = color
|
||||||
|
pixels[pt[0],pt[1]-1] = color
|
||||||
|
pixels[pt[0],pt[1]+1] = color
|
||||||
|
pixels[pt[0]+1,pt[1]] = color
|
||||||
|
pixels[pt[0]+1,pt[1]] = color
|
||||||
|
|
||||||
|
return img
|
||||||
|
|
||||||
|
class Point():
|
||||||
|
def __init__(self,x,y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
|
||||||
|
def get_location(self):
|
||||||
|
return Point(self.x,self.y)
|
||||||
|
|
||||||
|
def __eq__(self, value):
|
||||||
|
if not isinstance(value,Point): return False
|
||||||
|
return value.x == self.x and value.y == self.y
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.x, self.y))
|
||||||
|
|
||||||
|
class Car(Point):
|
||||||
|
"""A class which represents a car"""
|
||||||
|
def __init__(self, p:Point, timestamp:int,walk = 0):
|
||||||
|
super().__init__(p.x, p.y)
|
||||||
|
self.timestamp:int = timestamp
|
||||||
|
self.walk = walk
|
||||||
|
|
||||||
|
def get_location(self):
|
||||||
|
return super().get_location()
|
||||||
|
|
||||||
|
def get_walk(self):
|
||||||
|
return self.walk
|
||||||
|
|
||||||
|
def set_walk(self,value):
|
||||||
|
self.walk = value
|
||||||
|
|
||||||
|
def add_to_walk(self,value):
|
||||||
|
self.walk += value
|
||||||
|
|
||||||
|
def __eq__(self, value):
|
||||||
|
if not isinstance(value,Car): return False
|
||||||
|
return value.x == self.x and value.y == self.y and self.timestamp == value.timestamp
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.x, self.y,self.timestamp))
|
||||||
|
|
||||||
|
class Garage(Point):
|
||||||
|
"""A class which represents a garage"""
|
||||||
|
def __init__(self, p:Point, max_capacity):
|
||||||
|
super().__init__(p.x, p.y)
|
||||||
|
self.max_capacity = max_capacity
|
||||||
|
self.cars_parked = []
|
||||||
|
|
||||||
|
def get_location(self):
|
||||||
|
return super().get_location()
|
||||||
|
|
||||||
|
def __eq__(self, value):
|
||||||
|
if not isinstance(value,Garage): return False
|
||||||
|
return value.x == self.x and value.y == self.y and self.max_capacity == value.max_capacity
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.x, self.y,self.max_capacity,1))# hash with 1 to avoid collisions witch car class
|
||||||
|
|
||||||
|
|
||||||
|
class DistanceFunction():
|
||||||
|
def apply(self, pointA: Point, pointB: Point):
|
||||||
|
return math.sqrt( ( (pointA.x-pointB.x) **2) + ( (pointA.y-pointB.y) **2) )
|
||||||
|
|
||||||
|
|
||||||
|
class MetricSpace:
|
||||||
|
@staticmethod
|
||||||
|
def getPopulatedSpace(x,y):
|
||||||
|
points = set()
|
||||||
|
for i in range(x):
|
||||||
|
for j in range(y):
|
||||||
|
points.add(Point(i,j))
|
||||||
|
return MetricSpace(points,DistanceFunction())
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self,points:set, distancefunction:DistanceFunction):
|
||||||
|
self.points: set = points
|
||||||
|
self.distancefunction:DistanceFunction = distancefunction
|
||||||
|
|
||||||
|
def get_max_min_values(self)->list:
|
||||||
|
if(len(self.points)==0): return None
|
||||||
|
|
||||||
|
point = self.points.pop()
|
||||||
|
self.points.add(point)
|
||||||
|
|
||||||
|
x_max = point.x
|
||||||
|
y_max = point.y
|
||||||
|
x_min = x_max
|
||||||
|
y_min = y_max
|
||||||
|
|
||||||
|
for p in self.points:
|
||||||
|
if p.x > x_max: x_max = p.x
|
||||||
|
if p.y > y_max: y_max = p.y
|
||||||
|
if p.x < x_min: x_min = p.x
|
||||||
|
if p.y < y_min: y_min = p.y
|
||||||
|
|
||||||
|
x_dif = x_max-x_min
|
||||||
|
y_dif = y_max-y_min
|
||||||
|
|
||||||
|
return [x_max,y_max,x_min,y_min, x_dif +1,y_dif+1]
|
||||||
|
|
||||||
|
class GarageManager:
|
||||||
|
def __init__(self, garages:set, capacities:dict ={}):
|
||||||
|
self.garages:set[Garage] = garages
|
||||||
|
|
||||||
|
# To delete
|
||||||
|
self.capacities = capacities
|
||||||
|
self.garageArrays = []
|
||||||
|
self.currentFillLevel = capacities.copy()
|
||||||
|
|
||||||
|
# initialize capacities
|
||||||
|
for x in self.currentFillLevel.keys():
|
||||||
|
self.currentFillLevel[x]=0
|
||||||
|
|
||||||
|
def is_full(self, garage:Point):
|
||||||
|
garage_found = False
|
||||||
|
current_garage:Garage
|
||||||
|
|
||||||
|
for g in self.garages:
|
||||||
|
if g.x == garage.x and g.y == garage.y:
|
||||||
|
current_garage = g
|
||||||
|
garage_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not garage_found:
|
||||||
|
raise RuntimeError(" garage not found in is Full check")
|
||||||
|
|
||||||
|
return current_garage.max_capacity <= len(current_garage.cars_parked)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getCurrentCapacity(self, garage:Point):
|
||||||
|
"""DEPRECATED"""
|
||||||
|
raise DeprecationWarning()
|
||||||
|
return self.currentFillLevel.get(garage,-99)
|
||||||
|
|
||||||
|
def getMaxCapacity(self, garage:Point):
|
||||||
|
raise DeprecationWarning()
|
||||||
|
return self.capacities.get(garage,-99)
|
||||||
|
|
||||||
|
def addToCapacity(self,garage:Point,amount):
|
||||||
|
raise DeprecationWarning()
|
||||||
|
self.currentFillLevel[garage] = self.getCurrentCapacity(garage) + amount
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class frameGenerator():
|
||||||
|
def __init__(self, space:MetricSpace, garages:GarageManager):
|
||||||
|
self.space = space
|
||||||
|
self.garages:GarageManager = garages
|
||||||
|
self.garagePoints = []
|
||||||
|
for g in garages.garages:
|
||||||
|
self.garagePoints.append(g.get_location())
|
||||||
|
self.car_exists :bool = False
|
||||||
|
self.car:Point = None
|
||||||
|
|
||||||
|
self.space_limits = space.get_max_min_values()
|
||||||
|
"[ x_max, y_max, x_min, y_min, x_dif, y_dif]"
|
||||||
|
|
||||||
|
self.frame_width = (self.space_limits[4]*34)-2 # plot +2 pixel for road -2 for end
|
||||||
|
self.frame_height = (self.space_limits[5]*34)-2 # plot +2 pixel for road -2 for end
|
||||||
|
|
||||||
|
self.time = 0
|
||||||
|
self.frameNum = 0
|
||||||
|
|
||||||
|
|
||||||
|
def spawnCar(self,point:Point):
|
||||||
|
if(not self.car_exists):
|
||||||
|
self.frameNum = 0
|
||||||
|
self.time += 1
|
||||||
|
self.car = point
|
||||||
|
self.car_exists= True
|
||||||
|
|
||||||
|
self.renderFrame()
|
||||||
|
else:
|
||||||
|
print("ERROR: double cars!!!!")
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
def add_transition(self, point_B:Point):
|
||||||
|
if(self.car_exists):
|
||||||
|
x0,y0 =self._point_to_pixel_center(self.car)
|
||||||
|
x1,y1 =self._point_to_pixel_center(point_B)
|
||||||
|
rend_task = RenderTask(RenderTaskType.LINE, "transition",[x0,y0,x1,y1, (255,100,100,200)])
|
||||||
|
RenderTaskStack.add_single_frame_render(RenderTaskFrame( [rend_task]))
|
||||||
|
self.renderFrame()
|
||||||
|
self.car = point_B
|
||||||
|
self.renderFrame()
|
||||||
|
self.car = None
|
||||||
|
self.car_exists= False
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("ERROR: no cars was driven somewhere!!!!")
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
|
||||||
|
def _point_to_pixel(self, point:Point)->tuple:
|
||||||
|
x = point.x-self.space_limits[2]#xmin
|
||||||
|
y = point.y-self.space_limits[3]#ymin
|
||||||
|
|
||||||
|
pix_x = x*34
|
||||||
|
pix_y = y*34
|
||||||
|
|
||||||
|
return (pix_x,pix_y)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def point_to_pixel_center(space, point: Point) -> tuple:
|
||||||
|
space_limits = space.get_max_min_values()
|
||||||
|
x = point.x - space_limits[2] # xmin
|
||||||
|
y = point.y - space_limits[3] # ymin
|
||||||
|
|
||||||
|
pix_x = x * 34 + 16
|
||||||
|
pix_y = y * 34 + 16
|
||||||
|
|
||||||
|
return (pix_x, pix_y)
|
||||||
|
|
||||||
|
|
||||||
|
def _point_to_pixel_center(self, point:Point)->tuple:
|
||||||
|
x = point.x-self.space_limits[2]#xmin
|
||||||
|
y = point.y-self.space_limits[3]#ymin
|
||||||
|
|
||||||
|
pix_x = x*34 +16
|
||||||
|
pix_y = y*34 +16
|
||||||
|
|
||||||
|
return (pix_x,pix_y)
|
||||||
|
|
||||||
|
def _insert_Image(self, frame , pix_x,pix_y, image:Image):
|
||||||
|
img:Image.core.PixelAccess = image.load()
|
||||||
|
fme:Image.core.PixelAccess = frame.load()
|
||||||
|
width, height = image.size
|
||||||
|
for x in range(width):
|
||||||
|
for y in range(height):
|
||||||
|
if img[x,y] != (0,0,0,0):
|
||||||
|
fme[pix_x+x,pix_y+y] = img[x,y]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def renderFrame(self, drawLine = False, LineColor = (200,0,0,200), endPoint:Point = None ):
|
||||||
|
frame = Image.new("RGBA",(self.frame_width,self.frame_height),(100,100,100,255))
|
||||||
|
|
||||||
|
for p in self.space.points:
|
||||||
|
x,y = self._point_to_pixel(p)
|
||||||
|
|
||||||
|
img = PLOT_EMPTY
|
||||||
|
if((self.car_exists) and (p.get_location() == self.car.get_location()) and (p.get_location() in self.garagePoints)):
|
||||||
|
img = PLOT_GARAGE_CAR
|
||||||
|
elif(self.car_exists and p.get_location() == self.car.get_location()):
|
||||||
|
img = PLOT_CAR
|
||||||
|
elif(p.get_location() in self.garagePoints):
|
||||||
|
if self.garages.is_full(p):
|
||||||
|
img = full_garage_sprite
|
||||||
|
else:
|
||||||
|
img = PLOT_GARAGE
|
||||||
|
|
||||||
|
self._insert_Image(frame, x, y,img)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# render temp and permanent
|
||||||
|
static_overlay = Image.new("RGBA", (self.frame_width, self.frame_height), (0, 0, 0, 0))
|
||||||
|
for ta in RenderTaskStack.get_permanents():
|
||||||
|
if ta.type == RenderTaskType.LINE:
|
||||||
|
car_x, car_y = ta.data[0], ta.data[1]
|
||||||
|
ep_x, ep_y = ta.data[2], ta.data[3]
|
||||||
|
Linedrawer.draw_line_between_points(static_overlay, car_x, car_y, ep_x, ep_y, ta.data[4])
|
||||||
|
|
||||||
|
for ta in RenderTaskStack.get_temps():
|
||||||
|
if ta.type == RenderTaskType.LINE:
|
||||||
|
car_x, car_y = ta.data[0], ta.data[1]
|
||||||
|
ep_x, ep_y = ta.data[2], ta.data[3]
|
||||||
|
Linedrawer.draw_line_between_points(static_overlay, car_x, car_y, ep_x, ep_y, ta.data[4])
|
||||||
|
|
||||||
|
frame = Image.alpha_composite(frame, static_overlay)
|
||||||
|
|
||||||
|
# _Tasks:List[RenderTask] = []
|
||||||
|
# _TempStack:List[RenderTask] = []
|
||||||
|
# _SingleFrameRenderTaskList: List[RenderTaskFrame] = []
|
||||||
|
firstInteration:bool = True
|
||||||
|
frame_src = frame.copy()
|
||||||
|
while (firstInteration or RenderTaskStack.has_frame()):
|
||||||
|
frame = frame_src.copy()
|
||||||
|
passingOverlay = Image.new("RGBA", (self.frame_width, self.frame_height), (0, 0, 0, 0))
|
||||||
|
if RenderTaskStack.has_frame():
|
||||||
|
framedata:RenderTaskFrame = RenderTaskStack.pop_single_frame_render()
|
||||||
|
# process task per frame
|
||||||
|
for ta in framedata.tasks:
|
||||||
|
if ta.type == RenderTaskType.LINE:
|
||||||
|
car_x,car_y = ta.data[0],ta.data[1]
|
||||||
|
ep_x,ep_y = ta.data[2],ta.data[3]
|
||||||
|
Linedrawer.draw_line_between_points(passingOverlay,car_x,car_y,ep_x,ep_y, ta.data[4])
|
||||||
|
|
||||||
|
# handle migration
|
||||||
|
if framedata.become_temp:
|
||||||
|
RenderTaskStack.add_temps(framedata.tasks)
|
||||||
|
if framedata.become_permanent:
|
||||||
|
RenderTaskStack.add_permanents(framedata.tasks)
|
||||||
|
|
||||||
|
#add overlay
|
||||||
|
frame = Image.alpha_composite(frame,passingOverlay)
|
||||||
|
|
||||||
|
# save
|
||||||
|
frame.save(OUTPUT_DIR +f"frame-t{self.time:03d}-f{self.frameNum:02d}.png",format="PNG")
|
||||||
|
|
||||||
|
self.frameNum += 1
|
||||||
|
firstInteration = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
from math import ceil
|
||||||
|
|
||||||
|
from PIL.ImageChops import offset
|
||||||
|
|
||||||
|
if "clip005.avi".endswith(".png"):
|
||||||
|
raise RuntimeError;
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
from algorithms import *
|
||||||
|
from classes import *
|
||||||
|
import os
|
||||||
|
import cv2
|
||||||
|
import random
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
FRAME_MULTIPLIER_VIDEO = 10
|
||||||
|
|
||||||
|
def renderTomp4(removeImageSource = True):
|
||||||
|
img_list_unfiltered = os.listdir(OUTPUT_DIR)
|
||||||
|
img_list =[]
|
||||||
|
|
||||||
|
for x in img_list_unfiltered:
|
||||||
|
if (""+x).endswith(".png"):
|
||||||
|
img_list.append(x)
|
||||||
|
|
||||||
|
# for x in img_list:
|
||||||
|
# if not x.endswith(".png"):
|
||||||
|
# print("removed: "+x)
|
||||||
|
# img_list.remove(x)
|
||||||
|
# else:
|
||||||
|
# print("keept: "+x)
|
||||||
|
#
|
||||||
|
# print(img_list)
|
||||||
|
#
|
||||||
|
img_list.sort()
|
||||||
|
img_array = []
|
||||||
|
size = (100,100)
|
||||||
|
frameindex = 0
|
||||||
|
for filename in img_list:
|
||||||
|
frameindex += 1
|
||||||
|
img = cv2.imread(OUTPUT_DIR + filename)
|
||||||
|
if(img is None):
|
||||||
|
print("loadingError: "+filename)
|
||||||
|
return
|
||||||
|
height, width, layers = img.shape
|
||||||
|
size = (width, height)
|
||||||
|
img_array+=[img]*FRAME_MULTIPLIER_VIDEO
|
||||||
|
|
||||||
|
clipIndex = 0
|
||||||
|
while( os.path.exists(OUTPUT_DIR+f"clip{clipIndex:03d}.avi")):
|
||||||
|
clipIndex +=1
|
||||||
|
|
||||||
|
out = cv2.VideoWriter(OUTPUT_DIR+f"clip{clipIndex:03d}.avi", cv2.VideoWriter_fourcc(*'DIVX'), 15, size)
|
||||||
|
|
||||||
|
for i in range(len(img_array)):
|
||||||
|
out.write(img_array[i])
|
||||||
|
out.release()
|
||||||
|
|
||||||
|
if not removeImageSource: return
|
||||||
|
for x in img_list:
|
||||||
|
os.remove(OUTPUT_DIR + x)
|
||||||
|
|
||||||
|
def createRandomSubspace(points:set,size):
|
||||||
|
pointslist = list(points)
|
||||||
|
random.shuffle(pointslist)
|
||||||
|
return set(pointslist[:size])
|
||||||
|
|
||||||
|
def createRandomsListSequence(points:set):#, garages:set
|
||||||
|
pointslist = list(points)*5
|
||||||
|
if len(pointslist) < 50:
|
||||||
|
pointslist = pointslist * int(ceil(50/len(pointslist))+1)
|
||||||
|
random.shuffle(pointslist)
|
||||||
|
cars = pointslist[:50]
|
||||||
|
#gar = list(garages)
|
||||||
|
|
||||||
|
#garageOrder =[]
|
||||||
|
#for x in range(len(cars)):
|
||||||
|
# random.shuffle(gar)
|
||||||
|
# garageOrder.append(gar[0])
|
||||||
|
|
||||||
|
return cars #(cars,garageOrder)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# seeded randomness
|
||||||
|
random.seed(0)
|
||||||
|
space = MetricSpace.getPopulatedSpace(10,10)
|
||||||
|
|
||||||
|
ammountToKeep = random.randint(20,95)
|
||||||
|
|
||||||
|
points = createRandomSubspace(space.points,ammountToKeep)
|
||||||
|
func = space.distancefunction
|
||||||
|
|
||||||
|
space = MetricSpace(points,func)
|
||||||
|
|
||||||
|
# generate garages
|
||||||
|
garagesCount = random.randint(3, 8)
|
||||||
|
garages_locations = createRandomSubspace(points, garagesCount)
|
||||||
|
capactiyPerGarage = math.ceil(50.0/garagesCount)
|
||||||
|
#create Garage capacity
|
||||||
|
garages: List[Garage] = []
|
||||||
|
for x in garages_locations:
|
||||||
|
garages.append(Garage(x,capactiyPerGarage))
|
||||||
|
|
||||||
|
gMngr = GarageManager(garages)
|
||||||
|
|
||||||
|
# initiate solving Algorithm
|
||||||
|
algo : SolvingAlgorithm = SolvingAlgorithm(space,gMngr)
|
||||||
|
algo : SolvingAlgorithm = AlgorithmA(space,gMngr)
|
||||||
|
|
||||||
|
# sequence = createRandomsListSequence(points.difference(garages),garages) squence without garages
|
||||||
|
#sequence = createRandomsListSequence(points)
|
||||||
|
sequence = createRandomsListSequence(garages) # For algo A
|
||||||
|
|
||||||
|
fmg = frameGenerator(space,gMngr)
|
||||||
|
fmg.renderFrame()
|
||||||
|
|
||||||
|
for car in sequence:
|
||||||
|
fmg.spawnCar(car)
|
||||||
|
g = algo.getGarageForCar(car)
|
||||||
|
fmg.add_transition(g)
|
||||||
|
|
||||||
|
renderTomp4()
|
||||||
|
|
||||||
|
print("Traveled: "+str(algo.amountTraveled))
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 276 B |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 243 B |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 277 B |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 165 B |
Reference in New Issue
Block a user