br.py 6.1 KB

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