/*=============================================================================
Project: SharpImage
Module: siCircleSelection.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;
namespace SharpImage.Rendering
{
public class siCircleSelection : siShapeSelection
{
#region Construction and Disposal
//=====================================================================
///
/// Protected default constructor.
///
protected siCircleSelection() : base()
{
// Set the extrusion type
this.ShapeType = ShapeTypeEnum.Object;
// Setup the initial Metadata
this.Metadata["IsTranslating"] = false;
this.Metadata["IsResizing"] = false;
this.Metadata["IsMouseOverControlPoint"] = false;
this.Metadata["IsMouseOverSelection"] = false;
this.Metadata["CurrentControlPointIndex"] = -1;
this.Metadata["MouseDownCenterOffset"] = new itk.itkVector(3U);
}
///
/// Public constuctor, which adds a circular selction to the given image.
///
/// The initial center of the selection.
/// The initial radius of the selection.
public siCircleSelection(itk.itkPoint center, float radius) : this()
{
// Setup the initial member variables
this.m_Center = center;
this.m_Radius = radius;
// Compute the default start and end points (for an extrusion object)
this.ExtrusionDimension = 2;
this.ExtrusionStartPoint = this.Center[2] - this.Radius / 2.0F;
this.ExtrusionEndPoint = this.Center[2] + this.Radius / 2.0F;
}
///
/// Public constuctor, which adds a circular selction to the center of the given image.
///
/// Uses the size and spacing of the image to compute the center.
public siCircleSelection(itk.itkImageBase input) : this()
{
// Compute the default radius
double radius = input.PhysicalSize[0] / 5.0;
this.m_Radius = (float)Math.Ceiling(radius);
// Compute the default center of the image
this.m_Center = new itk.itkPoint(input.Dimension);
for (int i = 0; i < input.Dimension; i++)
this.m_Center[i] = input.PhysicalSize[i] / 2.0 + input.Origin[i];
// Compute the default start and end points (for an extrusion object)
if (input.Dimension == 3)
{
this.ExtrusionDimension = 2;
this.ExtrusionStartPoint = this.Center[2] - input.PhysicalSize[2] / 5.0;
this.ExtrusionEndPoint = this.Center[2] + input.PhysicalSize[2] / 5.0;
}
}
//=====================================================================
#endregion
#region Properties
//=====================================================================
private itk.itkPoint m_Center = null;
private float m_Radius = 0;
///
/// Get/set the center of the circle selection (in physical space).
/// On set, the Modified event will be raised.
///
public itk.itkPoint Center
{
get { return this.m_Center; }
set
{
this.m_Center = value;
this.RaiseModified();
}
}
///
/// Get/set the radius of the circular selection (in physical space).
/// We assume that the spacing in the X and Y directions are
/// equal or close.
///
public float Radius
{
get { return this.m_Radius; }
set
{
this.m_Radius = value;
this.RaiseModified();
}
}
///
/// Gets a string describing the selection type.
/// "Circle" for 2D images, "Sphere" for 3D objects,
/// and "Cylinder" for 3D extrusions.
///
public override string TypeName
{
get
{
String result = "Circle";
if (this.ShapeType == ShapeTypeEnum.Object &&
this.Center.Dimension == 3)
result = "Sphere";
else if (this.ShapeType == ShapeTypeEnum.Extrusion &&
this.Center.Dimension == 3)
result = "Cylinder";
return result;
}
}
///
/// Returns the GenerateMaskImageFilter "Ellipse" type.
///
public override string GenerateMaskImageFilterType
{
get { return "Ellipse"; }
}
#region Start/End Extrusion Point
//=====================================================================
private double m_ExtrusionDistanceFromCenter = 0.0;
///
/// Gets/sets the starting point along the secondary plane for the extrusion.
///
public override double ExtrusionStartPoint
{
get
{
return this.Center[2] - this.m_ExtrusionDistanceFromCenter;
}
set
{
this.m_ExtrusionDistanceFromCenter = value + this.Center[2];
this.RaiseModified();
}
}
///
/// Gets/sets the ending point along the secondary plane for the extrusion.
///
public override double ExtrusionEndPoint
{
get
{
return this.Center[2] + this.m_ExtrusionDistanceFromCenter;
}
set
{
this.m_ExtrusionDistanceFromCenter = value - this.Center[2];
this.RaiseModified();
}
}
//=====================================================================
#endregion
//=====================================================================
#endregion
#region Public Methods
//=====================================================================
///
/// Return a string representing the selection.
///
///
public override string ToString()
{
String result = this.TypeName + ": ";
if (this.ShapeType == ShapeTypeEnum.Object)
{
result += "Center=" + this.Center.ToString() + " ";
result += "Radius=" + this.Radius.ToString("0.0");
}
else if (this.ShapeType == ShapeTypeEnum.Extrusion)
{
itk.itkPoint center = new itk.itkPoint(this.Center[0], this.Center[1]);
itk.itkPoint size = new itk.itkPoint(this.ExtrusionStartPoint, this.ExtrusionEndPoint);
result += "Center=" + center.ToString() + " ";
result += "Size=" + size.ToString() + " ";
result += "Radius=" + this.Radius.ToString("0.0");
}
return result;
}
//=====================================================================
#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.
///
///
protected void OnPaint(siGdiSliceRenderer renderer, PaintEventArgs e)
{
// Set to draw smooth
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
switch (this.ShapeType)
{
case ShapeTypeEnum.Object:
this.OnPaintObject(renderer, e);
break;
case ShapeTypeEnum.Extrusion:
this.OnPaintExtrusion(renderer, e);
break;
}
}
///
/// Renderer the circular selection as an object (a circle in 2D or a
/// sphere in 3D).
///
///
protected void OnPaintObject(siGdiSliceRenderer renderer, PaintEventArgs e)
{
// Get the graphics handle
Graphics g = e.Graphics;
// Pass the center through the direction transform
itk.itkImageBase input = this.GetInputAsImage(renderer);
if (input == null) return;
itk.itkPoint pointCenterT = renderer.DirectionTransformInversePoint(this.Center);
itk.itkIndex indexCenterT;
input.TransformPhysicalPointToIndex(pointCenterT, out indexCenterT);
// Convert center to screen index
PointF screenCenter = renderer.TransformImagePointToScreenPoint(input, pointCenterT);
// Convert radius to this slice and then screen coordinates
float radiusSlice = this.ComputeRadiusAtSlicePlane(renderer, input, indexCenterT);
float diameterSlice = 2.0F * radiusSlice;
// Only render if the radius is valid
if (radiusSlice <= 0.0F)
return;
// Draw fill
SolidBrush brushFill = new SolidBrush(COLOR_FILL);
float x = screenCenter.X - radiusSlice;
float y = screenCenter.Y - radiusSlice;
g.FillEllipse(brushFill, x, y, diameterSlice, diameterSlice);
// Draw outline
SolidBrush brushOutline = new SolidBrush(COLOR_OUTLINE);
Pen penOutline = new Pen(brushOutline, PEN_OUTLINE_WIDTH);
g.DrawEllipse(penOutline, x, y, diameterSlice, diameterSlice);
// Draw control points
SolidBrush brushControlFill = new SolidBrush(COLOR_CONTROL_FILL);
SolidBrush brushControlOutline = new SolidBrush(COLOR_CONTROL_OUTLINE);
Pen penControlOutline = new Pen(brushControlOutline, PEN_CONTROL_OUTLINE_WIDTH);
foreach ( RectangleF controlPoint in this.GetControlPoints(renderer) )
{
g.FillRectangle(brushControlFill, controlPoint);
g.DrawRectangle(penControlOutline, controlPoint.X, controlPoint.Y, controlPoint.Width, controlPoint.Height);
}
}
///
/// Render the shape of the extruded object (a circle in this case).
///
///
protected override void OnPaintShape(siGdiSliceRenderer renderer, PaintEventArgs e)
{
// Get the graphics handle
Graphics g = e.Graphics;
// Pass the center through the direction transform
itk.itkImageBase input = this.GetInputAsImage(renderer);
if (input == null) return;
itk.itkPoint pointCenterT = renderer.DirectionTransformInversePoint(this.Center);
itk.itkIndex indexCenterT;
input.TransformPhysicalPointToIndex(pointCenterT, out indexCenterT);
// Convert center to screen index
PointF screenCenter = renderer.TransformImagePointToScreenPoint(input, pointCenterT);
// Convert the slice index to a point
itk.itkPoint pointSlice;
itk.itkIndex indexSlice = new itk.itkIndex(0, 0, renderer.Slice);
input.TransformIndexToPhysicalPoint(indexSlice, out pointSlice);
// Determine if the current slice is within the start and end range
if (pointSlice[2] < this.ExtrusionStartPoint ||
pointSlice[2] > this.ExtrusionEndPoint)
// The slice does not intersect with the shape, there is nothing to paint
return;
// Draw fill
float radius = this.ComputeRadiusAtSlicePlane(renderer, input, indexCenterT);
float diameter = 2.0F * radius;
SolidBrush brushFill = new SolidBrush(COLOR_FILL);
float x = screenCenter.X - radius;
float y = screenCenter.Y - radius;
g.FillEllipse(brushFill, x, y, diameter, diameter);
// Draw outline
SolidBrush brushOutline = new SolidBrush(COLOR_OUTLINE);
Pen penOutline = new Pen(brushOutline, PEN_OUTLINE_WIDTH);
g.DrawEllipse(penOutline, x, y, diameter, diameter);
// Draw control points
SolidBrush brushControlFill = new SolidBrush(COLOR_CONTROL_FILL);
SolidBrush brushControlOutline = new SolidBrush(COLOR_CONTROL_OUTLINE);
Pen penControlOutline = new Pen(brushControlOutline, PEN_CONTROL_OUTLINE_WIDTH);
foreach (RectangleF controlPoint in this.GetControlPoints(renderer))
{
g.FillRectangle(brushControlFill, controlPoint);
g.DrawRectangle(penControlOutline, controlPoint.X, controlPoint.Y, controlPoint.Width, controlPoint.Height);
}
}
///
/// Render the extruded object (ie. a rectangle starting at StartExtrusionIndex
/// and ending at EndExtrusionIndex, of height 2.0*this.Radius).
///
///
protected override void OnPaintExtrudedShape(siGdiSliceRenderer renderer, PaintEventArgs e)
{
// Get the graphics handle
Graphics g = e.Graphics;
// Get the rectangle
RectangleF r = this.GetExtrudedShapeScreenRectangle(renderer);
if (r == RectangleF.Empty) return;
// Get the brushes and pens
SolidBrush brushFill = new SolidBrush(COLOR_FILL);
SolidBrush brushOutline = new SolidBrush(COLOR_OUTLINE);
Pen penOutline = new Pen(brushOutline, PEN_OUTLINE_WIDTH);
// Draw outline and fill
g.DrawRectangle(penOutline, r.X, r.Y, r.Width, r.Height);
g.FillRectangle(brushFill, r.X, r.Y, r.Width, r.Height);
// Draw control points
SolidBrush brushControlFill = new SolidBrush(COLOR_CONTROL_FILL);
SolidBrush brushControlOutline = new SolidBrush(COLOR_CONTROL_OUTLINE);
Pen penControlOutline = new Pen(brushControlOutline, PEN_CONTROL_OUTLINE_WIDTH);
foreach (RectangleF controlPoint in this.GetControlPoints(renderer))
{
g.FillRectangle(brushControlFill, controlPoint);
g.DrawRectangle(penControlOutline, controlPoint.X, controlPoint.Y, controlPoint.Width, controlPoint.Height);
}
}
///
/// Allows the actor to consume the MouseMove event.
///
///
///
protected override bool OnMouseMove(siRenderer renderer, MouseEventArgs e)
{
base.OnMouseMove(renderer, e);
// Check the Renderer has all the required Metadata variables
if (!renderer.ContainsMetadata("LastImagePointMouseMove"))
return false;
// Get the location as an itkPoint
itk.itkImageBase input = this.GetInputAsImage(renderer);
itk.itkPoint pointMouseMove = (itk.itkPoint)renderer.Metadata["LastImagePointMouseMove"];
itk.itkPoint pointMouseMoveT = renderer.DirectionTransformPoint(pointMouseMove);
// Check if we are translating
if ( (bool)this.Metadata["IsTranslating"] )
{
// Translate the center of the selection
itk.itkVector vectorOffset = (itk.itkVector)this.Metadata["MouseDownCenterOffset"];
itk.itkPoint center = pointMouseMoveT + vectorOffset;
this.Center = center;
return true;
}
// Check if we are resizing
if ( (bool)this.Metadata["IsResizing"] )
{
double radius = 0.0;
if (this.ShapeType == ShapeTypeEnum.Object)
{
radius = pointMouseMoveT.EuclideanDistanceTo(this.Center);
}
else if (this.ShapeType == ShapeTypeEnum.Extrusion &&
this.IsRenderingShape(renderer, this.GetInputAsImage(renderer).Direction))
{
itk.itkPoint pointMouse2D = new itk.itkPoint(pointMouseMoveT[0], pointMouseMoveT[1]);
itk.itkPoint pointCenter2D = new itk.itkPoint(this.Center[0], this.Center[1]);
radius = pointMouse2D.EuclideanDistanceTo(pointCenter2D);
}
else if (this.ShapeType == ShapeTypeEnum.Extrusion &&
!this.IsRenderingShape(renderer, this.GetInputAsImage(renderer).Direction))
{
itk.itkPoint pointMouse2D = new itk.itkPoint(pointMouseMoveT[0], pointMouseMoveT[1]);
itk.itkPoint pointCenter2D = new itk.itkPoint(this.Center[0], this.Center[1]);
radius = pointMouse2D.EuclideanDistanceTo(pointCenter2D);
this.m_ExtrusionDistanceFromCenter = Math.Abs(this.Center[2] - pointMouseMoveT[2]);
}
this.Radius = (float)radius;
return true;
}
// Check if the mouse is over a control point
int controlPointIndex = this.IsMouseOverControlPoint(renderer, e);
if ( controlPointIndex >= 0 )
{
// Show the correct cursor
renderer.Metadata["Cursor"] = this.GetControlPointCursor(controlPointIndex);
this.Metadata["CurrentControlPointIndex"] = controlPointIndex;
this.Metadata["IsMouseOverControlPoint"] = true;
this.Metadata["IsMouseOverSelection"] = false;
return true;
}
// Check if the mouse is over the selection
if (this.IsMouseOverSelection(renderer, pointMouseMoveT))
{
renderer.Metadata["Cursor"] = Cursors.Hand;
this.Metadata["IsMouseOverControlPoint"] = false;
this.Metadata["IsMouseOverSelection"] = true;
this.Metadata["CurrentControlPointIndex"] = -1;
return true;
}
// We did not consume this event
renderer.Metadata["Cursor"] = null;
this.Metadata["IsMouseOverControlPoint"] = false;
this.Metadata["IsMouseOverSelection"] = false;
this.Metadata["CurrentControlPointIndex"] = -1;
return false;
}
///
/// Allows the actor to consume the MouseDown event.
///
///
///
protected override bool OnMouseDown(siRenderer renderer, MouseEventArgs e)
{
base.OnMouseDown(renderer, e);
// Check if we are over the selection
if ( (bool)this.Metadata["IsMouseOverSelection"] )
{
// Override image translation
renderer.Metadata["IsTranslatingImage"] = false;
// Start selection translation
this.Metadata["IsTranslating"] = true;
// Compute the center offset
itk.itkImageBase input = this.GetInputAsImage(renderer);
itk.itkPoint pointMouseDown = (itk.itkPoint)renderer.Metadata["LastImagePointMouseDown"];
itk.itkPoint pointMouseDownT = renderer.DirectionTransformPoint(pointMouseDown);
itk.itkVector vectorOffset = (this.Center - pointMouseDownT);
this.Metadata["MouseDownCenterOffset"] = vectorOffset;
return true;
}
// Check if we are over a control point
if ( (bool)this.Metadata["IsMouseOverControlPoint"] )
{
// Override other translations
renderer.Metadata["IsTranslatingImage"] = false;
this.Metadata["IsTranslating"] = false;
// Start selection resize
this.Metadata["IsResizing"] = true;
return true;
}
// We did not consume this event
return false;
}
///
/// Allows the actor to consume the MouseUp event.
///
///
///
protected override bool OnMouseUp(siRenderer renderer, MouseEventArgs e)
{
base.OnMouseUp(renderer, e);
if ((bool)this.Metadata["IsTranslating"])
{
this.Metadata["IsTranslating"] = false;
return true;
}
else if ( (bool)this.Metadata["IsResizing"] )
{
this.Metadata["IsResizing"] = false;
return true;
}
// We did not consume this event
return false;
}
//=====================================================================
#endregion
#region Private Helper Methods
//=====================================================================
///
/// Compute the radius at the given slice.
///
///
private float ComputeRadiusAtSlicePlane(siGdiSliceRenderer renderer, itk.itkImageBase input, itk.itkIndex indexCenterT)
{
// Setup for calculation
double radiusSlice = this.Radius;
// Find the difference in the current slice and the center slice
if (this.Center.Dimension == 3 && this.ShapeType == ShapeTypeEnum.Object)
{
double centerDiff = input.Spacing[2] * (indexCenterT[2] - renderer.Slice);
// Check if the selection is intersected by the current slice plane
if (centerDiff >= this.Radius || -centerDiff >= this.Radius)
// The selection is not intersected by the slice, return
radiusSlice = 0.0F;
else
// Else, compute the radius at the current slice plane
radiusSlice = Math.Sqrt(this.Radius*this.Radius - centerDiff*centerDiff);
}
// Adjust for zoom and return
return (float)((radiusSlice / input.Spacing[0]) * renderer.ZoomFactor);
}
///
/// Computes the control point rectangles for the current center and radius.
///
///
private RectangleF[] GetControlPoints(siGdiSliceRenderer renderer)
{
// Get the input
itk.itkImageBase input = this.GetInputAsImage(renderer);
// Get the control width
float widthControl = CONTROL_WIDTH * (renderer.ZoomFactor < 0.25 ? (float)renderer.ZoomFactor : 1.0F);
// The control points depend on the shape type
if (this.ShapeType == ShapeTypeEnum.Object ||
this.ShapeType == ShapeTypeEnum.Extrusion &&
this.IsRenderingShape(renderer, input.Direction))
{
// Pass the center through the direction transform
itk.itkPoint pointCenterT = renderer.DirectionTransformInversePoint(this.Center);
itk.itkIndex indexCenterT;
input.TransformPhysicalPointToIndex(pointCenterT, out indexCenterT);
// Convert center to screen index
PointF screenCenter = renderer.TransformImagePointToScreenPoint(input, pointCenterT);
// Convert radius to this slice
float radiusSlice = this.ComputeRadiusAtSlicePlane(renderer, input, indexCenterT);
float diameterSlice = 2.0F * radiusSlice;
// Setup for calculation
float offsetControl = (radiusSlice / (float)Math.Cos(Math.PI / 4.0)) / 2.0F;
// Create the control points
RectangleF[] result = new RectangleF[4];
result[0] = new RectangleF(screenCenter.X - offsetControl - widthControl / 2.0F, screenCenter.Y - offsetControl - widthControl / 2.0F, widthControl, widthControl);
result[1] = new RectangleF(screenCenter.X - offsetControl - widthControl / 2.0F, screenCenter.Y + offsetControl - widthControl / 2.0F, widthControl, widthControl);
result[2] = new RectangleF(screenCenter.X + offsetControl - widthControl / 2.0F, screenCenter.Y - offsetControl - widthControl / 2.0F, widthControl, widthControl);
result[3] = new RectangleF(screenCenter.X + offsetControl - widthControl / 2.0F, screenCenter.Y + offsetControl - widthControl / 2.0F, widthControl, widthControl);
return result;
}
else if (this.ShapeType == ShapeTypeEnum.Extrusion &&
!this.IsRenderingShape(renderer, input.Direction))
{
RectangleF r = this.GetExtrudedShapeScreenRectangle(renderer);
// Create the control points
RectangleF[] result = new RectangleF[4];
result[0] = new RectangleF(r.X - widthControl / 2.0F, r.Y - widthControl / 2.0F, widthControl, widthControl);
result[1] = new RectangleF(r.X + r.Width - widthControl / 2.0F, r.Y - widthControl / 2.0F, widthControl, widthControl);
result[2] = new RectangleF(r.X - widthControl / 2.0F, r.Y + r.Height - widthControl / 2.0F, widthControl, widthControl);
result[3] = new RectangleF(r.X + r.Width - widthControl / 2.0F, r.Y + r.Height - widthControl / 2.0F, widthControl, widthControl);
return result;
}
return new RectangleF[0];
}
///
/// Returns the index of the control point which the mouse is over.
/// Returns -1 if not over a control point.
///
///
/// The index of the control OR -1 if not over a control point.
private int IsMouseOverControlPoint(siRenderer renderer, MouseEventArgs e)
{
RectangleF[] controlPoints = this.GetControlPoints(renderer as siGdiSliceRenderer);
int index = 0;
foreach (RectangleF controlPoint in controlPoints)
{
if (controlPoint.Contains(e.Location))
return index;
index++;
}
return -1;
}
///
/// Returns if the mouse is inside the selection.
///
/// The position of the mouse in phyiscal space, transformed by the direction matrix.
///
private bool IsMouseOverSelection(siRenderer renderer, itk.itkPoint pointMouseT)
{
if (this.ShapeType == ShapeTypeEnum.Object)
{
return (this.Center.EuclideanDistanceTo(pointMouseT) <= this.Radius);
}
else if (this.ShapeType == ShapeTypeEnum.Extrusion &&
this.IsRenderingShape(renderer, this.GetInputAsImage(renderer).Direction))
{
// Create 2D center and mouse points (we ignore the secondary axis)
itk.itkPoint pointMouse2D = new itk.itkPoint(pointMouseT[0], pointMouseT[1]);
itk.itkPoint pointCenter2D = new itk.itkPoint(this.Center[0], this.Center[1]);
// Compute
return (pointCenter2D.EuclideanDistanceTo(pointMouse2D) <= this.Radius);
}
else if (this.ShapeType == ShapeTypeEnum.Extrusion &&
!this.IsRenderingShape(renderer, this.GetInputAsImage(renderer).Direction))
{
// Get the screen rectangle
RectangleF r = this.GetExtrudedShapeScreenRectangle(renderer as siGdiSliceRenderer);
if (r == RectangleF.Empty) return false;
// Use the mouse coords to determine if the mouse is over the selection
MouseEventArgs last = renderer.Metadata["LastScreenMouseMove"] as MouseEventArgs;
return r.Contains(last.Location);
}
return false;
}
///
/// Get the cursor for the given control point index.
///
///
///
private Cursor GetControlPointCursor(int controlPoint)
{
switch (controlPoint)
{
case 0: return Cursors.SizeNWSE;
case 1: return Cursors.SizeNESW;
case 2: return Cursors.SizeNESW;
case 3: return Cursors.SizeNWSE;
default: return Cursors.Default;
}
}
///
/// Gets the rectangle in screen coordinates which represents the slice of the
/// cylinder.
///
///
///
private RectangleF GetExtrudedShapeScreenRectangle(siGdiSliceRenderer renderer)
{
// Get the input image
itk.itkImageBase input = this.GetInputAsImage(renderer);
if (input == null) return RectangleF.Empty;
// Convert the slice index to physical space
itk.itkPoint pointSlice;
itk.itkIndex indexSlice = new itk.itkIndex(0, 0, renderer.Slice);
input.TransformIndexToPhysicalPoint(indexSlice, out pointSlice);
// Pass the z-axis through the direction transform
itk.itkPoint zaxis = new itk.itkPoint(0.0, 0.0, 1.0);
itk.itkPoint zaxisT = renderer.DirectionTransformInversePoint(zaxis);
// Pass the center through the direction transform
itk.itkPoint pointCenterT = renderer.DirectionTransformInversePoint(this.Center);
// Create the rectangle in physical space (from the view of the primary axis)
itk.itkPoint pointCenterTop = new itk.itkPoint(this.Center[0], this.Center[1], this.ExtrusionStartPoint);
itk.itkPoint pointCenterBottom = new itk.itkPoint(this.Center[0], this.Center[1], this.ExtrusionEndPoint);
itk.itkPoint pointCenterTopT = renderer.DirectionTransformInversePoint(pointCenterTop);
itk.itkPoint pointCenterBottomT = renderer.DirectionTransformInversePoint(pointCenterBottom);
// Compute the radius, and check this slice intersects with the shape
double radius = this.Radius - Math.Abs(pointCenterTopT[2] - pointSlice[2]);
if (radius <= 0.0) return RectangleF.Empty;
// Draw the extruded rectangle
if (zaxisT[0] != 0.0)
{
// Adjust for the radius
pointCenterTopT[1] += radius;
pointCenterBottomT[1] -= radius;
}
else if (zaxisT[1] != 0.0)
{
// Adjust for the radius
pointCenterTopT[0] += radius;
pointCenterBottomT[0] -= radius;
}
// Convert to screen coords
PointF pointCenterTopScreen = renderer.TransformImagePointToScreenPoint(input, pointCenterTopT);
PointF pointCenterBottomScreen = renderer.TransformImagePointToScreenPoint(input, pointCenterBottomT);
// Construct and return the rectangle
float x = pointCenterBottomScreen.X;
float y = pointCenterBottomScreen.Y;
float w = Math.Abs(pointCenterBottomScreen.X - pointCenterTopScreen.X);
float h = Math.Abs(pointCenterBottomScreen.Y - pointCenterTopScreen.Y);
return new RectangleF(x, y, w, h);
}
//=====================================================================
#endregion
}
}