Skip to content

Commit

Permalink
arch: WIP: Added selection list for edit mode
Browse files Browse the repository at this point in the history
Adds selection list for edit mode and model loader as well for the
aliases. The VehicleImporter should be now obsolete, the main vehicle
should be loaded from the scenario file.
  • Loading branch information
dervelakos committed Dec 31, 2024
1 parent 99aa075 commit 44e9e79
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 19 deletions.
Binary file added models/white-truck.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions models/white-truck.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#Pixel to centimeter ratio is 0.75
width: 93.75
length: 421.5

mass: 100.0
friction: 200.0

steeringAngle: 40.0
wheelDiameter: 20.0

image: 'models/white-truck.png'
axleWidth: 5.0
3 changes: 2 additions & 1 deletion run-sim.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/bash
source /opt/ros/jazzy/setup.bash
source env/bin/activate
./src/Main.py --graphics --ros
#./src/Main.py --graphics --ros
./src/Main.py --graphics --ros --scenario scenarios/campain-1.yaml
16 changes: 16 additions & 0 deletions scenarios/campain-1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
aliases:
- name: Wall
model: null
render: RectangleRender
type: Wall
- name: Vehicle
model: null
render: SimpleVehicleRender
type: Vehicle
- name: WhiteTruck
model: "models/white-truck.yaml"
render: SimpleVehicleRender
type: Vehicle
objects:
dynamic: []
static: []
13 changes: 13 additions & 0 deletions scenarios/empty.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
aliases:
- name: Wall
render: RectangleRender
type: Wall
- name: Vehicle
render: SimpleVehicleRender
type: Vehicle
- name: WhiteTruck
render: SimpleVehicleRender
type: Vehicle
objects:
dynamic: []
static: []
24 changes: 21 additions & 3 deletions src/GraphicalWindow.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import math

from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QWidget, QScrollArea, QVBoxLayout
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QWidget, QScrollArea, QHBoxLayout, QListWidget
from PyQt5.QtGui import QPainter, QMouseEvent, QColor
from PyQt5.QtCore import Qt, QTimer, QPoint, QLineF

Expand All @@ -15,11 +15,17 @@ def __init__(self, mainArea, simEngine, renderEngine, aliases):
self.drawArea = None

self.editMode = False
self.selectedListObject = next(iter(self.aliases))
print(self.selectedListObject)

def toggleEditMode(self):
self.editMode = not self.editMode
self.mainArea.selectionList.setVisible(self.editMode)
return self.editMode

def selectListObject(self, item):
self.selectedListObject = item.text()

def createObject(self):
if not self.editMode:
return
Expand Down Expand Up @@ -47,7 +53,7 @@ def createObject(self):
print (center_x, center_y, angle+90, length, width)

if self.editMode:
alias = self.aliases["Wall"]
alias = self.aliases[self.selectedListObject]
tmp = alias.genObject([center_x, center_y],
angle+90,
[length, width])
Expand Down Expand Up @@ -158,6 +164,7 @@ def mouseMoveEvent(self, event: QMouseEvent):

def mouseReleaseEvent(self, event: QMouseEvent):
if event.button() == Qt.LeftButton:
print(self.controller)
self.controller.createObject()
self.dragging = False
print(f"Start:{self.dragStartPosition}, End: {event.pos()}")
Expand Down Expand Up @@ -198,7 +205,7 @@ def __init__(self, vehicle, scenario, simEngine):
self.setCentralWidget(centralWidget)

# Create a layout for the central widget
layout = QVBoxLayout(centralWidget)
layout = QHBoxLayout(centralWidget)

# Create a scroll area
self.scrollArea = QScrollArea()
Expand All @@ -218,6 +225,17 @@ def __init__(self, vehicle, scenario, simEngine):
# Add the scroll area to the main layout
layout.addWidget(self.scrollArea)

self.selectionList = QListWidget()

for itemName in self.controller.aliases:
self.selectionList.addItem(itemName)

self.selectionList.itemClicked.connect(self.controller.selectListObject)
self.selectionList.setFixedWidth(100)
self.selectionList.setVisible(False)
layout.addWidget(self.selectionList)


# Create and setup the timer
self.timer = QTimer(self)
self.timer.timeout.connect(self.updateRotation)
Expand Down
18 changes: 17 additions & 1 deletion src/ScenarioLoader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,38 @@

from SceneObjects import *
from VehicleRender import *
from Vehicle import Vehicle

class Alias:
def __init__(self, classType, render, name):
#TODO: This initialization is too redudant simplify it
def __init__(self, classType, model, render, name):
self.classType = classType
self.model = model
self.render = render
self.name = name

if self.model:
with open(self.model, "r") as file:
self.data = yaml.safe_load(file)
else:
self.data = None

def genObject(self, loc, angle, dim):
if self.data:
return globals()[self.classType](loc, angle, dim, data=self.data)
return globals()[self.classType](loc, angle, dim)

def genRender(self, obj):
if self.data:
return globals()[self.render](obj, data=self.data)
return globals()[self.render](obj)

def getName(self):
return self.name

def getDict(self):
return {"type": self.classType,
"model": self.model,
"render": self.render,
"name": self.name}

Expand All @@ -38,12 +52,14 @@ def createAliases(self):

for alias in self.data["aliases"]:
if ("type" not in alias or
"model" not in alias or
"name" not in alias or
"render" not in alias):
print("Could not read alias (missing type or name).")
continue
self.aliases[alias['name']] = Alias(
alias["type"],
alias["model"],
alias["render"],
alias["name"])

Expand Down
11 changes: 4 additions & 7 deletions src/SceneObjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from Utils import Vector2D

class SceneObject:
def __init__(self, initialPos, rotation):
def __init__(self, initialPos, rotation, dimensions, data=None):

self.pos = Vector2D(initialPos[0], initialPos[1])
self.angle = rotation

#We support only rectanglular objects :P
self.width = 0.0
self.length = 0.0
self.width = dimensions[0]
self.length = dimensions[1]

self.boundOffset = Vector2D(0.0, 0.0)

Expand Down Expand Up @@ -198,7 +198,4 @@ def __str__(self):

class Wall(SceneObject):
def __init__(self, initialPos, rotation, dimensions=[100.0, 10.0]):
super().__init__(initialPos, rotation)

self.width = dimensions[0]
self.length = dimensions[1]
super().__init__(initialPos, rotation, dimensions)
4 changes: 2 additions & 2 deletions src/Vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class Vehicle(SceneObject):
"""
A class representing a vehicle.
"""
def __init__(self, initialPos, rotation, data=None):
super().__init__(initialPos, rotation)
def __init__(self, initialPos, rotation, dimensions=[0, 0], data=None):
super().__init__(initialPos, rotation, dimensions)

self.inModel = InertialModel1D(mass=data["mass"],
friction=data["friction"])
Expand Down
4 changes: 2 additions & 2 deletions src/VehicleImporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ def __init__(self, descriptor):

def getVehicle(self, initialPos=[0,0], rotation=0):
if self.vehicle is None:
self.vehicle = Vehicle(initialPos, rotation, self.data)
self.vehicle = Vehicle(initialPos, rotation, data=self.data)
return self.vehicle

def getVehicleRender(self):
if self.vehicleRender is None:
self.vehicleRender = SimpleVehicleRender(self.getVehicle(),
self.data)
data=self.data)
return self.vehicleRender

def easyImport(descriptor):
Expand Down
41 changes: 38 additions & 3 deletions src/VehicleRender.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ def drawMain(self, painter):
pass

class RectangleRender:
def __init__(self, parent, color=QColor(0, 255, 0), image=None):
def __init__(self, parent, color=QColor(0, 255, 0), data=None):
self.parent = parent
self.color = color

self.image = image
if data and 'image' in data:
self.image = QImage(data["image"]).scaled(int(self.parent.length),
int(self.parent.width))
else:
self.image = None

def drawMain(self, painter):
def drawRect(self, painter):
painter.save()

painter.setPen(Qt.black)
Expand All @@ -29,6 +33,37 @@ def drawMain(self, painter):

painter.restore()

def drawImage(self, painter):
"""
Draws the truck on the GUI.
Args:
painter (QPainter): the painter to draw with
"""
# Set the color and draw the rectangle
painter.save()

painter.setPen(Qt.black)
painter.setBrush(self.color)

painter.translate(int(self.parent.pos.x), int(self.parent.pos.y))
painter.rotate(self.parent.angle)
# Draw rectangle centered at origin
painter.translate(int(self.parent.wheelBase/2),0)
painter.drawImage(int(-self.parent.length/2),
int(-self.parent.width/2),
self.image)
#sw=int(self.parent.length),
#sh=int(self.parent.width))

painter.restore()

def drawMain(self, painter):
if self.image:
self.drawImage(painter)
else:
self.drawRect(painter)

class SimpleVehicleRender:
"""
A class representing a vehicle.
Expand Down

0 comments on commit 44e9e79

Please sign in to comment.