br.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. """Algorithme de Bresenham"""
  2. from __future__ import division
  3. from math import *
  4. from dmF import *
  5. def ligne(coord1, coord2, formeCases = "H"):
  6. if coord1[0] != coord2[0] or coord1[1] != coord2[1]:
  7. if len(coord1) == 2 and len(coord2) == 2:
  8. retour = _ligne2d(coord1, coord2, formeCases)
  9. elif len(coord1) == 3 and len(coord2) == 3:
  10. retour = _ligne3d(coord1, coord2, formeCases)
  11. elif len(coord1) == 2 and len(coord2) == 3:
  12. x1, y1 = coord1
  13. retour = _ligne3d((x1, y1, 0), coord2, formeCases)
  14. elif len(coord1) == 2 and len(coord2) == 3:
  15. x2, y2 = coord2
  16. retour = _ligne3d(coord1, (x2, y2, 0), formeCases)
  17. else:
  18. retour = [coord1]
  19. else:
  20. retour = [coord1]
  21. return retour
  22. def _ligne2d(coord1, coord2, formeCases = "H"):
  23. """renvoie la liste des cases traversees par la ligne entre les cases 1 et 2
  24. prend en parametre des coord de la forme (x,y)"""
  25. x1, y1 = coord1
  26. x2, y2 = coord2
  27. # on inverse les coord si necessaire (si on va de gauche a droite)
  28. inversee = False
  29. if x1 > x2:
  30. x1, x2 = x2, x1
  31. y1, y2 = y2, y1
  32. inversee = True
  33. if formeCases == "H":
  34. retour = _brH(x1, y1, x2, y2)
  35. else:
  36. retour = _brC(x1, y1, x2, y2)
  37. # retourne la liste si les coordonnees ont ete interverties
  38. if inversee:
  39. retour.reverse()
  40. return retour
  41. def _ligne3d(coord1, coord2, formeCases = "H"):
  42. """renvoie la liste des cases traversees par la ligne entre les cases 1 et 2
  43. prend en parametre des coord de la forme (x,y, z)"""
  44. x1, y1, z1 = coord1
  45. x2, y2, z2 = coord2
  46. ligne = _ligne2d((x1, y1), (x2, y2), formeCases)
  47. ligneZ = _brC(0, z1, (len(ligne)-1), z2)
  48. retour = []
  49. for coordZ in ligneZ:
  50. dist, z = coordZ
  51. x, y = ligne[dist]
  52. retour.append((x, y, z))
  53. return retour
  54. def _brC(x1, y1, x2, y2):
  55. """Algorithme ligne de Bresenham (pour cases carrees)"""
  56. # on verifie si la ligne est plus verticale qu'horizontale
  57. estVerticale = abs(y2 - y1) > abs(x2 - x1)
  58. if estVerticale:
  59. x1, y1 = y1, x1
  60. x2, y2 = y2, x2
  61. # Calcul des ecarts
  62. dx = x2 - x1
  63. dy = y2 - y1
  64. # Calcul de l'erreur (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
  65. #2dx est l'unite, de maniere a travailler avec des entiers
  66. error = 0.0
  67. pasY = 1 if y1 < y2 else -1
  68. # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
  69. y = y1
  70. retour = []
  71. for x in range(x1, x2 + 1):
  72. coord = (y, x) if estVerticale else (x, y)
  73. retour.append(coord)
  74. error += (abs(dy) / dx)
  75. if error > 0.5:
  76. y += pasY
  77. error -= 1.0
  78. return retour
  79. def _brH(x1, y1, x2, y2):
  80. """Algorithme ligne de Bresenham (pour cases hexagonales)"""
  81. #calcul selon secteur
  82. if abs(x2 - x1) < (2*abs((y2-y1)) + abs(x2 % 2) - abs(x1 % 1)):
  83. retour = _brH_v(x1, y1, x2, y2)
  84. else:
  85. retour = _brH_h(x1, y1, x2, y2)
  86. return retour
  87. def _brH_h(x1, y1, x2, y2):
  88. """Algorithme ligne de Bresenham (pour cases hexagonales - secteur horizontal)"""
  89. # Calcul des ecarts
  90. dx = x2 - x1
  91. dy = y2 - y1
  92. if (x1 + x2) % 2 == 1:
  93. if x1 % 2 == 0:
  94. dy += 0.5
  95. else:
  96. dy -= 0.5
  97. # Calcul de l'erreur (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
  98. k = dy / dx
  99. pas = 1
  100. # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
  101. retour = []
  102. d = 0.0
  103. pos = (x1, y1)
  104. retour.append(pos)
  105. while pos != (x2, y2):
  106. d += k*pas
  107. if d > 0:
  108. #on se deplace vers la case en dessous a droite
  109. x, y = pos
  110. if x %2 == 0:
  111. pos = x + 1, y
  112. else:
  113. pos = x + 1, y + 1
  114. retour.append(pos)
  115. d -= 0.5
  116. else:
  117. #on se deplace vers la case au dessus a droite
  118. x, y = pos
  119. if x %2 == 0:
  120. pos = x + 1, y - 1
  121. else:
  122. pos = x + 1, y
  123. retour.append(pos)
  124. d += 0.5
  125. if pos[0] > x2:
  126. retour = []
  127. break
  128. return retour
  129. def _brH_v(x1, y1, x2, y2):
  130. """Algorithme ligne de Bresenham (pour cases hexagonales - secteur vertical)"""
  131. #on prend comme unite la demi largeur: u = 0.5773
  132. #la demi hauteur d'un hexa vaut donc 0.8860u, ou sqrt(3)/2
  133. #[a revoir] une fois cela pose, on muliplie tout par 4dy afin d'eviter nombres flottants et divisions
  134. sens = 1 if y2 > y1 else -1
  135. # Calcul des ecarts
  136. dx = 1.5 * (x2 - x1) #en x, on a 1.5u de centre a centre
  137. dy = sens * (y2 - y1) #en y, on compte en demi hauteurs
  138. if (x1 + x2) % 2 == 1:
  139. if x1 % 2 == 0:
  140. dy += sens*0.5
  141. else:
  142. dy -= sens*0.5
  143. k = dx/(dy*sqrt(3)) #k est la tangente de l'angle par rapport a la verticale
  144. pas = 0.5*sqrt(3) #on avance par demi hauteurs
  145. retour = []
  146. d = 0.0 #decalage
  147. pos = (x1, y1)
  148. retour.append(pos)
  149. while pos != (x2, y2):
  150. d += (k*pas)
  151. if d <= 0.5:
  152. #on se deplace vers la case en dessous (ou au dessus)
  153. x, y = pos
  154. pos = x, y + sens
  155. retour.append(pos)
  156. d += (k*pas)
  157. else:
  158. #on se deplace vers la case en dessous (ou au dessus) a droite
  159. x, y = pos
  160. if (x %2 == 0 and sens == 1) or (x % 2 == 1 and sens == -1):
  161. pos = x + 1, y
  162. else:
  163. pos = x + 1, y + sens
  164. retour.append(pos)
  165. d -= 1.5
  166. if sens*pos[1] > sens*y2:
  167. retour = []
  168. break
  169. return retour