test_imagery_sigsetfile.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. """Test of imagery library sigset file handling
  2. @author Maris Nartiss
  3. @copyright 2021 by Maris Nartiss and the GRASS Development Team
  4. @license This program is free software under the GNU General Public License (>=v2).
  5. Read the file COPYING that comes with GRASS
  6. for details
  7. """
  8. import os
  9. import stat
  10. import ctypes
  11. import shutil
  12. from grass.gunittest.case import TestCase
  13. from grass.gunittest.main import test
  14. from grass.script.core import tempname
  15. from grass.pygrass import utils
  16. from grass.pygrass.gis import Mapset
  17. from grass.lib.gis import G_mapset_path
  18. from grass.lib.raster import Rast_write_semantic_label
  19. from grass.lib.imagery import (
  20. SigSet,
  21. I_InitSigSet,
  22. I_NewClassSig,
  23. I_NewSubSig,
  24. I_WriteSigSet,
  25. I_ReadSigSet,
  26. I_SortSigSetBySemanticLabel,
  27. I_fopen_sigset_file_new,
  28. I_fopen_sigset_file_old,
  29. Ref,
  30. I_init_group_ref,
  31. I_add_file_to_group_ref,
  32. I_free_group_ref,
  33. ReturnString,
  34. )
  35. class SigSetFileTestCase(TestCase):
  36. @classmethod
  37. def setUpClass(cls):
  38. cls.libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c"))
  39. cls.mpath = utils.decode(G_mapset_path())
  40. cls.mapset_name = Mapset().name
  41. cls.sig_name = tempname(10)
  42. cls.sig_dir = f"{cls.mpath}/signatures/sigset/{cls.sig_name}"
  43. @classmethod
  44. def tearDownClass(cls):
  45. shutil.rmtree(cls.sig_dir, ignore_errors=True)
  46. def test_I_fopen_signature_file_old_fail(self):
  47. sigfile = I_fopen_sigset_file_old(tempname(10))
  48. self.assertFalse(sigfile)
  49. def test_roundtrip_sigset_v1_one_label(self):
  50. """Test writing and reading back sigset file (v1)
  51. with a single label and fully qualified sigfile name"""
  52. # Create signature struct
  53. So = SigSet()
  54. I_InitSigSet(ctypes.byref(So), 1)
  55. self.assertEqual(So.nbands, 1)
  56. I_NewClassSig(ctypes.byref(So))
  57. self.assertEqual(So.nclasses, 1)
  58. I_NewSubSig(ctypes.byref(So), ctypes.byref(So.ClassSig[0]))
  59. self.assertEqual(So.ClassSig[0].nsubclasses, 1)
  60. # Fill sigset struct with data
  61. So.title = ReturnString("Signature title")
  62. So.semantic_labels[0] = ctypes.create_string_buffer(b"The_Doors")
  63. So.ClassSig[0].used = 1
  64. So.ClassSig[0].classnum = 2
  65. So.ClassSig[0].title = ReturnString("1st class")
  66. So.ClassSig[0].type = 1
  67. So.ClassSig[0].SubSig[0].pi = 3.14
  68. So.ClassSig[0].SubSig[0].means[0] = 42.42
  69. So.ClassSig[0].SubSig[0].R[0][0] = 69.69
  70. # Write signatures to file
  71. p_new_sigfile = I_fopen_sigset_file_new(self.sig_name)
  72. sig_stat = os.stat(f"{self.sig_dir}/sig")
  73. self.assertTrue(stat.S_ISREG(sig_stat.st_mode))
  74. I_WriteSigSet(p_new_sigfile, ctypes.byref(So))
  75. self.libc.fclose(p_new_sigfile)
  76. # Read back from signatures file
  77. Sn = SigSet()
  78. fq_name = f"{self.sig_name}@{self.mapset_name}"
  79. p_old_sigfile = I_fopen_sigset_file_old(fq_name)
  80. ret = I_ReadSigSet(p_old_sigfile, ctypes.byref(Sn))
  81. self.assertEqual(ret, 1)
  82. self.assertEqual(utils.decode(Sn.title), "Signature title")
  83. self.assertEqual(Sn.nbands, 1)
  84. semantic_label = utils.decode(
  85. ctypes.cast(Sn.semantic_labels[0], ctypes.c_char_p).value
  86. )
  87. self.assertEqual(semantic_label, "The_Doors")
  88. self.assertEqual(Sn.nclasses, 1)
  89. self.assertEqual(Sn.ClassSig[0].nsubclasses, 1)
  90. self.assertEqual(Sn.ClassSig[0].used, 1)
  91. self.assertEqual(Sn.ClassSig[0].nsubclasses, 1)
  92. self.assertEqual(Sn.ClassSig[0].classnum, 2)
  93. self.assertEqual(utils.decode(Sn.ClassSig[0].title), "1st class")
  94. self.assertEqual(Sn.ClassSig[0].type, 1)
  95. self.assertEqual(Sn.ClassSig[0].SubSig[0].pi, 3.14)
  96. self.assertEqual(Sn.ClassSig[0].SubSig[0].means[0], 42.42)
  97. self.assertEqual(Sn.ClassSig[0].SubSig[0].R[0][0], 69.69)
  98. # SigSet does not have free function
  99. def test_read_fail_sigset_v1_one_label(self):
  100. """Reading back should fail as semantic label length exceeds limit"""
  101. # Create signature struct
  102. So = SigSet()
  103. I_InitSigSet(ctypes.byref(So), 1)
  104. self.assertEqual(So.nbands, 1)
  105. I_NewClassSig(ctypes.byref(So))
  106. self.assertEqual(So.nclasses, 1)
  107. I_NewSubSig(ctypes.byref(So), ctypes.byref(So.ClassSig[0]))
  108. self.assertEqual(So.ClassSig[0].nsubclasses, 1)
  109. # Fill sigset struct with data
  110. So.title = ReturnString("Signature title")
  111. So.semantic_labels[0] = ctypes.create_string_buffer(tempname(252).encode())
  112. So.ClassSig[0].used = 1
  113. So.ClassSig[0].classnum = 2
  114. So.ClassSig[0].title = ReturnString("1st class")
  115. So.ClassSig[0].type = 1
  116. So.ClassSig[0].SubSig[0].pi = 3.14
  117. So.ClassSig[0].SubSig[0].means[0] = 42.42
  118. So.ClassSig[0].SubSig[0].R[0][0] = 69.69
  119. # Write signatures to file
  120. p_new_sigfile = I_fopen_sigset_file_new(self.sig_name)
  121. sig_stat = os.stat(f"{self.sig_dir}/sig")
  122. self.assertTrue(stat.S_ISREG(sig_stat.st_mode))
  123. I_WriteSigSet(p_new_sigfile, ctypes.byref(So))
  124. self.libc.fclose(p_new_sigfile)
  125. # Read back from signatures file
  126. Sn = SigSet()
  127. I_InitSigSet(ctypes.byref(So), 0)
  128. p_old_sigfile = I_fopen_sigset_file_old(self.sig_name)
  129. ret = I_ReadSigSet(p_old_sigfile, ctypes.byref(Sn))
  130. self.assertEqual(ret, -1)
  131. # SigSet does not have free function
  132. def test_roundtrip_sigset_v1_two_labels(self):
  133. """Test writing and reading back sigset (v1) with two labels"""
  134. # Create signature struct
  135. So = SigSet()
  136. I_InitSigSet(ctypes.byref(So), 2)
  137. self.assertEqual(So.nbands, 2)
  138. I_NewClassSig(ctypes.byref(So))
  139. self.assertEqual(So.nclasses, 1)
  140. I_NewSubSig(ctypes.byref(So), ctypes.byref(So.ClassSig[0]))
  141. self.assertEqual(So.ClassSig[0].nsubclasses, 1)
  142. # Fill sigset struct with data
  143. So.title = ReturnString("Signature title")
  144. So.semantic_labels[0] = ctypes.create_string_buffer(b"The_Doors")
  145. So.semantic_labels[1] = ctypes.create_string_buffer(b"The_Who")
  146. So.ClassSig[0].used = 1
  147. So.ClassSig[0].classnum = 2
  148. So.ClassSig[0].title = ReturnString("1st class")
  149. So.ClassSig[0].type = 1
  150. So.ClassSig[0].SubSig[0].pi = 3.14
  151. So.ClassSig[0].SubSig[0].means[0] = 42.42
  152. So.ClassSig[0].SubSig[0].means[1] = 24.24
  153. So.ClassSig[0].SubSig[0].R[0][0] = 69.69
  154. So.ClassSig[0].SubSig[0].R[0][1] = 13.37
  155. So.ClassSig[0].SubSig[0].R[1][0] = 13.37
  156. So.ClassSig[0].SubSig[0].R[1][1] = 21.21
  157. # Write signatures to file
  158. p_new_sigfile = I_fopen_sigset_file_new(self.sig_name)
  159. sig_stat = os.stat(f"{self.sig_dir}/sig")
  160. self.assertTrue(stat.S_ISREG(sig_stat.st_mode))
  161. I_WriteSigSet(p_new_sigfile, ctypes.byref(So))
  162. self.libc.fclose(p_new_sigfile)
  163. # Read back from signatures file
  164. Sn = SigSet()
  165. p_old_sigfile = I_fopen_sigset_file_old(self.sig_name)
  166. ret = I_ReadSigSet(p_old_sigfile, ctypes.byref(Sn))
  167. self.assertEqual(ret, 1)
  168. self.assertEqual(utils.decode(Sn.title), "Signature title")
  169. self.assertEqual(Sn.nbands, 2)
  170. semantic_label = utils.decode(
  171. ctypes.cast(Sn.semantic_labels[0], ctypes.c_char_p).value
  172. )
  173. self.assertEqual(semantic_label, "The_Doors")
  174. semantic_label = utils.decode(
  175. ctypes.cast(Sn.semantic_labels[1], ctypes.c_char_p).value
  176. )
  177. self.assertEqual(semantic_label, "The_Who")
  178. self.assertEqual(Sn.nclasses, 1)
  179. self.assertEqual(Sn.ClassSig[0].nsubclasses, 1)
  180. self.assertEqual(Sn.ClassSig[0].used, 1)
  181. self.assertEqual(Sn.ClassSig[0].nsubclasses, 1)
  182. self.assertEqual(Sn.ClassSig[0].classnum, 2)
  183. self.assertEqual(utils.decode(Sn.ClassSig[0].title), "1st class")
  184. self.assertEqual(Sn.ClassSig[0].type, 1)
  185. self.assertEqual(Sn.ClassSig[0].SubSig[0].pi, 3.14)
  186. self.assertEqual(Sn.ClassSig[0].SubSig[0].means[0], 42.42)
  187. self.assertEqual(Sn.ClassSig[0].SubSig[0].means[1], 24.24)
  188. self.assertEqual(Sn.ClassSig[0].SubSig[0].R[0][0], 69.69)
  189. self.assertEqual(Sn.ClassSig[0].SubSig[0].R[0][1], 13.37)
  190. self.assertEqual(Sn.ClassSig[0].SubSig[0].R[1][0], 13.37)
  191. self.assertEqual(Sn.ClassSig[0].SubSig[0].R[1][1], 21.21)
  192. # SigSet does not have free function
  193. class SortSigSetBySemanticLabelTest(TestCase):
  194. @classmethod
  195. def setUpClass(cls):
  196. cls.libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c"))
  197. cls.mapset = Mapset().name
  198. cls.map1 = tempname(10)
  199. cls.semantic_label1 = "The_Doors"
  200. cls.map2 = tempname(10)
  201. cls.semantic_label2 = "The_Who"
  202. cls.map3 = tempname(10)
  203. cls.use_temp_region()
  204. cls.runModule("g.region", n=1, s=0, e=1, w=0, res=1)
  205. cls.runModule("r.mapcalc", expression=f"{cls.map1} = 1")
  206. cls.runModule("r.mapcalc", expression=f"{cls.map2} = 1")
  207. cls.runModule("r.mapcalc", expression=f"{cls.map3} = 1")
  208. Rast_write_semantic_label(cls.map1, cls.semantic_label1)
  209. Rast_write_semantic_label(cls.map2, cls.semantic_label2)
  210. @classmethod
  211. def tearDownClass(cls):
  212. cls.del_temp_region()
  213. cls.runModule("g.remove", flags="f", type="raster", name=cls.map1)
  214. cls.runModule("g.remove", flags="f", type="raster", name=cls.map2)
  215. cls.runModule("g.remove", flags="f", type="raster", name=cls.map3)
  216. def test_symmetric_complete_difference(self):
  217. # Prepare imagery group reference struct
  218. R = Ref()
  219. I_init_group_ref(ctypes.byref(R))
  220. ret = I_add_file_to_group_ref(self.map1, self.mapset, ctypes.byref(R))
  221. self.assertEqual(ret, 0)
  222. # Prepare sigset struct
  223. S = SigSet()
  224. I_InitSigSet(ctypes.byref(S), 1)
  225. self.assertEqual(S.nbands, 1)
  226. I_NewClassSig(ctypes.byref(S))
  227. self.assertEqual(S.nclasses, 1)
  228. I_NewSubSig(ctypes.byref(S), ctypes.byref(S.ClassSig[0]))
  229. self.assertEqual(S.ClassSig[0].nsubclasses, 1)
  230. S.title = ReturnString("Signature title")
  231. S.semantic_labels[0] = ctypes.create_string_buffer(b"The_Troggs")
  232. S.ClassSig[0].used = 1
  233. S.ClassSig[0].classnum = 2
  234. S.ClassSig[0].title = ReturnString("1st class")
  235. S.ClassSig[0].type = 1
  236. S.ClassSig[0].SubSig[0].pi = 3.14
  237. S.ClassSig[0].SubSig[0].means[0] = 42.42
  238. S.ClassSig[0].SubSig[0].R[0][0] = 69.69
  239. # This should result in two error strings in ret
  240. ret = I_SortSigSetBySemanticLabel(ctypes.byref(S), ctypes.byref(R))
  241. self.assertTrue(bool(ret))
  242. sig_err = utils.decode(ctypes.cast(ret[0], ctypes.c_char_p).value)
  243. ref_err = utils.decode(ctypes.cast(ret[1], ctypes.c_char_p).value)
  244. self.assertEqual(sig_err, "The_Troggs")
  245. self.assertEqual(ref_err, "The_Doors")
  246. # Clean up memory to help track memory leaks when run by valgrind
  247. # I_free_sigset is missing
  248. I_free_group_ref(ctypes.byref(R))
  249. if ret:
  250. if ret[0]:
  251. self.libc.free(ret[0])
  252. if ret[1]:
  253. self.libc.free(ret[1])
  254. self.libc.free(ret)
  255. def test_asymmetric_complete_difference(self):
  256. # Prepare imagery group reference struct
  257. R = Ref()
  258. I_init_group_ref(ctypes.byref(R))
  259. ret = I_add_file_to_group_ref(self.map1, self.mapset, ctypes.byref(R))
  260. self.assertEqual(ret, 0)
  261. ret = I_add_file_to_group_ref(self.map2, self.mapset, ctypes.byref(R))
  262. self.assertEqual(ret, 1)
  263. # Prepare signature struct
  264. S = SigSet()
  265. I_InitSigSet(ctypes.byref(S), 1)
  266. self.assertEqual(S.nbands, 1)
  267. I_NewClassSig(ctypes.byref(S))
  268. self.assertEqual(S.nclasses, 1)
  269. I_NewSubSig(ctypes.byref(S), ctypes.byref(S.ClassSig[0]))
  270. self.assertEqual(S.ClassSig[0].nsubclasses, 1)
  271. S.title = ReturnString("Signature title")
  272. S.semantic_labels[0] = ctypes.create_string_buffer(b"The_Troggs")
  273. S.ClassSig[0].used = 1
  274. S.ClassSig[0].classnum = 2
  275. S.ClassSig[0].title = ReturnString("1st class")
  276. S.ClassSig[0].type = 1
  277. S.ClassSig[0].SubSig[0].pi = 3.14
  278. S.ClassSig[0].SubSig[0].means[0] = 42.42
  279. S.ClassSig[0].SubSig[0].R[0][0] = 69.69
  280. # This should result in two error strings in ret
  281. ret = I_SortSigSetBySemanticLabel(ctypes.byref(S), ctypes.byref(R))
  282. self.assertTrue(bool(ret))
  283. sig_err = utils.decode(ctypes.cast(ret[0], ctypes.c_char_p).value)
  284. ref_err = utils.decode(ctypes.cast(ret[1], ctypes.c_char_p).value)
  285. self.assertEqual(sig_err, "The_Troggs")
  286. self.assertEqual(ref_err, "The_Doors,The_Who")
  287. # Clean up memory to help track memory leaks when run by valgrind
  288. I_free_group_ref(ctypes.byref(R))
  289. if ret:
  290. if ret[0]:
  291. self.libc.free(ret[0])
  292. if ret[1]:
  293. self.libc.free(ret[1])
  294. self.libc.free(ret)
  295. def test_missing_label(self):
  296. # Prepare imagery group reference struct
  297. R = Ref()
  298. I_init_group_ref(ctypes.byref(R))
  299. ret = I_add_file_to_group_ref(self.map1, self.mapset, ctypes.byref(R))
  300. self.assertEqual(ret, 0)
  301. ret = I_add_file_to_group_ref(self.map2, self.mapset, ctypes.byref(R))
  302. self.assertEqual(ret, 1)
  303. ret = I_add_file_to_group_ref(self.map3, self.mapset, ctypes.byref(R))
  304. self.assertEqual(ret, 2)
  305. # Prepare signature struct
  306. S = SigSet()
  307. I_InitSigSet(ctypes.byref(S), 10)
  308. self.assertEqual(S.nbands, 10)
  309. I_NewClassSig(ctypes.byref(S))
  310. self.assertEqual(S.nclasses, 1)
  311. I_NewSubSig(ctypes.byref(S), ctypes.byref(S.ClassSig[0]))
  312. self.assertEqual(S.ClassSig[0].nsubclasses, 1)
  313. S.title = ReturnString("Signature title")
  314. S.semantic_labels[0] = ctypes.create_string_buffer(b"The_Who")
  315. S.ClassSig[0].used = 1
  316. S.ClassSig[0].classnum = 2
  317. S.ClassSig[0].title = ReturnString("1st class")
  318. S.ClassSig[0].type = 1
  319. S.ClassSig[0].SubSig[0].pi = 3.14
  320. S.ClassSig[0].SubSig[0].means[0] = 42.42
  321. S.ClassSig[0].SubSig[0].R[0][0] = 69.69
  322. # This should result in two error strings in ret
  323. ret = I_SortSigSetBySemanticLabel(ctypes.byref(S), ctypes.byref(R))
  324. self.assertTrue(bool(ret))
  325. sig_err = utils.decode(ctypes.cast(ret[0], ctypes.c_char_p).value)
  326. ref_err = utils.decode(ctypes.cast(ret[1], ctypes.c_char_p).value)
  327. self.assertEqual(
  328. sig_err,
  329. "<semantic label missing>,<semantic label missing>,"
  330. + "<semantic label missing>,<semantic label missing>,"
  331. + "<semantic label missing>,<semantic label missing>,"
  332. + "<semantic label missing>,<semantic label missing>,"
  333. + "<semantic label missing>",
  334. )
  335. self.assertEqual(ref_err, f"The_Doors,{self.map3}")
  336. # Clean up memory to help track memory leaks when run by valgrind
  337. I_free_group_ref(ctypes.byref(R))
  338. if ret:
  339. if ret[0]:
  340. self.libc.free(ret[0])
  341. if ret[1]:
  342. self.libc.free(ret[1])
  343. self.libc.free(ret)
  344. def test_single_complete_match(self):
  345. # Prepare imagery group reference struct
  346. R = Ref()
  347. I_init_group_ref(ctypes.byref(R))
  348. ret = I_add_file_to_group_ref(self.map1, self.mapset, ctypes.byref(R))
  349. self.assertEqual(ret, 0)
  350. # Prepare signature struct
  351. S = SigSet()
  352. I_InitSigSet(ctypes.byref(S), 1)
  353. self.assertEqual(S.nbands, 1)
  354. I_NewClassSig(ctypes.byref(S))
  355. self.assertEqual(S.nclasses, 1)
  356. I_NewSubSig(ctypes.byref(S), ctypes.byref(S.ClassSig[0]))
  357. self.assertEqual(S.ClassSig[0].nsubclasses, 1)
  358. S.title = ReturnString("Signature title")
  359. S.semantic_labels[0] = ctypes.create_string_buffer(b"The_Doors")
  360. S.ClassSig[0].used = 1
  361. S.ClassSig[0].classnum = 2
  362. S.ClassSig[0].title = ReturnString("1st class")
  363. S.ClassSig[0].type = 1
  364. S.ClassSig[0].SubSig[0].pi = 3.14
  365. S.ClassSig[0].SubSig[0].means[0] = 42.42
  366. S.ClassSig[0].SubSig[0].R[0][0] = 69.69
  367. # This should result in returning NULL
  368. ret = I_SortSigSetBySemanticLabel(ctypes.byref(S), ctypes.byref(R))
  369. self.assertFalse(bool(ret))
  370. semantic_label = utils.decode(
  371. ctypes.cast(S.semantic_labels[0], ctypes.c_char_p).value
  372. )
  373. self.assertEqual(semantic_label, "The_Doors")
  374. self.assertEqual(S.ClassSig[0].SubSig[0].pi, 3.14)
  375. self.assertEqual(S.ClassSig[0].SubSig[0].means[0], 42.42)
  376. self.assertEqual(S.ClassSig[0].SubSig[0].R[0][0], 69.69)
  377. # Clean up memory to help track memory leaks when run by valgrind
  378. I_free_group_ref(ctypes.byref(R))
  379. if ret:
  380. if ret[0]:
  381. self.libc.free(ret[0])
  382. if ret[1]:
  383. self.libc.free(ret[1])
  384. self.libc.free(ret)
  385. def test_double_complete_match_reorder(self):
  386. # Prepare imagery group reference struct
  387. R = Ref()
  388. I_init_group_ref(ctypes.byref(R))
  389. ret = I_add_file_to_group_ref(self.map1, self.mapset, ctypes.byref(R))
  390. self.assertEqual(ret, 0)
  391. ret = I_add_file_to_group_ref(self.map2, self.mapset, ctypes.byref(R))
  392. self.assertEqual(ret, 1)
  393. # Prepare signature struct
  394. S = SigSet()
  395. I_InitSigSet(ctypes.byref(S), 2)
  396. self.assertEqual(S.nbands, 2)
  397. I_NewClassSig(ctypes.byref(S))
  398. self.assertEqual(S.nclasses, 1)
  399. I_NewSubSig(ctypes.byref(S), ctypes.byref(S.ClassSig[0]))
  400. self.assertEqual(S.ClassSig[0].nsubclasses, 1)
  401. S.title = ReturnString("Signature title")
  402. S.semantic_labels[0] = ctypes.create_string_buffer(b"The_Who")
  403. S.semantic_labels[1] = ctypes.create_string_buffer(b"The_Doors")
  404. S.ClassSig[0].used = 1
  405. S.ClassSig[0].classnum = 2
  406. S.ClassSig[0].title = ReturnString("1st class")
  407. S.ClassSig[0].type = 1
  408. S.ClassSig[0].SubSig[0].pi = 3.14
  409. S.ClassSig[0].SubSig[0].means[0] = 42.42
  410. S.ClassSig[0].SubSig[0].means[1] = 24.24
  411. S.ClassSig[0].SubSig[0].R[0][0] = 69.69
  412. S.ClassSig[0].SubSig[0].R[0][1] = 96.96
  413. S.ClassSig[0].SubSig[0].R[1][0] = -69.69
  414. S.ClassSig[0].SubSig[0].R[1][1] = -96.96
  415. # This should result in returning NULL
  416. ret = I_SortSigSetBySemanticLabel(ctypes.byref(S), ctypes.byref(R))
  417. self.assertFalse(bool(ret))
  418. # Semantic labels and sig items should be swapped
  419. # Static items
  420. self.assertEqual(S.ClassSig[0].SubSig[0].pi, 3.14)
  421. # Reordered items
  422. semantic_label1 = utils.decode(
  423. ctypes.cast(S.semantic_labels[0], ctypes.c_char_p).value
  424. )
  425. self.assertEqual(semantic_label1, "The_Doors")
  426. semantic_label2 = utils.decode(
  427. ctypes.cast(S.semantic_labels[1], ctypes.c_char_p).value
  428. )
  429. self.assertEqual(semantic_label2, "The_Who")
  430. self.assertEqual(S.ClassSig[0].SubSig[0].means[0], 24.24)
  431. self.assertEqual(S.ClassSig[0].SubSig[0].means[1], 42.42)
  432. self.assertEqual(S.ClassSig[0].SubSig[0].R[0][0], -96.96)
  433. self.assertEqual(S.ClassSig[0].SubSig[0].R[0][1], -69.69)
  434. self.assertEqual(S.ClassSig[0].SubSig[0].R[1][0], 96.96)
  435. self.assertEqual(S.ClassSig[0].SubSig[0].R[1][1], 69.69)
  436. # Clean up memory to help track memory leaks when run by valgrind
  437. I_free_group_ref(ctypes.byref(R))
  438. if ret:
  439. if ret[0]:
  440. self.libc.free(ret[0])
  441. if ret[1]:
  442. self.libc.free(ret[1])
  443. self.libc.free(ret)
  444. def test_double_complete_match_same_order(self):
  445. # Prepare imagery group reference struct
  446. R = Ref()
  447. I_init_group_ref(ctypes.byref(R))
  448. ret = I_add_file_to_group_ref(self.map2, self.mapset, ctypes.byref(R))
  449. self.assertEqual(ret, 0)
  450. ret = I_add_file_to_group_ref(self.map1, self.mapset, ctypes.byref(R))
  451. self.assertEqual(ret, 1)
  452. # Prepare signature struct
  453. S = SigSet()
  454. I_InitSigSet(ctypes.byref(S), 2)
  455. self.assertEqual(S.nbands, 2)
  456. I_NewClassSig(ctypes.byref(S))
  457. self.assertEqual(S.nclasses, 1)
  458. I_NewSubSig(ctypes.byref(S), ctypes.byref(S.ClassSig[0]))
  459. self.assertEqual(S.ClassSig[0].nsubclasses, 1)
  460. S.title = ReturnString("Signature title")
  461. S.semantic_labels[0] = ctypes.create_string_buffer(b"The_Who")
  462. S.semantic_labels[1] = ctypes.create_string_buffer(b"The_Doors")
  463. S.ClassSig[0].used = 1
  464. S.ClassSig[0].classnum = 2
  465. S.ClassSig[0].title = ReturnString("1st class")
  466. S.ClassSig[0].type = 1
  467. S.ClassSig[0].SubSig[0].pi = 3.14
  468. S.ClassSig[0].SubSig[0].means[0] = 42.42
  469. S.ClassSig[0].SubSig[0].means[1] = 24.24
  470. S.ClassSig[0].SubSig[0].R[0][0] = 69.69
  471. S.ClassSig[0].SubSig[0].R[0][1] = 96.96
  472. S.ClassSig[0].SubSig[0].R[1][0] = -69.69
  473. S.ClassSig[0].SubSig[0].R[1][1] = -96.96
  474. # This should result in returning NULL
  475. ret = I_SortSigSetBySemanticLabel(ctypes.byref(S), ctypes.byref(R))
  476. self.assertFalse(bool(ret))
  477. # Semantic labels and sig items should not be swapped
  478. # Static items
  479. self.assertEqual(S.ClassSig[0].SubSig[0].pi, 3.14)
  480. # Reordered items
  481. semantic_label1 = utils.decode(
  482. ctypes.cast(S.semantic_labels[0], ctypes.c_char_p).value
  483. )
  484. self.assertEqual(semantic_label1, "The_Who")
  485. semantic_label2 = utils.decode(
  486. ctypes.cast(S.semantic_labels[1], ctypes.c_char_p).value
  487. )
  488. self.assertEqual(semantic_label2, "The_Doors")
  489. self.assertEqual(S.ClassSig[0].SubSig[0].means[0], 42.42)
  490. self.assertEqual(S.ClassSig[0].SubSig[0].means[1], 24.24)
  491. self.assertEqual(S.ClassSig[0].SubSig[0].R[0][0], 69.69)
  492. self.assertEqual(S.ClassSig[0].SubSig[0].R[0][1], 96.96)
  493. self.assertEqual(S.ClassSig[0].SubSig[0].R[1][0], -69.69)
  494. self.assertEqual(S.ClassSig[0].SubSig[0].R[1][1], -96.96)
  495. # Clean up memory to help track memory leaks when run by valgrind
  496. I_free_group_ref(ctypes.byref(R))
  497. if ret:
  498. if ret[0]:
  499. self.libc.free(ret[0])
  500. if ret[1]:
  501. self.libc.free(ret[1])
  502. self.libc.free(ret)
  503. if __name__ == "__main__":
  504. test()