bresenham.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. """Algorithme de Bresenham"""
  2. from __future__ import division
  3. from math import *
  4. from dmF import *
  5. dbg = True
  6. def casesEntre(coord1, coord2, formeCases = "H"):
  7. x1, y1 = coord1
  8. x2, y2 = coord2
  9. # on inverse les coord si necessaire (si on va de gauche a droite)
  10. inversee = False
  11. if x1 > x2:
  12. x1, x2 = x2, x1
  13. y1, y2 = y2, y1
  14. inversee = True
  15. if coord1 != coord2:
  16. if formeCases == "H":
  17. retour = _brH(x1, y1, x2, y2)
  18. else:
  19. retour = _brC(x1, y1, x2, y2)
  20. else:
  21. retour = [coord1]
  22. # retourne la liste si les coordonnees ont ete interverties
  23. if inversee:
  24. retour.reverse()
  25. return retour
  26. def _brC(x1, y1, x2, y2):
  27. """Algorithme ligne de Bresenham (pour cases carrees)"""
  28. # on verifie si la ligne est plus verticale qu'horizontale
  29. estVerticale = abs(y2 - y1) > abs(x2 - x1)
  30. if estVerticale:
  31. x1, y1 = y1, x1
  32. x2, y2 = y2, x2
  33. # Calcul des ecarts
  34. dx = x2 - x1
  35. dy = y2 - y1
  36. # Calcul de l'erreur (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
  37. #2dx est l'unite, de maniere a travailler avec des entiers
  38. error = 0.0
  39. pasY = 1 if y1 < y2 else -1
  40. # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
  41. y = y1
  42. retour = []
  43. for x in range(x1, x2 + 1):
  44. coord = (y, x) if estVerticale else (x, y)
  45. retour.append(coord)
  46. error += (abs(dy) / dx)
  47. if error > 0.5:
  48. y += pasY
  49. error -= 1.0
  50. return retour
  51. def _brH(x1, y1, x2, y2):
  52. """Algorithme ligne de Bresenham (pour cases hexagonales)"""
  53. #calcul selon secteur
  54. if abs(x2 - x1) < (2*(y2-y1) + abs(x2 % 2) - abs(x1 % 1)):
  55. if dbg: print "*** V"
  56. retour = _brH_v(x1, y1, x2, y2)
  57. else:
  58. if dbg: print "*** H"
  59. retour = _brH_h(x1, y1, x2, y2)
  60. return retour
  61. def _brH_h(x1, y1, x2, y2):
  62. """Algorithme ligne de Bresenham (pour cases hexagonales - secteur horizontal)"""
  63. # Calcul des ecarts
  64. dx = x2 - x1
  65. dy = y2 - y1
  66. # Calcul de l'erreur (l'ecart qui doit s'accumuler au fur et a mesure qu'on avance)
  67. error = 0.0
  68. pasY = 1 if y1 < y2 else -1
  69. if dbg: print "# de: {}|{} vers {}|{}".format(x1, y1, x2, y2)
  70. # on itere sur les coordonnees de la boite qui contient les coordonnees 1 et 2
  71. retour = []
  72. x, y = x1, y1
  73. #ky: decalage entre cases paires et impaires
  74. ky = 0
  75. while not x > x2:
  76. if dbg: print " > {}, {}, {}, {}".format(x, y, pasY * ky, error)
  77. coord = (x, y + (pasY * ky))
  78. retour.append(coord)
  79. x += 1
  80. ky = 0.5 if (x - x1) % 2 == 1 else 0
  81. error += (0.9087 * (abs(dy) / dx))
  82. if error > 0.5 + ky:
  83. y += pasY
  84. error -= 1
  85. return retour
  86. def _brH_v(x1, y1, x2, y2):
  87. """Algorithme ligne de Bresenham (pour cases hexagonales - secteur vertical)"""
  88. #on prend comme unite la demi largeur: u = 0.5773
  89. #la demi hauteur d'un hexa vaut donc 0.8860u, ou sqrt(3)/2
  90. #[a revoir] une fois cela pose, on muliplie tout par 4dy afin d'eviter nombres flottants et divisions
  91. # Calcul des ecarts
  92. dx = 1.5 * (x2 - x1) #en x, on a 1.5u de centre a centre
  93. dy = y2 - y1 #en y, on compte en demi hauteurs
  94. if (x1 + x2) % 2 == 1:
  95. if x1 % 2 == 0:
  96. dy += 0.5
  97. else:
  98. dy -= 0.5
  99. #k est la tangente de l'angle par rapport a la verticale
  100. k = dx/(dy*sqrt(3))
  101. pas = 0.5*sqrt(3) #on avance par demi hauteurs
  102. retour = []
  103. d = 0.0 #decalage
  104. pos = (x1, y1)
  105. retour.append(pos)
  106. while pos != (x2, y2):
  107. d += (k*pas)
  108. if d <= 0.5:
  109. #on se deplace vers la case en dessous
  110. x, y = pos
  111. pos = x, y+1
  112. retour.append(pos)
  113. d += (k*pas)
  114. else:
  115. #on se deplace vers la case en dessous a droite
  116. x, y = pos
  117. if x %2 == 0:
  118. pos = x + 1, y
  119. else:
  120. pos = x + 1, y + 1
  121. retour.append(pos)
  122. d -= 1.5
  123. if dbg: print " > d = {} -> {}".format(d, pos)
  124. return retour
  125. # print casesEntre((0,0), (4,5))
  126. # print casesEntre((1,0), (5,5))