Kaynağa Gözat

更新 terms

gavin.chen 10 ay önce
ebeveyn
işleme
2ba5ea1549
2 değiştirilmiş dosya ile 3436 ekleme ve 0 silme
  1. 3386 0
      SRMeasures.txt
  2. 50 0
      lib/interfaces/process/items/terms.dart

+ 3386 - 0
SRMeasures.txt

@@ -0,0 +1,3386 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Windows;
+using System.Windows.Threading;
+using UtilityService;
+using Vinno.DataManager.Data;
+using Vinno.DataManager.Infrastructure;
+using Vinno.DataManager.Infrastructure.Interfaces;
+using Vinno.DataManager.Utilities;
+using Vinno.DataTypes;
+using Vinno.Enums;
+using Vinno.Infrastructure;
+using Vinno.Infrastructure.Enums;
+using Vinno.Infrastructure.Interfaces;
+using Vinno.Infrastructure.Utilities;
+using Vinno.Models.Base;
+using Vinno.Models.Base.Modes;
+using Vinno.Models.Base.Parameters;
+using Vinno.Models.Base.VisualAreas;
+using Vinno.Models.Base.Visuals;
+using Vinno.Models.Dicom.Replay.Modes;
+using Vinno.Models.SpecificImpl.Modes;
+using Vinno.Modules.MeasureModule.Calculators;
+using Vinno.Modules.MeasureModule.ItemMetas;
+using Vinno.Modules.MeasureModule.Items;
+using Vinno.Modules.MeasureModule.Results;
+using Vinno.Modules.RenderModule;
+using Vinno.Services.InputServices;
+using Vinno.Services.MessageService;
+using Vinno.Utilities;
+using Vinno.vCloud.Report.JsonConverters;
+
+
+namespace Vinno.Modules.MeasureModule.Primitives.SRMeasure
+{
+    public static class SRPointTrans
+    {
+        //Scream Point To ImgPoint
+        public static DPoint TransPointS2I(DPoint srcPoint, double roundw, double roundh, double urmw, double urmh, int datew, int dateh, bool limit = true)
+        {
+            double Scalarx = (double) datew / urmw;
+            double Scalary = (double) dateh / urmh;
+            DPoint urmzeroPoint=new DPoint(-urmw/2,(roundh- urmh) /2);
+            DPoint outPoint = new DPoint((srcPoint.X - urmzeroPoint.X) * Scalarx,
+                (srcPoint.Y - urmzeroPoint.Y) * Scalary);
+            if (limit)
+            {
+                if (outPoint.X < 0)
+                    outPoint.X = 0;
+                if (outPoint.X > (datew - 1))
+                    outPoint.X = datew - 1;
+                if (outPoint.Y < 0)
+                    outPoint.Y = 0;
+                if (outPoint.Y > (dateh - 1))
+                    outPoint.Y = dateh - 1;
+            }
+            return outPoint;
+        }
+        //Scream Point To ImgPoint
+        public static DPoint TransPointI2S(DPoint srcPoint, double roundw, double roundh, double urmw, double urmh, int datew, int dateh)
+        {
+            double Scalarx = (double)urmw/ datew;
+            double Scalary = (double) urmh/ dateh ;
+            DPoint urmzeroPoint = new DPoint(-urmw / 2, (roundh - urmh) / 2);
+            DPoint outPoint = new DPoint(srcPoint.X  * Scalarx+ urmzeroPoint.X, srcPoint.Y * Scalary + urmzeroPoint.Y);
+            return outPoint;
+        }
+    }
+    
+
+    // 用于
+    public class SRStraightCurvatureLineMeasure : StraightCurvatureLine
+    {
+        private bool calflag = false;
+        public SRStraightCurvatureLineMeasure(ItemMeta meta, IMeasureItem parent):base(meta, parent)
+        {
+            
+        }
+
+        protected override bool OnExecute(PointInfo args)
+        {
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null||modewithurm?.URMStyle!="URM(Den)")
+                    return false;
+            }
+
+            calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null&& calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+
+        internal static StraightCurvatureLine CreateSRStraightCurvatureLineMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRStraightCurvatureLineMeasure)
+            {
+                throw new ArgumentException();
+            }
+            var item = new SRStraightCurvatureLineMeasure(meta, parent);
+            item.Calculator = new SRStraightCurvatureLineCal(item);
+            return item;
+        }
+
+        internal class SRStraightCurvatureLineCal : Calculator<StraightCurvatureLine>
+        {
+            internal static readonly string SRkey = "SRCurvature";
+            protected internal override string[] SupportedOutputKeys
+            {
+                get { return new[] { SRkey }; }
+            }
+            public SRStraightCurvatureLineCal(StraightCurvatureLine straightLine)
+                : base(straightLine)
+            {
+
+            }
+            public SRStraightCurvatureLineCal()
+            {
+
+            }
+
+            protected override void OnCalculate()
+            {
+                var wizardManager = ServiceManager.Instance.GetService<IWizardManager>();
+                wizardManager.Startup("URM", "Calculating...", CalculatSRCurvature, double.NaN, WizardButtonEnum.None);
+            }
+
+
+            private void CalculatSRCurvature()
+            {
+                TaskManagerFactory.Instance.GetTaskManager("Calculating")
+                    .StartNewTaskProxy("CalculatSRCurvature", CalculteSRCurvature, OnSRCurvatureCalculated);
+
+            }
+
+            private void CalculteSRCurvature(TaskProxy proxy)
+            {
+                StraightLineFeature feature = RefItem.GeoFeature;
+
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if(modewithURM.URMStyle!="URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint startDPoint = SRPointTrans.TransPointS2I(feature.StartPoint, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                DPoint endDPoint = SRPointTrans.TransPointS2I(feature.EndPoint, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                if (startDPoint.X < 0 || startDPoint.X > width || endDPoint.X < 0 || endDPoint.X > width
+                    || startDPoint.Y < 0 || startDPoint.Y > height || endDPoint.Y < 0 || endDPoint.Y > height)
+                    return;
+
+                int outPointsNum = 0;
+                double curvature = 0;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if(urmcal == null)
+                    return;
+                double[] outPoints = urmcal.GetSRCurvature(srcArray.Start, width, height, startDPoint.X,
+                    startDPoint.Y, endDPoint.X, endDPoint.Y, ref curvature, ref outPointsNum);
+                DPoint[] points = new DPoint[outPointsNum];
+                for (int i = 0; i < outPointsNum; i++)
+                {
+                    DPoint imgpoint = new DPoint(outPoints[i], outPoints[i + outPointsNum]);
+                    points[i] = SRPointTrans.TransPointI2S(imgpoint, regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                }
+                List<GeometryFeature> autoLines = new List<GeometryFeature>
+                    {
+                        new ManualTraceFeature(points, feature.Creator, feature.XUnit, feature.YUnit)
+                    };
+                ServiceManager.MainDispatcher.Invoke(UpdateChildFeatures, autoLines);
+                feature.UpdateValue(PrimaryOutput, RoundValue(curvature, GetResultDigits(PrimaryOutput)), Unit.None);
+
+            }
+
+            public void UpdateChildFeatures(List<GeometryFeature> autoLines)
+            {
+                var feature = RefItem.GeoFeature;
+                if (feature != null)
+                    feature.UpdateChildFeatures(autoLines);
+            }
+
+            private void OnSRCurvatureCalculated(TaskProxy proxy)
+            {
+                IWizardManager manager = ServiceManager.Instance.GetService<IWizardManager>();
+                using (manager.ClosingWizard())
+                {
+                    var showError = false;
+                    if (proxy.Task.IsCanceled)
+                    {
+                        Logger.WriteLineInfo("Task:{0} is canceled.", proxy.Name);
+                    }
+                    else if (proxy.Task.Exception != null)
+                    {
+                        showError = true;
+                        Logger.WriteLineError("Task:{0} failed, exception: {1}.", proxy.Name, proxy.Task.Exception);
+                    }
+
+                    if (!showError || (bool)proxy.Tag)
+                    {
+                        manager.Close();
+                    }
+                    else
+                    {
+                        manager.Close("SRCurvatureCalculate failed", false);
+                    }
+                }
+            }
+        }
+    }
+
+    public class SRCurveCurvatureLineMeasure : Trace
+    {
+        private bool calflag = false;
+        public SRCurveCurvatureLineMeasure(ItemMeta meta, IMeasureItem parent) : base(meta, parent)
+        {
+
+        }
+
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as SRCurveCurvatureLineCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+
+        internal static Trace CreateSRCurveCurvatureLineMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRCurveCurvatureLineMeasure)
+            {
+                throw new ArgumentException();
+            }
+            var item = new SRCurveCurvatureLineMeasure(meta, parent);
+            item.Calculator = new SRCurveCurvatureLineCal(item);
+            return item;
+        }
+
+        internal class SRCurveCurvatureLineCal : Calculator<Trace>
+        {
+            public bool calflag = false;
+            internal static readonly string URMkey = "SRCurvature";
+
+            protected internal override string[] SupportedOutputKeys
+            {
+                get { return new[] { URMkey }; }
+            }
+
+            public SRCurveCurvatureLineCal(Trace trace)
+                : base(trace)
+            {
+
+            }
+
+            public SRCurveCurvatureLineCal()
+            {
+
+            }
+
+            protected override void OnCalculate()
+            {
+                if (!calflag)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var SrcDPoints =new List<DPoint>();
+                for (int i = 0; i < feature.Points.Count; i++)
+                {
+                    var curpoint = SRPointTrans.TransPointS2I(feature.Points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    SrcDPoints.Add(curpoint);
+                }
+                if (SrcDPoints[0].X < 0 || SrcDPoints[0].X > width || SrcDPoints.Last().X < 0 || SrcDPoints.Last().X > width
+                    || SrcDPoints[0].Y < 0 || SrcDPoints[0].Y > height || SrcDPoints.Last().Y < 0 || SrcDPoints.Last().Y > height)
+                    return;
+                double curvature = 0;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                 urmcal.GetSRTraceCurvaturel(srcArray.Start, width, height, SrcDPoints, ref curvature);
+                feature.UpdateValue(PrimaryOutput, RoundValue(curvature, GetResultDigits(PrimaryOutput)), Unit.None);
+            }
+        }
+    }
+
+    public class SRCurvatureMeasure : MultiMethodItem
+    {
+        internal SRCurvatureMeasure(ItemMeta meta, IMeasureItem parent = null) : base(meta, parent)
+        {
+        }
+        internal static SRCurvatureMeasure CreateSRCurvatureMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.SRCurvature)
+            {
+                throw new ArgumentException();
+            }
+            var item = new SRCurvatureMeasure(meta, parent);
+            return item;
+        }
+    }
+
+    public class URMVesselMeasure : StraightLine
+    {
+        private bool calflag = false;
+        public URMVesselMeasure(ItemMeta meta, IMeasureItem parent) : base(meta, parent)
+        {
+
+        }
+
+        protected override bool OnExecute(PointInfo args)
+        {
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+
+            calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+
+        internal static URMVesselMeasure CreateURMVesselMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.URMVesselMeasure)
+            {
+                throw new ArgumentException();
+            }
+            var item = new URMVesselMeasure(meta, parent);
+            item.Calculator = new URMVesselMeasureCal(item);
+            return item;
+        }
+
+        internal class URMVesselMeasureCal : Calculator<URMVesselMeasure>
+        {
+
+           
+            public URMVesselMeasureCal(URMVesselMeasure straightLine)
+                : base(straightLine)
+            {
+
+            }
+            public URMVesselMeasureCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.MaxVessDistance, MeasureTerms.MinVessDistance, MeasureTerms.MeanVessDistacne,MeasureTerms.StdVessDistance,
+                        MeasureTerms.MaxVessDiameter, MeasureTerms.MinVessDiameter, MeasureTerms.MeanVessDiameter,MeasureTerms.StdVessDiameter
+                    };
+                }
+            }
+
+            protected override void OnCalculate()
+            {
+                StraightLineFeature feature = RefItem.GeoFeature;
+
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint startDPoint = SRPointTrans.TransPointS2I(feature.StartPoint, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                DPoint endDPoint = SRPointTrans.TransPointS2I(feature.EndPoint, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                if (startDPoint.X < 0 || startDPoint.X > width || endDPoint.X < 0 || endDPoint.X > width
+                    || startDPoint.Y < 0 || startDPoint.Y > height || endDPoint.Y < 0 || endDPoint.Y > height)
+                    return;
+                List<DPoint> Points=new List<DPoint>();
+                Points.Add(startDPoint);
+                Points.Add(endDPoint);
+                var cmlength=Math.Sqrt(Math.Pow((feature.StartPoint.X- feature.EndPoint.X),2)+Math.Pow((feature.StartPoint.Y - feature.EndPoint.Y), 2));
+                var pixelscaler = UrmPhysicalwidth / width;
+                int outPointNum = (int)(cmlength*1000);
+                SRMeasurePoint[] outPoints=new SRMeasurePoint[outPointNum];
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetUrmVessMeasureResult(srcArray.Start, width, height, Points, pixelscaler, outPoints);
+                foreach (var outputItem in Outputs)
+                {
+                    outputItem.UpdateDescription(outputItem.Name);
+                    if (string.Equals(outputItem.Name, MeasureTerms.MaxVessDistance))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxVessDistance, outputItem), Unit.mm);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.MinVessDistance))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinVessDistance, outputItem), Unit.mm);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.MeanVessDistacne))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanVessDistacne, outputItem), Unit.mm);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.StdVessDistance))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceVessDistance), outputItem), Unit.mm);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.MaxVessDiameter))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxVessDiameter, outputItem), Unit.mm);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.MinVessDiameter))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinVessDiameter, outputItem), Unit.mm);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.MeanVessDiameter))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanVessDiameter, outputItem), Unit.mm);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.StdVessDiameter))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceVessDiameter), outputItem), Unit.mm);
+                    }
+                }
+                var maxPointIndex = result.MaxPos;
+                var minPointIndex = result.MinPos;
+                var srChart = ServiceManager.Instance.GetService<IMeasureService>().SrChart;
+                srChart.Update(feature, outPoints.Select(x => new DPoint(x.X, x.Y)).ToArray(), maxPointIndex, minPointIndex);
+        }
+        }
+    }
+    internal class SRROIMeasure : Rect
+    {
+        private bool calflag=false;
+        public SRROIMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static SRROIMeasure CreateSRROIMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRRoiDensity )
+            {
+                throw new ArgumentException();
+            }
+            var SRROI = new SRROIMeasure(meta, parent);
+            SRROI.Calculator = new SRROICal(SRROI);
+            return SRROI;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as SRROICal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class SRROICal : Calculator<SRROIMeasure>
+        {
+            public bool calflag=false;
+            public SRROICal(SRROIMeasure item)
+                : base(item)
+            {
+
+            }
+            public SRROICal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenROI
+                    };
+                }
+            }
+
+
+
+            protected override void OnCalculate()
+            {
+                if(!calflag)
+                    return;
+                RectFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint startDPoint = SRPointTrans.TransPointS2I(feature.TopLeft, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                DPoint endDPoint = SRPointTrans.TransPointS2I(feature.BottomRight, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                if (startDPoint.X < 0 || startDPoint.X > width || endDPoint.X < 0 || endDPoint.X > width
+                    || startDPoint.Y < 0 || startDPoint.Y > height || endDPoint.Y < 0 || endDPoint.Y > height)
+                    return;
+                int outPointsNum = 0;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                double roivel = urmcal.GetSRRoiVel(srcArray.Start, width, height, startDPoint.X,
+                    startDPoint.Y, endDPoint.X, endDPoint.Y);
+                Outputs[0].UpdateDescription(Outputs[0].Name);
+                feature.UpdateValue(Outputs[0], RoundValue(roivel * 100, GetResultDigits(PrimaryOutput)), Unit.percent);
+            }
+        }
+    }
+
+    internal class URMRectDenMeasure : Rect
+    {
+        private bool calflag = false;
+        public URMRectDenMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static URMRectDenMeasure CreateURMRectDenMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.URMRectDenMeasure)
+            {
+                throw new ArgumentException();
+            }
+            var item = new URMRectDenMeasure(meta, parent);
+            item.Calculator = new URMRectDenMeasureCal(item);
+            return item;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as URMRectDenMeasureCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class URMRectDenMeasureCal : Calculator<URMRectDenMeasure>
+        {
+            public bool calflag = false;
+            public URMRectDenMeasureCal(URMRectDenMeasure item)
+                : base(item)
+            {
+
+            }
+            public URMRectDenMeasureCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenROI, MeasureTerms.URMDenFractalDim, MeasureTerms.URMDenMax,
+                        MeasureTerms.URMDenMin, MeasureTerms.URMDenMean, MeasureTerms.URMDenStd, MeasureTerms.Area,
+                        MeasureTerms.URMDenROIIn, MeasureTerms.URMDenFractalDimIn, MeasureTerms.URMDenMaxIn,
+                        MeasureTerms.URMDenMinIn, MeasureTerms.URMDenMeanIn, MeasureTerms.URMDenStdIn, MeasureTerms.URMAreaIn,
+                        MeasureTerms.URMDenROIOut, MeasureTerms.URMDenFractalDimOut, MeasureTerms.URMDenMaxOut,
+                        MeasureTerms.URMDenMinOut, MeasureTerms.URMDenMeanOut, MeasureTerms.URMDenStdOut, MeasureTerms.URMAreaOut,
+                    };
+                }
+            }
+
+
+
+            protected override void OnCalculate()
+            {
+                if (!calflag)
+                    return;
+                RectFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint startDPoint = SRPointTrans.TransPointS2I(feature.TopLeft, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                DPoint endDPoint = SRPointTrans.TransPointS2I(feature.BottomRight, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+              
+                if (startDPoint.X < 0 || startDPoint.X > width || endDPoint.X < 0 || endDPoint.X > width
+                    || startDPoint.Y < 0 || startDPoint.Y > height || endDPoint.Y < 0 || endDPoint.Y > height)
+                    return;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                double areaScaler = (UrmPhysicalwidth / width) * (UrmPhysicalheight / height);
+                    ImagePoint.Add(startDPoint);
+                ImagePoint.Add(endDPoint);
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetURMDenMeasureResult(srcArray.Start, width, height, ImagePoint,areaScaler);
+                foreach (var outputItem in Outputs)
+                {
+                    outputItem.UpdateDescription(outputItem.Name);
+                    if (string.Equals(outputItem.Name,MeasureTerms.URMDenROI))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiDen*100, outputItem), Unit.percent);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenFractalDim))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiFractalDim, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMax))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMin))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMean))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenStd))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceDensity), outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.Area))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiArea, outputItem), Unit.cm2);
+                    }
+                }
+            }
+        }
+    }
+
+    internal class URMRectVelMeasure : Rect
+    {
+        private bool calflag = false;
+        public URMRectVelMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static URMRectVelMeasure CreateURMRectVelMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.URMRectVelMeasure)
+            {
+                throw new ArgumentException();
+            }
+            var item = new URMRectVelMeasure(meta, parent);
+            item.Calculator = new URMRectVelMeasureCal(item);
+            return item;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as URMRectVelMeasureCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSrVel = dicomvisual.isSRVel();
+                if (args.VisualArea.Mode == null || !isSrVel)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Vel)")
+                    return false;
+            }
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class URMRectVelMeasureCal : Calculator<URMRectVelMeasure>
+        {
+            public bool calflag = false;
+            public URMRectVelMeasureCal(URMRectVelMeasure item)
+                : base(item)
+            {
+
+            }
+            public URMRectVelMeasureCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMVelMax, MeasureTerms.URMVelMin, MeasureTerms.URMVelMean, MeasureTerms.URMVelStd, MeasureTerms.Area,
+                        MeasureTerms.URMVelMaxIn, MeasureTerms.URMVelMinIn, MeasureTerms.URMVelMeanIn, MeasureTerms.URMVelStdIn, MeasureTerms.URMAreaIn,
+                        MeasureTerms.URMVelMaxOut, MeasureTerms.URMVelMinOut, MeasureTerms.URMVelMeanOut, MeasureTerms.URMVelStdOut, MeasureTerms.URMAreaOut,
+                    };
+                }
+            }
+
+
+
+            protected override void OnCalculate()
+            {
+                if (!calflag)
+                    return;
+                RectFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                double UrmMinVel = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRVel = dicomvisual.isSRVel();
+                    if (!isSRVel)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                    UrmMinVel = dicomvisual.GetSRMinVel();
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Vel)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    UrmMinVel = modewithURM.URMMinVel;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint startDPoint = SRPointTrans.TransPointS2I(feature.TopLeft, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                DPoint endDPoint = SRPointTrans.TransPointS2I(feature.BottomRight, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+
+                if (startDPoint.X < 0 || startDPoint.X > width || endDPoint.X < 0 || endDPoint.X > width
+                    || startDPoint.Y < 0 || startDPoint.Y > height || endDPoint.Y < 0 || endDPoint.Y > height)
+                    return;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                double areaScaler = (UrmPhysicalwidth / width) * (UrmPhysicalheight / height);
+                ImagePoint.Add(startDPoint);
+                ImagePoint.Add(endDPoint);
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetURMVelMeasureResult(srcArray.Start, width, height, ImagePoint, areaScaler);
+                foreach (var outputItem in Outputs)
+                {
+                    outputItem.UpdateDescription(outputItem.Name);
+                    if (string.Equals(outputItem.Name, MeasureTerms.URMVelMax))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxVel+UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMin))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMean))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelStd))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceVel), outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.Area))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiArea, outputItem), Unit.cm2);
+                    }
+                }
+            }
+        }
+    }
+
+    internal class URMTraceDenMeasure : Trace
+    {
+        private bool calflag = false;
+        public URMTraceDenMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static URMTraceDenMeasure CreateURMTraceDenMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.URMTraceDenMeasure)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var item = new URMTraceDenMeasure(meta, parent);
+            item.Calculator = new URMTraceDenMeasureCal(item);
+            return item;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as URMTraceDenMeasureCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class URMTraceDenMeasureCal : Calculator<URMTraceDenMeasure>
+        {
+            public bool calflag = false;
+            public URMTraceDenMeasureCal(URMTraceDenMeasure item)
+                : base(item)
+            {
+
+            }
+            public URMTraceDenMeasureCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenROI, MeasureTerms.URMDenFractalDim, MeasureTerms.URMDenMax,
+                        MeasureTerms.URMDenMin, MeasureTerms.URMDenMean, MeasureTerms.URMDenStd,
+                        MeasureTerms.Area
+                    };
+                }
+            }
+            protected override void OnCalculate()
+            {
+                if (!calflag)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point = SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+                double areaScaler = (UrmPhysicalwidth / width) * (UrmPhysicalheight / height);
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetURMDenMeasureResult(srcArray.Start, width, height, ImagePoint, areaScaler);
+                foreach (var outputItem in Outputs)
+                {
+                    outputItem.UpdateDescription(outputItem.Name);
+                    if (string.Equals(outputItem.Name, MeasureTerms.URMDenROI))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiDen*100, outputItem), Unit.percent);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenFractalDim))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiFractalDim, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMax))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMin))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMean))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenStd))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceDensity), outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.Area))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiArea, outputItem), Unit.cm2);
+                    }
+                }
+            }
+        }
+    }
+
+    internal class URMTraceVelMeasure : Trace
+    {
+        private bool calflag = false;
+        public URMTraceVelMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static URMTraceVelMeasure CreateURMTraceVelMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.URMTraceVelMeasure)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var item = new URMTraceVelMeasure(meta, parent);
+            item.Calculator = new URMTraceVelMeasureCal(item);
+            return item;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as URMTraceVelMeasureCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSrVel = dicomvisual.isSRVel();
+                if (args.VisualArea.Mode == null || !isSrVel)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Vel)")
+                    return false;
+            }
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class URMTraceVelMeasureCal : Calculator<URMTraceVelMeasure>
+        {
+            public bool calflag = false;
+            public URMTraceVelMeasureCal(URMTraceVelMeasure item)
+                : base(item)
+            {
+
+            }
+            public URMTraceVelMeasureCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMVelMax, MeasureTerms.URMVelMin, MeasureTerms.URMVelMean, MeasureTerms.URMVelStd,
+                        MeasureTerms.Area
+                    };
+                }
+            }
+
+
+
+            protected override void OnCalculate()
+            {
+                if (!calflag)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                double UrmMinVel = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRVel = dicomvisual.isSRVel();
+                    if (!isSRVel)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                    UrmMinVel = dicomvisual.GetSRMinVel();
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Vel)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    UrmMinVel = modewithURM.URMMinVel;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point = SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+                double areaScaler = (UrmPhysicalwidth / width) * (UrmPhysicalheight / height);
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetURMVelMeasureResult(srcArray.Start, width, height, ImagePoint, areaScaler);
+                foreach (var outputItem in Outputs)
+                {
+                    outputItem.UpdateDescription(outputItem.Name);
+                    if (string.Equals(outputItem.Name, MeasureTerms.URMVelMax))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMin))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMean))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelStd))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceVel), outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.Area))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiArea, outputItem), Unit.cm2);
+                    }
+                }
+            }
+        }
+    }
+
+    public class URMShellMeasure : Trace
+    {
+        private bool _isSmartMove;
+        public FloatParameter ShellWidth { get; set; }
+        internal static readonly string ShellWidthKey = "ShellWidth";
+        internal static readonly string ShellWidthMetaKey = "ShellWidth_Meta";
+        public static string ShellWidthMeta = "[1 2 3 4 5]";
+        public static string ShellWidthDefaultValue = "1";
+        public URMShellMeasure(ItemMeta meta, IMeasureItem parent = null)
+           : base(meta, parent)
+        {
+            if (!meta.TryGetArgValue(ShellWidthMetaKey, out var shellWidthMeta) || string.IsNullOrEmpty(shellWidthMeta))
+            {
+                shellWidthMeta = ShellWidthMeta;
+            }
+
+            if (!meta.TryGetArgValue(ShellWidthKey, out var shellWidthDefaultValue) || string.IsNullOrEmpty(shellWidthDefaultValue))
+            {
+                shellWidthDefaultValue = ShellWidthDefaultValue;
+            }
+            ShellWidth = CreateArrayFloatParam(ShellWidthKey, shellWidthMeta, shellWidthDefaultValue);
+            ShellWidth.ValueChanged += OnShellWidthParamsChanged;
+        }
+
+        protected override bool OnExecuteMouse(PointInfo args)
+        {
+            if (args != null && (State == ItemStates.Waiting || State == ItemStates.Running || State == ItemStates.Finished))
+            {
+                bool completed = false;
+
+                if (State == ItemStates.Finished)
+                {
+                    switch (args.Action)
+                    {
+                        case PointAction.MouseMove:
+                        case PointAction.MouseUp:
+                            return false;
+                        case PointAction.MouseDown:
+                            HandleMouseDownWhileFinished();
+                            break;
+                    }
+                }
+                if (State == ItemStates.Waiting)
+                {
+                    switch (args.Action)
+                    {
+                        case PointAction.MouseMove:
+                        case PointAction.MouseUp:
+                            return false;
+                        case PointAction.MouseDown:
+                            HandleMouseDownWhileWaiting((MultiRegionPointInfo)args,
+                                (vertices, refItem, xUnit, yUnit) => new ShellTraceFeature(vertices, refItem, xUnit, yUnit));
+                            FirstPoint = args;
+                            if (!args.PixelPerX.AlmostEquals(0))
+                            {
+                                float pixelThreshold = PixelThreshold.AlmostEquals(0) ? 4 : PixelThreshold;
+                                Threshold = (float)(pixelThreshold / args.PixelPerX);
+                            }
+                            break;
+                    }
+                }
+                else if (State == ItemStates.Running)
+                {
+                    var points = (MultiRegionPointInfo)args;
+                    if (!GeoFeature.AnyExist(points.AllAreas))
+                    {
+                        return false;
+                    }
+                    switch (args.Action)
+                    {
+                        case PointAction.MouseDown:
+                            IsClosed = true;
+                            GeoFeature.IsClosed = true;
+                            completed = true;
+                            break;
+
+                        case PointAction.MouseMove:
+                            //Use the IsAutoSnap to check if the trace need to use smart move.
+                            var measureService = ServiceManager.Instance.GetService<IMeasureService>();
+                            double autoSnapThreshold = measureService.Settings.AutoSnapThreshold;
+                            if (IsAutoSnap && autoSnapThreshold > 0)
+                            {
+                                //Change autosnapdistance unit from cm to pixel
+                                if (FirstPoint != null)
+                                {
+                                    var current = points.AllRegionPoints.FirstOrDefault(x => x.VisualArea == FirstPoint.VisualArea);
+                                    if (current != null)
+                                    {
+                                        var length = (FirstPoint.PhyPoint - current.PhyPoint).Length;
+                                        if (GeoFeature.Points.Count < 3)
+                                        {
+                                            _isSmartMove = false;
+                                        }
+                                        if (length > autoSnapThreshold * 2.0 && !_isSmartMove)
+                                        {
+                                            _isSmartMove = true;
+                                        }
+                                        // User clear points if GeoFeature.ActivePoint== current.LogicPoint, so the trace shouldn't be smart closed.
+                                        if (length < autoSnapThreshold && _isSmartMove && !GeoFeature.ActivePoint.AlmostEquals(current.LogicPoint))
+                                        {
+                                            IsClosed = true;
+                                            GeoFeature.IsClosed = true;
+                                            _isSmartMove = false;
+                                            completed = true;
+                                            GeoFeature.SyncStates(x =>
+                                            {
+                                                x.AddPoint(x.Points[0]);
+                                            });
+
+                                            GeoFeature.Points[0].SynchToMainMonitorScreen(GeoFeature.HostArea);
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+
+                            foreach (var point in points.AllRegionPoints)
+                            {
+                                var geoFeature = GeoFeature.GetSpecificFeature(point.VisualArea);
+                                if (geoFeature != null)
+                                {
+                                    geoFeature.AddPoint(point.LogicPoint);
+                                    geoFeature.ActivePoint = point.LogicPoint;
+                                }
+                            }
+
+                            break;
+                    }
+                }
+                if (GeoFeature != null)
+                {
+                    Calculator.Calculate();
+                }
+
+                //Update state
+                if (args.Action == PointAction.MouseDown)
+                {
+                    if (State == ItemStates.Waiting || State == ItemStates.Finished)
+                    {
+                        State = ItemStates.Running;
+                    }
+                    if (State == ItemStates.Running && completed)
+                    {
+                        FinishEditing((MultiRegionPointInfo)args);
+                    }
+                }
+
+                if ((args.Action == PointAction.MouseMove || args.Action == PointAction.TouchMove) && IsClosed)
+                {
+                    if (State == ItemStates.Running && completed)
+                    {
+                        FinishEditing((MultiRegionPointInfo)args);
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+
+        protected override bool OnExecuteTouch(PointInfo args)
+        {
+            if (State == ItemStates.Finished)
+            {
+                switch (args.Action)
+                {
+                    case PointAction.TouchUp:
+                    case PointAction.TouchMove:
+                        return false;
+                    case PointAction.TouchDown:
+                        HandleMouseDownWhileFinished();
+                        break;
+                }
+            }
+
+            if (State == ItemStates.Waiting)
+            {
+                switch (args.Action)
+                {
+                    case PointAction.TouchUp:
+                    case PointAction.TouchMove:
+                        return false;
+                    case PointAction.TouchDown:
+                        CaliperExtension.HideCaliper();
+                        HandleMouseDownWhileWaiting((MultiRegionPointInfo)args, (vertices, refItem, xUnit, yUnit) => new ShellTraceFeature(vertices, refItem, xUnit, yUnit));
+                        if (!args.PixelPerX.AlmostEquals(0))
+                        {
+                            float pixelThreshold = PixelThreshold.AlmostEquals(0) ? 4 : PixelThreshold;
+                            Threshold = (float)(pixelThreshold / args.PixelPerX);
+                        }
+                        IsNewMeasure = true;
+                        IsCompleted = false;
+                        StartSyncIgnore();
+                        State = ItemStates.Running;
+                        break;
+                }
+            }
+            else if (State == ItemStates.Running)
+            {
+                var points = (MultiRegionPointInfo)args;
+                switch (args.Action)
+                {
+                    case PointAction.TouchUp:
+                        IsRelocatePoints = false;
+
+                        if (!IsIgnore)
+                        {
+                            if (!GeoFeature.ReEditing && !IsCompleted)
+                            {
+                                if (!GeoFeature.Points[0].AlmostEquals(GeoFeature.Points[GeoFeature.Points.Count / 2]))
+                                {
+                                    IsCompleted = true;
+                                }
+                            }
+                        }
+
+                        IsNewMeasure = false;
+                        FinishEditingForTouch(points);
+                        GeoFeature.ReEditing = false;
+                        break;
+                    case PointAction.TouchMove:
+                        if (!IsIgnore)
+                        {
+                            if (IsNewMeasure && IsRelocatePoints)
+                            {
+                                RelocatePoints(points);
+                            }
+                            else
+                            {
+                                CaliperExtension.HideCaliper();
+
+                                if (!GeoFeature.ReEditing)
+                                {
+                                    var measureService = ServiceManager.Instance.GetService<IMeasureService>();
+                                    double autoSnapThreshold = measureService.Settings.AutoSnapThreshold;
+                                    if ((IsAutoSnap) && autoSnapThreshold > 0)
+                                    {
+                                        var current = points.AllRegionPoints.FirstOrDefault(x => x.VisualArea == GeoFeature.HostArea);
+                                        if (current != null)
+                                        {
+                                            var length = (GeoFeature.Points[0].PointToMainMonitorScreen(GeoFeature.HostArea) - (current.LogicPoint + ActiveTouchPointVector).PointToMainMonitorScreen(GeoFeature.HostArea)).Length;
+                                            if (GeoFeature.Points.Count < 3)
+                                            {
+                                                IsSmartMove = false;
+                                            }
+                                            if (length > autoSnapThreshold * 2.0 && !IsSmartMove)
+                                            {
+                                                IsSmartMove = true;
+                                            }
+                                            if (length < autoSnapThreshold && IsSmartMove)
+                                            {
+                                                IsCompleted = true;
+                                                IsSmartMove = false;
+                                                GeoFeature.SyncStates(x =>
+                                                {
+                                                    x.AddPoint(x.Points[0]);
+                                                });
+                                                FinishEditingForTouch(points);
+                                                return true;
+                                            }
+                                        }
+                                    }
+                                }
+
+                                foreach (var point in points.AllRegionPoints)
+                                {
+                                    var geoFeature = GeoFeature.GetSpecificFeature(point.VisualArea);
+                                    if (geoFeature != null)
+                                    {
+                                        var tempEndPoint = point.LogicPoint + ActiveTouchPointVector;
+
+                                        if (!ServiceManager.Instance.GetService<ISystemSettingValues>().GetParameterValue("EnableCrossRegionOperation", false) &&
+                                            !point.ContainerBound.Contains(tempEndPoint))
+                                        {
+                                            return true;
+                                        }
+                                        geoFeature.AddPoint(tempEndPoint);
+                                        geoFeature.ActivePoint = tempEndPoint;
+                                    }
+                                }
+                            }
+                        }
+                        break;
+                    case PointAction.TouchEnter:
+                    case PointAction.TouchDown:
+                    case PointAction.HoldGesture:
+                        base.OnExecuteTouch(args);
+                        break;
+                }
+            }
+
+            return true;
+        }
+
+        internal override MeasuredFeature CreateMeasureFeatureFrom(MeasuredFeature source)
+        {
+            if (source is ShellTraceFeature feature)
+            {
+                return new ShellTraceFeature(feature.Points, this, feature.XUnit, feature.YUnit)
+                {
+                    HostArea = feature.HostArea,
+                    ReferenceArea = feature.ReferenceArea,
+                    FrameIndex = feature.FrameIndex,
+                    VisualAreaType = feature.VisualAreaType,
+                    IsClosed = feature.IsClosed,
+                    ActivePointIndex = -1,
+                };
+            }
+            return null;
+        }
+
+        private void OnShellWidthParamsChanged(object sender, EventArgs e)
+        {
+            Calculator.Calculate();
+        }
+    }
+
+    public class URMShellDenMeasure : URMShellMeasure
+    {
+        public URMShellDenMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+
+        }
+
+        internal static URMShellDenMeasure CreateURMShellDenMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.URMShellDenMeasure)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var item = new URMShellDenMeasure(meta, parent);
+            item.Calculator = new URMShellDenMeasureCal(item);
+            return item;
+        }
+
+        internal sealed class URMShellDenMeasureCal : Calculator<URMShellDenMeasure>
+        {
+            public URMShellDenMeasureCal(URMShellDenMeasure item)
+                : base(item)
+            {
+
+            }
+            public URMShellDenMeasureCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenROI, MeasureTerms.URMDenFractalDim, MeasureTerms.URMDenMax,
+                        MeasureTerms.URMDenMin, MeasureTerms.URMDenMean, MeasureTerms.URMDenStd, MeasureTerms.Area,
+                        MeasureTerms.URMDenROIIn, MeasureTerms.URMDenFractalDimIn, MeasureTerms.URMDenMaxIn,
+                        MeasureTerms.URMDenMinIn, MeasureTerms.URMDenMeanIn, MeasureTerms.URMDenStdIn, MeasureTerms.URMAreaIn,
+                        MeasureTerms.URMDenROIOut, MeasureTerms.URMDenFractalDimOut, MeasureTerms.URMDenMaxOut,
+                        MeasureTerms.URMDenMinOut, MeasureTerms.URMDenMeanOut, MeasureTerms.URMDenStdOut, MeasureTerms.URMAreaOut,
+                    };
+                }
+            }
+            protected override void OnCalculate()
+            {
+                if (RefItem.State != ItemStates.Finished)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point = SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height,false);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+                if(ImagePoint.Count<3)
+                    return;
+                double pixelscaler = UrmPhysicalwidth / width;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                //double ShellWidth = 10;//Todo 这一块需要修改为根据设置的shellwidth来
+                var result = urmcal.GetURMShellDenMeasureResult(srcArray.Start, width, height, ImagePoint, RefItem.ShellWidth.Value/10,
+                    pixelscaler, out var outshellPoints); //Todo OutShellPoint调用TransPointI2S转换为逻辑坐标用于绘制
+                var transpoints = new List<DPoint>();
+                foreach (var point in outshellPoints)
+                {
+                    var transpoint = SRPointTrans.TransPointI2S(point, regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    transpoints.Add(transpoint);
+                }
+                UpdateGeometry(transpoints);
+                foreach (var outputItem in Outputs)
+                {
+                    outputItem.UpdateDescription(outputItem.Name);
+                    if (string.Equals(outputItem.Name, MeasureTerms.URMDenROI))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiDen * 100, outputItem), Unit.percent);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenFractalDim))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiFractalDim, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMax))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMin))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMean))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenStd))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceDensity), outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.Area))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiArea, outputItem), Unit.cm2);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenROIIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InRoiDen * 100, outputItem), Unit.percent);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenFractalDimIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InRoiFractalDim, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMaxIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InMaxDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMinIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InMinDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMeanIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InMeanDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenStdIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.InVarianceDensity), outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMAreaIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InRoiArea, outputItem), Unit.cm2);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenROIOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutRoiDen * 100, outputItem), Unit.percent);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenFractalDimOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutRoiFractalDim, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMaxOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutMaxDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMinOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutMinDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenMeanOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutMeanDensity, outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMDenStdOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.OutVarianceDensity), outputItem), Unit.None);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMAreaOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutRoiArea, outputItem), Unit.cm2);
+                    }
+                }
+            }
+
+            protected void UpdateGeometry(List<DPoint> outResult)
+            {
+                var geometry = new TraceLineFeature(outResult, RefItem, RefItem.GeoFeature.XUnit,
+                    RefItem.GeoFeature.YUnit, false)
+                {
+                    IsClosed = true,
+                };
+                if (RefItem.GeoFeature is ShellTraceFeature feature)
+                {
+                    feature.UpdateChildFeatures(new List<GeometryFeature> { geometry });
+                }
+
+
+            }
+        }
+    }
+    public class URMShellFractalDim: URMShellMeasure
+    {
+        public URMShellFractalDim(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+
+        }
+
+        internal static URMShellFractalDim CreateURMShellFractalDim(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.URMShellFractalDim)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var item = new URMShellFractalDim(meta, parent);
+            item.Calculator = new URMShellFractalDimCal(item);
+            return item;
+        }
+
+        internal sealed class URMShellFractalDimCal : Calculator<URMShellFractalDim>
+        {
+            public URMShellFractalDimCal(URMShellFractalDim item)
+                : base(item)
+            {
+
+            }
+            public URMShellFractalDimCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenFractalDim,
+                    };
+                }
+            }
+            protected override void OnCalculate()
+            {
+                if (RefItem.State != ItemStates.Finished)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point = SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height,false);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+                if (ImagePoint.Count < 3)
+                    return;
+                double pixelscaler = UrmPhysicalwidth / width;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetURMShellDenMeasureResult(srcArray.Start, width, height, ImagePoint, RefItem.ShellWidth.Value / 10,
+                    pixelscaler, out var outshellPoints); //Todo OutShellPoint调用TransPointI2S转换为逻辑坐标用于绘制
+                var transpoints = new List<DPoint>();
+                foreach (var point in outshellPoints)
+                {
+                    var transpoint = SRPointTrans.TransPointI2S(point, regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    transpoints.Add(transpoint);
+                }
+                UpdateGeometry(transpoints);
+                Outputs[0].UpdateDescription(Outputs[0].Name);
+                feature.UpdateValue(Outputs[0], RoundValue(result.RoiFractalDim, GetResultDigits(PrimaryOutput)), Unit.None);
+            }
+
+            protected void UpdateGeometry(List<DPoint> outResult)
+            {
+                var geometry = new TraceLineFeature(outResult, RefItem, RefItem.GeoFeature.XUnit,
+                    RefItem.GeoFeature.YUnit, false)
+                {
+                    IsClosed = true,
+                };
+                if (RefItem.GeoFeature is ShellTraceFeature feature)
+                {
+                    feature.UpdateChildFeatures(new List<GeometryFeature> { geometry });
+                }
+            }
+        }
+    }
+    public class URMShellDensity : URMShellMeasure
+    {
+        public URMShellDensity(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+
+        }
+
+        internal static URMShellDensity CreateURMShellDensity(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.URMShellDensity)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var item = new URMShellDensity(meta, parent);
+            item.Calculator = new URMShellDensityCal(item);
+            return item;
+        }
+
+        internal sealed class URMShellDensityCal : Calculator<URMShellDensity>
+        {
+            public URMShellDensityCal(URMShellDensity item)
+                : base(item)
+            {
+
+            }
+            public URMShellDensityCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenROI,
+                    };
+                }
+            }
+            protected override void OnCalculate()
+            {
+                if (RefItem.State != ItemStates.Finished)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point = SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height,false);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+                if (ImagePoint.Count < 3)
+                    return;
+                double pixelscaler = UrmPhysicalwidth / width;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetURMShellDenMeasureResult(srcArray.Start, width, height, ImagePoint, RefItem.ShellWidth.Value / 10,
+                    pixelscaler, out var outshellPoints); //Todo OutShellPoint调用TransPointI2S转换为逻辑坐标用于绘制
+                var transpoints = new List<DPoint>();
+                foreach (var point in outshellPoints)
+                {
+                    var transpoint = SRPointTrans.TransPointI2S(point, regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    transpoints.Add(transpoint);
+                }
+                UpdateGeometry(transpoints);
+                Outputs[0].UpdateDescription(Outputs[0].Name);
+                feature.UpdateValue(Outputs[0], RoundValue(result.RoiDen * 100, GetResultDigits(PrimaryOutput)), Unit.percent);
+            }
+
+            protected void UpdateGeometry(List<DPoint> outResult)
+            {
+                var geometry = new TraceLineFeature(outResult, RefItem, RefItem.GeoFeature.XUnit,
+                    RefItem.GeoFeature.YUnit, false)
+                {
+                    IsClosed = true,
+                };
+                if (RefItem.GeoFeature is ShellTraceFeature feature)
+                {
+                    feature.UpdateChildFeatures(new List<GeometryFeature> { geometry });
+                }
+            }
+        }
+    }
+    internal class URMShellVelMeasure : URMShellMeasure
+    {
+        public URMShellVelMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+
+        internal static URMShellVelMeasure CreateURMShellVelMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.URMShellVelMeasure)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var item = new URMShellVelMeasure(meta, parent);
+            item.Calculator = new URMShellVelMeasureCal(item);
+            return item;
+        }
+
+        internal sealed class URMShellVelMeasureCal : Calculator<URMShellVelMeasure>
+        {
+            public URMShellVelMeasureCal(URMShellVelMeasure item)
+                : base(item)
+            {
+
+            }
+            public URMShellVelMeasureCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMVelMax, MeasureTerms.URMVelMin, MeasureTerms.URMVelMean, MeasureTerms.URMVelStd, MeasureTerms.Area,
+                        MeasureTerms.URMVelMaxIn, MeasureTerms.URMVelMinIn, MeasureTerms.URMVelMeanIn, MeasureTerms.URMVelStdIn, MeasureTerms.URMAreaIn,
+                        MeasureTerms.URMVelMaxOut, MeasureTerms.URMVelMinOut, MeasureTerms.URMVelMeanOut, MeasureTerms.URMVelStdOut, MeasureTerms.URMAreaOut,
+                    };
+                }
+            }
+            protected override void OnCalculate()
+            {
+                if (RefItem.State != ItemStates.Finished)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                double UrmMinVel = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRVel = dicomvisual.isSRVel();
+                    if (!isSRVel)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                    UrmMinVel = dicomvisual.GetSRMinVel();
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Vel)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    UrmMinVel = modewithURM.URMMinVel;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point = SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height,false);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+                if(ImagePoint.Count<3)
+                    return;
+                double pixelscaler = UrmPhysicalwidth / width;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                var result = urmcal.GetURMShellVelMeasureResult(srcArray.Start, width, height, ImagePoint, RefItem.ShellWidth.Value/10,
+                    pixelscaler, out var outshellPoints); //Todo OutShellPoint调用TransPointI2S转换为逻辑坐标用于绘制
+                var transpoints = new List<DPoint>();
+                foreach (var point in outshellPoints)
+                {
+                    var transpoint = SRPointTrans.TransPointI2S(point, regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    transpoints.Add(transpoint);
+                }
+                UpdateGeometry(transpoints);
+                foreach (var outputItem in Outputs)
+                {
+                    outputItem.UpdateDescription(outputItem.Name);
+                    if (string.Equals(outputItem.Name, MeasureTerms.URMVelMax))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MaxVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMin))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MinVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMean))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.MeanVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelStd))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.VarianceVel), outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.Area))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.RoiArea, outputItem), Unit.cm2);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMaxIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InMaxVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMinIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InMinVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMeanIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InMeanVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelStdIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.InVarianceVel), outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMAreaIn))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.InRoiArea, outputItem), Unit.cm2);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMaxOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutMaxVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMinOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutMinVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelMeanOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutMeanVel + UrmMinVel, outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMVelStdOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(Math.Sqrt(result.OutVarianceVel), outputItem), Unit.mms);
+                    }
+                    else if (string.Equals(outputItem.Name, MeasureTerms.URMAreaOut))
+                    {
+                        feature.UpdateValue(outputItem, RoundValue(result.OutRoiArea, outputItem), Unit.cm2);
+                    }
+                }
+            }
+
+            private void UpdateGeometry(List<DPoint> outResult)
+            {
+                //if (outResult.ResultFlag)
+                {
+                    //var resultPoints = outResult.OuterShellPoints;
+                    // var transformPoints = new List<DPoint>();
+                    // foreach (var point in outResult)
+                    // {
+                    //     transformPoints.Add(RefItem.GeoFeature.HostArea.ViewPort.Convert(point));
+                    // }
+                    var geometry = new TraceLineFeature(outResult, RefItem, RefItem.GeoFeature.XUnit,
+                        RefItem.GeoFeature.YUnit, false)
+                    {
+                        IsClosed = true,
+                    };
+                    if (RefItem.GeoFeature is ShellTraceFeature feature)
+                    {
+                        feature.UpdateChildFeatures(new List<GeometryFeature> { geometry });
+                    }
+                }
+            }
+        }
+    }
+    internal class SRTraceMeasure : Trace
+    {
+        private bool calflag = false;
+        public SRTraceMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static SRTraceMeasure CreateSRTraceMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRTraceDensity)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var SRTrace = new SRTraceMeasure(meta, parent);
+            SRTrace.Calculator = new SRTraceCal(SRTrace);
+            return SRTrace;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as SRTraceCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class SRTraceCal : Calculator<SRTraceMeasure>
+        {
+            public bool calflag = false;
+            public SRTraceCal(SRTraceMeasure item)
+                : base(item)
+            {
+
+            }
+            public SRTraceCal()
+            {
+                
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenROI
+                    };
+                }
+            }
+
+            protected override void OnCalculate()
+            {
+                if (!calflag)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint=new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point= SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+
+                int outPointsNum = 0;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null|| ImagePoint.Count<3)
+                    return;
+                double roivel = urmcal.GetSRTraceVel(srcArray.Start, width, height, ImagePoint);
+                Outputs[0].UpdateDescription(Outputs[0].Name);
+                feature.UpdateValue(Outputs[0], RoundValue(roivel * 100, GetResultDigits(PrimaryOutput)), Unit.percent);
+            }
+        }
+    }
+    internal class SRROIFractalDimMeasure : Rect
+    {
+        private bool calflag = false;
+        public SRROIFractalDimMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static SRROIFractalDimMeasure CreateSRROIFractalDimMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRROIFractalDim)
+            {
+                throw new ArgumentException();
+            }
+            var SRROIFractalDim = new SRROIFractalDimMeasure(meta, parent);
+            SRROIFractalDim.Calculator = new SRROIFractalDimCal(SRROIFractalDim);
+            return SRROIFractalDim;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as SRROIFractalDimCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+            calflag = false;
+            cal.calfalg = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calfalg = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class SRROIFractalDimCal : Calculator<SRROIFractalDimMeasure>
+        {
+            public bool calfalg = false;
+            public SRROIFractalDimCal(SRROIFractalDimMeasure item)
+                : base(item)
+            {
+
+            }
+            public SRROIFractalDimCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenFractalDim
+                    };
+                }
+            }
+
+            protected override void OnCalculate()
+            {
+                if(!calfalg)
+                    return;
+                RectFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint startDPoint = SRPointTrans.TransPointS2I(feature.TopLeft, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                DPoint endDPoint = SRPointTrans.TransPointS2I(feature.BottomRight, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                if (startDPoint.X < 0 || startDPoint.X > width || endDPoint.X < 0 || endDPoint.X > width
+                    || startDPoint.Y < 0 || startDPoint.Y > height || endDPoint.Y < 0 || endDPoint.Y > height)
+                    return;
+                int outPointsNum = 0;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                double FractalDimvel = urmcal.GetSRRoiFractalDim(srcArray.Start, width, height, startDPoint.X,
+                    startDPoint.Y, endDPoint.X, endDPoint.Y);
+                Outputs[0].UpdateDescription(Outputs[0].Name);
+                feature.UpdateValue(Outputs[0], RoundValue(FractalDimvel, GetResultDigits(PrimaryOutput)), Unit.None);
+            }
+        }
+    }
+    internal class SRROIVelMeasure : Rect
+    {
+        private bool calflag = false;
+        public SRROIVelMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static SRROIVelMeasure CreateSRROIVelMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRRoiVel)
+            {
+                throw new ArgumentException();
+            }
+            var SRROIVel = new SRROIVelMeasure(meta, parent);
+            SRROIVel.Calculator = new SRRolVelCal(SRROIVel);
+            return SRROIVel;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as SRRolVelCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSrVel = dicomvisual.isSRVel();
+                if (args.VisualArea.Mode == null || !isSrVel)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Vel)")
+                    return false;
+            }
+            calflag = false;
+            cal.calfalg = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calfalg = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class SRRolVelCal : Calculator<SRROIVelMeasure>
+        {
+            public bool calfalg = false;
+            public SRRolVelCal(SRROIVelMeasure item)
+                : base(item)
+            {
+
+            }
+            public SRRolVelCal()
+            {
+
+            }
+            internal static readonly string SRkey = "SRRoiVel";
+            protected internal override string[] SupportedOutputKeys
+            {
+                get { return new[] { SRkey }; }
+            }
+            protected override void OnCalculate()
+            {
+                if (!calfalg)
+                    return;
+                RectFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                double UrmMinVel = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRVel = dicomvisual.isSRVel();
+                    if (!isSRVel)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                    UrmMinVel = dicomvisual.GetSRMinVel();
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Vel)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    UrmMinVel = modewithURM.URMMinVel;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint startDPoint = SRPointTrans.TransPointS2I(feature.TopLeft, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                DPoint endDPoint = SRPointTrans.TransPointS2I(feature.BottomRight, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                if (startDPoint.X < 0 || startDPoint.X > width || endDPoint.X < 0 || endDPoint.X > width
+                    || startDPoint.Y < 0 || startDPoint.Y > height || endDPoint.Y < 0 || endDPoint.Y > height)
+                    return;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null)
+                    return;
+                double meanSpeed = urmcal.GetSRRoiSpeed(srcArray.Start, width, height, startDPoint.X,
+                    startDPoint.Y, endDPoint.X, endDPoint.Y);
+                meanSpeed += UrmMinVel;
+                feature.UpdateValue(PrimaryOutput, RoundValue(meanSpeed, GetResultDigits(PrimaryOutput)), Unit.mms);
+            }
+        }
+    }
+    internal class SRTraceFractalDimMeasure : Trace
+    {
+        private bool calflag = false;
+        public SRTraceFractalDimMeasure(ItemMeta meta, IMeasureItem parent = null)
+            : base(meta, parent)
+        {
+
+        }
+        internal static SRTraceFractalDimMeasure CreateSRTraceFractalDimMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRTraceFractalDim)
+            {
+                throw new ArgumentException();
+            }
+            meta.AddArgs(new MeasureParam(IsAutoSnapKey, "true", DefinitionPriorityEnum.Root));
+            var SRTraceFractalDim = new SRTraceFractalDimMeasure(meta, parent);
+            SRTraceFractalDim.Calculator = new SRTraceFractalDimCal(SRTraceFractalDim);
+            return SRTraceFractalDim;
+        }
+
+        public override void DownloadValueFromPreviousItem()
+        {
+
+        }
+        protected override bool OnExecute(PointInfo args)
+        {
+            var cal = Calculator as SRTraceFractalDimCal;
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRDen = dicomvisual.isSRDen();
+                if (args.VisualArea.Mode == null || !isSRDen)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Den)")
+                    return false;
+            }
+            calflag = false;
+            cal.calflag = false;
+            var preState = State;
+            var result = base.OnExecute(args);
+            if (result && preState == ItemStates.Running && State == ItemStates.Finished)
+            {
+                calflag = true;
+                cal.calflag = true;
+            }
+
+            return result;
+        }
+        protected override void OnExecuted(PointInfo args)
+        {
+            if (GeoFeature != null && Calculator != null && calflag)
+            {
+                Calculator.Calculate();
+            }
+        }
+        internal sealed class SRTraceFractalDimCal : Calculator<SRTraceFractalDimMeasure>
+        {
+            public bool calflag = false;
+            public SRTraceFractalDimCal(SRTraceFractalDimMeasure item)
+                : base(item)
+            {
+
+            }
+            public SRTraceFractalDimCal()
+            {
+
+            }
+            protected internal override string[] SupportedOutputKeys
+            {
+                get
+                {
+                    return new[]
+                    {
+                        MeasureTerms.URMDenFractalDim
+                    };
+                }
+            }
+
+
+
+            protected override void OnCalculate()
+            {
+                if (!calflag)
+                    return;
+                PolyLineFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                NativeArray srcArray = new NativeArray(0);
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)//dicom回放
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRDen = dicomvisual.isSRDen();
+                    if (!isSRDen)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth,
+                        ref UrmPhysicalheight);
+                    //todo 坐标转换
+                    srcArray.Resize(dicomdate.Length);
+                    Marshal.Copy(dicomdate, 0, srcArray.Start, dicomdate.Length);
+                }
+                else if (feature.HostArea.Mode is IModeWithURM)//在URM runing时测量
+                {
+                    var modewithURM = feature.HostArea.Mode as IModeWithURM;
+                    if (modewithURM.URMStyle != "URM(Den)")
+                        return;
+                    var date = modewithURM.UrmArray;
+                    width = modewithURM.URMImgWidth;
+                    height = modewithURM.URMImgHeight;
+                    UrmPhysicalwidth = modewithURM.URMPhyWidth;
+                    UrmPhysicalheight = modewithURM.URMPhyHeight;
+                    srcArray.Resize(date.Length);
+                    Marshal.Copy(date, 0, srcArray.Start, date.Length);
+                }
+                else
+                {
+                    return;
+                }
+                if (srcArray.Length != 8 * width * height)
+                {
+                    _delayAction.BeginInvoke();
+                    return;
+                }
+                //todo 坐标转换
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                var points = RefItem.GeoFeature.Points;
+                List<DPoint> ImagePoint = new List<DPoint>();
+                for (int i = 0; i < points.Count; i++)
+                {
+                    var point = SRPointTrans.TransPointS2I(points[i], regionwidth, regionheight,
+                        UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                    if (point.X < 0 || point.X > width || point.X < 0 || point.X > width)
+                        continue;
+                    ImagePoint.Add(point);
+                }
+
+                int outPointsNum = 0;
+                var urmcal = feature.HostArea.Mode as IURMCal;
+                if (urmcal == null || ImagePoint.Count < 3)
+                    return;
+                double roivel = urmcal.GetSRTraceFractalDim(srcArray.Start, width, height, ImagePoint);
+                Outputs[0].UpdateDescription(Outputs[0].Name);
+                feature.UpdateValue(Outputs[0], RoundValue(roivel, GetResultDigits(PrimaryOutput)), Unit.None);
+            }
+        }
+    }
+    public class SRVelMeasure : Location
+    {
+        internal SRVelMeasure(ItemMeta meta, IMeasureItem parent) :
+           base(meta, parent, false)
+        {
+        }
+        // Methods 
+        protected override bool OnExecute(PointInfo args)
+        {
+            if (args.VisualArea is ISRDicom)
+            {
+                var dicomvisual = args.VisualArea as ISRDicom;
+                bool isSRVel = dicomvisual.isSRVel();
+                if (args.VisualArea.Mode == null || !isSRVel)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                var modewithurm = args.VisualArea.Mode as IModeWithURM;
+                if (modewithurm == null || modewithurm?.URMStyle != "URM(Vel)")
+                    return false;
+            }
+            return base.OnExecute(args);
+        }
+        internal static Location CreateSRVelMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.SRLoactionVel)
+            {
+                throw new ArgumentException();
+            }
+
+            SRVelMeasure location = new SRVelMeasure(meta, parent);
+            location.Calculator = new SRVelMeasure.SRVelCal(location);
+            return location;
+        }
+        #region Nested Classes 
+
+
+        internal class SRVelCal : LocationCal, IGeoCalculator
+        {
+            #region Properties 
+
+            protected internal override string[] SupportedOutputKeys
+            {
+                get { return new[] { "SRVel" }; }
+            }
+
+            #endregion Properties 
+
+            #region Methods 
+
+            // Constructors 
+
+            internal SRVelCal(Location item)
+                : base(item)
+            {
+
+            }
+
+            protected internal SRVelCal()
+            {
+
+            }
+            // Methods 
+
+            protected override void OnCalculate()
+            {
+                // throw new NotImplementedException();
+            }
+
+            public void Calculate(PointInfo pointInfo)
+            {
+                LocationFeature feature = RefItem.GeoFeature;
+                int width = 0;
+                int height = 0;
+                double UrmPhysicalwidth = 0;
+                double UrmPhysicalheight = 0;
+                double UrmMinVel = 0;
+                IntPtr buffer = new IntPtr();
+                if (feature != null && feature.HostArea is ISRDicom && feature.HostArea.Mode is IDicomMode)
+                {
+                    var dicomvisual = feature.HostArea as ISRDicom;
+                    bool isSRVel =dicomvisual.isSRVel();
+                    if (!isSRVel)
+                        return;
+                    var dicomdate = dicomvisual.GetSRDicomFile(ref width, ref height, ref UrmPhysicalwidth, ref UrmPhysicalheight);
+                    int size = dicomdate.Length;
+                    buffer = Marshal.AllocHGlobal(size);
+                    Marshal.Copy(dicomdate, 0, buffer, size);
+                    UrmMinVel = dicomvisual.GetSRMinVel();
+                }
+                else if(feature.HostArea.Mode is IModeWithURM)
+                {
+                    var modewithurm = feature.HostArea.Mode as IModeWithURM;
+                    if(modewithurm.URMStyle!="URM(Vel)")
+                        return;
+                    var date = modewithurm.UrmArray;
+                    width = modewithurm.URMImgWidth;
+                    height = modewithurm.URMImgHeight;
+                    UrmPhysicalwidth = modewithurm.URMPhyWidth;
+                    UrmPhysicalheight = modewithurm.URMPhyHeight;
+                    UrmMinVel = modewithurm.URMMinVel;
+                    int size = date.Length;
+                    buffer = Marshal.AllocHGlobal(size);
+                    Marshal.Copy(date, 0, buffer, size);
+                }
+                else
+                {
+                    return;
+                }
+                double regionwidth = feature.HostArea.ViewPort.Region.Width;
+                double regionheight = feature.HostArea.ViewPort.Region.Height;
+                DPoint curPoint = SRPointTrans.TransPointS2I(feature.Point, regionwidth, regionheight,
+                    UrmPhysicalwidth, UrmPhysicalheight, width, height);
+                if (curPoint.X < 0 || curPoint.X > width || curPoint.Y < 0 || curPoint.Y > height)
+                    return;
+                var curptr = buffer + sizeof(double) * ((int)curPoint.X + (int)curPoint.Y * width);
+                double[] curvel = new double[1];
+                Marshal.Copy(curptr, curvel, 0, 1);
+                var velvalue = curvel[0];
+                velvalue += UrmMinVel;
+                if (velvalue < 0.01)
+                    velvalue = 0;
+                feature.UpdateValue(PrimaryOutput, RoundValue(velvalue, GetResultDigits(PrimaryOutput)), Unit.mms);
+
+
+            }
+
+            #endregion Methods 
+        }
+        #endregion Nested Classes 
+    }
+
+    public class URMDen : ProtocolItem
+    {
+        internal URMDen(ItemMeta meta, IMeasureItem parent = null) : base(meta, true, parent)
+        {
+        }
+
+        internal static URMDen Create(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.URMDen)
+            {
+                throw new ArgumentException();
+            }
+            var item = new URMDen(meta, parent);
+            item.Calculator = new URMDenCal(item);
+            return item;
+        }
+
+        internal class URMDenCal : Calculator<URMDen>
+        {
+            protected internal override string[] SupportedOutputKeys => new[] { "URMDen" };
+
+            public URMDenCal()
+            {
+            }
+
+            public URMDenCal(URMDen item) : base(item)
+            {
+            }
+
+            protected override void OnCalculate()
+            {
+                if (RefItem.Feature != null)
+                {
+                    RefItem.Feature.Values.Clear();
+                    if (PrimaryOutput != null)
+                    {
+                        RefItem.Feature.UpdateValue(PrimaryOutput.Name, new StringValue(PrimaryOutput.Name) { Description = PrimaryOutput.Description });
+                    }
+                }
+            }
+        }
+    }
+
+    public class URMVel : ProtocolItem
+    {
+        internal URMVel(ItemMeta meta, IMeasureItem parent = null) : base(meta, true, parent)
+        {
+        }
+
+        internal static URMVel Create(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta == null || meta.BaseType != MeasureTypes.URMVel)
+            {
+                throw new ArgumentException();
+            }
+            var item = new URMVel(meta, parent);
+            item.Calculator = new URMVelCal(item);
+            return item;
+        }
+        internal class URMVelCal : Calculator<URMVel>
+        {
+            protected internal override string[] SupportedOutputKeys => new[] { "URMVel" };
+
+            public URMVelCal()
+            {
+            }
+
+            public URMVelCal(URMVel item):base(item)
+            {
+            }
+
+            protected override void OnCalculate()
+            {
+                if (RefItem.Feature != null)
+                {
+                    RefItem.Feature.Values.Clear();
+                    if (PrimaryOutput != null)
+                    {
+                        RefItem.Feature.UpdateValue(PrimaryOutput.Name, new StringValue(PrimaryOutput.Name) { Description = PrimaryOutput.Description});
+                    }
+                }
+            }
+        }
+    }
+
+    public class FractalDimSR: URMDensityMeasure
+    {
+        internal FractalDimSR(ItemMeta meta, IMeasureItem parent = null) : base(meta, parent)
+        {
+        }
+
+        internal static FractalDimSR CreateFractalDimSR(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.FractalDimSR)
+            {
+                throw new ArgumentException();
+            }
+            var item = new FractalDimSR(meta, parent);
+            return item;
+        }
+    }
+
+    public class DensitySR : URMDensityMeasure
+    {
+        internal DensitySR(ItemMeta meta, IMeasureItem parent = null) : base(meta, parent)
+        {
+        }
+        internal static DensitySR CreateDensitySR(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.DensitySR)
+            {
+                throw new ArgumentException(); 
+            }
+            var item = new DensitySR(meta, parent);
+            return item;
+        }
+    }
+
+    public class URMDensityMeasure : MultiMethodItem
+    {
+        internal URMDensityMeasure(ItemMeta meta, IMeasureItem parent = null) : base(meta, parent)
+        {
+        }
+        internal static URMDensityMeasure CreateURMDensityMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.URMDensityMeasure)
+            {
+                throw new ArgumentException();
+            }
+            var item = new URMDensityMeasure(meta, parent);
+            return item;
+        }
+    }
+
+    public class URMVelMeasure : URMDensityMeasure
+    {
+        internal URMVelMeasure(ItemMeta meta, IMeasureItem parent = null) : base(meta, parent)
+        {
+        }
+        internal static URMVelMeasure CreateURMVelMeasure(ItemMeta meta, IMeasureItem parent)
+        {
+            if (meta.BaseType != MeasureTypes.URMVelMeasure)
+            {
+                throw new ArgumentException();
+            }
+            var item = new URMVelMeasure(meta, parent);
+            return item;
+        }
+    }
+
+}

+ 50 - 0
lib/interfaces/process/items/terms.dart

@@ -48,6 +48,56 @@ class MeasureTerms {
   static const VesselDiameter = "VesselDiameter";
   static const VesselDistance = "VesselDistance";
 
+  /// <summary>
+  /// URM相关
+  /// </summary>
+  static const URMDenROI = "Vessel ratio";
+
+  static const URMDenFractalDim = "Complexity level";
+  static const URMDenMax = "Max";
+  static const URMDenMin = "Min";
+  static const URMDenMean = "Mean";
+  static const URMDenStd = "Std";
+  static const URMDenROIIn = "Vessel ratio(In)";
+  static const URMDenFractalDimIn = "Complexity level(In)";
+  static const URMDenMaxIn = "Max(In)";
+  static const URMDenMinIn = "Min(In)";
+  static const URMDenMeanIn = "Mean(In)";
+  static const URMDenStdIn = "Std(In)";
+  static const URMDenROIOut = "Vessel ratio(Out)";
+  static const URMDenFractalDimOut = "Complexity level(Out)";
+  static const URMDenMaxOut = "Max(Out)";
+  static const URMDenMinOut = "Min(Out)";
+  static const URMDenMeanOut = "Mean(Out)";
+  static const URMDenStdOut = "Std(Out)";
+
+  static const URMVelMax = "Max";
+  static const URMVelMin = "Min";
+  static const URMVelMean = "Mean";
+  static const URMVelStd = "Std";
+  static const URMVelMaxIn = "Max(In)";
+  static const URMVelMinIn = "Min(In)";
+  static const URMVelMeanIn = "Mean(In)";
+  static const URMVelStdIn = "Std(In)";
+  static const URMVelMaxOut = "Max(Out)";
+  static const URMVelMinOut = "Min(Out)";
+  static const URMVelMeanOut = "Mean(Out)";
+  static const URMVelStdOut = "Std(Out)";
+
+  static const URMAreaIn = "Area(In)";
+  static const URMAreaOut = "Area(Out)";
+
+  static const MaxVessDistance = "Max Distance";
+  static const MinVessDistance = "Min Distance";
+  static const MeanVessDistacne = "Mean Distance";
+  static const StdVessDistance = "Std Distance";
+  static const MaxVessDiameter = "Max Diameter";
+  static const MinVessDiameter = "Min Diameter";
+  static const MeanVessDiameter = "Mean Diameter";
+  static const StdVessDiameter = "Std Diameter";
+  static const MaxPos = "MaxPos";
+  static const MinPos = "MinPos";
+
   ///////////////////////////////////////////////////////////////////////////////////////////////////////
 
   /* AI [begin]*/