Exemple #1
0
        private bool createTSStructures()
        {
            if (RemoveOldTSStructures(TS_structures))
            {
                return(true);
            }

            if (scleroTrial)
            {
                if (RemoveOldTSStructures(scleroStructures))
                {
                    return(true);
                }
            }

            //determine if any TS structures need to be added to the selected structure set (i.e., were not present or were removed in the first foreach loop)
            //this is provided here to only add additional TS if they are relevant to the current case (i.e., it doesn't make sense to add the brain TS's if we
            //are not interested in sparing brain)
            foreach (Tuple <string, string, double> itr in spareStructList)
            {
                optParameters.Add(Tuple.Create(itr.Item1, itr.Item2));
                if (itr.Item1.ToLower().Contains("lungs"))
                {
                    foreach (Tuple <string, string> itr1 in TS_structures.Where(x => x.Item2.ToLower().Contains("lungs")))
                    {
                        AddTSStructures(itr1);
                    }
                    //do NOT add the scleroStructures to the addedStructures vector as these will be handled manually!
                    if (scleroTrial)
                    {
                        if (selectedSS.CanAddStructure("CONTROL", "Lung_Block_L"))
                        {
                            selectedSS.AddStructure("CONTROL", "Lung_Block_L");
                        }
                        if (selectedSS.CanAddStructure("CONTROL", "Lung_Block_R"))
                        {
                            selectedSS.AddStructure("CONTROL", "Lung_Block_R");
                        }
                        if (selectedSS.CanAddStructure("CONTROL", "Lungs_Eval"))
                        {
                            selectedSS.AddStructure("CONTROL", "Lungs_Eval");
                        }
                    }
                }
                else if (itr.Item1.ToLower().Contains("liver"))
                {
                    foreach (Tuple <string, string> itr1 in TS_structures.Where(x => x.Item2.ToLower().Contains("liver")))
                    {
                        AddTSStructures(itr1);
                    }
                }
                else if (itr.Item1.ToLower().Contains("brain"))
                {
                    foreach (Tuple <string, string> itr1 in TS_structures.Where(x => x.Item2.ToLower().Contains("brain")))
                    {
                        AddTSStructures(itr1);
                    }
                }
                else if (itr.Item1.ToLower().Contains("kidneys"))
                {
                    foreach (Tuple <string, string> itr1 in TS_structures.Where(x => x.Item2.ToLower().Contains("kidneys")))
                    {
                        AddTSStructures(itr1);
                    }
                    //do NOT add the scleroStructures to the addedStructures vector as these will be handled manually!
                    if (scleroTrial)
                    {
                        if (selectedSS.CanAddStructure("CONTROL", "Kidney_Block_R"))
                        {
                            selectedSS.AddStructure("CONTROL", "Kidney_Block_R");
                        }
                        if (selectedSS.CanAddStructure("CONTROL", "Kidney_Block_L"))
                        {
                            selectedSS.AddStructure("CONTROL", "Kidney_Block_L");
                        }
                    }
                }
            }

            if (scleroTrial)
            {
                foreach (Tuple <string, string> itr in scleroStructures)
                {
                    Structure tmp  = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == itr.Item2.ToLower());
                    Structure tmp1 = null;
                    if (itr.Item2.ToLower().Contains("lung_block_l"))
                    {
                        //AxisAlignedMargins(inner or outer margin, margin from negative x, margin for negative y, margin for negative z, margin for positive x, margin for positive y, margin for positive z)
                        tmp1 = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "lung_l");
                        if (tmp1 != null)
                        {
                            tmp.SegmentVolume = tmp1.AsymmetricMargin(new AxisAlignedMargins(
                                                                          StructureMarginGeometry.Inner,
                                                                          10.0,
                                                                          10.0,
                                                                          15.0,
                                                                          10.0,
                                                                          10.0,
                                                                          10.0));
                        }
                    }
                    else if (itr.Item2.ToLower().Contains("lung_block_r"))
                    {
                        tmp1 = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "lung_r");
                        if (tmp1 != null)
                        {
                            tmp.SegmentVolume = tmp1.AsymmetricMargin(new AxisAlignedMargins(
                                                                          StructureMarginGeometry.Inner,
                                                                          10.0,
                                                                          10.0,
                                                                          15.0,
                                                                          10.0,
                                                                          10.0,
                                                                          10.0));
                        }
                    }
                    else if (itr.Item2.ToLower().Contains("lungs_eval"))
                    {
                        tmp1 = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "lung_block_l");
                        Structure tmp2 = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "lung_block_r");
                        if (tmp1 != null && tmp2 != null)
                        {
                            tmp.SegmentVolume = tmp2.Or(tmp1.Margin(0.0));
                        }
                    }
                    else if (itr.Item2.ToLower().Contains("kidney_block_l"))
                    {
                        tmp1 = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "kidney_l");
                        if (tmp1 != null)
                        {
                            tmp.SegmentVolume = tmp1.AsymmetricMargin(new AxisAlignedMargins(
                                                                          StructureMarginGeometry.Outer,
                                                                          5.0,
                                                                          20.0,
                                                                          20.0,
                                                                          20.0,
                                                                          20.0,
                                                                          20.0));
                        }
                    }
                    else
                    {
                        tmp1 = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "kidney_r");
                        if (tmp1 != null)
                        {
                            tmp.SegmentVolume = tmp1.AsymmetricMargin(new AxisAlignedMargins(
                                                                          StructureMarginGeometry.Outer,
                                                                          20.0,
                                                                          20.0,
                                                                          20.0,
                                                                          5.0,
                                                                          20.0,
                                                                          20.0));
                        }
                    }
                }
            }

            //now contour the various structures
            foreach (string s in addedStructures)
            {
                Structure tmp = selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == s.ToLower());
                //MessageBox.Show(s);
                if (!(s.ToLower().Contains("ptv")))
                {
                    Structure tmp1   = null;
                    double    margin = 0.0;
                    if (s.ToLower().Contains("human"))
                    {
                        tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "body");
                    }
                    else if (s.ToLower().Contains("lungs"))
                    {
                        if (selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "lungs_lowres") == null)
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "lungs");
                        }
                        else
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "lungs_lowres");
                        }
                    }
                    else if (s.ToLower().Contains("liver"))
                    {
                        if (selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "liver_lowres") == null)
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "liver");
                        }
                        else
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "liver_lowres");
                        }
                    }
                    else if (s.ToLower().Contains("kidneys"))
                    {
                        if (selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "kidneys_lowres") == null)
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "kidneys");
                        }
                        else
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "kidneys_lowres");
                        }
                    }
                    else if (s.ToLower().Contains("brain"))
                    {
                        if (selectedSS.Structures.FirstOrDefault(x => x.Id.ToLower() == "brain_lowres") == null)
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "brain");
                        }
                        else
                        {
                            tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "brain_lowres");
                        }
                    }

                    //all structures in TS_structures and scleroStructures are inner margins, which is why the below code works.
                    int pos1 = s.IndexOf("-");
                    int pos2 = s.IndexOf("cm");
                    if (pos1 != -1 && pos2 != -1)
                    {
                        double.TryParse(s.Substring(pos1, pos2 - pos1), out margin);
                    }

                    //convert from cm to mm
                    tmp.SegmentVolume = tmp1.Margin(margin * 10);
                }
                else if (s.ToLower() == "ptv_body")
                {
                    //get the body contour and create the ptv structure using the user-specified inner margin
                    Structure tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "body");
                    tmp.SegmentVolume = tmp1.Margin(-targetMargin * 10);

                    //subtract all the structures the user wants to spare from PTV_Body
                    foreach (Tuple <string, string, double> spare in spareStructList)
                    {
                        if (spare.Item2 == "Mean Dose < Rx Dose")
                        {
                            if (spare.Item1.ToLower() == "kidneys" && scleroTrial)
                            {
                                tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "kidney_block_r");
                                tmp.SegmentVolume = tmp.Sub(tmp1.Margin(0.0));
                                tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "kidney_block_l");
                                tmp.SegmentVolume = tmp.Sub(tmp1.Margin(0.0));
                            }
                            else
                            {
                                tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == spare.Item1.ToLower());
                                tmp.SegmentVolume = tmp.Sub(tmp1.Margin((spare.Item3) * 10));
                            }
                        }
                    }
                }
                else if (s.ToLower() == "ts_ptv_vmat")
                {
                    //copy the ptv_body contour onto the TS_ptv_vmat contour
                    Structure tmp1 = selectedSS.Structures.First(x => x.Id.ToLower() == "ptv_body");
                    tmp.SegmentVolume = tmp1.Margin(0.0);

                    //matchplane exists and needs to be cut from TS_PTV_Body. Also remove all TS_PTV_Body segements inferior to match plane
                    if (selectedSS.Structures.Where(x => x.Id.ToLower() == "matchline").Any())
                    {
                        //find the image plane where the matchline is location. Record this value and break the loop. Also find the first slice where the ptv_body contour starts and record this value
                        Structure matchline      = selectedSS.Structures.First(x => x.Id.ToLower() == "matchline");
                        bool      lowLimNotFound = true;
                        int       lowLim         = -1;
                        if (!matchline.IsEmpty)
                        {
                            int matchplaneLocation = 0;
                            for (int i = 0; i != selectedSS.Image.ZSize - 1; i++)
                            {
                                if (matchline.GetContoursOnImagePlane(i).Any())
                                {
                                    matchplaneLocation = i;
                                    break;
                                }
                                if (lowLimNotFound && tmp1.GetContoursOnImagePlane(i).Any())
                                {
                                    lowLim         = i;
                                    lowLimNotFound = false;
                                }
                            }

                            if (selectedSS.Structures.Where(x => x.Id.ToLower() == "dummybox").Any())
                            {
                                selectedSS.RemoveStructure(selectedSS.Structures.First(x => x.Id.ToLower() == "dummybox"));
                            }
                            Structure dummyBox = selectedSS.AddStructure("CONTROL", "DummyBox");

                            //get min/max positions of ptv_body contour to contour the dummy box for creating TS_PTV_Legs
                            Point3DCollection ptv_bodyPts = tmp1.MeshGeometry.Positions;
                            double            xMax        = ptv_bodyPts.Max(p => p.X) + 50.0;
                            double            xMin        = ptv_bodyPts.Min(p => p.X) - 50.0;
                            double            yMax        = ptv_bodyPts.Max(p => p.Y) + 50.0;
                            double            yMin        = ptv_bodyPts.Min(p => p.Y) - 50.0;

                            //box with contour points located at (x,y), (x,0), (x,-y), (0,-y), (-x,-y), (-x,0), (-x, y), (0,y)
                            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)
                            };

                            //give 5cm margin on TS_PTV_LEGS (one slice of the CT should be 5mm) in case user wants to include flash up to 5 cm
                            for (int i = matchplaneLocation - 1; i > lowLim - 10; i--)
                            {
                                dummyBox.AddContourOnImagePlane(pts, i);
                            }

                            //do the structure manipulation
                            if (selectedSS.Structures.Where(x => x.Id.ToLower() == "ts_ptv_legs").Any())
                            {
                                selectedSS.RemoveStructure(selectedSS.Structures.First(x => x.Id.ToLower() == "ts_ptv_legs"));
                            }
                            Structure TS_legs = selectedSS.AddStructure("CONTROL", "TS_PTV_Legs");
                            TS_legs.SegmentVolume = dummyBox.And(tmp.Margin(0));
                            //subtract both dummybox and matchline from TS_PTV_VMAT
                            tmp.SegmentVolume = tmp.Sub(dummyBox.Margin(0.0));
                            tmp.SegmentVolume = tmp.Sub(matchline.Margin(0.0));
                            //remove the dummybox structure if flash is NOT being used as its no longer needed
                            if (!useFlash)
                            {
                                selectedSS.RemoveStructure(dummyBox);
                            }
                        }
                    }
                }
            }
            return(false);
        }
Exemple #2
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);
        }
Exemple #3
0
        /// <summary>
        /// Gets 2D shape of the mesh. Checks all verticies regardless of z axis. Uses a grid-based approach:
        /// breaks an area up into x-y grid and if it detects one or more points in that square, it is considered filled
        /// The countour is around these filled squares
        /// </summary>
        /// <param name="points">The points from a mesh</param>
        /// <param name="size">The resolution size</param>
        /// <returns>List of 2D points for the contour</returns>
        private List <Point> GetContour(Point3DCollection points, double size)
        {
            if (points.Count > 0)
            {
                double offset = 3; //used to give some space at the start of the contour boxes
                double bottom_x, top_x, bottom_y, top_y;

                bottom_x = points.Min(p => p.X);
                top_x    = points.Max(p => p.X) - bottom_x;
                bottom_y = points.Min(p => p.Y);
                top_y    = points.Max(p => p.Y) - bottom_y;

                double gridsize = size;
                double start_x  = bottom_x - gridsize - offset;
                double start_y  = bottom_y - gridsize - offset;

                int x_grid = Convert.ToInt16((top_x - start_x) / gridsize) + 1;
                int y_grid = Convert.ToInt16((top_y - start_y) / gridsize) + 1;
                bool[,] contourgrid = new bool[x_grid, y_grid];

                //finds which box areas contain the model's positions
                for (int y = 0; y < y_grid; y++)
                {
                    double            lowY     = start_y + y * gridsize;
                    double            highY    = lowY + gridsize;
                    Point3DCollection points_y = new Point3DCollection();
                    foreach (Point3D p in points)
                    {
                        if (p.Y > lowY && p.Y < highY)
                        {
                            points_y.Add(p);
                        }
                    }

                    for (int x = 0; x < x_grid; x++)
                    {
                        double lowX  = start_x + x * gridsize;
                        double highX = lowX + gridsize;
                        foreach (Point3D p in points_y)
                        {
                            if (p.X > lowX && p.X < highX)
                            {
                                contourgrid[x, y] = true;
                                break;
                            }
                        }
                    }
                }

                FillHoles(contourgrid);

                //create contour points by finding boxes that are adjacent to the edge of the good boxes
                List <Point> contourPointsList = new List <Point>();
                for (int y = 0; y < y_grid; y++)
                {
                    for (int x = 0; x < x_grid; x++)
                    {
                        int sides = AdjacentGoodBoxes(x, y, contourgrid);
                        if (sides > 0 && sides < 4 && !contourgrid[x, y])//beside a good box and not a good box itself
                        {
                            Point point = new Point(start_x + x * gridsize + gridsize / 2, start_y + y * gridsize + gridsize / 2);
                            contourPointsList.Add(point);
                        }
                    }
                }

                return(contourPointsList);
            }

            return(null);
        }
        public Point3DCollection GetCoordinatesForBoundingBox(Point3DCollection positions)
        {
            const double distance = 10.0;
            const double half     = 2.0;

            var minX = positions.Min(x => x.X);
            var minY = positions.Min(x => x.Y);
            var minZ = positions.Min(x => x.Z);
            var maxX = positions.Max(x => x.X);
            var maxY = positions.Max(x => x.Y);
            var maxZ = positions.Max(x => x.Z);

            return(new Point3DCollection
            {
                //Upper
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = (maxY + minY) / half,
                    Z = maxZ
                },
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = (maxY + minY) / half,
                    Z = maxZ + distance
                },

                //Left
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = maxY,
                    Z = (maxZ + minZ) / half
                },
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = maxY + distance,
                    Z = (maxZ + minZ) / half
                },

                //Down
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = (maxY + minY) / half,
                    Z = minZ
                },
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = (maxY + minY) / half,
                    Z = minZ - distance
                },

                //Face
                new Point3D
                {
                    X = maxX,
                    Y = (maxY + minY) / half,
                    Z = (minZ + maxZ) / half
                },
                new Point3D
                {
                    X = maxX + distance,
                    Y = (maxY + minY) / half,
                    Z = (minZ + maxZ) / half
                },

                //Right
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = minY,
                    Z = (minZ + maxZ) / half
                },
                new Point3D
                {
                    X = (maxX + minX) / half,
                    Y = minY - distance,
                    Z = (minZ + maxZ) / half
                },

                //Back
                new Point3D
                {
                    X = minX,
                    Y = (minY + maxY) / half,
                    Z = (minZ + maxZ) / half
                },
                new Point3D
                {
                    X = minX - distance,
                    Y = (minY + maxY) / half,
                    Z = (minZ + maxZ) / half
                }
            });
        }
Exemple #5
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++;
            }
        }