/*============================================================================= Project: SharpImage Module: siPointsSelection.cs Language: C# Author: Dan Mueller Date: $Date: 2007-07-06 10:57:00 +1000 (Fri, 06 Jul 2007) $ Revision: $Revision: 2 $ Copyright (c) Queensland University of Technology (QUT) 2007. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =============================================================================*/ using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Windows.Forms; using System.Diagnostics; using SharpImage.Main; using SharpImage.Properties; namespace SharpImage.Rendering { public class siPointsSelection : siSelection { #region Instance Variables //===================================================================== //========================================================================= #endregion #region Construction and Disposal //===================================================================== /// /// Public constuctor. /// public siPointsSelection() : base() { } //===================================================================== #endregion #region Properties //===================================================================== #region Points and Indicies //===================================================================== private List m_Points = new List(); /// /// Gets the list of points. /// public List Points { get { return this.m_Points; } } /// /// Get the list of indicies. /// /// public List GetIndicies(itk.itkImageBase input) { List result = new List(); foreach (itk.itkPoint point in this.Points) { itk.itkIndex index; input.TransformPhysicalPointToIndex(point, out index); result.Add(index); } return result; } //===================================================================== #endregion #region InAdditionMode //===================================================================== private bool m_InAdditionMode = false; /// /// Gets if the actor is in point addition mode, /// allowing the user to add new points. /// public bool InAdditionMode { get { return this.m_InAdditionMode; } } /// /// Allows the actor to add points. /// public void EnterAdditionMode() { this.m_InAdditionMode = true; } /// /// Stops the actor from adding points. /// public void ExitAdditionMode() { this.m_InAdditionMode = false; this.RaiseExitedAdditionMode(); } //===================================================================== #endregion #region GenerateMaskImageFilterType //===================================================================== /// /// Returns the GenerateMaskImageFilter "Point" type. /// public override string GenerateMaskImageFilterType { get { return "Point"; } } //===================================================================== #endregion #region TypeName //===================================================================== /// /// Returns a the type name of the selection. /// public override string TypeName { get { return "Points"; } } //===================================================================== #endregion //===================================================================== #endregion #region Events //===================================================================== public delegate void siPointsHandler(siPointsSelection sender, itk.itkPoint point); private siPointsHandler m_EventStorage_PointAdded; private siPointsHandler m_EventStorage_PointSelected; private siActorHandler m_EventStorage_ExitedAdditionMode; /// /// An event raised when the user adds a point. /// public event siPointsHandler PointAdded { add { this.m_EventStorage_PointAdded += value; } remove { this.m_EventStorage_PointAdded -= value; } } /// /// An event raised when the user selects an existing point. /// public event siPointsHandler PointSelected { add { this.m_EventStorage_PointSelected += value; } remove { this.m_EventStorage_PointSelected -= value; } } /// /// An event raised when the user exits addition mode. /// public event siActorHandler ExitedAdditionMode { add { this.m_EventStorage_ExitedAdditionMode += value; } remove { this.m_EventStorage_ExitedAdditionMode -= value; } } /// /// Raises the PointAdded event. /// /// private void RaisePointAdded(itk.itkPoint point) { if (this.m_EventStorage_PointAdded != null) { this.m_EventStorage_PointAdded(this, point); this.RaiseModified(); } } /// /// Raises the PointSelected event. /// /// private void RaisePointSelected(itk.itkPoint point) { if (this.m_EventStorage_PointSelected != null) { this.m_EventStorage_PointSelected(this, point); this.RaiseModified(); } } /// /// Raises the ExitedAdditionMode event. /// private void RaiseExitedAdditionMode() { if (this.m_EventStorage_ExitedAdditionMode != null) { this.m_EventStorage_ExitedAdditionMode(this); this.RaiseModified(); } } //===================================================================== #endregion #region Public Methods //===================================================================== /// /// Changes the currently selected point. /// The point value can be null to unselect all point. /// If the point is not currently included as a landmark, no points are selected. /// /// public void SelectPoint(itk.itkPoint point) { this.Metadata["SelectedPoint"] = point; this.RaiseModified(); } /// /// Removes the given point from the list. /// /// public void RemovePoint(itk.itkPoint point) { this.Points.Remove(point); this.RaiseModified(); } /// /// Removes all the points from the list /// public void ClearPoints() { this.Points.Clear(); this.RaiseModified(); } /// /// Returns a string representation of the selection. /// public override string ToString() { return "Points: " + this.Points.Count.ToString(); } //===================================================================== #endregion #region Actor Methods //===================================================================== /// /// Allows the actor to render itself. /// /// protected override void OnPaint(siRenderer renderer, PaintEventArgs e) { if (renderer is siGdiSliceRenderer) this.OnPaint(renderer as siGdiSliceRenderer, e); else this.ThrowNotSupported("The given renderer is not supported."); } /// /// Allows the actor to render itself to an siGdiSliceRenderer. /// /// /// protected void OnPaint(siGdiSliceRenderer renderer, PaintEventArgs e) { // Set to draw smooth Graphics g = e.Graphics; g.SmoothingMode = SmoothingMode.AntiAlias; // Setup for rendering the seed location itk.itkImageBase input = this.GetInputAsImage(renderer); if (input == null) return; Pen pen = new Pen(new SolidBrush(Color.Red), 1.0F); const float width = 9.0F; const float widthHalf = width / 2.0F; float crossLength = (widthHalf / (float)Math.Cos(Math.PI / 4.0)) / 2.0F; // Enumerate the point list foreach (itk.itkPoint point in this.Points) { // Pass the point through the inverse direction transform itk.itkPoint pointT = renderer.DirectionTransformInversePoint(point); // Convert the point to an index itk.itkIndex indexT; input.TransformPhysicalPointToIndex(pointT, out indexT); // Check the point is visible at the moment if (indexT.Dimension == 2 || (indexT.Dimension == 3 && renderer.Slice == indexT[2])) { // Get info for drawing index PointF pointScreen = renderer.TransformImageIndexToScreenPoint(indexT, true); // Check if the index is selected if (this.Metadata.ContainsKey("SelectedPoint") && (this.Metadata["SelectedPoint"] as itk.itkPoint) == point) { // Draw larger circle around selected point RectangleF rectSelected = new RectangleF(pointScreen.X - widthHalf - 2.0F, pointScreen.Y - widthHalf - 2.0F, width + 4.0F, width + 4.0F); g.DrawArc(pen, rectSelected, 0.0F, 360.0F); } // Draw RectangleF rect = new RectangleF(pointScreen.X - widthHalf, pointScreen.Y - widthHalf, width, width); g.DrawArc(pen, rect, 0.0F, 360.0F); g.DrawLine(pen, pointScreen.X - crossLength, pointScreen.Y - crossLength, pointScreen.X + crossLength, pointScreen.Y + crossLength); g.DrawLine(pen, pointScreen.X - crossLength, pointScreen.Y + crossLength, pointScreen.X + crossLength, pointScreen.Y - crossLength); } } // End enumerate points } /// /// Allows the actor to consume the MouseDown event. /// /// protected override bool OnMouseDown(siRenderer renderer, MouseEventArgs e) { if (renderer is siGdiSliceRenderer) return this.OnMouseDown(renderer as siGdiSliceRenderer, e); else throw new NotSupportedException("The given renderer is not supported."); } /// /// Allows the actor to consume the MouseDown event for an siGdiSliceRenderer. /// /// /// /// protected bool OnMouseDown(siGdiSliceRenderer renderer, MouseEventArgs e) { // Check the Renderer has all the required Metadata variables if (!renderer.ContainsMetadata("IsMouseInsideImageSpace", "LastImagePointMouseDown")) return false; // Only allow selections inside the image if (!(bool)renderer.Metadata["IsMouseInsideImageSpace"]) return false; // Check the mode if (this.InAdditionMode && e.Button == MouseButtons.Left) { // Add the point itk.itkImageBase input = this.GetInputAsImage(renderer); itk.itkPoint pointToAdd = (itk.itkPoint)renderer.Metadata["LastImagePointMouseDown"]; itk.itkPoint pointToAddT = renderer.DirectionTransformPoint(pointToAdd); // Check the point is not already added to the list foreach (itk.itkPoint pointInList in this.Points) { if (pointToAddT == pointInList) { // Select this seed this.Metadata["SelectedPoint"] = pointToAddT; this.RaisePointSelected(pointToAddT); return true; } } // Add the point to the list, it is unique this.Points.Add(pointToAddT); this.Metadata["SelectedPoint"] = pointToAddT; this.RaisePointAdded(pointToAddT); return true; } else if (this.InAdditionMode && e.Button == MouseButtons.Right) { // Exit addition mode this.ExitAdditionMode(); return true; } return false; } //===================================================================== #endregion } }