basic.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Tue Jul 31 13:06:20 2012
  4. @author: pietro
  5. """
  6. import ctypes
  7. import grass.lib.vector as libvect
  8. from collections import Iterable
  9. class Bbox(object):
  10. """Instantiate a Bounding Box class that contains
  11. a ctypes pointer to the C struct bound_box, that could be used
  12. by C GRASS functions. ::
  13. >>> bbox = Bbox()
  14. >>> bbox
  15. Bbox(0.0, 0.0, 0.0, 0.0)
  16. The default parameters are 0. It is possible to set or change
  17. the parameters later, with: ::
  18. >>> bbox.north = 10
  19. >>> bbox.south = -10
  20. >>> bbox.east = -20
  21. >>> bbox.west = 20
  22. >>> bbox
  23. Bbox(10.0, -10.0, -20.0, 20.0)
  24. Or directly istantiate the class with the values, with: ::
  25. >>> bbox = Bbox(north=100, south=0, east=0, west=100)
  26. >>> bbox
  27. Bbox(100.0, 0.0, 0.0, 100.0)
  28. ..
  29. """
  30. def __init__(self, north=0, south=0, east=0, west=0, top=0, bottom=0):
  31. self.c_bbox = ctypes.pointer(libvect.bound_box())
  32. # self.c_bbox.contents.N = north ? etc
  33. self.north = north
  34. self.south = south
  35. self.east = east
  36. self.west = west
  37. self.top = top
  38. self.bottom = bottom
  39. def _get_n(self):
  40. return self.c_bbox.contents.N
  41. def _set_n(self, value):
  42. self.c_bbox.contents.N = value
  43. north = property(fget=_get_n, fset=_set_n)
  44. def _get_s(self):
  45. return self.c_bbox.contents.S
  46. def _set_s(self, value):
  47. self.c_bbox.contents.S = value
  48. south = property(fget=_get_s, fset=_set_s)
  49. def _get_e(self):
  50. return self.c_bbox.contents.E
  51. def _set_e(self, value):
  52. self.c_bbox.contents.E = value
  53. east = property(fget=_get_e, fset=_set_e)
  54. def _get_w(self):
  55. return self.c_bbox.contents.W
  56. def _set_w(self, value):
  57. self.c_bbox.contents.W = value
  58. west = property(fget=_get_w, fset=_set_w)
  59. def _get_t(self):
  60. return self.c_bbox.contents.T
  61. def _set_t(self, value):
  62. self.c_bbox.contents.T = value
  63. top = property(fget=_get_t, fset=_set_t)
  64. def _get_b(self):
  65. return self.c_bbox.contents.B
  66. def _set_b(self, value):
  67. self.c_bbox.contents.B = value
  68. bottom = property(fget=_get_b, fset=_set_b)
  69. def __repr__(self):
  70. return "Bbox({n}, {s}, {e}, {w})".format(n=self.north, s=self.south,
  71. e=self.east, w=self.west)
  72. class BoxList(object):
  73. def __init__(self, boxlist=None):
  74. # should this
  75. self.c_boxlist = ctypes.pointer(libvect.boxlist())
  76. # not rather be
  77. # self.c_boxlist = libvect.Vect_new_boxlist(1)
  78. # ?
  79. # if set to 0, the list will hold only ids and no boxes
  80. self.c_boxlist.contents.have_boxes = 1
  81. if boxlist is not None:
  82. for box in boxlist:
  83. self.append(box)
  84. def __len__(self):
  85. return self.c_boxlist.contents.n_values
  86. def __repr__(self):
  87. return "Boxlist([%s])" % ", ".join([repr(box)
  88. for box in self.__iter__()])
  89. def __getitem__(self, indx):
  90. bbox = Bbox()
  91. bbox.c_bbox = ctypes.pointer(self.c_boxlist.contents.box[indx])
  92. return bbox
  93. def __setitem__(self, indx, bbox):
  94. self.c_boxlist.contents.box[indx] = bbox
  95. def __iter__(self):
  96. return (self.__getitem__(box_id) for box_id in xrange(self.__len__()))
  97. def __str__(self):
  98. return self.__repr__()
  99. def append(self, box):
  100. """Append a Bbox object to a Boxlist object, using the
  101. ``Vect_boxlist_append`` C fuction. ::
  102. >>> box0 = Bbox()
  103. >>> box1 = Bbox(1,2,3,4)
  104. >>> box2 = Bbox(5,6,7,8)
  105. >>> boxlist = BoxList([box0, box1])
  106. >>> boxlist
  107. Boxlist([Bbox(0.0, 0.0, 0.0, 0.0), Bbox(1.0, 2.0, 3.0, 4.0)])
  108. >>> len(boxlist)
  109. 2
  110. >>> boxlist.append(box2)
  111. >>> len(boxlist)
  112. 3
  113. ..
  114. """
  115. indx = self.__len__()
  116. # MM: I am not sure about ctypes.byref
  117. # Vect_boxlist_append() wants a pointer to the box, not the box itself
  118. libvect.Vect_boxlist_append(self.c_boxlist, indx, ctypes.byref(box.c_bbox.contents))
  119. # def extend(self, boxlist):
  120. # """Extend a boxlist with another boxlist or using a list of Bbox, using
  121. # ``Vect_boxlist_append_boxlist`` c function. ::
  122. #
  123. # >>> box0 = Bbox()
  124. # >>> box1 = Bbox(1,2,3,4)
  125. # >>> box2 = Bbox(5,6,7,8)
  126. # >>> box3 = Bbox(9,8,7,6)
  127. # >>> boxlist0 = BoxList([box0, box1])
  128. # >>> boxlist0
  129. # Boxlist([Bbox(0.0, 0.0, 0.0, 0.0), Bbox(1.0, 2.0, 3.0, 4.0)])
  130. # >>> boxlist1 = BoxList([box2, box3])
  131. # >>> len(boxlist0)
  132. # 2
  133. # >>> boxlist0.extend(boxlist1)
  134. # >>> len(boxlist0)
  135. # 4
  136. # >>> boxlist1.extend([box0, box1])
  137. # >>> len(boxlist1)
  138. # 4
  139. #
  140. # ..
  141. # """
  142. # if hasattr(boxlist, 'c_boxlist'):
  143. # #import pdb; pdb.set_trace()
  144. # # FIXME: doesn't work
  145. # libvect.Vect_boxlist_append_boxlist(self.c_boxlist,
  146. # boxlist.c_boxlist)
  147. # else:
  148. # for box in boxlist:
  149. # self.append(box)
  150. def remove(self, indx):
  151. """Remove Bbox from the boxlist, given an integer or a list of integer
  152. or a boxlist, using ``Vect_boxlist_delete`` C function or the
  153. ``Vect_boxlist_delete_boxlist``. ::
  154. >>> boxlist = BoxList([Bbox(),
  155. ... Bbox(1, 0, 0, 1),
  156. ... Bbox(1, -1, -1, 1)])
  157. >>> boxlist.remove(0)
  158. >>> boxlist
  159. Boxlist([Bbox(1.0, 0.0, 0.0, 1.0), Bbox(1.0, -1.0, -1.0, 1.0)])
  160. ..
  161. """
  162. if hasattr(indx, 'c_boxlist'):
  163. libvect.Vect_boxlist_delete_boxlist(self.c_boxlist, indx.c_boxlist)
  164. elif isinstance(indx, int):
  165. libvect.Vect_boxlist_delete(self.c_boxlist, indx)
  166. else:
  167. for ind in indx:
  168. libvect.Vect_boxlist_delete(self.c_boxlist, ind)
  169. def reset(self):
  170. """Reset the c_boxlist C struct, using the ``Vect_reset_boxlist`` C
  171. function. ::
  172. >>> boxlist = BoxList([Bbox(),
  173. ... Bbox(1, 0, 0, 1),
  174. ... Bbox(1, -1, -1, 1)])
  175. >>> len(boxlist)
  176. 3
  177. >>> boxlist.reset()
  178. >>> len(boxlist)
  179. 0
  180. ..
  181. """
  182. libvect.Vect_reset_boxlist(self.c_boxlist)
  183. class Ilist(object):
  184. """Instantiate a list of integer using the C GRASS struct ``ilist``,
  185. the class contains this struct as ``c_ilist`` attribute. """
  186. def __init__(self, integer_list=None):
  187. # should this
  188. self.c_ilist = ctypes.pointer(libvect.struct_ilist())
  189. # not rather be
  190. # self.c_ilist = libvect.Vect_new_list()
  191. # ?
  192. if integer_list is not None:
  193. self.extend(integer_list)
  194. def __getitem__(self, key):
  195. if isinstance(key, slice):
  196. #import pdb; pdb.set_trace()
  197. #Get the start, stop, and step from the slice
  198. return [self.c_ilist.contents.value[indx]
  199. for indx in xrange(*key.indices(len(self)))]
  200. elif isinstance(key, int):
  201. if key < 0: # Handle negative indices
  202. key += self.c_ilist.contents.n_values
  203. if key >= self.c_ilist.contents.n_values:
  204. raise IndexError('Index out of range')
  205. return self.c_ilist.contents.value[key]
  206. else:
  207. raise ValueError("Invalid argument type: %r." % key)
  208. def __setitem__(self, key, value):
  209. if self.contains(value):
  210. raise ValueError('Integer already in the list')
  211. self.c_ilist.contents.value[key] = int(value)
  212. def __len__(self):
  213. return self.c_ilist.contents.n_values
  214. def __iter__(self):
  215. return [self.c_ilist.contents.value[i] for i in xrange(self.__len__())]
  216. def __repr__(self):
  217. return "Ilist(%r)" % repr(self.__iter__())
  218. def append(self, value):
  219. """Append an integer to the list"""
  220. if libvect.Vect_list_append(self.c_ilist, value):
  221. raise # TODO
  222. def reset(self):
  223. """Reset the list"""
  224. libvect.Vect_reset_list(self.c_ilist)
  225. def extend(self, ilist):
  226. """Extend the list with another Ilist object or
  227. with a list of integers"""
  228. if isinstance(ilist, Ilist):
  229. libvect.Vect_list_append_list(self.c_ilist, ilist.ilist)
  230. else:
  231. for i in ilist:
  232. self.append(i)
  233. def remove(self, value):
  234. """Remove a value from a list"""
  235. if isinstance(value, int):
  236. libvect.Vect_list_delete(self.c_ilist, value)
  237. elif isinstance(value, Ilist):
  238. libvect.Vect_list_delete_list(self.c_ilist, value.ilist)
  239. elif isinstance(value, Iterable):
  240. for i in value:
  241. libvect.Vect_list_delete(self.c_ilist, int(i))
  242. else:
  243. raise ValueError('Value: %r, is not supported' % value)
  244. def contains(self, value):
  245. """Check if value is in the list"""
  246. return bool(libvect.Vect_val_in_list(self.c_ilist, value))
  247. class Cats(object):
  248. """Instantiate a Category class that contains a ctypes pointer
  249. to the Map_info C struct, and a ctypes pointer to that C cats struct,
  250. that could be used by C functions.
  251. """
  252. def __init__(self, c_mapinfo, v_id, c_cats=None):
  253. self.c_mapinfo = c_mapinfo
  254. self.id = v_id
  255. if c_cats is not None:
  256. self.c_cats = c_cats
  257. else:
  258. # should this
  259. self.c_cats = ctypes.pointer(libvect.line_cats())
  260. # not rather be
  261. # self.c_cats = libvect.Vect_new_cats_struct()
  262. # ?
  263. self.get_area_cats()
  264. def get_area_cats(self):
  265. """Get area categories, set the c_cats struct given an area, using the
  266. ``Vect_get_area_cats`` function.
  267. """
  268. libvect.Vect_get_area_cats(self.c_mapinfo, self.id, self.c_cats)
  269. def reset(self):
  270. """Reset the C cats struct from previous values."""
  271. libvect.Vect_reset_cats(self.c_cats)