Question

What would be the best way to draw a Line with points with some degree or angle.

For example If x=ythen that would mean that points have 45 degrees. showing enter image description here

But I would like to give θ as a parameter and inside a loop draw a line with θ degrees, I have following code, but I do not know how to continue.

Could you please explain the best way to affect points given θ ?

public struct MyPoint
{
    public double X { set; get; }
    public double Y { set; get; }

    public PointF ToPoint()
    {
        return new PointF((float)X, (float)Y);
    }
}

public partial class Form1 : Form
{
    List<MyPoint> points;
    public Form1()
    {
        InitializeComponent();

        // Initialize points to draw
        //-----------THIS IS PART TO DRAW LINE x=i and y = i meaning θ=45
        // [x,y] = [xcos(θ)−ysin(θ),xsin(θ)+ycos(θ)] 
        points=new List<MyPoint>(100);
        for (int i=0; i<=100; i++)
        {
            double θ=45;
            double x=i; //(i * Math.Cos(θ) - i * Math.Sin(θ));
            double y=i; //(i *Math.Sin(θ) + i * Math.Cos(θ));
            points.Add(new MyPoint() { X=x, Y=y });
        }
        //------------------------------
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        // smooth graphics
        e.Graphics.SmoothingMode=SmoothingMode.AntiAlias;            
        // set margins inside the control client area in pixels
        var margin=new System.Drawing.Printing.Margins(16, 16, 16, 16);
        // set the domain of (x,y) values
        var range=new RectangleF(-3, -3, 6, 6);
        // scale graphics
        ScaleGraphics(e.Graphics, pictureBox1, range, margin);            
        // convert points to pixels
        PointF[] pixels=points.Select((v) => v.ToPoint()).ToArray();
        // draw arrow axes
        using (var pen=new Pen(Color.Black, 0))
        {
            pen.EndCap=System.Drawing.Drawing2D.LineCap.ArrowAnchor;
            e.Graphics.DrawLine(pen, range.Left, 0.0f, range.Right, 0.0f);
            e.Graphics.DrawLine(pen, 0.0f, range.Top, 0.0f, range.Bottom);
        }
        // draw bounding rectangle (on margin)
        using (var pen=new Pen(Color.LightGray, 0))
        {
            pen.DashStyle=DashStyle.Dash;
            e.Graphics.DrawRectangle(pen, Rectangle.Round(range));
        }
        // draw curve
        using (var pen = new Pen(Color.Blue, 0))
        {                
            //e.Graphics.DrawLines(pen, pixels);
            e.Graphics.DrawCurve(pen, pixels);
        }            
    }
    /// <summary>
    /// Scales the Graphics to fit a Control, given a domain of x,y values and side margins in pixels
    /// </summary>
    /// <param name="g">The Graphics object</param>
    /// <param name="control">The Control</param>
    /// <param name="domain">The value domain</param>
    /// <param name="margin">The margin</param>
    void ScaleGraphics(Graphics g, Control control, RectangleF domain, Margins margin)
    {
        // Find the drawable area in pixels (control-margins)
        int W=control.Width-margin.Left-margin.Right;
        int H=control.Height-margin.Bottom-margin.Top;
        // Ensure drawable area is at least 1 pixel wide
        W=Math.Max(1, W);
        H=Math.Max(1, H);
        // Find the origin (0,0) in pixels
        float OX=margin.Left-W*(domain.Left/domain.Width);
        float OY=margin.Top+H*(1+domain.Top/domain.Height);
        // Find the scale to fit the control
        float SX=W/domain.Width;
        float SY=H/domain.Height;
        // Transform the Graphics
        g.TranslateTransform(OX, OY);
        g.ScaleTransform(SX, -SY);
    }

    private void pictureBox1_SizeChanged(object sender, EventArgs e)
    {
        // redraw on resize
        pictureBox1.Refresh();
    }
}
Was it helpful?

Solution

Getting the line coordinates passing through a point at an angle is the easy part. Finding the end points of the line to be contained within the display rectangle is slightly more involved.

A line through a point P=(xp,yp) with angle θ satisfies the equation

(x-xp)*SIN(θ)-(y-yp)*COS(θ) = 0

In parametric form the above is

P(t) = ( xp+t*COS(θ), yp+t*SIN(θ) )

where t is the distance along the line from point P.

So if you want a line to span the entire drawing bounds (range variable in your code) you have to find which t corresponds to the top, bottom, left and right bounds and draw between the middle two.

// example angle at 15° through xp=2.0, yp=1.0
RectangleF range = new RectangleF(-3.0,-3.0, 6.0, 6.0);
double xp=2.0, yp=1.0;
double θ = 15.0*(Math.PI/180);   
// If angle is 0°, 90° etc, the following will fail
double[] t = new double[4];
t[0] = (range.Left-xp)/Math.Cos(θ);
t[1] = (range.Right-xp)/Math.Cos(θ);
t[2] = (range.Top-yp)/Math.Sin(θ);
t[3] = (range.Bottom-yp)/Math.Sin(θ);
Array.Sort(t);
// pick middle two points
var A = new MyPoint() { X = xp+t[1]*Math.Cos(θ), Y = yp+t[1]*Math.Sin(θ) };
var B = new MyPoint() { X = xp+t[2]*Math.Cos(θ), Y = yp+t[2]*Math.Sin(θ) };
g.DrawLine(pen, A.ToPoint(), B.ToPoint());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top