Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the projection/camera technique in c#

I drew the following grid:

Grid (Top-View)

The above grid is drawn using the following two methods, one to calculate the grid and the other to calculate the centers for each cell:

//makes grid in picture box
private void drawGrid(int numOfCells, int cellSize, Graphics gr)
{
    Pen p = new Pen(Color.SteelBlue);

    for (int i = 0; i < Math.Sqrt(numOfCells) + 1; i++)
    {
        // Vertical
        gr.DrawLine(p, i * cellSize + 300, 200, i * cellSize + 300, 700);
        // Horizontal
        gr.DrawLine(p, 300, i * cellSize+200, 800, i * cellSize+200);
    }

    this.topology.SendToBack();
}


//draw the center point for each cell of the grid 
private void drawCenters(Graphics gr)
{
    for (int j = 0; j < rows; j++)
    {
        for (int i = 0; i < columns; i++)
        {
            gr.FillRectangle(Brushes.IndianRed, cellsCenters[0, i], cellsCenters[1, j], 3, 3);
        }
    }
}

My question is how to make this grid appear as in the following picture and how to place the nodes at different cells (random deployment) in such grid.

Expected result

I need the grid to be drawn in a 3D view in which I have z as well as x and y!

like image 992
Rose Avatar asked Jul 18 '17 06:07

Rose


1 Answers

Note: Many of the constructs already exist in one form or another, here I'm showing you how to do it from scratch. enter image description here Same control, same data, different perspective

Since your data is 3-dimensional, you need store your positional data 3-dimensional so you don't have to calculate everything by hand every time you change the perspective:

[TypeConverter(typeof(ExpandableObjectConverter))]
public struct Point3D
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Z { get; set; }

    public Point3D(int x, int y, int z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

To project these 3D-points to screen coordinates (2D) you need some kind of projection/camera system. Usually you would do this with Matrix/Vector math, but for this example the following orthographic approach will suffice.

The perspective handles the transformation from 3D to 2D. Depending on the parameters your graphic will skew/roatate/translate etc.

[TypeConverter(typeof(ExpandableObjectConverter))]
public class Perspective
{
    public float X_shift { get; set; } = 0.0f;
    public float Y_shift { get; set; } = 0.0f;

    public float X_x { get; set; } = 1.0f;
    public float X_y { get; set; } = 0.0f;
    public float X_z { get; set; } = 0.0f;

    public float Y_x { get; set; } = 0.0f;
    public float Y_y { get; set; } = 1.0f;
    public float Y_z { get; set; } = 0.0f;

    public PointF Project(Point3D p)
    {
        return new PointF(X_shift + X_x * p.X + X_y * p.Y + X_z * p.Z, Y_shift + Y_x * p.X + Y_y * p.Y + Y_z * p.Z);
    }
}

All you need to do now, is draw everything as usual, but with 3D-coordinates translated to 2D. The following control draws a grid (at depth 400) and two sensors.

using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public class PerspectiveGrid : Control
    {
        private Perspective _perspective;

        public Perspective Perspective
        {
            get { return _perspective; }
            set
            {
                _perspective = value; 
                Invalidate();
            }
        }

        public PerspectiveGrid()
        {
            Perspective = new Perspective
            {
                X_shift = 100,
                Y_shift = 10,

                X_x = -0.2f,
                X_y = 1.0f,
                X_z = 0.0f,

                Y_x = 0.2f,
                Y_y = 0.0f,
                Y_z = 1.0f,
            };
        }

        /// <summary>
        /// Paints a Grid at Z = 400 and two Sensors
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            DrawGrid(10,40,400,e.Graphics);

            DrawSensor(new Point3D(80, 120, 400), new Point3D(80, 120, 200), e.Graphics);
            DrawSensor(new Point3D(240, 240, 400), new Point3D(240, 240, 120), e.Graphics);
        }

        /// <summary>
        /// Draws a sensor at the specified position(s)
        /// </summary>
        private void DrawSensor(Point3D from, Point3D to, Graphics gr)
        {
            DrawLine(gr, Pens.Black, from, to);
            DrawSphere(gr, Pens.Black, Brushes.Orange, to, 6);
        }

        /// <summary>
        /// Draws a sphere as a Circle at the specified position
        /// </summary>
        private void DrawSphere(Graphics gr, Pen outline, Brush fill, Point3D center, float radius)
        {
            PointF center2D = Project(center);
            gr.FillEllipse(fill, center2D.X - radius, center2D.Y - radius, radius * 2, radius * 2);
            gr.DrawEllipse(outline, center2D.X - radius, center2D.Y - radius, radius * 2, radius * 2);
        }

        /// <summary>
        /// Draws the grid at the specified depth
        /// </summary>
        private void DrawGrid(int numOfCells, int cellSize, int depth, Graphics gr)
        {
            Pen p = Pens.SteelBlue;

            for (int i = 0; i <= numOfCells; i++)
            {
                // Vertical
                DrawLine(gr, p, new Point3D(i * cellSize, 0 , depth), new Point3D(i * cellSize, numOfCells * cellSize, depth));
                // Horizontal
                DrawLine(gr, p, new Point3D(0, i * cellSize, depth), new Point3D(numOfCells * cellSize, i * cellSize, depth));
            }
        }

        /// <summary>
        /// Draws a line from one 3DPoint to another
        /// </summary>
        private void DrawLine(Graphics graphics, Pen pen, Point3D p1, Point3D p2)
        {
            PointF pointFrom = Project(p1);
            PointF pointTo = Project(p2);

            graphics.DrawLine(pen, pointFrom, pointTo);
        }

        /// <summary>
        /// Projects a Point3D to a PointF
        /// </summary>
        private PointF Project(Point3D p)
        {
            return Perspective.Project(p);
        }
    }
}

A couple of links that might help you build on these concepts:

Orthographic projection
Quaternion
Math Library with Matrix and Vector support

like image 103
Manfred Radlwimmer Avatar answered Oct 29 '22 13:10

Manfred Radlwimmer