/*============================================================================= Project: SharpImage Module: siTransferFunctionPartRectangle.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.Drawing; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Drawing.Drawing2D; namespace SharpImage.Rendering { public class siTransferFunctionPartRectangle : siTransferFunctionPart { #region Constants //===================================================================== protected const float CONTROL_POINT_WIDTH = 6.0F; protected 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 siTransferFunctionPartRectangle() : 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 siTransferFunctionPartRectangle(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[4]; result[0] = new RectangleF(this.BoundingBox.X - CONTROL_POINT_WIDTH / 2.0F, this.BoundingBox.Y - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[1] = new RectangleF(this.BoundingBox.X + this.BoundingBox.Width - 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 - CONTROL_POINT_WIDTH / 2.0F, this.BoundingBox.Y + this.BoundingBox.Height - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); result[3] = new RectangleF(this.BoundingBox.X + this.BoundingBox.Width - CONTROL_POINT_WIDTH / 2.0F, this.BoundingBox.Y + this.BoundingBox.Height - CONTROL_POINT_WIDTH / 2.0F, CONTROL_POINT_WIDTH, CONTROL_POINT_HEIGHT); return result; } } //===================================================================== #endregion #region Falloff //============================================================================ private Single m_Falloff = 0.0F; /// /// Gets/sets the falloff location (clamped between 0.0 and 0.5). /// 0.0 is at the edge, 0.5 is the center. /// [System.ComponentModel.Browsable(true)] [System.ComponentModel.Category("Color")] public virtual 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 > 0.5F) this.m_Falloff = 0.5F; this.RaiseModified(); } } //============================================================================ #endregion //===================================================================== #endregion #region Public Methods //===================================================================== public override string ToString() { return "Rectangle: " + 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); LinearGradientBrush brushFill = new LinearGradientBrush(this.BoundingBox, Color.Transparent, this.BackColor, LinearGradientMode.Horizontal); brushFill.LinearColors = new Color[] { Color.Transparent, this.BackColor, this.BackColor, Color.Transparent }; Blend blend = new Blend(4); blend.Positions = new float[] { 0.0F, this.Falloff, 1.0F - this.Falloff, 1.0F }; blend.Factors = new float[] { 0.0F, 1.0F, 1.0F, 0.0F }; brushFill.Blend = blend; e.Graphics.FillRectangle(brushFill, this.BoundingBox); } 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); RectangleF[] cpts = this.ControlPoints; for (int i = 0; i < 4; i++) { e.Graphics.FillRectangle(brushFill, cpts[i]); e.Graphics.DrawRectangle(penOutline, cpts[i].X, cpts[i].Y, cpts[i].Width, cpts[i].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.DrawRectangle(penOutline, this.BoundingBox.X, this.BoundingBox.Y, this.BoundingBox.Width, this.BoundingBox.Height); } //===================================================================== #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.SizeNWSE; case 1: return Cursors.SizeNESW; case 2: return Cursors.SizeNESW; case 3: 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; if (m_BoundingBox.Y + m_BoundingBox.Height > parent.Image.Size[1]) m_BoundingBox.Y = parent.Image.Size[1] - m_BoundingBox.Height; // 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]; if (m_BoundingBox.Y > parent.Image.Size[1]) m_BoundingBox.Y = parent.Image.Size[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.X += change.X; m_BoundingBox.Y += change.Y; m_BoundingBox.Width -= change.X; 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.Height += change.Y; m_BoundingBox.X += change.X; m_BoundingBox.Width -= change.X; break; case 3: 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]; if (m_BoundingBox.Y > parent.Image.Size[1]) m_BoundingBox.Y = parent.Image.Size[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]; if (m_BoundingBox.Height > parent.Image.Size[1]) m_BoundingBox.Height = parent.Image.Size[1]; this.RaiseModified(); } //===================================================================== #endregion } }