OpenREM 1.0.0b2__py3-none-any.whl → 1.0.0b3__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.
- openrem/locale/de/LC_MESSAGES/django.po +1060 -1059
- openrem/locale/django.pot +973 -972
- openrem/locale/es_MX/LC_MESSAGES/django.po +1049 -1048
- openrem/locale/it/LC_MESSAGES/django.po +1044 -1043
- openrem/locale/lt/LC_MESSAGES/django.po +989 -988
- openrem/locale/nb_NO/LC_MESSAGES/django.po +985 -984
- openrem/locale/pt_BR/LC_MESSAGES/django.po +1003 -1002
- openrem/manage.py +10 -10
- openrem/openremproject/__init__.py +1 -1
- openrem/openremproject/local_settings.py.linux +128 -128
- openrem/openremproject/local_settings.py.windows +144 -144
- openrem/openremproject/local_settings.py.windows-sqlite3 +129 -129
- openrem/openremproject/settings.py +278 -278
- openrem/openremproject/urls.py +32 -32
- openrem/openremproject/wsgi.py.example +28 -28
- openrem/remapp/__init__.py +2 -2
- openrem/remapp/admin.py +31 -31
- openrem/remapp/exports/ct_export.py +780 -753
- openrem/remapp/exports/dx_export.py +817 -805
- openrem/remapp/exports/export_common.py +931 -951
- openrem/remapp/exports/export_common_pandas.py +2422 -0
- openrem/remapp/exports/exportviews.py +815 -860
- openrem/remapp/exports/mg_csv_nhsbsp.py +292 -292
- openrem/remapp/exports/mg_export.py +673 -510
- openrem/remapp/exports/nm_export.py +796 -575
- openrem/remapp/exports/rf_export.py +1418 -1431
- openrem/remapp/extractors/ct_philips.py +424 -414
- openrem/remapp/extractors/ct_toshiba.py +2116 -2108
- openrem/remapp/extractors/dx.py +1033 -952
- openrem/remapp/extractors/extract_common.py +817 -817
- openrem/remapp/extractors/import_views.py +426 -426
- openrem/remapp/extractors/mam.py +685 -672
- openrem/remapp/extractors/nm_image.py +439 -431
- openrem/remapp/extractors/ptsizecsv2db.py +368 -368
- openrem/remapp/extractors/rdsr.py +667 -654
- openrem/remapp/extractors/rdsr_methods.py +1771 -1768
- openrem/remapp/extractors/rrdsr_methods.py +630 -622
- openrem/remapp/fixtures/openskin_safelist.json +11 -11
- openrem/remapp/forms.py +2286 -2277
- openrem/remapp/interface/chart_functions.py +2412 -2393
- openrem/remapp/interface/mod_filters.py +1241 -1243
- openrem/remapp/migrations/0001_initial.py.1-0-upgrade +1043 -1043
- openrem/remapp/models.py +3418 -3407
- openrem/remapp/netdicom/dicomviews.py +681 -683
- openrem/remapp/netdicom/qrscu.py +2646 -2646
- openrem/remapp/netdicom/tools.py +134 -134
- openrem/remapp/static/css/bootstrap-theme.css +587 -587
- openrem/remapp/static/css/bootstrap-theme.min.css +4 -4
- openrem/remapp/static/css/bootstrap.css +6800 -6800
- openrem/remapp/static/css/bootstrap.min.css +4 -4
- openrem/remapp/static/css/datepicker3.css +790 -790
- openrem/remapp/static/css/jquery.qtip.min.css +2 -2
- openrem/remapp/static/css/openrem-extra.css +442 -442
- openrem/remapp/static/css/openrem.css +96 -96
- openrem/remapp/static/css/registration.css +34 -34
- openrem/remapp/static/fonts/glyphicons-halflings-regular.svg +287 -287
- openrem/remapp/static/js/bootstrap-datepicker.js +1671 -1671
- openrem/remapp/static/js/bootstrap.js +2363 -2363
- openrem/remapp/static/js/bootstrap.min.js +6 -6
- openrem/remapp/static/js/charts/chartCommonFunctions.js +75 -75
- openrem/remapp/static/js/charts/chartFullScreen.js +41 -41
- openrem/remapp/static/js/charts/ctChartAjax.js +331 -331
- openrem/remapp/static/js/charts/dxChartAjax.js +290 -290
- openrem/remapp/static/js/charts/mgChartAjax.js +144 -144
- openrem/remapp/static/js/charts/nmChartAjax.js +64 -64
- openrem/remapp/static/js/charts/plotly-2.35.2.min.js +8 -0
- openrem/remapp/static/js/charts/rfChartAjax.js +128 -128
- openrem/remapp/static/js/chroma.min.js +32 -32
- openrem/remapp/static/js/datepicker.js +5 -5
- openrem/remapp/static/js/dicom.js +115 -115
- openrem/remapp/static/js/django_reverse/reverse.js +13 -13
- openrem/remapp/static/js/formatDate.js +7 -7
- openrem/remapp/static/js/html5shiv.min.js +8 -8
- openrem/remapp/static/js/jquery-1.11.0.min.js +4 -4
- openrem/remapp/static/js/npm.js +12 -12
- openrem/remapp/static/js/respond.min.js +4 -4
- openrem/remapp/static/js/skin-dose-maps/jquery.qtip.min.js +4 -4
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dHUDObject.js +112 -112
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dObject.js +367 -367
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dPersonObject.js +158 -158
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapColourScaleObject.js +153 -153
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapObject.js +367 -367
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping.js +584 -584
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping3d.js +255 -255
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMappingAjax.js +267 -212
- openrem/remapp/static/js/skin-dose-maps/three.min.js +835 -835
- openrem/remapp/static/js/sorttable.js +495 -495
- openrem/remapp/templates/base.html +253 -253
- openrem/remapp/templates/registration/changepassword.html +25 -25
- openrem/remapp/templates/registration/changepassworddone.html +12 -12
- openrem/remapp/templates/registration/login.html +42 -42
- openrem/remapp/templates/remapp/backgroundtaskmaximumrows_form.html +29 -29
- openrem/remapp/templates/remapp/base.html +1 -1
- openrem/remapp/templates/remapp/ctdetail.html +235 -235
- openrem/remapp/templates/remapp/ctfiltered.html +310 -310
- openrem/remapp/templates/remapp/dicomdeletesettings_form.html +31 -31
- openrem/remapp/templates/remapp/dicomqr.html +147 -147
- openrem/remapp/templates/remapp/dicomquerydetails.html +83 -83
- openrem/remapp/templates/remapp/dicomqueryimages.html +49 -49
- openrem/remapp/templates/remapp/dicomqueryseries.html +109 -109
- openrem/remapp/templates/remapp/dicomquerysummary.html +48 -48
- openrem/remapp/templates/remapp/dicomremoteqr_confirm_delete.html +60 -60
- openrem/remapp/templates/remapp/dicomremoteqr_form.html +32 -32
- openrem/remapp/templates/remapp/dicomstorescp_confirm_delete.html +53 -53
- openrem/remapp/templates/remapp/dicomstorescp_form.html +48 -48
- openrem/remapp/templates/remapp/dicomsummary.html +257 -257
- openrem/remapp/templates/remapp/displaychartoptions.html +184 -184
- openrem/remapp/templates/remapp/displayhomepageoptions.html +57 -57
- openrem/remapp/templates/remapp/displayname-count.html +6 -6
- openrem/remapp/templates/remapp/displayname-last-date.html +3 -3
- openrem/remapp/templates/remapp/displayname-modality.html +86 -105
- openrem/remapp/templates/remapp/displayname-skinmap.html +18 -18
- openrem/remapp/templates/remapp/displaynameupdate.html +100 -100
- openrem/remapp/templates/remapp/displaynameview.html +222 -219
- openrem/remapp/templates/remapp/dxdetail.html +176 -176
- openrem/remapp/templates/remapp/dxfiltered.html +324 -324
- openrem/remapp/templates/remapp/exports-active.html +25 -25
- openrem/remapp/templates/remapp/exports-complete.html +35 -35
- openrem/remapp/templates/remapp/exports-error.html +26 -26
- openrem/remapp/templates/remapp/exports-queue.html +18 -18
- openrem/remapp/templates/remapp/exports.html +191 -191
- openrem/remapp/templates/remapp/failed_summary_list.html +27 -27
- openrem/remapp/templates/remapp/filteredbase.html +162 -162
- openrem/remapp/templates/remapp/highdosemetricalertsettings_form.html +76 -76
- openrem/remapp/templates/remapp/home-list-modalities.html +94 -94
- openrem/remapp/templates/remapp/home.html +202 -202
- openrem/remapp/templates/remapp/list_filters.html +24 -24
- openrem/remapp/templates/remapp/mgdetail.html +160 -138
- openrem/remapp/templates/remapp/mgfiltered.html +311 -311
- openrem/remapp/templates/remapp/nmdetail.html +300 -300
- openrem/remapp/templates/remapp/nmfiltered.html +255 -255
- openrem/remapp/templates/remapp/notpatient.html +190 -190
- openrem/remapp/templates/remapp/notpatientindicators_form_base.html +81 -81
- openrem/remapp/templates/remapp/notpatientindicatorsid_confirm_delete.html +54 -54
- openrem/remapp/templates/remapp/notpatientindicatorsid_form.html +23 -23
- openrem/remapp/templates/remapp/notpatientindicatorsname_confirm_delete.html +54 -54
- openrem/remapp/templates/remapp/notpatientindicatorsname_form.html +23 -23
- openrem/remapp/templates/remapp/notpatientindicatorsname_form_base.html +85 -85
- openrem/remapp/templates/remapp/openskinsafelist_add.html +130 -130
- openrem/remapp/templates/remapp/openskinsafelist_confirm_delete.html +100 -100
- openrem/remapp/templates/remapp/openskinsafelist_form.html +207 -207
- openrem/remapp/templates/remapp/patientidsettings_form.html +83 -83
- openrem/remapp/templates/remapp/populate_summary_progress.html +83 -83
- openrem/remapp/templates/remapp/populate_summary_progress_error.html +36 -36
- openrem/remapp/templates/remapp/review_failed_imports.html +157 -157
- openrem/remapp/templates/remapp/review_failed_study.html +41 -41
- openrem/remapp/templates/remapp/review_studies_delete_button.html +20 -20
- openrem/remapp/templates/remapp/review_study.html +19 -19
- openrem/remapp/templates/remapp/review_summary_list.html +245 -245
- openrem/remapp/templates/remapp/rf_dose_alert_email_template.html +14 -1
- openrem/remapp/templates/remapp/rfalertnotificationsview.html +59 -59
- openrem/remapp/templates/remapp/rfdetail.html +547 -543
- openrem/remapp/templates/remapp/rfdetailbase.html +18 -18
- openrem/remapp/templates/remapp/rffiltered.html +404 -404
- openrem/remapp/templates/remapp/sizeimports.html +119 -119
- openrem/remapp/templates/remapp/sizeprocess.html +96 -96
- openrem/remapp/templates/remapp/sizeupload.html +110 -110
- openrem/remapp/templates/remapp/skindosemapcalcsettings_form.html +28 -28
- openrem/remapp/templates/remapp/standardname-modality.html +69 -69
- openrem/remapp/templates/remapp/standardnames_confirm_delete.html +71 -71
- openrem/remapp/templates/remapp/standardnames_form.html +87 -87
- openrem/remapp/templates/remapp/standardnamesettings_form.html +41 -41
- openrem/remapp/templates/remapp/standardnamesrefreshall.html +92 -92
- openrem/remapp/templates/remapp/standardnameview.html +103 -103
- openrem/remapp/templates/remapp/study_confirm_delete.html +147 -147
- openrem/remapp/templates/remapp/task_admin.html +265 -265
- openrem/remapp/templates/remapp/tasks.html +76 -76
- openrem/remapp/templatetags/formfilters.py +13 -13
- openrem/remapp/templatetags/proper_paginate.py +38 -38
- openrem/remapp/templatetags/remappduration.py +36 -36
- openrem/remapp/templatetags/sigdig.py +38 -38
- openrem/remapp/templatetags/sort_class_property_value.py +15 -15
- openrem/remapp/templatetags/update_variable.py +20 -20
- openrem/remapp/templatetags/url_replace.py +25 -25
- openrem/remapp/tests/test_charts_common.py +202 -202
- openrem/remapp/tests/test_charts_ct.py +7111 -7111
- openrem/remapp/tests/test_charts_dx.py +3513 -3513
- openrem/remapp/tests/test_charts_mg.py +1116 -1115
- openrem/remapp/tests/test_dcmdatetime.py +189 -189
- openrem/remapp/tests/test_dicom_qr.py +2580 -2580
- openrem/remapp/tests/test_display_name.py +274 -274
- openrem/remapp/tests/test_export_ct_xlsx.py +272 -248
- openrem/remapp/tests/test_export_dx_xlsx.py +137 -134
- openrem/remapp/tests/test_export_mammo_csv.py +242 -242
- openrem/remapp/tests/test_export_rf_xlsx.py +246 -246
- openrem/remapp/tests/test_files/DX-Im-DRGEM.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-GEPristina-2D.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-GEPristina-DBT.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-Giotto-DBT.dcm +0 -0
- openrem/remapp/tests/test_files/skin_map_alphenix.py +590 -590
- openrem/remapp/tests/test_files/skin_map_zee.py +354 -354
- openrem/remapp/tests/test_filters_ct.py +321 -321
- openrem/remapp/tests/test_filters_dx.py +92 -92
- openrem/remapp/tests/test_filters_mammo.py +183 -183
- openrem/remapp/tests/test_filters_rf.py +118 -118
- openrem/remapp/tests/test_get_values.py +72 -72
- openrem/remapp/tests/test_hash_id.py +65 -65
- openrem/remapp/tests/test_import_ct_esr_ge.py +3034 -3034
- openrem/remapp/tests/test_import_ct_philips_rdsr.py +42 -42
- openrem/remapp/tests/test_import_ct_rdsr_multiple.py +256 -256
- openrem/remapp/tests/test_import_ct_rdsr_siemens.py +827 -827
- openrem/remapp/tests/test_import_ct_rdsr_spectrumdynamics.py +91 -91
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_dosecheck.py +67 -67
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_multivaluesd.py +33 -33
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_pixelmed.py +118 -118
- openrem/remapp/tests/test_import_ct_sc_philips.py +44 -44
- openrem/remapp/tests/test_import_dual_rdsr.py +110 -110
- openrem/remapp/tests/test_import_dx.py +1267 -1191
- openrem/remapp/tests/test_import_dx_rdsr.py +1250 -1253
- openrem/remapp/tests/test_import_mam.py +438 -438
- openrem/remapp/tests/test_import_mg_im_hol_proj.py +46 -46
- openrem/remapp/tests/test_import_mg_rdsr.py +586 -586
- openrem/remapp/tests/test_import_nm_image.py +420 -420
- openrem/remapp/tests/test_import_nm_siemens_rdsr.py +396 -396
- openrem/remapp/tests/test_import_px.py +161 -161
- openrem/remapp/tests/test_import_rf_rdsr.py +420 -418
- openrem/remapp/tests/test_missing_date.py +42 -42
- openrem/remapp/tests/test_not_patient.py +60 -60
- openrem/remapp/tests/test_openskin.py +272 -272
- openrem/remapp/tests/test_patient_id_settings.py +72 -72
- openrem/remapp/tests/test_pt_size_import.py +232 -232
- openrem/remapp/tests/test_rf_detail.py +113 -113
- openrem/remapp/tests/test_rf_high_dose_alert.py +361 -361
- openrem/remapp/tools/background.py +361 -361
- openrem/remapp/tools/check_standard_name_status.py +47 -0
- openrem/remapp/tools/check_uid.py +70 -70
- openrem/remapp/tools/dcmdatetime.py +248 -248
- openrem/remapp/tools/default_import.py +44 -47
- openrem/remapp/tools/get_values.py +230 -230
- openrem/remapp/tools/hash_id.py +58 -58
- openrem/remapp/tools/make_skin_map.py +448 -406
- openrem/remapp/tools/not_patient_indicators.py +72 -72
- openrem/remapp/tools/openskin/calc_exp_map.py +173 -173
- openrem/remapp/tools/openskin/geomclass.py +475 -475
- openrem/remapp/tools/openskin/geomfunc.py +433 -432
- openrem/remapp/tools/openskin/skinmap.py +417 -417
- openrem/remapp/tools/populate_summary.py +185 -193
- openrem/remapp/tools/save_skin_map_structure.py +73 -73
- openrem/remapp/tools/send_high_dose_alert_emails.py +238 -207
- openrem/remapp/urls.py +456 -448
- openrem/remapp/version.py +11 -11
- openrem/remapp/views.py +1147 -1052
- openrem/remapp/views_admin.py +3876 -3936
- openrem/remapp/views_charts_ct.py +2110 -2058
- openrem/remapp/views_charts_dx.py +1906 -1836
- openrem/remapp/views_charts_mg.py +1349 -1196
- openrem/remapp/views_charts_nm.py +535 -535
- openrem/remapp/views_charts_rf.py +1219 -1241
- openrem/remapp/views_openskin.py +379 -384
- openrem/sample-config/openrem-consumer.service +12 -12
- openrem/sample-config/openrem-gunicorn.service +13 -13
- openrem/sample-config/openrem-server +14 -13
- openrem/sample-config/openrem_orthanc_config_linux.lua +454 -454
- openrem/sample-config/openrem_orthanc_config_windows.lua +455 -455
- openrem/sample-config/queue-init.bat +73 -73
- openrem/scripts/openrem_ctphilips.py +25 -25
- openrem/scripts/openrem_cttoshiba.py +28 -28
- openrem/scripts/openrem_dx.py +22 -22
- openrem/scripts/openrem_mg.py +22 -22
- openrem/scripts/openrem_nm.py +22 -22
- openrem/scripts/openrem_ptsizecsv.py +17 -17
- openrem/scripts/openrem_qr.py +12 -12
- openrem/scripts/openrem_rdsr.py +25 -25
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/METADATA +39 -29
- openrem-1.0.0b3.dist-info/RECORD +379 -0
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/WHEEL +1 -1
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/COPYING-GPLv3 +674 -674
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/LICENSE +22 -22
- OpenREM-1.0.0b2.dist-info/RECORD +0 -373
- openrem/remapp/static/js/charts/plotly-2.17.1.min.js +0 -8
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ctphilips.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_cttoshiba.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_dx.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_mg.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_nm.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ptsizecsv.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_qr.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_rdsr.py +0 -0
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/top_level.txt +0 -0
|
@@ -1,432 +1,433 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
axis =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
[
|
|
171
|
-
[2 * (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
x
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
target1_length =
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
+ math.pow(target1_vec[
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
target2_length =
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
+ math.pow(target2_vec[
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
[1.
|
|
312
|
-
[1.3, 1.
|
|
313
|
-
[1.3, 1.4, 1.4, 1.
|
|
314
|
-
[1.3, 1.4, 1.
|
|
315
|
-
[1.3, 1.
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
[1.3, 1.4, 1.
|
|
320
|
-
[1.3, 1.
|
|
321
|
-
[1.
|
|
322
|
-
[1.4, 1.5, 1.
|
|
323
|
-
[1.4, 1.5, 1.7, 1.7],
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
[1.3, 1.
|
|
328
|
-
[1.3, 1.5, 1.6, 1.
|
|
329
|
-
[1.
|
|
330
|
-
[1.4, 1.5, 1.
|
|
331
|
-
[1.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
[1.3, 1.5, 1.
|
|
336
|
-
[1.3, 1.5, 1.6, 1.
|
|
337
|
-
[1.3, 1.5, 1.6, 1.7],
|
|
338
|
-
[1.3, 1.5, 1.6, 1.7],
|
|
339
|
-
[1.3, 1.5, 1.6, 1.7],
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
[0.
|
|
393
|
-
[0.
|
|
394
|
-
[0.
|
|
395
|
-
[0.
|
|
396
|
-
[0.86, 0.87, 0.
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
[0.
|
|
425
|
-
[0.
|
|
426
|
-
[0.
|
|
427
|
-
[0.
|
|
428
|
-
[0.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
1
|
+
"""
|
|
2
|
+
Copyright 2016 Jonathan Cole
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import math
|
|
20
|
+
import numpy as np
|
|
21
|
+
from .geomclass import Triangle3, Segment3
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def intersect(a_ray, a_triangle):
|
|
25
|
+
"""Derived from example code at http://geomalgorithms.com/a06-_intersect-2.html
|
|
26
|
+
provided under the following license:
|
|
27
|
+
|
|
28
|
+
Copyright 2001 softSurfer, 2012 Dan Sunday
|
|
29
|
+
This code may be freely used and modified for any purpose
|
|
30
|
+
providing that this copyright notice is included with it.
|
|
31
|
+
SoftSurfer makes no warranty for this code, and cannot be held
|
|
32
|
+
liable for any real or imagined damage resulting from its use.
|
|
33
|
+
Users of this code must verify correctness for their application.
|
|
34
|
+
|
|
35
|
+
This function checks if a ray intersects a triangle
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
a_ray: the ray (Segment3) being projected
|
|
39
|
+
a_triangle: the triangle (Triangle3) to hit
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
A string describing the status of the hit.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
# Get triangle plane normal
|
|
46
|
+
plane_normal = np.cross(a_triangle.vector_ab, a_triangle.vector_ac)
|
|
47
|
+
if np.array_equal(plane_normal, [0, 0, 0]):
|
|
48
|
+
output = "degenerate"
|
|
49
|
+
return output
|
|
50
|
+
|
|
51
|
+
# Determine if ray intersects with triangle plane
|
|
52
|
+
w0 = a_ray.source - a_triangle.point_a
|
|
53
|
+
a = -np.dot(plane_normal, w0)
|
|
54
|
+
b = np.dot(plane_normal, a_ray.vector)
|
|
55
|
+
|
|
56
|
+
# Get the intersection point of the ray with the triangle plane
|
|
57
|
+
if abs(b) < 0.00000001:
|
|
58
|
+
output = "same plane"
|
|
59
|
+
return output
|
|
60
|
+
|
|
61
|
+
r = a / b
|
|
62
|
+
if r < 0.0:
|
|
63
|
+
output = "away from triangle"
|
|
64
|
+
return output
|
|
65
|
+
|
|
66
|
+
intersect_point = a_ray.source + r * a_ray.vector
|
|
67
|
+
|
|
68
|
+
# Determine if intersection point is within inside the triangle
|
|
69
|
+
uu = np.dot(a_triangle.vector_ab, a_triangle.vector_ab)
|
|
70
|
+
uv = np.dot(a_triangle.vector_ab, a_triangle.vector_ac)
|
|
71
|
+
vv = np.dot(a_triangle.vector_ac, a_triangle.vector_ac)
|
|
72
|
+
w = intersect_point - a_triangle.point_a
|
|
73
|
+
wu = np.dot(w, a_triangle.vector_ab)
|
|
74
|
+
wv = np.dot(w, a_triangle.vector_ac)
|
|
75
|
+
d = uv * uv - uu * vv
|
|
76
|
+
|
|
77
|
+
s = (uv * wv - vv * wu) / d
|
|
78
|
+
t = (uv * wu - uu * wv) / d
|
|
79
|
+
|
|
80
|
+
# Hit some precision problems so either use this fix or use an exact maths library. This seems easier for now.
|
|
81
|
+
|
|
82
|
+
if s < 0.0 or s > 1.000000000001: # Technically >1 but for the rounding errors.
|
|
83
|
+
output = "outside test 1"
|
|
84
|
+
elif t < 0.0 or (s + t) > 1.000000000001:
|
|
85
|
+
output = "outside test 2" + "S:" + str(s) + " t:" + str(t)
|
|
86
|
+
else:
|
|
87
|
+
output = "hit"
|
|
88
|
+
|
|
89
|
+
return output
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def collimate( # pylint: disable=too-many-locals
|
|
93
|
+
a_ray, area, d_ref, lr_angle, cc_angle
|
|
94
|
+
):
|
|
95
|
+
"""This function produces a pair of triangles representing a square field
|
|
96
|
+
of a collimated x-ray beam. These are then used for intersection checks to
|
|
97
|
+
see if the phantom cell sees radiation.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
a_ray: the x-ray beam from focus to isocentre as a Segment3
|
|
101
|
+
area: an area of the beam in square centimetres at any arbitrary distance
|
|
102
|
+
d_ref: the reference distance the area is defined at
|
|
103
|
+
lr_angle: the left-right angle. +90 is detector to the patient's left
|
|
104
|
+
cc_angle: the cranial-caudal angle in degrees. +90 is detector to the head
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
A tuple of two touching triangles making a square field oriented
|
|
108
|
+
perpendicular to the beam direction.
|
|
109
|
+
"""
|
|
110
|
+
side_length = math.sqrt(area) * 10 / d_ref # Side at 10 cm
|
|
111
|
+
|
|
112
|
+
# Get the angles in radians and correct the sign on LR to account for our patient coordinate system
|
|
113
|
+
lr_rads = math.radians(-lr_angle)
|
|
114
|
+
cc_rads = math.radians(cc_angle)
|
|
115
|
+
|
|
116
|
+
# Set up a default vecotr pointing up Z
|
|
117
|
+
up_point = np.array([0, 0, 10])
|
|
118
|
+
|
|
119
|
+
# Get the rotation matrix for LR (rotation around Y)
|
|
120
|
+
rot_mat_lr = rotation_matrix(np.array([0, 1, 0]), lr_rads)
|
|
121
|
+
|
|
122
|
+
# Rotate our default vector for LR
|
|
123
|
+
rot_vector = np.dot(up_point, rot_mat_lr)
|
|
124
|
+
|
|
125
|
+
# Create a new axis of rotation 90 degrees from the current vector to do CC rotation
|
|
126
|
+
new_up_point = np.array([-rot_vector[2], 0, rot_vector[0]])
|
|
127
|
+
|
|
128
|
+
# Get the rotation matrix for CC
|
|
129
|
+
rot_mat_cc = rotation_matrix(new_up_point, cc_rads)
|
|
130
|
+
|
|
131
|
+
# Set up a series of vectors for each corner of the square field
|
|
132
|
+
vec1 = np.array([(side_length / 2), (side_length / 2), 10])
|
|
133
|
+
vec2 = np.array([-(side_length / 2), (side_length / 2), 10])
|
|
134
|
+
vec3 = np.array([(side_length / 2), -(side_length / 2), 10])
|
|
135
|
+
vec4 = np.array([-(side_length / 2), -(side_length / 2), 10])
|
|
136
|
+
|
|
137
|
+
# Rotate each corner vector by LR and then by CC rotation matrices
|
|
138
|
+
point_a = a_ray.source + np.dot(np.dot(vec1, rot_mat_lr), rot_mat_cc)
|
|
139
|
+
point_b = a_ray.source + np.dot(np.dot(vec2, rot_mat_lr), rot_mat_cc)
|
|
140
|
+
point_c = a_ray.source + np.dot(np.dot(vec3, rot_mat_lr), rot_mat_cc)
|
|
141
|
+
point_d = a_ray.source + np.dot(np.dot(vec4, rot_mat_lr), rot_mat_cc)
|
|
142
|
+
|
|
143
|
+
# Build two triangles representing the square field
|
|
144
|
+
triangle_1 = Triangle3(point_d, point_b, point_c)
|
|
145
|
+
triangle_2 = Triangle3(point_a, point_b, point_c)
|
|
146
|
+
|
|
147
|
+
return triangle_1, triangle_2
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def rotation_matrix(axis, theta): # pylint: disable=too-many-locals
|
|
151
|
+
"""
|
|
152
|
+
Return the rotation matrix for a rotation theta radians about an arbitrary axis.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
axis: a vector representing the axis of rotation
|
|
156
|
+
theta: the angle of rotation in radians
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
A numpy array containing the rotation matrix which can then be applied to a point or vector
|
|
160
|
+
"""
|
|
161
|
+
axis = np.asarray(axis)
|
|
162
|
+
axis = axis / math.sqrt(np.dot(axis, axis))
|
|
163
|
+
a = math.cos(theta / 2.0)
|
|
164
|
+
b, c, d = -axis * math.sin(theta / 2.0)
|
|
165
|
+
aa, bb, cc, dd = a * a, b * b, c * c, d * d
|
|
166
|
+
bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d
|
|
167
|
+
|
|
168
|
+
return np.array(
|
|
169
|
+
[
|
|
170
|
+
[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac)],
|
|
171
|
+
[2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)],
|
|
172
|
+
[2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc],
|
|
173
|
+
]
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def build_ray(
|
|
178
|
+
table_longitudinal, table_lateral, table_height, lr_angle, cc_angle, d_ref
|
|
179
|
+
):
|
|
180
|
+
"""This function takes RDSR geometry information and uses it to build
|
|
181
|
+
an x-ray (Segment3) taking into account translation and rotation.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
table_longitudinal: the table longitudinal offset as defined in the DICOM statement
|
|
185
|
+
table_lateral: the table lateral offset as defined in the DICOM statement
|
|
186
|
+
table_height: the table height offset as defined in the DICOM statement
|
|
187
|
+
lr_angle: the left-right angle. +90 is detector to the patient's left
|
|
188
|
+
cc_angle: the cranial-caudal angle in degrees. +90 is detector to the head
|
|
189
|
+
d_ref: the reference distance to the isocentre
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
A ray (Segment3) representing the x-ray beam.
|
|
193
|
+
"""
|
|
194
|
+
# Co-ordinate system: pat L is +ve x, pat feet is + y, ceiling is + z (HFS)
|
|
195
|
+
x = 0
|
|
196
|
+
y = 0
|
|
197
|
+
z = -d_ref
|
|
198
|
+
|
|
199
|
+
lr_rads = math.radians(-lr_angle)
|
|
200
|
+
cc_rads = math.radians(cc_angle)
|
|
201
|
+
up_point = np.array([0, 0, 10])
|
|
202
|
+
rot_mat_lr = rotation_matrix(np.array([0, 1, 0]), lr_rads)
|
|
203
|
+
rot_vector = np.dot(up_point, rot_mat_lr)
|
|
204
|
+
|
|
205
|
+
new_up_point = np.array([-rot_vector[2], 0, rot_vector[0]])
|
|
206
|
+
rot_mat_cc = rotation_matrix(new_up_point, cc_rads)
|
|
207
|
+
|
|
208
|
+
source = np.array([x, y, z])
|
|
209
|
+
rotated_source = np.dot(np.dot(source, rot_mat_lr), rot_mat_cc)
|
|
210
|
+
|
|
211
|
+
z_translated = rotated_source[2] + table_height
|
|
212
|
+
x_translated = rotated_source[0] - table_longitudinal
|
|
213
|
+
y_translated = rotated_source[1] + table_lateral
|
|
214
|
+
|
|
215
|
+
focus = np.array([x_translated, y_translated, z_translated])
|
|
216
|
+
|
|
217
|
+
isocentre = np.array([x - table_longitudinal, y + table_lateral, 0 + table_height])
|
|
218
|
+
|
|
219
|
+
my_ray = Segment3(focus, isocentre)
|
|
220
|
+
|
|
221
|
+
return my_ray
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def check_orthogonal(segment1, segment2):
|
|
225
|
+
"""This function checks whether two segments are within 90 degrees
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
segment1: A Segment3 line segment
|
|
229
|
+
segment2: Another Segment3 line segment
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
A boolean: true if the segments are within 90 degrees,
|
|
233
|
+
false if outside.
|
|
234
|
+
"""
|
|
235
|
+
return np.dot(segment1.vector, segment2.vector) >= 0
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def check_miss(source, centre, target1, target2):
|
|
239
|
+
"""This function compares two angles between a source and two targets.
|
|
240
|
+
If the second target is at a steeper angle than the first, it misses.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
source: the shared start point
|
|
244
|
+
centre: the reference point to angle against
|
|
245
|
+
target1: the triangle corner
|
|
246
|
+
target2: the ray cell target
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
A boolean: true if the second target misses.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
main_line = centre - source
|
|
253
|
+
main_length = np.linalg.norm(main_line)
|
|
254
|
+
target1_vec = target1 - source
|
|
255
|
+
# target1_length = np.linalg.norm(target1_vec)
|
|
256
|
+
target1_length = math.sqrt(
|
|
257
|
+
math.pow(target1_vec[0], 2)
|
|
258
|
+
+ math.pow(target1_vec[1], 2)
|
|
259
|
+
+ math.pow(target1_vec[2], 2)
|
|
260
|
+
)
|
|
261
|
+
target2_vec = target2 - source
|
|
262
|
+
# target2_length = np.linalg.norm(target2_vec)
|
|
263
|
+
target2_length = math.sqrt(
|
|
264
|
+
math.pow(target2_vec[0], 2)
|
|
265
|
+
+ math.pow(target2_vec[1], 2)
|
|
266
|
+
+ math.pow(target2_vec[2], 2)
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
angle1 = np.arccos(np.dot(main_line, target1_vec) / (main_length * target1_length))
|
|
270
|
+
angle2 = np.arccos(np.dot(main_line, target2_vec) / (main_length * target2_length))
|
|
271
|
+
|
|
272
|
+
return abs(angle2) > abs(angle1)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def find_nearest(array, value):
|
|
276
|
+
"""This function finds the closest match to a value from an array.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
The array to search and the value to compare.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
The index of the matching value.
|
|
283
|
+
"""
|
|
284
|
+
return (np.abs(array - value)).argmin()
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def get_bsf(tube_voltage, cu_thickness, size):
|
|
288
|
+
"""This function gives a BSF and f-factor combined. Data from:
|
|
289
|
+
Backscatter factors and mass energy-absorption coefficient ratios for diagnostic radiology dosimetry
|
|
290
|
+
Hamza Benmakhlouf et al 2011 Phys. Med. Biol. 56 7179 doi:10.1088/0031-9155/56/22/012
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
tube_voltage: The peak kilovoltage
|
|
294
|
+
cu_thickness: the added copper filtration in mm. In addition, 3.1 mm Al is assumed by default
|
|
295
|
+
size: The side of the square field incident on the patient
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
A combined backscatter factor and f-factor.
|
|
299
|
+
"""
|
|
300
|
+
kv_table = np.array([50, 80, 110, 150])
|
|
301
|
+
cu_table = np.array([0, 0.1, 0.2, 0.3, 0.6, 0.9])
|
|
302
|
+
size_table = np.array([5, 10, 20, 35])
|
|
303
|
+
|
|
304
|
+
lookup_kv = find_nearest(kv_table, tube_voltage)
|
|
305
|
+
lookup_cu = find_nearest(cu_table, cu_thickness)
|
|
306
|
+
lookup_size = find_nearest(size_table, size)
|
|
307
|
+
|
|
308
|
+
lookup_array = np.array(
|
|
309
|
+
[
|
|
310
|
+
[
|
|
311
|
+
[1.2, 1.3, 1.3, 1.3],
|
|
312
|
+
[1.3, 1.3, 1.4, 1.4],
|
|
313
|
+
[1.3, 1.4, 1.4, 1.4],
|
|
314
|
+
[1.3, 1.4, 1.4, 1.5],
|
|
315
|
+
[1.3, 1.4, 1.5, 1.5],
|
|
316
|
+
[1.3, 1.5, 1.5, 1.6],
|
|
317
|
+
],
|
|
318
|
+
[
|
|
319
|
+
[1.3, 1.4, 1.4, 1.5],
|
|
320
|
+
[1.3, 1.4, 1.5, 1.5],
|
|
321
|
+
[1.3, 1.5, 1.6, 1.6],
|
|
322
|
+
[1.4, 1.5, 1.6, 1.7],
|
|
323
|
+
[1.4, 1.5, 1.7, 1.7],
|
|
324
|
+
[1.4, 1.5, 1.7, 1.7],
|
|
325
|
+
],
|
|
326
|
+
[
|
|
327
|
+
[1.3, 1.4, 1.5, 1.5],
|
|
328
|
+
[1.3, 1.5, 1.6, 1.6],
|
|
329
|
+
[1.3, 1.5, 1.6, 1.7],
|
|
330
|
+
[1.4, 1.5, 1.6, 1.7],
|
|
331
|
+
[1.4, 1.5, 1.7, 1.7],
|
|
332
|
+
[1.3, 1.5, 1.7, 1.7],
|
|
333
|
+
],
|
|
334
|
+
[
|
|
335
|
+
[1.3, 1.5, 1.5, 1.6],
|
|
336
|
+
[1.3, 1.5, 1.6, 1.6],
|
|
337
|
+
[1.3, 1.5, 1.6, 1.7],
|
|
338
|
+
[1.3, 1.5, 1.6, 1.7],
|
|
339
|
+
[1.3, 1.5, 1.6, 1.7],
|
|
340
|
+
[1.3, 1.5, 1.6, 1.7],
|
|
341
|
+
],
|
|
342
|
+
]
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
return lookup_array[lookup_kv, lookup_cu, lookup_size]
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def rotate_ray_y(segment1, angle):
|
|
349
|
+
"""This function rotates a ray around the end point of the ray by angle degrees.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
segment1: the ray to rotate_ray_y
|
|
353
|
+
angle: rotation angle in degrees
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
A new ray with the same end point but the start point rotated.
|
|
357
|
+
"""
|
|
358
|
+
isocentre = segment1.target
|
|
359
|
+
translate_source = segment1.source - isocentre
|
|
360
|
+
angle_rads = angle / 360 * 2.0 * math.pi
|
|
361
|
+
my_y = translate_source[1]
|
|
362
|
+
my_x = translate_source[2] * math.sin(angle_rads) + translate_source[0] * math.cos(
|
|
363
|
+
angle_rads
|
|
364
|
+
)
|
|
365
|
+
my_z = translate_source[2] * math.cos(angle_rads) - translate_source[0] * math.sin(
|
|
366
|
+
angle_rads
|
|
367
|
+
)
|
|
368
|
+
new_source = np.array([my_x, my_y, my_z])
|
|
369
|
+
return Segment3(new_source + isocentre, isocentre)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def get_table_trans(tube_voltage, cu_thickness):
|
|
373
|
+
"""This function gives just the table transmission factor based
|
|
374
|
+
on measurements made at the Royal Free Hospital on a Siemens Artis Zeego
|
|
375
|
+
in early 2016.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
tube_voltage: The peak kilovoltage
|
|
379
|
+
cu_thickness: the added copper filtration in mm. In addition, 3.1 mm Al is assumed by default
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
A transmission factor for the table without a mattress.
|
|
383
|
+
"""
|
|
384
|
+
kv_table = np.array([60, 80, 110, 125])
|
|
385
|
+
cu_table = np.array([0, 0.1, 0.2, 0.3, 0.6, 0.9])
|
|
386
|
+
|
|
387
|
+
lookup_kv = find_nearest(kv_table, tube_voltage)
|
|
388
|
+
lookup_cu = find_nearest(cu_table, cu_thickness)
|
|
389
|
+
|
|
390
|
+
lookup_array = np.array(
|
|
391
|
+
[
|
|
392
|
+
[0.80, 0.82, 0.82, 0.82],
|
|
393
|
+
[0.84, 0.84, 0.86, 0.87],
|
|
394
|
+
[0.86, 0.86, 0.88, 0.88],
|
|
395
|
+
[0.84, 0.86, 0.88, 0.89],
|
|
396
|
+
[0.86, 0.87, 0.88, 0.90],
|
|
397
|
+
[0.86, 0.87, 0.89, 0.90],
|
|
398
|
+
]
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
return lookup_array[lookup_cu, lookup_kv]
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def get_table_mattress_trans(tube_voltage, cu_thickness):
|
|
405
|
+
"""This function gives a table and mattress transmission factor based
|
|
406
|
+
on measurements made at the Royal Free Hospital on a Siemens Artis Zeego
|
|
407
|
+
in early 2016.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
tube_voltage: The peak kilovoltage
|
|
411
|
+
cu_thickness: the added copper filtration in mm. In addition, 3.1 mm Al is assumed by default
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
A combined transmission factor for table and mattress.
|
|
415
|
+
"""
|
|
416
|
+
kv_table = np.array([60, 80, 110, 125])
|
|
417
|
+
cu_table = np.array([0, 0.1, 0.2, 0.3, 0.6, 0.9])
|
|
418
|
+
|
|
419
|
+
lookup_kv = find_nearest(kv_table, tube_voltage)
|
|
420
|
+
lookup_cu = find_nearest(cu_table, cu_thickness)
|
|
421
|
+
|
|
422
|
+
lookup_array = np.array(
|
|
423
|
+
[
|
|
424
|
+
[0.66, 0.68, 0.71, 0.72],
|
|
425
|
+
[0.73, 0.75, 0.78, 0.78],
|
|
426
|
+
[0.75, 0.78, 0.81, 0.81],
|
|
427
|
+
[0.76, 0.79, 0.83, 0.83],
|
|
428
|
+
[0.79, 0.81, 0.85, 0.85],
|
|
429
|
+
[0.80, 0.82, 0.85, 0.86],
|
|
430
|
+
]
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
return lookup_array[lookup_cu, lookup_kv]
|