bresenham.py 4.3 KB

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