// Compute isocenter shift on verification plan
        public VVector ComputeIsoShift(QASettings qaSet)
        {
            verifPlnIso = qaSet.pIso;                        // Set iso center from settings
            List <Double> infFldEdges = new List <Double>(); // create list to store inferior field edge for each beam

            foreach (Beam bm in currPln.Beams)
            {
                if (bm.MetersetPerGy > 0)
                {
                    BeamParameters bmParam = bm.GetEditableParameters();
                    Double         collAng = bmParam.ControlPoints.First().CollimatorAngle;
                    VRect <Double> collPos = bmParam.ControlPoints.First().JawPositions;
                    // Compute the approximate inferior field edge position shaped by the collimator and MLC
                    Double cosAng = Math.Cos(Math.PI * collAng / 180.0);
                    Double sinAng = Math.Sin(Math.PI * collAng / 180.0);
                    Double DelX   = 400.0; //field edge can be defined by one X and one Y jaw
                    Double DelY   = 400.0;
                    if (cosAng > 0.01)
                    {
                        DelY = -collPos.Y1 / cosAng;
                    }
                    if (cosAng < -0.01)
                    {
                        DelY = -collPos.Y2 / cosAng;
                    }                                                    //past 90 deg, Y2 defines inferior edge
                    if (sinAng > 0.01)
                    {
                        DelX = -collPos.X1 / sinAng;
                    }                                                    //ccw rotation (respect to BEV), X1 defines inferior edge
                    if (sinAng < -0.01)
                    {
                        DelX = -collPos.X2 / sinAng;
                    }                                      //cw rotation (respect to BEV), X2 defines inferior edge
                    infFldEdges.Add(Math.Min(DelX, DelY)); //use the minimum between DelX and DelY as the approximate inferior field edge
                }
            }
            if (infFldEdges.Count == 0)
            {
                return(new VVector(Double.NaN, Double.NaN, Double.NaN));
            }                                                                                       // no field edge found, either beam parameters invalid or no MU
            Double MedInfFldEdge = GetMedian(infFldEdges);

            if (MedInfFldEdge > qaSet.pLen)                                                              // if the field edge is longer than the length of qa phantom
            {
                verifPlnIso.z = verifPlnIso.z + Math.Ceiling(MedInfFldEdge / 10 - qaSet.pLen / 10) * 10; // shift the iso superiorly (cm as minimum shift unit)
            }
            return(verifPlnIso);
        }
Ejemplo n.º 2
0
        // Create QA button is clicked
        private void btnCrtQA_Click(object sender, RoutedEventArgs e)
        {
            // Get the selected plan
            currPln = EclipseContext.Course.ExternalPlanSetups.FirstOrDefault(p => p.Id == cmbPln.SelectedItem.ToString());
            // Get the name of the QA course
            String verifCrsID = txtbQACrs.Text;
            // Create a new CreateAndComputeQAPlan Object
            CreateAndComputeQAPlan CrtQApln = new CreateAndComputeQAPlan(currPt, currPln);
            // Check and/or create QA course
            Course verifCrs = currPt.Courses.FirstOrDefault(c => c.Id == verifCrsID);

            if (verifCrs == null)
            {
                msgTxt = "Creating course " + verifCrsID + "...";
                ShowMessage(msgTxt);
                verifCrs = CrtQApln.CreateCourse(verifCrsID);
            }
            // Check if current plan already exists in verifCrs
            String verifPlnID = currPln.Id;

            if (verifCrs.PlanSetups.Any(p => p.Id == verifPlnID))
            {
                msgTxt = "Plan " + verifPlnID + " already exists in course " + verifCrsID + ".";
                ShowMessage(msgTxt);
                return;
            }
            // Copy QA phantom struct set if not available
            QASettings qaSet = FindQASetbyMachine(); // find the qa setting of the machine of the current plan

            if (qaSet == null)
            {
                msgTxt = "Treatment machine is not set in settings or multiple machines present in plan!";
                ShowMessage(msgTxt);
                return;
            }
            StructureSet pStructSt = currPt.StructureSets.FirstOrDefault(s => s.Id == qaSet.pStrutId);

            if (pStructSt == null)
            {
                msgTxt = "Copying structure set " + qaSet.pStrutId + " from patient " + qaSet.pPtId + "...";
                ShowMessage(msgTxt);
                pStructSt = currPt.CopyImageFromOtherPatient(qaSet.pPtId, null, qaSet.pImgId);
            }
            // Create verification plan
            msgTxt = "Creating QA plan " + verifPlnID + "...";
            ShowMessage(msgTxt);
            ExternalPlanSetup verifPln = CrtQApln.CreateVerificationPlan(pStructSt, verifCrs, verifPlnID);
            // Compute if isocenter shift is needed based on QA phantom length
            VVector verifPlnIso = CrtQApln.ComputeIsoShift(qaSet);  //  the isocenter location of the QA plan

            if (Double.IsNaN(verifPlnIso.z))
            {
                msgTxt = "Cannot find field edge.";
                ShowMessage(msgTxt);
                msgTxt = "Please double check field parameters and its MU.";
                ShowMessage(msgTxt);
                return;
            }
            int shftIso = (int)(verifPlnIso.z / 10 - qaSet.pIso.z / 10);  // convert iso shift to cm

            if (shftIso > 0)
            {
                msgTxt = "Iso-center of the QA plan will be shifted by " + shftIso.ToString() + "cm superiorly.";
                ShowMessage(msgTxt);
            }
            // Create beams in verification plan
            foreach (Beam currBm in currPln.Beams)
            {
                if (currBm.MetersetPerGy > 0)
                {
                    if (currBm.ControlPoints.First().PatientSupportAngle != 0.0)
                    {
                        msgTxt = "Couch angle for beam " + currBm.Id + " will be set to 0.0.";
                        ShowMessage(msgTxt);
                    }
                    msgTxt = "Adding beam " + currBm.Id + " to QA plan " + verifPln.Id + "...";
                    ShowMessage(msgTxt);
                    Beam verifBm = CrtQApln.AddBeamToVerifPlan(currBm);
                    if (verifBm == null)
                    {
                        msgTxt = "Cannot add beam " + currBm.Id + " to QA plan, please delete QA plan & try again.";
                        ShowMessage(msgTxt);
                        return;
                    }
                }
            }
            // Compute dose in verification plan
            msgTxt = "Calculating dose for QA plan " + verifPln.Id + "...";
            ShowMessage(msgTxt);
            CrtQApln.ComputeDose();
            // Ready for next
            msgTxt = "Dose calculation completed.";
            ShowMessage(msgTxt);
            if (shftIso > 0)
            {
                msgTxt = "Please inform QA personnel:";
                ShowMessage(msgTxt, Colors.Red);
                msgTxt = "Iso-center of QA plan is shifted by " + shftIso.ToString() + "cm.";
                ShowMessage(msgTxt, Colors.Red);
            }
            txtbStat.Text = "Ready.";
        }
 // Copy QA phantom struct set if not available
 public StructureSet CopyImageSet(QASettings qaSet)
 {
     return(currPt.CopyImageFromOtherPatient(qaSet.pPtId, null, qaSet.pImgId));
 }