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;
        }
        public static TemplateTree.AimTemplateTree AimAnnotationToAimTemplateTree(Aim3AnnotationInstance annotationInstance, TemplateTree.AimTemplateTree template)
        {
            if (annotationInstance == null || annotationInstance.AimAnnotation == null)
                return null;

            var annotation = annotationInstance.AimAnnotation;
            if (annotation.AnatomyEntityCollection != null)
            {
                foreach (var ae in annotation.AnatomyEntityCollection)
                {
                    if (IsNullCodeSequence(ToStandardCodeSequence(ae)))
                        continue;

                    TemplateTree.AimTemplateTreeAnatomicEntityNode matchingTreeNode =
                        template.TemplateNodes.OfType<TemplateTree.AimTemplateTreeAnatomicEntityNode>().FirstOrDefault(treeAe => treeAe.Label == ae.Label);
                    if (matchingTreeNode != null)
                    {
                        TemplateTree.AimTemplateTreeAllowedTerm matchingAllowedTerm =
                            matchingTreeNode.AllowedTerms.FirstOrDefault(treeAe => ToStandardCodeSequence(treeAe).CodeValue == ae.CodeValue);
                        if (matchingAllowedTerm != null)
                        {
                            matchingAllowedTerm.Selected = true;
                        }
                        else
                            return null;

                        if (matchingTreeNode.HasConfidence && ae.AnnotatorConfidence.HasValue)
                            matchingTreeNode.ConfidenceValue = ae.AnnotatorConfidence.Value;
                    }
                    else
                        return null;

                    if (ae.AnatomicEntityCharacteristicCollection != null)
                    {
                        foreach (var aec in ae.AnatomicEntityCharacteristicCollection)
                        {
                            if (IsNullCodeSequence(ToStandardCodeSequence(aec)))
                                continue;

                            TemplateTree.AimTemplateTreeAnatomicEntityCharacteristicNode matchingAecTreeNode =
                                matchingTreeNode.AnatomicEntityCharacteristicTreeNodes.FirstOrDefault(treeAec => treeAec.Label == aec.Label);
                            if (matchingAecTreeNode != null)
                            {
                                TemplateTree.CharacteristicQuantificationAllowedTerm matchingAllowedTerm =
                                    matchingAecTreeNode.CharacteristicQuantificationAllowedTerms.FirstOrDefault(treeAec => ToStandardCodeSequence(treeAec).CodeValue == aec.CodeValue);
                                if (matchingAllowedTerm != null)
                                {
                                    matchingAllowedTerm.Selected = true;

                                    foreach (var quantification in matchingAllowedTerm.CharacteristicQuantifications)
                                    {
                                        if (ReadBackCharacteristicQuantificationFromAnnotation(aec.CharacteristicQuantificationCollection, quantification) == null)
                                            return null;
                                    }
                                }
                                else
                                    return null;

                                if (matchingAecTreeNode.HasConfidence && aec.AnnotatorConfidence.HasValue)
                                    matchingAecTreeNode.ConfidenceValue = aec.AnnotatorConfidence.Value;

                            }
                            else
                                return null;
                        }
                    }

                }
            }
            if (annotation.ImagingObservationCollection != null)
            {
                foreach (var io in annotation.ImagingObservationCollection)
                {
                    if (IsNullCodeSequence(ToStandardCodeSequence(io)))
                        continue;

                    TemplateTree.AimTemplateTreeImagingObservationNode matchingTreeNode =
                        template.TemplateNodes.OfType<TemplateTree.AimTemplateTreeImagingObservationNode>().FirstOrDefault(
                            treeIo => treeIo.Label == io.Label);
                    if (matchingTreeNode != null)
                    {
                        TemplateTree.AimTemplateTreeAllowedTerm matchingAllowedTerm =
                            matchingTreeNode.AllowedTerms.FirstOrDefault(
                                treeIo => ToStandardCodeSequence(treeIo).CodeValue == io.CodeValue);
                        if (matchingAllowedTerm != null)
                        {
                            matchingAllowedTerm.Selected = true;
                        }
                        else
                            return null;

                        if (matchingTreeNode.HasConfidence && io.AnnotatorConfidence.HasValue)
                            matchingTreeNode.ConfidenceValue = io.AnnotatorConfidence.Value;
                    }
                    else
                        return null;

                    if (io.ImagingObservationCharacteristicCollection != null)
                    {
                        foreach (var ioc in io.ImagingObservationCharacteristicCollection)
                        {
                            if (IsNullCodeSequence(ToStandardCodeSequence(ioc)))
                                continue;

                            TemplateTree.AimTemplateTreeImagingObservationCharacteristicNode matchingIocTreeNode =
                                matchingTreeNode.ImagingObservationCharacteristicTreeNodes.FirstOrDefault(
                                    treeIoc => treeIoc.Label == ioc.Label);
                            if (matchingIocTreeNode != null)
                            {
                                TemplateTree.CharacteristicQuantificationAllowedTerm matchingAllowedTerm =
                                    matchingIocTreeNode.CharacteristicQuantificationAllowedTerms.FirstOrDefault(
                                        treeIoc => ToStandardCodeSequence(treeIoc).CodeValue == ioc.CodeValue);
                                if (matchingAllowedTerm != null)
                                {
                                    matchingAllowedTerm.Selected = true;

                                    foreach (var quantification in matchingAllowedTerm.CharacteristicQuantifications)
                                    {
                                        if (ReadBackCharacteristicQuantificationFromAnnotation(ioc.CharacteristicQuantificationCollection, quantification) == null)
                                            return null;
                                    }
                                }
                                else
                                    return null;

                                if (matchingIocTreeNode.HasConfidence && ioc.AnnotatorConfidence.HasValue)
                                    matchingIocTreeNode.ConfidenceValue = ioc.AnnotatorConfidence.Value;

                            }
                            else
                                return null;
                        }
                    }
                }
            }
            if (annotation.CalculationCollection != null)
            {
                //foreach (var calc in annotation.CalculationCollection)
                //{
                //    AimTemplateTreeCalculationNode matchingTreeNode =
                //        template.TemplateNodes.OfType<AimTemplateTreeCalculationNode>().FirstOrDefault(
                //            treeCalc => treeCalc.Label == calc.Description);
                //    if (matchingTreeNode != null)
                //    {
                //        AimTemplateTreeCalculationType matchingCalculationType =
                //            matchingTreeNode.CalculationTypes.FirstOrDefault(
                //                treeCalc => ToStandardCodeSequence(treeCalc).CodeValue == calc.CodeValue);
                //        if (matchingCalculationType != null)
                //        {
                //            matchingTreeNode.SelectedCalculationType = matchingCalculationType;
                //        }
                //        else
                //            return null;

                //        //if (matchingTreeNode.HasConfidence && calc..HasValue)
                //        //    matchingTreeNode.ConfidenceValue = calc.AnnotatorConfidence.Value;
                //    }
                //    else
                //        return null;
                //}
            }
            if (annotation.InferenceCollection != null)
            {
                foreach (var inference in annotation.InferenceCollection)
                {
                    if (IsNullCodeSequence(ToStandardCodeSequence(inference)))
                        continue;

                    foreach (var inferenceNode in template.TemplateNodes.OfType<TemplateTree.AimTemplateTreeInferenceNode>())
                    {
                        TemplateTree.AimTemplateTreeAllowedTerm matchingAllowedTerm =
                            inferenceNode.AllowedTerms.FirstOrDefault(
                                term => ToStandardCodeSequence(term).CodeValue == inference.CodeValue);
                        if (matchingAllowedTerm != null)
                            matchingAllowedTerm.Selected = true;
                    }
                }
            }
            template.Markup.Clear();
            if (annotation is aim_dotnet.ImageAnnotation)
            {
                var imageAnnotation = (aim_dotnet.ImageAnnotation)annotation;
                var annotationName = string.IsNullOrEmpty(imageAnnotation.Name) ? "" : imageAnnotation.Name;

                if (imageAnnotation.GeometricShapeCollection != null)
                {
                    foreach (var geometricShape in imageAnnotation.GeometricShapeCollection)
                    {
                        var markup = ToMarkup(geometricShape, annotationName);
                        if (markup != null)
                            template.Markup.Add(markup);
                    }
                }
                if (imageAnnotation.TextAnnotationCollection != null)
                {
                    foreach (var textAnnotation in imageAnnotation.TextAnnotationCollection)
                    {
                        if (textAnnotation.ConnectorPoints != null && textAnnotation.ConnectorPoints.SpatialCoordinateCollection != null)
                        {
                            var calloutText = AimHelpers.FormatPointCalloutText(annotationName, textAnnotation.Text);
                            switch (textAnnotation.ConnectorPoints.SpatialCoordinateCollection.Count)
                            {
                                case 1:
                                    {
                                        var markup = new TemplateTree.MarkupPoint();
                                        markup.Name = annotationName;
                                        markup.IncludeInAnnotation = textAnnotation.ConnectorPoints.IsIncludeFlag;
                                        markup.Point = AimNativeConverter.AsPointF(textAnnotation.ConnectorPoints.SpatialCoordinateCollection[0]);
                                        markup.CalloutText = calloutText;
                                        markup.CalloutLocation = new PointF(markup.Point.X, markup.Point.Y);
                                        SetMarkupImageReference(markup, textAnnotation.ConnectorPoints.SpatialCoordinateCollection[0]);
                                        markup.UseCrosshair = AimSettings.Default.UseCrosshairsForTextCallouts;
                                        template.Markup.Add(markup);
                                    }
                                    break;
                                case 2:
                                    {
                                        var markup = new TemplateTree.MarkupPoint();
                                        markup.Name = annotationName;
                                        markup.IncludeInAnnotation = textAnnotation.ConnectorPoints.IsIncludeFlag;
                                        markup.Point = AimNativeConverter.AsPointF(textAnnotation.ConnectorPoints.SpatialCoordinateCollection[0]);
                                        markup.CalloutText = calloutText;
                                        markup.CalloutLocation = AimNativeConverter.AsPointF(textAnnotation.ConnectorPoints.SpatialCoordinateCollection[1]);
                                        SetMarkupImageReference(markup, textAnnotation.ConnectorPoints.SpatialCoordinateCollection[0]);
                                        markup.UseCrosshair = AimSettings.Default.UseCrosshairsForTextCallouts;
                                        template.Markup.Add(markup);
                                    }
                                    break;
                                default:
                                    Platform.Log(LogLevel.Error, "TextAnnotation has [{0}] Connector Points", textAnnotation.ConnectorPoints.SpatialCoordinateCollection.Count);
                                    break;
                            }
                        }
                    }
                }
            }
            return template;
        }