PieSlice.cs
Description du code
PieSlice.cs est un fichier du projet BrolDev.Ce fichier est situé dans /var/www/bin/sniplets/bibliobrol/broldev/src/.
Projet BrolDev : Librairie de composants réutilisables pour les applications BrolDev en CSharp.
Code source ou contenu du fichier
Code c# (PieSlice.cs) (1218 lignes)
using System; using System.Collections; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; namespace be.gaudry.model.drawing.chart { /// <summary> /// Object representing 3D pie. /// </summary> public class PieSlice : IDisposable, ICloneable { /// <summary> /// Initializes an empty instance of <c>PieSlice</c>. /// </summary> protected PieSlice() : base() { } /// <summary> /// Initializes a new instance of flat <c>PieSlice</c> class with given /// bounds and visual style. /// </summary> /// <param name="xBoundingRect"> /// x-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="yBoundingRect"> /// y-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="widthBoundingRect"> /// Width of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="heightBoundingRect"> /// Height of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="startAngle"> /// Starting angle (in degrees) of the pie slice. /// </param> /// <param name="sweepAngle"> /// Sweep angle (in degrees) of the pie slice. /// </param> /// <param name="surfaceColor"> /// Color used to paint the pie slice. /// </param> public PieSlice(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, float startAngle, float sweepAngle, Color surfaceColor) : this (xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, 0F, startAngle, sweepAngle, surfaceColor, ShadowStyle.NoShadow, EdgeColorType.NoEdge) { } /// <summary> /// Initializes a new instance of <c>PieSlice</c> class with given /// bounds and visual style. /// </summary> /// <param name="xBoundingRect"> /// x-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="yBoundingRect"> /// y-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="widthBoundingRect"> /// Width of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="heightBoundingRect"> /// Height of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="sliceHeight"> /// Height of the pie slice. /// </param> /// <param name="startAngle"> /// Starting angle (in degrees) of the pie slice. /// </param> /// <param name="sweepAngle"> /// Sweep angle (in degrees) of the pie slice. /// </param> /// <param name="surfaceColor"> /// Color used to paint the pie slice. /// </param> /// <param name="shadowStyle"> /// Shadow style used for slice rendering. /// </param> /// <param name="edgeColorType"> /// Edge color style used for slice rendering. /// </param> public PieSlice(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, float sliceHeight, float startAngle, float sweepAngle, Color surfaceColor, ShadowStyle shadowStyle, EdgeColorType edgeColorType) : this() { // set some persistent values m_actualStartAngle = startAngle; m_actualSweepAngle = sweepAngle; m_surfaceColor = surfaceColor; m_shadowStyle = shadowStyle; m_edgeColorType = edgeColorType; // create pens for rendering Color edgeLineColor = EdgeColor.GetRenderingColor(edgeColorType, surfaceColor); m_pen.LineJoin = LineJoin.Round; InitializePieSlice(xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, sliceHeight); } /// <summary> /// Initializes a new instance of <c>PieSlice</c> class with given /// bounds and visual style. /// </summary> /// <param name="boundingRect"> /// Bounding rectangle used to draw the top surface of the slice. /// </param> /// <param name="sliceHeight"> /// Pie slice height. /// </param> /// <param name="startAngle"> /// Starting angle (in degrees) of the pie slice. /// </param> /// <param name="sweepAngle"> /// Sweep angle (in degrees) of the pie slice. /// </param> /// <param name="surfaceColor"> /// Color used to render pie slice surface. /// </param> /// <param name="shadowStyle"> /// Shadow style used in rendering. /// </param> /// <param name="edgeColorType"> /// Edge color type used for rendering. /// </param> public PieSlice(RectangleF boundingRect, float sliceHeight, float startAngle, float sweepAngle, Color surfaceColor, ShadowStyle shadowStyle, EdgeColorType edgeColorType) : this(boundingRect.X, boundingRect.Y, boundingRect.Width, boundingRect.Height, sliceHeight, startAngle, sweepAngle, surfaceColor, shadowStyle, edgeColorType) { } /// <summary> /// Initializes a new instance of <c>PieSlice</c> class with given /// bounds and visual style. /// </summary> /// <param name="xBoundingRect"> /// x-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="yBoundingRect"> /// y-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="widthBoundingRect"> /// Width of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="heightBoundingRect"> /// Height of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="sliceHeight"> /// Height of the pie slice. /// </param> /// <param name="startAngle"> /// Starting angle (in degrees) of the pie slice. /// </param> /// <param name="sweepAngle"> /// Sweep angle (in degrees) of the pie slice. /// </param> /// <param name="surfaceColor"> /// Color used to render pie slice surface. /// </param> /// <param name="shadowStyle"> /// Shadow style used in rendering. /// </param> /// <param name="edgeColorType"> /// Edge color type used for rendering. /// </param> /// <param name="edgeLineWidth"> /// Edge line width. /// </param> public PieSlice(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, float sliceHeight, float startAngle, float sweepAngle, Color surfaceColor, ShadowStyle shadowStyle, EdgeColorType edgeColorType, float edgeLineWidth) : this (xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, sliceHeight, startAngle, sweepAngle, surfaceColor, shadowStyle, edgeColorType) { m_pen.Width = edgeLineWidth; } /// <summary> /// Initializes a new instance of <c>PieSlice</c> class with given /// bounds and visual style. /// </summary> /// <param name="boundingRect"> /// Bounding rectangle used to draw the top surface of the pie slice. /// </param> /// <param name="sliceHeight"> /// Pie slice height. /// </param> /// <param name="startAngle"> /// Starting angle (in degrees) of the pie slice. /// </param> /// <param name="sweepAngle"> /// Sweep angle (in degrees) of the pie slice. /// </param> /// <param name="surfaceColor"> /// Color used to render pie slice surface. /// </param> /// <param name="shadowStyle"> /// Shadow style used in rendering. /// </param> /// <param name="edgeColorType"> /// Edge color type used for rendering. /// </param> /// <param name="edgeLineWidth"> /// Edge line width. /// </param> public PieSlice(Rectangle boundingRect, float sliceHeight, float startAngle, float sweepAngle, Color surfaceColor, ShadowStyle shadowStyle, EdgeColorType edgeColorType, float edgeLineWidth) : this(boundingRect.X, boundingRect.Y, boundingRect.Width, boundingRect.Height, sliceHeight, startAngle, sweepAngle, surfaceColor, shadowStyle, edgeColorType, edgeLineWidth) { } /// <summary> /// <c>Finalize</c> implementation /// </summary> ~PieSlice() { Dispose(false); } /// <summary> /// Implementation of <c>IDisposable</c> interface. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Disposes of all resources used by <c>PieSlice</c> object. /// </summary> /// <param name="disposing"></param> protected virtual void Dispose(bool disposing) { if (!m_disposed) { if (disposing) { Debug.Assert(m_pen != null); m_pen.Dispose(); DisposeBrushes(); Debug.Assert(m_startSide != null); m_startSide.Dispose(); Debug.Assert(m_endSide != null); m_endSide.Dispose(); } m_disposed = true; } } /// <summary> /// Implementation of ICloneable interface. /// </summary> /// <returns> /// A deep copy of this object. /// </returns> public object Clone() { return new PieSlice(BoundingRectangle, SliceHeight, StartAngle, SweepAngle, m_surfaceColor, m_shadowStyle, m_edgeColorType); } /// <summary> /// Gets starting angle (in degrees) of the pie slice. /// </summary> public float StartAngle { get { return m_startAngle; } } /// <summary> /// Gets sweep angle (in degrees) of the pie slice. /// </summary> public float SweepAngle { get { return m_sweepAngle; } } /// <summary> /// Gets ending angle (in degrees) of the pie slice. /// </summary> public float EndAngle { get { return (m_startAngle + m_sweepAngle) % 360; } } public string Text { get { return m_text; } set { m_text = value; } } /// <summary> /// Draws the pie slice. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> public void Draw(Graphics graphics) { DrawBottom(graphics); DrawSides(graphics); DrawTop(graphics); } /// <summary> /// Checks if given pie slice contains given point. /// </summary> /// <param name="point"> /// <c>PointF</c> to check. /// </param> /// <returns> /// <c>true</c> if point given is contained within the slice. /// </returns> public bool Contains(PointF point) { if (PieSliceContainsPoint(point)) return true; if (PeripheryContainsPoint(point)) return true; if (m_startSide.Contains(point)) return true; if (m_endSide.Contains(point)) return true; return false; } /// <summary> /// Evaluates the point in the middle of the slice. /// </summary> /// <returns> /// <c>PointF</c> in the middle of the pie top. /// </returns> public virtual PointF GetTextPosition() { if (SweepAngle >= 180) return PeripheralPoint(m_center.X, m_center.Y, m_boundingRectangle.Width / 3, m_boundingRectangle.Height / 3, GetActualAngle(StartAngle) + SweepAngle / 2); float x = (m_pointStart.X + m_pointEnd.X) / 2; float y = (m_pointStart.Y + m_pointEnd.Y) / 2; float angle = (float)(Math.Atan2(y - m_center.Y, x - m_center.X) * 180 / Math.PI); return PeripheralPoint(m_center.X, m_center.Y, m_boundingRectangle.Width / 3, m_boundingRectangle.Height / 3, GetActualAngle(angle)); } /// <summary> /// Gets or sets the bounding rectangle. /// </summary> internal RectangleF BoundingRectangle { get { return m_boundingRectangle; } set { m_boundingRectangle = value; } } /// <summary> /// Gets or sets the slice height. /// </summary> internal float SliceHeight { get { return m_sliceHeight; } set { m_sliceHeight = value; } } /// <summary> /// Draws pie slice sides. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawSides(Graphics graphics) { DrawHiddenPeriphery(graphics); // draw wegde sides if (StartAngle > 90 && StartAngle < 270) { DrawEndSide(graphics); DrawStartSide(graphics); } else { DrawStartSide(graphics); DrawEndSide(graphics); } DrawVisiblePeriphery(graphics); } /// <summary> /// Splits a pie slice into two on the split angle. /// </summary> /// <param name="splitAngle"> /// Angle at which splitting is performed. /// </param> /// <returns> /// An array of two pie slices. /// </returns> internal PieSlice[] Split(float splitAngle) { // if split angle equals one of bounding angles, then nothing to split if (StartAngle == splitAngle || this.EndAngle == splitAngle) float transformedSplitAngle = TransformAngle(splitAngle); float actualStartAngle = GetActualAngle(StartAngle); float newSweepAngle = (splitAngle - actualStartAngle + 360) % 360; PieSlice pieSlice1 = new PieSlice(BoundingRectangle, SliceHeight, actualStartAngle, newSweepAngle, m_surfaceColor, m_shadowStyle, m_edgeColorType); pieSlice1.InitializeSides(true, false); newSweepAngle = GetActualAngle(EndAngle) - splitAngle; PieSlice pieSlice2 = new PieSlice(BoundingRectangle, SliceHeight, splitAngle, newSweepAngle, m_surfaceColor, m_shadowStyle, m_edgeColorType); pieSlice2.InitializeSides(false, true); } /// <summary> /// Reajusts the pie slice to fit new bounding rectangle provided. /// </summary> /// <param name="xBoundingRect"> /// x-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="yBoundingRect"> /// y-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="widthBoundingRect"> /// Width of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="heightBoundingRect"> /// Height of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="sliceHeight"> /// Height of the pie slice. /// </param> internal void Readjust(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, float sliceHeight) { InitializePieSlice(xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect, sliceHeight); } /// <summary> /// Draws visible start side. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawStartSide(Graphics graphics) { if (m_startSide != null) { // checks if the side is visible if (StartAngle > 90 && StartAngle < 270) m_startSide.Draw(graphics, m_pen, m_brushStartSide); else m_startSide.Draw(graphics, m_pen, m_brushSurface); } } /// <summary> /// Draws visible end side. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawEndSide(Graphics graphics) { if (m_endSide != null) { // checks if the side is visible if (EndAngle > 90 && EndAngle < 270) m_endSide.Draw(graphics, m_pen, m_brushSurface); else m_endSide.Draw(graphics, m_pen, m_brushEndSide); } } /// <summary> /// Draws visible outer periphery of the pie slice. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawVisiblePeriphery(Graphics graphics) { PeripherySurfaceBounds[] peripherySurfaceBounds = GetVisiblePeripherySurfaceBounds(); foreach (PeripherySurfaceBounds surfaceBounds in peripherySurfaceBounds) { DrawCylinderSurfaceSection(graphics, m_pen, m_brushPeripherySurface, surfaceBounds.StartAngle, surfaceBounds.EndAngle, surfaceBounds.StartPoint, surfaceBounds.EndPoint); } } /// <summary> /// Draws hidden outer periphery of the pie slice. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawHiddenPeriphery(Graphics graphics) { PeripherySurfaceBounds[] peripherySurfaceBounds = GetHiddenPeripherySurfaceBounds(); foreach (PeripherySurfaceBounds surfaceBounds in peripherySurfaceBounds) { DrawCylinderSurfaceSection(graphics, m_pen, m_brushSurface, surfaceBounds.StartAngle, surfaceBounds.EndAngle, surfaceBounds.StartPoint, surfaceBounds.EndPoint); } } /// <summary> /// Draws the bottom of the pie slice. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawBottom(Graphics graphics) { graphics.FillPie(m_brushSurface, m_boundingRectangle.X, m_boundingRectangle.Y + m_sliceHeight, m_boundingRectangle.Width, m_boundingRectangle.Height, m_startAngle, m_sweepAngle); graphics.DrawPie(m_pen, m_boundingRectangle.X, m_boundingRectangle.Y + m_sliceHeight, m_boundingRectangle.Width, m_boundingRectangle.Height, m_startAngle, m_sweepAngle); } /// <summary> /// Draws the top of the pie slice. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> used to draw the pie slice. /// </param> internal void DrawTop(Graphics graphics) { graphics.FillPie(m_brushSurface, m_boundingRectangle.X, m_boundingRectangle.Y, m_boundingRectangle.Width, m_boundingRectangle.Height, m_startAngle, m_sweepAngle); graphics.DrawPie(m_pen, m_boundingRectangle, m_startAngle, m_sweepAngle); } /// <summary> /// Calculates the smallest rectangle into which this pie slice fits. /// </summary> /// <returns> /// <c>RectangleF</c> into which this pie slice fits exactly. /// </returns> internal RectangleF GetFittingRectangle() { if ((m_startAngle == 0F) || (m_startAngle + m_sweepAngle >= 360)) GraphicsUtil.IncludePointX(ref boundingRectangle, m_boundingRectangle.Right); if ((m_startAngle <= 90) && (m_startAngle + m_sweepAngle >= 90) || (m_startAngle + m_sweepAngle >= 450)) GraphicsUtil.IncludePointY(ref boundingRectangle, m_boundingRectangle.Bottom + SliceHeight); if ((m_startAngle <= 180) && (m_startAngle + m_sweepAngle >= 180) || (m_startAngle + m_sweepAngle >= 540)) GraphicsUtil.IncludePointX(ref boundingRectangle, m_boundingRectangle.Left); if ((m_startAngle <= 270) && (m_startAngle + m_sweepAngle >= 270) || (m_startAngle + m_sweepAngle >= 630)) GraphicsUtil.IncludePointY(ref boundingRectangle, m_boundingRectangle.Top); GraphicsUtil.IncludePoint(ref boundingRectangle, m_center); GraphicsUtil.IncludePoint(ref boundingRectangle, m_centerBelow); GraphicsUtil.IncludePoint(ref boundingRectangle, m_pointStart); GraphicsUtil.IncludePoint(ref boundingRectangle, m_pointStartBelow); GraphicsUtil.IncludePoint(ref boundingRectangle, m_pointEnd); GraphicsUtil.IncludePoint(ref boundingRectangle, m_pointEndBelow); return boundingRectangle; } /// <summary> /// Checks if given point is contained inside the pie slice. /// </summary> /// <param name="point"> /// <c>PointF</c> to check for. /// </param> /// <returns> /// <c>true</c> if given point is inside the pie slice. /// </returns> internal bool PieSliceContainsPoint(PointF point) { return PieSliceContainsPoint(point, m_boundingRectangle.X, m_boundingRectangle.Y, m_boundingRectangle.Width, m_boundingRectangle.Height, m_startAngle, m_sweepAngle); } /// <summary> /// Checks if given point is contained by cylinder periphery. /// </summary> /// <param name="point"> /// <c>PointF</c> to check for. /// </param> /// <returns> /// <c>true</c> if given point is inside the cylinder periphery. /// </returns> internal bool PeripheryContainsPoint(PointF point) { PeripherySurfaceBounds[] peripherySurfaceBounds = GetVisiblePeripherySurfaceBounds(); foreach (PeripherySurfaceBounds surfaceBounds in peripherySurfaceBounds) { if (CylinderSurfaceSectionContainsPoint(point, surfaceBounds.StartAngle, surfaceBounds.EndAngle, surfaceBounds.StartPoint, surfaceBounds.EndPoint)) return true; } return false; } /// <summary> /// Checks if point provided is inside pie slice start cut side. /// </summary> /// <param name="point"> /// <c>PointF</c> to check. /// </param> /// <returns> /// <c>true</c> if point is inside the start side. /// </returns> internal bool StartSideContainsPoint(PointF point) { if (m_sliceHeight > 0) return (m_startSide.Contains(point)); return false; } /// <summary> /// Checks if point provided is inside pie slice end cut side. /// </summary> /// <param name="point"> /// <c>PointF</c> to check. /// </param> /// <returns> /// <c>true</c> if point is inside the end side. /// </returns> internal bool EndSideContainsPoint(PointF point) { if (m_sliceHeight > 0) return (m_endSide.Contains(point)); return false; } /// <summary> /// Checks if bottom side of the pie slice contains the point. /// </summary> /// <param name="point"> /// <c>PointF</c> to check. /// </param> /// <returns> /// <c>true</c> if point is inside the bottom of the pie slice. /// </returns> internal bool BottomSurfaceSectionContainsPoint(PointF point) { if (m_sliceHeight > 0) { return (PieSliceContainsPoint(point, m_boundingRectangle.X, m_boundingRectangle.Y + m_sliceHeight, m_boundingRectangle.Width, m_boundingRectangle.Height, m_startAngle, m_sweepAngle)); } return false; } /// <summary> /// Creates brushes used to render the pie slice. /// </summary> /// <param name="surfaceColor"> /// Color used for rendering. /// </param> /// <param name="shadowStyle"> /// Shadow style used for rendering. /// </param> protected virtual void CreateSurfaceBrushes(Color surfaceColor, ShadowStyle shadowStyle) { m_brushSurfaceHighlighted = new SolidBrush(ColorUtil.CreateColorWithCorrectedLightness(surfaceColor, ColorUtil.BrightnessEnhancementFactor1)); switch (shadowStyle) { case ShadowStyle.NoShadow: break; case ShadowStyle.UniformShadow: m_brushStartSide = m_brushEndSide = m_brushPeripherySurface = new SolidBrush(ColorUtil.CreateColorWithCorrectedLightness(surfaceColor, -ColorUtil.BrightnessEnhancementFactor1)); break; case ShadowStyle.GradualShadow: double angle = m_startAngle - 180 - s_shadowAngle; if (angle < 0) angle += 360; m_brushStartSide = CreateBrushForSide(surfaceColor, angle); angle = m_startAngle + m_sweepAngle - s_shadowAngle; if (angle < 0) angle += 360; m_brushEndSide = CreateBrushForSide(surfaceColor, angle); m_brushPeripherySurface = CreateBrushForPeriphery(surfaceColor); break; } } /// <summary> /// Disposes brush objects. /// </summary> protected void DisposeBrushes() { Debug.Assert(m_brushSurface != null); Debug.Assert(m_brushStartSide != null); Debug.Assert(m_brushEndSide != null); Debug.Assert(m_brushPeripherySurface != null); Debug.Assert(m_brushSurfaceHighlighted != null); m_brushSurface.Dispose(); m_brushStartSide.Dispose(); m_brushEndSide.Dispose(); m_brushPeripherySurface.Dispose(); m_brushSurfaceHighlighted.Dispose(); } /// <summary> /// Creates a brush for start and end sides of the pie slice for /// gradual shade. /// </summary> /// <param name="color"> /// Color used for pie slice rendering. /// </param> /// <param name="angle"> /// Angle of the surface. /// </param> /// <returns> /// <c>Brush</c> object. /// </returns> protected virtual Brush CreateBrushForSide(Color color, double angle) { return new SolidBrush(ColorUtil.CreateColorWithCorrectedLightness(color, -(float)(ColorUtil.BrightnessEnhancementFactor1 * (1 - 0.8 * Math.Cos(angle * Math.PI / 180))))); } /// <summary> /// Creates a brush for outer periphery of the pie slice used for /// gradual shadow. /// </summary> /// <param name="color"> /// Color used for pie slice rendering. /// </param> /// <returns> /// <c>Brush</c> object. /// </returns> protected virtual Brush CreateBrushForPeriphery(Color color) { ColorUtil.CreateColorWithCorrectedLightness(color, -ColorUtil.BrightnessEnhancementFactor1 / 2), color, ColorUtil.CreateColorWithCorrectedLightness(color, -ColorUtil.BrightnessEnhancementFactor1), }; LinearGradientBrush brush = new LinearGradientBrush(m_boundingRectangle, Color.Blue, Color.White, LinearGradientMode.Horizontal); brush.InterpolationColors = colorBlend; return brush; } /// <summary> /// Draws the outer periphery of the pie slice. /// </summary> /// <param name="graphics"> /// <c>Graphics</c> object used to draw the surface. /// </param> /// <param name="pen"> /// <c>Pen</c> used to draw outline. /// </param> /// <param name="brush"> /// <c>Brush</c> used to fill the quadrilateral. /// </param> /// <param name="boundingRect"> /// Bounding rectangle that is used to draw the top surface of the /// pie slice. /// </param> /// <param name="startAngle"> /// Start angle (in degrees) of the periphery section. /// </param> /// <param name="endAngle"> /// End angle (in degrees) of the periphery section. /// </param> /// <param name="pointStart"> /// Point representing the start of the periphery. /// </param> /// <param name="pointEnd"> /// Point representing the end of the periphery. /// </param> protected void DrawCylinderSurfaceSection(Graphics graphics, Pen pen, Brush brush, float startAngle, float endAngle, PointF pointStart, PointF pointEnd) { GraphicsPath path = CreatePathForCylinderSurfaceSection(startAngle, endAngle, pointStart, pointEnd); graphics.FillPath(brush, path); graphics.DrawPath(pen, path); } /// <summary> /// Transforms actual angle to angle used for rendering. They are /// different because of perspective. /// </summary> /// <param name="angle"> /// Actual angle. /// </param> /// <returns> /// Rendering angle. /// </returns> protected float TransformAngle(float angle) { double x = m_boundingRectangle.Width * Math.Cos(angle * Math.PI / 180); double y = m_boundingRectangle.Height * Math.Sin(angle * Math.PI / 180); float result = (float)(Math.Atan2(y, x) * 180 / Math.PI); if (result < 0) return result + 360; return result; } /// <summary> /// Gets the actual angle from the rendering angle. /// </summary> /// <param name="transformedAngle"> /// Transformed angle for which actual angle has to be evaluated. /// </param> /// <returns> /// Actual angle. /// </returns> protected float GetActualAngle(float transformedAngle) { double x = m_boundingRectangle.Height * Math.Cos(transformedAngle * Math.PI / 180); double y = m_boundingRectangle.Width * Math.Sin(transformedAngle * Math.PI / 180); float result = (float)(Math.Atan2(y, x) * 180 / Math.PI); if (result < 0) return result + 360; return result; } /// <summary> /// Calculates the point on ellipse periphery for angle. /// </summary> /// <param name="xCenter"> /// x-coordinate of the center of the ellipse. /// </param> /// <param name="yCenter"> /// y-coordinate of the center of the ellipse. /// </param> /// <param name="semiMajor"> /// Horizontal semi-axis. /// </param> /// <param name="semiMinor"> /// Vertical semi-axis. /// </param> /// <param name="angleDegrees"> /// Angle (in degrees) for which corresponding periphery point has to /// be obtained. /// </param> /// <returns> /// <c>PointF</c> on the ellipse. /// </returns> protected PointF PeripheralPoint(float xCenter, float yCenter, float semiMajor, float semiMinor, float angleDegrees) { double angleRadians = angleDegrees * Math.PI / 180; return new PointF(xCenter + (float)(semiMajor * Math.Cos(angleRadians)), yCenter + (float)(semiMinor * Math.Sin(angleRadians))); } /// <summary> /// Initializes pie bounding rectangle, pie height, corners /// coordinates and brushes used for rendering. /// </summary> /// <param name="xBoundingRect"> /// x-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="yBoundingRect"> /// y-coordinate of the upper-left corner of the rectangle that is /// used to draw the top surface of the pie slice. /// </param> /// <param name="widthBoundingRect"> /// Width of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="heightBoundingRect"> /// Height of the rectangle that is used to draw the top surface of /// the pie slice. /// </param> /// <param name="sliceHeight"> /// Height of the pie slice. /// </param> private void InitializePieSlice(float xBoundingRect, float yBoundingRect, float widthBoundingRect, float heightBoundingRect, float sliceHeight) { // stores bounding rectangle and pie slice height m_boundingRectangle = new RectangleF(xBoundingRect, yBoundingRect, widthBoundingRect, heightBoundingRect); m_sliceHeight = sliceHeight; // recalculates start and sweep angle used for rendering m_startAngle = TransformAngle(m_actualStartAngle); m_sweepAngle = m_actualSweepAngle; if (m_sweepAngle % 180 != 0F) m_sweepAngle = TransformAngle(m_actualStartAngle + m_actualSweepAngle) - m_startAngle; if (m_sweepAngle < 0) m_sweepAngle += 360; // creates brushes CreateSurfaceBrushes(m_surfaceColor, m_shadowStyle); // calculates center and end points on periphery float xCenter = xBoundingRect + widthBoundingRect / 2; float yCenter = yBoundingRect + heightBoundingRect / 2; m_pointStart = PeripheralPoint(xCenter, yCenter, widthBoundingRect / 2, heightBoundingRect / 2, m_actualStartAngle); m_pointEnd = PeripheralPoint(xCenter, yCenter, widthBoundingRect / 2, heightBoundingRect / 2, m_actualStartAngle + m_actualSweepAngle); InitializeSides(); } /// <summary> /// Initializes start and end pie slice sides. /// </summary> private void InitializeSides() { InitializeSides(true, true); } /// <summary> /// Initializes start and end pie slice sides. /// </summary> /// <param name="startSideExists"> /// Does start side exists. /// </param> /// <param name="endSideExists"> /// Does end side exists. /// </param> private void InitializeSides(bool startSideExists, bool endSideExists) { if (startSideExists) m_startSide = new Quadrilateral(m_center, m_pointStart, m_pointStartBelow, m_centerBelow, m_sweepAngle != 180); else m_startSide = Quadrilateral.Empty; if (endSideExists) m_endSide = new Quadrilateral(m_center, m_pointEnd, m_pointEndBelow, m_centerBelow, m_sweepAngle != 180); else m_endSide = Quadrilateral.Empty; } /// <summary> /// Gets an array of visible periphery bounds. /// </summary> /// <returns> /// Array of <c>PeripherySurfaceBounds</c> objects. /// </returns> private PeripherySurfaceBounds[] GetVisiblePeripherySurfaceBounds() { // outer periphery side is visible only when startAngle or endAngle // is between 0 and 180 degrees if (!(m_sweepAngle == 0 || (m_startAngle >= 180 && m_startAngle + m_sweepAngle <= 360))) { // draws the periphery from start angle to the end angle or left // edge, whichever comes first if (StartAngle < 180) { float fi1 = m_startAngle; float fi2 = EndAngle; if (m_startAngle + m_sweepAngle > 180) { fi2 = 180; x2.X = m_boundingRectangle.X; x2.Y = m_center.Y; } } // if lateral surface is visible from the right edge if (m_startAngle + m_sweepAngle > 360) { float fi1 = 0; float fi2 = EndAngle; if (fi2 > 180) { fi2 = 180; x2.X = m_boundingRectangle.Left; x2.Y = m_center.Y; } } } } /// <summary> /// Gets an array of hidden periphery bounds. /// </summary> /// <returns> /// Array of <c>PeripherySurfaceBounds</c> objects. /// </returns> private PeripherySurfaceBounds[] GetHiddenPeripherySurfaceBounds() { // outer periphery side is not visible when startAngle or endAngle // is between 180 and 360 degrees if (!(m_sweepAngle == 0 || (m_startAngle >= 0 && m_startAngle + m_sweepAngle <= 180))) { // draws the periphery from start angle to the end angle or right // edge, whichever comes first if (m_startAngle + m_sweepAngle > 180) { float fi1 = m_startAngle; float fi2 = m_startAngle + m_sweepAngle; if (fi1 < 180) { fi1 = 180; x1.X = m_boundingRectangle.Left; x1.Y = m_center.Y; } if (fi2 > 360) { fi2 = 360; x2.X = m_boundingRectangle.Right; x2.Y = m_center.Y; } // if pie is crossing 360 & 180 deg. boundary, we have to // invisible peripheries if (m_startAngle < 360 && m_startAngle + m_sweepAngle > 540) { fi1 = 180; fi2 = EndAngle; } } } } /// <summary> /// Creates <c>GraphicsPath</c> for cylinder surface section. This /// path consists of two arcs and two vertical lines. /// </summary> /// <param name="startAngle"> /// Starting angle of the surface. /// </param> /// <param name="endAngle"> /// Ending angle of the surface. /// </param> /// <param name="pointStart"> /// Starting point on the cylinder surface. /// </param> /// <param name="pointEnd"> /// Ending point on the cylinder surface. /// </param> /// <returns> /// <c>GraphicsPath</c> object representing the cylinder surface. /// </returns> private GraphicsPath CreatePathForCylinderSurfaceSection(float startAngle, float endAngle, PointF pointStart, PointF pointEnd) { path.AddArc(m_boundingRectangle, startAngle, endAngle - startAngle); path.AddLine(pointEnd.X, pointEnd.Y, pointEnd.X, pointEnd.Y + m_sliceHeight); path.AddArc(m_boundingRectangle.X, m_boundingRectangle.Y + m_sliceHeight, m_boundingRectangle.Width, m_boundingRectangle.Height, endAngle, startAngle - endAngle); path.AddLine(pointStart.X, pointStart.Y + m_sliceHeight, pointStart.X, pointStart.Y); return path; } /// <summary> /// Checks if given point is contained within upper and lower pie /// slice surfaces or within the outer slice brink. /// </summary> /// <param name="point"> /// <c>PointF</c> structure to check for. /// </param> /// <param name="startAngle"> /// Start angle of the slice. /// </param> /// <param name="endAngle"> /// End angle of the slice. /// </param> /// <param name="point1"> /// Starting point on the periphery. /// </param> /// <param name="point2"> /// Ending point on the periphery. /// </param> /// <returns> /// <c>true</c> if point given is contained. /// </returns> private bool CylinderSurfaceSectionContainsPoint(PointF point, float startAngle, float endAngle, PointF point1, PointF point2) { if (m_sliceHeight > 0) { } return false; } /// <summary> /// Checks if point given is contained within the pie slice. /// </summary> /// <param name="point"> /// <c>PointF</c> to check for. /// </param> /// <param name="xBoundingRectangle"> /// x-coordinate of the rectangle that bounds the ellipse from which /// slice is cut. /// </param> /// <param name="yBoundingRectangle"> /// y-coordinate of the rectangle that bounds the ellipse from which /// slice is cut. /// </param> /// <param name="widthBoundingRectangle"> /// Width of the rectangle that bounds the ellipse from which /// slice is cut. /// </param> /// <param name="heightBoundingRectangle"> /// Height of the rectangle that bounds the ellipse from which /// slice is cut. /// </param> /// <param name="startAngle"> /// Start angle of the slice. /// </param> /// <param name="sweepAngle"> /// Sweep angle of the slice. /// </param> /// <returns> /// <c>true</c> if point is contained within the slice. /// </returns> private bool PieSliceContainsPoint(PointF point, float xBoundingRectangle, float yBoundingRectangle, float widthBoundingRectangle, float heightBoundingRectangle, float startAngle, float sweepAngle) { double x = point.X - xBoundingRectangle - widthBoundingRectangle / 2; double y = point.Y - yBoundingRectangle - heightBoundingRectangle / 2; double angle = Math.Atan2(y, x); if (angle < 0) angle += (2 * Math.PI); double angleDegrees = angle * 180 / Math.PI; // point is inside the pie slice only if between start and end angle if ((angleDegrees >= startAngle && angleDegrees <= (startAngle + sweepAngle)) || (startAngle + sweepAngle > 360) && ((angleDegrees + 360) <= (startAngle + sweepAngle))) { // distance of the point from the ellipse centre double r = Math.Sqrt(y * y + x * x); return GetEllipseRadius(angle) > r; } return false; } /// <summary> /// Evaluates the distance of an ellipse perimeter point for a /// given angle. /// </summary> /// <param name="angle"> /// Angle for which distance has to be evaluated. /// </param> /// <returns> /// Distance of the point from the ellipse centre. /// </returns> private double GetEllipseRadius(double angle) { double a = m_boundingRectangle.Width / 2; double b = m_boundingRectangle.Height / 2; double a2 = a * a; double b2 = b * b; double cosFi = Math.Cos(angle); double sinFi = Math.Sin(angle); // distance of the ellipse perimeter point return (a * b) / Math.Sqrt(b2 * cosFi * cosFi + a2 * sinFi * sinFi); } /// <summary> /// Internal structure used to store periphery bounds data. /// </summary> private struct PeripherySurfaceBounds { public PeripherySurfaceBounds(float startAngle, float endAngle, PointF startPoint, PointF endPoint) { m_startAngle = startAngle; m_endAngle = endAngle; m_startPoint = startPoint; m_endPoint = endPoint; } public float StartAngle { get { return m_startAngle; } } public float EndAngle { get { return m_endAngle; } } public PointF StartPoint { get { return m_startPoint; } } public PointF EndPoint { get { return m_endPoint; } } private float m_startAngle; private float m_endAngle; private PointF m_startPoint; private PointF m_endPoint; } /// <summary> /// Bounding rectangle that bounds the ellipse from which pie slice /// is cut. /// </summary> protected RectangleF m_boundingRectangle; /// <summary> /// Pie slice height. /// </summary> protected float m_sliceHeight; /// <summary> /// Start angle. /// </summary> protected float m_startAngle; /// <summary> /// Sweep angle. /// </summary> protected float m_sweepAngle; /// <summary> /// Actual start angle. /// </summary> private float m_actualStartAngle; /// <summary> /// Actual sweep angle. /// </summary> private float m_actualSweepAngle; /// <summary> /// Color of the surface. /// </summary> private Color m_surfaceColor = Color.Empty; /// <summary> /// Style used for shadow. /// </summary> private ShadowStyle m_shadowStyle = ShadowStyle.NoShadow; /// <summary> /// <c>EdgeColorType</c> used to draw pie sliece edges. /// </summary> private EdgeColorType m_edgeColorType = EdgeColorType.NoEdge; /// <summary> /// <c>Brush</c> used to render slice top surface. /// </summary> protected Brush m_brushSurface = null; /// <summary> /// <c>Brush</c> used to render slice top surface when highlighted. /// </summary> protected Brush m_brushSurfaceHighlighted = null; /// <summary> /// <c>Brush</c> used to render slice starting cut side. /// </summary> protected Brush m_brushStartSide = null; /// <summary> /// <c>Brush</c> used to render slice ending cut side. /// </summary> protected Brush m_brushEndSide = null; /// <summary> /// <c>Brush</c> used to render pie slice periphery (cylinder outer surface). /// </summary> protected Brush m_brushPeripherySurface = null; /// <summary> /// <c>Pen</c> object used to draw pie slice edges. /// </summary> protected Pen m_pen = null; /// <summary> /// <c>PointF</c> corresponding to pie slice center. /// </summary> protected PointF m_center; /// <summary> /// <c>PointF</c> corresponding to the lower pie slice center. /// </summary> protected PointF m_centerBelow; /// <summary> /// <c>PointF</c> on the periphery corresponding to the start cut /// side. /// </summary> protected PointF m_pointStart; /// <summary> /// <c>PointF</c> on the periphery corresponding to the start cut /// side. /// </summary> protected PointF m_pointStartBelow; /// <summary> /// <c>PointF</c> on the periphery corresponding to the end cut /// side. /// </summary> protected PointF m_pointEnd; /// <summary> /// <c>PointF</c> on the periphery corresponding to the end cut /// side. /// </summary> protected PointF m_pointEndBelow; /// <summary> /// <c>Quadrilateral</c> representing the start side. /// </summary> protected Quadrilateral m_startSide = Quadrilateral.Empty; /// <summary> /// <c>Quadrilateral</c> representing the end side. /// </summary> protected Quadrilateral m_endSide = Quadrilateral.Empty; /// <summary> /// Text attached to the slice. /// </summary> private string m_text; /// <summary> /// Flag indicating if object has been disposed. /// </summary> private bool m_disposed = false; /// <summary> /// Angle offset used to define reference angle for gradual shadow. /// </summary> private static float s_shadowAngle = 20F; } }
Structure et Fichiers du projet
Afficher/masquer...Icône | Nom | Taille | Modification |
Pas de sous-répertoires. | |||
Icône | Nom | Taille | Modification |
| _ | Répertoire parent | 0 octets | 1734985549 23/12/2024 21:25:49 |
Utilisation de l'explorateur de code
- Navigation :
- Un clic sur une icône de répertoire ouvre ce répertoire pour en afficher les fichiers.
- Lorsque le répertoire en cours ne contient pas de sous-répertoires il est possible de remonter vers le répertoire parent.
- La structure de répertoires en treetable (tableau en forme d'arborescence) n'est plus possibledans cette version.
- Un clic sur une icône de fichier ouvre ce fichier pour en afficher le code avec la coloration syntaxique adaptée en fonction du langage principal utilisé dans le fichier.
- Affichage :
- Il est possible de trier les répertoires ou les fichiers selon certains critères (nom, taille, date).
- Actions :
- Les actions possible sur les fichiers dépendent de vos droits d'utilisateur sur le site. Veuillez activer le mode utilisateur pour activer les actions.
Nederlandse vertaling
U hebt gevraagd om deze site in het Nederlands te bezoeken. Voor nu wordt alleen de interface vertaald, maar nog niet alle inhoud.Als je me wilt helpen met vertalingen, is je bijdrage welkom. Het enige dat u hoeft te doen, is u op de site registreren en mij een bericht sturen waarin u wordt gevraagd om u toe te voegen aan de groep vertalers, zodat u de gewenste pagina's kunt vertalen. Een link onderaan elke vertaalde pagina geeft aan dat u de vertaler bent en heeft een link naar uw profiel.
Bij voorbaat dank.
Document heeft de 16/10/2009 gemaakt, de laatste keer de 26/10/2018 gewijzigd
Bron van het afgedrukte document:https://www.gaudry.be/nl/cs-broldev-source-rf-model/drawing/chart//PieSlice.cs.html
De infobrol is een persoonlijke site waarvan de inhoud uitsluitend mijn verantwoordelijkheid is. De tekst is beschikbaar onder CreativeCommons-licentie (BY-NC-SA). Meer info op de gebruiksvoorwaarden en de auteur.