LEADTOOLS Medical (Leadtools.MedicalViewer assembly)

MedicalViewerCustomAnnotationRequestedObject Enumeration

Show in webframe





Represents the enumeration that will be sent through the MedicalViewerBaseCell.CustomAnnotationDataRequested to the custom annotation object, run designer, or edit designer.
Syntax
public enum MedicalViewerCustomAnnotationRequestedObject : System.Enum, System.IComparableSystem.IConvertibleSystem.IFormattable  
'Declaration
 
Public Enum MedicalViewerCustomAnnotationRequestedObject 
   Inherits System.Enum
   Implements System.IComparableSystem.IConvertibleSystem.IFormattable 

            

            
public enum class MedicalViewerCustomAnnotationRequestedObject : public System.Enum, System.IComparableSystem.IConvertibleSystem.IFormattable  
Members
ValueMemberDescription
0x00000000EditDesignerThe request is a new instance of the custom annotation edit designer.
0x00000001DrawDesignerThe request is a new instance of the custom annotation run designer.
0x00000002AnnotationObjectThe request is a new instance of the custom annotation object.
Remarks

The annotation as custom must be declared before registering the MedicalViewerBaseCell.CustomAnnotationDataRequested event.

For more information on how to create a custom annotation, refer to the MedicalViewerBaseCell.CustomAnnotationDataRequested event.

Example
        Imports Leadtools
        Imports Leadtools.Drawing
        Imports Leadtools.Codecs
        Imports Leadtools.MedicalViewer
        Imports Leadtools.ImageProcessing
        Imports Leadtools.Annotations

        Private Class MedicalViewerCustomAnnotationForm : Inherits Form
            Private _medicalViewer As MedicalViewer
            Private Sub MedicalViewerForm_SizeChanged(ByVal sender As Object, ByVal e As EventArgs)
                _medicalViewer.Size = New Size(Me.ClientRectangle.Right, Me.ClientRectangle.Bottom)
            End Sub

            Public Sub New()
                Dim _codecs As RasterCodecs = New RasterCodecs()
                Dim _image As RasterImage

                AddHandler SizeChanged, AddressOf MedicalViewerForm_SizeChanged

                ' Create the medical viewer and adjust the size and the location.
                _medicalViewer = New MedicalViewer(1, 2)
                _medicalViewer.Location = New Point(0, 0)
                _medicalViewer.Size = New Size(Me.ClientRectangle.Right, Me.ClientRectangle.Bottom)

                ' Load an image and then add it to the control.
                _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir, "xa.dcm"))
                Dim cell As MedicalViewerMultiCell = New MedicalViewerMultiCell(_image, True, 1, 1)
                ' add some actions that will be used to change the properties of the images inside the control.
                cell.AddAction(MedicalViewerActionType.WindowLevel)
                cell.AddAction(MedicalViewerActionType.Scale)
                cell.AddAction(MedicalViewerActionType.Offset)

                ' assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
                cell.SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active)
                cell.SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active)
                cell.SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active)

                _medicalViewer.Cells.Add(cell)

                ' adjust some properties of the cell and add some tags.
                _medicalViewer.Cells(0).SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448")
                _medicalViewer.Cells(0).SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame)
                _medicalViewer.Cells(0).SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale)
                _medicalViewer.Cells(0).SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData)
                _medicalViewer.Cells(0).SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView)


                ' Load another image and then add it to the control.
                _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir, "mr.dcm"))
                _medicalViewer.Cells.Add(New MedicalViewerMultiCell(_image, True, 2, 2))

                ' add some actions that will be used to change the properties of the images inside the control.
                _medicalViewer.Cells(1).AddAction(MedicalViewerActionType.WindowLevel)
                _medicalViewer.Cells(1).AddAction(MedicalViewerActionType.Scale)
                _medicalViewer.Cells(1).AddAction(MedicalViewerActionType.Offset)

                ' assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
                _medicalViewer.Cells(1).SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active)
                _medicalViewer.Cells(1).SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active)
                _medicalViewer.Cells(1).SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active)

                ' adjust some properties of the cell and add some tags.
                _medicalViewer.Cells(1).SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448")
                _medicalViewer.Cells(1).SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame)
                _medicalViewer.Cells(1).SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale)
                _medicalViewer.Cells(1).SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData)
                _medicalViewer.Cells(1).SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView)


                Controls.Add(_medicalViewer)
                _medicalViewer.Dock = DockStyle.Fill
            End Sub
            Public ReadOnly Property Viewer() As MedicalViewer
                Get
                    Return _medicalViewer
                End Get
            End Property
        End Class
      Private Function GetMedicalControlForCustomAnnotationExample() As MedicalViewerCustomAnnotationForm
         Return New MedicalViewerCustomAnnotationForm()
      End Function


      Public Sub MedicalViewerCustomAnnotationExample()
         Dim myForm As MedicalViewerCustomAnnotationForm = GetMedicalControlForCustomAnnotationExample()
         Dim medicalViewer As MedicalViewer = myForm.Viewer
         Dim cell As MedicalViewerMultiCell = CType(medicalViewer.Cells(0), MedicalViewerMultiCell)

         cell.AddAction(CType(101, MedicalViewerActionType))
         cell.SetAction(CType(101, MedicalViewerActionType), MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active)
         cell.DeclareActionAsAnnotation(CType(101, MedicalViewerActionType), GetType(MyTriangleObject))
         AddHandler cell.CustomAnnotationDataRequested, AddressOf cell_CustomAnnotationDataRequested

         myForm.ShowDialog()
      End Sub

      Private Sub cell_CustomAnnotationDataRequested(ByVal sender As Object, ByVal e As MedicalViewerCustomAnnotationArgs)
         Select Case e.RequestedObject
            Case MedicalViewerCustomAnnotationRequestedObject.AnnotationObject
               If e.AnnotationAction = CType(101, MedicalViewerActionType) Then
                  Dim triangle As MyTriangleObject = New MyTriangleObject()
                  triangle.Pen = New AnnPen(Color.Blue, New AnnLength(3, AnnUnit.Pixel))
                  e.AnnotationObject = triangle
               End If
            Case MedicalViewerCustomAnnotationRequestedObject.DrawDesigner
               If e.AnnotationAction = CType(101, MedicalViewerActionType) Then
                  e.DrawDesigner = New MyTriangleObjectDrawDesigner()
               End If
            Case MedicalViewerCustomAnnotationRequestedObject.EditDesigner
               If e.AnnotationAction = CType(101, MedicalViewerActionType) Then
                  e.EditDesigner = New MyTriangleObjectEditDesigner()
               End If
         End Select
      End Sub



      '
      ' Triangle annotation object class
      ' This class will have a 3 points for a triangle objects that can be stroked with a pen and filled with a brush
      '

      <Serializable()> _
      Public Class MyTriangleObject : Inherits AnnObject ' must derive from AnnObject or one of its derived classes
         '
         ' our private variables
         '

         ' the three points that define our triangle
         <NonSerialized()> _
         Private _firstPoint As AnnPoint
         <NonSerialized()> _
         Private _secondPoint As AnnPoint
         <NonSerialized()> _
         Private _thirdPoint As AnnPoint

         '
         ' constructor
         '

         Public Sub New()
            ' no, we do not require a font
            MyBase.New(True, True, False)
            ' initialize the points

            _firstPoint = AnnPoint.Empty
            _secondPoint = AnnPoint.Empty
            _thirdPoint = AnnPoint.Empty
         End Sub

         '
         ' ISerializable implementation
         '

         Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            ' do not forget to call the base class version
            MyBase.New(info, context)
            ' we need to deserialize our private variables here
            _firstPoint = CType(info.GetValue("FirstPointName", GetType(AnnPoint)), AnnPoint)
            _secondPoint = CType(info.GetValue("SecondPointName", GetType(AnnPoint)), AnnPoint)
            _thirdPoint = CType(info.GetValue("ThirdPointName", GetType(AnnPoint)), AnnPoint)
         End Sub

         Public Overrides Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            ' we need to serialize our private variables here

            ' call the base class version
            MyBase.GetObjectData(info, context)

            ' serialize the points
            info.AddValue("FirstPointName", _firstPoint, GetType(AnnPoint))
            info.AddValue("SecondPointName", _secondPoint, GetType(AnnPoint))
            info.AddValue("ThirdPointName", _thirdPoint, GetType(AnnPoint))
         End Sub

         '
         ' accessors to the points
         '

         Public Property FirstPoint() As AnnPoint
            Get
               Return _firstPoint
            End Get

            Set(ByVal value As AnnPoint)
               _firstPoint = Value
            End Set
         End Property

         Public Property SecondPoint() As AnnPoint
            Get
               Return _secondPoint
            End Get

            Set(ByVal value As AnnPoint)
               _secondPoint = Value
            End Set
         End Property

         Public Property ThirdPoint() As AnnPoint
            Get
               Return _thirdPoint
            End Get

            Set(ByVal value As AnnPoint)
               _thirdPoint = Value
            End Set
         End Property

         '
         ' AnnObject overrides
         '

         Protected Overrides Function Create() As AnnObject
            ' must return a new instance of our class
            Return New MyTriangleObject()
         End Function

         Public Overrides Function Clone() As Object
            ' override the clone method

            ' first call the base implementation
            Dim obj As MyTriangleObject = TryCast(MyBase.Clone(), MyTriangleObject)

            ' next, copy the points
            obj.FirstPoint = FirstPoint
            obj.SecondPoint = SecondPoint
            obj.ThirdPoint = ThirdPoint

            Return obj
         End Function

         Public Overrides Function GetGraphicsPath(ByVal mode As AnnGetGraphicsPathMode) As GraphicsPath
            ' must a return a graphics path representation of our object
            ' Note: this object does not require us to override AnnObject.DrawObject since we can
            ' use a graphics path to represents the object completely.

            ' create a new graphics path
            Dim path As GraphicsPath = New GraphicsPath()

            ' add the triangle points as a series of lines

            ' convert the points to pixels PointF
            Dim pts As PointF() = {FirstPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(), SecondPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(), ThirdPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF()}

            path.AddLines(pts)
            path.CloseFigure()

            Return path
         End Function

         Public Overrides Sub ResetRotatePoints()
            ' Place the rotate center control point in the center of the triangle
            Dim CenterX As Single = (FirstPoint.X + SecondPoint.X + ThirdPoint.X) / 3
            Dim CenterY As Single = (FirstPoint.Y + SecondPoint.Y + ThirdPoint.Y) / 3
            RotateCenter = New AnnPoint(CenterX, CenterY)

            ' Place the RotateGripper along a line from the center of the triangle through a vertex
            Dim cx As Single = FirstPoint.X - RotateCenter.X
            Dim cy As Single = FirstPoint.Y - RotateCenter.Y

            Dim dist As Single = CSng(Math.Sqrt(cx * cx + cy * cy))
            Dim fract As Single = 1
            If dist <> 0 Then
               fract = (Math.Abs(dist) + Math.Abs(GripperDistance)) / dist
            End If
            Dim GripperX As Single = CenterX + fract * cx
            Dim GripperY As Single = CenterY + fract * cy
            RotateGripper = New AnnPoint(GripperX, GripperY)
         End Sub
      End Class



      '
      ' MyTriangleObject draw designer
      ' Will require the user to click 3 times once for each point
      '

      Public Class MyTriangleObjectDrawDesigner : Inherits AnnDrawDesigner ' must derive from AnnDrawDesigner or one of its derived classes
         '
         ' private variables
         '

         ' we need to keep track on next point to add
         Private _clickCount As Integer

         '
         ' constructor
         '
         Public Sub New()
            _clickCount = 0
         End Sub

         '
         ' AnnDrawDesigner overrides
         '

         Public Overrides Function MouseDown(ByVal e As MouseEventArgs) As Boolean
            Dim handled As Boolean = False

            ' only process left button clicks
            If e.Button = MouseButtons.Left Then
               ' check if we have not started drawing yet, DrawObject will be null
               If DrawObject Is Nothing Then
                  ' yes, create a new MyTriangleObject from ObjectTemplate
                  Dim obj As MyTriangleObject = TryCast(ObjectTemplate.Clone(), MyTriangleObject)

                  ' setup the points
                  Dim pt As AnnPoint = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit)
                  obj.FirstPoint = pt
                  obj.SecondPoint = pt
                  obj.ThirdPoint = pt

                  ' start drawing this new object
                  StartWorking(obj)
                  handled = True

                  ' we processed first click
                  _clickCount += 1
               Else
                  ' an object is already being drawn, so process next click

                  ' get our object and assign next point to it

                  Dim obj As MyTriangleObject = TryCast(DrawObject, MyTriangleObject)

                  Dim pt As AnnPoint = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit)

                  If _clickCount = 1 Then
                     ' second point
                     obj.SecondPoint = pt
                     _clickCount += 1
                     handled = True
                  ElseIf _clickCount = 2 Then
                     ' third point
                     obj.ThirdPoint = pt
                     handled = True

                     ' we are done!
                     EndWorking()
                  End If
               End If
            Else
               ' we want to cancel the drawing if any other button has been clicked
               If Not DrawObject Is Nothing Then
                  Cancel()
                  handled = True
               End If
            End If

            Return handled
         End Function

         Public Overrides Function MouseMove(ByVal e As MouseEventArgs) As Boolean
            Dim handled As Boolean = False

            ' check if we are already drawing an object
            If Not DrawObject Is Nothing Then
               ' yes, get this object and assign the next point

               ' first, save the old invalid rectangle
               Dim rcOld As Rectangle = DrawObject.InvalidRectangle

               ' get out object and assign the point
               Dim obj As MyTriangleObject = TryCast(DrawObject, MyTriangleObject)

               Dim pt As AnnPoint = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit)

               If _clickCount = 1 Then
                  obj.SecondPoint = pt
               ElseIf _clickCount = 2 Then
                  obj.ThirdPoint = pt
               End If

               ' get the new invalid rectangle
               Dim rcNew As Rectangle = DrawObject.InvalidRectangle

               ' continue drawing this object
               Working(Rectangle.Union(rcOld, rcNew))
               handled = True
            End If

            Return handled
         End Function

         Public Overrides Function MouseUp(ByVal e As MouseEventArgs) As Boolean
            ' we do not need to do anything special on mouse up.
            ' so just see if we are drawing to return true (we handled it)

            Dim handled As Boolean = False

            If DrawObject Is Nothing Then
               handled = True
            End If

            Return handled
         End Function
      End Class


      '
      ' MyTriangleObject edit designer
      ' User can click on any of the points and move them around as well as clicking and dragging the object itself.
      '

      Public Class MyTriangleObjectEditDesigner : Inherits AnnEditDesigner ' must derive from AnnEditDesigner or one of its derived classes
         '
         ' constructor
         '
         Public Sub New()
         End Sub

         '
         ' AnnEditDesigner overrides
         '

         Public Overrides ReadOnly Property ControlPointCount() As Integer
            Get
               ' return the number of control points we need
               ' in this case 3, one for each point in our triangle
               Return 3
            End Get
         End Property

         Public Overrides Function GetControlPointsLocation() As AnnPoint()
            ' return the position of these control points
            ' in this case, same as the points from our object
            Dim obj As MyTriangleObject = TryCast(EditObject, MyTriangleObject)
            Return New AnnPoint() {obj.FirstPoint, obj.SecondPoint, obj.ThirdPoint}
         End Function

         Protected Overrides Sub MoveControlPoint(ByVal controlPointIndex As Integer, ByVal pt As AnnPoint)
            ' user has clicked and moved a point.
            ' based on the index, we can tell if the user dragged the first, second or third point

            Dim obj As MyTriangleObject = TryCast(EditObject, MyTriangleObject)
            Select Case controlPointIndex
               Case 0
                  ' first point
                  obj.FirstPoint = pt.ConvertTo(Container.UnitConverter, obj.FirstPoint.Unit)

               Case 1
                  ' second point
                  obj.SecondPoint = pt.ConvertTo(Container.UnitConverter, obj.SecondPoint.Unit)

               Case 2
                  ' third point
                  obj.ThirdPoint = pt.ConvertTo(Container.UnitConverter, obj.ThirdPoint.Unit)
            End Select
         End Sub

         ' Note, we will not override Move or MoveName since the default implementation is good enough for our object
      End Class


        Public NotInheritable Class LEAD_VARS
        Public Const ImagesDir As String = "C:\Users\Public\Documents\LEADTOOLS Images"
        End Class
        using Leadtools;
        using Leadtools.Drawing;
        using Leadtools.Codecs;
        using Leadtools.MedicalViewer;
        using Leadtools.ImageProcessing;
        using Leadtools.Annotations;

        class MedicalViewerCustomAnnotationForm : Form
        {
           private MedicalViewer _medicalViewer;
           void MedicalViewerForm_SizeChanged(object sender, EventArgs e)
           {
              _medicalViewer.Size = new Size(this.ClientRectangle.Right, this.ClientRectangle.Bottom);
           }

           public MedicalViewerCustomAnnotationForm()
           {
              RasterCodecs _codecs = new RasterCodecs();
              RasterImage _image;

              this.SizeChanged += new EventHandler(MedicalViewerForm_SizeChanged);

              // Create the medical viewer and adjust the size and the location.
              _medicalViewer = new MedicalViewer(1, 2);
              _medicalViewer.Location = new Point(0, 0);
              _medicalViewer.Size = new Size(this.ClientRectangle.Right, this.ClientRectangle.Bottom);

              // Load an image and then add it to the control.
              _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir,"xa.dcm"));
              MedicalViewerMultiCell cell = new MedicalViewerMultiCell(_image, true, 1, 1);
              // add some actions that will be used to change the properties of the images inside the control.
              cell.AddAction(MedicalViewerActionType.WindowLevel);
              cell.AddAction(MedicalViewerActionType.Scale);
              cell.AddAction(MedicalViewerActionType.Offset);

              // assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
              cell.SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
              cell.SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active);
              cell.SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active);

              _medicalViewer.Cells.Add(cell);

              // adjust some properties of the cell and add some tags.
              _medicalViewer.Cells[0].SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448");
              _medicalViewer.Cells[0].SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame);
              _medicalViewer.Cells[0].SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale);
              _medicalViewer.Cells[0].SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData);
              _medicalViewer.Cells[0].SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView);


              // Load another image and then add it to the control.
              _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir,"mr.dcm"));
              _medicalViewer.Cells.Add(new MedicalViewerMultiCell(_image, true, 2, 2));

              // add some actions that will be used to change the properties of the images inside the control.
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.WindowLevel);
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.Scale);
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.Offset);

              // assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active);
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active);

              // adjust some properties of the cell and add some tags.
              _medicalViewer.Cells[1].SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448");
              _medicalViewer.Cells[1].SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame);
              _medicalViewer.Cells[1].SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale);
              _medicalViewer.Cells[1].SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData);
              _medicalViewer.Cells[1].SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView);


              Controls.Add(_medicalViewer);
              _medicalViewer.Dock = DockStyle.Fill;
           }
           public MedicalViewer Viewer
           {
              get { return _medicalViewer; }
           }
        }
        MedicalViewerCustomAnnotationForm GetMedicalControlForCustomAnnotationExample()
        {
           return new MedicalViewerCustomAnnotationForm();
        }


        public void MedicalViewerCustomAnnotationExample()
        {
           MedicalViewerCustomAnnotationForm myForm = GetMedicalControlForCustomAnnotationExample();
           MedicalViewer medicalViewer = myForm.Viewer;
           MedicalViewerMultiCell cell = (MedicalViewerMultiCell)(medicalViewer.Cells[0]);

           cell.AddAction((MedicalViewerActionType)101);
           cell.SetAction((MedicalViewerActionType)101, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
           cell.DeclareActionAsAnnotation((MedicalViewerActionType)101, typeof(MyTriangleObject));
           cell.CustomAnnotationDataRequested += new EventHandler<MedicalViewerCustomAnnotationArgs>(cell_CustomAnnotationDataRequested);

           myForm.ShowDialog();
        }

        void cell_CustomAnnotationDataRequested(object sender, MedicalViewerCustomAnnotationArgs e)
        {
           switch (e.RequestedObject)
           {
              case MedicalViewerCustomAnnotationRequestedObject.AnnotationObject:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                 {
                    MyTriangleObject triangle = new MyTriangleObject();
                    triangle.Pen = new AnnPen(Color.Blue, new AnnLength(3, AnnUnit.Pixel));
                    e.AnnotationObject = triangle;
                 }
                 break;
              case MedicalViewerCustomAnnotationRequestedObject.DrawDesigner:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                    e.DrawDesigner = new MyTriangleObjectDrawDesigner();
                 break;
              case MedicalViewerCustomAnnotationRequestedObject.EditDesigner:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                    e.EditDesigner = new MyTriangleObjectEditDesigner();
                 break;
           }
        }



        //
        // Triangle annotation object class
        // This class will have a 3 points for a triangle objects that can be stroked with a pen and filled with a brush
        //

        [Serializable] // our class must be serializable to play well with the annotation load/save and undo/redo features
        public class MyTriangleObject :
           AnnObject        // must derive from AnnObject or one of its derived classes
        {
           //
           // our private variables
           //

           // the three points that define our triangle
           [NonSerialized()]
           private AnnPoint _firstPoint;
           [NonSerialized()]
           private AnnPoint _secondPoint;
           [NonSerialized()]
           private AnnPoint _thirdPoint;

           //
           // constructor
           //


           public MyTriangleObject()
              :
              base(
              true,    // yes, we require a pen
              true,    // yes, we require a brush
              false)   // no, we do not require a font
           {
              // initialize the points

              _firstPoint = AnnPoint.Empty;
              _secondPoint = AnnPoint.Empty;
              _thirdPoint = AnnPoint.Empty;
           }

           //
           // ISerializable implementation
           //


           protected MyTriangleObject(SerializationInfo info, StreamingContext context)
              :
              base(info, context)  // do not forget to call the base class version
           {
              // we need to deserialize our private variables here
              _firstPoint = (AnnPoint)info.GetValue("FirstPointName", typeof(AnnPoint));
              _secondPoint = (AnnPoint)info.GetValue("SecondPointName", typeof(AnnPoint));
              _thirdPoint = (AnnPoint)info.GetValue("ThirdPointName", typeof(AnnPoint));
           }

           public override void GetObjectData(SerializationInfo info, StreamingContext context)
           {
              // we need to serialize our private variables here

              // call the base class version
              base.GetObjectData(info, context);

              // serialize the points
              info.AddValue("FirstPointName", _firstPoint, typeof(AnnPoint));
              info.AddValue("SecondPointName", _secondPoint, typeof(AnnPoint));
              info.AddValue("ThirdPointName", _thirdPoint, typeof(AnnPoint));
           }

           //
           // accessors to the points
           //


           public AnnPoint FirstPoint
           {
              get
              {
                 return _firstPoint;
              }

              set
              {
                 _firstPoint = value;
              }
           }

           public AnnPoint SecondPoint
           {
              get
              {
                 return _secondPoint;
              }

              set
              {
                 _secondPoint = value;
              }
           }

           public AnnPoint ThirdPoint
           {
              get
              {
                 return _thirdPoint;
              }

              set
              {
                 _thirdPoint = value;
              }
           }

           //
           // AnnObject overrides
           //


           protected override AnnObject Create()
           {
              // must return a new instance of our class
              return new MyTriangleObject();
           }

           public override object Clone()
           {
              // override the clone method

              // first call the base implementation
              MyTriangleObject obj = base.Clone() as MyTriangleObject;

              // next, copy the points
              obj.FirstPoint = FirstPoint;
              obj.SecondPoint = SecondPoint;
              obj.ThirdPoint = ThirdPoint;

              return obj;
           }

           public override GraphicsPath GetGraphicsPath(AnnGetGraphicsPathMode mode)
           {
              // must a return a graphics path representation of our object
              // Note: this object does not require us to override AnnObject.DrawObject since we can
              // use a graphics path to represents the object completely.

              // create a new graphics path
              GraphicsPath path = new GraphicsPath();

              // add the triangle points as a series of lines

              // convert the points to pixels PointF
              PointF[] pts =
         {
            FirstPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(),
            SecondPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(),
            ThirdPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF()
         };

              path.AddLines(pts);
              path.CloseFigure();

              return path;
           }

           public override void ResetRotatePoints()
           {
              // Place the rotate center control point in the center of the triangle
              float CenterX = (FirstPoint.X + SecondPoint.X + ThirdPoint.X) / 3;
              float CenterY = (FirstPoint.Y + SecondPoint.Y + ThirdPoint.Y) / 3;
              RotateCenter = new AnnPoint(CenterX, CenterY);

              // Place the RotateGripper along a line from the center of the triangle through a vertex
              float cx = FirstPoint.X - RotateCenter.X;
              float cy = FirstPoint.Y - RotateCenter.Y;

              float dist = (float)Math.Sqrt(cx * cx + cy * cy);
              float fract = 1;
              if (dist != 0)
                 fract = (Math.Abs(dist) + Math.Abs(GripperDistance)) / dist;
              float GripperX = CenterX + fract * cx;
              float GripperY = CenterY + fract * cy;
              RotateGripper = new AnnPoint(GripperX, GripperY);
           }
        }



        //
        // MyTriangleObject draw designer
        // Will require the user to click 3 times once for each point
        //


        public class MyTriangleObjectDrawDesigner :
           AnnDrawDesigner      // must derive from AnnDrawDesigner or one of its derived classes
        {
           //
           // private variables
           //

           // we need to keep track on next point to add
           private int _clickCount;

           //
           // constructor
           //

           public MyTriangleObjectDrawDesigner()
           {
              _clickCount = 0;
           }

           //
           // AnnDrawDesigner overrides
           //


           public override bool MouseDown(MouseEventArgs e)
           {
              bool handled = false;

              // only process left button clicks
              if (e.Button == MouseButtons.Left)
              {
                 // check if we have not started drawing yet, DrawObject will be null
                 if (DrawObject == null)
                 {
                    // yes, create a new MyTriangleObject from ObjectTemplate
                    MyTriangleObject obj = ObjectTemplate.Clone() as MyTriangleObject;

                    // setup the points
                    AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);
                    obj.FirstPoint = pt;
                    obj.SecondPoint = pt;
                    obj.ThirdPoint = pt;

                    // start drawing this new object
                    StartWorking(obj);
                    handled = true;

                    // we processed first click
                    _clickCount++;
                 }
                 else
                 {
                    // an object is already being drawn, so process next click

                    // get our object and assign next point to it

                    MyTriangleObject obj = DrawObject as MyTriangleObject;

                    AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);

                    if (_clickCount == 1)
                    {
                       // second point
                       obj.SecondPoint = pt;
                       _clickCount++;
                       handled = true;
                    }
                    else if (_clickCount == 2)
                    {
                       // third point
                       obj.ThirdPoint = pt;
                       handled = true;

                       // we are done!
                       EndWorking();
                    }
                 }
              }
              else
              {
                 // we want to cancel the drawing if any other button has been clicked
                 if (DrawObject != null)
                 {
                    Cancel();
                    handled = true;
                 }
              }

              return handled;
           }

           public override bool MouseMove(MouseEventArgs e)
           {
              bool handled = false;

              // check if we are already drawing an object
              if (DrawObject != null)
              {
                 // yes, get this object and assign the next point

                 // first, save the old invalid rectangle
                 Rectangle rcOld = DrawObject.InvalidRectangle;

                 // get out object and assign the point
                 MyTriangleObject obj = DrawObject as MyTriangleObject;

                 AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);

                 if (_clickCount == 1)
                    obj.SecondPoint = pt;
                 else if (_clickCount == 2)
                    obj.ThirdPoint = pt;

                 // get the new invalid rectangle
                 Rectangle rcNew = DrawObject.InvalidRectangle;

                 // continue drawing this object
                 Working(Rectangle.Union(rcOld, rcNew));
                 handled = true;
              }

              return handled;
           }

           public override bool MouseUp(MouseEventArgs e)
           {
              // we do not need to do anything special on mouse up.
              // so just see if we are drawing to return true (we handled it)

              bool handled = false;

              if (DrawObject == null)
                 handled = true;

              return handled;
           }
        }


        //
        // MyTriangleObject edit designer
        // User can click on any of the points and move them around as well as clicking and dragging the object itself.
        //


        public class MyTriangleObjectEditDesigner :
           AnnEditDesigner      // must derive from AnnEditDesigner or one of its derived classes
        {
           //
           // constructor
           //

           public MyTriangleObjectEditDesigner()
           {
           }

           //
           // AnnEditDesigner overrides
           //


           public override int ControlPointCount
           {
              get
              {
                 // return the number of control points we need
                 // in this case 3, one for each point in our triangle
                 return 3;
              }
           }

           public override AnnPoint[] GetControlPointsLocation()
           {
              // return the position of these control points
              // in this case, same as the points from our object
              MyTriangleObject obj = EditObject as MyTriangleObject;
              return new AnnPoint[]
            {
               obj.FirstPoint,
               obj.SecondPoint,
               obj.ThirdPoint
            };
           }

           protected override void MoveControlPoint(int controlPointIndex, AnnPoint pt)
           {
              // user has clicked and moved a point.
              // based on the index, we can tell if the user dragged the first, second or third point

              MyTriangleObject obj = EditObject as MyTriangleObject;
              switch (controlPointIndex)
              {
                 case 0:
                    // first point
                    obj.FirstPoint = pt.ConvertTo(Container.UnitConverter, obj.FirstPoint.Unit);
                    break;

                 case 1:
                    // second point
                    obj.SecondPoint = pt.ConvertTo(Container.UnitConverter, obj.SecondPoint.Unit);
                    break;

                 case 2:
                    // third point
                    obj.ThirdPoint = pt.ConvertTo(Container.UnitConverter, obj.ThirdPoint.Unit);
                    break;
              }
           }

           // Note, we will not override Move or MoveName since the default implementation is good enough for our object
        }


        static class LEAD_VARS
        {
        public const string ImagesDir = @"C:\Users\Public\Documents\LEADTOOLS Images";
        }

        Imports Leadtools
        Imports Leadtools.Drawing
        Imports Leadtools.Codecs
        Imports Leadtools.MedicalViewer
        Imports Leadtools.ImageProcessing
        Imports Leadtools.Annotations

        Private Class MedicalViewerCustomAnnotationForm : Inherits Form
            Private _medicalViewer As MedicalViewer
            Private Sub MedicalViewerForm_SizeChanged(ByVal sender As Object, ByVal e As EventArgs)
                _medicalViewer.Size = New Size(Me.ClientRectangle.Right, Me.ClientRectangle.Bottom)
            End Sub

            Public Sub New()
                Dim _codecs As RasterCodecs = New RasterCodecs()
                Dim _image As RasterImage

                AddHandler SizeChanged, AddressOf MedicalViewerForm_SizeChanged

                ' Create the medical viewer and adjust the size and the location.
                _medicalViewer = New MedicalViewer(1, 2)
                _medicalViewer.Location = New Point(0, 0)
                _medicalViewer.Size = New Size(Me.ClientRectangle.Right, Me.ClientRectangle.Bottom)

                ' Load an image and then add it to the control.
                _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir, "xa.dcm"))
                Dim cell As MedicalViewerMultiCell = New MedicalViewerMultiCell(_image, True, 1, 1)
                ' add some actions that will be used to change the properties of the images inside the control.
                cell.AddAction(MedicalViewerActionType.WindowLevel)
                cell.AddAction(MedicalViewerActionType.Scale)
                cell.AddAction(MedicalViewerActionType.Offset)

                ' assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
                cell.SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active)
                cell.SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active)
                cell.SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active)

                _medicalViewer.Cells.Add(cell)

                ' adjust some properties of the cell and add some tags.
                _medicalViewer.Cells(0).SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448")
                _medicalViewer.Cells(0).SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame)
                _medicalViewer.Cells(0).SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale)
                _medicalViewer.Cells(0).SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData)
                _medicalViewer.Cells(0).SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView)


                ' Load another image and then add it to the control.
                _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir, "mr.dcm"))
                _medicalViewer.Cells.Add(New MedicalViewerMultiCell(_image, True, 2, 2))

                ' add some actions that will be used to change the properties of the images inside the control.
                _medicalViewer.Cells(1).AddAction(MedicalViewerActionType.WindowLevel)
                _medicalViewer.Cells(1).AddAction(MedicalViewerActionType.Scale)
                _medicalViewer.Cells(1).AddAction(MedicalViewerActionType.Offset)

                ' assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
                _medicalViewer.Cells(1).SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active)
                _medicalViewer.Cells(1).SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active)
                _medicalViewer.Cells(1).SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active)

                ' adjust some properties of the cell and add some tags.
                _medicalViewer.Cells(1).SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448")
                _medicalViewer.Cells(1).SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame)
                _medicalViewer.Cells(1).SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale)
                _medicalViewer.Cells(1).SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData)
                _medicalViewer.Cells(1).SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView)


                Controls.Add(_medicalViewer)
                _medicalViewer.Dock = DockStyle.Fill
            End Sub
            Public ReadOnly Property Viewer() As MedicalViewer
                Get
                    Return _medicalViewer
                End Get
            End Property
        End Class
      Private Function GetMedicalControlForCustomAnnotationExample() As MedicalViewerCustomAnnotationForm
         Return New MedicalViewerCustomAnnotationForm()
      End Function


      Public Sub MedicalViewerCustomAnnotationExample()
         Dim myForm As MedicalViewerCustomAnnotationForm = GetMedicalControlForCustomAnnotationExample()
         Dim medicalViewer As MedicalViewer = myForm.Viewer
         Dim cell As MedicalViewerMultiCell = CType(medicalViewer.Cells(0), MedicalViewerMultiCell)

         cell.AddAction(CType(101, MedicalViewerActionType))
         cell.SetAction(CType(101, MedicalViewerActionType), MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active)
         cell.DeclareActionAsAnnotation(CType(101, MedicalViewerActionType), GetType(MyTriangleObject))
         AddHandler cell.CustomAnnotationDataRequested, AddressOf cell_CustomAnnotationDataRequested

         myForm.ShowDialog()
      End Sub

      Private Sub cell_CustomAnnotationDataRequested(ByVal sender As Object, ByVal e As MedicalViewerCustomAnnotationArgs)
         Select Case e.RequestedObject
            Case MedicalViewerCustomAnnotationRequestedObject.AnnotationObject
               If e.AnnotationAction = CType(101, MedicalViewerActionType) Then
                  Dim triangle As MyTriangleObject = New MyTriangleObject()
                  triangle.Pen = New AnnPen(Color.Blue, New AnnLength(3, AnnUnit.Pixel))
                  e.AnnotationObject = triangle
               End If
            Case MedicalViewerCustomAnnotationRequestedObject.DrawDesigner
               If e.AnnotationAction = CType(101, MedicalViewerActionType) Then
                  e.DrawDesigner = New MyTriangleObjectDrawDesigner()
               End If
            Case MedicalViewerCustomAnnotationRequestedObject.EditDesigner
               If e.AnnotationAction = CType(101, MedicalViewerActionType) Then
                  e.EditDesigner = New MyTriangleObjectEditDesigner()
               End If
         End Select
      End Sub



      '
      ' Triangle annotation object class
      ' This class will have a 3 points for a triangle objects that can be stroked with a pen and filled with a brush
      '

      <Serializable()> _
      Public Class MyTriangleObject : Inherits AnnObject ' must derive from AnnObject or one of its derived classes
         '
         ' our private variables
         '

         ' the three points that define our triangle
         <NonSerialized()> _
         Private _firstPoint As AnnPoint
         <NonSerialized()> _
         Private _secondPoint As AnnPoint
         <NonSerialized()> _
         Private _thirdPoint As AnnPoint

         '
         ' constructor
         '

         Public Sub New()
            ' no, we do not require a font
            MyBase.New(True, True, False)
            ' initialize the points

            _firstPoint = AnnPoint.Empty
            _secondPoint = AnnPoint.Empty
            _thirdPoint = AnnPoint.Empty
         End Sub

         '
         ' ISerializable implementation
         '

         Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            ' do not forget to call the base class version
            MyBase.New(info, context)
            ' we need to deserialize our private variables here
            _firstPoint = CType(info.GetValue("FirstPointName", GetType(AnnPoint)), AnnPoint)
            _secondPoint = CType(info.GetValue("SecondPointName", GetType(AnnPoint)), AnnPoint)
            _thirdPoint = CType(info.GetValue("ThirdPointName", GetType(AnnPoint)), AnnPoint)
         End Sub

         Public Overrides Sub GetObjectData(ByVal info As SerializationInfo, ByVal context As StreamingContext)
            ' we need to serialize our private variables here

            ' call the base class version
            MyBase.GetObjectData(info, context)

            ' serialize the points
            info.AddValue("FirstPointName", _firstPoint, GetType(AnnPoint))
            info.AddValue("SecondPointName", _secondPoint, GetType(AnnPoint))
            info.AddValue("ThirdPointName", _thirdPoint, GetType(AnnPoint))
         End Sub

         '
         ' accessors to the points
         '

         Public Property FirstPoint() As AnnPoint
            Get
               Return _firstPoint
            End Get

            Set(ByVal value As AnnPoint)
               _firstPoint = Value
            End Set
         End Property

         Public Property SecondPoint() As AnnPoint
            Get
               Return _secondPoint
            End Get

            Set(ByVal value As AnnPoint)
               _secondPoint = Value
            End Set
         End Property

         Public Property ThirdPoint() As AnnPoint
            Get
               Return _thirdPoint
            End Get

            Set(ByVal value As AnnPoint)
               _thirdPoint = Value
            End Set
         End Property

         '
         ' AnnObject overrides
         '

         Protected Overrides Function Create() As AnnObject
            ' must return a new instance of our class
            Return New MyTriangleObject()
         End Function

         Public Overrides Function Clone() As Object
            ' override the clone method

            ' first call the base implementation
            Dim obj As MyTriangleObject = TryCast(MyBase.Clone(), MyTriangleObject)

            ' next, copy the points
            obj.FirstPoint = FirstPoint
            obj.SecondPoint = SecondPoint
            obj.ThirdPoint = ThirdPoint

            Return obj
         End Function

         Public Overrides Function GetGraphicsPath(ByVal mode As AnnGetGraphicsPathMode) As GraphicsPath
            ' must a return a graphics path representation of our object
            ' Note: this object does not require us to override AnnObject.DrawObject since we can
            ' use a graphics path to represents the object completely.

            ' create a new graphics path
            Dim path As GraphicsPath = New GraphicsPath()

            ' add the triangle points as a series of lines

            ' convert the points to pixels PointF
            Dim pts As PointF() = {FirstPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(), SecondPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(), ThirdPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF()}

            path.AddLines(pts)
            path.CloseFigure()

            Return path
         End Function

         Public Overrides Sub ResetRotatePoints()
            ' Place the rotate center control point in the center of the triangle
            Dim CenterX As Single = (FirstPoint.X + SecondPoint.X + ThirdPoint.X) / 3
            Dim CenterY As Single = (FirstPoint.Y + SecondPoint.Y + ThirdPoint.Y) / 3
            RotateCenter = New AnnPoint(CenterX, CenterY)

            ' Place the RotateGripper along a line from the center of the triangle through a vertex
            Dim cx As Single = FirstPoint.X - RotateCenter.X
            Dim cy As Single = FirstPoint.Y - RotateCenter.Y

            Dim dist As Single = CSng(Math.Sqrt(cx * cx + cy * cy))
            Dim fract As Single = 1
            If dist <> 0 Then
               fract = (Math.Abs(dist) + Math.Abs(GripperDistance)) / dist
            End If
            Dim GripperX As Single = CenterX + fract * cx
            Dim GripperY As Single = CenterY + fract * cy
            RotateGripper = New AnnPoint(GripperX, GripperY)
         End Sub
      End Class



      '
      ' MyTriangleObject draw designer
      ' Will require the user to click 3 times once for each point
      '

      Public Class MyTriangleObjectDrawDesigner : Inherits AnnDrawDesigner ' must derive from AnnDrawDesigner or one of its derived classes
         '
         ' private variables
         '

         ' we need to keep track on next point to add
         Private _clickCount As Integer

         '
         ' constructor
         '
         Public Sub New()
            _clickCount = 0
         End Sub

         '
         ' AnnDrawDesigner overrides
         '

         Public Overrides Function MouseDown(ByVal e As MouseEventArgs) As Boolean
            Dim handled As Boolean = False

            ' only process left button clicks
            If e.Button = MouseButtons.Left Then
               ' check if we have not started drawing yet, DrawObject will be null
               If DrawObject Is Nothing Then
                  ' yes, create a new MyTriangleObject from ObjectTemplate
                  Dim obj As MyTriangleObject = TryCast(ObjectTemplate.Clone(), MyTriangleObject)

                  ' setup the points
                  Dim pt As AnnPoint = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit)
                  obj.FirstPoint = pt
                  obj.SecondPoint = pt
                  obj.ThirdPoint = pt

                  ' start drawing this new object
                  StartWorking(obj)
                  handled = True

                  ' we processed first click
                  _clickCount += 1
               Else
                  ' an object is already being drawn, so process next click

                  ' get our object and assign next point to it

                  Dim obj As MyTriangleObject = TryCast(DrawObject, MyTriangleObject)

                  Dim pt As AnnPoint = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit)

                  If _clickCount = 1 Then
                     ' second point
                     obj.SecondPoint = pt
                     _clickCount += 1
                     handled = True
                  ElseIf _clickCount = 2 Then
                     ' third point
                     obj.ThirdPoint = pt
                     handled = True

                     ' we are done!
                     EndWorking()
                  End If
               End If
            Else
               ' we want to cancel the drawing if any other button has been clicked
               If Not DrawObject Is Nothing Then
                  Cancel()
                  handled = True
               End If
            End If

            Return handled
         End Function

         Public Overrides Function MouseMove(ByVal e As MouseEventArgs) As Boolean
            Dim handled As Boolean = False

            ' check if we are already drawing an object
            If Not DrawObject Is Nothing Then
               ' yes, get this object and assign the next point

               ' first, save the old invalid rectangle
               Dim rcOld As Rectangle = DrawObject.InvalidRectangle

               ' get out object and assign the point
               Dim obj As MyTriangleObject = TryCast(DrawObject, MyTriangleObject)

               Dim pt As AnnPoint = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit)

               If _clickCount = 1 Then
                  obj.SecondPoint = pt
               ElseIf _clickCount = 2 Then
                  obj.ThirdPoint = pt
               End If

               ' get the new invalid rectangle
               Dim rcNew As Rectangle = DrawObject.InvalidRectangle

               ' continue drawing this object
               Working(Rectangle.Union(rcOld, rcNew))
               handled = True
            End If

            Return handled
         End Function

         Public Overrides Function MouseUp(ByVal e As MouseEventArgs) As Boolean
            ' we do not need to do anything special on mouse up.
            ' so just see if we are drawing to return true (we handled it)

            Dim handled As Boolean = False

            If DrawObject Is Nothing Then
               handled = True
            End If

            Return handled
         End Function
      End Class


      '
      ' MyTriangleObject edit designer
      ' User can click on any of the points and move them around as well as clicking and dragging the object itself.
      '

      Public Class MyTriangleObjectEditDesigner : Inherits AnnEditDesigner ' must derive from AnnEditDesigner or one of its derived classes
         '
         ' constructor
         '
         Public Sub New()
         End Sub

         '
         ' AnnEditDesigner overrides
         '

         Public Overrides ReadOnly Property ControlPointCount() As Integer
            Get
               ' return the number of control points we need
               ' in this case 3, one for each point in our triangle
               Return 3
            End Get
         End Property

         Public Overrides Function GetControlPointsLocation() As AnnPoint()
            ' return the position of these control points
            ' in this case, same as the points from our object
            Dim obj As MyTriangleObject = TryCast(EditObject, MyTriangleObject)
            Return New AnnPoint() {obj.FirstPoint, obj.SecondPoint, obj.ThirdPoint}
         End Function

         Protected Overrides Sub MoveControlPoint(ByVal controlPointIndex As Integer, ByVal pt As AnnPoint)
            ' user has clicked and moved a point.
            ' based on the index, we can tell if the user dragged the first, second or third point

            Dim obj As MyTriangleObject = TryCast(EditObject, MyTriangleObject)
            Select Case controlPointIndex
               Case 0
                  ' first point
                  obj.FirstPoint = pt.ConvertTo(Container.UnitConverter, obj.FirstPoint.Unit)

               Case 1
                  ' second point
                  obj.SecondPoint = pt.ConvertTo(Container.UnitConverter, obj.SecondPoint.Unit)

               Case 2
                  ' third point
                  obj.ThirdPoint = pt.ConvertTo(Container.UnitConverter, obj.ThirdPoint.Unit)
            End Select
         End Sub

         ' Note, we will not override Move or MoveName since the default implementation is good enough for our object
      End Class


        Public NotInheritable Class LEAD_VARS
        Public Const ImagesDir As String = "C:\Users\Public\Documents\LEADTOOLS Images"
        End Class
        using Leadtools;
        using Leadtools.Drawing;
        using Leadtools.Codecs;
        using Leadtools.MedicalViewer;
        using Leadtools.ImageProcessing;
        using Leadtools.Annotations;

        class MedicalViewerCustomAnnotationForm : Form
        {
           private MedicalViewer _medicalViewer;
           void MedicalViewerForm_SizeChanged(object sender, EventArgs e)
           {
              _medicalViewer.Size = new Size(this.ClientRectangle.Right, this.ClientRectangle.Bottom);
           }

           public MedicalViewerCustomAnnotationForm()
           {
              RasterCodecs _codecs = new RasterCodecs();
              RasterImage _image;

              this.SizeChanged += new EventHandler(MedicalViewerForm_SizeChanged);

              // Create the medical viewer and adjust the size and the location.
              _medicalViewer = new MedicalViewer(1, 2);
              _medicalViewer.Location = new Point(0, 0);
              _medicalViewer.Size = new Size(this.ClientRectangle.Right, this.ClientRectangle.Bottom);

              // Load an image and then add it to the control.
              _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir,"xa.dcm"));
              MedicalViewerMultiCell cell = new MedicalViewerMultiCell(_image, true, 1, 1);
              // add some actions that will be used to change the properties of the images inside the control.
              cell.AddAction(MedicalViewerActionType.WindowLevel);
              cell.AddAction(MedicalViewerActionType.Scale);
              cell.AddAction(MedicalViewerActionType.Offset);

              // assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
              cell.SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
              cell.SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active);
              cell.SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active);

              _medicalViewer.Cells.Add(cell);

              // adjust some properties of the cell and add some tags.
              _medicalViewer.Cells[0].SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448");
              _medicalViewer.Cells[0].SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame);
              _medicalViewer.Cells[0].SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale);
              _medicalViewer.Cells[0].SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData);
              _medicalViewer.Cells[0].SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView);


              // Load another image and then add it to the control.
              _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir,"mr.dcm"));
              _medicalViewer.Cells.Add(new MedicalViewerMultiCell(_image, true, 2, 2));

              // add some actions that will be used to change the properties of the images inside the control.
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.WindowLevel);
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.Scale);
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.Offset);

              // assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active);
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active);

              // adjust some properties of the cell and add some tags.
              _medicalViewer.Cells[1].SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448");
              _medicalViewer.Cells[1].SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame);
              _medicalViewer.Cells[1].SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale);
              _medicalViewer.Cells[1].SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData);
              _medicalViewer.Cells[1].SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView);


              Controls.Add(_medicalViewer);
              _medicalViewer.Dock = DockStyle.Fill;
           }
           public MedicalViewer Viewer
           {
              get { return _medicalViewer; }
           }
        }
        MedicalViewerCustomAnnotationForm GetMedicalControlForCustomAnnotationExample()
        {
           return new MedicalViewerCustomAnnotationForm();
        }


        public void MedicalViewerCustomAnnotationExample()
        {
           MedicalViewerCustomAnnotationForm myForm = GetMedicalControlForCustomAnnotationExample();
           MedicalViewer medicalViewer = myForm.Viewer;
           MedicalViewerMultiCell cell = (MedicalViewerMultiCell)(medicalViewer.Cells[0]);

           cell.AddAction((MedicalViewerActionType)101);
           cell.SetAction((MedicalViewerActionType)101, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
           cell.DeclareActionAsAnnotation((MedicalViewerActionType)101, typeof(MyTriangleObject));
           cell.CustomAnnotationDataRequested += new EventHandler<MedicalViewerCustomAnnotationArgs>(cell_CustomAnnotationDataRequested);

           myForm.ShowDialog();
        }

        void cell_CustomAnnotationDataRequested(object sender, MedicalViewerCustomAnnotationArgs e)
        {
           switch (e.RequestedObject)
           {
              case MedicalViewerCustomAnnotationRequestedObject.AnnotationObject:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                 {
                    MyTriangleObject triangle = new MyTriangleObject();
                    triangle.Pen = new AnnPen(Color.Blue, new AnnLength(3, AnnUnit.Pixel));
                    e.AnnotationObject = triangle;
                 }
                 break;
              case MedicalViewerCustomAnnotationRequestedObject.DrawDesigner:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                    e.DrawDesigner = new MyTriangleObjectDrawDesigner();
                 break;
              case MedicalViewerCustomAnnotationRequestedObject.EditDesigner:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                    e.EditDesigner = new MyTriangleObjectEditDesigner();
                 break;
           }
        }



        //
        // Triangle annotation object class
        // This class will have a 3 points for a triangle objects that can be stroked with a pen and filled with a brush
        //

        [Serializable] // our class must be serializable to play well with the annotation load/save and undo/redo features
        public class MyTriangleObject :
           AnnObject        // must derive from AnnObject or one of its derived classes
        {
           //
           // our private variables
           //

           // the three points that define our triangle
           [NonSerialized()]
           private AnnPoint _firstPoint;
           [NonSerialized()]
           private AnnPoint _secondPoint;
           [NonSerialized()]
           private AnnPoint _thirdPoint;

           //
           // constructor
           //


           public MyTriangleObject()
              :
              base(
              true,    // yes, we require a pen
              true,    // yes, we require a brush
              false)   // no, we do not require a font
           {
              // initialize the points

              _firstPoint = AnnPoint.Empty;
              _secondPoint = AnnPoint.Empty;
              _thirdPoint = AnnPoint.Empty;
           }

           //
           // ISerializable implementation
           //


           protected MyTriangleObject(SerializationInfo info, StreamingContext context)
              :
              base(info, context)  // do not forget to call the base class version
           {
              // we need to deserialize our private variables here
              _firstPoint = (AnnPoint)info.GetValue("FirstPointName", typeof(AnnPoint));
              _secondPoint = (AnnPoint)info.GetValue("SecondPointName", typeof(AnnPoint));
              _thirdPoint = (AnnPoint)info.GetValue("ThirdPointName", typeof(AnnPoint));
           }

           public override void GetObjectData(SerializationInfo info, StreamingContext context)
           {
              // we need to serialize our private variables here

              // call the base class version
              base.GetObjectData(info, context);

              // serialize the points
              info.AddValue("FirstPointName", _firstPoint, typeof(AnnPoint));
              info.AddValue("SecondPointName", _secondPoint, typeof(AnnPoint));
              info.AddValue("ThirdPointName", _thirdPoint, typeof(AnnPoint));
           }

           //
           // accessors to the points
           //


           public AnnPoint FirstPoint
           {
              get
              {
                 return _firstPoint;
              }

              set
              {
                 _firstPoint = value;
              }
           }

           public AnnPoint SecondPoint
           {
              get
              {
                 return _secondPoint;
              }

              set
              {
                 _secondPoint = value;
              }
           }

           public AnnPoint ThirdPoint
           {
              get
              {
                 return _thirdPoint;
              }

              set
              {
                 _thirdPoint = value;
              }
           }

           //
           // AnnObject overrides
           //


           protected override AnnObject Create()
           {
              // must return a new instance of our class
              return new MyTriangleObject();
           }

           public override object Clone()
           {
              // override the clone method

              // first call the base implementation
              MyTriangleObject obj = base.Clone() as MyTriangleObject;

              // next, copy the points
              obj.FirstPoint = FirstPoint;
              obj.SecondPoint = SecondPoint;
              obj.ThirdPoint = ThirdPoint;

              return obj;
           }

           public override GraphicsPath GetGraphicsPath(AnnGetGraphicsPathMode mode)
           {
              // must a return a graphics path representation of our object
              // Note: this object does not require us to override AnnObject.DrawObject since we can
              // use a graphics path to represents the object completely.

              // create a new graphics path
              GraphicsPath path = new GraphicsPath();

              // add the triangle points as a series of lines

              // convert the points to pixels PointF
              PointF[] pts =
         {
            FirstPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(),
            SecondPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(),
            ThirdPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF()
         };

              path.AddLines(pts);
              path.CloseFigure();

              return path;
           }

           public override void ResetRotatePoints()
           {
              // Place the rotate center control point in the center of the triangle
              float CenterX = (FirstPoint.X + SecondPoint.X + ThirdPoint.X) / 3;
              float CenterY = (FirstPoint.Y + SecondPoint.Y + ThirdPoint.Y) / 3;
              RotateCenter = new AnnPoint(CenterX, CenterY);

              // Place the RotateGripper along a line from the center of the triangle through a vertex
              float cx = FirstPoint.X - RotateCenter.X;
              float cy = FirstPoint.Y - RotateCenter.Y;

              float dist = (float)Math.Sqrt(cx * cx + cy * cy);
              float fract = 1;
              if (dist != 0)
                 fract = (Math.Abs(dist) + Math.Abs(GripperDistance)) / dist;
              float GripperX = CenterX + fract * cx;
              float GripperY = CenterY + fract * cy;
              RotateGripper = new AnnPoint(GripperX, GripperY);
           }
        }



        //
        // MyTriangleObject draw designer
        // Will require the user to click 3 times once for each point
        //


        public class MyTriangleObjectDrawDesigner :
           AnnDrawDesigner      // must derive from AnnDrawDesigner or one of its derived classes
        {
           //
           // private variables
           //

           // we need to keep track on next point to add
           private int _clickCount;

           //
           // constructor
           //

           public MyTriangleObjectDrawDesigner()
           {
              _clickCount = 0;
           }

           //
           // AnnDrawDesigner overrides
           //


           public override bool MouseDown(MouseEventArgs e)
           {
              bool handled = false;

              // only process left button clicks
              if (e.Button == MouseButtons.Left)
              {
                 // check if we have not started drawing yet, DrawObject will be null
                 if (DrawObject == null)
                 {
                    // yes, create a new MyTriangleObject from ObjectTemplate
                    MyTriangleObject obj = ObjectTemplate.Clone() as MyTriangleObject;

                    // setup the points
                    AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);
                    obj.FirstPoint = pt;
                    obj.SecondPoint = pt;
                    obj.ThirdPoint = pt;

                    // start drawing this new object
                    StartWorking(obj);
                    handled = true;

                    // we processed first click
                    _clickCount++;
                 }
                 else
                 {
                    // an object is already being drawn, so process next click

                    // get our object and assign next point to it

                    MyTriangleObject obj = DrawObject as MyTriangleObject;

                    AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);

                    if (_clickCount == 1)
                    {
                       // second point
                       obj.SecondPoint = pt;
                       _clickCount++;
                       handled = true;
                    }
                    else if (_clickCount == 2)
                    {
                       // third point
                       obj.ThirdPoint = pt;
                       handled = true;

                       // we are done!
                       EndWorking();
                    }
                 }
              }
              else
              {
                 // we want to cancel the drawing if any other button has been clicked
                 if (DrawObject != null)
                 {
                    Cancel();
                    handled = true;
                 }
              }

              return handled;
           }

           public override bool MouseMove(MouseEventArgs e)
           {
              bool handled = false;

              // check if we are already drawing an object
              if (DrawObject != null)
              {
                 // yes, get this object and assign the next point

                 // first, save the old invalid rectangle
                 Rectangle rcOld = DrawObject.InvalidRectangle;

                 // get out object and assign the point
                 MyTriangleObject obj = DrawObject as MyTriangleObject;

                 AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);

                 if (_clickCount == 1)
                    obj.SecondPoint = pt;
                 else if (_clickCount == 2)
                    obj.ThirdPoint = pt;

                 // get the new invalid rectangle
                 Rectangle rcNew = DrawObject.InvalidRectangle;

                 // continue drawing this object
                 Working(Rectangle.Union(rcOld, rcNew));
                 handled = true;
              }

              return handled;
           }

           public override bool MouseUp(MouseEventArgs e)
           {
              // we do not need to do anything special on mouse up.
              // so just see if we are drawing to return true (we handled it)

              bool handled = false;

              if (DrawObject == null)
                 handled = true;

              return handled;
           }
        }


        //
        // MyTriangleObject edit designer
        // User can click on any of the points and move them around as well as clicking and dragging the object itself.
        //


        public class MyTriangleObjectEditDesigner :
           AnnEditDesigner      // must derive from AnnEditDesigner or one of its derived classes
        {
           //
           // constructor
           //

           public MyTriangleObjectEditDesigner()
           {
           }

           //
           // AnnEditDesigner overrides
           //


           public override int ControlPointCount
           {
              get
              {
                 // return the number of control points we need
                 // in this case 3, one for each point in our triangle
                 return 3;
              }
           }

           public override AnnPoint[] GetControlPointsLocation()
           {
              // return the position of these control points
              // in this case, same as the points from our object
              MyTriangleObject obj = EditObject as MyTriangleObject;
              return new AnnPoint[]
            {
               obj.FirstPoint,
               obj.SecondPoint,
               obj.ThirdPoint
            };
           }

           protected override void MoveControlPoint(int controlPointIndex, AnnPoint pt)
           {
              // user has clicked and moved a point.
              // based on the index, we can tell if the user dragged the first, second or third point

              MyTriangleObject obj = EditObject as MyTriangleObject;
              switch (controlPointIndex)
              {
                 case 0:
                    // first point
                    obj.FirstPoint = pt.ConvertTo(Container.UnitConverter, obj.FirstPoint.Unit);
                    break;

                 case 1:
                    // second point
                    obj.SecondPoint = pt.ConvertTo(Container.UnitConverter, obj.SecondPoint.Unit);
                    break;

                 case 2:
                    // third point
                    obj.ThirdPoint = pt.ConvertTo(Container.UnitConverter, obj.ThirdPoint.Unit);
                    break;
              }
           }

           // Note, we will not override Move or MoveName since the default implementation is good enough for our object
        }


        static class LEAD_VARS
        {
        public const string ImagesDir = @"C:\Users\Public\Documents\LEADTOOLS Images";
        }

        using Leadtools;
        using Leadtools.Drawing;
        using Leadtools.Codecs;
        using Leadtools.MedicalViewer;
        using Leadtools.ImageProcessing;
        using Leadtools.Annotations;

        class MedicalViewerCustomAnnotationForm : Form
        {
           private MedicalViewer _medicalViewer;
           void MedicalViewerForm_SizeChanged(object sender, EventArgs e)
           {
              _medicalViewer.Size = new Size(this.ClientRectangle.Right, this.ClientRectangle.Bottom);
           }

           public MedicalViewerCustomAnnotationForm()
           {
              RasterCodecs _codecs = new RasterCodecs();
              RasterImage _image;

              this.SizeChanged += new EventHandler(MedicalViewerForm_SizeChanged);

              // Create the medical viewer and adjust the size and the location.
              _medicalViewer = new MedicalViewer(1, 2);
              _medicalViewer.Location = new Point(0, 0);
              _medicalViewer.Size = new Size(this.ClientRectangle.Right, this.ClientRectangle.Bottom);

              // Load an image and then add it to the control.
              _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir,"xa.dcm"));
              MedicalViewerMultiCell cell = new MedicalViewerMultiCell(_image, true, 1, 1);
              // add some actions that will be used to change the properties of the images inside the control.
              cell.AddAction(MedicalViewerActionType.WindowLevel);
              cell.AddAction(MedicalViewerActionType.Scale);
              cell.AddAction(MedicalViewerActionType.Offset);

              // assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
              cell.SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
              cell.SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active);
              cell.SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active);

              _medicalViewer.Cells.Add(cell);

              // adjust some properties of the cell and add some tags.
              _medicalViewer.Cells[0].SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448");
              _medicalViewer.Cells[0].SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame);
              _medicalViewer.Cells[0].SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale);
              _medicalViewer.Cells[0].SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData);
              _medicalViewer.Cells[0].SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView);


              // Load another image and then add it to the control.
              _image = _codecs.Load(Path.Combine(LEAD_VARS.ImagesDir,"mr.dcm"));
              _medicalViewer.Cells.Add(new MedicalViewerMultiCell(_image, true, 2, 2));

              // add some actions that will be used to change the properties of the images inside the control.
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.WindowLevel);
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.Scale);
              _medicalViewer.Cells[1].AddAction(MedicalViewerActionType.Offset);

              // assign the added actions to a mouse button, meaning that when the user clicks and drags the mouse button, the associated action will be activated.
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.WindowLevel, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.Scale, MedicalViewerMouseButtons.Middle, MedicalViewerActionFlags.Active);
              _medicalViewer.Cells[1].SetAction(MedicalViewerActionType.Offset, MedicalViewerMouseButtons.Right, MedicalViewerActionFlags.Active);

              // adjust some properties of the cell and add some tags.
              _medicalViewer.Cells[1].SetTag(2, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.UserData, "EX. ID 230-36-5448");
              _medicalViewer.Cells[1].SetTag(4, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Frame);
              _medicalViewer.Cells[1].SetTag(6, MedicalViewerTagAlignment.TopLeft, MedicalViewerTagType.Scale);
              _medicalViewer.Cells[1].SetTag(2, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.WindowLevelData);
              _medicalViewer.Cells[1].SetTag(1, MedicalViewerTagAlignment.BottomLeft, MedicalViewerTagType.FieldOfView);


              Controls.Add(_medicalViewer);
              _medicalViewer.Dock = DockStyle.Fill;
           }
           public MedicalViewer Viewer
           {
              get { return _medicalViewer; }
           }
        }
        MedicalViewerCustomAnnotationForm GetMedicalControlForCustomAnnotationExample()
        {
           return new MedicalViewerCustomAnnotationForm();
        }


        public void MedicalViewerCustomAnnotationExample()
        {
           MedicalViewerCustomAnnotationForm myForm = GetMedicalControlForCustomAnnotationExample();
           MedicalViewer medicalViewer = myForm.Viewer;
           MedicalViewerMultiCell cell = (MedicalViewerMultiCell)(medicalViewer.Cells[0]);

           cell.AddAction((MedicalViewerActionType)101);
           cell.SetAction((MedicalViewerActionType)101, MedicalViewerMouseButtons.Left, MedicalViewerActionFlags.Active);
           cell.DeclareActionAsAnnotation((MedicalViewerActionType)101, typeof(MyTriangleObject));
           cell.CustomAnnotationDataRequested += new EventHandler<MedicalViewerCustomAnnotationArgs>(cell_CustomAnnotationDataRequested);

           myForm.ShowDialog();
        }

        void cell_CustomAnnotationDataRequested(object sender, MedicalViewerCustomAnnotationArgs e)
        {
           switch (e.RequestedObject)
           {
              case MedicalViewerCustomAnnotationRequestedObject.AnnotationObject:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                 {
                    MyTriangleObject triangle = new MyTriangleObject();
                    triangle.Pen = new AnnPen(Color.Blue, new AnnLength(3, AnnUnit.Pixel));
                    e.AnnotationObject = triangle;
                 }
                 break;
              case MedicalViewerCustomAnnotationRequestedObject.DrawDesigner:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                    e.DrawDesigner = new MyTriangleObjectDrawDesigner();
                 break;
              case MedicalViewerCustomAnnotationRequestedObject.EditDesigner:
                 if (e.AnnotationAction == (MedicalViewerActionType)101)
                    e.EditDesigner = new MyTriangleObjectEditDesigner();
                 break;
           }
        }



        //
        // Triangle annotation object class
        // This class will have a 3 points for a triangle objects that can be stroked with a pen and filled with a brush
        //

        [Serializable] // our class must be serializable to play well with the annotation load/save and undo/redo features
        public class MyTriangleObject :
           AnnObject        // must derive from AnnObject or one of its derived classes
        {
           //
           // our private variables
           //

           // the three points that define our triangle
           [NonSerialized()]
           private AnnPoint _firstPoint;
           [NonSerialized()]
           private AnnPoint _secondPoint;
           [NonSerialized()]
           private AnnPoint _thirdPoint;

           //
           // constructor
           //


           public MyTriangleObject()
              :
              base(
              true,    // yes, we require a pen
              true,    // yes, we require a brush
              false)   // no, we do not require a font
           {
              // initialize the points

              _firstPoint = AnnPoint.Empty;
              _secondPoint = AnnPoint.Empty;
              _thirdPoint = AnnPoint.Empty;
           }

           //
           // ISerializable implementation
           //


           protected MyTriangleObject(SerializationInfo info, StreamingContext context)
              :
              base(info, context)  // do not forget to call the base class version
           {
              // we need to deserialize our private variables here
              _firstPoint = (AnnPoint)info.GetValue("FirstPointName", typeof(AnnPoint));
              _secondPoint = (AnnPoint)info.GetValue("SecondPointName", typeof(AnnPoint));
              _thirdPoint = (AnnPoint)info.GetValue("ThirdPointName", typeof(AnnPoint));
           }

           public override void GetObjectData(SerializationInfo info, StreamingContext context)
           {
              // we need to serialize our private variables here

              // call the base class version
              base.GetObjectData(info, context);

              // serialize the points
              info.AddValue("FirstPointName", _firstPoint, typeof(AnnPoint));
              info.AddValue("SecondPointName", _secondPoint, typeof(AnnPoint));
              info.AddValue("ThirdPointName", _thirdPoint, typeof(AnnPoint));
           }

           //
           // accessors to the points
           //


           public AnnPoint FirstPoint
           {
              get
              {
                 return _firstPoint;
              }

              set
              {
                 _firstPoint = value;
              }
           }

           public AnnPoint SecondPoint
           {
              get
              {
                 return _secondPoint;
              }

              set
              {
                 _secondPoint = value;
              }
           }

           public AnnPoint ThirdPoint
           {
              get
              {
                 return _thirdPoint;
              }

              set
              {
                 _thirdPoint = value;
              }
           }

           //
           // AnnObject overrides
           //


           protected override AnnObject Create()
           {
              // must return a new instance of our class
              return new MyTriangleObject();
           }

           public override object Clone()
           {
              // override the clone method

              // first call the base implementation
              MyTriangleObject obj = base.Clone() as MyTriangleObject;

              // next, copy the points
              obj.FirstPoint = FirstPoint;
              obj.SecondPoint = SecondPoint;
              obj.ThirdPoint = ThirdPoint;

              return obj;
           }

           public override GraphicsPath GetGraphicsPath(AnnGetGraphicsPathMode mode)
           {
              // must a return a graphics path representation of our object
              // Note: this object does not require us to override AnnObject.DrawObject since we can
              // use a graphics path to represents the object completely.

              // create a new graphics path
              GraphicsPath path = new GraphicsPath();

              // add the triangle points as a series of lines

              // convert the points to pixels PointF
              PointF[] pts =
         {
            FirstPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(),
            SecondPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF(),
            ThirdPoint.ConvertTo(UnitConverter, AnnUnit.Pixel).ToPointF()
         };

              path.AddLines(pts);
              path.CloseFigure();

              return path;
           }

           public override void ResetRotatePoints()
           {
              // Place the rotate center control point in the center of the triangle
              float CenterX = (FirstPoint.X + SecondPoint.X + ThirdPoint.X) / 3;
              float CenterY = (FirstPoint.Y + SecondPoint.Y + ThirdPoint.Y) / 3;
              RotateCenter = new AnnPoint(CenterX, CenterY);

              // Place the RotateGripper along a line from the center of the triangle through a vertex
              float cx = FirstPoint.X - RotateCenter.X;
              float cy = FirstPoint.Y - RotateCenter.Y;

              float dist = (float)Math.Sqrt(cx * cx + cy * cy);
              float fract = 1;
              if (dist != 0)
                 fract = (Math.Abs(dist) + Math.Abs(GripperDistance)) / dist;
              float GripperX = CenterX + fract * cx;
              float GripperY = CenterY + fract * cy;
              RotateGripper = new AnnPoint(GripperX, GripperY);
           }
        }



        //
        // MyTriangleObject draw designer
        // Will require the user to click 3 times once for each point
        //


        public class MyTriangleObjectDrawDesigner :
           AnnDrawDesigner      // must derive from AnnDrawDesigner or one of its derived classes
        {
           //
           // private variables
           //

           // we need to keep track on next point to add
           private int _clickCount;

           //
           // constructor
           //

           public MyTriangleObjectDrawDesigner()
           {
              _clickCount = 0;
           }

           //
           // AnnDrawDesigner overrides
           //


           public override bool MouseDown(MouseEventArgs e)
           {
              bool handled = false;

              // only process left button clicks
              if (e.Button == MouseButtons.Left)
              {
                 // check if we have not started drawing yet, DrawObject will be null
                 if (DrawObject == null)
                 {
                    // yes, create a new MyTriangleObject from ObjectTemplate
                    MyTriangleObject obj = ObjectTemplate.Clone() as MyTriangleObject;

                    // setup the points
                    AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);
                    obj.FirstPoint = pt;
                    obj.SecondPoint = pt;
                    obj.ThirdPoint = pt;

                    // start drawing this new object
                    StartWorking(obj);
                    handled = true;

                    // we processed first click
                    _clickCount++;
                 }
                 else
                 {
                    // an object is already being drawn, so process next click

                    // get our object and assign next point to it

                    MyTriangleObject obj = DrawObject as MyTriangleObject;

                    AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);

                    if (_clickCount == 1)
                    {
                       // second point
                       obj.SecondPoint = pt;
                       _clickCount++;
                       handled = true;
                    }
                    else if (_clickCount == 2)
                    {
                       // third point
                       obj.ThirdPoint = pt;
                       handled = true;

                       // we are done!
                       EndWorking();
                    }
                 }
              }
              else
              {
                 // we want to cancel the drawing if any other button has been clicked
                 if (DrawObject != null)
                 {
                    Cancel();
                    handled = true;
                 }
              }

              return handled;
           }

           public override bool MouseMove(MouseEventArgs e)
           {
              bool handled = false;

              // check if we are already drawing an object
              if (DrawObject != null)
              {
                 // yes, get this object and assign the next point

                 // first, save the old invalid rectangle
                 Rectangle rcOld = DrawObject.InvalidRectangle;

                 // get out object and assign the point
                 MyTriangleObject obj = DrawObject as MyTriangleObject;

                 AnnPoint pt = GetLogicalAnnPoint(e.X, e.Y, obj.FirstPoint.Unit);

                 if (_clickCount == 1)
                    obj.SecondPoint = pt;
                 else if (_clickCount == 2)
                    obj.ThirdPoint = pt;

                 // get the new invalid rectangle
                 Rectangle rcNew = DrawObject.InvalidRectangle;

                 // continue drawing this object
                 Working(Rectangle.Union(rcOld, rcNew));
                 handled = true;
              }

              return handled;
           }

           public override bool MouseUp(MouseEventArgs e)
           {
              // we do not need to do anything special on mouse up.
              // so just see if we are drawing to return true (we handled it)

              bool handled = false;

              if (DrawObject == null)
                 handled = true;

              return handled;
           }
        }


        //
        // MyTriangleObject edit designer
        // User can click on any of the points and move them around as well as clicking and dragging the object itself.
        //


        public class MyTriangleObjectEditDesigner :
           AnnEditDesigner      // must derive from AnnEditDesigner or one of its derived classes
        {
           //
           // constructor
           //

           public MyTriangleObjectEditDesigner()
           {
           }

           //
           // AnnEditDesigner overrides
           //


           public override int ControlPointCount
           {
              get
              {
                 // return the number of control points we need
                 // in this case 3, one for each point in our triangle
                 return 3;
              }
           }

           public override AnnPoint[] GetControlPointsLocation()
           {
              // return the position of these control points
              // in this case, same as the points from our object
              MyTriangleObject obj = EditObject as MyTriangleObject;
              return new AnnPoint[]
            {
               obj.FirstPoint,
               obj.SecondPoint,
               obj.ThirdPoint
            };
           }

           protected override void MoveControlPoint(int controlPointIndex, AnnPoint pt)
           {
              // user has clicked and moved a point.
              // based on the index, we can tell if the user dragged the first, second or third point

              MyTriangleObject obj = EditObject as MyTriangleObject;
              switch (controlPointIndex)
              {
                 case 0:
                    // first point
                    obj.FirstPoint = pt.ConvertTo(Container.UnitConverter, obj.FirstPoint.Unit);
                    break;

                 case 1:
                    // second point
                    obj.SecondPoint = pt.ConvertTo(Container.UnitConverter, obj.SecondPoint.Unit);
                    break;

                 case 2:
                    // third point
                    obj.ThirdPoint = pt.ConvertTo(Container.UnitConverter, obj.ThirdPoint.Unit);
                    break;
              }
           }

           // Note, we will not override Move or MoveName since the default implementation is good enough for our object
        }


        static class LEAD_VARS
        {
        public const string ImagesDir = @"C:\Users\Public\Documents\LEADTOOLS Images";
        }

Inheritance Hierarchy

System.Object
   System.ValueType
      System.Enum
         Leadtools.MedicalViewer.MedicalViewerCustomAnnotationRequestedObject

Requirements

Target Platforms

See Also

Reference

Leadtools.MedicalViewer Namespace

 

 


Products | Support | Contact Us | Copyright Notices
© 2006-2014 All Rights Reserved. LEAD Technologies, Inc.

Leadtools.MedicalViewer requires a Medical Imaging license and unlock key. For more information, refer to: Imaging Pro/Document/Medical Features