-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUserControl1.xaml.cs
More file actions
351 lines (318 loc) · 15.7 KB
/
UserControl1.xaml.cs
File metadata and controls
351 lines (318 loc) · 15.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
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
256
257
258
259
260
261
262
263
264
265
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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VMS.TPS.Common.Model.API;
using VMS.TPS.Common.Model.Types;
namespace BeamEnumerator
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
private ScriptContext context;
public DRRCalculationParameters drrParam = new DRRCalculationParameters(500); // 50 cm DRR size
private DRRCalculationParameters drrParamBone = new DRRCalculationParameters(500);
private string mbtext = "";
private string beamIdx;
public string BeamIdx
{
get { return beamIdx; }
set {
beamIdx = value;
if(value.Length >= 3)
{
beamIdx = value.Substring(0,3);
}
else if(value.Length < 3)
{
beamIdx = value;
while(beamIdx.Length < 3) { BeamIdx += "1"; }
}
}
}
public UserControl1(ScriptContext context)
{
InitializeComponent();
DataContext = this;
this.context = context;
BeamIdx = "111"; //default value in case gueassing fails
// extra parameter set for Mamma Dok0
drrParamBone.SetLayerParameters(0, 2.0, -16.0, 126.0, 20.0, 60.0);
drrParamBone.SetLayerParameters(1, 10.0, 100.0, 1000.0);
}
private void ButtonOK(object sender, RoutedEventArgs e)
{
// add default setup beams if none exist
if (context.ExternalPlanSetup.Beams.Where(x => x.IsSetupField).Count() == 0)
{
if (!MammaButton.IsChecked.Value)
{
AddSetupFields(context);
}
else
{
AddMammaSetupFields(context);
}
}
EnumerateBeams(context);
if (mbtext.Length > 0) { MessageBox.Show(mbtext, "Info"); }
Window.GetWindow(this).Close();
}
private void ButtonCancel(object sender, RoutedEventArgs e)
{
return; // will not return script?!
}
private void KnochenButton_Checked(object sender, RoutedEventArgs e)
{
drrParam = new DRRCalculationParameters(500);
drrParam.SetLayerParameters(0, 2.0, -16.0, 126.0, 20.0, 60.0);
drrParam.SetLayerParameters(1, 10.0, 100.0, 1000.0);
}
private void MammaButton_Checked(object sender, RoutedEventArgs e)
{
drrParam = new DRRCalculationParameters(500);
drrParam.SetLayerParameters(0, 1.0, -450.0, 150.0, -1000.0, 1000.0);
}
private void ThoraxButton_Checked(object sender, RoutedEventArgs e)
{
drrParam = new DRRCalculationParameters(500);
drrParam.SetLayerParameters(0, 1.0, -500.0, 1000.0, -020.0, -100.0);
drrParam.SetLayerParameters(1, 2.0, -300.0, 800.0, -200.0, 50.0);
}
private void ExtremitaetButton_Checked(object sender, RoutedEventArgs e)
{
drrParam = new DRRCalculationParameters(500);
drrParam.SetLayerParameters(0, 0.6, -990.0, 0.0, 10.0, 50.0);
drrParam.SetLayerParameters(1, 0.1, -450.0, 150.0, -40.0, 80.0);
drrParam.SetLayerParameters(2, 1.0, 100.0, 1000.0);
}
private void Seeds3Button_Checked(object sender, RoutedEventArgs e)
{
drrParam = new DRRCalculationParameters(500);
drrParam.SetLayerParameters(0, 10.0, 1000.0, 4000.0, -30.0, 30.0);
drrParam.SetLayerParameters(1, 0.1, 100.0, 1000.0);
}
private void Seeds5Button_Checked(object sender, RoutedEventArgs e)
{
drrParam = new DRRCalculationParameters(500);
drrParam.SetLayerParameters(0, 2.0, -16.0, 126.0, 20.0, 60.0);
drrParam.SetLayerParameters(1, 10.0, 100.0, 1000.0);
}
// add default setup beams
private void AddSetupFields(ScriptContext context)
{
bool setupDirection = false;
// Setup Beam Machine Parameters
string linac = context.ExternalPlanSetup.Beams.First().TreatmentUnit.Id;
VVector iso = context.ExternalPlanSetup.Beams.First().IsocenterPosition;
ExternalBeamMachineParameters mParams = new ExternalBeamMachineParameters(linac, "6X", 300, "STATIC", null); // dose rate correct?
// check if there are beams between 180 and 60 degree
foreach (Beam b in context.ExternalPlanSetup.Beams)
{
double ga = Math.Round(b.ControlPoints.First().GantryAngle, 0);
if (60.0 <= ga && ga <= 180 && !b.IsGantryExtended) { setupDirection = true; }
if (ga > 180.0 && b.IsGantryExtended) { setupDirection = true; } // also if there is a beam with extended angle > 180
}
// if there is a field between 180 and 60 degree, add setup fields at 180 an 90 degree
if (setupDirection)
{
if (linac.StartsWith("TrueBeam"))
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -125.0, 125.0, 125.0), 0.0, 180.0, 0.0, iso);
Beam nb2 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -125.0, 125.0, 125.0), 0.0, 90.0, 0.0, iso);
}
else
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -90.0, 125.0, 90.0), 0.0, 180.0, 0.0, iso);
Beam nb2 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -90.0, 125.0, 90.0), 0.0, 90.0, 0.0, iso);
}
}
// if there are no fields between 180 and 45 degree use gantry angles 0 and 270.
else
{
if (linac.StartsWith("TrueBeam"))
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -125.0, 125.0, 125.0), 0.0, 0.0, 0.0, iso);
Beam nb2 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -125.0, 125.0, 125.0), 0.0, 270.0, 0.0, iso);
}
else
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -90.0, 125.0, 90.0), 0.0, 0.0, 0.0, iso);
Beam nb2 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -90.0, 125.0, 90.0), 0.0, 270.0, 0.0, iso);
}
}
this.mbtext += "Setup Felder wurden erstellt, bitte die gewünschte\nToleranztabelle hinterlegen und die Plannormierung\nwieder einstellen!";
}
// add mamma setup beams
private void AddMammaSetupFields(ScriptContext context)
{
bool setupDirection = false;
// Setup Beam Machine Parameters
string linac = context.ExternalPlanSetup.Beams.First().TreatmentUnit.Id;
VVector iso = context.ExternalPlanSetup.Beams.First().IsocenterPosition;
ExternalBeamMachineParameters mParams = new ExternalBeamMachineParameters(linac, "6X", 300, "STATIC", null);
// test for left or right side breast, x>0 -> left x<0 -> right
if (iso.x > 0) { setupDirection = true; }
// if left sided tumor use 300°
if (setupDirection)
{
if (linac.StartsWith("TrueBeam"))
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -125.0, 125.0, 125.0), 0.0, 300.0, 0.0, iso);
}
else
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -90.0, 125.0, 90.0), 0.0, 300.0, 0.0, iso);
}
}
// else: right sided tumor use 60°
else
{
if (linac.StartsWith("TrueBeam"))
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -125.0, 125.0, 125.0), 0.0, 60.0, 0.0, iso);
}
else
{
Beam nb1 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -90.0, 125.0, 90.0), 0.0, 60.0, 0.0, iso);
}
}
if (context.ExternalPlanSetup.ReferencePoints.Count() > 2) // if more than two reference points we assume the is a supra clav ptv which get's an extra setup field
{
if (linac.StartsWith("TrueBeam"))
{
Beam nb2 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -125.0, 125.0, 125.0), 0.0, 00.0, 0.0, iso);
}
else
{
Beam nb2 = context.ExternalPlanSetup.AddSetupBeam(mParams, new VRect<double>(-125.0, -90.0, 125.0, 90.0), 0.0, 00.0, 0.0, iso);
}
}
this.mbtext += "Mamma Setup Felder wurden erstellt, bitte die gewünschte\nToleranztabelle hinterlegen und die Plannormierung\nwieder einstellen!";
}
// Change Beam Ids to nubmers according to plan name or user input
private void EnumerateBeams(ScriptContext context)
{
int BeamCount = 1;
string newBeamId = "";
string gantryangle = "";
string newBeamCount = "";
// let the user order arc treatments by himself via the beam id
if (context.PlanSetup.Beams.Where(x => !x.IsSetupField).First().Technique.ToString() == "ARC")
{
foreach (Beam b in context.PlanSetup.Beams.OrderBy(x => x.Id))
{
b.Id = "x" + (20 - BeamCount).ToString(); // Fields are later named in descending order!
BeamCount++;
}
}
else
{
// first beam loop is necessary to change all beam-IDs to unique ones (other than the script wants to produce). The new name is used for sorting CCW and grouping on table angles.
foreach (Beam b in context.PlanSetup.Beams.OrderBy(y => y.ControlPoints.First().GantryAngle).ThenBy(x => JawArea(x.ControlPoints.First().JawPositions)).ThenBy(z => z.WeightFactor))
{
double subnr = BeamCount;
if (b.ControlPoints.First().GantryAngle <= 180.0)
{
if (b.IsGantryExtended) { newBeamId = (b.ControlPoints.First().GantryAngle + subnr / 10).ToString(); }
else { newBeamId = (b.ControlPoints.First().GantryAngle + 360.0 + subnr / 10).ToString(); }
}
else
{
if (!b.IsGantryExtended) { newBeamId = (b.ControlPoints.First().GantryAngle + subnr / 10).ToString(); }
else { newBeamId = (b.ControlPoints.First().GantryAngle + 360.0 + subnr / 10).ToString(); }
}
if (b.ControlPoints.First().PatientSupportAngle != 0.0)
{
newBeamId = "_" + Math.Round(b.ControlPoints.First().PatientSupportAngle, 0).ToString("000") + newBeamId;
}
// left over from kiragroh BeamIdChanger script
b.Id = newBeamId.Length > 16 ? newBeamId.Substring(0, 16) : newBeamId;
BeamCount++;
}
}
//Treatment field-Loop
BeamCount = 1;
foreach (Beam b in context.PlanSetup.Beams.Where(x => !x.IsSetupField).OrderByDescending(y => y.Id)) //.OrderBy(y => y.Id) ControlPoints.First().GantryAngle
{
newBeamCount = BeamCount < 10 ? "0" + BeamCount.ToString() : BeamCount.ToString(); // handle single and double digits
newBeamId = BeamIdx + newBeamCount;
// left over from kiragroh BeamIdChanger script
b.Id = newBeamId.Length > 16 ? newBeamId.Substring(0, 16) : newBeamId;
BeamCount++;
b.CreateOrReplaceDRR(drrParam);
}
// Setup field-Loop for normal setup fields
if (!MammaButton.IsChecked.Value)
{
foreach (Beam b in context.PlanSetup.Beams.Where(x => x.IsSetupField)) //.OrderBy(y => y.Id)
{
gantryangle = Math.Round(b.ControlPoints.First().GantryAngle, 0).ToString();
newBeamCount = gantryangle.ToString().Length < 2 ? gantryangle.ToString() : gantryangle.ToString().Substring(gantryangle.ToString().Length - 2, 1);
newBeamId = BeamIdx + "9" + newBeamCount;
try // changing beam id, info if it fails
{
// left over from kiragroh BeamIdChanger script
b.Id = newBeamId.Length > 16 ? newBeamId.Substring(0, 16) : newBeamId;
}
catch { mbtext += "\nNummerierung der Dokfelder nicht eindeutig, bitte händisch korrigieren"; }
b.CreateOrReplaceDRR(drrParam);
}
}
else // DokMedLat and Dok0
{
foreach (Beam b in context.PlanSetup.Beams.Where(x => x.IsSetupField)) //.OrderBy(y => y.Id)
{
List<string> defAngles = new List<string> { "90", "270", "180" }; // "normal" setup field angles
gantryangle = Math.Round(b.ControlPoints.First().GantryAngle, 0).ToString();
// decide on Beam Ids by gantry angle name, special cases are Dok0 and DokMedLat
if (gantryangle == "0")
{
newBeamId = "Dok0";
}
else if (defAngles.Contains(gantryangle))
{
newBeamCount = gantryangle.ToString().Length < 2 ? gantryangle.ToString() : gantryangle.ToString().Substring(gantryangle.ToString().Length - 2, 1);
newBeamId = BeamIdx + "9" + newBeamCount;
}
else
{
newBeamId = "DokMedLat";
}
try // changing beam id, info if it fails
{
// left over from kiragroh BeamIdChanger script
b.Id = newBeamId.Length > 16 ? newBeamId.Substring(0, 16) : newBeamId;
}
catch { mbtext += "\nBenennung der Dokfelder nicht eindeutig, bitte händisch korrigieren"; }
if (b.Id == "Dok0")
{
b.CreateOrReplaceDRR(drrParamBone); // Bone Rendering for supra clav setup field
}
else
{
b.CreateOrReplaceDRR(drrParam);
}
}
}
}
// calculate jaw area
private double JawArea(VRect<double> jaws)
{
double area = (jaws.X2 - jaws.X1) * (jaws.Y2 - jaws.Y1);
return area;
}
}
}