IRESTE/CarController.py
2022-05-09 15:48:24 +02:00

220 lines
7.6 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 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.infoWidget = None
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":
if(self.infoWidget is not None) :
wId=self.infoWidget.addItem(carInfo(self.infoWidget), vehicle.id)
self.cars.append(Car(vehicle.id,route,vehicle.depart,self.map,self,self.infoWidget.widget(wId)))
else:
self.cars.append(Car(vehicle.id,route,vehicle.depart,self.map,self,None))
elif vehicle.name == "flow":
randomFlow = 0
burstInterval = 1
burstTime = 1
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")
self.flows.append(Flow(vehicle.id, route, vehicle.begin, vehicle.vehsPerHour, randomFlow, burstInterval, burstTime, 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
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):
for ind,car in enumerate(self.cars):
selectedId = self.infoWidget.currentIndex()
selectedCar = self.cars[selectedId]
if ind == selectedId:
painter.setPen(Qt.green)
elif(selectedCar.leader is not None and selectedCar.leader.id == car.id):
painter.setPen(Qt.red)
else:
painter.setPen(Qt.white)
car.draw(painter)
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])