示例#1
0
        public void CreateRingFromPTV(StructureSet structureSet, string ptvId, string ringId, double innerMargin, double outerMargin)
        {
            structureSet.Patient.BeginModifications();
            Structure ptv = structureSet.Structures.Where(structure => structure.Id == ptvId).FirstOrDefault();
            Structure ring;
            Structure spacerTemp;

            try
            {
                ring = structureSet.AddStructure("CONTROL", ringId);  //doesnt exist yet
            }
            catch
            {
                ring = structureSet.Structures.FirstOrDefault(x => x.Id == ringId);                 //already exists
                ring.SegmentVolume = ring.Sub(structureSet.Structures.Single(x => x.Id == "BODY")); //cleanup
            }
            try
            {
                spacerTemp = structureSet.AddStructure("CONTROL", "spacerTemp");  //doesnt exist yet
            }
            catch
            {
                spacerTemp = structureSet.Structures.FirstOrDefault(x => x.Id == "spacerTemp");                 //already exists
                spacerTemp.SegmentVolume = spacerTemp.Sub(structureSet.Structures.Single(x => x.Id == "BODY")); //cleanup
            }
            //ring.ConvertToHighResolution();
            ring.SegmentVolume       = ptv.Margin(outerMargin);
            spacerTemp.SegmentVolume = ptv.Margin(innerMargin); //3 mm between ring and PTV
            ring.SegmentVolume       = ring.Sub(ptv);
            ring.SegmentVolume       = ring.Sub(spacerTemp);
            ring.SegmentVolume       = ring.And(structureSet.Structures.Single(x => x.Id == "BODY")); //clear outside of body
            structureSet.RemoveStructure(spacerTemp);
        }
        /// <summary>
        /// This splits a structure into two. It creates a margin around the target,
        /// so that it approximately crosses the mass center of the structure, and then
        /// uses boolean operators to create two new structures. Note: due to the nature
        /// of the segment model in Eclipse, the new structures do not always perfectly cover
        /// the whole volume of the original structure.
        /// </summary>
        /// <param name="s"></param>
        /// <param name="ss"></param>
        /// <returns></returns>
        bool SplitStructure(StructureSet ss, Structure target, Structure roi)
        {
            if (ss.CanAddStructure(roi.DicomType, roi.Id + "_spl1"))
            {
                Structure newStr1 = ss.AddStructure(roi.DicomType, roi.Id + "_spl1");
                Structure newStr2 = ss.AddStructure(roi.DicomType, roi.Id + "_spl2");

                VVector targetCenter = target.CenterPoint;
                VVector roiCenter    = roi.CenterPoint;
                double  dist         = (targetCenter - roiCenter).Length;

                //figure out distance from target center to target surface
                System.Collections.BitArray buffer = new System.Collections.BitArray(100);
                SegmentProfile profile             = target.GetSegmentProfile(targetCenter, roiCenter, buffer);
                double         distToTargetSurface = 0;
                foreach (SegmentProfilePoint point in profile)
                {
                    if (point.Value == false)
                    {
                        //first point outside structure
                        distToTargetSurface = (point.Position - targetCenter).Length;
                        break;
                    }
                }
                //SegmentVolume seg = target.Margin(dist - distToTargetSurface);
                SegmentVolume seg = target.LargeMargin(dist - distToTargetSurface);
                newStr1.SegmentVolume = seg.And(roi);
                newStr2.SegmentVolume = roi.Sub(newStr1);
                return(true);
            }
            return(false);
        }
示例#3
0
        public void Execute(ScriptContext context /*, System.Windows.Window window, ScriptEnvironment environment*/)
        {
            if (context.Patient == null || context.StructureSet == null)
            {
                MessageBox.Show("Please load a patient, 3D image, and structure set before running this script.", SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            StructureSet ss = context.StructureSet;

            // find Rectum
            Structure rectum = ss.Structures.FirstOrDefault(x => x.Id == RECTUM_ID);

            if (rectum == null)
            {
                MessageBox.Show(string.Format("'{0}' not found!", RECTUM_ID), SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }

            // find PTV
            Structure ptv = ss.Structures.FirstOrDefault(x => x.Id == PTV_ID);

            if (ptv == null)
            {
                MessageBox.Show(string.Format("'{0}' not found!", PTV_ID), SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            context.Patient.BeginModifications();   // enable writing with this script.

            //============================
            // GENERATE 5mm expansion of PTV
            //============================

            // create the empty "ptv+5mm" structure
            Structure ptv_5mm = ss.AddStructure("PTV", EXPANDED_PTV_ID);

            // expand PTV
            ptv_5mm.SegmentVolume = ptv.Margin(5.0);

            //============================
            // subtract rectum from expansion to create 5mm buffer
            //============================
            Structure buffered_rectum = ss.AddStructure("AVOIDANCE", RECTUM_OPT_ID);

            // calculate overlap structures using Boolean operators.
            buffered_rectum.SegmentVolume = rectum.Sub(ptv_5mm); //'Sub' subtracts overlapping volume of expanded PTV from rectum

            string message = string.Format("{0} volume = {4}\n{1} volume = {5}\n{2} volume = {6}\n{3} volume = {7}",
                                           ptv.Id, rectum.Id, ptv_5mm.Id, buffered_rectum.Id,
                                           ptv.Volume, rectum.Volume, ptv_5mm.Volume, buffered_rectum.Volume);

            MessageBox.Show(message);

            ss.RemoveStructure(ptv_5mm);
        }
示例#4
0
        public void CreateRingFromPTV(StructureSet structureSet, string ptvId, string ringInnerId, string ringMiddleId, string ringOuterId, double innerMargin, double middleMargin, double outerMargin)
        {
            structureSet.Patient.BeginModifications();
            Structure ptv = structureSet.Structures.Where(x => x.Id == ptvId).FirstOrDefault();
            Structure ringInner;
            Structure ringMiddle;
            Structure ringOuter;

            if (structureSet.Structures.Any(x => x.Id == ringInnerId))
            {
                ringInner = structureSet.Structures.Where(x => x.Id == ringInnerId).FirstOrDefault();
            }
            else
            {
                ringInner = structureSet.AddStructure("CONTROL", ringInnerId);  //doesnt exist yet
            }
            if (structureSet.Structures.Any(x => x.Id == ringMiddleId))
            {
                ringMiddle = structureSet.Structures.Where(x => x.Id == ringMiddleId).FirstOrDefault();
            }
            else
            {
                ringMiddle = structureSet.AddStructure("CONTROL", ringMiddleId);  //doesnt exist yet
            }
            if (structureSet.Structures.Any(x => x.Id == ringOuterId))
            {
                ringOuter = structureSet.Structures.Where(x => x.Id == ringOuterId).FirstOrDefault();
            }
            else
            {
                ringOuter = structureSet.AddStructure("CONTROL", ringOuterId);  //doesnt exist yet
            }
            ringInner.ConvertToHighResolution();
            ringMiddle.ConvertToHighResolution();
            ringOuter.ConvertToHighResolution();

            ringInner.SegmentVolume  = ptv.Margin(innerMargin);
            ringMiddle.SegmentVolume = ptv.Margin(middleMargin);
            ringOuter.SegmentVolume  = ptv.Margin(outerMargin);

            ringInner.SegmentVolume  = ringInner.Sub(ptv);
            ringMiddle.SegmentVolume = ringMiddle.Sub(ptv);
            ringOuter.SegmentVolume  = ringOuter.Sub(ptv);

            ringMiddle.SegmentVolume = ringMiddle.Sub(ringInner);
            ringOuter.SegmentVolume  = ringOuter.Sub(ringInner);
            ringOuter.SegmentVolume  = ringOuter.Sub(ringMiddle);

            ringInner.SegmentVolume  = ringInner.And(structureSet.Structures.Single(x => x.Id == "BODY"));  //clear outside of body
            ringMiddle.SegmentVolume = ringMiddle.And(structureSet.Structures.Single(x => x.Id == "BODY")); //clear outside of body
            ringOuter.SegmentVolume  = ringOuter.And(structureSet.Structures.Single(x => x.Id == "BODY"));  //clear outside of body
        }
        public static Structure CheckOverlap_OptiMaker(Structure structure, ref StructureSet ss, bool isCritical)
        {
            if (structure.Name.ToLower().Contains("ptv") || structure.Name.ToLower().Contains("body")) //don't check if it is a ptv already or body contours...
            {
                return(structure);
            }
            else if (isCritical)
            {
                return(structure);
            }

            int    nameLen = Math.Min(structure.Name.Length, 7);
            string name    = "PC_opti_" + structure.Name.Substring(0, nameLen);

            Structure opti;

            foreach (Structure struc in ss.Structures.ToList())
            {
                if (struc.Name == name)
                {
                    ss.RemoveStructure(struc);
                }
            }
            try
            {
                opti = ss.AddStructure("CONTROL", name);
            }
            catch
            {
                return(structure);
            }

            opti.SegmentVolume = structure.Margin(0);
            //Make an opti structure, but delete it if its exactly the same as the original structure

            //Loop through and subtract all PTV volumes:
            foreach (Structure s in ss.Structures)
            {
                if (s.Name.ToLower().Contains("ptv"))
                {
                    opti.SegmentVolume = opti.Sub(s);
                }
            }
            //Check if it changed (if it did overlap, need to make a new opti structure)

            //So this is an imperfect function and the volumes will be different no matter what... so make sure they are different by more than 5%
            if ((structure.Volume - opti.Volume) / structure.Volume > 0.05)
            {
                return(opti);
            }
            else
            {
                ss.RemoveStructure(opti);
                return(structure);
            }
        }
示例#6
0
        /// <summary>
        /// Boolean an IEnumerable collection of structures
        /// </summary>
        /// <param name="structuresToBoolean"></param>
        /// <returns>Returns a booleaned structure</returns>
        public static SegmentVolume BooleanStructures(StructureSet ss, IEnumerable <Structure> structuresToBoolean)
        {
            Structure combinedStructure;

            try
            {
                combinedStructure = ss.AddStructure("CONTROL", "zzzTEMP");
            }
            catch
            {
                combinedStructure = ss.AddStructure("CONTROL", "zzzTEMP2");
            }
            combinedStructure.SegmentVolume = structuresToBoolean.First().SegmentVolume;

            foreach (var s in structuresToBoolean)
            {
                combinedStructure.SegmentVolume = combinedStructure.SegmentVolume.Or(s.SegmentVolume);
            }

            return(combinedStructure.SegmentVolume);
        }
        public void Execute(ScriptContext context /*, System.Windows.Window window, ScriptEnvironment environment*/)
        {
            // TODO : Add here the code that is called when the script is launched from Eclipse.

            if (context.PlanSetup == null)
            {
                MessageBox.Show("Please load a plan before running this script.", SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            if (context.PlanSetup.Dose == null)
            {
                MessageBox.Show("Please complete dose calculation  before running this script.", SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }

            StructureSet ss      = context.StructureSet;
            Dose         dose    = context.PlanSetup.Dose;
            string       logtext = "";

            // enable writing with this script.
            context.Patient.BeginModifications();

            foreach (Isodose isodose in context.PlanSetup.Dose.Isodoses)
            {
                string isoStructureName = "";
                isoStructureName = context.PlanSetup.Id + "_"
                                   + string.Format("{0:f3}", Math.Round(context.PlanSetup.TotalDose.Dose * isodose.Level.Dose / 100.0, 3)) + "Gy";
                //isoStructureName = context.PlanSetup.Id + "_" + isodose.Level.ValueAsString + isodose.Level.UnitAsString;
                int    nameLength     = isoStructureName.Length;
                string isoStructureId = "";
                if (isoStructureName.Length > 16)
                {
                    isoStructureId = isoStructureName.Substring(0, 16);
                }
                else
                {
                    isoStructureId = isoStructureName;
                }

                if (ss.CanAddStructure("DOSE_REGION", isoStructureId) == true)
                {
                    Structure newIsoStructure = ss.Structures.FirstOrDefault(x => x.Id == isoStructureId);
                    if (newIsoStructure == null)
                    {
                        newIsoStructure = ss.AddStructure("DOSE_REGION", isoStructureId);
                    }
                    newIsoStructure.ConvertDoseLevelToStructure(dose, isodose.Level);
                    logtext += isoStructureName + "\n";
                }
            }
            MessageBox.Show(logtext + "\nDone.", SCRIPT_NAME);
        }
示例#8
0
        public static Structure CreateStructureIfNotExists(this StructureSet ss, string id, string dicomType)
        {
            var match = ss.Structures.FirstOrDefault(s => s.Id == id);

            if (match != null)
            {
                return(match);
            }

            if (!ss.CanAddStructure(dicomType, id))
            {
                return(null);
            }

            return(ss.AddStructure(dicomType, id));
        }
        /// <summary>
        /// Select a section of body structure that is X mm up and down from an existing structure's
        /// top and bottom slices. Make it into a new structure.
        /// </summary>
        /// <param name="s">The structure to enlarge</param>
        /// <param name="ss">The structure set where to add</param>
        /// <param name="upMm">The margin up in mm</param>
        /// <param name="downMm">The margin down in mm</param>
        /// <returns>The new structure. Null if new structure cannot be added.</returns>
        Structure EnlargeStructure(Structure s, StructureSet ss, double upMm, double downMm)
        {
            if (ss.CanAddStructure(s.DicomType, s.Id + "_enl"))
            {
                var    newStr     = ss.AddStructure(s.DicomType, s.Id + "_enl");
                var    image      = ss.Image;
                double res        = image.ZRes;
                int    startSlice = 0;
                for (int z = 0; z < image.ZSize; z++)
                {
                    if (s.GetContoursOnImagePlane(z).Count() > 0)
                    {
                        startSlice = (int)(z - downMm / res);
                        break;
                    }
                }
                int stopSlice = image.ZSize - 1;
                for (int z = image.ZSize - 1; z >= 0; z--)
                {
                    if (s.GetContoursOnImagePlane(z).Count() > 0)
                    {
                        stopSlice = (int)(z + upMm / res);
                        break;
                    }
                }
                startSlice = Math.Max(startSlice, 0);
                stopSlice  = Math.Min(stopSlice, image.ZSize - 1);
                var contour = new VVector[4]
                {
                    // these are real coordinates, not voxel coordinates
                    new VVector(-10000, -10000, 0),
                    new VVector(10000, -10000, 0),
                    new VVector(10000, 10000, 0),
                    new VVector(-10000, 10000, 0)
                };

                for (int z = startSlice; z <= stopSlice; z++)
                {
                    newStr.AddContourOnImagePlane(contour, z);
                }
                var body = ss.Structures.First(st => st.DicomType == "EXTERNAL");
                newStr.SegmentVolume = newStr.And(body);
                return(newStr);
            }
            return(null);
        }
示例#10
0
        private bool preliminaryChecks()
        {
            //check if user origin was set
            //get the points collection for the Body (used for calculating number of isocenters)
            Point3DCollection pts = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "body").MeshGeometry.Positions;

            if (!selectedSS.Image.HasUserOrigin || !(selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "body").IsPointInsideSegment(selectedSS.Image.UserOrigin)))
            {
                MessageBox.Show("Did you forget to set the user origin? \nUser origin is NOT inside body contour! \nPlease fix and try again!");
                return(true);
            }

            //check if patient length is > 116cm, if so, check for matchline contour
            if ((pts.Max(p => p.Z) - pts.Min(p => p.Z)) > 1160.0 && !(selectedSS.Structures.Where(x => x.Id.ToLower() == "matchline").Any()))
            {
                //check to see if the user wants to proceed even though there is no matchplane contour or the matchplane contour exists, but is not filled
                VMATTBIautoPlan.confirmUI CUI = new VMATTBIautoPlan.confirmUI();
                CUI.message.Text = "No matchplane contour found even though patient length > 116.0 cm!" + Environment.NewLine + Environment.NewLine + "Continue?!";
                CUI.ShowDialog();
                if (!CUI.confirm)
                {
                    return(true);
                }

                //checks for LA16 couch and spinning manny couch/bolt will be performed at optimization stage
            }

            //calculate number of required isocenters
            if (!(selectedSS.Structures.Where(x => x.Id.ToLower() == "matchline").Any()))
            {
                //no matchline implying that this patient will be treated with VMAT only. For these cases the maximum number of allowed isocenters is 3.
                //the reason for the explicit statements calculating the number of isos and then truncating them to 3 was to account for patients requiring < 3 isos and if, later on, we want to remove the restriction of 3 isos
                numIsos = numVMATIsos = (int)Math.Ceiling(((pts.Max(p => p.Z) - pts.Min(p => p.Z)) / (400.0 - 20.0)));
                if (numIsos > 3)
                {
                    numIsos = numVMATIsos = 3;
                }
            }
            else
            {
                //matchline structure is present, but empty
                if (selectedSS.Structures.First(x => x.Id.ToLower() == "matchline").IsEmpty)
                {
                    VMATTBIautoPlan.confirmUI CUI = new VMATTBIautoPlan.confirmUI();
                    CUI.message.Text = "I found a matchline structure in the structure set, but it's empty!" + Environment.NewLine + Environment.NewLine + "Do you want to continue without using the matchline structure?!";
                    CUI.ShowDialog();
                    if (!CUI.confirm)
                    {
                        return(true);
                    }

                    //continue and ignore the empty matchline structure (same calculation as VMAT only)
                    numIsos = numVMATIsos = (int)Math.Ceiling(((pts.Max(p => p.Z) - pts.Min(p => p.Z)) / (400.0 - 20.0)));
                    if (numIsos > 3)
                    {
                        numIsos = numVMATIsos = 3;
                    }
                }
                //matchline structure is present and not empty
                else
                {
                    //get number of isos for PTV superior to matchplane (always truncate this value to a maximum of 3 isocenters)
                    numVMATIsos = (int)Math.Ceiling(((pts.Max(p => p.Z) - selectedSS.Structures.First(x => x.Id.ToLower() == "matchline").CenterPoint.z) / (400.0 - 20.0)));
                    if (numVMATIsos > 3)
                    {
                        numVMATIsos = 3;
                    }

                    //get number of iso for PTV inferior to matchplane
                    //if (selectedSS.Structures.First(x => x.Id.ToLower() == "matchline").CenterPoint.z - pts.Min(p => p.Z) - 3.0 <= (400.0 - 20.0)) numIsos = numVMATIsos + 1;

                    //5-20-2020 Nataliya said to only add a second legs iso if the extent of the TS_PTV_LEGS is > 40.0 cm
                    if (selectedSS.Structures.First(x => x.Id.ToLower() == "matchline").CenterPoint.z - pts.Min(p => p.Z) - 3.0 <= (400.0 - 0.0))
                    {
                        numIsos = numVMATIsos + 1;
                    }
                    else
                    {
                        numIsos = numVMATIsos + 2;
                    }
                    //MessageBox.Show(String.Format("{0}", selectedSS.Structures.First(x => x.Id.ToLower() == "matchline").CenterPoint.z - pts.Min(p => p.Z) - 3.0));
                }
            }

            //set isocenter names based on numIsos and numVMATIsos (determined these names from prior cases). Need to implement a more clever way to name the isocenters
            isoNames.Add("Head");
            if (numVMATIsos == 2)
            {
                isoNames.Add("Pelvis");
            }
            else if (numVMATIsos == 3 && numIsos > numVMATIsos)
            {
                isoNames.Add("Chest"); isoNames.Add("Pelvis");
            }
            //this could technically be an else statement, but I left it as an else-if statement so it's explicit what situation is being considered here
            else if (numVMATIsos == 3 && numIsos == numVMATIsos)
            {
                isoNames.Add("Pelvis"); isoNames.Add("Legs");
            }
            if (numIsos > numVMATIsos)
            {
                isoNames.Add("AP / PA upper legs");
                if (numIsos == numVMATIsos + 2)
                {
                    isoNames.Add("AP / PA lower legs");
                }
            }

            //check if selected structures are empty or of high-resolution (i.e., no operations can be performed on high-resolution structures)
            string           output            = "The following structures are high-resolution:" + System.Environment.NewLine;
            List <Structure> highResStructList = new List <Structure> {
            };
            List <Tuple <string, string, double> > highResSpareList = new List <Tuple <string, string, double> > {
            };

            foreach (Tuple <string, string, double> itr in spareStructList)
            {
                if (itr.Item2 == "Mean Dose < Rx Dose")
                {
                    if (selectedSS.Structures.First(x => x.Id == itr.Item1).IsEmpty)
                    {
                        MessageBox.Show(String.Format("Error! \nThe selected structure that will be subtracted from PTV_Body and TS_PTV_VMAT is empty! \nContour the structure and try again."));
                        return(true);
                    }
                    else if (selectedSS.Structures.First(x => x.Id == itr.Item1).IsHighResolution)
                    {
                        highResStructList.Add(selectedSS.Structures.First(x => x.Id == itr.Item1));
                        highResSpareList.Add(itr);
                        output += String.Format("{0}", itr.Item1) + System.Environment.NewLine;
                    }
                }
            }
            //if there are high resolution structures, they will need to be converted to default resolution.
            if (highResStructList.Count() > 0)
            {
                //ask user if they are ok with converting the relevant high resolution structures to default resolution
                output += "They must be converted to default resolution before proceeding!";
                VMATTBIautoPlan.confirmUI CUI = new VMATTBIautoPlan.confirmUI();
                CUI.message.Text = output + Environment.NewLine + Environment.NewLine + "Continue?!";
                CUI.message.Font = new System.Drawing.Font("Microsoft Sans Serif", 11F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                CUI.ShowDialog();
                if (!CUI.confirm)
                {
                    return(true);
                }

                int count = 0;
                foreach (Structure s in highResStructList)
                {
                    //get the high res structure mesh geometry
                    MeshGeometry3D mesh = s.MeshGeometry;
                    //get the start and stop image planes for this structure
                    int startSlice = (int)((mesh.Bounds.Z - selectedSS.Image.Origin.z) / selectedSS.Image.ZRes);
                    int stopSlice  = (int)(((mesh.Bounds.Z + mesh.Bounds.SizeZ) - selectedSS.Image.Origin.z) / selectedSS.Image.ZRes) + 1;
                    //create an Id for the low resolution struture that will be created. The name will be '_lowRes' appended to the current structure Id
                    string newName = s.Id + "_lowRes";
                    if (newName.Length > 16)
                    {
                        newName = newName.Substring(0, 16);
                    }
                    //add a new structure (default resolution by default)
                    Structure lowRes = null;
                    if (selectedSS.CanAddStructure("CONTROL", newName))
                    {
                        lowRes = selectedSS.AddStructure("CONTROL", newName);
                    }
                    else
                    {
                        MessageBox.Show(String.Format("Error! Cannot add new structure: {0}!\nCorrect this issue and try again!", newName.Substring(0, 16)));
                        return(true);
                    }

                    //foreach slice that contains contours, get the contours, and determine if you need to add or subtract the contours on the given image plane for the new low resolution structure. You need to subtract contours if the points lie INSIDE the current structure contour.
                    //We can sample three points (first, middle, and last points in array) to see if they are inside the current contour. If any of them are, subtract the set of contours from the image plane. Otherwise, add the contours to the image plane. NOTE: THIS LOGIC ASSUMES
                    //THAT YOU DO NOT OBTAIN THE CUTOUT CONTOUR POINTS BEFORE THE OUTER CONTOUR POINTS (it seems that ESAPI generally passes the main structure contours first before the cutout contours, but more testing is needed)
                    //string data = "";
                    for (int slice = startSlice; slice < stopSlice; slice++)
                    {
                        VVector[][] points = s.GetContoursOnImagePlane(slice);
                        for (int i = 0; i < points.GetLength(0); i++)
                        {
                            //for (int j = 0; j < points[i].GetLength(0); j++) data += String.Format("{0}, {1}, {2}", points[i][j].x, points[i][j].y, points[i][j].z) + System.Environment.NewLine;
                            if (lowRes.IsPointInsideSegment(points[i][0]) || lowRes.IsPointInsideSegment(points[i][points[i].GetLength(0) - 1]) || lowRes.IsPointInsideSegment(points[i][(int)(points[i].GetLength(0) / 2)]))
                            {
                                lowRes.SubtractContourOnImagePlane(points[i], slice);
                            }
                            else
                            {
                                lowRes.AddContourOnImagePlane(points[i], slice);
                            }
                            //data += System.Environment.NewLine;
                        }
                    }

                    //get the index of the high resolution structure in the structure sparing list and repace this entry with the newly created low resolution structure
                    int index = spareStructList.IndexOf(highResSpareList.ElementAt(count));
                    spareStructList.RemoveAt(index);
                    spareStructList.Insert(index, new Tuple <string, string, double>(newName, highResSpareList.ElementAt(count).Item2, highResSpareList.ElementAt(count).Item3));
                    count++;

                    //data += System.Environment.NewLine;
                    //points = lowRes.GetContoursOnImagePlane((int)((stopSlice + startSlice) / 2));
                    //for (int i = 0; i < points.GetLength(0); i++)
                    //{
                    //    for (int j = 0; j < points[i].GetLength(0); j++) data += String.Format("{0}, {1}, {2}", points[i][j].x, points[i][j].y, points[i][j].z) + System.Environment.NewLine;
                    //    //data += System.Environment.NewLine;
                    //}

                    //File.WriteAllText(@"\\enterprise.stanfordmed.org\depts\RadiationTherapy\Public\Users\ESimiele\vvectorData.txt", data);
                }
                //inform the main UI class that the UI needs to be updated
                updateSparingList = true;

                //string mod = "";
                //foreach (Tuple<string, string, double> itr in spareStructList) mod += String.Format("{0}, {1}, {2}", itr.Item1, itr.Item2, itr.Item3) + System.Environment.NewLine;
                //MessageBox.Show(test);
                //MessageBox.Show(mod);
            }
            return(false);
        }
        public void Execute(ScriptContext context /*, System.Windows.Window window, ScriptEnvironment environment*/)

        {
            if (context.Patient == null || context.StructureSet == null)

            {
                MessageBox.Show("Please load a patient, 3D image, and structure set before running this script.", SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);

                return;
            }

            string msg1 = "";

            string msg2 = "";

            StructureSet ss = context.StructureSet;


            // get list of structures for loaded plan

            var listStructures = context.StructureSet.Structures;

            // define PTV (selected)

            //Structure ptv = listStructures.Where(x => !x.IsEmpty && x.Id.ToUpper().Contains("PTV1 REKTM")).FirstOrDefault();

            //Structure ptv = listStructures.Where(x => x.Id == context.PlanSetup.TargetVolumeID).FirstOrDefault();

            var ptv = SelectStructureWindow.SelectStructure(ss);

            if (ptv == null)
            {
                return;
            }

            else
            {
                msg2 += string.Format("'{0}' found \n", ptv.Id);
            }


            context.Patient.BeginModifications();   // enable writing with this script.

            //============================

            // FIND OAR

            //============================


            // find Rectum

            Structure rectum = listStructures.Where(x => !x.IsEmpty && (x.Id.ToUpper().Contains("REKTUM") || x.Id.ToUpper().Contains("RECTUM")) && x.DicomType.Equals("ORGAN") & !x.Id.ToUpper().Contains("HK")).FirstOrDefault();

            if (rectum == null)
            {
                msg1 += string.Format("Not found: '{0}' \n", "Rektum (OAR)");
            }

            else
            {
                msg2 += string.Format("'{0}' found \n", rectum.Id);
            }



            // find Blase

            Structure blase = listStructures.Where(x => !x.IsEmpty && x.Id.ToUpper().Contains("BLASE") && x.DicomType.Equals("ORGAN") & !x.Id.ToUpper().Contains("HK")).FirstOrDefault();

            if (blase == null)
            {
                msg1 += string.Format("Not found: '{0}' \n", "Blase (OAR)");
            }

            else
            {
                msg2 += string.Format("'{0}' found \n", blase.Id);
            }



            MessageBox.Show(msg2 + "\n" + msg1, SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Information);



            //============================

            // GENERATE HelpStructures

            //============================

            int RectumHkCount = 1;

            int BlaseHkCount = 1;

            foreach (Structure scan in listStructures)

            {
                if (scan.Id.ToUpper().Contains("ZHK REKTUM"))
                {
                    RectumHkCount++;
                }
                if (scan.Id.ToUpper().Contains("ZHK BLASE"))
                {
                    BlaseHkCount++;
                }
            }

            // HK Rektum

            if (rectum != null)

            {
                Structure hk_rectum = ss.AddStructure("CONTROL", "zHK Rektum_" + RectumHkCount);

                hk_rectum.SegmentVolume = rectum.Margin(8.0);

                hk_rectum.SegmentVolume = hk_rectum.Sub(ptv);
            }



            // HK Blase (german for bladder)

            if (blase != null)

            {
                double             x1       = 5;
                double             y1       = 10;
                double             z1       = 15;
                double             x2       = 5;
                double             y2       = 20;
                double             z2       = 8;
                AxisAlignedMargins margins  = new AxisAlignedMargins(StructureMarginGeometry.Outer, x1, y1, z1, x2, y2, z2);
                Structure          hk_blase = ss.AddStructure("CONTROL", "zHK Blase_" + BlaseHkCount);

                hk_blase.SegmentVolume = blase.AsymmetricMargin(margins);

                hk_blase.SegmentVolume = hk_blase.Sub(ptv);
            }

            //============================

            // remove structures unneccesary for optimization

            //============================
            //ss.RemoveStructure(ptv_3mm);
            //ss.RemoveStructure(ptv_minus);
            //ss.RemoveStructure(Iso95);
        }
示例#12
0
        static void Planning(Application curapp, Patient curpat, StructureSet curstructset, List <Tuple <string, string, float, string> > TargetStructures, List <string> AllowedNonTargetStructures, float RxDose, int NFractions)
        {
            curpat.BeginModifications();

            string IDofptv_low  = string.Empty;
            string IDofptv_high = string.Empty; //

            StringBuilder sb = new StringBuilder();

            //Check structure nameing
            sb.AppendLine("Check Structure Naming");
            sb.AppendLine("Structure ID        \tIs Standard Name?");
            foreach (Structure curstruct in curstructset.Structures.OrderBy(x => x.Id))
            {
                if (curstruct.DicomType == "PTV" | curstruct.DicomType == "CTV" | curstruct.DicomType == "GTV")
                {
                    if (TargetStructures.Where(x => x.Item1 == curstruct.Id).Any() || TargetStructures.Where(x => curstruct.DicomType.ToString() + "_" + x.Item3 + (x.Item4 == "Gy" ? "00" : string.Empty) == curstruct.Id).Any())
                    {
                        sb.AppendLine(curstruct.Id.PadRight(curstruct.Id.Length < 20 ? 20 - curstruct.Id.Length : 0) + "\tYes");
                    }
                    else
                    {
                        sb.AppendLine(curstruct.Id.PadRight(curstruct.Id.Length < 20 ? 20 - curstruct.Id.Length : 0) + "\tNo");
                    }
                }
                else
                {
                    if (AllowedNonTargetStructures.Where(x => x == curstruct.Id).Any() || curstruct.Id.ToString().StartsWith("z"))
                    {
                        sb.AppendLine(curstruct.Id.PadRight(curstruct.Id.Length < 20 ? 20 - curstruct.Id.Length : 0) + "\tYes");
                    }
                    else
                    {
                        sb.AppendLine(curstruct.Id.PadRight(curstruct.Id.Length < 20 ? 20 - curstruct.Id.Length : 0) + "\tNo");
                    }
                }
            }
            sb.AppendLine();
            sb.AppendLine("Press OK to continue with creating optimization structures");
            System.Windows.MessageBox.Show(sb.ToString());



            //Create optimization structures
            if (TargetStructures.Where(x => x.Item1 == "PTV_Low").Any())
            {
                IDofptv_low = TargetStructures.Where(x => x.Item1 == "PTV_Low").Select(x => x.Item2).First();                                                      //Get the ID of the structure identified as PTV_Low
            }
            if (TargetStructures.Where(x => x.Item1 == "PTV_High").Any())
            {
                IDofptv_high = TargetStructures.Where(x => x.Item1 == "PTV_High").Select(x => x.Item2).First();                                                      //Get the ID of the structure identified as PTV_High
            }
            Structure ptv_low  = null;
            Structure ptv_high = null;


            //Check that PT_High structure exists, issue warning if it does not.
            if (curstructset.Structures.Where(x => x.Id == IDofptv_low).Any())
            {
                ptv_low = curstructset.Structures.Where(x => x.Id == IDofptv_low).First();
            }
            else
            {
                System.Windows.MessageBox.Show("Did not find a PTV_High Structure. Fix before proceeding");
            }

            //Check that PT_Low structure exists, issue warning if it does not.
            if (curstructset.Structures.Where(x => x.Id == IDofptv_high).Any())
            {
                ptv_high = curstructset.Structures.Where(x => x.Id == IDofptv_high).First();
            }
            else
            {
                System.Windows.MessageBox.Show("Did not find a PTV_Low Structure. Fix before proceeding");
            }


            //Creation of optimization structures. If a copy already exitst delete it first.

            //Optimization structure for the PTV_Low volume is named zPTV_Low^Opt
            if (curstructset.Structures.Where(x => x.Id.Contains("zPTV_Low^Opt")).Any())
            {
                curstructset.RemoveStructure(curstructset.Structures.Where(x => x.Id.Contains("zPTV_Low^Opt")).First());
            }
            Structure zptvlowopt = curstructset.AddStructure("ORGAN", "zPTV_Low^Opt");

            //Dose limiting annulus (DLA) structure is used to make the prescribed dose conformal. DLA for PTV_Low is named zDLA_Low
            if (curstructset.Structures.Where(x => x.Id.Contains("zDLA__Low")).Any())
            {
                curstructset.RemoveStructure(curstructset.Structures.Where(x => x.Id.Contains("zDLA__Low")).First());
            }
            Structure zdlalow = curstructset.AddStructure("ORGAN", "zDLA__Low");

            //Optimization structure for the PTV_High volume is named zPTV_High^Opt
            if (curstructset.Structures.Where(x => x.Id.Contains("zPTV_High^Opt")).Any())
            {
                curstructset.RemoveStructure(curstructset.Structures.Where(x => x.Id.Contains("zPTV_High^Opt")).First());
            }
            Structure zptvhighopt = curstructset.AddStructure("ORGAN", "zPTV_High^Opt");


            //Dose limiting annulus (DLA) structure is used to make the prescribed dose conformal. DLA for PTV_High is named zDLA_High
            if (curstructset.Structures.Where(x => x.Id.Contains("zDLA__High")).Any())
            {
                curstructset.RemoveStructure(curstructset.Structures.Where(x => x.Id.Contains("zDLA__High")).First());
            }
            Structure zdlahigh = curstructset.AddStructure("ORGAN", "zDLA__High");

            //Make zPTV_High^Opt from PTV_High and boolean out the rectum
            zptvhighopt.SegmentVolume = ptv_high.Margin(0.0f);
            zptvhighopt.SegmentVolume = zptvhighopt.Sub(curstructset.Structures.Where(x => x.Id.Contains("Rectum")).Single());//Boolean the Rectum out of the high dose ptv optimization structure


            //Make zPTV_Low^Opt from PTV_Low and boolean out the PTV_High structure
            zptvlowopt.SegmentVolume = ptv_low.Margin(0.0f);
            zptvlowopt.SegmentVolume = zptvlowopt.Sub(ptv_high.Margin(1.0f));//Boolean the ptv_high out of ptv_low optimization structure


            //Make a dose limiting annulus arround the low dose ptv optimization structure
            zdlalow.SegmentVolume = zptvlowopt.SegmentVolume;
            zdlalow.SegmentVolume = zdlalow.Margin(10.0f);
            zdlalow.SegmentVolume = zdlalow.Sub(zptvlowopt.Margin(1.0f));
            zdlalow.SegmentVolume = zdlalow.Sub(zptvhighopt.Margin(5.0f));

            //Make a dose limiting annulus arround the high dose ptv optimization structure
            zdlahigh.SegmentVolume = zptvhighopt.SegmentVolume;
            zdlahigh.SegmentVolume = zdlahigh.Margin(10.0f);
            zdlahigh.SegmentVolume = zdlahigh.Sub(zptvhighopt.Margin(1.0f));

            sb = new StringBuilder();
            sb.AppendLine("Done with creating optimization strutures");
            sb.AppendLine("Click OK to proceed with setting up course and VMAT plan");
            System.Windows.MessageBox.Show(sb.ToString());

            //Add course
            Course curcourse;

            if (curpat.Courses.Where(x => x.Id == "AutoPlan").Any())
            {
                curcourse = curpat.Courses.Where(x => x.Id == "AutoPlan").Single();
            }
            else
            {
                curcourse    = curpat.AddCourse();
                curcourse.Id = "AutoPlan";
            }

            //Remove PlanSetup if it exists then create new plan setup

            if (curcourse.PlanSetups.Where(x => x.Id == "AutoPlanVMAT").Any())
            {
                curcourse.RemovePlanSetup(curcourse.PlanSetups.Where(x => x.Id == "AutoPlanVMAT").Single());
            }
            ExternalPlanSetup cureps = curcourse.AddExternalPlanSetup(curstructset);

            cureps.Id = "AutoPlanVMAT";



            //Add VMAT Beams
            VVector isocenter = new VVector(Math.Round(ptv_high.CenterPoint.x / 10.0f) * 10.0f, Math.Round(ptv_high.CenterPoint.y / 10.0f) * 10.0f, Math.Round(ptv_high.CenterPoint.z / 10.0f) * 10.0f);
            ExternalBeamMachineParameters ebmp = new ExternalBeamMachineParameters("Truebeam", "6X", 600, "ARC", null);
            Beam VMAT1 = cureps.AddArcBeam(ebmp, new VRect <double>(-100, -100, 100, 100), 30, 181, 179, GantryDirection.Clockwise, 0, isocenter);
            Beam VMAT2 = cureps.AddArcBeam(ebmp, new VRect <double>(-100, -100, 100, 100), 330, 179, 181, GantryDirection.CounterClockwise, 0, isocenter);

            VMAT1.Id = "CW";
            VMAT2.Id = "CCW";

            VMAT1.FitCollimatorToStructure(new FitToStructureMargins(10), ptv_low, true, true, false);
            VMAT2.FitCollimatorToStructure(new FitToStructureMargins(10), ptv_low, true, true, false);



            cureps.SetCalculationModel(CalculationType.PhotonVMATOptimization, "PO_15014");
            cureps.SetPrescription(NFractions, new DoseValue(RxDose / NFractions, "Gy"), 1);

            curapp.SaveModifications();

            sb = new StringBuilder();
            sb.AppendLine("Done with setting up course and VMAT plan");
            sb.AppendLine("Click OK to proceed with plan optimization");
            System.Windows.MessageBox.Show(sb.ToString());

            float doseobjectivevalue_low  = TargetStructures.Where(x => x.Item1 == "PTV_Low").Select(x => x.Item3).First();
            float doseobjectivevalue_high = TargetStructures.Where(x => x.Item1 == "PTV_High").Select(x => x.Item3).First();


            cureps.OptimizationSetup.AddPointObjective(zptvlowopt, OptimizationObjectiveOperator.Lower, new DoseValue(doseobjectivevalue_low, "Gy"), 100, 100);
            cureps.OptimizationSetup.AddPointObjective(zptvlowopt, OptimizationObjectiveOperator.Upper, new DoseValue(doseobjectivevalue_low + 3.0f, "Gy"), 30, 50);
            cureps.OptimizationSetup.AddPointObjective(zdlalow, OptimizationObjectiveOperator.Upper, new DoseValue(doseobjectivevalue_low, "Gy"), 0, 50);

            cureps.OptimizationSetup.AddPointObjective(zptvhighopt, OptimizationObjectiveOperator.Lower, new DoseValue(doseobjectivevalue_high, "Gy"), 100, 120);
            cureps.OptimizationSetup.AddPointObjective(zptvhighopt, OptimizationObjectiveOperator.Upper, new DoseValue(doseobjectivevalue_high + 2.0f, "Gy"), 0, 100);
            cureps.OptimizationSetup.AddPointObjective(zdlahigh, OptimizationObjectiveOperator.Upper, new DoseValue(doseobjectivevalue_high, "Gy"), 0, 50);

            cureps.OptimizationSetup.AddNormalTissueObjective(80.0f, 0.0f, 100.0f, 40.0f, 0.05f);
            OptimizerResult optresult = cureps.OptimizeVMAT(new OptimizationOptionsVMAT(OptimizationIntermediateDoseOption.NoIntermediateDose, string.Empty));



            sb = new StringBuilder();
            sb.AppendLine("VMAT optimization is done");
            sb.AppendLine("NIterattions:" + optresult.NumberOfIMRTOptimizerIterations.ToString() + " , ObjectiveFunctionValue: " + optresult.TotalObjectiveFunctionValue.ToString());
            sb.AppendLine("Click OK to proceed with optimization");

            cureps.OptimizeVMAT();

            curapp.SaveModifications();

            sb = new StringBuilder();
            sb.AppendLine("Done with optimization");
            sb.AppendLine("Click OK to proceed with dose calculation");
            System.Windows.MessageBox.Show(sb.ToString());

            cureps.CalculateDose();
            //cureps.PlanNormalizationValue = 99.0f;

            curapp.SaveModifications();
            sb = new StringBuilder();
            sb.AppendLine("Done with dose calculation");

            if (cureps.StructureSet.Structures.Where(x => x.Id == "Rectum").Any())
            {
                Structure reportstructure = cureps.StructureSet.Structures.Where(x => x.Id == "Rectum").First();
                sb.AppendLine("Rectum:V65Gy[%]:" + cureps.GetVolumeAtDose(reportstructure, new DoseValue(65.0f, DoseValue.DoseUnit.Gy), VolumePresentation.Relative).ToString());
            }

            sb.AppendLine("PTV_High:D95%[Gy]:" + cureps.GetDoseAtVolume(ptv_high, 95.0f, VolumePresentation.Relative, DoseValuePresentation.Absolute).ToString());


            sb.AppendLine("Click OK to finish script");
            System.Windows.MessageBox.Show(sb.ToString());
        }
        public void Execute(ScriptContext context /*, System.Windows.Window window, ScriptEnvironment environment*/)
        {
            //============================
            // FIND Structure Set. If patient or structure set don't exist, show warning and exit code
            //============================

            if (context.Patient == null || context.StructureSet == null)
            {
                MessageBox.Show("Please load a patient, 3D image, and structure set before running this script.", SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            StructureSet ss = context.StructureSet;

            //============================
            // FIND Body and PTVs. If they don't exist, show warning and exit code
            //============================

            List <string> misingrois = new List <string>()
            {
            };

            Structure body = ss.Structures.FirstOrDefault(x => x.Id == BODY_ID);

            misingrois = CheckBaseROI(body, BODY_ID, SCRIPT_NAME, misingrois);

            Structure ptv_highclin = ss.Structures.FirstOrDefault(x => x.Id == PTVHIGHclin_ID);

            misingrois = CheckBaseROI(ptv_highclin, PTVHIGHclin_ID, SCRIPT_NAME, misingrois);

            Structure ptv_intclin = ss.Structures.FirstOrDefault(x => x.Id == PTVINTclin_ID);

            misingrois = CheckBaseROI(ptv_intclin, PTVINTclin_ID, SCRIPT_NAME, misingrois);

            Structure ptv_lowclin = ss.Structures.FirstOrDefault(x => x.Id == PTVLOWclin_ID);

            misingrois = CheckBaseROI(ptv_lowclin, PTVLOWclin_ID, SCRIPT_NAME, misingrois);

            if (misingrois.Count > 0)
            {
                foreach (string element in misingrois)
                {
                    MessageBox.Show(string.Format("'{0}' not found! Exiting script", element), SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                }
                return;
            }


            //============================
            // CHECK if PTV_HIGH already exists. If it does exist, show warning and exit code
            //============================
            // Do this because other structures that this code makes rely on it

            Structure check_PTVHigh = ss.Structures.FirstOrDefault(x => x.Id == PTVHIGH_ID);

            if (check_PTVHigh != null)
            {
                MessageBox.Show(string.Format("'{0}' already exists! Please delete or rename '{0}' and re-run script.", PTVHIGH_ID,
                                              PTVHIGH_ID), SCRIPT_NAME, MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }


            //============================
            // FIND OARs. If they don't exist, show warning and skip. CHECK for OAR_planning. If it exists, show warning and skip
            //============================

            // find Parotid L
            Structure parotid_L        = ss.Structures.FirstOrDefault(x => x.Id == PAROTID_L_ID);
            bool      flagOAR_parotidL = CheckOAR(PAROTID_L_ID, parotid_L, SCRIPT_NAME, ss, PAROTID_L_OPT_ID);

            // find Parotid R
            Structure parotid_R        = ss.Structures.FirstOrDefault(x => x.Id == PAROTID_R_ID);
            bool      flagOAR_parotidR = CheckOAR(PAROTID_R_ID, parotid_R, SCRIPT_NAME, ss, PAROTID_R_OPT_ID);

            // find Pharynx
            Structure pharynx         = ss.Structures.FirstOrDefault(x => x.Id == PHARYNX_ID);
            bool      flagOAR_pharynx = CheckOAR(PHARYNX_ID, pharynx, SCRIPT_NAME, ss, PHARYNX_OPT_ID);

            // find Brainstem
            Structure brainstem         = ss.Structures.FirstOrDefault(x => x.Id == BRAINSTEM_ID);
            bool      flagOAR_brainstem = CheckOAR(BRAINSTEM_ID, brainstem, SCRIPT_NAME, ss, BRAINSTEM3mm_ID);

            // find Spinal Cord
            Structure cord         = ss.Structures.FirstOrDefault(x => x.Id == CORD_ID);
            bool      flagOAR_cord = CheckOAR(CORD_ID, cord, SCRIPT_NAME, ss, CORD5mm_ID);


            //============================
            // CHECK if structures to be written already exist. If they do exist, show warning and skip creating those
            //============================

            // Check for PTV_INT_DVH
            bool flagPTV_INTDVH = CheckNewROI(PTVINTDVH_ID, ss, SCRIPT_NAME);

            // Check for PTV_INT_OPT
            bool flagPTV_INTOPT = CheckNewROI(PTVINTOPT_ID, ss, SCRIPT_NAME);

            // Check for PTV_LOW_DVH
            bool flagPTV_LOWDVH = CheckNewROI(PTVLOWDVH_ID, ss, SCRIPT_NAME);

            // Check for PTV_LOW_OPT
            bool flagPTV_LOWOPT = CheckNewROI(PTVLOWOPT_ID, ss, SCRIPT_NAME);

            // Check for 3_10mm RING
            bool flagPTV_RING = CheckNewROI(RING3_10_ID, ss, SCRIPT_NAME);


            context.Patient.BeginModifications();       // enable writing with this script.

            try
            {
                //============================
                // 1 GENERATE 3mm contraction of body
                //============================
                Structure body_3mm = ss.AddStructure("CONTROL", BODY3mm_ID);
                body_3mm.SegmentVolume = body.Margin(-3.0);

                string message1 = string.Format("{0} volume = {2}\n{1} created with volume = {3}",
                                                body.Id, body_3mm.Id, body.Volume, body_3mm.Volume);
                MessageBox.Show(message1);

                //============================
                // 2 GENERATE PTV_HIGH, PTV_INT, and PTV_LOW, from which is subtracted 3mm from body
                //============================

                Structure ptv_high = ss.AddStructure("PTV", PTVHIGH_ID);
                Structure ptv_int  = ss.AddStructure("PTV", PTVINT_ID);
                Structure ptv_low  = ss.AddStructure("PTV", PTVLOW_ID);
                ptv_high.SegmentVolume = ptv_highclin.And(body_3mm);
                ptv_int.SegmentVolume  = ptv_intclin.And(body_3mm);
                ptv_low.SegmentVolume  = ptv_lowclin.And(body_3mm);

                string message2 = string.Format("{0} volume = {6}\n{1} created with volume = {7}\n{2} volume = " +
                                                "{8}\n{3} created with volume = {9}\n{4} volume = {10}\n{5} created with volume {11}",
                                                ptv_highclin.Id, ptv_high.Id, ptv_intclin.Id, ptv_int.Id, ptv_lowclin.Id, ptv_low.Id,
                                                ptv_highclin.Volume, ptv_high.Volume, ptv_intclin.Volume, ptv_int.Volume, ptv_lowclin.Volume, ptv_low.Volume);
                MessageBox.Show(message2);

                //============================
                // 3 GENERATE PTV_ALL, which is PTV_HIGH + PTV_INT + PTV+LOW
                //============================
                Structure ptv_highint = ss.AddStructure("PTV", PTVHIGHINT_ID);
                Structure ptv_all     = ss.AddStructure("PTV", PTVALL_ID);
                ptv_highint.SegmentVolume = ptv_high.Or(ptv_int);
                ptv_all.SegmentVolume     = ptv_highint.Or(ptv_low);

                string message3 = string.Format("{0} volume = {5}\n{1} volume = {6}\n{2} created with volume = {7}" +
                                                "\n{3} volume = {8}\n{4} created with volume = {9}",
                                                ptv_high.Id, ptv_int.Id, ptv_highint.Id, ptv_low.Id, ptv_all.Id,
                                                ptv_high.Volume, ptv_int.Volume, ptv_highint.Volume, ptv_low.Volume, ptv_all.Volume);
                MessageBox.Show(message3);

                //============================
                // 4 GENERATE PTV_INT_DVH, which is PTV_INT Subtracting PTV_HIGH
                //============================
                if (flagPTV_INTDVH == true)
                {
                    Structure ptv_intdvh = ss.AddStructure("PTV", PTVINTDVH_ID);
                    ptv_intdvh.SegmentVolume = ptv_int.Sub(ptv_high);

                    string message4 = string.Format("{0} volume = {2}\n{1} created with volume = {3}",
                                                    ptv_int.Id, ptv_intdvh.Id, ptv_int.Volume, ptv_intdvh.Volume);
                    MessageBox.Show(message4);
                }

                //============================
                // 5 GENERATE PTV_INT_OPT, which is PTV_INT Subtracting PTV_HIGH+3mm
                //============================
                if (flagPTV_INTOPT == true)
                {
                    Structure ptv_high3mm = ss.AddStructure("PTV", PTVHIGH3mm_ID);
                    Structure ptv_intopt  = ss.AddStructure("PTV", PTVINTOPT_ID);
                    ptv_high3mm.SegmentVolume = ptv_high.Margin(3.0);
                    ptv_intopt.SegmentVolume  = ptv_int.Sub(ptv_high3mm);

                    string message5 = string.Format("{0} volume = {4}\n{1} created with volume = {5}\n" +
                                                    "{2} volume = {6}\n{3} created with volume = {7}",
                                                    ptv_high.Id, ptv_high3mm.Id, ptv_int.Id, ptv_intopt.Id,
                                                    ptv_high.Volume, ptv_high3mm.Volume, ptv_int.Volume, ptv_intopt.Volume);
                    MessageBox.Show(message5);

                    ss.RemoveStructure(ptv_high3mm);
                }

                //============================
                // 6 GENERATE PTV_LOW_DVH, which is PTV_LOW Subtracting PTV_HIGH+INT
                //============================
                if (flagPTV_LOWDVH == true)
                {
                    Structure ptv_lowdvh = ss.AddStructure("PTV", PTVLOWDVH_ID);
                    ptv_lowdvh.SegmentVolume = ptv_low.Sub(ptv_highint);

                    string message6 = string.Format("{0} volume = {2}\n{1} created with volume = {3}",
                                                    ptv_low.Id, ptv_lowdvh.Id, ptv_low.Volume, ptv_lowdvh.Volume);
                    MessageBox.Show(message6);
                }

                //============================
                // 7 GENERATE PTV_LOW_OPT, which is PTV_LOW Subtracting PTV_HIGH+INT+3mm
                //============================
                if (flagPTV_LOWOPT == true)
                {
                    Structure ptv_highint3mm = ss.AddStructure("PTV", PTVHIGHINT3mm_ID);
                    Structure ptv_lowopt     = ss.AddStructure("PTV", PTVLOWOPT_ID);
                    ptv_highint3mm.SegmentVolume = ptv_highint.Margin(3.0);
                    ptv_lowopt.SegmentVolume     = ptv_low.Sub(ptv_highint3mm);

                    string message7 = string.Format("{0} volume = {4}\n{1} created with volume = {5}\n" +
                                                    "{2} volume = {6}\n{3} created with volume = {7}",
                                                    ptv_highint.Id, ptv_highint3mm.Id, ptv_low.Id, ptv_lowopt.Id,
                                                    ptv_highint.Volume, ptv_highint3mm.Volume, ptv_low.Volume, ptv_lowopt.Volume);
                    MessageBox.Show(message7);

                    ss.RemoveStructure(ptv_highint3mm);
                }

                //============================
                // 8 GENERATE 3_10mm RING, which is PTV_ALL+10mm Subtracting PTV_ALL+3mm
                //============================
                if (flagPTV_RING == true)
                {
                    Structure ptv_all3mm   = ss.AddStructure("CONTROL", PTVALL3mm_ID);
                    Structure ptv_all10mm  = ss.AddStructure("CONTROL", PTVALL10mm_ID);
                    Structure ring_3_10pre = ss.AddStructure("CONTROL", RING3_10PRE_ID);
                    Structure ring_3_10    = ss.AddStructure("CONTROL", RING3_10_ID);
                    ptv_all3mm.SegmentVolume   = ptv_all.Margin(3.0);
                    ptv_all10mm.SegmentVolume  = ptv_all.Margin(10.0);
                    ring_3_10pre.SegmentVolume = ptv_all10mm.Sub(ptv_all3mm);
                    ring_3_10.SegmentVolume    = ring_3_10pre.And(body_3mm);

                    string message8 = string.Format("{0} was created with volume {1}.", ring_3_10.Id, ring_3_10.Volume);

                    MessageBox.Show(message8);

                    ss.RemoveStructure(ptv_all3mm);
                    ss.RemoveStructure(ptv_all10mm);
                    ss.RemoveStructure(ring_3_10pre);
                }


                //============================
                // 101 SUBTRACT from the parotids (L and R) the PTVs
                //============================
                if (flagOAR_parotidL == true)
                {
                    Structure parotid_L_oar = ss.AddStructure("AVOIDANCE", PAROTID_L_OPT_ID);
                    parotid_L_oar.SegmentVolume = parotid_L.Sub(ptv_all);

                    string message101_L = string.Format("{0} volume = {2}\n{1} created with volume = {3}",
                                                        parotid_L.Id, parotid_L_oar.Id, parotid_L.Volume, parotid_L_oar.Volume);
                    MessageBox.Show(message101_L);
                }

                if (flagOAR_parotidR == true)
                {
                    Structure parotid_R_oar = ss.AddStructure("AVOIDANCE", PAROTID_R_OPT_ID);
                    parotid_R_oar.SegmentVolume = parotid_R.Sub(ptv_all);

                    string message101_R = string.Format("{0} volume = {2}\n{1} created with volume = {3}",
                                                        parotid_R.Id, parotid_R_oar.Id, parotid_R.Volume, parotid_R_oar.Volume);
                    MessageBox.Show(message101_R);
                }

                //============================
                // 102 SUBTRACT from the pharynx the PTVs
                //============================
                if (flagOAR_pharynx == true)
                {
                    Structure pharynx_oar = ss.AddStructure("AVOIDANCE", PHARYNX_OPT_ID);
                    // Check if a high res structure. If so, try copying to a new, non high res structure
                    if (pharynx.IsHighResolution == true)
                    {
                        pharynx_oar.ConvertToHighResolution();
                        // Can I skip specifying that?
                        const string PTV_ALL_HIGHRES_ID = "PTV_ALL_HighRes";
                        Structure    ptv_all_highres    = ss.AddStructure("CONTROL", PTV_ALL_HIGHRES_ID);
                        ptv_all_highres.SegmentVolume = ptv_all.SegmentVolume;
                        ptv_all_highres.ConvertToHighResolution();
                        pharynx_oar.SegmentVolume = pharynx.Sub(ptv_all_highres);
                        ss.RemoveStructure(ptv_all_highres);

                        string message102HR = string.Format("{0} was a high resolution structure.", pharynx.Id);
                        MessageBox.Show(message102HR);
                    }
                    else
                    {
                        pharynx_oar.SegmentVolume = pharynx.Sub(ptv_all);
                    }

                    string message102 = string.Format("{0} volume = {2}\n{1} created with volume = {3}",
                                                      pharynx.Id, pharynx_oar.Id, pharynx.Volume, pharynx_oar.Volume);
                    MessageBox.Show(message102);
                }

                //============================
                // 103 EXPAND the Brainstem 3mm
                //============================
                if (flagOAR_brainstem == true)
                {
                    Structure brainstem_PRV = ss.AddStructure("AVOIDANCE", BRAINSTEM3mm_ID);
                    brainstem_PRV.SegmentVolume = brainstem.Margin(3.0);

                    string message103 = string.Format("{0} volume = {2}\n{1} created with volume {3}",
                                                      brainstem.Id, brainstem_PRV.Id, brainstem.Volume, brainstem_PRV.Volume);
                    MessageBox.Show(message103);
                }

                //============================
                // 104 EXPAND the Brainstem 3mm
                //============================
                if (flagOAR_cord == true)
                {
                    Structure cord_PRV = ss.AddStructure("AVOIDANCE", CORD5mm_ID);
                    cord_PRV.SegmentVolume = cord.Margin(5.0);

                    string message104 = string.Format("{0} volume = {2}\n{1} created with volume {3}",
                                                      cord.Id, cord_PRV.Id, cord.Volume, cord_PRV.Volume);
                    MessageBox.Show(message104);
                }

                //============================
                // PRINT out all relevant structures. Delete the rest! **** FOR FINAL VERSION
                //============================
                ss.RemoveStructure(body_3mm);
                ss.RemoveStructure(ptv_int);
                ss.RemoveStructure(ptv_low);
                ss.RemoveStructure(ptv_highint);
                ss.RemoveStructure(ptv_all);
            }


            catch (Exception e)
            {
                string messageError = string.Format("{0} Exception caught.", e);
                MessageBox.Show(messageError);
            }
        }
示例#14
0
        //function used to cnotour the overlap between fields in adjacent isocenters for the VMAT Plan ONLY!
        //this option is requested by the user by selecting the checkbox on the main UI on the beam placement tab
        private void contourFieldOverlap(List <VVector> isoLocations)
        {
            //grab the image and get the z resolution and dicom origin (we only care about the z position of the dicom origin)
            Image   image       = selectedSS.Image;
            double  zResolution = image.ZRes;
            VVector dicomOrigin = image.Origin;
            //center position between adjacent isocenters, number of image slices to contour on, start image slice location for contouring
            List <Tuple <double, int, int> > overlap = new List <Tuple <double, int, int> > {
            };

            //calculate the center position between adjacent isocenters, number of image slices to contour on based on overlap and with additional user-specified margin (from main UI)
            //and the slice where the contouring should begin
            //string output = "";
            for (int i = 1; i < numVMATIsos; i++)
            {
                //calculate the center position between adjacent isocenters. NOTE: this calculation works from superior to inferior!
                double center = isoLocations.ElementAt(i - 1).z + (isoLocations.ElementAt(i).z - isoLocations.ElementAt(i - 1).z) / 2;
                //this is left as a double so I can cast it to an int in the second overlap item and use it in the calculation in the third overlap item
                double numSlices = Math.Ceiling(400.0 + contourOverlapMargin - Math.Abs(isoLocations.ElementAt(i).z - isoLocations.ElementAt(i - 1).z));
                overlap.Add(new Tuple <double, int, int>(
                                center,
                                (int)(numSlices / zResolution),
                                (int)(Math.Abs(dicomOrigin.z - center + numSlices / 2) / zResolution)));
                //add a new junction structure (named TS_jnx<i>) to the stack. Contours will be added to these structure later
                jnxs.Add(selectedSS.AddStructure("CONTROL", string.Format("TS_jnx{0}", i)));
                //output += String.Format("{0}, {1}, {2}\n",
                //    isoLocations.ElementAt(i - 1).z + (isoLocations.ElementAt(i).z - isoLocations.ElementAt(i - 1).z) / 2,
                //    (int)Math.Ceiling((410.0 - Math.Abs(isoLocations.ElementAt(i).z - isoLocations.ElementAt(i - 1).z)) / zResolution),
                //    (int)(Math.Abs(dicomOrigin.z - (isoLocations.ElementAt(i - 1).z + ((isoLocations.ElementAt(i).z - isoLocations.ElementAt(i - 1).z) / 2)) + Math.Ceiling((410.0 - Math.Abs(isoLocations.ElementAt(i).z - isoLocations.ElementAt(i - 1).z))/2)) / zResolution));
            }
            //MessageBox.Show(output);

            //make a box at the min/max x,y positions of the target structure with 5 cm margin
            Point3DCollection targetPts = target.MeshGeometry.Positions;
            double            xMax      = targetPts.Max(p => p.X) + 50.0;
            double            xMin      = targetPts.Min(p => p.X) - 50.0;
            double            yMax      = targetPts.Max(p => p.Y) + 50.0;
            double            yMin      = targetPts.Min(p => p.Y) - 50.0;

            VVector[] pts = new[] {
                new VVector(xMax, yMax, 0),
                new VVector(xMax, 0, 0),
                new VVector(xMax, yMin, 0),
                new VVector(0, yMin, 0),
                new VVector(xMin, yMin, 0),
                new VVector(xMin, 0, 0),
                new VVector(xMin, yMax, 0),
                new VVector(0, yMax, 0)
            };

            //add the contours to each relevant plan for each structure in the jnxs stack
            int count = 0;

            foreach (Tuple <double, int, int> value in overlap)
            {
                for (int i = value.Item3; i < (value.Item3 + value.Item2); i++)
                {
                    jnxs.ElementAt(count).AddContourOnImagePlane(pts, i);
                }
                //only keep the portion of the box contour that overlaps with the target
                jnxs.ElementAt(count).SegmentVolume = jnxs.ElementAt(count).And(target.Margin(0));
                count++;
            }
        }
示例#15
0
        protected void WriteDoseStatisticsXML_HeadAndNeck2GyOrLess(Patient patient, StructureSet ss, PlanningItem plan, XmlWriter writer)
        {
            // find stats for the Brachial Plexus structure
            addStructurePQM(plan, ss, BrachialPlexus.searchIds, BrachialPlexus.PQMs, writer);

            // find stats for the Brain structure
            addStructurePQM(plan, ss, Brain.searchIds, Brain.PQMs, writer);

            // find stats for the Brainstem structure
            addStructurePQM(plan, ss, Brainstem.searchIds, Brainstem.PQMs, writer);

            // find stats for the Cochlea structure
            addStructurePQM(plan, ss, Cochlea.searchIds, Cochlea.PQMs, writer);

            // find stats for the Esophagus structure
            addStructurePQM(plan, ss, Esophagus.searchIds, Esophagus.PQMs, writer);

            // find stats for the Eye lens structures
            addStructurePQM(plan, ss, LensLeft.searchIds, LensLeft.PQMs, writer);
            addStructurePQM(plan, ss, LensRight.searchIds, LensRight.PQMs, writer);

            // find stats for the Eye structures
            addStructurePQM(plan, ss, OrbitLeft.searchIds, OrbitLeft.PQMs, writer);
            addStructurePQM(plan, ss, OrbitRight.searchIds, OrbitRight.PQMs, writer);

            // find stats for the Optic Nerve structures
            addStructurePQM(plan, ss, OpticNerveLeft.searchIds, OpticNerveLeft.PQMs, writer);
            addStructurePQM(plan, ss, OpticNerveRight.searchIds, OpticNerveRight.PQMs, writer);
            addStructurePQM(plan, ss, OpticChiasm.searchIds, OpticChiasm.PQMs, writer);

            // find stats for the Larynx structures
            addStructurePQM(plan, ss, Larynx.searchIds, Larynx.PQMs, writer);

            // find stats for the Lung structures (Lung (whole organ; target volume is NOT within the lung))
            addStructurePQM(plan, ss, LungLeft.searchIds, LungLeft.PQMs, writer);
            addStructurePQM(plan, ss, LungRight.searchIds, LungRight.PQMs, writer);

            // parotids
            addStructurePQM(plan, ss, ParotidLeft.searchIds, ParotidLeft.PQMs, writer);
            addStructurePQM(plan, ss, ParotidRight.searchIds, ParotidRight.PQMs, writer);

            // combined parotids (cut this out for version 11, won't work)
#if v13_ESAPI
            if (patient.CanModifyData())
            {
                int count = 0;
                patient.BeginModifications(); // enable writing with this script.
                // create the empty "Parotid Combined" structure
                string    ID = "Parotid Combined";
                Structure parotid_combined = ss.AddStructure("AVOIDANCE", ID);

                // search for left parotid, if found combine it into 'parotid_combined'
                foreach (string volumeId in ParotidLeft.searchIds)
                {
                    Structure oar = (from s in ss.Structures
                                     where s.Id.ToUpper().CompareTo(volumeId.ToUpper()) == 0
                                     select s).FirstOrDefault();
                    if (oar != null)
                    {
                        count++;
                        parotid_combined.SegmentVolume = parotid_combined.Or(oar);
                        break;
                    }
                }

                // search for right parotid, if found combine it into 'parotid_combined'
                foreach (string volumeId in ParotidRight.searchIds)
                {
                    Structure oar = (from s in ss.Structures
                                     where s.Id.ToUpper().CompareTo(volumeId.ToUpper()) == 0
                                     select s).FirstOrDefault();
                    if (oar != null)
                    {
                        count++;
                        parotid_combined.SegmentVolume = parotid_combined.Or(oar);
                        break;
                    }
                }
                if (count > 0)
                {
                    string[] searchIds = { ID };
                    addStructurePQM(plan, ss, searchIds, ParotidsCombined.PQMs, writer);
                }
                ss.RemoveStructure(parotid_combined);
            }
#endif
            // find stats for the spinal cord structure
            addStructurePQM(plan, ss, SpinalCord.searchIds, SpinalCord.PQMs, writer);

            // find stats for the Mandible structure
            addStructurePQM(plan, ss, Mandible.searchIds, Mandible.PQMs, writer);

            // find stats for the Oral Cavity structure
            addStructurePQM(plan, ss, OralCavity.searchIds, OralCavity.PQMs, writer);

            // find stats for the Pharynx structure
            addStructurePQM(plan, ss, Pharynx.searchIds, Pharynx.PQMs, writer);

            // find stats for the PharyngealConstrictor structure
            addStructurePQM(plan, ss, PharyngealConstrictor.searchIds, PharyngealConstrictor.PQMs, writer);

            // find stats for the submandibular structure
            addStructurePQM(plan, ss, Submandibular.searchIds, Submandibular.PQMs, writer);

            // find stats for the Thyroid structure
            addStructurePQM(plan, ss, Thyroid.searchIds, Thyroid.PQMs, writer);

            //      writer.WriteEndElement(); // </DoseStatistics>
        }