Pinceau.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. """pinceau utilise pour la selection et la mise a jour des cases du plateau"""
  2. class Pinceau():
  3. def __init__(self, plateau):
  4. self.plateau = plateau
  5. self._forme = "simple"
  6. self._epaisseur = 1
  7. self._origine = None
  8. self._point2 = None
  9. self._selection = []
  10. self._objetGraphique = None
  11. self._actif = False
  12. def majForme(self, forme):
  13. if forme in ["simple", "ligne", "frontiere", "pot", \
  14. "rectV", "rectP", "ecclipseV", "ecclipseP"]:
  15. self._forme = forme
  16. def majEpaisseur(self, val):
  17. if val in range(1, 5):
  18. self._epaisseur = val
  19. def defOrigine(self, coord):
  20. if self.plateau.coordonneesValides(coord):
  21. self._origine = self.cases[coord].centreGraphique
  22. def defPoint2(self, coord):
  23. if self.plateau.coordonneesValides(coord):
  24. self._point2 = self.cases[coord].centreGraphique
  25. def selection(self):
  26. return self._selection
  27. def demarrer(self, coord):
  28. """commence a peindre a partir de la case choisie comme origine"""
  29. if self.plateau.coordonneesValides(coord):
  30. self._origine = self.cases[coord].centreGraphique
  31. self._point2 = self.cases[coord].centreGraphique
  32. self._actif = True
  33. def maj(self, coord):
  34. """on met a jour la selection en fonction de la case qui vient d'etre ajoutee"""
  35. enPlus = [] #cases a ajouter a la selection
  36. enMoins = [] #cases a retirer de la selection
  37. if self._forme == "simple":
  38. #pas de forme: on ajoute les cases survolees a la liste des cases
  39. zone = self.plateau.zone(coord, self._epaisseur - 1)
  40. for coord in zone:
  41. if not coord in self._selection:
  42. enPlus.append(coord)
  43. elif self._forme == "frontiere":
  44. #droite qui selectionne toutes les cases situees au dessus d'elle
  45. if self._objetGraphique == None:
  46. pinceau = QPen()
  47. pinceau.setColor(QColor("black"))
  48. self._objetGraphique = QGraphicsLineItem()
  49. self._objetGraphique.setPen(pinceau)
  50. self.plateau.addItem(self._objetGraphique)
  51. self._point2 = self.plateau.cases[coord].centreGraphique
  52. ligne = QLineF(self._origine, self._point2)
  53. orientation = int((1+int(ligne.angle()/22.5))/2)
  54. ligne.setAngle(orientation*45)
  55. self._objetGraphique.setLine(ligne)
  56. select = self.selectionFrontiere()
  57. #on met compare avec l'ancienne selection pour minimiser le nombre de cases a maj
  58. for coord in self._selection:
  59. if not coord in select:
  60. enMoins.append(coord)
  61. select.remove(coord)
  62. enPlus = select #toutes les coord qui restent dans select sont a ajouter
  63. else:
  64. if self._forme == "ligne":
  65. #segment simple
  66. if self._objetGraphique == None:
  67. pinceau = QPen()
  68. pinceau.setColor(QColor("black"))
  69. self._objetGraphique = QGraphicsLineItem()
  70. self._objetGraphique.setPen(pinceau)
  71. self._objetGraphique.prepareGeometryChange()
  72. self.plateau.addItem(self._objetGraphique)
  73. self._point2 = self.plateau.cases[coord].centreGraphique
  74. ligne = QLineF(self._origine, self._point2)
  75. self._objetGraphique.setLine(ligne)
  76. elif self._forme == "rectV" or self.modeParam["typeFormeDessin"] == "rectP":
  77. #rectangle
  78. if self.modeParam["formeDessin"] == None:
  79. pinceau = QPen()
  80. pinceau.setColor(QColor("black"))
  81. self._objetGraphique = QGraphicsRectItem()
  82. self._objetGraphique.prepareGeometryChange()
  83. self._objetGraphique.setPen(pinceau)
  84. self.plateau.addItem(self._objetGraphique)
  85. rect = QRectF(QPointF(min(self._origine.x(), self._point2.x()), min(self._origine.y(), self._point2.y())), \
  86. QPointF(max(self._origine.x(), self._point2.x()), max(self._origine.y(), self._point2.y())) )
  87. self._objetGraphique.setRect(rect)
  88. elif self._forme == "ellipseV" or self.modeParam["typeFormeDessin"] == "ellipseP":
  89. #ellipse
  90. if self._objetGraphique == None:
  91. pinceau = QPen()
  92. pinceau.setColor(QColor("black"))
  93. self._objetGraphique = QGraphicsEllipseItem()
  94. self._objetGraphique.prepareGeometryChange()
  95. self._objetGraphique.setPen(pinceau)
  96. self.plateau.addItem(self._objetGraphique)
  97. rect = QRectF(QPointF(min(self._origine.x(), self._point2.x()), min(self._origine.y(), self._point2.y())), \
  98. QPointF(max(self._origine.x(), self._point2.x()), max(self._origine.y(), self._point2.y())) )
  99. self._objetGraphique.setRect(rect)
  100. #on liste les cases intersectant la forme
  101. select = self.casesSousForme(self._objetGraphique, (self._forme[-1:] == "P"), self._epaisseur - 1)
  102. for coord in self._selection:
  103. if not coord in select:
  104. enMoins.append(coord)
  105. select.remove(coord)
  106. enPlus = select
  107. for coord in enPlus:
  108. self.afficherCase(coord, True)
  109. self._selection.append(coord)
  110. for coord in enMoins:
  111. self.afficherCase(coord, False)
  112. self._selection.remove(coord)
  113. def annuler(self):
  114. self.reinit()
  115. def terminer(self):
  116. return self._selection
  117. def reinit(self):
  118. for coord in self_selection:
  119. self.afficherCase(coord, False)
  120. self._origine = (-1, -1)
  121. self._point2 = (-1, -1)
  122. self._selection = []
  123. self._actif = False
  124. def afficherCase(self, coord, actif):
  125. self.plateau.cases[coord].majEstCibleCurseur(actif)
  126. def selectionFrontiere(self):
  127. """retourne les cases selectionnees lors de l'utilisation de la forme 'frontiere'"""
  128. listeCases = []
  129. if self._objetGraphique != None:
  130. ligne = self._objetGraphique.line()
  131. normale = ligne.normalVector()
  132. normale = normale.unitVector()
  133. coordOrigine = self.coordonneesAuPoint(self.modeParam["origineFormeDessin"])
  134. dx = normale.p2().x() - normale.p1().x()
  135. dy = normale.p2().y() - normale.p1().y()
  136. for coord in self.plateau.cases:
  137. if dx < 0 and dy == 0: #normale pointe vers la gauche
  138. if (coord[0] - coordOrigine[0]) <= 0:
  139. listeCases.append(coord)
  140. if dx > 0 and dy == 0: #normale pointe vers la droite
  141. if (coord[0] - coordOrigine[0]) >= 0:
  142. listeCases.append(coord)
  143. if dx == 0 and dy < 0: #pointe vers le haut (rappel: axe y vers le bas)
  144. if (coord[1] - coordOrigine[1]) <= 0:
  145. listeCases.append(coord)
  146. elif dx == 0 and dy > 0: #pointe vers le bas
  147. if (coord[1] - coordOrigine[1]) >= 0:
  148. listeCases.append(coord)
  149. if dx > 0 and dy < 0: #pointe vers le haut droite
  150. if (coord[0] - coordOrigine[0]) + -1*(coord[1] - coordOrigine[1]) >= 0:
  151. listeCases.append(coord)
  152. elif dx > 0 and dy > 0: #pointe vers le bas droite
  153. if -1*(coord[0] - coordOrigine[0]) + -1*(coord[1] - coordOrigine[1]) <= 0:
  154. listeCases.append(coord)
  155. if dx < 0 and dy < 0: #pointe vers le haut gauche
  156. if (coord[0] - coordOrigine[0]) + (coord[1] - coordOrigine[1]) <= 0:
  157. listeCases.append(coord)
  158. elif dx < 0 and dy > 0: #pointe vers le bas gauche
  159. if -1*(coord[0] - coordOrigine[0]) + (coord[1] - coordOrigine[1]) >= 0:
  160. listeCases.append(coord)
  161. return listeCases
  162. def casesSousForme(self, forme, plein = True, epaisseur = 0):
  163. """renvoie la liste des cases en collision avec un QGraphicsItem en parametre
  164. plein = False: pas le contenu de la forme
  165. epaisseur = renvoie aussi les cases voisines jusqu'a la distance demandee"""
  166. tmp = []
  167. listeCases = []
  168. point1 = None
  169. point2 = None
  170. #point 1 et 2
  171. if forme.__class__.__name__ == "QGraphicsLineItem":
  172. point1 = forme.line().p1()
  173. point2 = forme.line().p2()
  174. elif forme.__class__.__name__ == "QGraphicsRectItem" or forme.__class__.__name__ == "QGraphicsEllipseItem":
  175. point1 = forme.rect().topLeft()
  176. point2 = forme.rect().bottomRight()
  177. else:
  178. point1 = forme.boundingRect().topLeft()
  179. point2 = forme.boundingRect().bottomRight()
  180. #preselection des cases (meilleures perf)
  181. if point1 != None and point2 != None and point1 != point2:
  182. preSelection = self.preSelectionCollision(point1, point2)
  183. else:
  184. preSelection = []
  185. for coord in self.cases:
  186. preSelection.append(coord)
  187. #on liste les cases en collision avec la forme
  188. for coord in preSelection:
  189. if self.cases[coord].collidesWithItem(forme, Qt.IntersectsItemShape):
  190. if plein:
  191. tmp.append(coord)
  192. else:
  193. contenu = True
  194. for i in range(0,len(self.cases[coord].polygon())):
  195. if not forme.contains(self.cases[coord].polygon().at(i)):
  196. contenu = False
  197. break
  198. if contenu == False:
  199. tmp.append(coord)
  200. #on applique l'epaisseur du pinceau (lignes ou formes vides seulement) si necessaire
  201. if not plein and epaisseur > 0:
  202. for coord in tmp:
  203. zone = self.zone(coord, epaisseur)
  204. for coord2 in zone:
  205. if not coord2 in listeCases:
  206. listeCases.append(coord2)
  207. else:
  208. listeCases = tmp
  209. #si la liste est vide, on ajoute l'origine de la forme
  210. if len(listeCases) == 0:
  211. listeCases = [self.coordonneesAuPoint(point1)]
  212. return listeCases