Skip to content
Snippets Groups Projects
Commit bba5d3b7 authored by Lucas Philippe's avatar Lucas Philippe
Browse files

Ajout TP2 fonctionnel

parent ef888311
No related branches found
No related tags found
No related merge requests found
Showing
with 379 additions and 64 deletions
......@@ -30,5 +30,4 @@ class BubbleCursor:
if previous_closest != self.closest:
if previous_closest:
previous_closest.highlighted = False
self.closest.highlighted = True
self.closest.highlighted = True
\ No newline at end of file
import csv, random, time
import csv
import random
import time
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QWidget
from Target import Target
from BubbleCursor import BubbleCursor
from Target import Target
class BubbleWidget(QWidget):
def __init__(self):
def __init__(self, file_name, exp_setup, number_of_targets):
super().__init__()
self.exp_setup = exp_setup
self.targets = []
self.loadTargets()
self.cursor = BubbleCursor(self.targets)
self.setMouseTracking(True)
self.start_time = None
self.selectRandomTarget()
self.errors = 0
def loadTargets(self):
with open('src_tp_bubble.csv', newline='') as csvfile:
# Chargement du fichier csv
with open(file_name) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
if len(row) >= 3:
x, y, size = map(int, row[:3])
self.targets.append(Target(x,y,size))
x = int(row[0])
y = int(row[1])
size = int(row[2])
target = Target(x, y, size)
self.targets.append(target)
self.target_to_select = self.targets[:number_of_targets]
self.cursor = BubbleCursor(self.targets)
self.selectRandomTarget()
def paintEvent(self, event):
painter = QPainter(self)
......@@ -35,15 +45,23 @@ class BubbleWidget(QWidget):
def selectRandomTarget(self):
if self.start_time == None:
self.start_time = time.time()
target = random.choice(self.targets)
target = self.target_to_select.pop()
target.toSelect = True
self.update()
def printTime(self):
print((time.time() - self.start_time)*1000)
def printLog(self):
current_time = (time.time() - self.start_time)*1000
self.exp_setup.add_line_to_response(current_time, self.errors)
self.errors = 0
self.start_time = None
def mousePressEvent(self, event):
if self.cursor.closest.click_cible():
self.printTime()
self.selectRandomTarget()
\ No newline at end of file
if self.cursor.closest is not None:
if self.cursor.closest.click_cible():
self.printLog()
if len(self.target_to_select) > 0:
self.selectRandomTarget()
else:
self.exp_setup.next_experience()
else:
self.errors += 1
......@@ -3,14 +3,18 @@ import sys
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication, QMainWindow
from BubbleWidget import BubbleWidget
file_name = "data/src_tp_bubble.csv"
def main():
app = QApplication(sys.argv)
main_window = QMainWindow()
main_window.resize(1024, 800)
bubble_widget = BubbleWidget()
bubble_widget = BubbleWidget(file_name)
main_window.setCentralWidget(bubble_widget)
main_window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
if len(sys.argv) == 2:
file_name = sys.argv[1]
main()
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from NormalWidget import NormalWidget
file_name = "data/src_tp_bubble.csv"
def main():
app = QApplication([])
window = QMainWindow()
window.resize(1024, 800)
normalWidget = NormalWidget()
normalWidget = NormalWidget(file_name)
window.setCentralWidget(normalWidget)
window.show()
app.exec_()
if __name__ == "__main__":
if len(sys.argv) == 2:
file_name = sys.argv[1]
main()
from PyQt5.QtWidgets import QApplication, QMainWindow
from RopeWidget import RopeWidget
file_name = "data/src_tp_bubble.csv"
def main():
app = QApplication([])
window = QMainWindow()
window.resize(1024, 800)
bubble_widget = RopeWidget()
bubble_widget = RopeWidget(file_name)
window.setCentralWidget(bubble_widget)
window.show()
app.exec_()
......
......@@ -11,16 +11,19 @@ class NormalCursor:
def move(self, x, y):
self.x = x
self.y = y
previous_closest = self.closest
closest_target = None
min_distance = float('inf')
for target in self.targets:
distance = ((self.x - target.x) ** 2 + (self.y - target.y) ** 2) ** 0.5 # cf. Theoreme de Pythagore
distance = ((self.x - target.x) ** 2 + (self.y - target.y) ** 2) ** 0.5
if distance < min_distance:
min_distance = distance
closest_target = target
if distance < target.size/2:
self.closest = target
self.closest.highlighted = True
if closest_target and min_distance < closest_target.size / 2:
closest_target.highlighted = True
else:
if self.closest and self.closest != closest_target:
self.closest.highlighted = False
if previous_closest is not None:
distance = ((self.x - previous_closest.x) ** 2 + (self.y - previous_closest.y) ** 2) ** 0.5 # cf. Theoreme de Pythagore
if distance > previous_closest.size / 2:
previous_closest.highlighted = False
\ No newline at end of file
self.closest = closest_target
\ No newline at end of file
import csv, random, time
import csv
import random
import time
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QWidget
from NormalCursor import NormalCursor
from Target import Target
from TP1.NormalCursor import NormalCursor
class NormalWidget(QWidget):
def __init__(self):
def __init__(self, file_name, exp_setup, number_of_targets):
super().__init__()
self.targets = []
self.loadTargets()
self.cursor = NormalCursor(self.targets)
self.setMouseTracking(True)
self.start_time = None
self.selectRandomTarget()
self.exp_setup = exp_setup
self.errors = 0
def loadTargets(self):
with open('src_tp_bubble.csv', newline='') as csvfile:
# Chargement du fichier csv
with open(file_name) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
if len(row) >= 3:
x, y, size = map(int, row[:3])
self.targets.append(Target(x,y,size))
x = int(row[0])
y = int(row[1])
size = int(row[2])
target = Target(x, y, size)
self.targets.append(target)
self.target_to_select = self.targets[:number_of_targets]
self.cursor = NormalCursor(self.targets)
self.selectRandomTarget()
def paintEvent(self, event):
painter = QPainter(self)
......@@ -32,17 +41,30 @@ class NormalWidget(QWidget):
self.update()
def selectRandomTarget(self):
if self.start_time == None:
if self.start_time is None:
self.start_time = time.time()
target = random.choice(self.targets)
target = self.target_to_select.pop()
target.toSelect = True
self.update()
def printTime(self):
print((time.time() - self.start_time)*1000)
def printLog(self):
current_time = (time.time() - self.start_time)*1000
self.exp_setup.add_line_to_response(current_time, self.errors)
self.errors = 0
self.start_time = None
def mousePressEvent(self, event):
if self.cursor.closest.click_cible():
self.printTime()
self.selectRandomTarget()
if self.cursor.closest is not None and self.cursor.closest.toSelect:
distance = ((event.x() - self.cursor.closest.x) ** 2 + (event.y() - self.cursor.closest.y) ** 2) ** 0.5
if distance <= self.cursor.closest.size / 2:
if self.cursor.closest.click_cible():
self.printLog()
if len(self.target_to_select) > 0:
self.selectRandomTarget()
else:
self.exp_setup.next_experience()
else:
self.errors += 1
else:
self.errors += 1
\ No newline at end of file
# Programmation d'une technique d'interaction : le Bubble Cursor
......@@ -5,22 +5,27 @@ from Target import Target
from RopeCursor import RopeCursor
class RopeWidget(QWidget):
def __init__(self):
def __init__(self, file_name, exp_setup, number_of_targets):
super().__init__()
self.exp_setup = exp_setup
self.targets = []
self.loadTargets()
self.cursor = RopeCursor(self.targets)
self.setMouseTracking(True)
self.start_time = None
self.selectRandomTarget()
self.errors = 0
def loadTargets(self):
with open('src_tp_bubble.csv', newline='') as csvfile:
# Chargement du fichier csv
with open(file_name) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
if len(row) >= 3:
x, y, size = map(int, row[:3])
self.targets.append(Target(x,y,size))
x = int(row[0])
y = int(row[1])
size = int(row[2])
target = Target(x, y, size)
self.targets.append(target)
self.target_to_select = self.targets[:number_of_targets]
self.cursor = RopeCursor(self.targets)
self.selectRandomTarget()
def paintEvent(self, event):
painter = QPainter(self)
......@@ -35,15 +40,23 @@ class RopeWidget(QWidget):
def selectRandomTarget(self):
if self.start_time == None:
self.start_time = time.time()
target = random.choice(self.targets)
target = self.target_to_select.pop()
target.toSelect = True
self.update()
def printTime(self):
print((time.time() - self.start_time)*1000)
def printLog(self):
current_time = (time.time() - self.start_time)*1000
self.exp_setup.add_line_to_response(current_time, self.errors)
self.errors = 0
self.start_time = None
def mousePressEvent(self, event):
if self.cursor.closest.click_cible():
self.printTime()
self.selectRandomTarget()
if self.cursor.closest is not None:
if self.cursor.closest.click_cible():
self.printLog()
if len(self.target_to_select) > 0:
self.selectRandomTarget()
else:
self.exp_setup.next_experience()
else:
self.errors += 1
No preview for this file type
No preview for this file type
No preview for this file type
import os
import sys
from PyQt5.QtGui import QIntValidator
from PyQt5.QtWidgets import QDialog, QLabel, QLineEdit, QComboBox, QGridLayout, QPushButton, QHBoxLayout, QVBoxLayout
from Experience import Experience
from FileDisplayWidget import FileDisplayWidget
DIR_PATH = "experience/generated_exp/"
TARGETS_PER_EXPERIENCE = 15
class ExpSetup(QDialog):
def __init__(self, window):
super().__init__()
self.file_name = 'experience/data/response.csv'
self.current_ordonnance = None
self.ordonnance = None
self.window = window
self.user_number = None
self.technique = None
self.repeats = None
self.current_repeat_series = 0
self.current_target_number = 1
user_label = QLabel("Numéro d'utilisateur :")
self.user_edit = QLineEdit()
self.user_edit.setValidator(QIntValidator())
tech_label = QLabel("Technique :")
self.tech_combo = QComboBox()
self.tech_combo.addItems(["Bubble", "Rope", "Normal"])
repeats_label = QLabel("Nombre de répétitions :")
self.repeats_edit = QLineEdit()
self.repeats_edit.setValidator(QIntValidator())
layout = QGridLayout()
layout.addWidget(user_label, 0, 0)
layout.addWidget(self.user_edit, 0, 1)
layout.addWidget(tech_label, 1, 0)
layout.addWidget(self.tech_combo, 1, 1)
layout.addWidget(repeats_label, 4, 0)
layout.addWidget(self.repeats_edit, 4, 1)
self.validate_button = QPushButton("Valider")
self.validate_button.clicked.connect(self.verify_entry)
h_layout = QHBoxLayout()
h_layout.addStretch()
h_layout.addWidget(self.validate_button)
h_layout.addStretch()
v_layout = QVBoxLayout()
v_layout.addLayout(layout)
v_layout.addLayout(h_layout)
self.setLayout(v_layout)
def verify_entry(self):
self.user_number = self.user_edit.text()
self.technique = self.tech_combo.currentIndex()
self.repeats = int(self.repeats_edit.text())
if self.repeats <= 1:
print('Répétition doit être strictement supérieur à 1')
else:
self.init_ordonnance()
self.next_experience()
def create_experience(self, experience, density, target_size):
if experience not in Experience:
# Error
print('Aucune expérience selectionné')
return None
density = str(density)
target_size = str(target_size)
file_name = "src_d_" + density + "_s_" + target_size + ".csv"
file_path = DIR_PATH + file_name
return experience.create_widget(file_path, self, TARGETS_PER_EXPERIENCE)
def start_experience(self, widget):
if widget is not None:
self.window.resize(1024, 800)
self.window.setCentralWidget(widget)
self.window.show()
def init_ordonnance(self):
self.ordonnance = []
self.current_ordonnance = -1
experience_list = [Experience.BUBBLE, Experience.ROPE, Experience.NORMAL]
experience_ordered = experience_list[self.technique:] + experience_list[:self.technique]
density_list = [30, 60, 90]
size_list = [9, 12, 18]
# Répéter la création des widgets pour chaque expérience en fonction du nombre de répétitions
for _ in range(self.repeats): # Répéter pour le nombre total de répétitions
for experience in experience_ordered:
for density in density_list:
for size in size_list:
widget = self.create_experience(experience, density, size)
self.ordonnance.append((widget, experience, density, size))
def next_experience(self):
self.current_target_number = 1
self.current_ordonnance += 1
if self.current_ordonnance >= len(self.ordonnance):
self.display_data()
return
if self.current_ordonnance % (len(self.ordonnance) / self.repeats) == 0:
self.current_repeat_series += 1
widget = self.ordonnance[self.current_ordonnance][0]
self.start_experience(widget)
def add_line_to_response(self, time, error):
line = f"{self.user_number}, {self.current_repeat_series}, {self.current_target_number}, {self.ordonnance[self.current_ordonnance][2]}, {self.ordonnance[self.current_ordonnance][3]}, {self.ordonnance[self.current_ordonnance][1].name}, {time}, {error}"
with open(self.file_name, "a") as file:
file.write(line + '\n')
self.current_target_number += 1
def display_data(self):
widget = FileDisplayWidget(self.file_name)
self.start_experience(widget)
from enum import Enum
from BubbleWidget import BubbleWidget
from RopeWidget import RopeWidget
from NormalWidget import NormalWidget
class Experience(Enum):
BUBBLE = 1
ROPE = 2
NORMAL = 3
def create_widget(self, file_path, exp_setup, number_of_targets):
if self.value == Experience.BUBBLE.value:
widget = BubbleWidget(file_path, exp_setup, number_of_targets)
elif self.value == Experience.ROPE.value:
widget = RopeWidget(file_path, exp_setup, number_of_targets)
elif self.value == Experience.NORMAL.value:
widget = NormalWidget(file_path, exp_setup, number_of_targets)
else:
print('Aucune expérience selectionnée')
widget = None
return widget
\ No newline at end of file
from PyQt5.QtWidgets import QTextEdit, QWidget, QApplication, QMainWindow
class FileDisplayWidget(QWidget):
def __init__(self, filename):
super().__init__()
self.filename = filename
self.textEdit = QTextEdit(self)
self.textEdit.setReadOnly(True)
with open(self.filename, 'r') as f:
self.textEdit.setPlainText(f.read())
def resizeEvent(self, event):
self.textEdit.setGeometry(0, 0, self.width(), self.height())
import random
import csv
SIZE_X_MAX = 1000
SIZE_Y_MAX = 800
DIR_NAME = 'generated_exp/'
SPACING = 5
all_density = (30, 60, 90)
all_size = (9, 12, 18)
max_density = max(all_density)
max_size = max(all_size)
def generate_targets(num_targets, max_target_size, min_spacing):
all_targets = []
for _ in range(num_targets):
x = random.randint(0, SIZE_X_MAX)
y = random.randint(0, SIZE_Y_MAX)
target = (x, y, max_target_size)
if not all_targets:
all_targets.append(target)
else:
# cf. Theoreme de Pythagore
# Prendre la distance avec le cercle et pas le centre
min_distance = min([(((x - t[0]) ** 2 + (y - t[1]) ** 2) ** 0.5) - max_target_size/2 for t in all_targets])
if min_distance >= min_spacing:
all_targets.append(target)
return all_targets
def save_to_csv(filename, all_targets, density, change_size):
with open(filename, "w", newline='\n') as f:
writer = csv.writer(f)
for target in all_targets[:density]:
as_list = list(target)
as_list[2] = change_size
writer.writerow(as_list)
def create_csv(filename, all_targets, density, change_size):
save_to_csv(filename, all_targets, density, change_size)
def create_all_files(min_spacing):
all_targets = generate_targets(max_density, max_size, min_spacing)
for density in all_density:
for size in all_size:
filename = "src_d_" + str(density) + '_s_' + str(size) + '.csv'
create_csv(DIR_NAME + filename, all_targets, density, size)
if __name__ == '__main__':
create_all_files(SPACING)
from PyQt5.QtWidgets import QApplication, QMainWindow
from experience.ExpSetup import ExpSetup
def main():
app = QApplication([])
window = QMainWindow()
exp_widget = ExpSetup(window)
window.setCentralWidget(exp_widget)
window.show()
app.exec_()
if __name__ == "__main__":
main()
1, 1, 1, 30, 9, BUBBLE, 6032.421827316284, 0
1, 1, 2, 30, 9, BUBBLE, 966.8619632720947, 0
1, 1, 3, 30, 9, BUBBLE, 1031.6030979156494, 0
1, 1, 4, 30, 9, BUBBLE, 964.9369716644287, 0
1, 1, 5, 30, 9, BUBBLE, 1550.239086151123, 0
1, 1, 6, 30, 9, BUBBLE, 683.8860511779785, 0
1, 1, 7, 30, 9, BUBBLE, 1350.4488468170166, 0
1, 1, 8, 30, 9, BUBBLE, 1297.9211807250977, 0
1, 1, 9, 30, 9, BUBBLE, 1032.7260494232178, 0
1, 1, 10, 30, 9, BUBBLE, 1032.9539775848389, 0
1, 1, 11, 30, 9, BUBBLE, 896.4080810546875, 0
1, 1, 12, 30, 9, BUBBLE, 969.0001010894775, 1
1, 1, 13, 30, 9, BUBBLE, 866.1530017852783, 0
1, 1, 14, 30, 9, BUBBLE, 614.9580478668213, 0
1, 1, 15, 30, 9, BUBBLE, 815.1013851165771, 0
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment