tomwer 1.2.1__py3-none-any.whl → 1.3.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. orangecontrib/tomwer/tutorials/icat_publication.ows +58 -0
  2. orangecontrib/tomwer/widgets/__init__.py +11 -11
  3. orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +2 -2
  4. orangecontrib/tomwer/widgets/control/DataListOW.py +9 -7
  5. orangecontrib/tomwer/widgets/control/DataListenerOW.py +6 -6
  6. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +21 -10
  7. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +6 -6
  8. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +24 -7
  9. orangecontrib/tomwer/widgets/control/EmailOW.py +4 -4
  10. orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +3 -3
  11. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +64 -23
  12. orangecontrib/tomwer/widgets/control/NXtomoConcatenate.py +20 -8
  13. orangecontrib/tomwer/widgets/control/NotifierOW.py +1 -0
  14. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +6 -6
  15. orangecontrib/tomwer/widgets/control/VolumeSelector.py +7 -4
  16. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +182 -182
  17. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +5 -5
  18. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +4 -4
  19. orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +3 -3
  20. orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +8 -1
  21. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +3 -3
  22. orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +3 -3
  23. orangecontrib/tomwer/widgets/icat/PublishProcessedDataOW.py +115 -0
  24. orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -0
  25. orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -0
  26. orangecontrib/tomwer/widgets/icat/__init__.py +13 -0
  27. orangecontrib/tomwer/widgets/icat/icons/add_gallery.png +0 -0
  28. orangecontrib/tomwer/widgets/icat/icons/add_gallery.svg +82 -0
  29. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.png +0 -0
  30. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.svg +95 -0
  31. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.png +0 -0
  32. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.svg +143 -0
  33. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.png +0 -0
  34. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.svg +76 -0
  35. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +22 -20
  36. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +19 -3
  37. orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +184 -169
  38. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +23 -0
  39. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +39 -5
  40. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +18 -22
  41. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +18 -26
  42. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +15 -19
  43. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +9 -9
  44. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  45. orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +1 -1
  46. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +3 -3
  47. orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -1
  48. orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +3 -29
  49. tomwer/__main__.py +7 -64
  50. tomwer/app/axis.py +3 -3
  51. tomwer/app/canvas.py +8 -0
  52. tomwer/app/canvas_launcher/config.py +16 -14
  53. tomwer/app/canvas_launcher/environ.py +1 -0
  54. tomwer/app/canvas_launcher/mainwindow.py +4 -1
  55. tomwer/app/darkref.py +1 -1
  56. tomwer/app/darkrefpatch.py +1 -1
  57. tomwer/app/diffframe.py +3 -3
  58. tomwer/app/imagekeyeditor.py +5 -5
  59. tomwer/app/imagekeyupgrader.py +5 -5
  60. tomwer/app/intensitynormalization.py +14 -13
  61. tomwer/app/{saaxis.py → multicor.py} +3 -3
  62. tomwer/app/{sadeltabeta.py → multipag.py} +3 -3
  63. tomwer/app/nabuapp.py +0 -11
  64. tomwer/app/radiostack.py +6 -4
  65. tomwer/app/samplemoved.py +3 -2
  66. tomwer/app/scanviewer.py +4 -2
  67. tomwer/app/sinogramviewer.py +3 -2
  68. tomwer/app/slicestack.py +3 -2
  69. tomwer/app/zstitching.py +88 -6
  70. tomwer/core/cluster/cluster.py +26 -0
  71. tomwer/core/log/logger.py +7 -5
  72. tomwer/core/process/conditions/filters.py +1 -1
  73. tomwer/core/process/control/datalistener/datalistener.py +19 -14
  74. tomwer/core/process/control/datawatcher/edfdwprocess.py +0 -9
  75. tomwer/core/process/control/nxtomoconcatenate.py +13 -13
  76. tomwer/core/process/control/nxtomomill.py +92 -34
  77. tomwer/core/process/control/scantransfer.py +20 -43
  78. tomwer/core/process/control/scanvalidator.py +3 -2
  79. tomwer/core/process/control/test/test_concatenate_nxtomos.py +9 -9
  80. tomwer/core/process/control/test/test_email.py +4 -4
  81. tomwer/core/process/control/test/test_h52nx_process.py +59 -7
  82. tomwer/core/process/control/test/test_volume_link.py +64 -64
  83. tomwer/core/process/control/timer.py +1 -1
  84. tomwer/core/process/control/volumesymlink.py +200 -200
  85. tomwer/core/process/edit/darkflatpatch.py +14 -15
  86. tomwer/core/process/edit/imagekeyeditor.py +41 -39
  87. tomwer/core/process/icat/__init__.py +0 -0
  88. tomwer/core/process/icat/createscreenshots.py +100 -0
  89. tomwer/core/process/icat/gallery.py +377 -0
  90. tomwer/core/process/icat/icatbase.py +36 -0
  91. tomwer/core/process/icat/publish.py +228 -0
  92. tomwer/core/process/icat/screenshots.py +27 -0
  93. tomwer/core/process/output.py +52 -0
  94. tomwer/core/process/reconstruction/axis/axis.py +280 -69
  95. tomwer/core/process/reconstruction/axis/mode.py +163 -48
  96. tomwer/core/process/reconstruction/axis/params.py +29 -21
  97. tomwer/core/process/reconstruction/darkref/darkrefs.py +41 -127
  98. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +4 -3
  99. tomwer/core/process/reconstruction/darkref/params.py +1 -1
  100. tomwer/core/process/reconstruction/nabu/castvolume.py +4 -4
  101. tomwer/core/process/reconstruction/nabu/helical.py +9 -5
  102. tomwer/core/process/reconstruction/nabu/nabucommon.py +71 -78
  103. tomwer/core/process/reconstruction/nabu/nabuscores.py +425 -53
  104. tomwer/core/process/reconstruction/nabu/nabuslices.py +114 -93
  105. tomwer/core/process/reconstruction/nabu/nabuvolume.py +54 -27
  106. tomwer/core/process/reconstruction/nabu/plane.py +9 -0
  107. tomwer/core/process/reconstruction/nabu/settings.py +2 -2
  108. tomwer/core/process/reconstruction/nabu/utils.py +164 -26
  109. tomwer/core/process/reconstruction/output.py +108 -0
  110. tomwer/core/process/reconstruction/saaxis/saaxis.py +238 -264
  111. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +151 -87
  112. tomwer/core/process/reconstruction/scores/params.py +7 -4
  113. tomwer/core/process/reconstruction/scores/scores.py +13 -0
  114. tomwer/core/process/reconstruction/test/test_axis_params.py +2 -2
  115. tomwer/core/process/reconstruction/test/test_darkref.py +3 -3
  116. tomwer/core/process/reconstruction/test/test_darkref_copy.py +7 -7
  117. tomwer/core/process/reconstruction/test/test_saaxis.py +3 -4
  118. tomwer/core/process/reconstruction/test/test_sadeltabeta.py +2 -2
  119. tomwer/core/process/stitching/nabustitcher.py +13 -12
  120. tomwer/core/process/task.py +34 -26
  121. tomwer/core/process/test/test_axis.py +13 -12
  122. tomwer/core/process/test/test_dark_and_flat.py +10 -7
  123. tomwer/core/process/test/test_data_transfer.py +10 -8
  124. tomwer/core/process/test/test_nabu.py +14 -6
  125. tomwer/core/process/test/test_normalization.py +4 -4
  126. tomwer/core/scan/blissscan.py +3 -3
  127. tomwer/core/scan/edfscan.py +13 -10
  128. tomwer/core/scan/hdf5scan.py +19 -530
  129. tomwer/core/scan/nxtomoscan.py +534 -0
  130. tomwer/core/scan/scanbase.py +72 -44
  131. tomwer/core/scan/scanfactory.py +13 -13
  132. tomwer/core/scan/test/test_edf.py +2 -2
  133. tomwer/core/scan/test/test_future_scan.py +3 -3
  134. tomwer/core/scan/test/test_h5.py +18 -16
  135. tomwer/core/scan/test/test_process_registration.py +4 -40
  136. tomwer/core/scan/test/test_scan.py +5 -78
  137. tomwer/core/settings.py +22 -2
  138. tomwer/core/test/test_scanutils.py +8 -7
  139. tomwer/core/test/test_utils.py +35 -28
  140. tomwer/core/tomwer_object.py +1 -1
  141. tomwer/core/utils/__init__.py +0 -466
  142. tomwer/core/utils/deprecation.py +1 -1
  143. tomwer/core/utils/dictutils.py +14 -0
  144. tomwer/core/utils/lbsram.py +35 -0
  145. tomwer/core/utils/nxtomoutils.py +1 -1
  146. tomwer/core/utils/scanutils.py +6 -6
  147. tomwer/core/utils/spec.py +263 -0
  148. tomwer/core/volume/edfvolume.py +6 -6
  149. tomwer/core/volume/hdf5volume.py +6 -6
  150. tomwer/core/volume/jp2kvolume.py +6 -6
  151. tomwer/core/volume/rawvolume.py +6 -6
  152. tomwer/core/volume/tiffvolume.py +12 -12
  153. tomwer/core/volume/volumefactory.py +2 -2
  154. tomwer/gui/cluster/slurm.py +274 -65
  155. tomwer/gui/cluster/supervisor.py +12 -0
  156. tomwer/gui/cluster/test/test_cluster.py +14 -2
  157. tomwer/gui/cluster/test/test_supervisor.py +3 -3
  158. tomwer/gui/configuration/__init__.py +0 -0
  159. tomwer/gui/{reconstruction/nabu → configuration}/action.py +1 -32
  160. tomwer/gui/configuration/level.py +22 -0
  161. tomwer/gui/control/actions.py +54 -0
  162. tomwer/gui/control/datalist.py +83 -16
  163. tomwer/gui/control/datalistener.py +4 -16
  164. tomwer/gui/control/datawatcher/controlwidget.py +2 -4
  165. tomwer/gui/control/datawatcher/datawatcher.py +1 -24
  166. tomwer/gui/control/{email.py → emailnotifier.py} +9 -18
  167. tomwer/gui/control/history.py +2 -2
  168. tomwer/gui/control/observations.py +2 -2
  169. tomwer/gui/control/reducedarkflatselector.py +9 -9
  170. tomwer/gui/control/selectorwidgetbase.py +36 -9
  171. tomwer/gui/control/serie/seriecreator.py +5 -22
  172. tomwer/gui/control/test/test_email.py +1 -1
  173. tomwer/gui/control/test/test_scanvalidator.py +6 -5
  174. tomwer/gui/control/test/test_single_tomo_obj.py +3 -3
  175. tomwer/gui/control/tomoobjdisplaymode.py +8 -0
  176. tomwer/gui/debugtools/datasetgenerator.py +3 -3
  177. tomwer/gui/edit/dkrfpatch.py +20 -26
  178. tomwer/gui/edit/imagekeyeditor.py +11 -12
  179. tomwer/gui/edit/nxtomoeditor.py +111 -44
  180. tomwer/gui/edit/nxtomowarmer.py +7 -6
  181. tomwer/gui/edit/test/test_dkrf_patch.py +13 -13
  182. tomwer/gui/edit/test/test_image_key_editor.py +3 -3
  183. tomwer/gui/edit/test/test_nx_editor.py +40 -16
  184. tomwer/gui/icat/__init__.py +0 -0
  185. tomwer/gui/icat/createscreenshots.py +80 -0
  186. tomwer/gui/icat/gallery.py +214 -0
  187. tomwer/gui/icat/publish.py +187 -0
  188. tomwer/gui/imagefromfile.py +2 -2
  189. tomwer/gui/qfolderdialog.py +24 -1
  190. tomwer/gui/reconstruction/axis/CompareImages.py +88 -168
  191. tomwer/gui/reconstruction/axis/axis.py +171 -57
  192. tomwer/gui/reconstruction/axis/radioaxis.py +122 -257
  193. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +3 -2
  194. tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -1
  195. tomwer/gui/reconstruction/nabu/castvolume.py +14 -3
  196. tomwer/gui/reconstruction/nabu/check.py +9 -9
  197. tomwer/gui/reconstruction/nabu/helical.py +29 -12
  198. tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
  199. tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +2 -1
  200. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +126 -35
  201. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +39 -32
  202. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +222 -31
  203. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +57 -27
  204. tomwer/gui/reconstruction/nabu/nabuflow.py +12 -20
  205. tomwer/gui/reconstruction/nabu/slices.py +10 -11
  206. tomwer/gui/reconstruction/nabu/volume.py +22 -10
  207. tomwer/gui/reconstruction/normalization/intensity.py +18 -48
  208. tomwer/gui/reconstruction/saaxis/corrangeselector.py +8 -24
  209. tomwer/gui/reconstruction/saaxis/dimensionwidget.py +1 -1
  210. tomwer/gui/reconstruction/saaxis/saaxis.py +9 -21
  211. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +45 -12
  212. tomwer/gui/reconstruction/scores/control.py +2 -9
  213. tomwer/gui/reconstruction/scores/scoreplot.py +13 -11
  214. tomwer/gui/reconstruction/test/test_axis.py +41 -16
  215. tomwer/gui/reconstruction/test/test_nabu.py +31 -9
  216. tomwer/gui/reconstruction/test/test_saaxis.py +3 -3
  217. tomwer/gui/reconstruction/test/test_sadeltabeta.py +12 -2
  218. tomwer/gui/settings.py +5 -28
  219. tomwer/gui/stackplot.py +2 -5
  220. tomwer/gui/stitching/action.py +49 -0
  221. tomwer/gui/stitching/config/axisparams.py +7 -24
  222. tomwer/gui/stitching/config/output.py +10 -8
  223. tomwer/gui/stitching/config/positionoveraxis.py +22 -23
  224. tomwer/gui/stitching/normalization.py +117 -0
  225. tomwer/gui/stitching/stitchandbackground.py +4 -6
  226. tomwer/gui/stitching/stitching.py +267 -45
  227. tomwer/gui/stitching/stitching_preview.py +62 -55
  228. tomwer/gui/stitching/stitching_raw.py +13 -12
  229. tomwer/gui/stitching/z_stitching/fineestimation.py +0 -60
  230. tomwer/gui/utils/buttons.py +112 -29
  231. tomwer/gui/utils/inputwidget.py +43 -25
  232. tomwer/gui/utils/lineselector/lineselector.py +1 -1
  233. tomwer/gui/utils/scandescription.py +4 -0
  234. tomwer/gui/utils/step.py +144 -0
  235. tomwer/gui/utils/unitsystem.py +2 -5
  236. tomwer/gui/utils/vignettes.py +176 -15
  237. tomwer/gui/visualization/dataviewer.py +48 -35
  238. tomwer/gui/visualization/diffviewer/diffviewer.py +7 -16
  239. tomwer/gui/visualization/diffviewer/shiftwidget.py +2 -5
  240. tomwer/gui/visualization/scanoverview.py +1 -1
  241. tomwer/gui/visualization/sinogramviewer.py +20 -36
  242. tomwer/gui/visualization/test/test_diffviewer.py +3 -3
  243. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +4 -4
  244. tomwer/gui/visualization/test/test_sinogramviewer.py +2 -2
  245. tomwer/gui/visualization/test/test_stacks.py +3 -3
  246. tomwer/gui/visualization/test/test_volumeviewer.py +65 -67
  247. tomwer/gui/visualization/volumeviewer.py +114 -113
  248. tomwer/io/utils/h5pyutils.py +3 -3
  249. tomwer/io/utils/raw_and_processed_data.py +84 -0
  250. tomwer/io/utils/tomoobj.py +4 -6
  251. tomwer/io/utils/utils.py +7 -7
  252. tomwer/resources/gui/icons/parameters.svg +1 -1
  253. tomwer/resources/gui/icons/ruler.png +0 -0
  254. tomwer/resources/gui/icons/ruler.svg +273 -0
  255. tomwer/resources/gui/icons/short_description.png +0 -0
  256. tomwer/resources/gui/icons/short_description.svg +58 -0
  257. tomwer/resources/gui/icons/url.png +0 -0
  258. tomwer/resources/gui/icons/url.svg +58 -0
  259. tomwer/resources/gui/illustrations/no_rot.svg +1 -1
  260. tomwer/synctools/stacks/edit/darkflatpatch.py +19 -14
  261. tomwer/synctools/stacks/edit/imagekeyeditor.py +2 -2
  262. tomwer/synctools/stacks/reconstruction/axis.py +4 -4
  263. tomwer/synctools/stacks/reconstruction/castvolume.py +22 -7
  264. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +25 -20
  265. tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
  266. tomwer/synctools/stacks/reconstruction/normalization.py +2 -2
  267. tomwer/synctools/stacks/reconstruction/saaxis.py +2 -2
  268. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +2 -2
  269. tomwer/synctools/test/test_darkRefs.py +7 -58
  270. tomwer/synctools/test/test_foldertransfer.py +6 -6
  271. tomwer/synctools/utils/scanstages.py +6 -6
  272. tomwer/tests/conftest.py +34 -0
  273. tomwer/tests/datasets.py +13 -0
  274. tomwer/tests/test_scripts.py +91 -41
  275. tomwer/tests/utils.py +5 -0
  276. tomwer/third_part/WaitingOverlay.py +110 -0
  277. tomwer/third_part/__init__.py +0 -0
  278. tomwer/version.py +2 -2
  279. tomwer-1.3.12-py3.11-nspkg.pth +1 -0
  280. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/METADATA +73 -58
  281. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/RECORD +287 -286
  282. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/WHEEL +1 -1
  283. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +0 -197
  284. orangecontrib/tomwer/widgets/reconstruction/icons/XY_lamino.svg +0 -168
  285. orangecontrib/tomwer/widgets/reconstruction/icons/XZ_lamino.svg +0 -275
  286. orangecontrib/tomwer/widgets/reconstruction/icons/YZ_lamino.svg +0 -182
  287. tomwer/app/lamino.py +0 -143
  288. tomwer/core/process/reconstruction/lamino/__init__.py +0 -1
  289. tomwer/core/process/reconstruction/lamino/tofu.py +0 -1000
  290. tomwer/core/process/test/test_lamino.py +0 -76
  291. tomwer/core/test/test_lamino.py +0 -92
  292. tomwer/gui/reconstruction/lamino/__init__.py +0 -31
  293. tomwer/gui/reconstruction/lamino/tofu/TofuOptionLoader.py +0 -107
  294. tomwer/gui/reconstruction/lamino/tofu/__init__.py +0 -1
  295. tomwer/gui/reconstruction/lamino/tofu/misc.py +0 -148
  296. tomwer/gui/reconstruction/lamino/tofu/projections.py +0 -896
  297. tomwer/gui/reconstruction/lamino/tofu/settings.py +0 -75
  298. tomwer/gui/reconstruction/lamino/tofu/tofu.py +0 -432
  299. tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +0 -567
  300. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +0 -760
  301. tomwer/gui/reconstruction/test/test_lamino.py +0 -189
  302. tomwer/resources/gui/icons/esrf_1.svg +0 -307
  303. tomwer/resources/gui/icons/lamino_parameters.svg +0 -70
  304. tomwer/resources/gui/icons/triangle.svg +0 -80
  305. tomwer/resources/gui/illustrations/lamino_angle.png +0 -0
  306. tomwer/resources/gui/illustrations/lamino_angle.svg +0 -509
  307. tomwer/resources/gui/illustrations/lamino_beta_angle.png +0 -0
  308. tomwer/resources/gui/illustrations/lamino_beta_angle.svg +0 -97
  309. tomwer/resources/gui/illustrations/lamino_theta_angle.png +0 -0
  310. tomwer/resources/gui/illustrations/lamino_theta_angle.svg +0 -368
  311. tomwer/resources/gui/illustrations/manual_slice.png +0 -0
  312. tomwer/resources/gui/illustrations/manual_slice.svg +0 -221
  313. tomwer/resources/gui/illustrations/psi_angle.png +0 -0
  314. tomwer/resources/gui/illustrations/psi_angle.svg +0 -479
  315. tomwer/resources/gui/illustrations/rotation_center.png +0 -0
  316. tomwer/resources/gui/illustrations/rotation_center.svg +0 -276
  317. tomwer/resources/gui/illustrations/slice_stack.png +0 -0
  318. tomwer/resources/gui/illustrations/slice_stack.svg +0 -266
  319. tomwer/resources/gui/illustrations/xy_slice.png +0 -0
  320. tomwer/resources/gui/illustrations/xy_slice.svg +0 -269
  321. tomwer/resources/gui/illustrations/xz_slice.png +0 -0
  322. tomwer/resources/gui/illustrations/xz_slice.svg +0 -270
  323. tomwer/resources/gui/illustrations/yz_slice.png +0 -0
  324. tomwer/resources/gui/illustrations/yz_slice.svg +0 -270
  325. tomwer/synctools/stacks/reconstruction/lamino.py +0 -233
  326. tomwer/synctools/test/test_scanstages.py +0 -162
  327. tomwer/tests/utils/__init__.py +0 -247
  328. tomwer/tests/utils/utilstest.py +0 -220
  329. tomwer-1.2.1-py3.11-nspkg.pth +0 -1
  330. /tomwer/core/process/control/{email.py → emailnotifier.py} +0 -0
  331. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/LICENSE +0 -0
  332. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/entry_points.txt +0 -0
  333. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/namespace_packages.txt +0 -0
  334. {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/top_level.txt +0 -0
@@ -1,760 +0,0 @@
1
- # coding: utf-8
2
- # /*##########################################################################
3
- #
4
- # Copyright (c) 2016-2017 European Synchrotron Radiation Facility
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to deal
8
- # in the Software without restriction, including without limitation the rights
9
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- # copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- # THE SOFTWARE.
23
- #
24
- # ###########################################################################*/
25
-
26
- __authors__ = ["H. Payno"]
27
- __license__ = "MIT"
28
- __date__ = "01/06/2018"
29
-
30
-
31
- import logging
32
- import os
33
-
34
- from silx.gui import qt
35
-
36
- from tomwer.core.process.reconstruction.lamino.tofu import (
37
- LAMINO_ANGLE_TYPE,
38
- PSI_ANGLE_TYPE,
39
- ROTATION_CENTER_TYPE,
40
- SLICE_STACK_TYPE,
41
- )
42
- from tomwer.core.settings import get_lbsram_path
43
- from tomwer.core.utils.char import DELTA_CHAR
44
- from tomwer.gui.reconstruction.lamino.tofu import settings
45
- from tomwer.gui.utils.illustrations import _IllustrationWidget
46
-
47
- from .misc import PadlockButton, _AngleWidget, _RegionLE
48
- from .TofuOptionLoader import _getterSetter, _TofuOptionLoader
49
-
50
- _logger = logging.getLogger(__name__)
51
-
52
-
53
- class OutputTofuWidget(_TofuOptionLoader, qt.QWidget):
54
- """
55
- Main widgets for the tofu reconstruction
56
- """
57
-
58
- def __init__(self, parent):
59
- qt.QWidget.__init__(self, parent)
60
- self._scan_type = "slice stack"
61
- self.__scanID = None
62
- self.setLayout(qt.QGridLayout())
63
-
64
- self._controlWidget = qt.QWidget(parent=self)
65
- self._controlWidget.setLayout(qt.QVBoxLayout())
66
-
67
- self._volumeAngleGrp = VolumeAnglesWidget(parent=self)
68
- self._stepSizeAndRange = StepGroup(parent=self._controlWidget)
69
-
70
- self._planeDisplay = _IllustrationWidget(parent=self)
71
- self._planeDisplay.setMinimumSize(qt.QSize(250, 250))
72
- self._planeDisplay.setSizePolicy(
73
- qt.QSizePolicy.Preferred, qt.QSizePolicy.Preferred
74
- )
75
- self._controlWidget.layout().setContentsMargins(0, 0, 0, 0)
76
- self._controlWidget.layout().addWidget(self._volumeAngleGrp)
77
- self._controlWidget.layout().addWidget(self._stepSizeAndRange)
78
- self._region = RegionGB(parent=self)
79
- self._controlWidget.layout().addWidget(self._region)
80
-
81
- self._outputWidget = _OutputPathWidget(parent=self)
82
- self.layout().addWidget(self._outputWidget, 1, 0, 1, 2)
83
-
84
- self.layout().addWidget(self._controlWidget, 0, 0)
85
- self.layout().addWidget(self._planeDisplay, 0, 1)
86
-
87
- spacer = qt.QWidget(self)
88
- spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
89
- self.layout().addWidget(spacer, 2, 0)
90
-
91
- self._controlWidget.setFixedWidth(500)
92
-
93
- # signal/slot connect
94
- self._volumeAngleGrp.sigPlaneChanged.connect(self._updateOutput)
95
-
96
- # expose API
97
- self.getAngles = self._volumeAngleGrp._angles.get
98
- self.getOutput = self._outputWidget.getOutput
99
- self.setOutput = self._outputWidget.setOutput
100
- self.lockOutput = self._outputWidget.lock
101
- self.forceLbsram = self._outputWidget.forceLbsram
102
- self.setForceLbsram = self._outputWidget.setForceLbsram
103
- self.isOutputFolderLocked = self._outputWidget.isLocked
104
- self.removeTiff = self._outputWidget.removeIfExist
105
- self.setRemoveTiff = self._outputWidget.setRemoveIfExist
106
- self.setVolumeAngleX = self._volumeAngleGrp.setVolumeAngleX
107
- self.setVolumeAngleY = self._volumeAngleGrp.setVolumeAngleY
108
- self.setVolumeAngleZ = self._volumeAngleGrp.setVolumeAngleZ
109
- self.getVolumeAngleX = self._volumeAngleGrp.getVolumeAngleX
110
- self.getVolumeAngleY = self._volumeAngleGrp.getVolumeAngleY
111
- self.getVolumeAngleZ = self._volumeAngleGrp.getVolumeAngleZ
112
- self.setRegionSelType = self._stepSizeAndRange.setRegionSelType
113
- self.setRegion = self._stepSizeAndRange.setRegion
114
- self.getRegion = self._stepSizeAndRange.getRegion
115
- self.dryRun = self._outputWidget.dryRun
116
- self.setHighLimit = self._stepSizeAndRange.setHighLimit
117
- self.resetHighLimit = self._stepSizeAndRange.resetHighLimit
118
- self.getZ = self._stepSizeAndRange.getZ
119
- self.setZ = self._stepSizeAndRange.setZ
120
-
121
- options = {
122
- "x-region": _getterSetter(
123
- getter=self._region.getXRegion, setter=self._region.setXRegionFrmStr
124
- ),
125
- "y-region": _getterSetter(
126
- getter=self._region.getYRegion, setter=self._region.setYRegionFrmStr
127
- ),
128
- "volume-angle-x": _getterSetter(
129
- getter=self.getVolumeAngleX, setter=self.setVolumeAngleX
130
- ),
131
- "volume-angle-y": _getterSetter(
132
- getter=self.getVolumeAngleY, setter=self.setVolumeAngleY
133
- ),
134
- "volume-angle-z": _getterSetter(
135
- getter=self.getVolumeAngleZ, setter=self.setVolumeAngleZ
136
- ),
137
- "region": _getterSetter(getter=self.getRegion, setter=self.setRegion),
138
- "output": _getterSetter(getter=self.getOutput, setter=self.setOutput),
139
- "dry-run": _getterSetter(getter=self.dryRun, setter=self.clearOutput),
140
- "z": _getterSetter(getter=self.getZ, setter=self.setZ),
141
- "rm-tif": _getterSetter(getter=self.removeTiff, setter=self.setRemoveTiff),
142
- }
143
- _TofuOptionLoader.__init__(self, options=options)
144
-
145
- def clearOutput(self, *args, **kwargs):
146
- self._outputWidget.clear()
147
-
148
- def _setImg(self, plane):
149
- assert plane in ("XY", "XZ", "YZ", "manual")
150
- self._planeDisplay.setImage(plane + "_lamino")
151
-
152
- def loadFromScan(self, scanID):
153
- self.__scanID = scanID
154
- self._updateOutput()
155
-
156
- def _updateOutput(self):
157
- if self.__scanID is None:
158
- return
159
- try:
160
- if self.isOutputFolderLocked() is False:
161
- self.setOutput(os.path.join(self.__scanID, self._getNameExtension()))
162
- except Exception as error:
163
- _logger.error(error)
164
-
165
- def setPlane(self, plane):
166
- self._volumeAngleGrp._grpPlane.setPlane(plane=plane)
167
-
168
- def _getNameExtension(self):
169
- """Return the default name extension according to the scan type"""
170
- if self._scan_type == SLICE_STACK_TYPE:
171
- if self._volumeAngleGrp._grpPlane.getPlane() == "XY":
172
- return "xySlice"
173
- elif self._volumeAngleGrp._grpPlane.getPlane() == "XZ":
174
- return "xzSlice"
175
- elif self._volumeAngleGrp._grpPlane.getPlane() == "YZ":
176
- return "yzSlice"
177
- elif self._volumeAngleGrp._grpPlane.getPlane() == "manual":
178
- return "Slice"
179
- elif self._scan_type == ROTATION_CENTER_TYPE:
180
- return "xCenter"
181
- elif self._scan_type == LAMINO_ANGLE_TYPE:
182
- return "ctAngle"
183
- elif self._scan_type in (PSI_ANGLE_TYPE, "psi angle"):
184
- return "rotC"
185
- else:
186
- return "Slice"
187
-
188
- def _setScanType(self, scan_type):
189
- self._scan_type = scan_type
190
- illustration = scan_type
191
- if illustration == "slice stack":
192
- if self._volumeAngleGrp._grpPlane.getPlane() == "XY":
193
- illustration = "xy slice"
194
- elif self._volumeAngleGrp._grpPlane.getPlane() == "XZ":
195
- illustration = "xz slice"
196
- elif self._volumeAngleGrp._grpPlane.getPlane() == "YZ":
197
- illustration = "yz slice"
198
- elif self._volumeAngleGrp._grpPlane.getPlane() == "manual":
199
- illustration = "manual slice"
200
- self._planeDisplay.setImage(illustration)
201
-
202
- self._updateOutput()
203
-
204
-
205
- class PlaneGroup(qt.QGroupBox):
206
- sigPlaneChanged = qt.Signal(str)
207
- """Signal emitted when the plane selection changed"""
208
-
209
- def __init__(self, parent):
210
- qt.QGroupBox.__init__(self, parent=parent, title="Plane selection")
211
-
212
- self.setLayout(qt.QVBoxLayout())
213
- self._XYPlaneRB = qt.QRadioButton("XY", parent=self)
214
- self.layout().addWidget(self._XYPlaneRB)
215
- self._YZPlaneRB = qt.QRadioButton("YZ", parent=self)
216
- self.layout().addWidget(self._YZPlaneRB)
217
- self._XZPlaneRB = qt.QRadioButton("XZ", parent=self)
218
- self.layout().addWidget(self._XZPlaneRB)
219
- self._autoPlaneRB = qt.QRadioButton("manual", parent=self)
220
- self.layout().addWidget(self._autoPlaneRB)
221
-
222
- self._rBtns = (
223
- self._XYPlaneRB,
224
- self._XZPlaneRB,
225
- self._YZPlaneRB,
226
- self._autoPlaneRB,
227
- )
228
- self._XYPlaneRB.setChecked(True)
229
-
230
- for btn in self._rBtns:
231
- btn.toggled.connect(self.__planeChangedCllbck)
232
-
233
- self.setSizePolicy(qt.QSizePolicy.Preferred, qt.QSizePolicy.Preferred)
234
-
235
- def getPlane(self):
236
- if self._XYPlaneRB.isChecked():
237
- return "XY"
238
- if self._YZPlaneRB.isChecked():
239
- return "YZ"
240
- if self._XZPlaneRB.isChecked():
241
- return "XZ"
242
- if self._autoPlaneRB.isChecked():
243
- return "manual"
244
-
245
- def setPlane(self, plane):
246
- assert plane in ("XY", "XZ", "YZ", "manual")
247
- for w in self._rBtns:
248
- w.blockSignals(True)
249
- if plane == "XY":
250
- self._XYPlaneRB.setChecked(True)
251
- elif plane == "XZ":
252
- self._XZPlaneRB.setChecked(True)
253
- elif plane == "YZ":
254
- self._YZPlaneRB.setChecked(True)
255
- else:
256
- self._autoPlaneRB.setChecked(True)
257
- self.sigPlaneChanged.emit(plane)
258
- for w in self._rBtns:
259
- w.blockSignals(False)
260
-
261
- def __planeChangedCllbck(self):
262
- self.sigPlaneChanged.emit(self.getPlane())
263
-
264
- def setManualEdition(self):
265
- self._autoPlaneRB.setChecked(True)
266
-
267
-
268
- class VolumeAnglesWidget(qt.QWidget):
269
- def __init__(self, parent):
270
- qt.QWidget.__init__(self, parent)
271
- self.setLayout(qt.QHBoxLayout())
272
- self._grpPlane = PlaneGroup(parent=self)
273
- self.layout().addWidget(self._grpPlane)
274
- self._angles = _AnglesWidget(parent=self)
275
- self.layout().addWidget(self._angles)
276
-
277
- # API exposed
278
- self.sigPlaneChanged = self._grpPlane.sigPlaneChanged
279
- self.sigAnglesEdited = self._angles.sigAnglesEdited
280
-
281
- self.sigAnglesEdited.connect(self._grpPlane.setManualEdition)
282
- self.sigPlaneChanged.connect(self._resetAngleFor)
283
-
284
- self.setAngles = self._angles.set
285
- self.getAngles = self._angles.get
286
- self.setVolumeAngleX = self._angles.setVolumeAngleX
287
- self.setVolumeAngleY = self._angles.setVolumeAngleY
288
- self.setVolumeAngleZ = self._angles.setVolumeAngleZ
289
- self.getVolumeAngleX = self._angles.getVolumeAngleX
290
- self.getVolumeAngleY = self._angles.getVolumeAngleY
291
- self.getVolumeAngleZ = self._angles.getVolumeAngleZ
292
-
293
- def _resetAngleFor(self, plane):
294
- assert plane in ("XY", "XZ", "YZ", "manual")
295
- if plane == "manual":
296
- return
297
-
298
- if plane == "XY":
299
- self._angles.set(0, 0, 0)
300
- if plane == "XZ":
301
- self._angles.set(90, 0, 0)
302
- if plane == "YZ":
303
- self._angles.set(0, 90, 0)
304
-
305
-
306
- class _AnglesWidget(qt.QWidget):
307
- sigAnglesEdited = qt.Signal()
308
- """Signal emitted when an angle is edited"""
309
-
310
- def __init__(self, parent):
311
- qt.QWidget.__init__(self, parent)
312
- self.setLayout(qt.QVBoxLayout())
313
- self.layout().setContentsMargins(0, 0, 0, 0)
314
- self._spacerTop = qt.QWidget(parent=self)
315
- self._spacerTop.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
316
- self.layout().addWidget(self._spacerTop)
317
-
318
- self._volAngleX = _AngleWidget(parent=self, name="volume angle x")
319
- self.layout().addWidget(self._volAngleX)
320
- self._volAngleY = _AngleWidget(parent=self, name="volume angle y")
321
- self.layout().addWidget(self._volAngleY)
322
- self._volAngleZ = _AngleWidget(parent=self, name="volume angle z")
323
- self.layout().addWidget(self._volAngleZ)
324
- self._spacerBot = qt.QWidget(parent=self)
325
- self._spacerBot.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
326
- self.layout().addWidget(self._spacerBot)
327
-
328
- self._volAngleX.sigEdited.connect(self._haveBeenEdited)
329
- self._volAngleY.sigEdited.connect(self._haveBeenEdited)
330
- self._volAngleZ.sigEdited.connect(self._haveBeenEdited)
331
-
332
- # aliases
333
- self.setVolumeAngleX = self._volAngleX.setAngle
334
- self.setVolumeAngleY = self._volAngleY.setAngle
335
- self.setVolumeAngleZ = self._volAngleZ.setAngle
336
- self.getVolumeAngleX = self._volAngleX.getAngle
337
- self.getVolumeAngleY = self._volAngleY.getAngle
338
- self.getVolumeAngleZ = self._volAngleZ.getAngle
339
-
340
- def _haveBeenEdited(self):
341
- self.sigAnglesEdited.emit()
342
-
343
- def set(self, xAngle, yAngle, zAngle):
344
- self.blockSignals(True)
345
- self.setVolumeAngleX(xAngle)
346
- self.setVolumeAngleY(yAngle)
347
- self.setVolumeAngleZ(zAngle)
348
- self.blockSignals(False)
349
-
350
- def get(self):
351
- """
352
-
353
- :return: tuple of (anglex, angley, anglez)
354
- """
355
- return (
356
- self._volAngleX.getAngle(),
357
- self._volAngleY.getAngle(),
358
- self._volAngleZ.getAngle(),
359
- )
360
-
361
-
362
- class StepGroup(qt.QGroupBox):
363
- sigSelectionChanged = qt.Signal()
364
- """Signal emitted when the selection changed"""
365
-
366
- _NB_SLICE_NAME = "number of slices"
367
- _RANGE_NAME = "range"
368
-
369
- _TITLE = "Cut selection"
370
-
371
- def __init__(self, parent):
372
- qt.QGroupBox.__init__(self, parent=parent, title=StepGroup._TITLE)
373
- self._xcenter = 0.0
374
- self.__mediumLimit = settings._N_SLICE_LIMITS_MEDIUM
375
- self.__highLimit = settings._N_SLICE_LIMITS_HIGH
376
-
377
- self._defaultStyleSheet = ""
378
- self._mediumLimitStyleSheet = (
379
- "QLineEdit {" + self._convertToStyleSheetColor(settings._COLOR_MEDIUM) + "}"
380
- )
381
- self._highLimitStyleSheet = (
382
- "QLineEdit {" + self._convertToStyleSheetColor(settings._COLOR_HIGH) + "}"
383
- )
384
-
385
- self.setLayout(qt.QGridLayout())
386
-
387
- # z
388
- self._z_label = qt.QLabel("z", parent=self)
389
- self.layout().addWidget(self._z_label, 0, 0)
390
- self._zSB = qt.QSpinBox(parent=self)
391
- self._zSB.setMinimum(-99999)
392
- self._zSB.setValue(0)
393
- self.layout().addWidget(self._zSB, 0, 1)
394
-
395
- # step size
396
- self._stepLabel = qt.QLabel("", parent=self)
397
- self.layout().addWidget(self._stepLabel, 1, 0)
398
-
399
- self._stepSize = qt.QLineEdit("1.0", parent=self)
400
- validator = qt.QDoubleValidator(parent=self._stepSize)
401
- validator.setBottom(0)
402
- self._stepSize.setValidator(validator)
403
- self.layout().addWidget(self._stepSize, 1, 1, 1, 6)
404
-
405
- style = qt.QApplication.style()
406
- icon = style.standardIcon(qt.QStyle.SP_MessageBoxWarning)
407
- self._warningLabel = qt.QLabel("", parent=self)
408
- self._warningLabel.setPixmap(icon.pixmap(30, state=qt.QIcon.On))
409
- self._warningLabel.setVisible(False)
410
- self._warningLabel.setToolTip(
411
- "Number of slice to reconstruct seems to high, might fail"
412
- )
413
-
414
- self.layout().addWidget(self._warningLabel, 1, 7, 1, 1)
415
-
416
- # selection mode
417
- self.layout().addWidget(qt.QLabel("selection mode:"), 2, 0)
418
- self._selModeTooltips = {
419
- self._NB_SLICE_NAME: "Will pick n slices from centered in the center, "
420
- "spaced of step size",
421
- self._RANGE_NAME: "Will pick slices from a range, each spaced of "
422
- "step size",
423
- }
424
- self._selectionMode = qt.QComboBox(parent=self)
425
- self._selectionMode.addItem(self._NB_SLICE_NAME)
426
- idx = self._selectionMode.findText(self._NB_SLICE_NAME)
427
- self._selectionMode.setItemData(
428
- idx, self._selModeTooltips[self._NB_SLICE_NAME], qt.Qt.ToolTipRole
429
- )
430
- self._selectionMode.addItem(self._RANGE_NAME)
431
- idx = self._selectionMode.findText(self._RANGE_NAME)
432
- self._selectionMode.setItemData(
433
- idx, self._selModeTooltips[self._RANGE_NAME], qt.Qt.ToolTipRole
434
- )
435
- self.layout().addWidget(self._selectionMode, 2, 1)
436
-
437
- self._nCutLE = qt.QLineEdit(str(-settings.SLICE_STACK_STEP_SIZE), self)
438
- validator = qt.QIntValidator(parent=self._nCutLE)
439
- validator.setBottom(1)
440
- self._nCutLE.setValidator(validator)
441
- self.layout().addWidget(self._nCutLE, 2, 2)
442
-
443
- self._fromLabel = qt.QLabel("from:", self)
444
- self.layout().addWidget(self._fromLabel, 2, 3)
445
- self._fromLE = qt.QLineEdit(str(-settings.SLICE_STACK_RANGE_HS), self)
446
- validator = qt.QDoubleValidator(parent=self._fromLE)
447
- self._fromLE.setValidator(validator)
448
- self.layout().addWidget(self._fromLE, 2, 4)
449
- self._toLabel = qt.QLabel("to:", self)
450
- self.layout().addWidget(self._toLabel, 2, 5)
451
- self._toLE = qt.QLineEdit(str(settings.SLICE_STACK_RANGE_HS), self)
452
- validator = qt.QDoubleValidator(parent=self._toLE)
453
- self._toLE.setValidator(validator)
454
- self.layout().addWidget(self._toLE, 2, 6)
455
-
456
- self.setRegionSelType(self._RANGE_NAME)
457
- self._selectionMode.currentIndexChanged[str].connect(self.setRegionSelType)
458
- self._setStepSizeType("(pixel)")
459
-
460
- # connect signals / SLOT
461
- for widget in (self._nCutLE, self._stepSize, self._toLE, self._fromLE):
462
- widget.textChanged.connect(self._updateLimitsColor)
463
-
464
- @staticmethod
465
- def _convertToStyleSheetColor(color):
466
- assert type(color) is tuple
467
- _color = []
468
- [_color.append(str(c)) for c in color]
469
- return "color: rgb(" + ",".join(_color) + ")"
470
-
471
- def _setStepSizeType(self, _type):
472
- assert type(_type) is str
473
- self._stepLabel.setText(" ".join(("Step size -", DELTA_CHAR, _type)))
474
-
475
- def setRegionSelType(self, selType):
476
- """
477
-
478
- :param str selType: should be in ('range', 'number of cut')
479
- """
480
- assert selType in (self._RANGE_NAME, self._NB_SLICE_NAME)
481
- index = self._selectionMode.findText(selType)
482
- assert index >= 0
483
- self._selectionMode.blockSignals(True)
484
- self._selectionMode.setCurrentIndex(index)
485
- self._selectionMode.setToolTip(self._selModeTooltips[selType])
486
- for w in (self._fromLE, self._toLE, self._toLabel, self._fromLabel):
487
- w.setVisible(selType == self._RANGE_NAME)
488
- self._nCutLE.setVisible(selType == self._NB_SLICE_NAME)
489
- self._selectionMode.blockSignals(False)
490
- self.sigSelectionChanged.emit()
491
-
492
- def getSelectionType(self):
493
- """Return active selected mode ('range' or 'number of cut')"""
494
- return self._selectionMode.currentText()
495
-
496
- def getStepSize(self):
497
- """Return step size in fofu ref (meter)"""
498
- return float(self._stepSize.text())
499
-
500
- def getNCut(self):
501
- if self.getSelectionType() != self._NB_SLICE_NAME:
502
- return None
503
- else:
504
- return int(self._nCutLE.text())
505
-
506
- def setNCut(self, ncut):
507
- self._nCutLE.setText(str(ncut))
508
-
509
- def getRegion(self):
510
- if self.getSelectionType() == self._NB_SLICE_NAME:
511
- start_from = self._xcenter
512
- if self._zSB.isVisible() is True:
513
- start_from = self.getZ() or 0.0
514
- nbCut = self.getNCut()
515
- if nbCut is None:
516
- raise ValueError("couldn't find nb cut")
517
- else:
518
- _from = (
519
- -nbCut / 2 * self.getStepSize() # pylint: disable=E1130
520
- + start_from
521
- )
522
- _to = nbCut / 2 * self.getStepSize() + start_from
523
- return _from, _to, self.getStepSize()
524
- else:
525
- start_from = 0.0
526
- if self._zSB.isVisible() is True:
527
- start_from = self.getZ() or 0.0
528
- # question: are from, to always integers ?
529
- return (
530
- float(self._fromLE.text()) + start_from,
531
- float(self._toLE.text()) + start_from,
532
- float(self.getStepSize()),
533
- )
534
-
535
- def setRegion(self, region):
536
- if type(region) is str:
537
- try:
538
- _from, _to, step_size = region.split(",")
539
- except Exception:
540
- _logger.warning(
541
- "Fail to setRegion range. given string "
542
- "does not fir the standard (from, to, stepSize)"
543
- )
544
- return
545
- else:
546
- assert type(region) is tuple
547
- _from, _to, step_size = region
548
- _from, _to, step_size = str(_from), str(_to), str(step_size)
549
-
550
- self._fromLE.setText(_from)
551
- self._toLE.setText(_to)
552
- self._stepSize.setText(step_size)
553
-
554
- def _updateLimitsColor(self, *argv, **kwargs):
555
- warning = False
556
- if self._isUpperHightLimit() is True:
557
- styleSheet = self._highLimitStyleSheet
558
- warning = True
559
- elif self._isUpperMediumLimit() is True:
560
- styleSheet = self._mediumLimitStyleSheet
561
- warning = True
562
- else:
563
- styleSheet = self._defaultStyleSheet
564
-
565
- for widget in (self._fromLE, self._toLE, self._nCutLE, self._stepSize):
566
- widget.blockSignals(True)
567
-
568
- self.setStyleSheet(styleSheet)
569
-
570
- for widget in (self._fromLE, self._toLE, self._nCutLE, self._stepSize):
571
- widget.blockSignals(False)
572
-
573
- self._warningLabel.setVisible(warning)
574
-
575
- def _isUpperMediumLimit(self):
576
- return self._getNSlices() > self.__mediumLimit
577
-
578
- def _isUpperHightLimit(self):
579
- return self._getNSlices() > self.__highLimit
580
-
581
- def _getNSlices(self):
582
- """
583
-
584
- :return: number of slice to be reconstructed
585
- :rtype: int
586
- """
587
- if self.getSelectionType() == self._NB_SLICE_NAME:
588
- return self.getNCut()
589
- else:
590
- # as this cast is made during edition, several value can fail on the
591
- # float conversion or division
592
- try:
593
- _from = float(self._fromLE.text())
594
- _to = float(self._toLE.text())
595
- _step = float(self.getStepSize())
596
- return int((_to - _from) / _step)
597
- except Exception:
598
- return 1.0
599
-
600
- def setHighLimit(self, val):
601
- if val == self.__highLimit:
602
- return
603
- if val is None:
604
- self.resetHighLimit()
605
- return
606
- if val <= 0.0:
607
- _logger.error("incoherent height limit: %s" % val)
608
- return
609
-
610
- self.__highLimit = val
611
- self._updateLimitsColor()
612
-
613
- def resetHighLimit(self):
614
- self.__highLimit = settings._N_SLICE_LIMITS_HIGH
615
- self._updateLimitsColor()
616
-
617
- def getZ(self):
618
- if self._zSB.isVisible():
619
- return self._zSB.value()
620
- else:
621
- return None
622
-
623
- def setZ(self, value):
624
- if value is None:
625
- return
626
- return self._zSB.setValue(int(value))
627
-
628
- def _setXCenter(self, xcenter):
629
- self._xcenter = xcenter
630
-
631
-
632
- class RegionGB(qt.QGroupBox):
633
- def __init__(self, parent):
634
- super().__init__("ROI", parent=parent)
635
- self.setLayout(qt.QVBoxLayout())
636
- self._xRegion = _RegionLE(name="x ROI", parent=self)
637
- self.layout().addWidget(self._xRegion)
638
- self._yRegion = _RegionLE(name="y ROI", parent=self)
639
- self.layout().addWidget(self._yRegion)
640
-
641
- # expose API
642
- self.getXRegion = self._xRegion.getRegion
643
- self.getYRegion = self._yRegion.getRegion
644
- self.setXRegion = self._xRegion.setRegion
645
- self.setYRegion = self._yRegion.setRegion
646
- self.setXRegionFrmStr = self._xRegion.setRegionFromStr
647
- self.setYRegionFrmStr = self._yRegion.setRegionFromStr
648
-
649
-
650
- class _OutputPathWidget(qt.QGroupBox):
651
- class _OptionsWidget(qt.QWidget):
652
- def __init__(self, parent):
653
- super().__init__(parent)
654
- self.setLayout(qt.QHBoxLayout())
655
- self.layout().setContentsMargins(0, 0, 0, 0)
656
-
657
- self.forceLbsram = qt.QCheckBox("force lbsram", parent=self)
658
- self.forceLbsram.setToolTip("Make sure reconstruction is saved in lbsram")
659
- self.layout().addWidget(self.forceLbsram)
660
- self.forceLbsram.setVisible(os.path.exists(get_lbsram_path()))
661
-
662
- self.removeExisting = qt.QCheckBox('rm "*.tif"', parent=self)
663
- self.removeExisting.setToolTip("Remove existing files if any")
664
- self.layout().addWidget(self.removeExisting)
665
- spacer = qt.QWidget(self)
666
- spacer.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Minimum)
667
- self.layout().addWidget(spacer)
668
-
669
- def __init__(self, parent):
670
- super().__init__("output folder", parent)
671
- self.setLayout(qt.QVBoxLayout())
672
- self.layout().setContentsMargins(4, 4, 4, 4)
673
-
674
- self._checkboxWidget = _OutputPathWidget._OptionsWidget(parent=self)
675
- self.layout().addWidget(self._checkboxWidget)
676
-
677
- self._qteFolderSelected = qt.QLineEdit("", parent=self)
678
- style = qt.QApplication.style()
679
- icon = style.standardIcon(qt.QStyle.SP_DialogOpenButton)
680
- self._qtbSelectFolder = qt.QPushButton(icon, "", parent=self)
681
- self._qteFolderSelected.setToolTip(
682
- "If not output folder is given, then" ' this will generate a "dry run"'
683
- )
684
-
685
- self._lockButton = PadlockButton(parent=self)
686
- self._lockButton.toggled.connect(self._dealWithLbsramOptAndLocker)
687
-
688
- leWidget = qt.QWidget(parent=self)
689
- leWidget.setLayout(qt.QHBoxLayout())
690
- leWidget.layout().setContentsMargins(0, 0, 0, 0)
691
- leWidget.layout().addWidget(self._qteFolderSelected)
692
- leWidget.layout().addWidget(self._qtbSelectFolder)
693
- leWidget.layout().addWidget(self._lockButton)
694
- self.layout().addWidget(leWidget)
695
-
696
- # connect signals/SLOT
697
- self._checkboxWidget.forceLbsram.toggled.connect(self._updateLbsramStatus)
698
- self._qtbSelectFolder.clicked.connect(self._setFolderPathFrmDiag)
699
- self._qteFolderSelected.editingFinished.connect(self._checkUpdateforLbsram)
700
-
701
- # add some speaking API
702
- self.clear = self._qteFolderSelected.clear
703
- self.isLocked = self._lockButton.isLocked
704
- self.forceLbsram = self._checkboxWidget.forceLbsram.isChecked
705
- self.setForceLbsram = self._checkboxWidget.forceLbsram.setChecked
706
- self.removeIfExist = self._checkboxWidget.removeExisting.isChecked
707
- self.setRemoveIfExist = self._checkboxWidget.removeExisting.setChecked
708
-
709
- def setOutput(self, text):
710
- if self.forceLbsram() is True and text.startswith(get_lbsram_path()) is False:
711
- text = os.path.join(get_lbsram_path(), text.lstrip(os.sep))
712
- self._qteFolderSelected.setText(text)
713
-
714
- def lock(self, lock=True):
715
- self._lockButton.setChecked(lock)
716
-
717
- def _setFolderPathFrmDiag(self): # pragma: no cover
718
- dialog = qt.QFileDialog(self)
719
- dialog.setFileMode(qt.QFileDialog.DirectoryOnly)
720
-
721
- if not dialog.exec_() or (len(dialog.selectedFiles()) < 1):
722
- dialog.close()
723
- return
724
- self._qteFolderSelected.setText(dialog.selectedFiles()[0])
725
-
726
- def dryRun(self):
727
- """Should we execute a dry-run and avoid storing reconstruction"""
728
- return self.getOutput() is None
729
-
730
- def getOutput(self):
731
- """Return output folder whre the reconstruction should be saved"""
732
- if self._qteFolderSelected.text() == "":
733
- return None
734
- else:
735
- return self.__getOutputWithLbsramExtension()
736
-
737
- def _dealWithLbsramOptAndLocker(self, toggle):
738
- self._checkboxWidget.forceLbsram.setDisabled(toggle)
739
- if toggle:
740
- self._checkboxWidget.forceLbsram.setChecked(False)
741
-
742
- def _updateLbsramStatus(self, toggle):
743
- if toggle is True:
744
- self._qteFolderSelected.setText(self.__getOutputWithLbsramExtension())
745
-
746
- def __getOutputWithLbsramExtension(self):
747
- _output = self._qteFolderSelected.text()
748
- if (
749
- self.forceLbsram() is True
750
- and _output.startswith(get_lbsram_path()) is False
751
- ):
752
- _output = os.path.join(get_lbsram_path(), _output.lstrip(os.sep))
753
- return _output
754
-
755
- def _checkUpdateforLbsram(self):
756
- """Check if the line edit value has to be changed if force lbsram is
757
- active and the line does not start with it"""
758
- if self.forceLbsram() is True:
759
- if not self._qteFolderSelected.text().startswith(get_lbsram_path()):
760
- self._qteFolderSelected.setText(self.__getOutputWithLbsramExtension())