Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/ball trail #130

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions Controller/DrawingObject/FieldGroundDrawing.py

This file was deleted.

65 changes: 50 additions & 15 deletions Controller/DrawingObject/FieldLineDrawing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Under MIT License, see LICENSE.txt
import math

from PyQt5 import QtCore
from PyQt5.QtGui import QPixmap, QPainter

from Controller.DrawingObject.color import Color
from Controller.DrawingObject.BaseDrawingObject import BaseDrawingObject
Expand All @@ -11,43 +13,76 @@ class FieldLineDrawing(BaseDrawingObject):
def __init__(self):
BaseDrawingObject.__init__(self)

self.field_cache = QPixmap(1000, 1000)
self.field_painter = QPainter(self.field_cache)

def draw(self, painter):
if self.isVisible():
painter.setBrush(QtToolBox.create_brush(is_visible=False))
if self.isVisible() and QtToolBox.field_ctrl.need_redraw:
QtToolBox.field_ctrl.need_redraw = False

# Grass drawing
self.drawGrass()

painter.setPen(QtToolBox.create_pen(color=Color.WHITE,
self.field_painter.setBrush(QtToolBox.create_brush(is_visible=False))

self.field_painter.setPen(QtToolBox.create_pen(color=Color.WHITE,
style='SolidLine',
width=QtToolBox.field_ctrl.line_width * QtToolBox.field_ctrl.ratio_screen))

for name, arc in QtToolBox.field_ctrl.field_arcs.items():
self.drawArc(painter, arc)
self.drawArc(self.field_painter, arc)
for name, line in QtToolBox.field_ctrl.field_lines.items():
self.drawLine(painter, line)
self.drawLine(self.field_painter, line)

# Dessine left goal
painter.setPen(QtToolBox.create_pen(color=Color.BLUE,
self.field_painter.setPen(QtToolBox.create_pen(color=Color.BLUE,
style='SolidLine',
width=50 * QtToolBox.field_ctrl.ratio_screen))
for name, line in QtToolBox.field_ctrl.field_goal_left.items():
self.drawLine(painter, line)
self.drawLine(self.field_painter, line)

# Dessine right goal
painter.setPen(QtToolBox.create_pen(color=Color.YELLOW,
self.field_painter.setPen(QtToolBox.create_pen(color=Color.YELLOW,
style='SolidLine',
width=50 * QtToolBox.field_ctrl.ratio_screen))
for name, line in QtToolBox.field_ctrl.field_goal_right.items():
self.drawLine(painter, line)
self.drawLine(self.field_painter, line)

painter.drawPixmap(0, 0, self.field_cache)

def drawGrass(self, nb_lines = 10):
self.field_painter.setPen(QtToolBox.create_pen(is_hide=True))
self.field_painter.setBrush(QtToolBox.create_brush(color=Color.DARK_GREEN_FIELD))
self.field_painter.drawRect(0, 0, 9500, 6500)
self.field_painter.setBrush(QtToolBox.create_brush(color=Color.GREEN_FIELD))

width, height = QtToolBox.field_ctrl.field_length, QtToolBox.field_ctrl.field_width
xo, yo = width / 2, height / 2
width_line = width / nb_lines
for i in range(0, nb_lines, 2):
# Top left
ax, ay, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst(i * width_line - xo, -yo)
# Bot right
bx, by, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst((i + 1) * width_line -xo, height -yo)
self.field_painter.drawRect(ax, ay, bx-ax, by-ay)


def drawArc(self, painter, arc):
x, y, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst(arc.center[0] - arc.radius,
arc.center[1] + arc.radius)
width = arc.radius * 2 * QtToolBox.field_ctrl.ratio_screen
# Top left
ax, ay, theta_off = QtToolBox.field_ctrl.convert_real_to_scene_pst(arc.center[0] - arc.radius,
arc.center[1] + arc.radius)
# Lower right
bx, by, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst(arc.center[0] + arc.radius,
arc.center[1] - arc.radius)
# Qt is weird and it require a rectangle to be defined to draw an arc
rect = QtCore.QRect(x, y, width, width)
rect = QtCore.QRect(ax, ay, bx-ax, by-ay)

# If the screen is rotate, the angle is also rotated
theta_off_deg = theta_off * 180 / math.pi
# Angle are calculate in 1/16th of a degree
painter.drawArc(rect,
int(arc.start_angle) * 16,
int(arc.end_angle - arc.start_angle) * 16)
int(arc.start_angle - theta_off_deg) * 16,
int(arc.end_angle - arc.start_angle - theta_off_deg) * 16)

def drawLine(self, painter, line):
x1, y1, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst(line.p1[0], line.p1[1])
Expand Down
4 changes: 3 additions & 1 deletion Controller/DrawingObject/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ class Color:
WHITE = ColorTuple(red=255, green=255, blue=255)
DARK_GREEN_FIELD = ColorTuple(red=0, green=150, blue=0)
GREEN_FIELD = ColorTuple(red=0, green=125, blue=0)
ORANGE = ColorTuple(red=255, green=100, blue=0)
CLEAR_ORANGE = ColorTuple(red=238, green=239, blue=168)
ORANGE = ColorTuple(red=255, green=100, blue=0)
DARK_ORANGE = ColorTuple(red=125, green=69, blue=25)
53 changes: 42 additions & 11 deletions Controller/FieldController.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Under MIT License, see LICENSE.txt

import math
from math import cos, sin, atan2, sqrt, pi

from Communication.messages_robocup_ssl_geometry_pb2 import SSL_GeometryFieldSize
Expand Down Expand Up @@ -51,6 +51,7 @@ def __init__(self):
self.ratio_screen = 1 / 10
self.is_x_axe_flipped = False
self.is_y_axe_flipped = True
self.is_horizontal = True

# Dimension du terrain
self.margin = 250 # Marge au tour du terrain pour l'écran
Expand All @@ -74,6 +75,10 @@ def __init__(self):
self.field_goal_left = {}
self.field_goal_right = {}

self.prev_field = None

self.need_redraw = True

@property
def line_width(self):
return self._line_width
Expand Down Expand Up @@ -124,27 +129,43 @@ def ratio_field_mobs(self, new_ratio):

def convert_real_to_scene_pst(self, x, y, theta=0.0):
""" Convertit les coordonnées réelles en coordonnées du terrain """

if not self.is_horizontal:
x, y = -y, x
theta += math.pi / 2
rot_x = cos(theta)
rot_y = sin(theta)

if self.is_x_axe_flipped:
x *= -1
rot_x *= -1
if self.is_y_axe_flipped:
y *= -1
rot_y *= -1
x = (x + self.field_length / 2 + self.margin) * self.ratio_screen + self._camera_position[0]
y = (y + self.field_width / 2 + self.margin) * self.ratio_screen + self._camera_position[1]
return x, y, atan2(rot_y, rot_x)

x_screen = (x + self.field_length / 2 + self.margin) * self.ratio_screen + self._camera_position[0]
y_screen = (y + self.field_width / 2 + self.margin) * self.ratio_screen + self._camera_position[1]
return x_screen, y_screen, atan2(rot_y, rot_x)

def convert_screen_to_real_pst(self, x, y):
""" Convertir les coordonnées du terrain en coordonnées réelles """
x_2 = (x - self._camera_position[0]) / self.ratio_screen - self.field_length / 2 - self.margin
y_2 = (y - self._camera_position[1]) / self.ratio_screen - self.field_width / 2 - self.margin
x_real = (x - self._camera_position[0]) / self.ratio_screen - self.field_length / 2 - self.margin
y_real = (y - self._camera_position[1]) / self.ratio_screen - self.field_width / 2 - self.margin

if self.is_x_axe_flipped:
x_2 *= -1
x_real *= -1
if self.is_y_axe_flipped:
y_2 *= -1
return x_2, y_2
y_real *= -1

if self.is_horizontal:
return x_real, y_real
else:
return y_real, -x_real

def set_horizontal(self, val: bool):
if self.is_horizontal != val:
self.need_redraw = True
self.is_horizontal = val

def flip_x_axe(self):
""" Retourne l'axe des X du terrain """
Expand All @@ -166,6 +187,7 @@ def get_size_to_screen(self):

def drag_camera(self, x, y):
""" Déplacement de la caméra """
self.need_redraw = True
if not self._lock_camera:
if self._cursor_last_pst is None:
self._cursor_last_pst = x, y
Expand Down Expand Up @@ -196,7 +218,9 @@ def _limit_camera(self):

def zoom(self, x, y, scroll_delta_y):
""" Zoom la caméra de +10% (+/- un facteur de ralentissement)"""
SCALE_CHANGE = 0.1
SCALE_CHANGE = 0.05

self.need_redraw = True
if not self._lock_camera and self.ratio_screen < 0.6:
rx, ry = self.convert_screen_to_real_pst(x, y)
self.ratio_screen *= 1 + SCALE_CHANGE * scroll_delta_y / self.scroll_slowing_factor
Expand All @@ -206,7 +230,9 @@ def zoom(self, x, y, scroll_delta_y):

def dezoom(self, x, y, scroll_delta_y):
""" Dézoom la caméra de -10% (+/- un facteur de ralentissement)"""
SCALE_CHANGE = 0.1
SCALE_CHANGE = 0.05

self.need_redraw = True
if not self._lock_camera and self.ratio_screen > 0.03:
rx, ry = self.convert_screen_to_real_pst(x, y)
self.ratio_screen /= 1 + SCALE_CHANGE * -scroll_delta_y / self.scroll_slowing_factor
Expand Down Expand Up @@ -237,6 +263,9 @@ def set_field_size(self, field: SSL_GeometryFieldSize):
def _set_field_size_new(self, field: SSL_GeometryFieldSize):
self.field_lines = self._convert_field_line_segments(field.field_lines)
self.field_arcs = self._convert_field_circular_arc(field.field_arcs)
if self.prev_field == field:
return
self.need_redraw = True # Only redraw when receiving new geometry message
self.field_goal_left = \
{name: line for name, line in self.field_lines.items() if
name.startswith("LeftGoal") and name != "LeftGoalLine"}
Expand All @@ -259,6 +288,8 @@ def _set_field_size_new(self, field: SSL_GeometryFieldSize):
self._center_circle_radius = self.field_arcs['CenterCircle'].radius
self._defense_stretch = self.field_lines['LeftPenaltyStretch'].length / 2

self.prev_field = field

def _convert_field_circular_arc(self, field_arcs):
return {arc.name: FieldCircularArc(arc) for arc in field_arcs}

Expand Down
16 changes: 16 additions & 0 deletions Controller/MainController.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,14 @@ def init_menubar(self):

fieldMenu.addSeparator()

horiAction = QAction("Changer à l'horizontal", self)
horiAction.triggered.connect(self.set_screen_to_horizontal)
fieldMenu.addAction(horiAction)

vertAction = QAction("Changer à la vertical", self)
vertAction.triggered.connect(self.set_screen_to_vertical)
fieldMenu.addAction(vertAction)

flipXAction = QAction("Changer l'axe des X", self, checkable=True)
flipXAction.triggered.connect(self.flip_screen_x_axe)
fieldMenu.addAction(flipXAction)
Expand Down Expand Up @@ -360,6 +368,14 @@ def toggle_full_screen(self):
else:
self.setWindowState(Qt.WindowActive)

def set_screen_to_horizontal(self):
""" Met l'écran à l'horizontal """
QtToolBox.field_ctrl.set_horizontal(True)

def set_screen_to_vertical(self):
""" Met l'écran à la vertical """
QtToolBox.field_ctrl.set_horizontal(False)

def flip_screen_x_axe(self):
""" Bascule l'axe des X de l'écran """
QtToolBox.field_ctrl.flip_x_axe()
Expand Down
30 changes: 27 additions & 3 deletions Controller/MobileObject/BallMob.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Under MIT License, see LICENSE.txt
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainterPath

from Controller.DrawingObject.color import Color
from Controller.MobileObject.BaseMobileObject import BaseMobileObject
from Controller.QtToolBox import QtToolBox
from collections import deque

__author__ = 'RoboCupULaval'

Expand All @@ -12,23 +15,44 @@ def __init__(self, x=0, y=0):
BaseMobileObject.__init__(self, x, y)
self._radius = 43 / 2

NB_BALL_POSE_TO_KEEP = 50
self.queue = deque(maxlen=NB_BALL_POSE_TO_KEEP)

@property
def radius(self):
return self._radius * QtToolBox.field_ctrl.ratio_field_mobs

def draw(self, painter):
if self.isVisible():
bx, by, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst(self._x, self._y)

self.queue.appendleft((self._x, self._y))

# Draw ball's trail
path_painter = QPainterPath()
path_painter.moveTo(bx, by)
for rx, ry in self.queue:
x, y, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst(rx, ry)
path_painter.lineTo(x, y)

painter.setBrush(Qt.NoBrush)
painter.setPen(QtToolBox.create_pen(color=Color.CLEAR_ORANGE,
style='SolidLine',
width=2))
painter.drawPath(path_painter)

# Draw ball
painter.setBrush(QtToolBox.create_brush(color=Color.ORANGE))
painter.setPen(QtToolBox.create_pen(color=Color.BLACK,
style='SolidLine',
width=1))
x, y, _ = QtToolBox.field_ctrl.convert_real_to_scene_pst(self._x, self._y)
radius = self.radius * QtToolBox.field_ctrl.ratio_screen
painter.drawEllipse(x - radius,
y - radius,
painter.drawEllipse(bx - radius,
by - radius,
radius * 2,
radius * 2)


@staticmethod
def get_datain_associated():
return 'ball'
10 changes: 2 additions & 8 deletions View/FieldView.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,6 @@ def draw_effects(self, painter):
for effect in list_effect:
effect.draw(painter)

def draw_field_ground(self, painter):
""" Dessine le sol du terrain """
self.graph_draw['field-ground'].draw(painter)

def draw_mobs(self, painter):
""" Dessine les objets mobiles """
self.graph_mobs['ball'].draw(painter)
Expand Down Expand Up @@ -204,8 +200,6 @@ def init_graph_mobs(self):
max_robots_in_team = 16 # TODO : Variable globale?

# Élément graphique pour les dessins
self.graph_draw['field-ground'] = self.controller.get_drawing_object('field-ground')()
self.graph_draw['field-ground'].show()
self.graph_draw['field-lines'] = self.controller.get_drawing_object('field-lines')()
self.graph_draw['field-lines'].show()
self.graph_draw['frame-rate'] = self.controller.get_drawing_object('frame-rate')()
Expand Down Expand Up @@ -450,11 +444,11 @@ def paintEvent(self, e):
painter = QPainter()
painter.begin(self)
painter.setBackground(QtToolBox.create_brush())
self.draw_field_ground(painter)
self.draw_field_lines(painter)
self.draw_map(painter)
self.draw_multiple_points(painter)
self.draw_effects(painter)
self.draw_field_lines(painter)
# self.draw_field_lines(painter)
if self.slingshot_mode:
self.draw_slingshot(painter)
self.draw_mobs(painter)
Expand Down
1 change: 0 additions & 1 deletion View/ParamView.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,6 @@ def _apply_param(self):
self.form_ratio_mobs.setStyleSheet(style_good)
QtToolBox.field_ctrl.ratio_field_mobs = float(self.form_ratio_mobs.text())
except Exception as e:
print(e)
self.form_ratio_mobs.setStyleSheet(style_bad)
is_wrong = True

Expand Down