From bba5d3b75aefe857d966178ad6bdc51372eea6fc Mon Sep 17 00:00:00 2001 From: Lucas Philippe <lucasphilippe@MacBook-Air-de-Lucas.local> Date: Thu, 1 Feb 2024 13:34:24 +0100 Subject: [PATCH] Ajout TP2 fonctionnel --- TP1/BubbleCursor.py | 3 +- TP1/BubbleWidget.py | 52 ++++--- TP1/MainBubble.py | 6 +- TP1/MainNormal.py | 8 +- TP1/MainRope.py | 4 +- TP1/NormalCursor.py | 21 +-- TP1/NormalWidget.py | 58 +++++--- TP1/README.md | 2 + TP1/RopeWidget.py | 43 +++--- TP1/__init__.py | 0 TP1/__pycache__/BubbleCursor.cpython-39.pyc | Bin 1374 -> 1248 bytes TP1/__pycache__/BubbleWidget.cpython-39.pyc | Bin 1630 -> 2226 bytes TP1/__pycache__/Target.cpython-39.pyc | Bin 930 -> 1169 bytes TP1/experience/ExpSetup.py | 127 ++++++++++++++++++ TP1/experience/Experience.py | 22 +++ TP1/experience/FileDisplayWidget.py | 15 +++ TP1/experience/Generate_targets.py | 52 +++++++ TP1/experience/MainExp.py | 15 +++ TP1/experience/data/__init__.py | 0 TP1/experience/data/response.csv | 15 +++ .../generated_exp/src_d_30_s_12.csv | 30 +++++ .../generated_exp/src_d_30_s_18.csv | 30 +++++ TP1/experience/generated_exp/src_d_30_s_9.csv | 30 +++++ .../generated_exp/src_d_60_s_12.csv | 60 +++++++++ .../generated_exp/src_d_60_s_18.csv | 60 +++++++++ TP1/experience/generated_exp/src_d_60_s_9.csv | 60 +++++++++ .../generated_exp/src_d_90_s_12.csv | 88 ++++++++++++ .../generated_exp/src_d_90_s_18.csv | 88 ++++++++++++ TP1/experience/generated_exp/src_d_90_s_9.csv | 88 ++++++++++++ 29 files changed, 913 insertions(+), 64 deletions(-) create mode 100644 TP1/__init__.py create mode 100644 TP1/experience/ExpSetup.py create mode 100644 TP1/experience/Experience.py create mode 100644 TP1/experience/FileDisplayWidget.py create mode 100644 TP1/experience/Generate_targets.py create mode 100644 TP1/experience/MainExp.py create mode 100644 TP1/experience/data/__init__.py create mode 100644 TP1/experience/data/response.csv create mode 100644 TP1/experience/generated_exp/src_d_30_s_12.csv create mode 100644 TP1/experience/generated_exp/src_d_30_s_18.csv create mode 100644 TP1/experience/generated_exp/src_d_30_s_9.csv create mode 100644 TP1/experience/generated_exp/src_d_60_s_12.csv create mode 100644 TP1/experience/generated_exp/src_d_60_s_18.csv create mode 100644 TP1/experience/generated_exp/src_d_60_s_9.csv create mode 100644 TP1/experience/generated_exp/src_d_90_s_12.csv create mode 100644 TP1/experience/generated_exp/src_d_90_s_18.csv create mode 100644 TP1/experience/generated_exp/src_d_90_s_9.csv diff --git a/TP1/BubbleCursor.py b/TP1/BubbleCursor.py index 49d54c0..d4eed38 100644 --- a/TP1/BubbleCursor.py +++ b/TP1/BubbleCursor.py @@ -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 diff --git a/TP1/BubbleWidget.py b/TP1/BubbleWidget.py index 4b20faf..22f8a86 100644 --- a/TP1/BubbleWidget.py +++ b/TP1/BubbleWidget.py @@ -1,26 +1,36 @@ -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 diff --git a/TP1/MainBubble.py b/TP1/MainBubble.py index 22990ba..bbfdcf3 100644 --- a/TP1/MainBubble.py +++ b/TP1/MainBubble.py @@ -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() diff --git a/TP1/MainNormal.py b/TP1/MainNormal.py index 73a04e5..d932cb9 100644 --- a/TP1/MainNormal.py +++ b/TP1/MainNormal.py @@ -1,13 +1,19 @@ +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() diff --git a/TP1/MainRope.py b/TP1/MainRope.py index e9519fb..dd1c364 100644 --- a/TP1/MainRope.py +++ b/TP1/MainRope.py @@ -1,10 +1,12 @@ 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_() diff --git a/TP1/NormalCursor.py b/TP1/NormalCursor.py index a2339e2..bc38c2d 100644 --- a/TP1/NormalCursor.py +++ b/TP1/NormalCursor.py @@ -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 diff --git a/TP1/NormalWidget.py b/TP1/NormalWidget.py index 9f34fb9..2cbcbe7 100644 --- a/TP1/NormalWidget.py +++ b/TP1/NormalWidget.py @@ -1,26 +1,35 @@ -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 diff --git a/TP1/README.md b/TP1/README.md index e69de29..1087c3c 100644 --- a/TP1/README.md +++ b/TP1/README.md @@ -0,0 +1,2 @@ +# Programmation d'une technique d'interaction : le Bubble Cursor + diff --git a/TP1/RopeWidget.py b/TP1/RopeWidget.py index 2aafc7a..93bb765 100644 --- a/TP1/RopeWidget.py +++ b/TP1/RopeWidget.py @@ -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 diff --git a/TP1/__init__.py b/TP1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/TP1/__pycache__/BubbleCursor.cpython-39.pyc b/TP1/__pycache__/BubbleCursor.cpython-39.pyc index 4d49281a3a479273257899a9b740c614c215d99e..e3cc227bd4c22cca27fc49eff4e11c2714483ea4 100644 GIT binary patch delta 586 zcmY*W%W4!s6s=pY>3L*~MB`vU6a*PCu5_tFMkNcGjjjUH^rUJsoph$Psyd3+FpFfF zg`t1I?6S>I#DD08WGAi#*WPLq(Q59kbGq*1+^TP_^JX_$SZEPkKYyL*ul%T+!u_KU ztG!pG->f=o#b}i2L1AoeDn7~zeR|e}d4%x;H2V^rhcCpFZ8!!9m^y}xqlq5bhnmU% zm{4%-^5g;^b0CUfPdfZTv1Y$fMOM2tQ`kw>QhJ;enH%I;)mA2XUp}D?QL%LD%IEYE zbjnY3b>6@<j#lgXT<h{ACZ3`PM-}YDEGT2Mpp8ExZ-z60h<LG0dPLEsdJ1Ilhut8G zEs>e@68{NBS1_t(Y=@YMmskz+W9G4HEavZS`%sweFmvd+IZ)j5SgO#1;U0#Q!ytNW zuAsUtG+gITU%c)&j6`U{1eF+PdE!iX64MMW+;!ESq+62=&1r?<?QrlnXQQ*5PFG@; zT9-^W^~T~`qxaIhu<>S=TWwuguzQaeF~{CQM?m5ifut?C3tdD!aAaZsc=g{mf3TbH f>0v)APxwQ5J#@WUe&=^OK~#h}k&Jk`EY^Pm1;U0d delta 684 zcmY*VPiqrF6n}4KcC))_QcH`eijbmE_E15no&>@4;AugULk-BX$xK7ibQfngB4tAk z6+D-{c(eHk-n{q``~rKB9=!Mwy!mEhYn|b}`Mo#q@9)z6;WeX1!vi`$zkXJ~`FV4U z`{(cXcBK0O`i}Iv;MdEw7qh`&syZ{BCc3mnTB-QUHy67#O6-uN&q(EX0Xa-?iD)n* z%t^$y@mkkNNZc}>>Rk#13DkrIzZli<?ZRgdidXCjHj0mIZ();DkW^g`t1dZ&kW=*# zCDjR8#wDKNyy|rTZ`yN_!-bWLCC;tf%K0(qc5cx>`9t=$O}&|f8S0)iGqTXGCg4HI z$MI3muW8d%o85F^xGAlpX%c1HHTaesr&$yaRWIp9dZe<_$&#*`s$u5ax=tZ|>m+%n z4p-0Xe*I(|AN<WJzVqG12F0YeNdel`b(n`9Iw;Vf(~X;KKQgt3hMKFx30yPslnmN| z_@2NvNZd3Ql7%a)1(I#ToMns{!wE5UZ$W`)NR;zHuT%PHRrvC`Fa9lF@@SB1hrWDX zEv4@e?l-TN@2EJ_O0SV~r5XmcNVQ2)GaukXJiY(lE>(8(26ut)7LUb#eT%~NU87pX VvDj%E)*WKQsX4+~FFuKve*htAl2`x$ diff --git a/TP1/__pycache__/BubbleWidget.cpython-39.pyc b/TP1/__pycache__/BubbleWidget.cpython-39.pyc index 3e9ebd96cf92dcab43c8065bb5482a9f7eccc59e..3f7d594363ce5f597ab00b02311700104235408b 100644 GIT binary patch literal 2226 zcmZ`)OK%)S5bo}I?yg?}6P#cv5${FBiz9K1P#~ZX30rn-6frUyji=l8*s~9J_d0kr zds?HM5PxBP^k3>L7xEW4AgX$HogGKaXsWAU(^X%6Rh`Vw*9koTvMXUcLjJ<e?Bhb` zF??zd1Sg#4Br01PQQKz`gO=q^+l^d`b58EH{m8evn+NS63aswsVLOaMN}dw#^WcK; zK=>mks&TqQn&E3WfowLZ3AeYBtfPelJ=lJc@k60O^>-6lYIEQ9_xE%0q%T!hrnqhP zaV8!06DWe9nGt(M4k)LbU4)Ut9qwL`$mJgQq4jvcLuh?o<8^2Q-r#f4hJ2ncKwEo7 zToTp6#6>eXxwI*zGsmKiC*!9cgV1C|#`Ka<a!3jivx1Br>}j_k$81Dl%!4tX(@To* zKtF(fh-*06Ay;g3w^=iu>i2{+VH{_jOvkYaw1q*LM&3<$iHVXBJ7WCQA`&erp*OmH zC3a<!o@AXvQ&+G{$2w~Z^Ntd^NcHoi!@KQr{}nYZj2=K+i{ms;l#1gk^3S)epOuiR zmG{#`^^USU>-9uyW4*QWu=VWOj~lJ&*n=!PYPWW`)>~z0N`TgS=duQdh485b5QNsL zPeVFq+rfL4#ZwO}um+RuPw*E72n`(Mj5~j@Klg@I(=jUmz#%Kx_vF_{Lq|J>Gosu* z@#Ly@wO2U6NcVSkhm6>sGjxaE(1!r{<3NXnTX+R95Cd?!`T}5g;T<`Ybe7hM>U;&E z!1tF)NSfZ};FgkUtb6gkrQlks&I|!^1|9J-&pP5Y#vj7wc6*{@9Gv#0NH~Ph$#JBe z^o#@SmY8?OPXN#kmzZYFKrTTO1+eKL%Z0p)Jx6w58v2`|=MbW7AmqC+T8d@V8X#`L zr{+Kqx&X)`zAJRFQbBiyEGfgKlLt@6&jP##iUuZ*5KwZA;4%aUbO+#F7y`J{vD3Sj zrF66DO8lWj10t`7scW5sarDP{;!JdO6xbQS!7mAX!x2-r^FQF)JFrb5X~={tgZC@G zyjfXs1+Bn5u&#Uv3YZNkSb!Us1SF*2B|~S%?lj3HE^B(F?QXk!CgeRBk@rCuzu)7D z7FW#rAwR;2D*9%jjcK+4`>f%(S0S2&-ll^ODn?gVR!EM9BX6wX4?#i0IXPi+83+zF z1Zo4(Z0x|e3uK2%R?xC~Tswk^0t}jm#<(`meQ7g1^3$VkmI@n_DAe5@oBr}s+%R$N zW6*E7CNW>pWo0i2pj91c<<r5vidS#fl8R^3s%SmC4}a5S>d`S<fmB`wu1%^RTq96p z*=F`PV9|7p*ON%4ChW3q$wky|1fXUY?LuAq0%qS}f4gGk^`f`<g3w<Zhp;2*FNs{8 zmh1mzOOWPWC6taDX`ZDgahk!EB)>!(5jy!9iW}B0S`utYp_Jtd=9}_C5WqI1gVl=F zHx@S=cnfrrwt!op9>?u2@8_t`#qnuB$;%mAaBWqPpP&Vwqp${9(;h(A%ui~3D)Kyz zXN<%`B5hegqmWXzY(qh*g<<H2ZWx5F#JOf&VwOro-G<0Cw$8Wp*K6DQX+N_C!7NTk m%G*Fmh%2$B&R$pcKQo70tnhFXJ}Q0t2I*t@w*vUsm;DF5{_&jv delta 797 zcmZ8f!EO^V5cPPy>rF_~f<zRF3L+su%cUFw7b?U7R1Sd)MZiiZTE#93+D(GJ2~cg- zLlB&!{Q$BYkhpMwPe6iy@S)$r*lkt7E6>innXzZy`1{$zMk{GH>jc;5U!P=$En6G? zK3akZNJ(t}G=+@D6s+#0UdCePbe8&=ANx-C(;y4t0LV5Gf#C0n;F2x8m@hv(h2HXT zv;L7V67$C-s+F5?sZQ|@54Y}>&)`~Hkb(>X0Vug37)2lLL}6LM&2~-aiOP3InT%_@ zBc=0)levt_kjCv053pM|P!Om?03kGf>`{Pz4G|M0)2SQ_#n6bjvSBeF>iO;{m8xwm zPfgw!cx&LDVS2PD)f%ElV%=(%n)ULx_u$|bYB{p903bOQx`2IJkXQ5`dC}VU3UB2V zv_jwOHlpmrI&Nlm4zs7pXq?}l%W>Ydb)`SQM!xZ<3Q=YGP_Aa*g{d<LM9h_Jd^wkQ z$GPFoC6x(~l9w|7uUJz*y`h8Y+RYUy36Yvc`Gxfkt|NTX1eOUaTENPy2ufCw3Wr>f zm0uA%R5yj0WhtA?w6wJUTYR7{qSIAsScYzO!P*-rOfZ{@B$p9&9jLB#tPyPRnA>v8 z@9+Ro0%7^w?^2xhH-6=b9j7B*UAEd)6s9>C4AVsGp-j`k;IF2eHpGp|p2Tr$_avYZ m;^NApQK-(B+u`jSr-OBxO*7$EHW9N_-T|9y>B9GO^wB@;_@=c0 diff --git a/TP1/__pycache__/Target.cpython-39.pyc b/TP1/__pycache__/Target.cpython-39.pyc index 23ca47c2f5451c35bafb6733925f0380401c87fa..947e9a63a4839aed0cd1353eae11b904ae83af75 100644 GIT binary patch literal 1169 zcmZWoO>fgc5ZzsW#EG3ys)CT<fH)xeK&>KiqCyoFEj=_!lydRKa=qKe#ra_Eh$c!; z?GI^h@Rxk$)IY$16K|ZPieRmMvpX}Ioq02ko6QEpy8Qh^bqvOS(Pe!>$M&%E*8s^R z&)9&6d>}$GFhYZ~LnehZZkRN#MQBR1$9(G^zRWjDySqQiMjG;?p5*<~>~_>JA>;ZI zxa?u)y8y*PE?Fp)A^9~AO-KQ0K^l;@G^KUJ!kV;Y4bqX0tV7mi0}s2UeG=<)RfN{L zR%#d;TFKBn%_b@_5q!1iOt0=^=dS>BK4%e|3m~5xKp{zk9Dt@|h%MR&zE$$el21!B zPiLxhicwExDk)00pPu(K>_SQ3gjr>0+D2SmBX9senf4(5ybr$QO6Nf~N#cCmPqTD9 zR>AR3(0dyk9eq9yR=PK7+8+cbot<D&()M^-I#HAk(;|xM2$ffj<M#5KJzDy$d=jc~ zwWy7hOI7h4hdH}oSE%=b>n)(T5<?Ht&@X`|Ed16g>^Zo<;~f0l)(U6sRxcXxbFn?i zpR;G|npc|Ue;RLTfxI(0MyTTQo|5xhWkag7c#;*E6HP^x?ut~>P=%%UKrU3FldGZ{ zCQT)UHm;Z{O&twgspIdTGEkbU(nyEJq6b8O)d=6vE=8=3V;GeVt%Sz2YRm$fWVR~v z297xa<F>H5Lo|yPZ}FM8Y6wM1IJqnroge0E3m34#^hPyB_)U8FeNes8J~;7tRW1Z& z^lt`klBLPlC`nH<^#b;sN<bd?Og`IOzQ5+w_8T-D!+4;gsBA>hU?e9QoxLdfHi@%^ zMN@K`iqe||j|o}?PY9k8(3GwLF`_L1F`Sdp0T=j$Q**q^(#C(`cBb9p-FCM)oTQ6a cs6AC%DxbB8)dLmL&h8@355!wexosJL0Wc-^hX4Qo delta 575 zcmZutJxc>Y5Z&2Ja(Bs@K(G)Lv9R!(XrY~m7$jg33`up}kzJF><%78kq6AWCVIe}u z5AdV&AK2O3*xx_!UpTV{RB(^?cHY~Wxt*Q4&vr3fTFMJrt+xk#D`&;E`Z_5k6hxvA z0f49pC6#p}lyxlwsWMIBXFs{bhcwry4x=HqS^i#<#33Qxo!#$og**GWD`&{TEK`o? zMPPp3hZAt-udp-a61J;^SP@OcxxnQKJOV}XiEc93pvc0lg_kj&w@_JD6z3?%CO8UK z#R_+E|0svmQwC^8x|ghf@{j%e6m8lAC)UXkj^l1xNQO-v>2^XBqC;n?*X?z>5rM5V zuk=|sjyMhq3d4)zDC&)3jb=)o#Ej}obh+3bg}p(d5&5;hsla~L_$9GPQ+s3x$U%`I zJ-G5(A$D|9F*$YLoxfY#(-Jo*GI2hZnSPp@h&!W2#E98)z<koNjbHbzv~YUaNcJj? dq&Ds$KY}^=uT|>o_lIg6=>wonBIaaIegVMjaJ>Kk diff --git a/TP1/experience/ExpSetup.py b/TP1/experience/ExpSetup.py new file mode 100644 index 0000000..0ea14e7 --- /dev/null +++ b/TP1/experience/ExpSetup.py @@ -0,0 +1,127 @@ +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) diff --git a/TP1/experience/Experience.py b/TP1/experience/Experience.py new file mode 100644 index 0000000..ea34303 --- /dev/null +++ b/TP1/experience/Experience.py @@ -0,0 +1,22 @@ +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 diff --git a/TP1/experience/FileDisplayWidget.py b/TP1/experience/FileDisplayWidget.py new file mode 100644 index 0000000..c71af36 --- /dev/null +++ b/TP1/experience/FileDisplayWidget.py @@ -0,0 +1,15 @@ +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()) diff --git a/TP1/experience/Generate_targets.py b/TP1/experience/Generate_targets.py new file mode 100644 index 0000000..f0bc38c --- /dev/null +++ b/TP1/experience/Generate_targets.py @@ -0,0 +1,52 @@ +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) diff --git a/TP1/experience/MainExp.py b/TP1/experience/MainExp.py new file mode 100644 index 0000000..e68cc72 --- /dev/null +++ b/TP1/experience/MainExp.py @@ -0,0 +1,15 @@ +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() diff --git a/TP1/experience/data/__init__.py b/TP1/experience/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/TP1/experience/data/response.csv b/TP1/experience/data/response.csv new file mode 100644 index 0000000..0d3c21c --- /dev/null +++ b/TP1/experience/data/response.csv @@ -0,0 +1,15 @@ +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 diff --git a/TP1/experience/generated_exp/src_d_30_s_12.csv b/TP1/experience/generated_exp/src_d_30_s_12.csv new file mode 100644 index 0000000..32d9f17 --- /dev/null +++ b/TP1/experience/generated_exp/src_d_30_s_12.csv @@ -0,0 +1,30 @@ +666,638,12 +1,172,12 +864,57,12 +8,125,12 +162,369,12 +796,19,12 +677,424,12 +312,9,12 +558,732,12 +674,128,12 +973,467,12 +592,150,12 +245,148,12 +425,561,12 +687,794,12 +14,652,12 +607,52,12 +295,440,12 +571,375,12 +769,588,12 +412,625,12 +857,611,12 +191,673,12 +648,702,12 +445,344,12 +218,338,12 +951,523,12 +542,229,12 +851,671,12 +518,383,12 diff --git a/TP1/experience/generated_exp/src_d_30_s_18.csv b/TP1/experience/generated_exp/src_d_30_s_18.csv new file mode 100644 index 0000000..3d90b12 --- /dev/null +++ b/TP1/experience/generated_exp/src_d_30_s_18.csv @@ -0,0 +1,30 @@ +666,638,18 +1,172,18 +864,57,18 +8,125,18 +162,369,18 +796,19,18 +677,424,18 +312,9,18 +558,732,18 +674,128,18 +973,467,18 +592,150,18 +245,148,18 +425,561,18 +687,794,18 +14,652,18 +607,52,18 +295,440,18 +571,375,18 +769,588,18 +412,625,18 +857,611,18 +191,673,18 +648,702,18 +445,344,18 +218,338,18 +951,523,18 +542,229,18 +851,671,18 +518,383,18 diff --git a/TP1/experience/generated_exp/src_d_30_s_9.csv b/TP1/experience/generated_exp/src_d_30_s_9.csv new file mode 100644 index 0000000..7b530a4 --- /dev/null +++ b/TP1/experience/generated_exp/src_d_30_s_9.csv @@ -0,0 +1,30 @@ +666,638,9 +1,172,9 +864,57,9 +8,125,9 +162,369,9 +796,19,9 +677,424,9 +312,9,9 +558,732,9 +674,128,9 +973,467,9 +592,150,9 +245,148,9 +425,561,9 +687,794,9 +14,652,9 +607,52,9 +295,440,9 +571,375,9 +769,588,9 +412,625,9 +857,611,9 +191,673,9 +648,702,9 +445,344,9 +218,338,9 +951,523,9 +542,229,9 +851,671,9 +518,383,9 diff --git a/TP1/experience/generated_exp/src_d_60_s_12.csv b/TP1/experience/generated_exp/src_d_60_s_12.csv new file mode 100644 index 0000000..2e1da25 --- /dev/null +++ b/TP1/experience/generated_exp/src_d_60_s_12.csv @@ -0,0 +1,60 @@ +666,638,12 +1,172,12 +864,57,12 +8,125,12 +162,369,12 +796,19,12 +677,424,12 +312,9,12 +558,732,12 +674,128,12 +973,467,12 +592,150,12 +245,148,12 +425,561,12 +687,794,12 +14,652,12 +607,52,12 +295,440,12 +571,375,12 +769,588,12 +412,625,12 +857,611,12 +191,673,12 +648,702,12 +445,344,12 +218,338,12 +951,523,12 +542,229,12 +851,671,12 +518,383,12 +670,3,12 +304,665,12 +562,112,12 +198,128,12 +363,337,12 +583,344,12 +168,558,12 +715,629,12 +697,660,12 +435,149,12 +239,82,12 +46,69,12 +380,685,12 +964,5,12 +620,136,12 +351,471,12 +528,536,12 +501,75,12 +910,317,12 +223,724,12 +563,641,12 +791,244,12 +987,77,12 +907,244,12 +22,538,12 +782,353,12 +235,793,12 +751,447,12 +515,258,12 +418,538,12 diff --git a/TP1/experience/generated_exp/src_d_60_s_18.csv b/TP1/experience/generated_exp/src_d_60_s_18.csv new file mode 100644 index 0000000..fc9e4bf --- /dev/null +++ b/TP1/experience/generated_exp/src_d_60_s_18.csv @@ -0,0 +1,60 @@ +666,638,18 +1,172,18 +864,57,18 +8,125,18 +162,369,18 +796,19,18 +677,424,18 +312,9,18 +558,732,18 +674,128,18 +973,467,18 +592,150,18 +245,148,18 +425,561,18 +687,794,18 +14,652,18 +607,52,18 +295,440,18 +571,375,18 +769,588,18 +412,625,18 +857,611,18 +191,673,18 +648,702,18 +445,344,18 +218,338,18 +951,523,18 +542,229,18 +851,671,18 +518,383,18 +670,3,18 +304,665,18 +562,112,18 +198,128,18 +363,337,18 +583,344,18 +168,558,18 +715,629,18 +697,660,18 +435,149,18 +239,82,18 +46,69,18 +380,685,18 +964,5,18 +620,136,18 +351,471,18 +528,536,18 +501,75,18 +910,317,18 +223,724,18 +563,641,18 +791,244,18 +987,77,18 +907,244,18 +22,538,18 +782,353,18 +235,793,18 +751,447,18 +515,258,18 +418,538,18 diff --git a/TP1/experience/generated_exp/src_d_60_s_9.csv b/TP1/experience/generated_exp/src_d_60_s_9.csv new file mode 100644 index 0000000..1052f3e --- /dev/null +++ b/TP1/experience/generated_exp/src_d_60_s_9.csv @@ -0,0 +1,60 @@ +666,638,9 +1,172,9 +864,57,9 +8,125,9 +162,369,9 +796,19,9 +677,424,9 +312,9,9 +558,732,9 +674,128,9 +973,467,9 +592,150,9 +245,148,9 +425,561,9 +687,794,9 +14,652,9 +607,52,9 +295,440,9 +571,375,9 +769,588,9 +412,625,9 +857,611,9 +191,673,9 +648,702,9 +445,344,9 +218,338,9 +951,523,9 +542,229,9 +851,671,9 +518,383,9 +670,3,9 +304,665,9 +562,112,9 +198,128,9 +363,337,9 +583,344,9 +168,558,9 +715,629,9 +697,660,9 +435,149,9 +239,82,9 +46,69,9 +380,685,9 +964,5,9 +620,136,9 +351,471,9 +528,536,9 +501,75,9 +910,317,9 +223,724,9 +563,641,9 +791,244,9 +987,77,9 +907,244,9 +22,538,9 +782,353,9 +235,793,9 +751,447,9 +515,258,9 +418,538,9 diff --git a/TP1/experience/generated_exp/src_d_90_s_12.csv b/TP1/experience/generated_exp/src_d_90_s_12.csv new file mode 100644 index 0000000..4633449 --- /dev/null +++ b/TP1/experience/generated_exp/src_d_90_s_12.csv @@ -0,0 +1,88 @@ +666,638,12 +1,172,12 +864,57,12 +8,125,12 +162,369,12 +796,19,12 +677,424,12 +312,9,12 +558,732,12 +674,128,12 +973,467,12 +592,150,12 +245,148,12 +425,561,12 +687,794,12 +14,652,12 +607,52,12 +295,440,12 +571,375,12 +769,588,12 +412,625,12 +857,611,12 +191,673,12 +648,702,12 +445,344,12 +218,338,12 +951,523,12 +542,229,12 +851,671,12 +518,383,12 +670,3,12 +304,665,12 +562,112,12 +198,128,12 +363,337,12 +583,344,12 +168,558,12 +715,629,12 +697,660,12 +435,149,12 +239,82,12 +46,69,12 +380,685,12 +964,5,12 +620,136,12 +351,471,12 +528,536,12 +501,75,12 +910,317,12 +223,724,12 +563,641,12 +791,244,12 +987,77,12 +907,244,12 +22,538,12 +782,353,12 +235,793,12 +751,447,12 +515,258,12 +418,538,12 +643,468,12 +471,327,12 +789,481,12 +48,420,12 +364,625,12 +296,629,12 +201,320,12 +159,3,12 +414,168,12 +873,230,12 +481,633,12 +357,702,12 +815,292,12 +393,674,12 +411,435,12 +646,90,12 +439,101,12 +691,187,12 +101,627,12 +411,597,12 +671,381,12 +977,516,12 +302,562,12 +383,285,12 +109,253,12 +37,337,12 +826,741,12 +583,91,12 diff --git a/TP1/experience/generated_exp/src_d_90_s_18.csv b/TP1/experience/generated_exp/src_d_90_s_18.csv new file mode 100644 index 0000000..81c233b --- /dev/null +++ b/TP1/experience/generated_exp/src_d_90_s_18.csv @@ -0,0 +1,88 @@ +666,638,18 +1,172,18 +864,57,18 +8,125,18 +162,369,18 +796,19,18 +677,424,18 +312,9,18 +558,732,18 +674,128,18 +973,467,18 +592,150,18 +245,148,18 +425,561,18 +687,794,18 +14,652,18 +607,52,18 +295,440,18 +571,375,18 +769,588,18 +412,625,18 +857,611,18 +191,673,18 +648,702,18 +445,344,18 +218,338,18 +951,523,18 +542,229,18 +851,671,18 +518,383,18 +670,3,18 +304,665,18 +562,112,18 +198,128,18 +363,337,18 +583,344,18 +168,558,18 +715,629,18 +697,660,18 +435,149,18 +239,82,18 +46,69,18 +380,685,18 +964,5,18 +620,136,18 +351,471,18 +528,536,18 +501,75,18 +910,317,18 +223,724,18 +563,641,18 +791,244,18 +987,77,18 +907,244,18 +22,538,18 +782,353,18 +235,793,18 +751,447,18 +515,258,18 +418,538,18 +643,468,18 +471,327,18 +789,481,18 +48,420,18 +364,625,18 +296,629,18 +201,320,18 +159,3,18 +414,168,18 +873,230,18 +481,633,18 +357,702,18 +815,292,18 +393,674,18 +411,435,18 +646,90,18 +439,101,18 +691,187,18 +101,627,18 +411,597,18 +671,381,18 +977,516,18 +302,562,18 +383,285,18 +109,253,18 +37,337,18 +826,741,18 +583,91,18 diff --git a/TP1/experience/generated_exp/src_d_90_s_9.csv b/TP1/experience/generated_exp/src_d_90_s_9.csv new file mode 100644 index 0000000..76a475e --- /dev/null +++ b/TP1/experience/generated_exp/src_d_90_s_9.csv @@ -0,0 +1,88 @@ +666,638,9 +1,172,9 +864,57,9 +8,125,9 +162,369,9 +796,19,9 +677,424,9 +312,9,9 +558,732,9 +674,128,9 +973,467,9 +592,150,9 +245,148,9 +425,561,9 +687,794,9 +14,652,9 +607,52,9 +295,440,9 +571,375,9 +769,588,9 +412,625,9 +857,611,9 +191,673,9 +648,702,9 +445,344,9 +218,338,9 +951,523,9 +542,229,9 +851,671,9 +518,383,9 +670,3,9 +304,665,9 +562,112,9 +198,128,9 +363,337,9 +583,344,9 +168,558,9 +715,629,9 +697,660,9 +435,149,9 +239,82,9 +46,69,9 +380,685,9 +964,5,9 +620,136,9 +351,471,9 +528,536,9 +501,75,9 +910,317,9 +223,724,9 +563,641,9 +791,244,9 +987,77,9 +907,244,9 +22,538,9 +782,353,9 +235,793,9 +751,447,9 +515,258,9 +418,538,9 +643,468,9 +471,327,9 +789,481,9 +48,420,9 +364,625,9 +296,629,9 +201,320,9 +159,3,9 +414,168,9 +873,230,9 +481,633,9 +357,702,9 +815,292,9 +393,674,9 +411,435,9 +646,90,9 +439,101,9 +691,187,9 +101,627,9 +411,597,9 +671,381,9 +977,516,9 +302,562,9 +383,285,9 +109,253,9 +37,337,9 +826,741,9 +583,91,9 -- GitLab