IRESTE/CarController.py
2022-05-23 22:24:59 +02:00

264 lines
9.9 KiB
Python

import sumolib
from Car import Car
from Flow import Flow
from math import ceil, dist
from globalImport import globalImport
def pysideImports():
globalImport(globals(), "carInfo", "Ui_carInfo")
globalImport(globals(), "varEdit", "Ui_varEdit")
globalImport(globals(), "PySide6.QtWidgets", ["QWidget", "QLabel", "QToolBox"])
globalImport(globals(), "PySide6.QtCore", ["Qt", "Slot", "Signal", "QThread"])
globalImport(globals(), "PySide6.QtCharts", ["QChart", "QSplineSeries", "QLineSeries"])
globalImport(globals(), "PySide6.QtGui", ["QColor"])
class carInfo(QWidget):
def __init__(self,parent):
super().__init__()
self.ui = Ui_carInfo()
self.ui.setupUi(self)
self.maxV = 0
self.parent = parent
self.pointsCount = [0] * 4
self.minX = 0
self.chart = self.ui.speedGraph.chart()
#self.chart.setAnimationOptions(QChart.AllAnimations)
speedsNames = ["vmax","vsec","Vitesse (m.s^-1)","inter vsec"]
self.speedSeries = []
for ind,s in enumerate(speedsNames):
self.speedSeries.append(QLineSeries())
self.speedSeries[ind].setName(s)
# self.speedSeries[ind].setPointsVisible()
self.chart.addSeries(self.speedSeries[ind])
self.chart.createDefaultAxes()
@Slot(tuple)
def addSpeedPoint(self,params):
ind=params[0]
if self.parent.currentWidget() != self:
return
t=params[1]
val=params[2]
if(self.pointsCount[ind] > 200):
self.speedSeries[ind].remove(0)
self.minX = max(self.minX,self.speedSeries[ind].at(0).x())
self.pointsCount[ind] -= 1
self.speedSeries[ind].append(t,val)
self.pointsCount[ind] += 1
if self.speedSeries[ind].count()>2:
i = self.speedSeries[ind].count()-1
pm2 = self.speedSeries[ind].at(i-2)
pm1 = self.speedSeries[ind].at(i-1)
pm0 = self.speedSeries[ind].at(i)
diffL = (pm1.y() - pm2.y())/(pm1.x() - pm2.x())
diffR = (pm0.y() - pm1.y())/(pm0.x() - pm1.x())
diff2 = diffR - diffL
if diff2 == 0:
self.speedSeries[ind].remove(i-1)
self.pointsCount[ind] -= 1
xAxis = self.chart.axes(Qt.Horizontal,self.speedSeries[ind])[0]
xAxis.setRange(self.minX,t)
if val>self.maxV:
self.maxV = val
yAxis = self.chart.axes(Qt.Vertical, self.speedSeries[ind])[0]
yAxis.setMax(ceil(val+1))
self.ui.speedGraph.update()
@Slot(tuple)
def setVal(self,params):
key = params[0]
val = params[1]
obj = self.findChild(QLabel,key)
if obj is None:
return
obj.setText(f"{key} : {val}")
obj.update()
global varEdit
class varEdit(QWidget):
def __init__(self, parent, carController, varName, value):
super().__init__()
self.ui = Ui_varEdit()
self.ui.setupUi(self)
self.hookName = varName
self.ui.name.setText(varName)
self.ui.value.setValue(value)
self.CC = carController
self.ui.value.valueChanged.connect(self.valueChanged)
def valueChanged(self):
value = self.ui.value.value()
self.CC.updateConstant(self.hookName, value)
class CarController:
def __init__(self, parentMap):
self.map=parentMap
self.cars=[]
self.flows=[]
self.t=0
self.dt=1/60
self.spawnFailed = 0
self.totalStopped = 0
self.carsDestroyed = 0
self.speedPercentageTotal = 0
self.maxCars = 100 # TODO: get it from net? demand?
self.dynSpeedRat = 1
self.infoWidget = None
self.selectedId = 0
self.vroomEnable=False
def addParent(self, mainWindow):
pysideImports()
self.infoWidget=mainWindow.findChild(QToolBox, "carInfos")
varWidget = mainWindow.ui.constEdit
varWidget.addWidget(varEdit(varWidget, self, "gamma", 5))
varWidget.addWidget(varEdit(varWidget, self, "delta", 0.5))
varWidget.addWidget(varEdit(varWidget, self, "T", 0.3))
varWidget.addWidget(varEdit(varWidget, self, "size", 3))
varWidget.addWidget(varEdit(varWidget, self, "dt", self.dt))
def fromPath(self,path):
self.cars=[]
self.flows=[]
self.t=0
while self.infoWidget is not None and self.infoWidget.count() != 0:
self.infoWidget.removeItem(0)
for vehicle in sumolib.xml.parse(path,["vehicle","flow"]):
route=vehicle.route[0].edges.split()
if vehicle.name == "vehicle":
dynSpeed = '0'
IA = '0'
if(vehicle.hasChild("param")):
for param in vehicle.getChild("param"):
key = param.getAttributeSecure("key")
if key == "dynamicSpeed":
dynSpeed = param.getAttributeSecure("value")
elif key == "IA":
IA = param.getAttributeSecure("value")
if(self.infoWidget is not None) :
wId=self.infoWidget.addItem(carInfo(self.infoWidget), vehicle.id)
self.cars.append(Car(vehicle.id,route,vehicle.depart,dynSpeed,IA,self.map,self,self.infoWidget.widget(wId)))
else:
self.cars.append(Car(vehicle.id,route,vehicle.depart,dynSpeed,IA,self.map,self,None))
elif vehicle.name == "flow":
randomFlow = 0
burstInterval = 1
burstTime = 1
dynSpeed = '0'
IA = '0'
if(vehicle.hasChild("param")):
for param in vehicle.getChild("param"):
key = param.getAttributeSecure("key")
if key == "random":
randomFlow = param.getAttributeSecure("value")
elif key == "burstInterval":
burstInterval = param.getAttributeSecure("value")
elif key == "burstTime":
burstTime = param.getAttributeSecure("value")
elif key == "dynamicSpeed":
dynSpeed = param.getAttributeSecure("value")
elif key == "IA":
IA = param.getAttributeSecure("value")
self.flows.append(Flow(vehicle.id, route, vehicle.begin, vehicle.vehsPerHour, randomFlow, burstInterval, burstTime, dynSpeed, IA, self.map, self))
def prepareRoute(self):
for car in self.cars:
car.prepareRoute()
for flow in self.flows:
flow.prepareRoute()
def getCarsOnEdge(self,edgeID):
return filter(lambda c: c.route[c.index].getID()==edgeID,self.cars)
def getCarsOnLane(self,edgeID,laneID):
cars = self.getCarsOnEdge(edgeID)
return filter(lambda c: c.laneId == laneID,cars)
def getCarsClose(self, car):
cars = self.getCarsOnEdge(car.getCurrentEdge().getID())
return filter(lambda c: dist(c.pos, car.pos) < car.minSpace, cars)
def update(self):
if self.map.net is None or self.dt == 0:
return
self.t+=self.dt
self.dynSpeedRat = 1 - len(self.cars) / self.maxCars
for car in self.cars:
car.update(self.dt)
for flow in sorted(self.flows, key=lambda f: f.priority, reverse = True):
if flow.shouldSpawn(self.t):
carsClose = self.getCarsClose(flow.carModel)
try:
next(carsClose)
except StopIteration:
self.cars.append(flow.spawnCar())
else:
self.spawnFailed += 1
#flow.addCar2Counter()
flow.priority += 1
#print(f"nope, y as déjà une voiture ici : n°{self.spawnFailed}")
def draw(self,painter):
selectedCar = [c for c in self.cars if c.id == self.selectedId]
for ind,car in enumerate(self.cars):
#selectedId = self.infoWidget.currentIndex()
colorOverride = False
if len(selectedCar) == 0:
painter.setPen(Qt.white)
pass
elif car.id == self.selectedId:
painter.setPen(Qt.green)
colorOverride = True
elif(selectedCar[0].leader is not None and selectedCar[0].leader.id == car.id):
painter.setPen(Qt.red)
colorOverride = True
elif(selectedCar[0].leaderAtInter is not None and selectedCar[0].leaderAtInter.id == car.id):
painter.setPen(QColor(100,0,255))
colorOverride = True
else:
painter.setPen(Qt.white)
colorOverride = False
car.draw(painter, colorOverride)
def destroyCar(self, car):
self.carsDestroyed += 1
self.totalStopped += car.timeStopped
self.speedPercentageTotal += car.speedPercentage / car.ticksLived
self.cars.remove(car)
def updateConstant(self, name, val):
if name == "dt":
self.dt = val
return
for car in self.cars:
car.__dict__[name] = val
def getFlowBacklog(self):
return sum([f.backlog(self.t) for f in self.flows])
def selectClosest(self, pos):
if len(self.cars) == 0:
return
closest = min(self.cars, key=lambda c: dist(c.pos, [pos.x(), pos.y()]))
self.selectedId = closest.id
self.infoWidget.setCurrentIndex(self.cars.index(closest))