/*=============================================================================
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
}
}