Pinceau.py 12 KB

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