public double[] GetDoseForStructure(Structure structure) { var doseList = new List <double>(); for (double z = _zStart; z < _zEnd; z += DoseSamplingDistanceInMm) { for (double y = _yStart; y < _yEnd; y += DoseSamplingDistanceInMm) { VVector start = new VVector(_xStart, y, z); VVector stop = new VVector(_xEnd, y, z); BitArray bitArray = new BitArray(_dose.XSize); var segmentProfile = structure.GetSegmentProfile(start, stop, bitArray); double[] doseArray = new double[_dose.XSize]; var doseProfile = _dose.GetDoseProfile(start, stop, doseArray); for (int i = 0; i < segmentProfile.Count; i++) { if (segmentProfile[i].Value) { doseList.Add(doseProfile[i].Value); } } } } return(doseList.ToArray()); }
private void CalcDepths() { Field = _beam.Id; if (_beam.MLCPlanType == MLCPlanType.VMAT || _beam.MLCPlanType == MLCPlanType.ArcDynamic) { double totalDistFromTarget = 0; foreach (ControlPoint controlPoint in _beam.ControlPoints) { //vector from source to reference point for calculating physical depth of point VVector ToRefPoint = _point.RefPointLocation - _beam.GetSourceLocation(controlPoint.GantryAngle); totalDistFromTarget += ToRefPoint.Length; } Depth = Math.Round((totalDistFromTarget / _beam.ControlPoints.Count() - _point.SSD) / 10.0, 1); } else { //vector from source to reference point for calculating physical depth of point VVector ToRefPoint = _point.RefPointLocation - _beam.GetSourceLocation(_beam.ControlPoints.First().GantryAngle); Depth = Math.Round((ToRefPoint.Length - _point.SSD) / 10.0, 1); } EffectiveDepth = Math.Round(_point.EffectiveDepth / 10.0, 1); }
private void SurfaceView_MouseWheel(object sender, MouseWheelEventArgs e) { if (viewMode == 1) { if (e.Delta > 0) { transform.Y += 10; } else { transform.Y -= 10; } camera.Transform = new TranslateTransform3D(0, transform.Y, 0); } if (viewMode == 2) { var q = quaternion; q.Invert(); double val = e.Delta > 0 ? -1 : 1; Point3D p = (new RotateTransform3D(new QuaternionRotation3D(q))).Transform(new Point3D(0, val, 0)); var s = ss.Structures.ElementAt(selected_roi); VVector vv = new VVector(-(p.X + transform.X), -(p.Y + transform.Y), -(p.Z + transform.Z)); if (s.IsPointInsideSegment(vv)) { transform = new Vector3D(p.X + transform.X, p.Y + transform.Y, p.Z + transform.Z); Transform3DGroup transform3DGroup = new Transform3DGroup(); transform3DGroup.Children.Add(new TranslateTransform3D(transform)); transform3DGroup.Children.Add(new RotateTransform3D(new QuaternionRotation3D(quaternion))); model.Transform = transform3DGroup; pre_transform = transform; } } }
/// <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); }
private void ChangeStructure(object sender, EventArgs e) { // Get selected structure Structure viewStructure = SelectedStructureSet.Structures.FirstOrDefault( s => s.Id == structureNames[structureList.SelectedIndex]); MeshGeometry3D viewContour = viewStructure.MeshGeometry; Color viewColor = viewStructure.Color; // Use body contour as mesh GeometryModel3D viewGeometryModel = ((myViewport3D.Children[0] as ModelVisual3D).Content as Model3DGroup).Children[1] as GeometryModel3D; viewGeometryModel.Geometry = viewContour; // Define material (e.g. brush) and apply to the mesh geometries. DiffuseMaterial viewMaterial = new DiffuseMaterial(new SolidColorBrush(viewColor)); viewGeometryModel.Material = viewMaterial; viewGeometryModel.BackMaterial = viewMaterial; // Reset camera to point at new structure PerspectiveCamera newPCamera = myViewport3D.Camera as PerspectiveCamera; cameraRadius = 800.0; cameraTheta = 90.0 * (Math.PI / 180.0); cameraPhi = 0.0 * (Math.PI / 180.0); cv = viewStructure.CenterPoint; double cameraX = cv.x + cameraRadius * Math.Sin(cameraTheta) * Math.Cos(cameraPhi - Math.PI / 2.0); double cameraY = cv.y + cameraRadius * Math.Sin(cameraTheta) * Math.Sin(cameraPhi - Math.PI / 2.0); double cameraZ = cv.z + (cameraRadius * Math.Cos(cameraTheta)); newPCamera.Position = new Point3D(cameraX, cameraY, cameraZ); newPCamera.LookDirection = new Vector3D(cv.x - cameraX, cv.y - cameraY, cv.z - cameraZ); myViewport3D.Camera = newPCamera; }
// // Cut profile with calculation volume. Could actaully be easier to simply prune out NaN's which is assiugned to points outside of the dose. // // Math.Abs(direction.x) > 1e-4 is a crude check for profile running parallel to axis (and thus beigbn outside of the calculation volume) // public static void cutWithCalculationVolume(VoiBox calculationVolume, ref VVector point, VVector direction) { var xDiff = Math.Max(point.x - calculationVolume.xmax, 0.0); xDiff = (xDiff == 0) ? Math.Min(point.x - calculationVolume.xmin, 0) : xDiff; if (xDiff != 0 && Math.Abs(direction.x) > 1e-4) { var l = xDiff / direction.x; point.x -= xDiff; point.y -= l * direction.y; point.z -= l * direction.z; } var yDiff = Math.Max(point.y - calculationVolume.ymax, 0.0); yDiff = (yDiff == 0) ? Math.Min(point.y - calculationVolume.ymin, 0) : yDiff; if (yDiff != 0 && Math.Abs(direction.y) > 1e-4) { var l = yDiff / direction.y; point.x -= l * direction.x; point.y -= yDiff; point.z -= l * direction.z; } var zDiff = Math.Max(point.z - calculationVolume.zmax, 0.0); zDiff = (zDiff == 0) ? Math.Min(point.z - calculationVolume.zmin, 0) : zDiff; if (zDiff != 0 && Math.Abs(direction.z) > 1e-4) { var l = zDiff / direction.z; point.x -= l * direction.x; point.y -= l * direction.y; point.z -= zDiff; } }
public VVector TransformPoint(VVector pt) { var local = this; var retVal = X.Instance.CurrentContext.GetValue(sc => { return(local._client.TransformPoint(pt)); }); return(retVal); }
// check each point on the image grid, and store the indices only static List <int> GetInterior(VMS.TPS.Common.Model.API.Image dose, VMS.TPS.Common.Model.API.Structure st) { List <int> result = new List <int>(); VVector p = new VVector(); Rect3D st_bounds = st.MeshGeometry.Bounds; for (int z = 0; z < dose.ZSize; ++z) { for (int y = 0; y < dose.YSize; ++y) { for (int x = 0; x < dose.XSize; ++x) { p.x = x * dose.XRes; p.y = y * dose.YRes; p.z = z * dose.ZRes; p = p + dose.Origin; if (st_bounds.Contains(p.x, p.y, p.z) && // trimming st.IsPointInsideSegment(p)) // this is an expensive call { int[,] voxels = new int[dose.XSize, dose.YSize]; dose.GetVoxels(z, voxels); result.Add(voxels[x, y]); } } } GC.Collect(); // do this to avoid time out GC.WaitForPendingFinalizers(); } return(result); }
public void computeStats(IEnumerable <VVector> sourcePoints, IEnumerable <VVector> registeredPoints, IEnumerable <VVector> transformedPoints) { // ensure that all lists have same number of points. if (sourcePoints.Count() != registeredPoints.Count() || sourcePoints.Count() != transformedPoints.Count()) { throw new ApplicationException("source and registered match points don't have the same # of points!"); } // compute statistics double sum = 0; int numPoints = sourcePoints.Count(); for (int i = 0; i < numPoints; i++) { VVector source = sourcePoints.ElementAt(i); VVector registered = registeredPoints.ElementAt(i); VVector derived = transformedPoints.ElementAt(i); double distance = VVector.Distance(registered, derived); min = Math.Min(min, distance); max = Math.Max(max, distance); sum += distance; } mean = sum / (double)numPoints; }
public DoseValue GetDoseToPoint(VVector at) { var local = this; var retVal = X.Instance.CurrentContext.GetValue(sc => { return(local._client.GetDoseToPoint(at)); }); return(retVal); }
/// <summary> /// Return image profiles through plan isocenter in primary axis direction /// </summary> /// <param name="plan">TPS.NET.Plan</param> /// <param name="profileLengthInmm"> length of the profiles in mm</param> /// <returns></returns> public static (ImageProfile, ImageProfile, ImageProfile) getImageProfilesThroughIsocenter(PlanSetup plan) { var image = plan.StructureSet.Image; var dirVecs = new VVector[] { plan.StructureSet.Image.XDirection, plan.StructureSet.Image.YDirection, plan.StructureSet.Image.ZDirection }; var steps = new double[] { plan.StructureSet.Image.XRes, plan.StructureSet.Image.YRes, plan.StructureSet.Image.ZRes }; var planIso = plan.Beams.First().IsocenterPosition; var tmpRes = new ImageProfile[3]; // // Throws if plan does not have 'BODY' // var body = plan.StructureSet.Structures.Single(st => st.Id == "BODY"); for (int ind = 0; ind < 3; ind++) { (var startPoint, var endPoint) = Helpers.GetStructureEntryAndExit(body, dirVecs[ind], planIso, steps[ind]); var samples = (int)Math.Ceiling((endPoint - startPoint).Length / steps[ind]); tmpRes[ind] = image.GetImageProfile(startPoint, endPoint, new double[samples]); } return(tmpRes[0], tmpRes[1], tmpRes[2]); }
public static int ProfileNumberOfIntervals(VVector start, VVector end, double res = 1.0) { double distance = VVector.Distance(start, end); int num = ((int)(distance / res)); return(num); }
public static DoseValue CalculateMeanDose(PlanSetup plan, Structure structure) { Dose dose = plan.Dose; if (dose == null) { return(new DoseValue(Double.NaN, DoseValue.DoseUnit.Unknown)); } plan.DoseValuePresentation = DoseValuePresentation.Absolute; double sum = 0.0; int count = 0; double xres = 2.5; double yres = 2.5; double zres = 2.5; int xcount = (int)((dose.XRes * dose.XSize) / xres); System.Collections.BitArray segmentStride = new System.Collections.BitArray(xcount); double[] doseArray = new double[xcount]; DoseValue.DoseUnit doseUnit = dose.DoseMax3D.Unit; for (double z = 0; z < dose.ZSize * dose.ZRes; z += zres) { for (double y = 0; y < dose.YSize * dose.YRes; y += yres) { VVector start = dose.Origin + dose.YDirection * y + dose.ZDirection * z; VVector end = start + dose.XDirection * dose.XRes * dose.XSize; SegmentProfile segmentProfile = structure.GetSegmentProfile(start, end, segmentStride); DoseProfile doseProfile = null; for (int i = 0; i < segmentProfile.Count; i++) { if (segmentStride[i]) { if (doseProfile == null) { doseProfile = dose.GetDoseProfile(start, end, doseArray); } double doseValue = doseProfile[i].Value; if (!Double.IsNaN(doseValue)) { sum += doseProfile[i].Value; count++; } } } doseProfile = null; } } double mean = sum / ((double)count); return(new DoseValue(mean, doseUnit)); }
/// <summary> /// Transforms point in DICOM (HFS patient only) into gantry coordinates (invert GantryToDICOM) /// </summary> /// <param name="point"> Point to transform</param> /// <param name="gantryInDegrees"> Gantry angle b</param> /// <param name="patientSupportInDegrees">Patient support angle</param> /// <param name="isoCenter"> Isocenter position</param> /// <returns></returns> public static VVector DICOMToGantry(VVector point, double gantryInDegrees, double patientSupportInDegrees, VVector isoCenter) { var retval = point - isoCenter; retval = new VVector(retval.x, retval.z, -retval.y); retval = RotateZ(retval, -patientSupportInDegrees); return(RotateY(retval, -gantryInDegrees)); }
public SegShift(VVector mMDisplacement, StructureSet structureSet, Structure structure) { MMDisplacement = mMDisplacement; Structure = structure; SS = structureSet; OriginalContours = GetContours(); Contours = OriginalContours; }
public static double distanciaMaxima(VVector punto1, VVector punto2) { double difX = Math.Abs(punto1.x - punto2.x); double difY = Math.Abs(punto1.y - punto2.y); double difZ = Math.Abs(punto1.z - punto2.z); return(Math.Max(difX, Math.Max(difY, difZ))); }
public static VVector ProfileEndVVector(VVector start, VVector end, double res = 1.0) { double distance = VVector.Distance(start, end); int num = ProfileNumberOfIntervals(start, end, res); VVector truncatedEnd = start + ((num * res) / distance) * (end - start); return(truncatedEnd); }
/// <summary> /// Aligns beam isocenter to within the nearest mm. /// </summary> /// <param name="beam">beam in which isocenter will be set</param> /// <param name="str">the structure in which the center will be used</param> public static void AlignToStructureCenter(this IonBeam beam, Structure str) { var beamParams = beam.GetEditableParameters(); var rounded = new VVector(Math.Round(str.CenterPoint.x), Math.Round(str.CenterPoint.x), Math.Round(str.CenterPoint.x)); beamParams.Isocenter = rounded; beam.ApplyParameters(beamParams); }
public static Point toPoint(VVector inp) { Point p = new Point(); p.X = inp.x; p.Y = inp.y; return(p); }
/// <summary> /// Aligns beam isocenter to within the nearest mm to structure midpoint (not "weighted" center). /// </summary> /// <param name="beam">beam in which isocenter will be set</param> /// <param name="str">the structure in which the center will be used</param> public static void AlignToStructureMidpoint(this IonBeam beam, Structure str) { var beamParams = beam.GetEditableParameters(); var midpoint = str.GetMidpoint(); var rounded = new VVector(Math.Round(midpoint.x), Math.Round(midpoint.y), Math.Round(midpoint.z)); beamParams.Isocenter = rounded; beam.ApplyParameters(beamParams); }
/// <summary> /// ESAPI DICOM coordinate system to the user coordinate system. /// </summary> /// <param name="x">The x coordinate in the DICOM coordinate system.</param> /// <param name="y">The y coordinate in the DICOM coordinate system.</param> /// <param name="z">The z coordinate in the DICOM coordinate system.</param> /// <param name="planSetup">ESAPI PlanSetup, which is necessary to convert from the DICOM to User coordinate system.</param> /// <returns>Coordinates in the User coordinate system.</returns> public static double[] DicomToUserCoordinates(double x, double y, double z, PlanSetup planSetup) { var strucureSet = planSetup.StructureSet; var imageEsapi = strucureSet.Image; var vectorInDCS = new VVector(x, y, z); var vectorInUCS = imageEsapi.DicomToUser(vectorInDCS, planSetup); return(new double[] { vectorInUCS.x, vectorInUCS.y, vectorInUCS.z }); }
/// <summary> /// cross product between two 3-vectors a and b /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static VVector CrossProduct(VVector a, VVector b) { return(new VVector() { x = a.y * b.z - a.z * b.y, y = -a.x * b.z + b.x * a.z, z = a.x * b.y - a.y * b.x }); }
public static double[] ImageProfile(Image imageEsapi, VVector start, VVector end, double res = 1.0) { int numberOfIntervals = ProfileNumberOfIntervals(start, end, res); double[] imageProfile = new double[numberOfIntervals + 1]; imageEsapi.GetImageProfile(start, end, imageProfile); return(imageProfile); }
private void SurfaceView_MouseMove(object sender, MouseEventArgs e) { var diff = e.GetPosition(this) - pre_point; var size = Math.Min(this.ActualWidth, this.ActualHeight); if (right_click) { double x = 360 * diff.X / size; double y = 360 * diff.Y / size; var q = new Quaternion(new Vector3D(0, 0, 1), x); q *= new Quaternion(new Vector3D(1, 0, 0), y); q *= quaternion; Transform3DGroup transform3DGroup = new Transform3DGroup(); if (viewMode == 1) { transform3DGroup.Children.Add(new RotateTransform3D(new QuaternionRotation3D(q))); transform3DGroup.Children.Add(new TranslateTransform3D(transform.X, 0, transform.Z)); model.Transform = transform3DGroup; } if (viewMode == 2) { transform3DGroup.Children.Add(new TranslateTransform3D(transform)); transform3DGroup.Children.Add(new RotateTransform3D(new QuaternionRotation3D(q))); model.Transform = transform3DGroup; } } if (left_click) { double x = diff.X / size * 100; double y = -diff.Y / size * 100; Transform3DGroup transform3DGroup = new Transform3DGroup(); if (viewMode == 1) { transform3DGroup.Children.Add(new RotateTransform3D(new QuaternionRotation3D(quaternion))); transform3DGroup.Children.Add(new TranslateTransform3D(x + transform.X, 0, y + transform.Z)); model.Transform = transform3DGroup; } if (viewMode == 2) { var q = quaternion; q.Invert(); x /= 5; y /= 5; Point3D p = (new RotateTransform3D(new QuaternionRotation3D(q))).Transform(new Point3D(x, 0, y)); var s = ss.Structures.ElementAt(selected_roi); VVector vv = new VVector(-(p.X + transform.X), -(p.Y + transform.Y), -(p.Z + transform.Z)); if (s.IsPointInsideSegment(vv)) { transform3DGroup.Children.Add(new TranslateTransform3D(p.X + transform.X, p.Y + transform.Y, p.Z + transform.Z)); transform3DGroup.Children.Add(new RotateTransform3D(new QuaternionRotation3D(quaternion))); model.Transform = transform3DGroup; pre_transform = new Vector3D(p.X + transform.X, p.Y + transform.Y, p.Z + transform.Z); } } } }
public ImageProfile GetImageProfile(VVector start, VVector stop, double[] preallocatedBuffer) { var local = this; var retVal = X.Instance.CurrentContext.GetValue(sc => { return(local._client.GetImageProfile(start, stop, preallocatedBuffer)); }); return(retVal); }
public bool IsPointInsideSegment(VVector point) { var local = this; var retVal = X.Instance.CurrentContext.GetValue(sc => { return(local._client.IsPointInsideSegment(point)); }); return(retVal); }
/// <summary> /// Rotate point about Y axis (gantry) /// </summary> /// <param name="point"></param> /// <param name="angleInDeg">Patient support angle</param> /// <param name="dir">Positive angle direction default clockwise</param> /// <returns>point rotated about y axis</returns> public static VVector RotateY(VVector point, double angleInDeg, Direction dir = Direction.CW) { var angleInRad = angleInDeg * 2 * Math.PI / 360; var c = Math.Cos(angleInRad); var s = ((int)dir) * Math.Sin(angleInRad); var x = point.x * c - point.z * s; var z = point.x * s + point.z * c; return(new VVector(x, point.y, z)); }
public VVector DicomToUser(VVector dicom, PlanSetup planSetup) { var local = this; var retVal = X.Instance.CurrentContext.GetValue(sc => { return(local._client.DicomToUser(dicom, planSetup._client)); }); return(retVal); }
public static double BeamPointDose(Beam beam, VVector pointDicom) { DoseValue dose = beam.Dose.GetDoseToPoint(pointDicom); double muPerGy = beam.MetersetPerGy; double mu = beam.Meterset.Value; double refDose = mu / muPerGy; double pointDose = refDose * dose.Dose; return(pointDose); }
public VVector UserToDicom(VVector user, PlanSetup planSetup) { var local = this; var retVal = X.Instance.CurrentContext.GetValue(sc => { return(local._client.UserToDicom(user, planSetup._client)); }); return(retVal); }