How to enable drawing on a picture box in C# - c#
I am trying to draw a network topology consists of many nodes to be like a 3D nodes using the idea of projection, but when I click the button that should implement the code nothing appears!!!! the following is the main code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Media;
using System.Text;
using System.Windows.Forms;
using AUV_Topology.AUV_Topology;
using AUV_Topology;
namespace AUV_Topology
{
public partial class Form2 : Form
{
private int iSetupDisplay = -1; // used for making drawing on the graphics
static int NodeNum = 0; // an int number is given for each node
static bool deploymentButtonWasClicked = false; // flag to check if button "Deploy" is clicked
static Sink sink; // sink object from sink class
static SensorNode[] SNs; // array of SNs
static int[,] SNsLocation; // to store SN locations
static int[,] SNsNighbors; // to store each SN nighbors
static int[] SinkNighbors; // to store each SN nighbors
static int transmissionRange; // the transmission range for each sensor node
static double sensorNodeIntialEnergy; // in order to store the energy filled in the text box in the GUI
System.IO.StreamWriter writer; // declare a writer object from the straem writer class
static Random r = new Random(); // in order to generate a random number
static AUV[] auv; // array of AUVs objects from AUV class
static int rows, columns; // to get the number of rows and columns from the text boxes in the GUI
static int[,] cellsCenters; // an array to store the indexes (col & row) for each center for each cell in the grid topology
static int[] columnsXs; // the index of each X cordinates in each column
static int[] rowsYs; // the index of each Y cordinates
static int numOfCells; // compute the number of cells by multpling the rows with columns
static int cellSide; // to compute the length of each side for each cell
public Form2()
{
InitializeComponent();
// Create a file for output named TraceFile.txt.
Stream myFile = File.Create("C:/Users/AMCT/Desktop/TraceFile2.txt");
TextWriterTraceListener myTextListener = new TextWriterTraceListener(myFile);
Trace.Listeners.Add(myTextListener);
}
private void Form2_Load(object sender, EventArgs e)
{
}
public delegate void UpdateControlsDelegate();
[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) : this()
{
this.X = x;
this.Y = y;
this.Z = z;
}
}
public static SoundPlayer player = new SoundPlayer("C:/Users/AMCT/Desktop/project/C#-Code-VisualStudio-2010/GAAPS/Sonar_pings.wav");
public static int tr;
//***Deployment***//
#region nodesDeployment
private void nodesDeployment_Click_1(object sender, EventArgs e)
{
//chromosome size
rows = 10;
columns = 10;
int numOfGridCells = rows * columns; // Calculate the total number of the cells for the grid topology
tr = Convert.ToInt32(TransRange.Text);
calculateCellsCenters(200, 200, 700, 700, numOfGridCells, 500, 500); // Compute all the center points (Xc,Yc) for all cells of the partitioned region (grid)
if (NumSN.Text != string.Empty) // to check that the user has entered the number of nodes for this topology
{
topology2.Visible = true;
NodeNum = Convert.ToInt32(NumSN.Text); // get the number from the text box
sensorNodeIntialEnergy = Convert.ToDouble(SNEnergy.Text);
Point3D[] auvLocation2D = new Point3D[4];
for (int i = 0; i < 4; i++)
auvLocation2D[i] = new Point3D(cellsCenters[0, 0], cellsCenters[1, 8], 700 - i * 100);
Point3D p3d = new Point3D(542, 600, 210);
PointF point2Dsink = Project(p3d);
sink = new Sink("Sink", 1, point2Dsink.X, point2Dsink.Y, 100);
auv = new AUV[4];
for (int i = 0; i < 4; i++)
{
PointF point2D = Project(auvLocation2D[i]);
int d = 700 - i * 100;
auv[i] = new AUV(point2D.X, point2D.Y, d, sink, i);
}
SNs = new SensorNode[NodeNum];
for (int i = 0; i < NodeNum; i++)
SNs[i] = new SensorNode(i, "SN" + i, r.Next(355, 750) % (topology2.Width), sensorNodeIntialEnergy, sink, auv[0], 0);
nodesCoordinations(); // choose XY coordinates for each sensor node
generateRoutingTable(); // build the routing table for each sensor node
deploymentButtonWasClicked = true;
}
makeDrawing(); // Draw
}
#endregion
//***Nodes Coordinates***//
#region Nodes Coordinates ( used by deployment process )
public void nodesCoordinations()
{
SNsLocation = new int[2, NodeNum]; // build an array of size n which is equal to the number of nodes that was chosen by the user to store all SNs locations
# region SNs Locations
for (int i = 0; i < NodeNum; i++)
if (NodeNum != 0)
{
SNsLocation[0, i] = r.Next(300, 800) % (topology2.Width); // choose random X coordinate between 300 & 800 pixel
SNsLocation[1, i] = r.Next(260, 725) % (topology2.Width); // choose random Y coordinate between 260 & 725 pixel
}
}
# endregion
public void generateRoutingTable()
{
/// Size of SNsNighbors Array = [node #, Nighbors #]
double D; // Euclidean distance
SNsNighbors = new int[NodeNum, NodeNum];
SinkNighbors = new int[NodeNum];
transmissionRange = Convert.ToInt32(TransRange.Text);
/// This Method estimate the Euclidean distance between SNs = (D)
/// Suppose that the transmission rane for all nodes = 150
/// if d <= Transmission Rang of SNi, SNi can communicate with SNj
for (int i = 0; i < NodeNum; i++) // For all SNs
for (int j = 0; j < NodeNum; j++) // For all SNs
{
if (i != j)
{
double Xn = SNsLocation[0, i]; // 0 for x - axis
double Yn = SNsLocation[1, i]; // 1 for y - axis
double Xs = SNsLocation[0, j]; // 0 for x - axis
double Ys = SNsLocation[1, j]; // 1 for y - axis
D = Math.Pow((Math.Pow(Xn - Xs, 2) + Math.Pow(Yn - Ys, 2)), 0.5);
// the transmission range is 150
if (D <= transmissionRange)
SNsNighbors[i, j] = 1; // SNj is nighbore for SNi
else
SNsNighbors[i, j] = 0; // SNj is NOT nighbore for SNi
}
else
SNsNighbors[i, j] = 0; // SNj is NOT nighbore for SNi
}
}
#endregion nodesDeployment
//***Paint Handlers***//
#region Paint handlers
private void topology_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Font font = new Font("Times New Roman", 7.0f); // choose the type of font and its size
StringFormat format = new StringFormat(); // declare string format
format.Alignment = StringAlignment.Center; // declare string alignment
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; // declare the quality for the drawings
Pen transmissionRangeColor = Pens.LightCyan; // the color used to draw the ellipse which repesents the transmission range for each node
Pen nodeNieghbors = Pens.LightSeaGreen; // the color used to draw the green lines between sensor nodes which indicates direct connection between nodes
Pen sinkNieghbors = Pens.Azure;
Brush nodeName = Brushes.White; // the color used for strings used to name the nodes
Brush auvSendMsg = Brushes.Red; // the color used for strings used to name the nodes
#region Display Sink
if (deploymentButtonWasClicked) // chech if the "Deploy" button was clicked
{
DrawImage("C:/Users/AMCT/Desktop/project/C#-Code-VisualStudio-2010/GAAPS/Sink.png", e.Graphics, sink.sinkX, sink.sinkY, 35, 45);
DrawString("Sink", e.Graphics, font, nodeName, new Point3D(600, 600 + 34, 233), 5);// Display the sink name
#region Draw Grid
topology2.Invalidate();
DrawGrid(numOfCells, cellSide, 800, e.Graphics);
DrawGrid(numOfCells, cellSide, 700, e.Graphics);
DrawGrid(numOfCells, cellSide, 600, e.Graphics);
DrawGrid(numOfCells, cellSide, 500, e.Graphics);
DrawGrid(numOfCells, cellSide, 400, e.Graphics);
for (int j = 0; j < rows; j++)
for (int i = 0; i < columns; i++)
{
DrawRectangle(e.Graphics, Brushes.SteelBlue, new Point3D(cellsCenters[0, i], cellsCenters[1, j], 800));
DrawRectangle(e.Graphics, Brushes.SteelBlue, new Point3D(cellsCenters[0, i], cellsCenters[1, j], 700));
DrawRectangle(e.Graphics, Brushes.SteelBlue, new Point3D(cellsCenters[0, i], cellsCenters[1, j], 600));
DrawRectangle(e.Graphics, Brushes.SteelBlue, new Point3D(cellsCenters[0, i], cellsCenters[1, j], 500));
DrawRectangle(e.Graphics, Brushes.SteelBlue, new Point3D(cellsCenters[0, i], cellsCenters[1, j], 400));
}
base.OnPaint(e);
#endregion
#region Display Sensor Nodes
/// node[0,i] means >> x-axis
/// node [1,i] means >> y-axis
for (int n = 0; n < NodeNum; n++)
{
DrawSensor(new Point3D(SNsLocation[0, n], SNsLocation[1, n], 760), new Point3D(SNsLocation[0, n], SNsLocation[1, n], SNs[n].snDepth), e.Graphics);
//DrawTransmissionRange(e.Graphics, transmissionRangeColor, new Point3D(SNsLocation[0, n],SNsLocation[1, n],SNs[n].snDepth), transmissionRange);
DrawString("SN" + (n + 1), e.Graphics, font, nodeName, new Point3D(SNsLocation[0, n] - 30, SNsLocation[1, n] - 10, SNs[n].snDepth), 12); // display node name
/*for (int i = 0; i < NodeNum - 1; i++)
{
if (SNsNighbors[n, i] == 1) // Green line between nieghbors
DrawLine(e.Graphics, nodeNieghbors, new Point3D(SNsLocation[0, n] + 5, SNsLocation[1, n] + 5, SNs[n].snDepth), new Point3D(SNsLocation[0, i] + 5, SNsLocation[1, i] + 5,SNs[i].snDepth));
}*/
}
#endregion
#region AUV-Animation
for (int i = 0; i < 4; i++)
{
DrawImage("C:/Users/AMCT/Desktop/project/C#-Code-VisualStudio-2010/GAAPS/AUVs-Icon.png", e.Graphics, auv[i].auvX, auv[i].auvY, 45, 20);
base.OnPaint(e);
}
}
#endregion
# endregion
// finish painting
}
/// <summary>
/// Draws a sensor at the specified position(s)
/// </summary>
private void DrawSensor(Point3D from, Point3D to, Graphics gr)
{
DrawLine(gr, Pens.Maroon, from, to);
DrawSphere(gr, Pens.Black, Brushes.Gold, to, 6);
}
/// <summary>
/// Draws a sensor at the specified position(s)
/// </summary>
private void DrawSendingSensor(Point3D from, Point3D to, Graphics gr)
{
DrawLine(gr, Pens.Maroon, from, to);
DrawSphere(gr, Pens.Black, Brushes.Black, 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 < Math.Sqrt(numOfCells) + 1; i++)
{
// Vertical
DrawLine(gr, p, new Point3D(i * cellSize + 200, 200, depth), new Point3D(i * cellSize + 200, 700, depth));
// Horizontal
DrawLine(gr, p, new Point3D(200, i * cellSize + 200, depth), new Point3D(700, i * cellSize + 200, 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>
/// Draws a small Rectangle to represent the center point for each cell in the grid
/// </summary>
private void DrawRectangle(Graphics graphics, Brush brush, Point3D center)
{
PointF center2D = Project(center);
graphics.FillRectangle(brush, center2D.X, center2D.Y, 2, 2);
}
/// <summary>
/// Projects a Point3D to a PointF
/// </summary>
///
/// <summary>
/// Draws a string at the specified position
/// </summary>
private void DrawString(String s, Graphics gr, Font f, Brush fill, Point3D center, float radius)
{
PointF center2D = Project(center);
gr.DrawString(s, f, fill, center2D.X - radius, center2D.Y - radius);
}
/// <summary>
/// Draws a string at the specified position
/// </summary>
private void DrawImage(String path, Graphics gr, float x, float y, int rectX, int rectY)
{
gr.DrawImage(new Bitmap(path), new Rectangle((int)x, (int)y, rectX, rectY)); // draw AUV
}
/// <summary>
/// Draws a transmission range for each node at the specified position
/// </summary>
private void DrawTransmissionRange(Graphics gr, Pen color, Point3D center, int tRange)
{
PointF center2D = Project(center);
gr.DrawEllipse(color, center2D.X - (tRange / 2) + 5, center2D.Y - (tRange / 2) + 5, tRange, tRange); // draw the tranmission range of node
}
/// <summary>
/// Converts from 3D point to 2D point
/// </summary>
private PointF Project(Point3D p)
{
Perspective per = new Perspective();
return per.Project(p);
}
#endregion
#region Cells Center Points
public void calculateCellsCenters(int intialPointX, int intialPointY, int lastPointX, int lastPointY, int cells, int squareGridX, int squareGridY)
{
double diagonalLengthEachCell;
numOfCells = cells;
int netArea = squareGridX * squareGridY;
double cellArea = netArea / numOfCells;
FileStream fs = new FileStream("C:/Users/AMCT/Desktop/testPositions.txt", FileMode.Append, FileAccess.Write);
cellSide = (int)Math.Sqrt(cellArea);
int centerPointEachCell;
columnsXs = new int[columns + 1];
cellsCenters = new int[2, rows]; // 0 for the point on the x axis and 1 for the point on the y axis so this is why the first element of size 2
rowsYs = new int[rows + 1];
diagonalLengthEachCell = cellSide * Math.Sqrt(2);
centerPointEachCell = (int)diagonalLengthEachCell / 3;
columnsXs[0] = intialPointX; // to let the first point for the first column equal to 300 later on
//Calculate The Columns Points
for (int k = 1; k < (columns + 1); k++)
columnsXs[k] = columnsXs[k - 1] + cellSide;
rowsYs[0] = intialPointY; // its equal to 175 in our case to let the first pint for the first column equal to 200 later on
//Calculate The Rows Points
for (int s = 1; s < (rows + 1); s++)
rowsYs[s] = rowsYs[s - 1] + cellSide;
/***calculate-centers***/
using (StreamWriter sw = new StreamWriter(fs))
{
for (int i = 0; i < rows; i++)
{
cellsCenters[1, i] = rowsYs[i] + centerPointEachCell;
for (int j = 0; j < columns; j++)
{
cellsCenters[0, j] = columnsXs[j] + centerPointEachCell;
sw.Write("({0},{1}) ", cellsCenters[0, j], cellsCenters[1, i]);
}
sw.WriteLine();
}
}
}
#endregion
public void makeDrawing()
{
iSetupDisplay = 0;
if (iSetupDisplay != -1)
{
iSetupDisplay += 10;
if (iSetupDisplay >= topology2.Width)
iSetupDisplay = -1;
topology2.Refresh();
}
}
}
}
I used this method in the previous code to enable the drawing:
public void makeDrawing()
{
iSetupDisplay = 0;
if (iSetupDisplay != -1)
{
iSetupDisplay += 10;
if (iSetupDisplay >= topology2.Width)
iSetupDisplay = -1;
topology2.Refresh();
}
}
But I can't get the things painted on the picture box as I want! The following code is the code I use to make the projection:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using AUVtopology;
namespace AUV_Topology
{
[TypeConverter(typeof(ExpandableObjectConverter))]
public class Perspective
{
public float X_shift { get; set; }
public float Y_shift { get; set; }
public float X_x { get; set; }
public float X_y { get; set; }
public float X_z { get; set; }
public float Y_x { get; set; }
public float Y_y { get; set; }
public float Y_z { get; set; }
public Perspective()
{
this.X_shift = 420;
this.Y_shift = -400;
this.X_x = -0.4f;
this.X_y = 1.0f;
this.X_z = 0.0f;
this.Y_x = 0.4f;
this.Y_y = 0.0f;
this.Y_z = 1.0f;
}
public PointF Project(Form1.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);
}
public PointF Project(Form2.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);
}
}
public class PerspectiveGrid : Control
{
private Perspective _perspective;
public Perspective Perspective
{
get { return _perspective; }
set
{
_perspective = value;
Invalidate();
}
}
public PerspectiveGrid()
{
Perspective = new Perspective
{
X_shift = 420,
Y_shift = -400,
X_x = -0.4f,
X_y = 1.0f,
X_z = 0.0f,
Y_x = 0.4f,
Y_y = 0.0f,
Y_z = 1.0f,
};
}
}
}
Is the problem in the method that I use to enable drawing or something else?!
It's easy. You just need to get graphics context of the image box.
Graphics g = Graphics.FromImage(this.pictureBox1.Image);
After you do that, you use the "g" in my example to do any line drawing, etc that you want to do. Not that this will still require you to invalidate the picture box after drawing to it, but you don't have to have your drawing code in
Form_Paint, and you don't need to mess with buffering settings. Personally i prefer this method to drawing in the Form_paint since it is persistent and doesn't have to be redrawn every frame (manually).
To prove it works:
Related
I am trying to update a Quadtree code to an Octree
I am trying to Use the QuadTree code to develop an Octree code. However I am stuck when it comes to changing the Rectangle3d to a Box. Basically I have a function to split the nodes, when slitting the rectangle I used the width and height and divided them, then use the constructor - Rectangle3d(Plane, Double, Double) but I am stuck as to which constructor to use and how to calculate it when I change from Rectangle3d to Box. Can anyone help me with this? public static Octree oct; public static DataTree < Point3d > psOUT; public static List<Line> lns = new List<Line>(); //////////Octree//////// public class Octree { public int MAX_OBJECTS = 10; public int MAX_LEVELS = 8; private int level; private List<Point3d>objects; private Box bounds; private Octree[] nodes; /* * Constructor */ public Octree(int pLevel, Box pBounds) { level = pLevel; objects = new List<Point3d>(); bounds = pBounds; nodes = new Octree[8]; } // implement the five methods of a Octree: clear, split, getIndex, insert, and retrieve. /* * Clears the Octree */ public void clear() { objects.Clear(); for (int i = 0; i < nodes.Length; i++) { if (nodes[i] != null) { nodes[i].clear(); nodes[i] = null; } } } /* * Splits the node into 8 subnodes */ private void split() { double subWidth = bounds.X * 0.5; double subDepth = bounds.Y * 0.5; double subHeight = bounds.Z *0.5; double x = bounds.X.T0; double y = bounds.Y.T0; double z = bounds.Z.T0; nodes[3] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x + subWidth, y, 0), new Point3d(x + 2 * subWidth, y + subHeight, 0))); nodes[2] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x, y, 0), new Point3d(x + subWidth, y + subHeight, 0))); nodes[1] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x, y + subHeight, 0), new Point3d(x + subWidth, y + 2 * subHeight, 0))); nodes[0] = new Quadtree(level + 1, new Box(Plane.WorldXY, new Point3d(x + subWidth, y + subHeight, 0), new Point3d(x + 2 * subWidth, y + 2 * subHeight, 0))); }
Maybe a little late but here it goes: Considering you have a Box in 3D space already constructed. In order to divide it into 8 smaller boxes you can use the X,Y,Z coordinate interval between each of the corners and the box center point. So, you would have something like this: private List<Box> Split(Box box) { List<Box> boxes = new List<Box>(); foreach(Point3d corner in box.GetCorners()) { Box newbox = CreateBoxFromPlaneAndTwoCorners(box.Plane, box.Center, corner); boxes.Add(newbox); } return boxes; } private Box CreateBoxFromPlaneAndTwoCorners(Plane plane, Point3d cornerA, Point3d cornerB) { plane.RemapToPlaneSpace(cornerA, out Point3d remapA); plane.RemapToPlaneSpace(cornerB, out Point3d remapB); Interval intX = new Interval(remapA.X,remapB.X); Interval intY = new Interval(remapA.Y,remapB.Y); Interval intZ = new Interval(remapA.Z,remapB.Z); return new Box(plane,intX,intY,intZ); }
Drawing circles with increasing radius in C#
I am using the below code to draw the circles(reading centres from a csv file) with increasing radius. The increase in radius is 5 units per circle. namespace MATLAB_file { public partial class Form1 : Form { string[] read; float th; int c = 0; int r; public List<PointF> circleCoordinates = new List<PointF>(); int rl; public Form1() { InitializeComponent(); } protected override void OnPaint(PaintEventArgs e) { Pen linePen = new Pen(System.Drawing.Color.CornflowerBlue); Graphics grphx = this.CreateGraphics(); grphx.Clear(this.BackColor); foreach (PointF point in this.circleCoordinates) { Pen redPen1 = new Pen(Color.Red, 100); e.Graphics.DrawArc(Pens.Red, point.X, point.Y, 1, 1, 0, 120F); } linePen.Dispose(); base.OnPaint(e); } private void Form1_Load(object sender, EventArgs e) { double xx, yy; int i; int n = 0; float[] centre1 = new float[1000]; System.IO.StreamReader sr; sr = new System.IO.StreamReader("centers.txt", true); char[] seperators = { ',' }; string data = sr.ReadLine(); read = data.Split(new Char[] { ',' }); rl = read.Length; int a1 = rl / 2; for (c = 0; c < rl; c++) { centre1[c] = float.Parse(read[c]); } while (r < 200) { for (i = 0; i < a1; i++) { while (th < 360) { xx = r * Math.Cos(th) + centre1[2 * i] + 100; xx1 = (float)xx; yy = r * Math.Sin(th) + centre1[2 * i + 1] + 100; yy1 = (float)yy; this.circleCoordinates.Add(new PointF(xx1, yy1)); this.Invalidate(); th = th + .360F; } th = 0; } r = r + 5; } } } } The above code is displaying all the circles but I do not want all circles to be displayed on canvas, rather only one circle should show with gradual increase in radius Please suggest how to delete the previous drawn circle on drawing new one. Is there any other way to do it, if my later use includes removal of certain section of circles based on "th" values?
If you move the Clear call within the foreach you will see only the last drawn circle, though this could be achieved with drawing only the Last circleCoordinates too. foreach (PointF point in this.circleCoordinates) { grphx.Clear(this.BackColor); Pen redPen1 = new Pen(Color.Red, 100); e.Graphics.DrawArc(Pens.Red, point.X, point.Y, 1, 1, 0, 120F); } An alternative interpretation: You want animation, which generates the onPaint events (by timer ticks or on user input) and you increase a counter to select the circle to draw. For that, you will need a new member in your program, like int Index; and you could select the circle based on this, using something the following code snippet (assuming you always have at least 1 circleCoordinates, animation restarts after it finished): PointF point = this.circleCoordinates[Index % circleCoordinates.Length]; or (last circle remain on the screen after the animation) PointF point = this.circleCoordinates[Math.Min(Index, circleCoordinates.Length - 1)];
How to create control that draws a table in panel
I want create a control that draws a table in panel . My code is: public class PanelZ : System.Windows.Forms.Panel { public static void Draw() { Panel p = new Panel(); p.Width = 200; p.Height = 200; Graphics g = p.CreateGraphics(); Pen mypen = new Pen(Brushes.Black, 1); Font myfont = new Font("tahoma", 10); int lines = 9; float x = 0; float y = 0; float xSpace = p.Width / lines; float yspace = p.Height / lines; for (int i = 0; i < lines + 1; i++) { g.DrawLine(mypen, x, y, x, p.Height); x += xSpace; } x = 0f; for (int i = 0; i < lines + 1; i++) { g.DrawLine(mypen, x, y, p.Width, y); y += yspace; } } ..but it dosen't draw a table; so what should I do?
This will work. But the numbers ought to be properties, as should the pen and then some.. Also: Properties ought to start with an uppercase letter. public class PanelZ : System.Windows.Forms.Panel { public PanelZ() // a constructor { Width = 200; Height = 200; DoubleBuffered = true; lines = 9; } public int lines { get; set; } // a property protected override void OnPaint(PaintEventArgs e) // the paint event { base.OnPaint(e); Graphics g = e.Graphics; Pen mypen = new Pen(Brushes.Black, 1); Font myfont = new Font("tahoma", 10); float x = 0; float y = 0; float xSpace = Width / lines; float yspace = Height / lines; for (int i = 0; i < lines + 1; i++) { g.DrawLine(mypen, x, y, x, Height); x += xSpace; } for (int i = 0; i < lines + 1; i++) { g.DrawLine(mypen, 0, y, Width, y); y += yspace; } } } At work in VS: Note that this only colors pixels. There is no useful grid there, just pixels with color.. So, if you actually want to use the Font you define you will have to calculate the coodordinates and the bounding boxes.
How can i color the points in the paint event faster?
This is the code . But it's not coloring the bmp4 in yellow. Maybe i did something wrong with the test variable and bmp4 variable and the CreateNonIndexedImage method ? Tried also to save the bmp4 but it's not working. In form1 when the operation end i'm saving the bitmap like this: CloudEnteringAlert.test.Save(#"c:\temp\yellowbmpcolor.jpg"); But the area that supposed to be in yellow is not it's justl ike the original image. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using System.IO; using DannyGeneral; using System.Reflection; using System.Diagnostics; using System.Drawing.Imaging; using System.Runtime.InteropServices; namespace mws { public static class CloudEnteringAlert { private static PointF point1; private static PointF point2; public static float redlinerectx1= 0; public static float redlinerecty1 = 0; public static float redlinerectx = 0; public static float redlinerecty = 0; private static Bitmap bm; private static Bitmap bmp2 = new Bitmap(#"C:\Temp\New folder (17)\radar001486.GIF"); public static Bitmap test = new Bitmap(#"D:\MyWeatherStation-Images-And-Icons\radar090.PNG"); public static Bitmap bmp4 = CreateNonIndexedImage(test); static BitmapData b1 = bmp4.LockBits(new System.Drawing.Rectangle(0, 0, bmp4.Width, bmp4.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb); static int stride = b1.Stride; static int k1, x1, y1; static float fx, fy; static System.IntPtr Scan0 = b1.Scan0; public static List<string> pointscoordinates = new List<string>(); public static float radius = 2.0f; private static Label lbl1 = new Label(); public static bool cloudsfound; // blinking colors: yellow, red, yellow, transparent, repeat... public static Brush[] cloudColors = new[] { Brushes.Yellow, Brushes.Transparent }; // current color index public static int cloudColorIndex = 0; public static List<PointF> AddDistanceToPoints = new List<PointF>(); public static List<PointF> MovingPoints = new List<PointF>(); public static List<PointF> PointsFloat = new List<PointF>(); public static List<Point> PointsInt; public static List<PointF> pointtocolor = new List<PointF>(); public static List<PointF> extendedPoints = new List<PointF>(); public static Bitmap newbitmap; private static List<PointF> clouds1; public static List<PointF> clouds; public static List<PointF> cloudsG = new List<PointF>(); public static List<PointF> cloudsY; public static List<PointF> cloudsR; private static Bitmap bmp3; private static int tolerancenumeric = 0; private static double[] treshhold_array = { 100, 50, 40, 30, 24, 18, 13, 9, 6, 4, 2, 1.2, 0.7, 0.2, 0.1 }; static List<float> LoadPoints_X = new List<float>(); static List<float> LoadPoints_Y = new List<float>(); static List<float> points_X = new List<float>(); static List<float> points_Y = new List<float>(); static string path; static string file; static List<PointF> points; public static Bitmap CreateNonIndexedImage(Image src) { Bitmap newBmp = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); using (Graphics gfx = Graphics.FromImage(newBmp)) { gfx.DrawImage(src, 0, 0); } return newBmp; } static CloudEnteringAlert() { points = new List<PointF>(); cloudsfound = false; } public static void Paint(Graphics e, double currentFactor, float kilometers) { Pen myPen = new Pen(Brushes.Red, 2); float x, y ,width, height; float distance = kilometers / (float)1.09;//289617486; // One pixel distance is 1.09 kilometer. if (points == null) { return; } redlinerectx = MovingPoints[0].X; redlinerecty = MovingPoints[0].Y; if (clouds != null) { y = PointsInt.Min(p => p.Y); PointF pointsIntMin = PointsInt.First(p => p.Y == y); //point with minimum Y in PointsInt list y = PointsInt.Max(p => p.Y); PointF pointsIntMax = PointsInt.First(p => p.Y == y); //point with maximum Y in PointsInt list y = MovingPoints.Min(p => p.Y); PointF movingPointsMin = MovingPoints.First(p => p.Y == y); //point with minimum Y in MovingPoints list y = MovingPoints.Max(p => p.Y); PointF movingPointsMax = PointsInt.First(p => p.Y == y); //point with minimum Y in MovingPoints list x = pointsIntMin.X * (float)currentFactor; y = pointsIntMin.Y * (float)currentFactor; width = movingPointsMin.X + distance - x; height = (pointsIntMax.Y - pointsIntMin.Y) * (float)currentFactor; if (clouds != null) { e.DrawRectangle(myPen, (int)x, (int)y, (int)width, (int)height); } myPen.Dispose(); try { unsafe { byte* p; for (k1 = 0; k1 < pointtocolor.Count; k1++) { //set pointer to the beggining p = (byte*)(void*)Scan0; fx = pointtocolor[k1].X * (float)currentFactor; fy = pointtocolor[k1].Y * (float)currentFactor; //check if point is inside bmp if ((int)fx >= bmp.Width || (int)fy >= bmp.Height) { continue; } //Add offset where the point is. The formula: position = Y * stride + X * 4 x = (int)(fy * (float)stride); y = (int)(fx * 4F); p += (x1 + y1); //set yellow color p[1] = p[2] = (byte)255; p[0] = (byte)0; p[3] = (byte)255; } } bmp.UnlockBits(b1); } catch { string t = "err"; } } } EDIT It is working but the color is not the yellow i need: This is what i get: And when i used with SetPixel this is what i got and what i want to get now too:
Draw individual pixels from list with yellow color on bmp Bitmap: BitmapData b1 = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb); int stride = b1.Stride; int k, x, y; float fx, fy; System.IntPtr Scan0 = b1.Scan0; unsafe { byte* p; for (k = 0; k < pointtocolor.Count; k++) { //set pointer to the beggining p = (byte*)(void*)Scan0; fx = pointtocolor[k].X * (float)currentFactor; fy = pointtocolor[k].Y * (float)currentFactor; //check if point is inside bmp if( (int)fx >= bmp.Width || (int)fy >= bmp.Height) { continue; } //Add offset where the point is. The formula: position = Y * stride + X * 4 x = (int)fy * stride; y = (int)fx * 4; p += ( x + y ); //set yellow color p[1] = p[2] = (byte)255; p[0] = (byte)0; p[3] = (byte)255; } } bmp.UnlockBits(b1);
Index was outside of bounds of the array while comparing images
I am trying to figure this one out. I am comparing images in my program. For the most part when I try and compare the image I have no issues. Although when I use a few different combinations I get this error. I originally thought it was because the image formats were different. Although that is not the case. If I take each image and compare them against something else it works fine. Just not when compared against eachother. I have marked below where the error appears. public Color this[int x, int y] { get { int index = (x + (y * image.Width)) * 4; return Color.FromArgb(rgbValues[index + 3], rgbValues[index + 2], rgbValues[index + 1], rgbValues[index]); //This line is where the index out of bounds of the array error happens. } set { int index = (x + (y * image.Width)) * 4; rgbValues[index] = value.B; rgbValues[index + 1] = value.G; rgbValues[index + 2] = value.R; rgbValues[index + 3] = value.A; } } /// <summary> /// Width of the image. /// </summary> public int Width { get { return image.Width; } } /// <summary> /// Height of the image. /// </summary> public int Height { get { return image.Height; } } /// <summary> /// Returns the modified Bitmap. /// </summary> I would appreciate any help. I am so confused to why it only happens when the images are used in combination. In case you were wondering how I load the image I do it in vb.net. The C# code is in a dll. Here is my vb.net code to load the bitmap to the memory. Also the image size is: 431x253 Dim bm As Bitmap = Bitmap.FromFile(Label1.Text) Dim bm2 As Bitmap = Bitmap.FromFile(Label2.Text) ' Dim pnt As Point = ImageFinder.Contains(bm, bm2) Dim ir As New ImageChecker(bm, bm2) Dim imageContains As Boolean = ir.findimageboolean() MessageBox.Show(imageContains) EDIT: Here is the full code of the DLL using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.IO; namespace ImageRecognition { public class LockedFastImage { private Bitmap image; private byte[] rgbValues; private System.Drawing.Imaging.BitmapData bmpData; private IntPtr ptr; private int bytes; public LockedFastImage(Bitmap image) { this.image = image; Rectangle rect = new Rectangle(0, 0, image.Width, image.Height); bmpData = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, image.PixelFormat); ptr = bmpData.Scan0; bytes = Math.Abs(bmpData.Stride) * image.Height; rgbValues = new byte[bytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); } ~LockedFastImage() { // Try to unlock the bits. Who cares if it dont work... try { image.UnlockBits(bmpData); } catch { } } /// <summary> /// Returns or sets a pixel of the image. /// </summary> /// <param name="x">x parameter of the pixel</param> /// <param name="y">y parameter of the pixel</param> public Color this[int x, int y] { get { int index = (x + (y * image.Width)) * 4; return Color.FromArgb(rgbValues[index + 3], rgbValues[index + 2], rgbValues[index + 1], rgbValues[index]); } set { int index = (x + (y * image.Width)) * 4; rgbValues[index] = value.B; rgbValues[index + 1] = value.G; rgbValues[index + 2] = value.R; rgbValues[index + 3] = value.A; } } /// <summary> /// Width of the image. /// </summary> public int Width { get { return image.Width; } } /// <summary> /// Height of the image. /// </summary> public int Height { get { return image.Height; } } /// <summary> /// Returns the modified Bitmap. /// </summary> public Bitmap asBitmap() { System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); return image; } } public class ImageChecker { private LockedFastImage big_image; private LockedFastImage small_image; /// <summary> /// The time needed for last operation. /// </summary> public TimeSpan time_needed = new TimeSpan(); /// <summary> /// Error return value. /// </summary> static public Point CHECKFAILED = new Point(-1, -1); /// <summary> /// Constructor of the ImageChecker /// </summary> /// <param name="big_image">The image containing the small image.</param> /// <param name="small_image">The image located in the big image.</param> public ImageChecker(Bitmap big_image, Bitmap small_image) { this.big_image = new LockedFastImage(big_image); this.small_image = new LockedFastImage(small_image); } /// <summary> /// Returns the location of the small image in the big image. Returns CHECKFAILED if not found. /// </summary> /// <param name="x_speedUp">speeding up at x achsis.</param> /// <param name="y_speedUp">speeding up at y achsis.</param> /// <param name="begin_percent_x">Reduces the search rect. 0 - 100</param> /// <param name="end_percent_x">Reduces the search rect. 0 - 100</param> /// <param name="begin_percent_x">Reduces the search rect. 0 - 100</param> /// <param name="end_percent_y">Reduces the search rect. 0 - 100</param> public Point bigContainsSmall(int x_speedUp = 4, int y_speedUp = 4, int begin_percent_x = 0, int end_percent_x = 100, int begin_percent_y = 0, int end_percent_y = 100) { /* * SPEEDUP PARAMETER * It might be enough to check each second or third pixel in the small picture. * However... In most cases it would be enough to check 4 pixels of the small image for diablo porposes. * */ /* * BEGIN, END PARAMETER * In most cases we know where the image is located, for this we have the begin and end paramenters. * */ DateTime begin = DateTime.Now; if (x_speedUp < 1) x_speedUp = 1; if (y_speedUp < 1) y_speedUp = 1; if (begin_percent_x < 0 || begin_percent_x > 100) begin_percent_x = 0; if (begin_percent_y < 0 || begin_percent_y > 100) begin_percent_y = 0; if (end_percent_x < 0 || end_percent_x > 100) end_percent_x = 100; if (end_percent_y < 0 || end_percent_y > 100) end_percent_y = 100; int x_start = (int)((double)big_image.Width * ((double)begin_percent_x / 100.0)); int x_end = (int)((double)big_image.Width * ((double)end_percent_x / 100.0)); int y_start = (int)((double)big_image.Height * ((double)begin_percent_y / 100.0)); int y_end = (int)((double)big_image.Height * ((double)end_percent_y / 100.0)); /* * We cant speed up the big picture, because then we have to check pixels in the small picture equal to the speeded up size * for each pixel in the big picture. * Would give no speed improvement. * */ //+ 1 because first pixel is in picture. - small because image have to be fully in the other image for (int x = x_start; x < x_end - small_image.Width + 1; x++) for (int y = y_start; y < y_end - small_image.Height + 1; y++) { //now we check if all pixels matches for (int sx = 0; sx < small_image.Width; sx += x_speedUp) for (int sy = 0; sy < small_image.Height; sy += y_speedUp) { if (small_image[sx, sy] != big_image[x + sx, y + sy]) goto CheckFailed; } //check ok time_needed = DateTime.Now - begin; return new Point(x, y); CheckFailed: ; } time_needed = DateTime.Now - begin; return CHECKFAILED; } public Boolean findimageboolean(int x_speedUp = 1, int y_speedUp = 1, int begin_percent_x = 0, int end_percent_x = 100, int begin_percent_y = 0, int end_percent_y = 100) { /* * SPEEDUP PARAMETER * It might be enough to check each second or third pixel in the small picture. * However... In most cases it would be enough to check 4 pixels of the small image for diablo porposes. * */ /* * BEGIN, END PARAMETER * In most cases we know where the image is located, for this we have the begin and end paramenters. * */ DateTime begin = DateTime.Now; if (x_speedUp < 1) x_speedUp = 1; if (y_speedUp < 1) y_speedUp = 1; if (begin_percent_x < 0 || begin_percent_x > 100) begin_percent_x = 0; if (begin_percent_y < 0 || begin_percent_y > 100) begin_percent_y = 0; if (end_percent_x < 0 || end_percent_x > 100) end_percent_x = 100; if (end_percent_y < 0 || end_percent_y > 100) end_percent_y = 100; int x_start = (int)((double)big_image.Width * ((double)begin_percent_x / 100.0)); int x_end = (int)((double)big_image.Width * ((double)end_percent_x / 100.0)); int y_start = (int)((double)big_image.Height * ((double)begin_percent_y / 100.0)); int y_end = (int)((double)big_image.Height * ((double)end_percent_y / 100.0)); /* * We cant speed up the big picture, because then we have to check pixels in the small picture equal to the speeded up size * for each pixel in the big picture. * Would give no speed improvement. * */ //+ 1 because first pixel is in picture. - small because image have to be fully in the other image for (int x = x_start; x < x_end - small_image.Width + 1; x++) for (int y = y_start; y < y_end - small_image.Height + 1; y++) { //now we check if all pixels matches for (int sx = 0; sx < small_image.Width; sx += x_speedUp) for (int sy = 0; sy < small_image.Height; sy += y_speedUp) { if (small_image[sx, sy] != big_image[x + sx, y + sy]) goto CheckFailed; } //check ok time_needed = DateTime.Now - begin; return true; CheckFailed: ; } time_needed = DateTime.Now - begin; return false; } } }
If Stride is negative you need to copy image bytes in a different way, so I made some modifications to your constructor: public LockedFastImage(Bitmap image) { this.image = image; Rectangle rect = new Rectangle(0, 0, image.Width, image.Height); bmpData = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); ptr = bmpData.Scan0; bytes = Math.Abs(bmpData.Stride) * image.Height; rgbValues = new byte[bytes]; if (bmpData.Stride < 0) { int lines, pos, BytesPerLine = Math.Abs(bmpData.Stride); for (lines = pos = 0; lines < image.Height; lines++, pos += BytesPerLine) { System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, pos, BytesPerLine); ptr = (IntPtr)(ptr.ToInt64() + bmpData.Stride); } } else System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); } If you are storing pixel data as ARGB, you need to lock pixels using the corresponding PixelFormat. I also modified your accessors: public Color this[int x, int y] { get { int index = y * (image.Width << 2) + x; return Color.FromArgb(rgbValues[index + 3], rgbValues[index + 2], rgbValues[index + 1], rgbValues[index]); } set { int index = y * (image.Width << 2) + x; rgbValues[index] = value.B; rgbValues[index + 1] = value.G; rgbValues[index + 2] = value.R; rgbValues[index + 3] = value.A; } } By the way, I haven't tested this code! Strictly speaking, you should save BytesPerLine as a private field and then use it to calculate index in your accessors. So you should change this (image.Width << 2) to BytesPerLine. Also you can try changing your get accessor to the following (not sure if it's faster, but you can try it if you wish): get { return Color.FromArgb(BitConverter.ToInt32(rgbValues, y * (image.Width << 2) + x)); }