PySide6 switch

Starting the switch to pyside instead of pygame
This commit is contained in:
Daniel Carta
2024-07-02 14:43:48 -06:00
parent e54086e86f
commit 91a5987c13
5 changed files with 77 additions and 1407 deletions
+77 -96
View File
@@ -1,112 +1,93 @@
import math
from copy import copy
import pygame as pg
from pygame.locals import *
from sys import exit
import sys
import os
import numpy as np
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QWidget
from PySide6.QtGui import QPixmap, QMouseEvent, QPainter, QPen
from PySide6.QtCore import Qt, QPoint, QRect
import src.render as render
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
import src.pathEditor as pathEditor
import src.buttonEditor as buttonEditor
import src.export as export
self.setWindowTitle("Auto Planner")
doubleClickDuration = 200
#Set background image to the field
self.image_label = QLabel(self)
pg.init()
pg.font.init()
script_dir = os.path.dirname(os.path.abspath(__file__))
image_path = os.path.join(script_dir, "images", "Field.png")
self.pixmap = QPixmap(image_path)
if self.pixmap.isNull():
self.image_label.setText(f"Image not found at: {image_path}")
else:
self.image_label.setPixmap(self.pixmap)
topBarHeight = 40
bottomBarHeight = 60
#Buttons
self.clear_button = QPushButton("Clear Auto")
self.clear_button.clicked.connect(self.clear_points)
screen_width = 1200
screen_height = (screen_width * (643/1286)) + topBarHeight + bottomBarHeight
#Layout of the auto planner
layout = QVBoxLayout()
layout.addWidget(self.clear_button)
layout.addWidget(self.image_label)
screen = pg.display.set_mode((screen_width, screen_height))#, pg.RESIZABLE)
pg.display.set_caption("Auto Planner")
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
render = render.render(pg, screen, topBarHeight, bottomBarHeight)
self.resize(self.pixmap.width(), self.pixmap.height() + 60)
tabIndex = 0
tabs = [
pathEditor.pathEditor(render),
buttonEditor.buttonEditor(render, pathEditor),
export.export(pg, render, buttonEditor)
]
self.setMouseTracking(True)
tabs[tabIndex].load()
#Variables
self.coordinates = np.empty((0, 2), dtype=int)
self.robot_size = 35
def addTab(i):
x1 = i * (screen_width/(len(tabs)))
x2 = (screen_width/(len(tabs)))
rect = (x1, 0, x2, topBarHeight)
def getIsSelected():
global tabIndex
return tabIndex == i
def getIsVisible():
return True
def onClick(pos):
global tabIndex
tabs[tabIndex].unload()
tabIndex = i
tabs[tabIndex].load()
render.renderElements(pos)
pg.display.update()
render.addButton(rect, tabs[i].name, getIsSelected, getIsVisible, onClick)
#Tell where the user clicked the screen
def mousePressEvent(self, event: QMouseEvent):
pos = self.image_label.mapFrom(self, event.position().toPoint())
x = pos.x()
y = pos.y()
if 0 <= x < self.pixmap.width() and 0 <= y < self.pixmap.height():
self.coordinates = np.vstack((self.coordinates, [x, y]))
if event.button() == Qt.RightButton:
self.instantiate_robot()
print(f"{self.coordinates}")
#Create a robot(square) at the point clicked
def instantiate_robot(self):
painter = QPainter(self.pixmap)
pen = QPen(Qt.white)
pen.setWidth(2)
painter.setPen(pen)
if len(self.coordinates) > 1:
for i in range(len(self.coordinates) - 1):
x1, y1 = self.coordinates[i]
x2, y2 = self.coordinates[i + 1]
painter.drawLine(x1, y1, x2, y2)
#Create robot
for x, y in self.coordinates:
top_left_x = int(x - self.robot_size // 2)
top_left_y = int(y - self.robot_size // 2)
for i in range(len(tabs)):
addTab(i)
render.renderElements((screen_width/2, screen_height/2))
running = True
last_click = -1
def offsetPos(pos):
return (pos[0],pos[1])
while running:
for event in pg.event.get():
painter.drawRect(QRect(top_left_x, top_left_y, self.robot_size, self.robot_size))
if event.type == pg.MOUSEMOTION:
pos = pg.mouse.get_pos()
render.renderElements(pos)
if pos[1] > topBarHeight:
tabs[tabIndex].mouseMove(offsetPos(pos))
# refreshTabs(pos)
elif event.type == pg.MOUSEBUTTONDOWN:
pos = pg.mouse.get_pos()
render.clickElement(pos)
if pos[1] > topBarHeight:
now = pg.time.get_ticks()
if now - last_click <= doubleClickDuration:
tabs[tabIndex].doubleClick(offsetPos(pos))
else:
tabs[tabIndex].mouseDown(offsetPos(pos))
last_click = pg.time.get_ticks()
# else:
# clickTab(pos)
elif event.type == pg.MOUSEBUTTONUP:
pos = pg.mouse.get_pos()
if pos[1] > topBarHeight:
tabs[tabIndex].mouseUp(offsetPos(pos))
self.image_label.setPixmap(self.pixmap)
elif event.type == pg.KEYDOWN:
tabs[tabIndex].keyDown(event.key)
if event.key == pg.K_TAB:
tabs[tabIndex].unload()
tabIndex = (tabIndex + 1) % len(tabs)
tabs[tabIndex].load()
render.renderElements(pg.mouse.get_pos())
#Clears all points
def clear_points(self):
self.coordinates = np.empty((0, 2), dtype=int)
self.pixmap = QPixmap(os.path.join(os.path.dirname(os.path.abspath(__file__)), "images", "Field.png"))
self.image_label.setPixmap(self.pixmap)
elif event.type == pg.QUIT:
running = False
pg.quit()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
-654
View File
@@ -1,654 +0,0 @@
import math
import copy
import json
render = None
pathEditor = None
bottomBarRect = None
# leftSidee = True
ogNodes = []
ogCtrlNodes = []
ogRotNodes = []
keyFrames = []
matchLength = 15
TPS = 50
tickTime = round(1/TPS*1000)
matchTicks = matchLength * TPS
displayTickResolution = 4
displayTicks = round(matchTicks / displayTickResolution)
buttonEditColor = (191,0,191)
buttonEditNodeRadius = 6
dragFrameIndex = -1
ogDragFramePos = -1
selFrame = -1
buttonImages = {}
buttonMode = False
buttonPositions = {
'A': ((1089,494),100),
'B': ((1187,404),100),
'X': ((996,411),100),
'Y': ((1093,321),100),
'Dpad': ((549,619),220),
'Dpad_Up': ((549,561),70),
'Dpad_Down': ((549,677),70),
'Dpad_Left': ((485,619),70),
'Dpad_Right': ((607,619),70),
'Menu': ((832,411),100),
'Windows': ((629,411),100),
'Left_Stick': ((375,422),150),
'Right_Stick': ((914,622),150),
'LB': ((352,184),150),
'RB': ((1100,184),150),
'LT': ((356,67),150),
'RT': ((1096,67),150)
}
def getKeyframeAtPos(index):
for frame in keyFrames:
if frame["timeIndex"] == index:
return frame
return None
def getFrameIndex(frame):
if frame == None:
return -1
return keyFrames.index(frame)
def getPosKeyframeAtPos(index):
for frame in keyFrames:
if frame["timeIndex"] == index and frame['type'] == 'position':
return frame
return None
def getPosKeyframes():
frames = []
for keyFrame in keyFrames:
if keyFrame['type'] == 'position':
frames.append(keyFrame)
return frames
def getButtonKeyframes():
frames = []
for keyFrame in keyFrames:
if keyFrame['type'] == 'controller':
frames.append(keyFrame)
return frames
def getBezierPointCounts():
counts = []
frames = getPosKeyframes()
for i in range(1,len(frames)):
counts.append(frames[i]['timeIndex'] - frames[i-1]['timeIndex'])
return counts
def getPosKeyframeByIndex(index):
for frame in keyFrames:
if frame['type'] == 'position' and frame["index"] == index:
return frame
return None
def getSurroundingPosFrames(index):
prevFrame = None
for i in range(index,-1,-1):
frame = getPosKeyframeAtPos(i)
if frame != None and (dragFrameIndex == -1 or not frame == keyFrames[dragFrameIndex]):
prevFrame = frame
break
nextFrame = None
for i in range(index,displayTicks,1):
frame = getPosKeyframeAtPos(i)
if frame != None and (dragFrameIndex == -1 or not frame == keyFrames[dragFrameIndex]):
nextFrame = frame
break
if nextFrame == None and prevFrame == None:
return prevFrame, nextFrame
# elif nextFrame == None:
# return prevFrame, prevFrame
# elif prevFrame == None:
# return nextFrame, nextFrame
return prevFrame, nextFrame
def getLeftButtonFrame(index):
for i in range(index,0,-1):
frame = getKeyframeAtPos(i)
if frame != None and frame['type'] == 'controller':
return frame
return None
def getButtonFrameAtPos(index):
for i in range(len(keyFrames)):
frame = keyFrames[i]
if frame != None and frame['type'] == 'controller':
return frame
return None
def getRobotAtIndex(index):
prevFrame, nextFrame = getSurroundingPosFrames(index)
# print(prevFrame)
# print(nextFrame)
if prevFrame == None and nextFrame == None:
return (0,0), 0
if prevFrame == None:
return nextFrame['position'], nextFrame['rotation']
elif nextFrame == None:
return prevFrame['position'], prevFrame['rotation']
elif nextFrame['timeIndex'] - prevFrame['timeIndex'] == 0:
return prevFrame['position'], prevFrame['rotation']
relPos = -((prevFrame['timeIndex'] - index)/(nextFrame['timeIndex'] - prevFrame['timeIndex']))
pos = calcBezierPoint(prevFrame['position'], ogCtrlNodes[prevFrame['index']], nextFrame['position'], relPos)
if prevFrame['rotation'] - nextFrame['rotation'] < -math.pi:
rot = ((nextFrame['rotation']-prevFrame['rotation']-math.pi*2)*relPos) + prevFrame['rotation']
elif prevFrame['rotation'] - nextFrame['rotation'] > math.pi:
rot = ((nextFrame['rotation']-prevFrame['rotation']+math.pi*2)*relPos) + prevFrame['rotation']
else:
rot = ((nextFrame['rotation']-prevFrame['rotation'])*relPos) + prevFrame['rotation']
# diff = (nextFrame['rotation']-prevFrame['rotation'])
# if diff >= math.pi:
# rot = ((nextFrame['rotation']-prevFrame['rotation']-math.pi*2)*relPos) + prevFrame['rotation']
# elif diff <= math.pi:
# rot = ((nextFrame['rotation']-prevFrame['rotation']+math.pi*2)*relPos) + prevFrame['rotation']
# else:
# rot = ((nextFrame['rotation']-prevFrame['rotation'])*relPos) + prevFrame['rotation']
return pos, rot
# def getTimeBarColor(index):
# frame = getKeyframeAtPos(index)
# if frame == None:
# return (0,0,0)
# if frame['type'] == 'position':
# return (127,127,0)
# elif frame['type'] == 'controller':
# return buttonEditColor
# return (16,16,32)
def calcBezierPoint(p0, p1, p2, t):
px = p0[0]*(1-t)**2 + 2*(1-t)*t*p1[0] + p2[0]*t**2
py = p0[1]*(1-t)**2 + 2*(1-t)*t*p1[1] + p2[1]*t**2
return (px, py)
def reloadBar(pos):
toggle = False
for i in range(displayTicks):
x1 = i * (render.width/(displayTicks))
x2 = (render.width/(displayTicks))
rect = (x1, bottomBarRect[1], x2, bottomBarRect[3])
color = (0, 0, 0)
if i == selFrame:
color = (color[0]+64,color[1]+64,color[2]+64)
if render.isInRect(pos, rect):
color = (color[0]+64,color[1]+64,color[2]+64)
if dragFrameIndex != -1 and getKeyframeAtPos(i) == None:
if keyFrames[dragFrameIndex]['type'] == 'position':
prevFrame, nextFrame = getSurroundingPosFrames(ogDragFramePos)
if prevFrame == nextFrame:
pass
elif prevFrame == None:
if i < nextFrame['timeIndex']:
keyFrames[dragFrameIndex]['timeIndex'] = i
elif nextFrame == None:
if i > prevFrame['timeIndex']:
keyFrames[dragFrameIndex]['timeIndex'] = i
elif i > prevFrame['timeIndex'] and i < nextFrame['timeIndex']:
keyFrames[dragFrameIndex]['timeIndex'] = i
else:
keyFrames[dragFrameIndex]['timeIndex'] = i
else:
color = (color[0]+16+(toggle*16),color[1]+16+(toggle*16),color[2]+32+(toggle*16))
frame = getKeyframeAtPos(i)
if frame == None:
pass
elif frame['type'] == 'position':
color = (191,191,0)
elif frame['type'] == 'controller':
color = buttonEditColor
toggle = not toggle
render.drawrect(color, rect)
# renderSelectIndicator(i)
render.update()
def clickBar(pos):
for i in range(displayTicks):
x1 = i * (render.width/(displayTicks))
x2 = (render.width/(displayTicks))
rect = (x1, bottomBarRect[1], x2, bottomBarRect[3])
if render.isInRect(pos, rect):
global selFrame
global dragFrameIndex
global ogDragFramePos
selFrame = i
if dragFrameIndex == -1:
dragFrameIndex = getFrameIndex(getKeyframeAtPos(i))
ogDragFramePos = i
return
def createBlankController():
returnArr = []
for i in range(len(controllerRects)):
returnArr.append({
'A': False,
'B': False,
'X': False,
'Y': False,
'Dpad_Up': False,
'Dpad_Down': False,
'Dpad_Left': False,
'Dpad_Right': False,
'Menu': False,
'Windows': False,
'Left_Stick': False,
'Right_Stick': False,
'LB': False,
'RB': False,
'LT': False,
'RT': False
})
return returnArr
def toggleControllerButton(btnStr, controllerIndex):
global keyFrames
lastFrame = getLeftButtonFrame(selFrame)
if lastFrame == None:
keyFrames.append({
"type": "controller",
"timeIndex": selFrame,
"controllers": createBlankController()
})
frame = keyFrames[len(keyFrames)-1]
elif lastFrame['timeIndex'] != selFrame:
keyFrames.append({
"type": "controller",
"timeIndex": selFrame,
"controllers": copy.deepcopy(lastFrame['controllers'])
})
frame = keyFrames[len(keyFrames)-1]
else:
frame = lastFrame
if not btnStr in ['Dpad_Up', 'Dpad_Down', 'Dpad_Left', 'Dpad_Right']:
frame['controllers'][controllerIndex][btnStr] = not frame['controllers'][controllerIndex][btnStr]
# Dpad Stuff
elif frame['controllers'][controllerIndex][btnStr] == True:
for btn in ['Dpad_Up', 'Dpad_Down', 'Dpad_Left', 'Dpad_Right']:
frame['controllers'][controllerIndex][btn] = False
else:
for btn in ['Dpad_Up', 'Dpad_Down', 'Dpad_Left', 'Dpad_Right']:
frame['controllers'][controllerIndex][btn] = False
frame['controllers'][controllerIndex][btnStr] = True
def getControllerButtons(controllerIndex):
frame = getLeftButtonFrame(selFrame)
if frame == None:
return createBlankController()[0]
else:
return frame['controllers'][controllerIndex]
def renderXboxControllers():
for i in range(len(controllerRects)):
rect = controllerRects[i]
offsetSize = rect[2]/buttonImages['Controller'].get_width()
def offsetControllerButton(index):
pos, size = buttonPositions[index]
rect2 = ((pos[0]-(size/2), pos[1]-(size/2), size, size))
return (rect[0]+(rect2[0])*offsetSize,rect[1]+(rect2[1])*offsetSize,rect2[2]*offsetSize,rect2[2]*offsetSize)
render.image(buttonImages['Controller'], rect)
btns = getControllerButtons(i)
for btn in ['A','B','X','Y','Menu','Windows','LB','RB','LT','RT','Left_Stick','Right_Stick']:
if btns[btn]:
render.image(render.invert(buttonImages[btn]), offsetControllerButton(btn))
else:
render.image(buttonImages[btn], offsetControllerButton(btn))
if btns['Dpad_Up']:
render.image(buttonImages['Dpad_Up'], offsetControllerButton('Dpad'))
elif btns['Dpad_Down']:
render.image(buttonImages['Dpad_Down'], offsetControllerButton('Dpad'))
elif btns['Dpad_Left']:
render.image(buttonImages['Dpad_Left'], offsetControllerButton('Dpad'))
elif btns['Dpad_Right']:
render.image(buttonImages['Dpad_Right'], offsetControllerButton('Dpad'))
else:
render.image(buttonImages['Dpad'], offsetControllerButton('Dpad'))
# for btn in ['Dpad_Up','Dpad_Down','Dpad_Left','Dpad_Right']:
# if
# render.drawrect((255,255,255), offsetControllerButton(btn))
def controllerClick(pos):
for i in range(len(controllerRects)):
rect = controllerRects[i]
offsetSize = rect[2]/buttonImages['Controller'].get_width()
def offsetControllerButton(index):
pos, size = buttonPositions[index]
rect2 = ((pos[0]-(size/2), pos[1]-(size/2), size, size))
return (rect[0]+(rect2[0])*offsetSize,rect[1]+(rect2[1])*offsetSize,rect2[2]*offsetSize,rect2[2]*offsetSize)
for btn in ['A','B','X','Y','Menu','Windows','LB','RB','LT','RT','Left_Stick','Right_Stick','Dpad_Up','Dpad_Down','Dpad_Left','Dpad_Right']:
if render.isInRect(pos, offsetControllerButton(btn)):
toggleControllerButton(btn, i)
def renderTimeText():
if selFrame == -1:
return
seconds = round((((selFrame*displayTickResolution)+1)/matchTicks)*matchLength,2)
text = f'{str(seconds)} s / {str(matchLength)}.0 s'
text = render.font.render(text, True, (255,255,255))
# global leftSide
# if leftSide:
# rect = text.get_rect(bottomright=(render.width,render.height+render.topBarHeight))
# else:
rect = text.get_rect(bottomleft=(0,render.height+render.topBarHeight))
render.screen.blit(text, rect)
class buttonEditor:
name = "Button Editor"
def __init__(self, tmprender, tmppathEditor):
global render
global pathEditor
render = tmprender
pathEditor = tmppathEditor
global indicatorBarHeight
indicatorBarHeight = round(render.screen.get_width()/displayTicks)
global bottomBarRect
bottomBarRect = (0, (render.screen.get_height()-render.bottomBarHeight), render.screen.get_width(), render.bottomBarHeight)
global buttonImages
buttonImages = {
"Controller": render.loadImg('images/XboxOne_Diagram_Simple.png'),
"A": render.loadImg('images/XboxOne_A.png'),
"B": render.loadImg('images/XboxOne_B.png'),
"X": render.loadImg('images/XboxOne_X.png'),
"Y": render.loadImg('images/XboxOne_Y.png'),
"Dpad": render.loadImg('images/XboxOne_Dpad.png'),
"Dpad_Up": render.loadImg('images/XboxOne_Dpad_Up.png'),
"Dpad_Down": render.loadImg('images/XboxOne_Dpad_Down.png'),
"Dpad_Left": render.loadImg('images/XboxOne_Dpad_Left.png'),
"Dpad_Right": render.loadImg('images/XboxOne_Dpad_Right.png'),
"Menu": render.loadImg('images/XboxOne_Menu.png'),
"Windows": render.loadImg('images/XboxOne_Windows.png'),
"Left_Stick": render.loadImg('images/XboxOne_Left_Stick.png'),
"Left_Stick_Click": render.loadImg('images/XboxOne_Left_Stick_Click.png'),
"Right_Stick": render.loadImg('images/XboxOne_Right_Stick.png'),
"Right_Stick_Click": render.loadImg('images/XboxOne_Right_Stick_Click.png'),
"LB": render.loadImg('images/XboxOne_LB.png'),
"RB": render.loadImg('images/XboxOne_RB.png'),
"LT": render.loadImg('images/XboxOne_LT.png'),
"RT": render.loadImg('images/XboxOne_RT.png')
}
ControllerSize = (render.width/2, render.width*(buttonImages['Controller'].get_height()/buttonImages['Controller'].get_width())/2)
ControllerYOffset = (render.height-ControllerSize[1])/2
global controllerRects
controllerRects = [
(0, render.topBarHeight+ControllerYOffset, ControllerSize[0], ControllerSize[1]),
(ControllerSize[0], render.topBarHeight+ControllerYOffset, ControllerSize[0], ControllerSize[1])
]
def refresh(self):
render.clear()
if not buttonMode:
global ogNodes
global ogCtrlNodes
global ogRotNodes
render.drawField()
pointCounts = getBezierPointCounts()
for i in range(0,len(ogCtrlNodes)):
render.bezier(ogNodes[i], ogCtrlNodes[i], ogNodes[i+1], pointCounts[i])
buttonFrames = getButtonKeyframes()
for frame in buttonFrames:
pos, rot = getRobotAtIndex(frame['timeIndex'])
render.circle(buttonEditColor, pos, buttonEditNodeRadius)
if selFrame != -1 and len(ogNodes) > 0:
pos, rot = getRobotAtIndex(selFrame)
render.robotSquare(pos, rot)
else:
renderXboxControllers()
renderTimeText()
reloadBar((0,0))
render.update()
def mouseDown(self, pos):
if buttonMode and pos[1] < bottomBarRect[1]:
controllerClick(pos)
self.refresh()
elif pos[1] > bottomBarRect[1]:
clickBar(pos)
self.refresh()
def mouseUp(self, pos):
global dragFrameIndex
if dragFrameIndex != -1:
dragFrameIndex = -1
ogDragFramePos = -1
self.refresh()
reloadBar((0, 0))
def mouseMove(self, pos):
global dragFrameIndex
if dragFrameIndex != -1 or pos[1] > bottomBarRect[1]:
reloadBar(pos)
# global leftSide
# if leftSide and pos[0] > (render.width/2):
# leftSide = False
# self.refresh()
# if not leftSide and pos[0] < (render.width/2):
# leftSide = True
# self.refresh()
# if pos[1] > bottomBarRect[1]:
def doubleClick(self, pos):
pass
# if pos[1] > bottomBarRect[1]:
# clickBar(pos)
# self.refresh()
def keyDown(self, key):
global selFrame
global buttonMode
if key == render.pg.K_LEFT and selFrame > 0:
selFrame -= 1
self.refresh()
elif key == render.pg.K_RIGHT and selFrame < displayTicks-1:
selFrame += 1
self.refresh()
elif buttonMode and key == render.pg.K_DELETE and selFrame != -1:
frame = getKeyframeAtPos(selFrame)
if frame != None and frame['type'] != 'position':
global keyFrames
keyFrames.remove(frame)
self.refresh()
elif selFrame != -1 and key == render.pg.K_e:
buttonMode = not buttonMode
self.refresh()
def updateNodes(self, loadKeyframes):
global ogNodes
global ogCtrlNodes
global ogRotNodes
ogNodes = pathEditor.nodes.copy()
ogCtrlNodes = pathEditor.curveEditPoints.copy()
ogRotNodes = pathEditor.nodeRotations.copy()
if not loadKeyframes:
return
for i in range(len(ogNodes)):
frame = getPosKeyframeByIndex(i)
frame['position'] = ogNodes[i]
frame['rotation'] = ogRotNodes[i]
def load(self):
global selFrame
global buttonMode
selFrame = -1
buttonMode = False
global ogNodes
global ogCtrlNodes
global ogRotNodes
if len(ogNodes) != len(pathEditor.nodes):
global keyFrames
for i in range(len(keyFrames)-1,-1,-1):
if keyFrames[i]['type'] == 'position':
keyFrames.pop(i)
self.updateNodes(False)
for i in range(len(ogNodes)):
if len(ogNodes) == 1:
timeIndex = 0
else:
timeIndex = round((i)/(len(ogNodes)-1) * (displayTicks-1))
keyFrames.append({
"type": "position",
"timeIndex": timeIndex,
"index": i,
"position": ogNodes[i],
"rotation": ogRotNodes[i]
})
else:
self.updateNodes(True)
self.refresh()
def unload(self):
pass
-252
View File
@@ -1,252 +0,0 @@
import crossfiledialog
import struct
import copy
pg = None
buttonEditor = None
events = []
#Save according to https://github.com/Team4388/2024AcrossTheRidgebotiverse/blob/Prep-For-Denver/src/main/java/frc4388/robot/commands/Autos/neo%20AutoRecoding%20format.txt
moveMultiplier = 0.1
rotMultiplier = 1
def buttonsToBytes(buttons):
data = 0
for i in range(16):
data |= buttons[i] << i
return data.to_bytes(2, "little", signed=True)
def toByte(num):
if num > 255:
raise OverflowError
return num.to_bytes(1, 'big', signed=False)
def toShort(num):
if num > 65535:
raise OverflowError
return num.to_bytes(2, 'big', signed=True)
def toInt(num):
return struct.pack('>i', num)
def toDouble(num):
return struct.pack('>d', num)
class xboxController:
def __init__(self):
self.buttons = [False for i in range(16)]
self.leftStick = (0,0)
self.rightStick = (0,0)
self.LT = -1
self.RT = -1
self.POV = -1
def getPOVhat(up, down, left, right):
if up and right:
return 45
elif right and down:
return 135
elif down and left:
return 225
elif left and up:
return 315
elif up:
return 0
elif right:
return 90
elif down:
return 180
elif left:
return 270
else:
return -1
def getSticksAtFrame(index):
fractionIndex = round(index/buttonEditor.displayTickResolution)
newpos, newrot = buttonEditor.getRobotAtIndex(fractionIndex)
oldpos, oldrot = buttonEditor.getRobotAtIndex(fractionIndex-1)
# print(oldrot-newrot)
diffPos = ((oldpos[0]-newpos[0])*moveMultiplier, (oldpos[1]-newpos[1])*moveMultiplier)
diffRot = (oldrot-newrot)*rotMultiplier
if abs(diffPos[0]) > 1 or abs(diffPos[1]) > 1 or abs(diffRot) > 1:
print("Error! Robot moved too fast!, Try to edit 'Multiplier' values in export.py")
return (0, 0), 0
print(diffPos)
# print(diffRot)
return diffPos, diffRot
def getControllersAtFrame(index):
controllers = [xboxController(), xboxController()]
if index >= buttonEditor.matchTicks:
return controllers
pos, rot = getSticksAtFrame(index)
controllers[0].leftStick = pos
controllers[0].rightStick = (rot,0)
btns = buttonEditor.getLeftButtonFrame(index)
if btns == None:
btns = buttonEditor.createBlankController()
else:
btns = btns['controllers']
for i in range(len(controllers)):
ctrlr = btns[i]
controllers[i].buttons[0] = ctrlr['A']
controllers[i].buttons[1] = ctrlr['B']
controllers[i].buttons[2] = ctrlr['X']
controllers[i].buttons[3] = ctrlr['Y']
controllers[i].buttons[4] = ctrlr['LB']
controllers[i].buttons[5] = ctrlr['RB']
controllers[i].buttons[6] = ctrlr['Menu']
controllers[i].buttons[7] = ctrlr['Windows']
controllers[i].buttons[8] = ctrlr['Left_Stick']
controllers[i].buttons[9] = ctrlr['Right_Stick']
controllers[i].LT = (ctrlr['LT']*2)-1
controllers[i].RT = (ctrlr['RT']*2)-1
controllers[i].POV = getPOVhat(ctrlr['Dpad_Up'], ctrlr['Dpad_Down'],
ctrlr['Dpad_Left'], ctrlr['Dpad_Right'])
return controllers
def getFrameData(index):
controllers = getControllersAtFrame(index)
data = b''
for ctrlr in controllers:
# print(ctrlr.leftStick[0])
data += toDouble(ctrlr.leftStick[0])
data += toDouble(ctrlr.leftStick[1])
data += toDouble(ctrlr.LT)
data += toDouble(ctrlr.RT)
data += toDouble(ctrlr.rightStick[0])
data += toDouble(ctrlr.rightStick[1])
data += buttonsToBytes(ctrlr.buttons)
# for btn in ctrlr.buttons:
# data += toBit(data)
# print(toBit(data))
data += toShort(ctrlr.POV)
data += toInt(index * buttonEditor.tickTime)
return data
def getHeader():
header = toByte(6) # Num Axes per controller
header += toByte(1) # Num POVs
header += toByte(2) # Num Controllers
header += toShort(buttonEditor.matchTicks) # Num Frames
return header
def getData():
data = b''
for i in range(buttonEditor.matchTicks):
data += getFrameData(i)
return getHeader() + data
def save():
path = crossfiledialog.save_file('Save auto file', './')
# path = "./file.txt"
with open(path, "wb") as f:
f.write(getData())
class export:
name = "Export"
def __init__(self, tmppg, tmprender, tmpbuttonEditor):
global pg
pg = tmppg
global render
render = tmprender
global buttonEditor
buttonEditor = tmpbuttonEditor
self.loaded = False
def getIsSelected():
return False
def getIsVisible():
return self.loaded
def onClick(pos):
save()
render.addButton((round(render.width/4),round(render.screen.get_height()/4),round(render.width/2),round(render.height/2)),
"Export", getIsSelected, getIsVisible, onClick)
def mouseDown(self, pos):
pass
def mouseUp(self, pos):
pass
def mouseMove(self, pos):
pass
def doubleClick(self, pos):
pass
def keyDown(self, key):
pass
def load(self):
self.loaded = True
# for keyFrame in buttonEditor.keyFrames:
# keyFrame['timeIndex'] = keyFrame['timeIndex'] * buttonEditor.displayTickResolution
render.clear()
pg.display.update()
def unload(self):
self.loaded = False
# for keyFrame in buttonEditor.keyFrames:
# keyFrame['timeIndex'] = round(keyFrame['timeIndex'] / buttonEditor.displayTickResolution)
-194
View File
@@ -1,194 +0,0 @@
import math
from pygame.locals import *
nodeColor = (255, 255, 255)
nodeRadius = 12
rotNodeDist = 35
rotNodeColor = (255, 0, 255)
rotNodeRadius = 8
lineApproximationLineColor = (127, 127, 127, 0.5)
lineApproximationLineWidth = 3
curveEditPointColor = (0, 255, 255)
curveEditPointRadius = 8
curvePointCount = 80
nodes = []
curveEditPoints = []
nodeRotations = []
clickType = -1
clickIndex = -1
render = None
def refresh():
render.clear()
render.drawField()
for i in range(0,len(curveEditPoints)):
render.line(lineApproximationLineColor, nodes[i], curveEditPoints[i], lineApproximationLineWidth)
render.line(lineApproximationLineColor, curveEditPoints[i], nodes[i+1], lineApproximationLineWidth)
render.bezier(nodes[i], curveEditPoints[i], nodes[i+1], curvePointCount)
render.circle(curveEditPointColor, curveEditPoints[i], curveEditPointRadius)
for i in range(0,len(nodeRotations)):
posX = (math.sin(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][0]
posY = (math.cos(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][1]
render.circle(rotNodeColor, (posX, posY), rotNodeRadius)
render.robotSquare(nodes[i], nodeRotations[i])
for pos in nodes:
render.circle(nodeColor, pos, nodeRadius)
render.update()
def getElemAt(pos):
for i in range(0,len(nodes)):
if getDist(pos, nodes[i], nodeRadius):
return 0, i
for i in range(0,len(nodeRotations)):
posX = (math.sin(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][0]
posY = (math.cos(nodeRotations[i])*rotNodeDist/render.offsetSize) + nodes[i][1]
if getDist(pos, (posX, posY), nodeRadius):
return 2, i
for i in range(0,len(curveEditPoints)):
if getDist(pos, curveEditPoints[i], curveEditPointRadius):
return 1, i
return -1, -1
def getDist(pos1, pos2, dist):
return math.sqrt(math.pow(pos1[0]-pos2[0], 2) + math.pow(pos1[1]-pos2[1], 2)) <= dist
def addNode(pos):
nodes.append(pos)
if len(nodes) > 1:
index = len(nodes)-1
# Middle point between current point and previous point
editPos = (nodes[index-1][0]+pos[0])/2,(nodes[index-1][1]+pos[1])/2
curveEditPoints.append(editPos)
nodeRotations.append(nodeRotations[index-1])
else:
nodeRotations.append(math.pi/2)
refresh()
def nearestCirclePoint(center, pos, R):
vX = pos[0] - center[0]
vY = pos[1] - center[1]
magV = math.sqrt(vX*vX + vY*vY)
aX = center[0] + vX / magV * R
aY = center[1] + vY / magV * R
return (aX, aY)
def points2rad(center, pos):
diffX = center[0] - pos[0]
diffY = center[1] - pos[1]
return -math.atan2(diffY, diffX) - (math.pi/2)
def smoothPoints(index: int):
for i in range(index+1, len(curveEditPoints)):
controlPointPos = curveEditPoints[i-1]
nodePos = nodes[i]
curveEditPoints[i] = (
2*nodePos[0] - controlPointPos[0],
2*nodePos[1] - controlPointPos[1]
)
for i in range(0, index):
controlPointPos = curveEditPoints[index-i]
nodePos = nodes[index-i]
curveEditPoints[index-i-1] = (
2*nodePos[0] - controlPointPos[0],
2*nodePos[1] - controlPointPos[1]
)
class pathEditor:
name = "Path Editor"
def __init__(self, tmprender):
# global screen
# screen = tmpscreen
global render
render = tmprender
refresh()
def mouseDown(self, pos):
global clickType
global clickIndex
clickType, clickIndex = getElemAt(pos)
if clickType == -1:
addNode(pos)
def mouseUp(self, pos):
global clickType
global clickIndex
if clickType != -1:
clickType = -1
clickIndex = -1
def mouseMove(self, pos):
if clickType != -1:
if clickType == 0:
nodes[clickIndex] = pos
if clickType == 1:
curveEditPoints[clickIndex] = pos
if clickType == 2:
nodeRotations[clickIndex] = points2rad(nodes[clickIndex], nearestCirclePoint(nodes[clickIndex], pos, rotNodeDist/render.offsetSize))
refresh()
def doubleClick(self, pos):
clickType, clickIndex = getElemAt(pos)
if clickType == -1:
pass
elif clickType == 1:
smoothPoints(clickIndex)
refresh()
elif clickType == 0:
if clickIndex > 0:
if clickIndex < len(nodes)-1:
newPos = (nodes[clickIndex-1][0]+nodes[clickIndex][0])/2,(nodes[clickIndex-1][1]+nodes[clickIndex][1])/2
curveEditPoints[clickIndex] = newPos
curveEditPoints.pop(clickIndex-1)
elif clickIndex == 0 and len(nodes) > 1:
curveEditPoints.pop(clickIndex)
nodes.pop(clickIndex)
nodeRotations.pop(clickIndex)
refresh()
def keyDown(self, key):
pass
def load(self):
refresh()
def unload(self):
pass
-211
View File
@@ -1,211 +0,0 @@
import math
import os
import sys
from pygame.locals import *
import numpy as np
curvePointColor = (255, 255, 0)
curvePointRadius = 2
selTabBorderSize = 2
selTabBorderIndent = 3
nodeSquareRadius = 35
nodeSquareColor = (127, 127, 127, 0.5)
nodeSquareWidth = 3
nodeTickLength = 5
def image_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
class render():
def __init__(self, pg, screen, topBarHeight, bottomBarHeight):
self.pg = pg
self.screen = screen
self.topBarHeight = topBarHeight
self.bottomBarHeight = bottomBarHeight
self.width = self.screen.get_width()
self.height = self.screen.get_width() * (643/1286)
self.rect = (0, self.topBarHeight, self.width, self.height+bottomBarHeight)
self.font = self.pg.font.Font(None, 25)
self.fieldImg = self.loadImg("images/Field.png")
self.offsetSize = self.fieldImg.get_width() / self.width
self.fieldImg = pg.transform.scale(self.fieldImg, (self.width, self.height))
self.elements = []
def invert(self, img):
inv = self.pg.Surface(img.get_rect().size, self.pg.SRCALPHA)
inv.fill((255,255,255))
inv.blit(img, (0,0), None, BLEND_RGB_SUB)
return inv
def line(self, color, pos1, pos2, width):
self.pg.draw.line(self.screen, color, pos1, pos2, round(width/self.offsetSize))
def circle(self, color, pos, radius):
self.pg.draw.circle(self.screen, color, pos, radius/self.offsetSize)
def drawrect(self, color, rect):
self.pg.draw.rect(self.screen, color, rect)
# def drawText(self, text, color,):
# text = self.font.render(text, True, color)
# rect = text.get_rect()
# self.screen.blit(text, rect)
# # text_rect = text.get_rect(center=(rect[0]+(rect[2]/2), rect[1]+(rect[3]/2)))
def isInRect(self, pos, rect):
return pos[0] >= rect[0] and \
pos[0] <= rect[0]+rect[2] and \
pos[1] >= rect[1] and \
pos[1] <= rect[1]+rect[3]
def image(self, img, rect):
self.screen.blit(self.pg.transform.scale(img, (rect[2], rect[3])), rect)
def loadImg(self, path):
return self.pg.image.load(image_path(path)).convert_alpha()
def robotSquare(self, pos, rot):
pos1 = ((math.sin(rot + math.pi*-0.25)*nodeSquareRadius/self.offsetSize) + pos[0],
(math.cos(rot + math.pi*-0.25)*nodeSquareRadius/self.offsetSize) + pos[1])
pos2 = ((math.sin(rot + math.pi*0.25)*nodeSquareRadius/self.offsetSize) + pos[0],
(math.cos(rot + math.pi*0.25)*nodeSquareRadius/self.offsetSize) + pos[1])
pos3 = ((math.sin(rot + math.pi*0.75)*nodeSquareRadius/self.offsetSize) + pos[0],
(math.cos(rot + math.pi*0.75)*nodeSquareRadius/self.offsetSize) + pos[1])
pos4 = ((math.sin(rot + math.pi*1.25)*nodeSquareRadius/self.offsetSize) + pos[0],
(math.cos(rot + math.pi*1.25)*nodeSquareRadius/self.offsetSize) + pos[1])
pos5 = ((math.sin(rot)*(nodeSquareRadius+nodeTickLength)/self.offsetSize) + pos[0],
(math.cos(rot)*(nodeSquareRadius+nodeTickLength)/self.offsetSize) + pos[1])
pos6 = ((math.sin(rot)*(nodeSquareRadius-nodeTickLength)/self.offsetSize) + pos[0],
(math.cos(rot)*(nodeSquareRadius-nodeTickLength)/self.offsetSize) + pos[1])
self.line(nodeSquareColor, pos1, pos2, nodeSquareWidth*self.offsetSize)
self.line(nodeSquareColor, pos2, pos3, nodeSquareWidth*self.offsetSize)
self.line(nodeSquareColor, pos3, pos4, nodeSquareWidth*self.offsetSize)
self.line(nodeSquareColor, pos4, pos1, nodeSquareWidth*self.offsetSize)
self.line(nodeSquareColor, pos5, pos6, nodeSquareWidth*self.offsetSize)
def bezier(self, p0, p1, p2, curvePointCount):
#for p in [p0, p1, p2]:
# pg.draw.circle(self.screen, (255, 255, 255), p, 5)
for t in np.arange(0, 1, 1/curvePointCount):
px = p0[0]*(1-t)**2 + 2*(1-t)*t*p1[0] + p2[0]*t**2
py = p0[1]*(1-t)**2 + 2*(1-t)*t*p1[1] + p2[1]*t**2
self.circle(curvePointColor, (px, py), curvePointRadius)
self.circle(curvePointColor, p2, curvePointRadius)
#self.drawrect(curvePointColor, (round(px+0.5), round(py+0.5), curvePointRadius, curvePointRadius))
def clear(self):
self.pg.draw.rect(self.screen, (0, 0, 0), self.rect)
def drawField(self):
self.screen.blit(self.fieldImg, self.rect)
def renderElements(self, pos):
for elem in self.elements:
if elem['type'] == 'button' and elem['getIsVisible']():
# print(elem['getIsSelected']())
self.renderButton(elem['rect'], elem['text'], elem['getIsSelected'](), pos)
def clickElement(self, pos):
for elem in self.elements:
if elem['type'] == 'button' and elem['getIsVisible']() and self.isInRect(pos, elem['rect']):
elem['onClick'](pos)
def update(self):
self.pg.display.update()
def addButton(self, rect, text, getIsSelected, getIsVisible, onClick):
self.elements.append({
"type": "button",
"text": text,
"getIsSelected": getIsSelected,
"getIsVisible": getIsVisible,
"onClick": onClick,
"rect": rect
})
def renderButton(self, rect, text, selected, mousePos):
# print(isInRect(mousePos, rect))
if self.isInRect(mousePos, rect):
color = (16,64,32)
else:
color = (16,16,32)
if selected:
borderColor = (0,255,0)
else:
borderColor = (64,127,127)
text = self.font.render(text, True, (255,255,255))
text_rect = text.get_rect(center=(rect[0]+(rect[2]/2), rect[1]+(rect[3]/2)))
self.pg.draw.rect(self.screen, color, rect)
rect = (rect[0]+selTabBorderIndent,rect[1]+selTabBorderIndent,
rect[2]-selTabBorderIndent*2,rect[3]-selTabBorderIndent*2)
self.pg.draw.rect(self.screen, borderColor, rect)
rect = (rect[0]+selTabBorderSize,rect[1]+selTabBorderSize,
rect[2]-selTabBorderSize*2,rect[3]-selTabBorderSize*2)
self.pg.draw.rect(self.screen, color, rect)
self.screen.blit(text, text_rect)
self.update()