public AimGraphic(IGraphic graphic, aim_dotnet.ImageAnnotation imageAnnotation, int shapeIdentifier)
     : base(graphic)
 {
     _imageAnnotation = imageAnnotation;
     _shapeIdentifier = shapeIdentifier;
     _graphic = graphic;
 }
 internal Aim3ObjectReference(aim_dotnet.Annotation aimAnnotation)
 {
     AimAnnotation = aimAnnotation;
 }
        private static string GetImageSOPInstanceUID(aim_dotnet.IGeometricShape geoShape)
        {
            if (geoShape.SpatialCoordinateCollection != null && geoShape.SpatialCoordinateCollection.Count > 0 &&
                geoShape.SpatialCoordinateCollection[0].CoordinateType == aim_dotnet.SpatialCoordinateType.SPATIAL_COORD_2D)
            {
                var twoDSpatialCoord = geoShape.SpatialCoordinateCollection[0] as aim_dotnet.TwoDimensionSpatialCoordinate;
                if (twoDSpatialCoord != null)
                    return twoDSpatialCoord.ImageReferenceUID;
            }

            return string.Empty;
        }
        private static PointF AsPointF(aim_dotnet.ISpatialCoordinate spatialCoord)
        {
            Platform.CheckTrue(spatialCoord != null, "Spatial Coordinate Exists");
            Platform.CheckTrue(spatialCoord.CoordinateType == aim_dotnet.SpatialCoordinateType.SPATIAL_COORD_2D, "SpatialCoordinate is 2D");
            var twoDCoord = spatialCoord as aim_dotnet.TwoDimensionSpatialCoordinate;
            if (twoDCoord == null)
                throw new ArgumentException("Spatial coordinate is not 2D");

            return new PointF((float)twoDCoord.X, (float)twoDCoord.Y);
        }
        public static bool WriteXmlAnnotationToFile(aim_dotnet.Annotation annotation, string filePathName)
        {
            var xmlModel = new aim_dotnet.XmlModel();
            try
            {
                xmlModel.WriteAnnotationToFile(annotation, filePathName);
                return true;
            }
            catch (Exception ex)
            {
                Platform.Log(LogLevel.Error, ex, "Failed to save annotation to file \"{0}\"", filePathName);
            }
            finally
            {
                xmlModel = null;
            }

            return false;
        }
        public static string GetAimHtml(aim_dotnet.Annotation annotation)
        {
            if (annotation == null)
                return GetEmptyHtml();

            switch (annotation.AnnotationKind)
            {
                case aim_dotnet.AnnotationKind.AK_ImageAnnotation:
                    return GetImageAnnotationHtml(annotation as aim_dotnet.ImageAnnotation);
                case aim_dotnet.AnnotationKind.AK_AnnotationOfAnnotation:
                    return GetAnnotationOfAnnotationHtml(annotation as aim_dotnet.AnnotationOfAnnotation);
            }

            Debug.Assert(false, "Uknown Annotation Type");
            Platform.Log(LogLevel.Error, "Annotation Display Formatting (HTML): unknown annotation type");
            return "Unknown Annotation Type";
        }
        private static string OperatorToString(aim_dotnet.ComparisonOperatorIdentifier operatorIdentifier, bool capFirst)
        {
            switch(operatorIdentifier)
            {
                case aim_dotnet.ComparisonOperatorIdentifier.Equal:
                    return capFirst ? "Equal to" : "equal to";
                case aim_dotnet.ComparisonOperatorIdentifier.NotEqual:
                    return capFirst ? "Not equal to" : "not equal to";
                case aim_dotnet.ComparisonOperatorIdentifier.LessThan:
                    return capFirst ? "Less than" : "less than";
                case aim_dotnet.ComparisonOperatorIdentifier.LessThanEqual:
                    return capFirst ? "Less than or equal" : "less than or equal";
                case aim_dotnet.ComparisonOperatorIdentifier.GreaterThan:
                    return capFirst ? "Greater than" : "greater than";
                case aim_dotnet.ComparisonOperatorIdentifier.GreaterThanEqual:
                    return capFirst ? "Greater than or equal" : "greater than or equal";
                case aim_dotnet.ComparisonOperatorIdentifier.None:
                    return capFirst ? "None" : "none";
                case aim_dotnet.ComparisonOperatorIdentifier.InvalidComparisonOperator:
                    return capFirst ? "Invalid" : "invalid";
            }

            return string.Empty;
        }
 private static string GetAnnotationOfAnnotationHtml(aim_dotnet.AnnotationOfAnnotation annotationOfAnnotation)
 {
     throw new NotImplementedException();
 }
 public static bool AimDotNetNonQuantifiableEqualsTemplateTreeNonQuantifiable(aim_dotnet.NonQuantifiable a, TemplateTree.StandardCodedTerm b)
 {
     return String.Equals(a.CodeValue, b.CodeValue) &&
         String.Equals(a.CodeMeaning, b.CodeMeaning) &&
         StringEquals(a.CodingSchemeVersion, b.CodingSchemeVersion) &&
         String.Equals(a.CodingSchemeDesignator, b.CodingSchemeDesignator);
 }
 public static bool AimDotNetIntervalEqualsTemplateTreeInterval(aim_dotnet.Interval a, TemplateTree.Interval b)
 {
     return
         a.MinValue == b.MinValue &&
         a.MaxValue == b.MaxValue &&
         a.MinOperator == ToAimComparisonOperator(b.MinOperator) &&
         a.MaxOperator == ToAimComparisonOperator(b.MaxOperator) &&
         a.UcumString == b.UcumString;
 }
 // Retrieves SOP Instance UID and Referenced Frame Number from the coordinate
 private static void SetMarkupImageReference(TemplateTree.IMarkup markup, aim_dotnet.ISpatialCoordinate spatialCoordinate)
 {
     if (spatialCoordinate.CoordinateType == aim_dotnet.SpatialCoordinateType.SPATIAL_COORD_2D)
     {
         var twoDSpatialCoord = spatialCoordinate as aim_dotnet.TwoDimensionSpatialCoordinate;
         if (twoDSpatialCoord != null)
         {
             Debug.Assert(twoDSpatialCoord.ReferencedFrameNumber > 0, "Referenced Frame Number must be positive");
             markup.PresentationImageUid = twoDSpatialCoord.ImageReferenceUID;
             markup.FrameNumber = twoDSpatialCoord.ReferencedFrameNumber;
         }
     }
     else
     {
         Debug.Assert(false, "Setting image references is not implemented for 3D");
     }
 }
 public static TemplateTree.StandardCodeSequence ToStandardCodeSequence(aim_dotnet.Inference inference)
 {
     return inference == null
             ? null
             :
                 new TemplateTree.StandardCodeSequence(inference.CodeValue, inference.CodeMeaning, inference.CodingSchemeDesignator,
                                          inference.CodingSchemeVersion);
 }
 public static TemplateTree.StandardCodeSequence ToStandardCodeSequence(aim_dotnet.ImagingObservationCharacteristic imagingObservationCharacteristic)
 {
     return imagingObservationCharacteristic == null
             ? null
             :
                 new TemplateTree.StandardCodeSequence(imagingObservationCharacteristic.CodeValue, imagingObservationCharacteristic.CodeMeaning, imagingObservationCharacteristic.CodingSchemeDesignator,
                                          imagingObservationCharacteristic.CodingSchemeVersion);
 }
 public static TemplateTree.StandardCodeSequence ToStandardCodeSequence(aim_dotnet.AnatomicEntityCharacteristic anatomicEntityCharacteristic)
 {
     return anatomicEntityCharacteristic == null
             ? null
             :
                 new TemplateTree.StandardCodeSequence(anatomicEntityCharacteristic.CodeValue, anatomicEntityCharacteristic.CodeMeaning,
                                          anatomicEntityCharacteristic.CodingSchemeDesignator,
                                          anatomicEntityCharacteristic.CodingSchemeVersion);
 }
        internal DataProvider(aim_dotnet.Annotation annotation)
        {
            Platform.CheckForNullReference(annotation, "Annotation");

            _annotation = annotation;
        }
 public static bool AimDotNetNumericalEqualsTemplateTreeNumerical(aim_dotnet.Numerical a, TemplateTree.Numerical b)
 {
     return
         a.Value == b.Value &&
         a.UcumString == b.UcumString &&
         a.Operator == ToAimComparisonOperator(b.Operator);
 }
        private static string CombineOperatorAndValue(aim_dotnet.ComparisonOperatorIdentifier operatorIdentifier, string aValue, bool capFirst)
        {
            aValue = aValue.Trim();
            if (operatorIdentifier == aim_dotnet.ComparisonOperatorIdentifier.None ||
                operatorIdentifier == aim_dotnet.ComparisonOperatorIdentifier.InvalidComparisonOperator)
                return string.IsNullOrEmpty(aValue) ? "" : aValue;

            if (string.IsNullOrEmpty(aValue))
                return OperatorToString(operatorIdentifier, capFirst);

            return string.Format("{0} {1}", OperatorToString(operatorIdentifier, capFirst), aValue);
        }
 public static bool AimDotNetScaleEqualsTemplateTreeScaleLevel(aim_dotnet.Scale a, TemplateTree.ScaleLevel b)
 {
     return a.Value == b.Value;
 }
        private static string GetImageAnnotationHtml(aim_dotnet.ImageAnnotation imageAnnotation)
        {
            var sb = new StringBuilder();
            var htmlFormatter = new AimHtmlFormatter();
            var ctrlColor = Color.FromKnownColor(KnownColor.Control);

            sb.Append(HtmlDocHeader);
            sb.AppendFormat("<body style=\"background-color: #{0}{1}{2};\" onload=\"setupPaths(['{3}', '{4}'])\">",
                ctrlColor.R.ToString("X2"), ctrlColor.G.ToString("X2"), ctrlColor.B.ToString("X2"),
                MinusImagePathName, PlusImagePathName);
            sb.Append("<div id=\"main_content\">");
            sb.Append(htmlFormatter.GetAnatomicEntitiesHtml(imageAnnotation.AnatomyEntityCollection));
            sb.Append(htmlFormatter.GetImagingObservationHtml(imageAnnotation.ImagingObservationCollection));
            sb.Append("</div>");
            sb.Append("</body>");
            sb.Append("</html>");

            return sb.ToString();
        }
        public static TemplateTree.IMarkup ToMarkup(aim_dotnet.IGeometricShape geometricShape, string markupText)
        {
            if (geometricShape == null)
                return null;

            if (geometricShape is aim_dotnet.Point)
            {
                var point = (aim_dotnet.Point)geometricShape;

                var markup = new TemplateTree.MarkupPoint();
                markup.Name = markupText;
                markup.IncludeInAnnotation = point.IsIncludeFlag;
                markup.Point = AimNativeConverter.AsPointF(point.Center);
                markup.CalloutText = string.Empty; // markupText;
                markup.CalloutLocation = markup.Point - new SizeF(30, 30);
                SetMarkupImageReference(markup, point.Center);

                return markup;
            }
            if (geometricShape is aim_dotnet.Circle)
            {
                var circle = (aim_dotnet.Circle)geometricShape;

                PointF centerPt = AimNativeConverter.AsPointF(circle.Center);
                PointF radiusPt = AimNativeConverter.AsPointF(circle.RadiusPoint);
                double radiusLength = Vector.Distance(centerPt, radiusPt);

                var markup = new TemplateTree.MarkupEllipse();
                markup.Name = markupText;
                markup.IncludeInAnnotation = circle.IsIncludeFlag;
                markup.TopLeft = new PointF((float)(centerPt.X - radiusLength), (float)(centerPt.Y - radiusLength));
                markup.BottomRight = new PointF((float)(centerPt.X + radiusLength), (float)(centerPt.Y + radiusLength));
                markup.CalloutLocation = markup.TopLeft - new SizeF(30, 30);
                SetMarkupImageReference(markup, circle.Center);

                return markup;
            }
            if (geometricShape is aim_dotnet.Ellipse)
            {
                var ellipse = (aim_dotnet.Ellipse)geometricShape;

                Debug.Assert(ellipse.EllipseCollection.Count == 4, "Ellipse must have four points");
                var firstMajorAxisPt = AimNativeConverter.AsPointF(ellipse.EllipseCollection[0]);
                var secondMajorAxisPt = AimNativeConverter.AsPointF(ellipse.EllipseCollection[1]);
                var firstMinorAxisPt = AimNativeConverter.AsPointF(ellipse.EllipseCollection[2]);
                var secondMinorAxisPt = AimNativeConverter.AsPointF(ellipse.EllipseCollection[3]);

                var markup = new TemplateTree.MarkupEllipse();
                markup.Name = markupText;
                markup.IncludeInAnnotation = ellipse.IsIncludeFlag;
                markup.TopLeft = new PointF(firstMajorAxisPt.X, firstMinorAxisPt.Y);
                markup.BottomRight = new PointF(secondMajorAxisPt.X, secondMinorAxisPt.Y);
                markup.CalloutLocation = markup.TopLeft - new SizeF(30, 30);
                SetMarkupImageReference(markup, ellipse.EllipseCollection[0]);

                return markup;
            }
            if (geometricShape is aim_dotnet.Polyline)
            {
                var polyline = (aim_dotnet.Polyline)geometricShape;

                // Check if this is a non-rotated rectangle
                if (polyline.SpatialCoordinateCollection.Count == 4)
                {
                    PointF twoDPoint1 = AimNativeConverter.AsPointF(polyline.SpatialCoordinateCollection[0]);
                    PointF twoDPoint2 = AimNativeConverter.AsPointF(polyline.SpatialCoordinateCollection[1]);
                    PointF twoDPoint3 = AimNativeConverter.AsPointF(polyline.SpatialCoordinateCollection[2]);
                    PointF twoDPoint4 = AimNativeConverter.AsPointF(polyline.SpatialCoordinateCollection[3]);
                    // If it's a rectangle with sides parallel to the axes
                    if ((twoDPoint1.X == twoDPoint2.X && twoDPoint2.Y == twoDPoint3.Y && twoDPoint3.X == twoDPoint4.X && twoDPoint4.Y == twoDPoint1.Y) ||
                        (twoDPoint1.Y == twoDPoint2.Y && twoDPoint2.X == twoDPoint3.X && twoDPoint3.Y == twoDPoint4.Y && twoDPoint4.X == twoDPoint1.X))
                    {
                        var markupRectangle = new TemplateTree.MarkupRectangle();
                        markupRectangle.TopLeft = twoDPoint1;
                        markupRectangle.BottomRight = twoDPoint3;
                        markupRectangle.Name = markupText;
                        markupRectangle.IncludeInAnnotation = polyline.IsIncludeFlag;
                        markupRectangle.CalloutLocation = markupRectangle.TopLeft - new SizeF(30, 30);
                        SetMarkupImageReference(markupRectangle, polyline.SpatialCoordinateCollection[0]);

                        return markupRectangle;
                    }
                }

                var points = new List<PointF>();
                foreach (var spatialCoordinate in polyline.SpatialCoordinateCollection)
                    if (spatialCoordinate is aim_dotnet.TwoDimensionSpatialCoordinate)
                        points.Add(AimNativeConverter.AsPointF(spatialCoordinate));

                var markup = new TemplateTree.MarkupPolygonal();
                markup.Vertices = points;
                markup.Name = markupText;
                markup.IncludeInAnnotation = polyline.IsIncludeFlag;
                markup.CalloutLocation = markup.Vertices[0] - new SizeF(30, 30);
                SetMarkupImageReference(markup, polyline.SpatialCoordinateCollection[0]);

                return markup;
            }
            if (geometricShape is aim_dotnet.MultiPoint)
            {
                var multiPoint = (aim_dotnet.MultiPoint)geometricShape;

                TemplateTree.IMarkup markup;
                switch (multiPoint.SpatialCoordinateCollection.Count)
                {
                    case 2:
                        {
                            // Line
                            var markupLinear = new TemplateTree.MarkupLinear();
                            markupLinear.Vertices = new List<PointF>(2);
                            markupLinear.Vertices.Add(AimNativeConverter.AsPointF(multiPoint.SpatialCoordinateCollection[0]));
                            markupLinear.Vertices.Add(AimNativeConverter.AsPointF(multiPoint.SpatialCoordinateCollection[1]));
                            markupLinear.CalloutLocation = markupLinear.Vertices[0] - new SizeF(30, 30);
                            markup = markupLinear;
                        }
                        break;
                    case 3:
                        {
                            // Protractor
                            var markupProtractor = new TemplateTree.MarkupProtractor();
                            markupProtractor.Points = new List<PointF>(3);
                            markupProtractor.Points.Add(AimNativeConverter.AsPointF(multiPoint.SpatialCoordinateCollection[0]));
                            markupProtractor.Points.Add(AimNativeConverter.AsPointF(multiPoint.SpatialCoordinateCollection[1]));
                            markupProtractor.Points.Add(AimNativeConverter.AsPointF(multiPoint.SpatialCoordinateCollection[2]));
                            markupProtractor.CalloutLocation = markupProtractor.Points[0] - new SizeF(30, 30);
                            markup = markupProtractor;
                        }
                        break;
                    default:
                        throw new NotImplementedException("Reading non-linear or non-triangular MultiPoint shape is not implemented");
                }

                markup.Name = markupText;
                markup.IncludeInAnnotation = multiPoint.IsIncludeFlag;
                SetMarkupImageReference(markup, multiPoint.SpatialCoordinateCollection[0]);
                return markup;
            }

            throw new NotImplementedException();
            return null;
        }
        private string GetCharacteristicQuantificationHtml(aim_dotnet.ICharacteristicQuantification characteristicQuantification)
        {
            if (characteristicQuantification == null)
                return "";

            switch (characteristicQuantification.QuantificationType)
            {
                case aim_dotnet.CharacteristicQuantificationType.Numerical:
                    var numerical = (aim_dotnet.Numerical) characteristicQuantification;
                    return numerical.Operator == aim_dotnet.ComparisonOperatorIdentifier.InvalidComparisonOperator ||
                           numerical.Operator == aim_dotnet.ComparisonOperatorIdentifier.None
                           	? string.Format("{0} {1}", numerical.Value, numerical.UcumString)
                           	: string.Format("{0} {1} {2}", OperatorToString(numerical.Operator, true), numerical.Value, numerical.UcumString);
                case aim_dotnet.CharacteristicQuantificationType.Quantile:
                    var quantile = (aim_dotnet.Quantile) characteristicQuantification;
                    return string.Format("Quantile [{0}]", quantile.Bin);
                case aim_dotnet.CharacteristicQuantificationType.NonQuantifiable:
                    var nonQuantifiable = (aim_dotnet.NonQuantifiable) characteristicQuantification;
                    return nonQuantifiable.CodeMeaning ?? "";
                case aim_dotnet.CharacteristicQuantificationType.Scale:
                    var scale = (aim_dotnet.Scale) characteristicQuantification;
                    return scale.Value ?? "";
                case aim_dotnet.CharacteristicQuantificationType.Interval:
                    var interval = (aim_dotnet.Interval) characteristicQuantification;
                    {
                        var left = CombineOperatorAndValue(interval.MinOperator, interval.MinValue == double.MinValue ? "" : interval.MinValue.ToString(), true);
                        var right = CombineOperatorAndValue(interval.MaxOperator, interval.MaxValue == double.MaxValue ? "" : interval.MaxValue.ToString(), string.IsNullOrEmpty(left));

                        var sb = new StringBuilder();
                        sb.Append(left);
                        if (!string.IsNullOrEmpty(left) && !string.IsNullOrEmpty(right))
                            sb.Append(" and ");
                        sb.Append(right);
                        return sb.ToString();
                    }
                default:
                    Debug.Assert(false, "Unknown characteristic quantification type");
                    break;
            }
            return "";
        }
		// ====================================================================
		//
		//  Read and display annotation back
		//
		// ====================================================================

		public static bool ReadGraphicsFromAnnotation(aim_dotnet.Annotation annotation, IPresentationImage presentationImage)
		{
			bool hasNewRoiGraphic = false;

			IOverlayGraphicsProvider graphicsProvider = presentationImage as IOverlayGraphicsProvider;
			//IApplicationGraphicsProvider graphicsProvider = presentationImage as IApplicationGraphicsProvider;
			IImageSopProvider currentImageSOP = presentationImage as IImageSopProvider;
			if (graphicsProvider == null || currentImageSOP == null)
				return false;

			if (annotation is aim_dotnet.ImageAnnotation)
			{
				aim_dotnet.ImageAnnotation imgAnnotation = annotation as aim_dotnet.ImageAnnotation;
				if (imgAnnotation.GeometricShapeCollection != null)
				{
					foreach (aim_dotnet.IGeometricShape geoShape in imgAnnotation.GeometricShapeCollection)
					{
						// Check if the image is the one on which the annotation was originally drawn
						if (GetImageSOPInstanceUID(geoShape) != currentImageSOP.ImageSop.SopInstanceUid)
							break;

						// Prevent from adding the same annotation again
						bool isAlreadyDisplayed = false;
						foreach (IGraphic graphic in graphicsProvider.OverlayGraphics)
						{
							AimGraphic aimGraphic = graphic as AimGraphic;
							isAlreadyDisplayed = aimGraphic != null && aimGraphic.AimAnnotation.UniqueIdentifier == imgAnnotation.UniqueIdentifier &&
							                     aimGraphic.ShapeIdentifier == geoShape.ShapeIdetifier;
							if (isAlreadyDisplayed)
								break;
						}
						if (isAlreadyDisplayed)
							continue;

						//hasNewRoiGraphic = AddRoiGraphic(geoShape, graphicsProvider) || hasNewRoiGraphic;
						RoiGraphic roiGraphic = GeoShapeToRoiGraphic(geoShape);
						if (roiGraphic != null)
						{
							AimGraphic aimGraphic = new AimGraphic(roiGraphic, imgAnnotation, geoShape.ShapeIdetifier);
							if (!String.IsNullOrEmpty(imgAnnotation.Name))
								roiGraphic.Name = imgAnnotation.Name;
							aimGraphic.Color = Color.SlateBlue;
							graphicsProvider.OverlayGraphics.Add(aimGraphic);
						}

						hasNewRoiGraphic |= roiGraphic == null;
					}
				}
			}

			return hasNewRoiGraphic;
		}
        // ====================================================================
        //
        //  Read and display annotation back
        //
        // ====================================================================
        public static bool ReadGraphicsFromAnnotation(aim_dotnet.Annotation annotation, IPresentationImage presentationImage)
        {
            var hasNewRoiGraphic = false;

            var graphicsProvider = presentationImage as IOverlayGraphicsProvider;
            var currentImageSOP = presentationImage as IImageSopProvider;
            if (graphicsProvider == null || currentImageSOP == null)
                return false;

            if (annotation is aim_dotnet.ImageAnnotation)
            {
                var imgAnnotation = annotation as aim_dotnet.ImageAnnotation;
                if (imgAnnotation.GeometricShapeCollection != null)
                {
                    foreach (var geoShape in imgAnnotation.GeometricShapeCollection)
                    {
                        if (GetImageSOPInstanceUID(geoShape) != currentImageSOP.ImageSop.SopInstanceUid)
                            continue;

                        var isAlreadyDisplayed = false;
                        foreach (var graphic in graphicsProvider.OverlayGraphics)
                        {
                            var aimGraphic = graphic as AimGraphic;
                            isAlreadyDisplayed = aimGraphic != null && aimGraphic.AimAnnotation.UniqueIdentifier == imgAnnotation.UniqueIdentifier &&
                                                 aimGraphic.ShapeIdentifier == geoShape.ShapeIdetifier;
                            if (isAlreadyDisplayed)
                                break;
                        }
                        if (isAlreadyDisplayed)
                            continue;

                        var geoGraphic = GeoShapeToGraphic(geoShape, string.IsNullOrEmpty(imgAnnotation.Name) ? string.Empty : imgAnnotation.Name);
                        if (geoGraphic != null)
                        {
                            var aimGraphic = new AimGraphic(geoGraphic, imgAnnotation, geoShape.ShapeIdetifier);
                            aimGraphic.Color = AimSettings.Default.GetAimGraphicColorForUser(aimGraphic.UserLoginName);
                            graphicsProvider.OverlayGraphics.Add(aimGraphic);
                        }

                        hasNewRoiGraphic |= geoGraphic != null;
                    }
                }
                if (imgAnnotation.TextAnnotationCollection != null)
                {
                    foreach (var textAnnotation in imgAnnotation.TextAnnotationCollection)
                    {
                        if (textAnnotation.ConnectorPoints == null)
                            continue;
                        if (GetImageSOPInstanceUID(textAnnotation.ConnectorPoints) != currentImageSOP.ImageSop.SopInstanceUid)
                            continue;

                        var isAlreadyDisplayed = false;
                        foreach (var graphic in graphicsProvider.OverlayGraphics)
                        {
                            var aimGraphic = graphic as AimGraphic;
                            isAlreadyDisplayed = aimGraphic != null && aimGraphic.AimAnnotation.UniqueIdentifier == imgAnnotation.UniqueIdentifier &&
                                                 aimGraphic.ShapeIdentifier == textAnnotation.ConnectorPoints.ShapeIdetifier;
                            if (isAlreadyDisplayed)
                                break;
                        }
                        if (isAlreadyDisplayed)
                            continue;

                        var textGraphic = TextAnnotationToGraphic(textAnnotation, string.IsNullOrEmpty(imgAnnotation.Name) ? string.Empty : imgAnnotation.Name);
                        if (textGraphic != null)
                        {
                            var aimGraphic = new AimGraphic(textGraphic, imgAnnotation, textAnnotation.ConnectorPoints.ShapeIdetifier);
                            aimGraphic.Color = Color.SlateBlue;
                            graphicsProvider.OverlayGraphics.Add(aimGraphic);
                        }
                        hasNewRoiGraphic |= textGraphic != null;
                    }
                }
            }

            return hasNewRoiGraphic;
        }
		private static RoiGraphic GeoShapeToRoiGraphic(aim_dotnet.IGeometricShape geoShape)
		{
			RoiGraphic roiGraphic = null;

			if (geoShape.SpatialCoordinateCollection == null || geoShape.SpatialCoordinateCollection.Count == 0)
				return null;

			if (geoShape is aim_dotnet.Circle)
			{
				// Ellipse
				aim_dotnet.Circle shapeCircle = geoShape as aim_dotnet.Circle;
				PointF centerPt = AsPointF(shapeCircle.Center);
				PointF radiusPt = AsPointF(shapeCircle.RadiusPoint);
				double radiusLength = Vector.Distance(centerPt, radiusPt);
				roiGraphic = RoiGraphic.CreateEllipse();
				BoundableGraphic boundableGraphic = roiGraphic.Subject as BoundableGraphic;
				if (boundableGraphic != null)
				{
					roiGraphic.Suspend(); // prevent callout location calculation untill all points are set
					boundableGraphic.TopLeft = new PointF((float) (centerPt.X - radiusLength), (float) (centerPt.Y - radiusLength));
					boundableGraphic.BottomRight = new PointF((float) (centerPt.X + radiusLength), (float) (centerPt.Y + radiusLength));
					roiGraphic.Resume(true); // Force callout location calculation
				}
			}
			else if (geoShape is aim_dotnet.Ellipse)
			{
				// Ellipse
				aim_dotnet.Ellipse shapeEllipse = geoShape as aim_dotnet.Ellipse;
				PointF firstMajorAxisPt = AsPointF(shapeEllipse.EllipseCollection[0]);
				PointF secondMajorAxisPt = AsPointF(shapeEllipse.EllipseCollection[1]);
				PointF firstMinorAxisPt = AsPointF(shapeEllipse.EllipseCollection[2]);
				PointF secondMinorAxisPt = AsPointF(shapeEllipse.EllipseCollection[3]);

				roiGraphic = RoiGraphic.CreateEllipse();
				BoundableGraphic boundableGraphic = roiGraphic.Subject as BoundableGraphic;
				if (boundableGraphic != null)
				{
					roiGraphic.Suspend(); // prevent callout location calculation untill all points are set
					boundableGraphic.TopLeft = new PointF(firstMajorAxisPt.X, firstMinorAxisPt.Y);
					boundableGraphic.BottomRight = new PointF(secondMajorAxisPt.X, secondMinorAxisPt.Y);
					roiGraphic.Resume(true); // Force callout location calculation
				}
			}
			else if (geoShape is aim_dotnet.Point)
			{
				throw new NotImplementedException("Reading Point shape is not implemented");
			}
			else if (geoShape is aim_dotnet.MultiPoint)
			{
				// How this case works:
				// If we have 2 points, it's a line
				// If we have 3 points, it's a protractor
				// All others - unknown unclosed object (not supported)

				aim_dotnet.MultiPoint shapeMultiPoint = geoShape as aim_dotnet.MultiPoint;
				switch (shapeMultiPoint.SpatialCoordinateCollection.Count)
				{
					case 2:
						{
							// Line
							VerticesControlGraphic interactiveGraphic = new VerticesControlGraphic(new MoveControlGraphic(new PolylineGraphic()));
							PointF firstPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[0]);
							PointF secondPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[1]);
							interactiveGraphic.Subject.Points.Add(firstPt);
							interactiveGraphic.Subject.Points.Add(secondPt);

							roiGraphic = CreateRoiGraphic(interactiveGraphic, null);
							roiGraphic.Resume(true); // Force callout location calculation
						}
						break;
					case 3:
						{
							// Protractor
							VerticesControlGraphic interactiveGraphic = new VerticesControlGraphic(new MoveControlGraphic(new ProtractorGraphic()));
							PointF firstPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[0]);
							PointF secondPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[1]);
							PointF thirdPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[2]);
							interactiveGraphic.Subject.Points.Add(firstPt);
							interactiveGraphic.Subject.Points.Add(secondPt);
							interactiveGraphic.Subject.Points.Add(thirdPt);

							roiGraphic = CreateRoiGraphic(interactiveGraphic, new ProtractorRoiCalloutLocationStrategy());
							roiGraphic.Resume(true); // Force callout location calculation
						}
						break;
					default:
						throw new NotImplementedException("Reading non-linear or non-triangular MultiPoint shape is not implemented");
				}
			}
			else if (geoShape is aim_dotnet.Polyline)
			{
				aim_dotnet.Polyline shapePolyline = geoShape as aim_dotnet.Polyline;

				bool isRectangle = false; // true - if we have CC's rectangle coordinates
				// Check if this is a non-rotated rectangle
				if (shapePolyline.SpatialCoordinateCollection.Count == 4)
				{
					PointF twoDPoint1 = AsPointF(shapePolyline.SpatialCoordinateCollection[0]);
					PointF twoDPoint2 = AsPointF(shapePolyline.SpatialCoordinateCollection[1]);
					PointF twoDPoint3 = AsPointF(shapePolyline.SpatialCoordinateCollection[2]);
					PointF twoDPoint4 = AsPointF(shapePolyline.SpatialCoordinateCollection[3]);
					// If it's a rectangle with sides parallel to the axes
					if ((twoDPoint1.X == twoDPoint2.X && twoDPoint2.Y == twoDPoint3.Y && twoDPoint3.X == twoDPoint4.X && twoDPoint4.Y == twoDPoint1.Y) ||
					    (twoDPoint1.Y == twoDPoint2.Y && twoDPoint2.X == twoDPoint3.X && twoDPoint3.Y == twoDPoint4.Y && twoDPoint4.X == twoDPoint1.X))
					{
						isRectangle = true;

						roiGraphic = RoiGraphic.CreateRectangle();
						BoundableGraphic boundableGraphic = roiGraphic.Subject as BoundableGraphic;
						if (boundableGraphic != null)
						{
							roiGraphic.Suspend(); // prevent callout location calculation untill all points are set
							// Assume that the points are in order and start at the top left corner.
							boundableGraphic.TopLeft = twoDPoint1;
							boundableGraphic.BottomRight = twoDPoint3;

							roiGraphic.Resume(true); // Force callout location calculation
						}
					}
				}
				// It's a CC's polygon if it's not a rectangle
				if (!isRectangle)
				{
					roiGraphic = RoiGraphic.CreatePolygon();
					PolylineGraphic polylineGraphic = roiGraphic.Subject as PolylineGraphic;
					if (polylineGraphic != null)
					{
						roiGraphic.Suspend();
						for (int i = 0; i < shapePolyline.SpatialCoordinateCollection.Count; i++)
						{
							PointF twoDPoint = AsPointF(shapePolyline.SpatialCoordinateCollection[i]);
							polylineGraphic.Points.Add(twoDPoint);
						}
						// We deal with closed polygons only
						if (polylineGraphic.Points.Count > 0)
							polylineGraphic.Points.Add(polylineGraphic.Points[0]);
						roiGraphic.Resume(true); // Force callout location calculation
					}
				}
			}
			else
				throw new Exception("Unknown shape type encountered: " + geoShape.GetType().FullName);

			return roiGraphic;
		}
        private static bool AddDicomImageReference(aim_dotnet.ImageAnnotation imageAnnotation, IImageSopProvider image)
        {
            Platform.CheckForNullReference(imageAnnotation, "ImageAnnotation");
            if (imageAnnotation.ImageReferenceCollection == null)
                imageAnnotation.ImageReferenceCollection = new List<aim_dotnet.ImageReference>();
            var imageReferences = imageAnnotation.ImageReferenceCollection;
            aim_dotnet.ImageStudy aimImageStudy = null;
            foreach (var imgRef in imageReferences)
            {
                var dicomImgRef = imgRef as aim_dotnet.DICOMImageReference;
                if (dicomImgRef != null)
                {
                    if (dicomImgRef.Study.InstanceUID == image.ImageSop.StudyInstanceUid &&
                        dicomImgRef.Study.Series.InstanceUID == image.ImageSop.SeriesInstanceUid)
                        aimImageStudy = dicomImgRef.Study;
                }
            }
            if (aimImageStudy == null)
            {
                aimImageStudy = CreateStudy(image);
                aimImageStudy.Series = CreateSeries(image);
                aimImageStudy.Series.ImageCollection = new List<aim_dotnet.Image>();
                var dicomImgRef = new aim_dotnet.DICOMImageReference();
                dicomImgRef.Study = aimImageStudy;
                imageReferences.Add(dicomImgRef);
            }
            foreach (var existingImage in aimImageStudy.Series.ImageCollection)
            {
                if (existingImage.SopInstanceUID == image.ImageSop.SopInstanceUid)
                    return false;
            }
            var aimImage = CreateImage(image);
            aimImageStudy.Series.ImageCollection.Add(aimImage);

            return true;
        }
        internal string WriteXmlAnnotationToString(aim_dotnet.Annotation annotation)
        {
            try
            {
                return Model.WriteAnnotationToXmlString(annotation);
            }
            catch (Exception ex)
            {
                Platform.Log(LogLevel.Error, ex, "Failed to convert annotation to xml.");
            }

            return null;
        }
        private static IGraphic GeoShapeToGraphic(aim_dotnet.IGeometricShape geoShape, string shapeLabel)
        {
            if (geoShape.SpatialCoordinateCollection == null || geoShape.SpatialCoordinateCollection.Count == 0)
                return null;

            IGraphic graphic = null;
            if (geoShape is aim_dotnet.Circle)
            {
                // Ellipse
                var shapeCircle = geoShape as aim_dotnet.Circle;
                var centerPt = AsPointF(shapeCircle.Center);
                var radiusPt = AsPointF(shapeCircle.RadiusPoint);
                var radiusLength = Vector.Distance(centerPt, radiusPt);
                RoiGraphic roiGraphic = AimRoiGraphic.CreateEllipse();
                var boundableGraphic = roiGraphic.Subject as BoundableGraphic;
                if (boundableGraphic != null)
                {
                    roiGraphic.Suspend();
                    roiGraphic.Name = shapeLabel;
                    boundableGraphic.TopLeft = new PointF((float) (centerPt.X - radiusLength), (float) (centerPt.Y - radiusLength));
                    boundableGraphic.BottomRight = new PointF((float) (centerPt.X + radiusLength), (float) (centerPt.Y + radiusLength));
                    roiGraphic.Resume(true);
                }
                graphic = roiGraphic;
            }
            else if (geoShape is aim_dotnet.Ellipse)
            {
                // Ellipse
                var shapeEllipse = geoShape as aim_dotnet.Ellipse;
                var firstMajorAxisPt = AsPointF(shapeEllipse.EllipseCollection[0]);
                var secondMajorAxisPt = AsPointF(shapeEllipse.EllipseCollection[1]);
                var firstMinorAxisPt = AsPointF(shapeEllipse.EllipseCollection[2]);
                var secondMinorAxisPt = AsPointF(shapeEllipse.EllipseCollection[3]);
                RoiGraphic roiGraphic = AimRoiGraphic.CreateEllipse();
                var boundableGraphic = roiGraphic.Subject as BoundableGraphic;
                if (boundableGraphic != null)
                {
                    roiGraphic.Suspend();
                    roiGraphic.Name = shapeLabel;
                    boundableGraphic.TopLeft = new PointF(firstMajorAxisPt.X, firstMinorAxisPt.Y);
                    boundableGraphic.BottomRight = new PointF(secondMajorAxisPt.X, secondMinorAxisPt.Y);
                    roiGraphic.Resume(true);
                }
                graphic = roiGraphic;
            }
            else if (geoShape is aim_dotnet.Point)
            {
                var shapePoint = geoShape as aim_dotnet.Point;
                var callout = new CalloutGraphic(shapeLabel);
                callout.LineStyle = LineStyle.Solid;
                callout.ShowArrowhead = true;
                callout.AnchorPoint = AsPointF(shapePoint.Center);
                callout.TextLocation = callout.AnchorPoint - new SizeF(30, 30);
                var statefulGraphic = new StandardStatefulGraphic(callout);
                statefulGraphic.State = statefulGraphic.CreateInactiveState();
                graphic = statefulGraphic;
            }
            else if (geoShape is aim_dotnet.MultiPoint)
            {
                // How this case works:
                // If we have 2 points, it's a line
                // If we have 3 points, it's a protractor
                // All others - unknown unclosed object (not supported)
                var shapeMultiPoint = geoShape as aim_dotnet.MultiPoint;
                switch (shapeMultiPoint.SpatialCoordinateCollection.Count)
                {
                    case 2:
                        {
                            // Line
                            var interactiveGraphic = new VerticesControlGraphic(new MoveControlGraphic(new PolylineGraphic()));
                            var firstPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[0]);
                            var secondPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[1]);
                            interactiveGraphic.Subject.Points.Add(firstPt);
                            interactiveGraphic.Subject.Points.Add(secondPt);
                            var roiGraphic = CreateRoiGraphic(interactiveGraphic, null);
                            roiGraphic.Name = shapeLabel;
                            roiGraphic.Resume(true);
                            graphic = roiGraphic;
                        }
                        break;
                    case 3:
                        {
                            // Protractor
                            var interactiveGraphic = new VerticesControlGraphic(new MoveControlGraphic(new ProtractorGraphic()));
                            var firstPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[0]);
                            var secondPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[1]);
                            var thirdPt = AsPointF(shapeMultiPoint.SpatialCoordinateCollection[2]);
                            interactiveGraphic.Subject.Points.Add(firstPt);
                            interactiveGraphic.Subject.Points.Add(secondPt);
                            interactiveGraphic.Subject.Points.Add(thirdPt);
                            var roiGraphic = CreateRoiGraphic(interactiveGraphic,  new ProtractorRoiCalloutLocationStrategy());
                            roiGraphic.Name = shapeLabel;
                            roiGraphic.Resume(true);
                            graphic = roiGraphic;
                        }
                        break;
                    default:
                        throw new NotImplementedException("Reading non-linear or non-triangular MultiPoint shape is not implemented");
                }
            }
            else if (geoShape is aim_dotnet.Polyline)
            {
                var shapePolyline = geoShape as aim_dotnet.Polyline;
                var isRectangle = false;
                if (shapePolyline.SpatialCoordinateCollection.Count == 4)
                {
                    var twoDPoint1 = AsPointF(shapePolyline.SpatialCoordinateCollection[0]);
                    var twoDPoint2 = AsPointF(shapePolyline.SpatialCoordinateCollection[1]);
                    var twoDPoint3 = AsPointF(shapePolyline.SpatialCoordinateCollection[2]);
                    var twoDPoint4 = AsPointF(shapePolyline.SpatialCoordinateCollection[3]);
                    if ((twoDPoint1.X == twoDPoint2.X && twoDPoint2.Y == twoDPoint3.Y && twoDPoint3.X == twoDPoint4.X && twoDPoint4.Y == twoDPoint1.Y) ||
                        (twoDPoint1.Y == twoDPoint2.Y && twoDPoint2.X == twoDPoint3.X && twoDPoint3.Y == twoDPoint4.Y && twoDPoint4.X == twoDPoint1.X))
                    {
                        isRectangle = true;

                        RoiGraphic roiGraphic = AimRoiGraphic.CreateRectangle();
                        var boundableGraphic = roiGraphic.Subject as BoundableGraphic;
                        if (boundableGraphic != null)
                        {
                            roiGraphic.Suspend();
                            roiGraphic.Name = shapeLabel;
                            boundableGraphic.TopLeft = twoDPoint1;
                            boundableGraphic.BottomRight = twoDPoint3;
                            roiGraphic.Resume(true);
                        }

                        graphic = roiGraphic;
                    }
                }
                if (!isRectangle)
                {
                    RoiGraphic roiGraphic = AimRoiGraphic.CreatePolygon();
                    var polylineGraphic = roiGraphic.Subject as PolylineGraphic;
                    if (polylineGraphic != null)
                    {
                        roiGraphic.Suspend();
                        for (var i = 0; i < shapePolyline.SpatialCoordinateCollection.Count; i++)
                        {
                            var twoDPoint = AsPointF(shapePolyline.SpatialCoordinateCollection[i]);
                            polylineGraphic.Points.Add(twoDPoint);
                        }
                        // We deal with closed polygons only
                        if (polylineGraphic.Points.Count > 0)
                            polylineGraphic.Points.Add(polylineGraphic.Points[0]);
                        roiGraphic.Name = shapeLabel;
                        roiGraphic.Resume(true);
                    }

                    graphic = roiGraphic;
                }
            }
            else
                throw new Exception("Unknown shape type encountered: " + geoShape.GetType().FullName);

            return graphic;
        }
        private string ToolTipTextFromAimAnnotation(aim_dotnet.Annotation annotation)
        {
            var toolTipText = String.Empty;
            toolTipText += annotation.Name + "\n";
            toolTipText += annotation.DateTime.ToString() + "\n";
            toolTipText += annotation.CodeValue + "\n";
            toolTipText += annotation.CodeMeaning += "\n";
            toolTipText += annotation.Comment;

            return toolTipText;
        }
        private static IGraphic TextAnnotationToGraphic(aim_dotnet.TextAnnotation textAnnotation, string shapeLabel)
        {
            Platform.CheckForNullReference(textAnnotation.ConnectorPoints, "ConnectorPoints");
            Platform.CheckForNullReference(textAnnotation.ConnectorPoints.SpatialCoordinateCollection, "SpatialCoordinateCollection");
            Platform.CheckArgumentRange(textAnnotation.ConnectorPoints.SpatialCoordinateCollection.Count, 1, 2, "SpatialCoordinateCollection");

            if (textAnnotation.ConnectorPoints == null || textAnnotation.ConnectorPoints.SpatialCoordinateCollection == null)
                return null;

            var graphicText = shapeLabel.Trim();
            graphicText = string.IsNullOrEmpty(graphicText)
                          	? textAnnotation.Text.Trim()
                          	: string.Format("{0}:\r\n{1}", graphicText, textAnnotation.Text.Trim());
            switch (textAnnotation.ConnectorPoints.SpatialCoordinateCollection.Count)
            {
                case 1:
                    {
                        var textPrimitive = new InvariantTextPrimitive(graphicText);
                        textPrimitive.Location = AsPointF(textAnnotation.ConnectorPoints.SpatialCoordinateCollection[0]);
                        var statefulGraphic = new StandardStatefulGraphic(textPrimitive);
                        statefulGraphic.State = statefulGraphic.CreateInactiveState();
                        return statefulGraphic;
                    }
                    break;
                case 2:
                    {
                        var callout = new CalloutGraphic(graphicText);
                        callout.LineStyle = LineStyle.Solid;
                        callout.ShowArrowhead = true;
                        callout.AnchorPoint = AsPointF(textAnnotation.ConnectorPoints.SpatialCoordinateCollection[0]);
                        callout.TextLocation = AsPointF(textAnnotation.ConnectorPoints.SpatialCoordinateCollection[1]);
                        var statefulGraphic = new StandardStatefulGraphic(callout);
                        statefulGraphic.State = statefulGraphic.CreateInactiveState();
                        return statefulGraphic;
                    }
                    break;
                default:
                    break;
            }
            return null;
        }
        private static string GetImageAnnotationHtml(aim_dotnet.ImageAnnotation imageAnnotation)
        {
            StringBuilder sb = new StringBuilder();
            AimHtmlFormatter htmlFormatter = new AimHtmlFormatter();

            Color ctrlColor = Color.FromKnownColor(KnownColor.Control);
            Color fontColor = Color.FromKnownColor(KnownColor.WindowText);

            sb.Append(HtmlDocHeader);
            sb.AppendFormat("<body style=\"background-color: #{0}{1}{2};\" onload=\"setupPaths(['{3}', '{4}'])\">",
                ctrlColor.R.ToString("X2"), ctrlColor.G.ToString("X2"), ctrlColor.B.ToString("X2"),
                MinusImagePathName, PlusImagePathName);
            sb.Append("<div id=\"main_content\">");
            sb.AppendFormat("<div><b>Name: {0}</b></div>", imageAnnotation.Name);
            sb.AppendFormat("<div>Number of Markups: {0}</div>", imageAnnotation.GeometricShapeCollection == null ? 0 : imageAnnotation.GeometricShapeCollection.Count(geoShape => geoShape != null));
            if (imageAnnotation.User != null)
                sb.AppendFormat("<div>Created by: {0}</div>", imageAnnotation.User.Name);
            sb.Append(htmlFormatter.GetAnatomicEntitiesHtml(imageAnnotation.AnatomyEntityCollection));
            sb.Append(htmlFormatter.GetImagingObservationHtml(imageAnnotation.ImagingObservationCollection));
            // TODO - append other sections
            sb.Append("</div>");
            sb.Append("</body>");
            sb.Append("</html>");

            return sb.ToString();
        }