Files
autoPlanner2025/main.py
T

340 lines
14 KiB
Python
Raw Normal View History

2024-07-02 14:43:48 -06:00
import sys
import os
2024-04-11 10:27:35 -06:00
import numpy as np
2024-07-03 14:15:25 -06:00
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QMessageBox
2024-07-02 21:00:29 -06:00
from PySide6.QtGui import QPixmap, QMouseEvent, QPainter, QPen, QColor, QPainterPath, QPolygon, QFont
2024-07-02 14:43:48 -06:00
from PySide6.QtCore import Qt, QPoint, QRect
2024-04-11 10:27:35 -06:00
2024-07-03 14:15:25 -06:00
from buttonEditor import ButtonEditor
class PathPlanner(QMainWindow):
2024-07-02 14:43:48 -06:00
def __init__(self):
super().__init__()
self.setWindowTitle("Auto Planner")
2024-07-03 15:12:25 -06:00
self.coordinates = np.empty((0, 2), dtype=int)
2024-07-03 17:44:46 -06:00
self.controlPoints = []
self.rotationHandles = []
self.nodeAngles = []
2024-07-03 15:12:25 -06:00
2024-07-03 17:44:46 -06:00
self.imageLabel = QLabel(self)
2024-07-02 14:43:48 -06:00
2024-07-03 17:44:46 -06:00
scriptDir = os.path.dirname(os.path.abspath(__file__))
imagePath = os.path.join(scriptDir, "images", "Field.png")
self.pixmap = QPixmap(imagePath)
2024-07-02 14:43:48 -06:00
if self.pixmap.isNull():
2024-07-03 17:44:46 -06:00
self.imageLabel.setText(f"Image not found at: {imagePath}")
2024-07-02 14:43:48 -06:00
else:
2024-07-03 17:44:46 -06:00
self.imageLabel.setPixmap(self.pixmap)
2024-04-11 10:27:35 -06:00
2024-07-03 17:44:46 -06:00
self.mainWindowButton = QPushButton("Main Window")
self.mainWindowButton.clicked.connect(self.showMainWindow)
self.buttonEditorButton = QPushButton("Button Editor")
self.buttonEditorButton.clicked.connect(self.showButtonEditor)
2024-07-03 14:15:25 -06:00
2024-07-03 17:44:46 -06:00
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(self.mainWindowButton)
buttonLayout.addWidget(self.buttonEditorButton)
2024-04-11 10:27:35 -06:00
2024-07-02 14:43:48 -06:00
layout = QVBoxLayout()
2024-07-03 17:44:46 -06:00
layout.addLayout(buttonLayout)
layout.addWidget(self.imageLabel)
2024-04-11 10:27:35 -06:00
2024-07-03 17:44:46 -06:00
self.buttonEditor = ButtonEditor(self)
2024-07-03 14:15:25 -06:00
2024-07-02 14:43:48 -06:00
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.resize(self.pixmap.width(), self.pixmap.height() + 60)
self.setMouseTracking(True)
2024-07-03 17:44:46 -06:00
self.lastClickPos = QPoint()
2024-07-02 21:00:29 -06:00
2024-07-02 14:43:48 -06:00
self.coordinates = np.empty((0, 2), dtype=int)
2024-07-03 17:44:46 -06:00
self.lastClickTime = 0
self.nodeSize = 35
self.handleSize = 15
self.rotationHandleDistance = 35
self.controlPoints = []
self.rotationHandles = []
self.nodeAngles = []
self.draggingControlPoint = False
self.draggingNode = False
self.draggingRotationHandle = False
self.draggingControlPointIndex = (-1, -1)
self.draggingNodeIndex = -1
self.draggingRotationHandleIndex = -1
2024-07-02 14:43:48 -06:00
def mousePressEvent(self, event: QMouseEvent):
2024-07-03 17:44:46 -06:00
pos = self.imageLabel.mapFrom(self, event.position().toPoint())
2024-07-02 16:15:40 -06:00
x, y = pos.x(), pos.y()
2024-04-11 10:27:35 -06:00
2024-07-02 14:43:48 -06:00
if 0 <= x < self.pixmap.width() and 0 <= y < self.pixmap.height():
2024-07-02 16:32:53 -06:00
if event.button() == Qt.RightButton:
self.coordinates = np.vstack((self.coordinates, [x, y]))
if len(self.coordinates) >= 2:
2024-07-03 17:44:46 -06:00
self.calculateControlPoints()
self.calculateRotationHandlePos()
self.drawScene()
self.buttonEditor.updateScene()
2024-07-02 16:32:53 -06:00
elif event.button() == Qt.LeftButton:
2024-07-03 17:44:46 -06:00
currentTime = event.timestamp()
if (currentTime - self.lastClickTime < 300 and
(pos - self.lastClickPos).manhattanLength() < 5):
nodeIndex = self.isPointInNode(x, y)
if nodeIndex != -1:
self.deleteNode(nodeIndex)
2024-07-02 21:18:10 -06:00
else:
2024-07-03 17:44:46 -06:00
controlPointIndex = self.isPointInControlPoint(x, y)
if controlPointIndex != (-1, -1):
self.smoothPoints(controlPointIndex[0], controlPointIndex[1])
self.drawScene()
self.buttonEditor.updateScene()
2024-07-02 21:00:29 -06:00
else:
2024-07-03 17:44:46 -06:00
controlPointIndex = self.isPointInControlPoint(x, y)
if controlPointIndex != (-1, -1):
self.draggingControlPoint = True
self.draggingControlPointIndex = controlPointIndex
2024-07-03 15:12:25 -06:00
else:
2024-07-03 17:44:46 -06:00
nodeIndex = self.isPointInNode(x, y)
if nodeIndex != -1:
self.draggingNode = True
self.draggingNodeIndex = nodeIndex
2024-07-02 21:00:29 -06:00
else:
2024-07-03 17:44:46 -06:00
rotationHandleIndex = self.isPointInRotationHandle(x, y)
if rotationHandleIndex != -1:
self.draggingRotationHandle = True
self.draggingRotationHandleIndex = rotationHandleIndex
2024-07-03 15:12:25 -06:00
2024-07-03 17:44:46 -06:00
self.lastClickTime = currentTime
self.lastClickPos = pos
2024-07-02 21:00:29 -06:00
2024-07-03 17:44:46 -06:00
def deleteNode(self, index):
2024-07-02 21:00:29 -06:00
self.coordinates = np.delete(self.coordinates, index, axis=0)
2024-07-03 17:44:46 -06:00
if index < len(self.controlPoints):
del self.controlPoints[index]
if index > 0 and index < len(self.controlPoints):
del self.controlPoints[index - 1]
if index < len(self.rotationHandles):
del self.rotationHandles[index]
self.drawScene()
self.buttonEditor.updateScene()
2024-07-02 16:15:40 -06:00
def mouseMoveEvent(self, event: QMouseEvent):
2024-07-03 17:44:46 -06:00
if self.draggingControlPoint:
pos = self.imageLabel.mapFrom(self, event.position().toPoint())
2024-07-02 16:15:40 -06:00
x, y = pos.x(), pos.y()
2024-07-03 17:44:46 -06:00
curveIndex, pointIndex = self.draggingControlPointIndex
self.controlPoints[curveIndex][pointIndex] = QPoint(x, y)
self.drawScene()
self.buttonEditor.updateScene()
elif self.draggingNode:
pos = self.imageLabel.mapFrom(self, event.position().toPoint())
2024-07-02 16:32:53 -06:00
x, y = pos.x(), pos.y()
2024-07-03 17:44:46 -06:00
self.coordinates[self.draggingNodeIndex] = [x, y]
self.calculateControlPoints()
self.calculateRotationHandlePos()
self.drawScene()
self.buttonEditor.updateScene()
elif self.draggingRotationHandle:
pos = self.imageLabel.mapFrom(self, event.position().toPoint())
2024-07-02 16:53:07 -06:00
x, y = pos.x(), pos.y()
2024-07-03 17:44:46 -06:00
nodeX, nodeY = self.coordinates[self.draggingRotationHandleIndex]
dx = x - nodeX
dy = y - nodeY
2024-07-02 16:53:07 -06:00
angle = np.arctan2(dy, dx)
2024-07-03 17:44:46 -06:00
self.nodeAngles[self.draggingRotationHandleIndex] = angle
2024-07-02 21:00:29 -06:00
2024-07-03 17:44:46 -06:00
rotationHandleX = int(nodeX + self.rotationHandleDistance * np.cos(angle))
rotationHandleY = int(nodeY + self.rotationHandleDistance * np.sin(angle))
self.rotationHandles[self.draggingRotationHandleIndex] = QPoint(rotationHandleX, rotationHandleY)
self.drawScene()
self.buttonEditor.updateScene()
2024-07-02 16:15:40 -06:00
def mouseReleaseEvent(self, event: QMouseEvent):
if event.button() == Qt.LeftButton:
2024-07-03 17:44:46 -06:00
self.draggingControlPoint = False
self.draggingControlPointIndex = (-1, -1)
self.draggingNode = False
self.draggingNodeIndex = -1
self.draggingRotationHandle = False
self.draggingRotationHandleIndex = -1
self.buttonEditor.updateScene()
def isPointInRotationHandle(self, x, y):
for i, handle in enumerate(self.rotationHandles):
if (abs(x - handle.x()) <= self.handleSize // 2 and
abs(y - handle.y()) <= self.handleSize // 2):
2024-07-02 16:53:07 -06:00
return i
return -1
2024-07-02 16:15:40 -06:00
2024-07-03 17:44:46 -06:00
def isPointInControlPoint(self, x, y):
for i, controlPair in enumerate(self.controlPoints):
for j, controlPoint in enumerate(controlPair):
if (abs(x - controlPoint.x()) <= self.handleSize // 2 and
abs(y - controlPoint.y()) <= self.handleSize // 2):
2024-07-03 13:35:23 -06:00
return (i, j)
return (-1, -1)
2024-07-02 16:32:53 -06:00
2024-07-03 17:44:46 -06:00
def isPointInNode(self, x, y):
for i, (nodeX, nodeY) in enumerate(self.coordinates):
if (abs(x - nodeX) <= self.nodeSize // 2 and
abs(y - nodeY) <= self.nodeSize // 2):
2024-07-02 16:32:53 -06:00
return i
return -1
2024-07-02 16:15:40 -06:00
2024-07-03 17:44:46 -06:00
def calculateControlPoints(self):
2024-07-02 16:15:40 -06:00
if len(self.coordinates) >= 2:
x1, y1 = self.coordinates[-2]
x2, y2 = self.coordinates[-1]
2024-07-03 17:44:46 -06:00
midX, midY = (x1 + x2) // 2, (y1 + y2) // 2
self.controlPoints.append([
QPoint(midX - (x2 - x1) // 4, midY - (y2 - y1) // 4),
QPoint(midX + (x2 - x1) // 4, midY + (y2 - y1) // 4)
2024-07-03 13:35:23 -06:00
])
2024-07-02 16:15:40 -06:00
2024-07-03 17:44:46 -06:00
def calculateRotationHandlePos(self):
2024-07-02 16:53:07 -06:00
for i, (x, y) in enumerate(self.coordinates):
2024-07-03 17:44:46 -06:00
if i >= len(self.nodeAngles):
self.nodeAngles.append(np.pi) # Default angle for new nodes
2024-07-02 21:00:29 -06:00
2024-07-03 17:44:46 -06:00
angle = self.nodeAngles[i]
2024-07-02 21:00:29 -06:00
2024-07-03 17:44:46 -06:00
rotationHandleX = int(x + self.rotationHandleDistance * np.cos(angle))
rotationHandleY = int(y + self.rotationHandleDistance * np.sin(angle))
2024-07-02 21:00:29 -06:00
2024-07-03 17:44:46 -06:00
if i >= len(self.rotationHandles):
self.rotationHandles.append(QPoint(rotationHandleX, rotationHandleY))
2024-07-02 16:53:07 -06:00
else:
2024-07-03 17:44:46 -06:00
self.rotationHandles[i] = QPoint(rotationHandleX, rotationHandleY)
2024-07-02 16:53:07 -06:00
2024-07-03 17:44:46 -06:00
def updateScene(self):
self.buttonEditor.updateScene(self.coordinates, self.controlPoints)
2024-07-03 15:12:25 -06:00
2024-07-03 17:44:46 -06:00
def drawScene(self):
2024-07-02 16:15:40 -06:00
self.pixmap = QPixmap(os.path.join(os.path.dirname(os.path.abspath(__file__)), "images", "Field.png"))
2024-07-02 14:43:48 -06:00
painter = QPainter(self.pixmap)
2024-07-02 16:15:40 -06:00
2024-07-03 17:44:46 -06:00
greyPen = QPen(QColor(127, 127, 127))
greyPen.setWidth(2)
painter.setPen(greyPen)
for i, controlPair in enumerate(self.controlPoints):
2024-07-03 13:35:23 -06:00
if i < len(self.coordinates) - 1:
2024-07-02 16:15:40 -06:00
start = QPoint(self.coordinates[i][0], self.coordinates[i][1])
end = QPoint(self.coordinates[i + 1][0], self.coordinates[i + 1][1])
2024-07-03 13:35:23 -06:00
pen = QPen(Qt.yellow)
pen.setWidth(2)
painter.setPen(pen)
path = QPainterPath()
path.moveTo(start)
2024-07-03 17:44:46 -06:00
path.cubicTo(controlPair[0], controlPair[1], end)
2024-07-03 13:35:23 -06:00
painter.drawPath(path)
painter.setBrush(Qt.NoBrush)
2024-07-03 17:44:46 -06:00
for controlPoint in controlPair:
2024-07-03 13:35:23 -06:00
painter.setPen(QPen(QColor(127, 127, 127), 1, Qt.DashLine))
2024-07-03 17:44:46 -06:00
painter.drawLine(start, controlPoint)
painter.drawLine(end, controlPoint)
2024-07-03 13:35:23 -06:00
painter.setPen(Qt.NoPen)
painter.setBrush(QColor(0, 255, 255))
2024-07-03 17:44:46 -06:00
for controlPoint in controlPair:
2024-07-02 21:00:29 -06:00
painter.drawEllipse(
2024-07-03 17:44:46 -06:00
controlPoint.x() - self.handleSize // 2,
controlPoint.y() - self.handleSize // 2,
self.handleSize,
self.handleSize
2024-07-02 16:15:40 -06:00
)
2024-07-03 13:35:23 -06:00
painter.setBrush(Qt.NoBrush)
2024-07-02 16:15:40 -06:00
for i, (x, y) in enumerate(self.coordinates):
2024-07-03 17:44:46 -06:00
if i < len(self.rotationHandles):
angle = self.nodeAngles[i]
2024-07-02 21:00:29 -06:00
painter.save()
painter.translate(x, y)
painter.rotate(np.degrees(angle))
pen = QPen(QColor(127, 127, 127))
pen.setWidth(2)
painter.setPen(pen)
painter.setBrush(Qt.NoBrush)
2024-07-03 17:44:46 -06:00
painter.drawRect(-self.nodeSize // 2, -self.nodeSize // 2,
self.nodeSize, self.nodeSize)
2024-07-02 21:00:29 -06:00
painter.restore()
painter.setPen(Qt.white)
font = painter.font()
font.setPointSize(25)
painter.setFont(font)
2024-07-03 17:44:46 -06:00
painter.drawText(QRect(x - self.nodeSize // 2, y - self.nodeSize // 2,
self.nodeSize, self.nodeSize),
2024-07-02 21:00:29 -06:00
Qt.AlignCenter, str(i + 1))
2024-07-03 17:44:46 -06:00
for i, handle in enumerate(self.rotationHandles):
2024-07-02 21:00:29 -06:00
painter.setBrush(QColor(255, 0, 255))
2024-07-02 16:53:07 -06:00
painter.drawEllipse(
handle,
2024-07-03 17:44:46 -06:00
self.handleSize // 2,
self.handleSize // 2
2024-07-02 16:53:07 -06:00
)
painter.setBrush(Qt.NoBrush)
2024-07-03 17:44:46 -06:00
self.imageLabel.setPixmap(self.pixmap)
self.buttonEditor.updateScene()
2024-07-02 14:43:48 -06:00
2024-07-03 17:44:46 -06:00
def smoothPoints(self, curveIndex: int, pointIndex: int):
if curveIndex + 1 < len(self.controlPoints):
prevControlPair = self.controlPoints[curveIndex]
nextControlPair = self.controlPoints[curveIndex + 1]
node = QPoint(self.coordinates[curveIndex + 1][0], self.coordinates[curveIndex + 1][1])
2024-07-03 13:35:23 -06:00
2024-07-03 17:44:46 -06:00
newControl2 = QPoint(
2 * node.x() - nextControlPair[0].x(),
2 * node.y() - nextControlPair[0].y()
2024-07-02 21:18:10 -06:00
)
2024-07-03 17:44:46 -06:00
self.controlPoints[curveIndex][1] = newControl2
2024-07-02 21:18:10 -06:00
2024-07-03 17:44:46 -06:00
newControl1 = QPoint(
2 * node.x() - prevControlPair[1].x(),
2 * node.y() - prevControlPair[1].y()
2024-07-03 13:35:23 -06:00
)
2024-07-03 17:44:46 -06:00
self.controlPoints[curveIndex + 1][0] = newControl1
2024-07-02 21:18:10 -06:00
2024-07-03 17:44:46 -06:00
def clearPoints(self):
2024-07-02 14:43:48 -06:00
self.coordinates = np.empty((0, 2), dtype=int)
2024-07-03 17:44:46 -06:00
self.controlPoints.clear()
self.rotationHandles.clear()
self.nodeAngles.clear()
self.drawScene()
self.buttonEditor.updateScene()
def showClearWarning(self):
2024-07-03 13:35:23 -06:00
reply = QMessageBox.question(self, "Clear Auto",
"Are you sure you want to clear this auto?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
2024-07-03 17:44:46 -06:00
self.clearPoints()
2024-07-02 14:43:48 -06:00
2024-07-03 17:44:46 -06:00
def showMainWindow(self):
2024-07-03 14:15:25 -06:00
self.show()
2024-07-03 17:44:46 -06:00
self.buttonEditor.hide()
2024-07-03 14:15:25 -06:00
2024-07-03 17:44:46 -06:00
def showButtonEditor(self):
2024-07-03 14:15:25 -06:00
self.hide()
2024-07-03 17:44:46 -06:00
self.buttonEditor.show()
2024-07-03 14:15:25 -06:00
2024-07-02 14:43:48 -06:00
if __name__ == "__main__":
app = QApplication(sys.argv)
2024-07-03 14:15:25 -06:00
window = PathPlanner()
2024-07-02 14:43:48 -06:00
window.show()
2024-07-03 17:44:46 -06:00
sys.exit(app.exec())