IRESTE/CarController.py
2022-05-14 16:10:55 +02:00

258 lines
9.3 KiB
Python

import sumolib
from Car import Car
from Flow import Flow
from carInfo import Ui_carInfo
from varEdit import Ui_varEdit
from PySide6.QtWidgets import QWidget, QLabel, QToolBox
from PySide6.QtCore import Qt, Slot, Signal, QThread
from PySide6.QtCharts import QChart, QSplineSeries, QLineSeries
from PySide6.QtGui import QColor
from math import ceil, dist
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,0,0]
self.minX = 0
self.chart = self.ui.speedGraph.chart()
#self.chart.setAnimationOptions(QChart.AllAnimations)
speedsNames = ["vmax","vsec","Vitesse (m.s^-1)"]
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()
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=True
def addParent(self, mainWindow):
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))