geodesic_grid.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #!/usr/bin/python
  2. # Copyright (C) 2016 Intel Corporation. All rights reserved.
  3. #
  4. # This file is free software: you can redistribute it and/or modify it
  5. # under the terms of the GNU General Public License as published by the
  6. # Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This file is distributed in the hope that it will be useful, but
  10. # WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. # See the GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License along
  15. # with this program. If not, see <http://www.gnu.org/licenses/>.
  16. from __future__ import print_function
  17. import argparse
  18. import numpy as np
  19. import sys
  20. import icosahedron as ico
  21. import grid
  22. def print_code_gen_notice():
  23. print("/* This was generated with")
  24. print(" * libraries/AP_Math/tools/geodesic_grid/geodesic_grid.py */")
  25. def header_neighbor_umbrella(index):
  26. t = ico.triangles[0]
  27. a, b, c = t
  28. triangle, edge = (
  29. ( t, ( a, b)),
  30. ( t, ( b, c)),
  31. ( t, ( c, a)),
  32. (-t, (-a, -b)),
  33. (-t, (-b, -c)),
  34. (-t, (-c, -a)),
  35. )[index]
  36. return ico.neighbor_umbrella(triangle, edge), edge
  37. parser = argparse.ArgumentParser(
  38. description="""
  39. Utility script for helping to understand concepts used by AP_GeodesicGrid as
  40. well as for aiding its development.
  41. When passing a vertex as argument to one of the options, the valid values for
  42. the coordinates are 0, -1, 1, g and -g, where g is the golden ratio.
  43. """,
  44. )
  45. parser.add_argument(
  46. '-p', '--plot',
  47. action='store_true',
  48. help="""
  49. Plot results when applicable.
  50. """,
  51. )
  52. parser.add_argument(
  53. '-b', '--plot-subtriangles',
  54. action='store_true',
  55. help="""
  56. Plot subtriangles as well. This implies -p.
  57. """,
  58. )
  59. parser.add_argument(
  60. '--icosahedron',
  61. action='store_true',
  62. help='Get the icosahedron triangles.',
  63. )
  64. parser.add_argument(
  65. '-t', '--triangle',
  66. action='append',
  67. type=int,
  68. nargs='+',
  69. metavar='INDEX',
  70. help="""
  71. Get the icosahedron triangle at INDEX.
  72. """,
  73. )
  74. parser.add_argument(
  75. '-s', '--section',
  76. action='append',
  77. type=int,
  78. nargs='+',
  79. help="""
  80. Get the grid section SECTION. If --plot is passed, then --plot-subtriangles is
  81. implied.
  82. """,
  83. )
  84. parser.add_argument(
  85. '-u', '--umbrella',
  86. action='append',
  87. nargs=3,
  88. metavar=('X', 'Y', 'Z'),
  89. help="""
  90. Get the umbrella with pivot denoted by (X, Y, Z). The pivot must be one of the
  91. icosahedron's vertices.
  92. """,
  93. )
  94. parser.add_argument(
  95. '-n', '--neighbor-umbrella',
  96. action='append',
  97. nargs='+',
  98. metavar='INDEX',
  99. help="""
  100. Get the neighbor umbrella at INDEX as described by _neighbor_umbrellas in
  101. AP_GeodesicGrid.h. The special value "all" for INDEX is also accepted, which
  102. will make it ignore other indexes passed and get all neighbor umbrellas for
  103. that member.
  104. """,
  105. )
  106. parser.add_argument(
  107. '--neighbor-umbrella-gen',
  108. action='store_true',
  109. help="""
  110. Generate C++ code for the initialization of the member _neighbor_umbrellas
  111. described in AP_GeodesicGrid.h.
  112. """,
  113. )
  114. parser.add_argument(
  115. '--inverses-gen',
  116. action='store_true',
  117. help="""
  118. Generate C++ code for the initialization of members _inverses and _mid_inverses
  119. declared in AP_GeodesicGrid.h.
  120. """)
  121. args = parser.parse_args()
  122. if args.plot_subtriangles:
  123. args.plot = True
  124. if args.plot:
  125. import plot
  126. polygons_to_plot = []
  127. if args.triangle:
  128. indexes = []
  129. for l in args.triangle:
  130. indexes += l
  131. for i in indexes:
  132. if 0 > i or i >= len(ico.triangles):
  133. print(
  134. 'Triangle index must be in the range [0,%d)' % len(ico.triangles),
  135. file=sys.stderr,
  136. )
  137. sys.exit(1)
  138. print(ico.triangles[i])
  139. if args.plot:
  140. plot.polygon(ico.triangles[i])
  141. if args.section:
  142. sections = []
  143. for l in args.section:
  144. sections += l
  145. for s in sections:
  146. if 0 > s or s >= 4 * len(ico.triangles):
  147. print(
  148. 'Section must be in the range [0,%d)' % 4 * len(ico.triangles),
  149. file=sys.stderr,
  150. )
  151. sys.exit(1)
  152. print(grid.section_triangle(s))
  153. if args.plot:
  154. args.plot_subtriangles = True
  155. plot.sections(sections)
  156. if args.umbrella:
  157. for pivot in args.umbrella:
  158. for i, x in enumerate(pivot):
  159. if x == 'g':
  160. x = ico.g
  161. elif x == '-g':
  162. x = -ico.g
  163. else:
  164. try:
  165. x = int(x)
  166. if x not in (0, -1, 1):
  167. raise ValueError()
  168. except ValueError:
  169. print(
  170. 'umbrella: invalid pivot coordinate: %s' % str(x),
  171. file=sys.stderr,
  172. )
  173. sys.exit(1)
  174. pivot[i] = x
  175. pivot = ico.Vertex(*pivot)
  176. if pivot not in ico.vertices:
  177. print(
  178. 'umbrella: invalid pivot:', pivot,
  179. file=sys.stderr,
  180. )
  181. sys.exit(1)
  182. u = ico.umbrella(pivot)
  183. print("Components of the umbrella of %s:" % str(pivot))
  184. for c in u.components:
  185. print(" %s" % str(c))
  186. if args.plot:
  187. plot.polygons(u.components)
  188. if args.neighbor_umbrella:
  189. indexes = []
  190. for l in args.neighbor_umbrella:
  191. indexes += l
  192. if 'all' in indexes:
  193. indexes = range(6)
  194. else:
  195. for i, arg in enumerate(indexes):
  196. try:
  197. arg = int(arg)
  198. if arg not in range(6):
  199. raise ValueError()
  200. except ValueError:
  201. print(
  202. 'neighbor_umbrella: invalid index %s' % str(arg),
  203. file=sys.stderr,
  204. )
  205. sys.exit(1)
  206. indexes[i] = arg
  207. for i in indexes:
  208. u, order_edge = header_neighbor_umbrella(i)
  209. print("Header umbrella %d:" % i)
  210. print(" Pivot:", u.pivot)
  211. for i in range(5):
  212. print(" Vertex %d:" % i, u.vertex(i, order_edge))
  213. for i in range(5):
  214. print(" Component %d:" % i, u.component(i, order_edge))
  215. if args.plot:
  216. plot.polygons(u.components)
  217. if args.neighbor_umbrella_gen:
  218. print("Header neighbor umbrellas code generation:")
  219. print_code_gen_notice()
  220. print("const struct AP_GeodesicGrid::neighbor_umbrella")
  221. print("AP_GeodesicGrid::_neighbor_umbrellas[3]{")
  222. for i in range(6):
  223. u, order_edge = header_neighbor_umbrella(i)
  224. components = tuple(
  225. ico.triangles.index(u.component(i, order_edge)) for i in range(5)
  226. )
  227. def vi_cj(i, j):
  228. v = u.vertex(i, order_edge)
  229. t = u.component(j, order_edge)
  230. return t.index(v)
  231. vi_cj_values = tuple(
  232. vi_cj(a, b) for a, b in ((0, 0), (1, 1), (2, 1), (4, 4), (0, 4))
  233. )
  234. print(" {{%s}, %s}," % (
  235. ", ".join("%2d" % i for i in components),
  236. ", ".join(str(i) for i in vi_cj_values),
  237. ))
  238. print("};")
  239. if args.inverses_gen:
  240. print("Header inverses code generation:")
  241. print_code_gen_notice()
  242. print("const Matrix3f AP_GeodesicGrid::_inverses[10]{")
  243. for i in range(10):
  244. a, b, c = ico.triangles[i]
  245. m = np.matrix((
  246. (a.x, b.x, c.x),
  247. (a.y, b.y, c.y),
  248. (a.z, b.z, c.z),
  249. )).getI()
  250. print(" {{%9.6ff, %9.6ff, %9.6ff}," % (m[0,0], m[0,1], m[0,2]))
  251. print(" {%9.6ff, %9.6ff, %9.6ff}," % (m[1,0], m[1,1], m[1,2]))
  252. print(" {%9.6ff, %9.6ff, %9.6ff}}," % (m[2,0], m[2,1], m[2,2]))
  253. print("};")
  254. print()
  255. print_code_gen_notice()
  256. print("const Matrix3f AP_GeodesicGrid::_mid_inverses[10]{")
  257. for i in range(10):
  258. a, b, c = ico.triangles[i]
  259. ma, mb, mc = .5 * (a + b), .5 * (b + c), .5 * (c + a)
  260. m = np.matrix((
  261. (ma.x, mb.x, mc.x),
  262. (ma.y, mb.y, mc.y),
  263. (ma.z, mb.z, mc.z),
  264. )).getI()
  265. print(" {{%9.6ff, %9.6ff, %9.6ff}," % (m[0,0], m[0,1], m[0,2]))
  266. print(" {%9.6ff, %9.6ff, %9.6ff}," % (m[1,0], m[1,1], m[1,2]))
  267. print(" {%9.6ff, %9.6ff, %9.6ff}}," % (m[2,0], m[2,1], m[2,2]))
  268. print("};")
  269. if args.icosahedron:
  270. print('Icosahedron:')
  271. for i, t in enumerate(ico.triangles):
  272. print(' %s' % str(t))
  273. if args.plot:
  274. plot.polygons(ico.triangles)
  275. if args.plot:
  276. plot.show(subtriangles=args.plot_subtriangles)