Pinceau.py 11 KB

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