I am trying to implement shading under a curve. I have successfully used the information/examples from this post: https://www.steema.com/support/viewtopic.php?t=10307
That post explains how to use the SeriesRegionTool to color an area under a curve starting at one X value (X1), ending at a second X value (X2) with an origin value (Y) that defines the baseline of the shaded area by the points (X1, Y) and (X2, Y). The SeriesRegionTool works great for this!
I will now need to extend this solution to handle shading when the baseline points do not share the same Y value (i.e. the baseline is sloped). Here's an example image where the left curve is the straight baseline I currently have working with the SeriesRegionTool and the right curve shows the sloped baseline that I need help implementing:
I'd like to continue using the SeriesRegionTool for this - but it doesn't seem to be able to handle multiple origin points. Can you please help me understand the best way to shade the area under the curve with a sloped baseline?
Thanks!!
Peak Shading Under a Curve
-
- Guru
- Posts: 1603
- Joined: Fri Nov 15, 2002 12:00 am
Re: Peak Shading Under a Curve
I think the only way you're going to be able to do this is to derive a new Tool from our SeriesRegionTool and then adapt it to your needs. Unfortunately some of the key methods of the SeriesRegionTool are private rather than protected virtual, but in order to help you we can share some of our source code with you:
Code: Select all
public class MySeriesRegionTool : SeriesRegionTool
{
public MySeriesRegionTool(Chart c) : base(c) { }
protected override void ChartEvent(EventArgs e)
{
if (Series != null)
{
if (((e is BeforeDrawSeriesEventArgs) && (DrawBehindSeries))
|| (e is AfterDrawSeriesEventsArgs) && (!DrawBehindSeries))
{
DrawRegion();
}
}
}
/// <summary>
/// Using point x coordinate it calculates point y coordinate
/// </summary>
/// <param name="val">intersection point x coordinate</param>
/// <param name="y">returns intersection point y coordinate.</param>
/// <returns>Point index</returns>
private int IntersectionPoint(double val, out double y)
{
var i = 0;
y = Series.mandatory[i];
while ((val > Series.notMandatory[i]) && (i < Series.Count))
{
i++;
}
// We have two choices:
// #1: value is exactly at point coordinate
// #2: value is between two points - use linear interpolation to calculate y
if (val == Series.notMandatory[i])
{
y = Series.mandatory[i];
}
else
{
double k;
if ((i > 0) && (i < Series.Count))
{
k = Series.mandatory[i] - Series.mandatory[i - 1];
k /= (Series.notMandatory[i] - Series.notMandatory[i - 1]);
y = Series.mandatory[i - 1] + k * (val - Series.notMandatory[i - 1]);
}
}
return i;
}
private void DrawRegion()
{
if (Active && (Chart != null) && (Series != null))
{
var lb = Series.notMandatory.Minimum;
var ub = Series.notMandatory.Maximum;
if (!AutoBound)
{
lb = Math.Max(lb, LowerBound);
ub = Math.Min(ub, UpperBound);
}
// plot only if it makes sense
if ((ub > Series.notMandatory.Minimum) && (lb < Series.notMandatory.Maximum))
{
var first = IntersectionPoint(lb, out var yl);
var last = IntersectionPoint(ub, out var yu);
if (last < first)
{
Utils.SwapInteger(ref first, ref last);
}
var plen = last - first + 1;
var pts = new Point[plen + 4]; // need four extra points
for (var i = 0; i < plen; i++)
{
pts[i].X = Series.CalcXPos(i + first);
pts[i].Y = Series.CalcYPos(i + first);
}
// upper bound intersect point
pts[plen].X = Series.CalcXPosValue(ub);
pts[plen].Y = Series.CalcYPosValue(yu);
// upper bound origin point
pts[plen + 1].X = pts[plen].X;
pts[plen + 1].Y = UseOrigin ? Series.CalcYPosValue(Origin) : Series.GetVertAxis.IEndPos;
// lower bound origin point
pts[plen + 2].X = Series.CalcXPosValue(lb);
pts[plen + 2].Y = pts[plen + 1].Y;
// lower bound intersect point
pts[plen + 3].X = pts[plen + 2].X;
pts[plen + 3].Y = Series.CalcYPosValue(yl);
var gr = Chart.Graphics3D;
gr.Brush = Brush;
gr.Pen = Pen;
var zpos = DrawBehindSeries ? Series.EndZ : Series.StartZ;
var tmpR = gr.RectFromRectZ(Chart.ChartRect, zpos);
gr.ClipRectangle(tmpR);
gr.Polygon(zpos, pts);
gr.UnClip();
}
}
}
}
Code: Select all
private void InitializeChart()
{
tChart1.Aspect.View3D = false;
var nSeries = 4;
var yPos = new int[nSeries];
var fast = new FastLine[nSeries];
var region = new MySeriesRegionTool[nSeries];
for (var i = 0; i < nSeries; i++)
{
yPos[i] = i * 5;
fast[i] = new FastLine(tChart1.Chart);
if (i % 2 == 0)
{
for (var j = 0; j < 200; j++) fast[i].Add(Math.Sin((double)j / 10) + yPos[i]);
}
else
{
for (var j = 0; j < 200; j++) fast[i].Add(Math.Cos((double)j / 10) + yPos[i]);
}
region[i] = new MySeriesRegionTool(tChart1.Chart);
region[i].Series = fast[i];
region[i].Origin = yPos[i];
region[i].UseOrigin = true;
region[i].Brush.Style = System.Drawing.Drawing2D.HatchStyle.Vertical;
region[i].Brush.Transparency = 100;
region[i].Pen.Visible = false;
region[i].Brush.ForegroundColor = fast[i].Color;
}
}
1) request a new feature request on http://bugs.teechart.net/
2) ask [email protected] for a quote from us for the work
Best Regards,
Christopher Ireland / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |