/*============================================================================= Project: SharpImage Module: siTransferFunctionPartOval.cs Language: C# Author: Dan Mueller Date: $Date: 2008-01-11 14:55:13 +1000 (Fri, 11 Jan 2008) $ Revision: $Revision: 30 $ 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.Drawing; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Drawing.Drawing2D; namespace SharpImage.Rendering { public class siTransferFunctionPartOval : siTransferFunctionPart { #region Constants //===================================================================== private const float CONTROL_POINT_WIDTH = 6.0F; private const float CONTROL_POINT_HEIGHT = 6.0F; //===================================================================== #endregion #region Instance Variables //===================================================================== //===================================================================== #endregion #region Construction and Disposal //===================================================================== /// /// Default constructor. This part will be drawn on all layers. /// public siTransferFunctionPartOval() : this(null, null) { } /// /// Constructor taking a layer key. /// /// Uses the parent.Image for creating a default sized part. /// The name of layer this part is to be drawn on. public siTransferFunctionPartOval(siTransferFunction parent, string layer) : base(layer) { // Create a default rectangle if (parent != null) { float x = (float)parent.Image.Size[0] / 4F; float y = (float)parent.Image.Size[1] / 4F; float w = (float)parent.Image.Size[0] / 2F; float h = (float)parent.Image.Size[1] / 2F; this.BoundingBox = new RectangleF(x, y, w, h); } } //===================================================================== #endregion #region Properties //===================================================================== #region ControlPoints //===================================================================== /// /// Get the control points. This property accessor builds the list /// from private member information each time it is called. /// [System.ComponentModel.Browsable(false)] [System.Xml.Serialization.XmlIgnore] public override RectangleF[] ControlPoints { get { RectangleF[] result = new RectangleF[8]; // Create corner control points result[0] = new RectangleF(this.BoundingBox.X + this.BoundingBox.Width / 2.0F - CONTROL_POINT_WIDTH / 2.0F, this.BoundingBox.Y - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[2] = new RectangleF(this.BoundingBox.X + this.BoundingBox.Width - CONTROL_POINT_WIDTH / 2.0F, this.BoundingBox.Y + this.BoundingBox.Height / 2.0F - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[4] = new RectangleF(this.BoundingBox.X + this.BoundingBox.Width / 2.0F - CONTROL_POINT_WIDTH / 2.0F, this.BoundingBox.Y + this.BoundingBox.Height - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[6] = new RectangleF(this.BoundingBox.X - CONTROL_POINT_WIDTH / 2.0F, this.BoundingBox.Y + this.BoundingBox.Height / 2.0F - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); // Create control points on ellipse float x = (this.BoundingBox.Width / 2.0F) * (float)Math.Cos(Math.PI / 4.0); float y = (this.BoundingBox.Height / 2.0F) * (float)Math.Sin(Math.PI / 4.0); result[1] = new RectangleF((this.BoundingBox.X + this.BoundingBox.Width / 2.0F) + x - CONTROL_POINT_WIDTH / 2.0F, (this.BoundingBox.Y + this.BoundingBox.Height / 2.0F) - y - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[3] = new RectangleF((this.BoundingBox.X + this.BoundingBox.Width / 2.0F) - x - CONTROL_POINT_WIDTH / 2.0F, (this.BoundingBox.Y + this.BoundingBox.Height / 2.0F) + y - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[5] = new RectangleF((this.BoundingBox.X + this.BoundingBox.Width / 2.0F) + x - CONTROL_POINT_WIDTH / 2.0F, (this.BoundingBox.Y + this.BoundingBox.Height / 2.0F) + y - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[7] = new RectangleF((this.BoundingBox.X + this.BoundingBox.Width / 2.0F) - x - CONTROL_POINT_WIDTH / 2.0F, (this.BoundingBox.Y + this.BoundingBox.Height / 2.0F) - y - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); // Return return result; } } //===================================================================== #endregion #region Falloff //============================================================================ private Single m_Falloff = 0.2F; /// /// Gets/sets the falloff location (clamped between 0.0 and 1.0). /// 0.0 is at the edge, 1.0 is the center. /// [System.ComponentModel.Browsable(true)] [System.ComponentModel.Category("Color")] public Single Falloff { get { return this.m_Falloff; } set { this.m_Falloff = value; if (this.m_Falloff < 0.0F) this.m_Falloff = 0.0F; if (this.m_Falloff > 1.0F) this.m_Falloff = 1.0F; this.RaiseModified(); } } //============================================================================ #endregion //===================================================================== #endregion #region Public Methods //===================================================================== public override string ToString() { return "Oval: " + this.Layer + " " + this.BackColor.ToString() + " " + this.BoundingBox.ToString(); } //===================================================================== #endregion #region Paint Methods //===================================================================== protected override void OnPaintFillFunction(siTransferFunction parent, siTransferFunctionPaintEventArgs e) { //Brush brushFill = new SolidBrush(this.BackColor); GraphicsPath path = new GraphicsPath(); path.AddArc(this.BoundingBox, 0.0F, 360.0F); PathGradientBrush brushFill = new PathGradientBrush(path); //brushFill.CenterPoint = new PointF(this.BoundingBoxX + this.BoundingBoxWidth / 2.0F, this.BoundingBoxY + this.BoundingBoxHeight / 2.0F); brushFill.CenterColor = this.BackColor; brushFill.SurroundColors = new Color[] { Color.Transparent }; Blend blend = new Blend(3); blend.Positions = new float[] { 0.0F, this.Falloff, 1.0F }; blend.Factors = new float[] { 0.0F, 1.0F, 1.0F }; brushFill.Blend = blend; e.Graphics.FillEllipse(brushFill, this.BoundingBox); path.Dispose(); } protected override void OnPaintControlPoints(siTransferFunction parent, siTransferFunctionPaintEventArgs e) { // Set smoothing mode to none SmoothingMode oldSmoothingMode = e.Graphics.SmoothingMode; e.Graphics.SmoothingMode = SmoothingMode.None; // Paint the control points SolidBrush brushFill = new SolidBrush(CONTROL_POINT_COLOR_FILL); SolidBrush brushOutline = new SolidBrush(CONTROL_POINT_COLOR_OUTLINE); Pen penOutline = new Pen(brushOutline, CONTROL_POINT_PEN_WIDTH); foreach (RectangleF cpt in this.ControlPoints) { e.Graphics.FillRectangle(brushFill, cpt); e.Graphics.DrawRectangle(penOutline, cpt.X, cpt.Y, cpt.Width, cpt.Height); } // Reset smoothing mode e.Graphics.SmoothingMode = oldSmoothingMode; } protected override void OnPaintBoundingBox(siTransferFunction parent, siTransferFunctionPaintEventArgs e) { Pen penOutline = null; if (this.Enabled) penOutline = new Pen(BOUNDING_BOX_COLOR_OUTLINE_ENABLED, PEN_WIDTH); else penOutline = new Pen(BOUNDING_BOX_COLOR_OUTLINE_DISABLED, PEN_WIDTH); e.Graphics.DrawEllipse(penOutline, this.BoundingBox); } protected override void OnPaintInformation(siTransferFunction parent, siTransferFunctionPaintEventArgs e) { Brush brush = new SolidBrush(Color.Black); //Brush brushShadow = new SolidBrush(Color.White); Font font = new Font("Arial", 8.0F, FontStyle.Bold); String info = this.ConstructInformationString(true, e); SizeF sizeInfo = e.Graphics.MeasureString(info, font); PointF pointInfo = new PointF(this.BoundingBox.X + this.BoundingBox.Width / 2.0F - sizeInfo.Width / 2.0F, this.BoundingBox.Y + this.BoundingBox.Height / 2.0F - sizeInfo.Height / 2.0F); e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; // Only draw the info if the height will not cut off the info string if (sizeInfo.Height <= (this.BoundingBox.Height - 2 * INFO_OFFSET) && sizeInfo.Width <= (this.BoundingBox.Width - 2 * INFO_OFFSET)) { //e.Graphics.DrawString(info, font, brushShadow, pointInfo.X + 0.5F, pointInfo.Y + 0.5F); e.Graphics.DrawString(info, font, brush, pointInfo.X, pointInfo.Y); return; } // Adjust the info string info = this.ConstructInformationString(false, e); sizeInfo = e.Graphics.MeasureString(info, font); pointInfo = new PointF(this.BoundingBox.X + this.BoundingBox.Width / 2.0F - sizeInfo.Width / 2.0F, this.BoundingBox.Y + this.BoundingBox.Height / 2.0F - sizeInfo.Height / 2.0F); // Only draw the info if the height will not cut off the info string if (sizeInfo.Height <= (this.BoundingBox.Height - 2 * INFO_OFFSET) && sizeInfo.Width <= (this.BoundingBox.Width - 2 * INFO_OFFSET)) { //e.Graphics.DrawString(info, font, brushShadow, pointInfo.X + 0.5F, pointInfo.Y + 0.5F); e.Graphics.DrawString(info, font, brush, pointInfo.X, pointInfo.Y); return; } } //===================================================================== #endregion #region Mouse Methods //===================================================================== /// /// Get the cursor for the given control point index. /// /// /// protected override Cursor GetControlPointCursor(int cpIndex) { switch (cpIndex) { case 0: return Cursors.SizeNS; case 1: return Cursors.SizeNESW; case 2: return Cursors.SizeWE; case 3: return Cursors.SizeNESW; case 4: return Cursors.SizeNS; case 5: return Cursors.SizeNWSE; case 6: return Cursors.SizeWE; case 7: return Cursors.SizeNWSE; default: return Cursors.Default; } } //===================================================================== #endregion #region Translate and Resize Methods //===================================================================== /// /// Translates the part by the given amount. /// /// public override void Translate(siTransferFunction parent, PointF translate) { // Translate the rectangle m_BoundingBox.X += translate.X; m_BoundingBox.Y += translate.Y; // Check the translation will keep rectangle inside the parent transfer function if (m_BoundingBox.X + m_BoundingBox.Width >= parent.Image.Size[0]) m_BoundingBox.X = parent.Image.Size[0] - m_BoundingBox.Width - 1f; if (m_BoundingBox.Y + m_BoundingBox.Height >= parent.Image.Size[1]) m_BoundingBox.Y = parent.Image.Size[1] - m_BoundingBox.Height - 1f; // Check the index is inside the image if (m_BoundingBox.X < 0F) m_BoundingBox.X = 0F; if (m_BoundingBox.Y < 0F) m_BoundingBox.Y = 0F; if (m_BoundingBox.X > parent.Image.Size[0]) m_BoundingBox.X = parent.Image.Size[0] - 1; if (m_BoundingBox.Y > parent.Image.Size[1]) m_BoundingBox.Y = parent.Image.Size[1] - 1; this.RaiseModified(); } /// /// Resize the part by the given amount. /// /// public override void Resize(siTransferFunction parent, PointF change) { switch ((int)this.Metadata["CurrentControlPointIndex"]) { case 0: m_BoundingBox.Y += change.Y; m_BoundingBox.Height -= change.Y; break; case 1: m_BoundingBox.Width += change.X; m_BoundingBox.Y += change.Y; m_BoundingBox.Height -= change.Y; break; case 2: m_BoundingBox.Width += change.X; break; case 3: m_BoundingBox.Height += change.Y; m_BoundingBox.X += change.X; m_BoundingBox.Width -= change.X; break; case 4: m_BoundingBox.Height += change.Y; break; case 5: m_BoundingBox.Width += change.X; m_BoundingBox.Height += change.Y; break; case 6: m_BoundingBox.X += change.X; m_BoundingBox.Width -= change.X; break; case 7: m_BoundingBox.X += change.X; m_BoundingBox.Y += change.Y; m_BoundingBox.Width -= change.X; m_BoundingBox.Height -= change.Y; break; } // Ensure the resize did not put rectangle outside of the image if (m_BoundingBox.X + m_BoundingBox.Width >= parent.Image.Size[0]) m_BoundingBox.Width = parent.Image.Size[0] - m_BoundingBox.X; if (m_BoundingBox.Y + m_BoundingBox.Height >= parent.Image.Size[1]) m_BoundingBox.Height = parent.Image.Size[1] - m_BoundingBox.Y; if (m_BoundingBox.X < 0) m_BoundingBox.X = 0; if (m_BoundingBox.Y < 0) m_BoundingBox.Y = 0; if (m_BoundingBox.X > parent.Image.Size[0]) m_BoundingBox.X = parent.Image.Size[0] - 1; if (m_BoundingBox.Y > parent.Image.Size[1]) m_BoundingBox.Y = parent.Image.Size[1] - 1; if (m_BoundingBox.Width < 1) m_BoundingBox.Width = 1; if (m_BoundingBox.Height < 1) m_BoundingBox.Height = 1; if (m_BoundingBox.Width >= parent.Image.Size[0]) m_BoundingBox.Width = parent.Image.Size[0] - 1; if (m_BoundingBox.Height >= parent.Image.Size[1]) m_BoundingBox.Height = parent.Image.Size[1] - 1; this.RaiseModified(); } //===================================================================== #endregion } }