示例#1
0
        private static IGraphic CreateInteractivePolyline(IList <PointF> vertices)
        {
            var closed = FloatComparer.AreEqual(vertices[0], vertices[vertices.Count - 1]);

            // use a standard rectangle primitive if the axes defines an axis-aligned rectangle
            if (closed && vertices.Count == 5 && IsAxisAligned(vertices[0], vertices[1]) && IsAxisAligned(vertices[1], vertices[2]) && IsAxisAligned(vertices[2], vertices[3]) && IsAxisAligned(vertices[3], vertices[4]))
            {
                var bounds    = RectangleUtilities.ConvertToPositiveRectangle(RectangleUtilities.ComputeBoundingRectangle(vertices[0], vertices[1], vertices[2], vertices[3]));
                var rectangle = new RectanglePrimitive {
                    TopLeft = bounds.Location, BottomRight = bounds.Location + bounds.Size
                };
                return(new BoundableResizeControlGraphic(new BoundableStretchControlGraphic(new MoveControlGraphic(rectangle))));
            }
            else if (!closed && vertices.Count == 3)
            {
                var protractor = new ProtractorGraphic {
                    Points = { vertices[0], vertices[1], vertices[2] }
                };
                return(new VerticesControlGraphic(new MoveControlGraphic(protractor)));
            }
            else if (!closed && vertices.Count == 2)
            {
                var line = new PolylineGraphic {
                    Points = { vertices[0], vertices[1] }
                };
                return(new VerticesControlGraphic(new MoveControlGraphic(line)));
            }

            var polyline = new PolylineGraphic(closed);

            polyline.Points.AddRange(vertices);
            return(closed ? new PolygonControlGraphic(true, new MoveControlGraphic(polyline)) : new VerticesControlGraphic(true, new MoveControlGraphic(polyline)));
        }
示例#2
0
        public void TestComplexAreaAlgorithmWithComplexPolygonNoBufferOverrun()
        {
            // the complex area algorithm is very low resolution compared to simple area, so the error magnitude is higher
            const int side     = 1000;
            const int expected = side * side / 2;

            PointF[] data = new PointF[5];
            data[0] = new PointF(0, 0);
            data[1] = new PointF(side, 0);
            data[2] = new PointF(0, side);
            data[3] = new PointF(side, side);
            data[4] = new PointF(side / 2f, side / 2f);

            PolygonF.TestVertexNormalization(data);

            RectangleF bounding = RectangleUtilities.ComputeBoundingRectangle(data);

            // test for a possible buffer overrun in the computation
            foreach (PointF garbagePoint in SimulatedBufferOverrunPoints)
            {
                data[data.Length - 1] = garbagePoint;
                unsafe
                {
                    fixed(PointF *points = data)
                    {
                        // inside PolygonF, the vertexCount is always exactly the expected array length
                        // which is 4 (the 5th point simulates garbage data beyond the array)
                        double result = PolygonF.TestComplexAreaComputation(bounding, points, data.Length - 1);

                        Trace.WriteLine(string.Format("Complex Area: Expected {0:f5} Got {1:f5}", expected, result), "UNIT_TESTS");
                        Assert.IsTrue(Math.Abs(expected - result) < expected / 100f);
                    }
                }
            }
        }
示例#3
0
        public void TestComplexAreaAlgorithmWithComplexPolygon()
        {
            // the complex area algorithm is very low resolution compared to simple area, so the error magnitude is higher
            const int side     = 1000;
            const int expected = side * side / 2;

            PointF[] data = new PointF[4];
            data[0] = new PointF(0, 0);
            data[1] = new PointF(side, 0);
            data[2] = new PointF(0, side);
            data[3] = new PointF(side, side);

            PolygonF.TestVertexNormalization(data);

            RectangleF bounding = RectangleUtilities.ComputeBoundingRectangle(data);

            unsafe
            {
                fixed(PointF *points = data)
                {
                    // inside PolygonF, the vertexCount is always exactly the expected array length
                    double result = PolygonF.TestComplexAreaComputation(bounding, points, data.Length);

                    Trace.WriteLine(string.Format("Complex Area: Expected {0:f5} Got {1:f5}", expected, result), "UNIT_TESTS");
                    Assert.IsTrue(Math.Abs(expected - result) < expected / 100f);
                }
            }
        }
示例#4
0
 private static IGraphic CreateInteractiveEllipse(PointF majorAxisEnd1, PointF majorAxisEnd2, PointF minorAxisEnd1, PointF minorAxisEnd2)
 {
     if (IsAxisAligned(majorAxisEnd1, majorAxisEnd2) && IsAxisAligned(minorAxisEnd1, minorAxisEnd2))
     {
         // use a standard ellipse primitive if the axes defines an axis-aligned ellipse
         var bounds  = RectangleUtilities.ConvertToPositiveRectangle(RectangleUtilities.ComputeBoundingRectangle(majorAxisEnd1, majorAxisEnd2, minorAxisEnd1, minorAxisEnd2));
         var ellipse = new EllipsePrimitive {
             TopLeft = bounds.Location, BottomRight = bounds.Location + bounds.Size
         };
         return(new BoundableResizeControlGraphic(new BoundableStretchControlGraphic(new MoveControlGraphic(ellipse))));
     }
     return(new MoveControlGraphic(CreateEllipse(majorAxisEnd1, majorAxisEnd2, minorAxisEnd1, minorAxisEnd2)));
 }
        public static SegFrameImageGraphic AddSegFrameImageGraphicToPresentationImage(
            IPresentationImage presentationImage,
            Color color,
            IEnumerable <PointF> vertices)
        {
            var image = presentationImage as IImageGraphicProvider;

            if (image == null)
            {
                return(null);
            }

            // Get the base image
            ImageGraphic baseImage = image.ImageGraphic;

            var segFrameImageGraphic = new SegFrameImageGraphic(baseImage.Rows, baseImage.Columns, color);

            segFrameImageGraphic.Alpha = Seg.DefaultOpacity;
            RectangleF boundingBox = RectangleUtilities.ComputeBoundingRectangle(vertices.ToArray());

            // Convert vector polygon to raster on a per pixel basis
            baseImage.PixelData.ForEachPixel(
                delegate(int i, int x, int y, int pixelIndex)
            {
                var point = new PointF(x, y);
                if (boundingBox.Contains(point))
                {
                    if (IsInPolygon(vertices.ToArray(), point))
                    {
                        segFrameImageGraphic[x, y] = true;
                    }
                }
            }
                );

            var overlayGraphicsProvider = presentationImage as IOverlayGraphicsProvider;

            if (overlayGraphicsProvider != null)
            {
                overlayGraphicsProvider.OverlayGraphics.Add(segFrameImageGraphic);
            }

            return(segFrameImageGraphic);
        }
示例#6
0
        /// <summary>
        /// Constructs a new <see cref="IGraphic"/> whose contents are constructed based on a <see cref="GraphicAnnotationSequenceItem">DICOM Graphic Annotation Sequence Item</see>.
        /// </summary>
        /// <param name="graphicAnnotationSequenceItem">The DICOM graphic annotation sequence item to render.</param>
        /// <param name="displayedArea">The image's displayed area with which to </param>
        public static DicomGraphicAnnotation Create(GraphicAnnotationSequenceItem graphicAnnotationSequenceItem, RectangleF displayedArea)
        {
            var subjectGraphic = new SubjectGraphic();
            var dataPoints     = new List <PointF>();

            if (graphicAnnotationSequenceItem.GraphicObjectSequence != null)
            {
                foreach (var graphicItem in graphicAnnotationSequenceItem.GraphicObjectSequence)
                {
                    try
                    {
                        var points  = GetGraphicDataAsSourceCoordinates(displayedArea, graphicItem);
                        var graphic = CreateGraphic(graphicItem.GraphicType, points, true);
                        if (graphic != null)
                        {
                            subjectGraphic.Graphics.Add(new ElementGraphic(graphic));
                        }
                        dataPoints.AddRange(points);
                    }
                    catch (Exception ex)
                    {
                        Platform.Log(LogLevel.Warn, ex, "DICOM Softcopy Presentation State Deserialization Fault (Graphic Object Type {0}). Reprocess with log level DEBUG to see DICOM data dump.", graphicItem.GraphicType);
                        Platform.Log(LogLevel.Debug, graphicItem.DicomSequenceItem.Dump());
                    }
                }
            }

            var annotations      = new List <IGraphic>();
            var annotationBounds = RectangleF.Empty;

            if (dataPoints.Count > 0)
            {
                annotationBounds = RectangleUtilities.ComputeBoundingRectangle(dataPoints.ToArray());
            }
            if (graphicAnnotationSequenceItem.TextObjectSequence != null)
            {
                foreach (var textItem in graphicAnnotationSequenceItem.TextObjectSequence)
                {
                    try
                    {
                        annotations.Add(CreateCalloutText(annotationBounds, displayedArea, textItem));
                    }
                    catch (Exception ex)
                    {
                        Platform.Log(LogLevel.Warn, ex, "DICOM Softcopy Presentation State Deserialization Fault (Text Object). Reprocess with log level DEBUG to see DICOM data dump.");
                        Platform.Log(LogLevel.Debug, textItem.DicomSequenceItem.Dump());
                    }
                }
            }

            var calloutGraphic = annotations.FirstOrDefault() as ICalloutGraphic;

            if (subjectGraphic.Graphics.Count == 1 && annotations.Count == 1 && calloutGraphic != null)
            {
                // disable the subject graphics before we add the callout, because we want the callout to be moveable
                subjectGraphic.SetEnabled(false);

                var subjectElement = (ElementGraphic)subjectGraphic.Graphics.Single();
                subjectElement.Graphics.Add(calloutGraphic);
                subjectElement.Callout = calloutGraphic;
            }
            else
            {
                subjectGraphic.Graphics.AddRange(annotations.Where(g => !(g is ICalloutGraphic)).Select(g => new TextEditControlGraphic(g)));
                subjectGraphic.Graphics.AddRange(annotations.OfType <ICalloutGraphic>().Select(g => new UserCalloutGraphic
                {
                    AnchorPoint   = g.AnchorPoint,
                    TextLocation  = g.TextLocation,
                    Text          = g.Text,
                    ShowArrowhead = !(g is CalloutGraphic) || ((CalloutGraphic)g).ShowArrowhead
                }));

                // disable both subject graphiucs and any callouts
                subjectGraphic.SetEnabled(false);
            }

            subjectGraphic.SetColor(Color.LemonChiffon);
            return(new DicomGraphicAnnotation(subjectGraphic));
        }
示例#7
0
        /// <summary>
        /// Constructs a new <see cref="IGraphic"/> whose contents are constructed based on a <see cref="GraphicAnnotationSequenceItem">DICOM Graphic Annotation Sequence Item</see>.
        /// </summary>
        /// <param name="graphicAnnotationSequenceItem">The DICOM graphic annotation sequence item to render.</param>
        /// <param name="displayedArea">The image's displayed area with which to </param>
        public DicomGraphicAnnotation(GraphicAnnotationSequenceItem graphicAnnotationSequenceItem, RectangleF displayedArea)
        {
            this.CoordinateSystem = CoordinateSystem.Source;
            _layerId = graphicAnnotationSequenceItem.GraphicLayer ?? string.Empty;

            try
            {
                List <PointF> dataPoints = new List <PointF>();
                if (graphicAnnotationSequenceItem.GraphicObjectSequence != null)
                {
                    foreach (GraphicAnnotationSequenceItem.GraphicObjectSequenceItem graphicItem in graphicAnnotationSequenceItem.GraphicObjectSequence)
                    {
                        try
                        {
                            IList <PointF> points = GetGraphicDataAsSourceCoordinates(displayedArea, graphicItem);
                            switch (graphicItem.GraphicType)
                            {
                            case GraphicAnnotationSequenceItem.GraphicType.Interpolated:
                                base.Graphics.Add(CreateInterpolated(points));
                                break;

                            case GraphicAnnotationSequenceItem.GraphicType.Polyline:
                                base.Graphics.Add(CreatePolyline(points));
                                break;

                            case GraphicAnnotationSequenceItem.GraphicType.Point:
                                base.Graphics.Add(CreatePoint(points[0]));
                                break;

                            case GraphicAnnotationSequenceItem.GraphicType.Circle:
                                base.Graphics.Add(CreateCircle(points[0], (float)Vector.Distance(points[0], points[1])));
                                break;

                            case GraphicAnnotationSequenceItem.GraphicType.Ellipse:
                                base.Graphics.Add(CreateEllipse(points[0], points[1], points[2], points[3]));
                                break;

                            default:
                                break;
                            }
                            dataPoints.AddRange(points);
                        }
                        catch (Exception ex)
                        {
                            Platform.Log(LogLevel.Warn, ex, "DICOM Softcopy Presentation State Deserialization Fault (Graphic Object Type {0}). Reprocess with log level DEBUG to see DICOM data dump.", graphicItem.GraphicType);
                            Platform.Log(LogLevel.Debug, graphicItem.DicomSequenceItem.Dump());
                        }
                    }
                }

                RectangleF annotationBounds = RectangleF.Empty;
                if (dataPoints.Count > 0)
                {
                    annotationBounds = RectangleUtilities.ComputeBoundingRectangle(dataPoints.ToArray());
                }
                if (graphicAnnotationSequenceItem.TextObjectSequence != null)
                {
                    foreach (GraphicAnnotationSequenceItem.TextObjectSequenceItem textItem in graphicAnnotationSequenceItem.TextObjectSequence)
                    {
                        try
                        {
                            base.Graphics.Add(CreateCalloutText(annotationBounds, displayedArea, textItem));
                        }
                        catch (Exception ex)
                        {
                            Platform.Log(LogLevel.Warn, ex, "DICOM Softcopy Presentation State Deserialization Fault (Text Object). Reprocess with log level DEBUG to see DICOM data dump.");
                            Platform.Log(LogLevel.Debug, textItem.DicomSequenceItem.Dump());
                        }
                    }
                }
            }
            finally
            {
                this.ResetCoordinateSystem();
            }

            OnColorChanged();
        }
示例#8
0
 /// <summary>
 /// Called by <see cref="Roi.BoundingBox"/> to compute the tightest bounding box of the region of interest.
 /// </summary>
 /// <remarks>
 /// <para>This method is only called once and the result is cached for future accesses.</para>
 /// <para>
 /// Regions of interest have no notion of coordinate system. All coordinates are inherently
 /// given relative to the image pixel space (i.e. <see cref="CoordinateSystem.Source"/>.)
 /// </para>
 /// </remarks>
 /// <returns>A rectangle defining the bounding box.</returns>
 protected override RectangleF ComputeBounds()
 {
     return(RectangleUtilities.ComputeBoundingRectangle(_points));
 }