I've been searching for just over a week now on how to create something like this.
I have the code and for loops to create each Panel by X, and Y coords and everything. Each Panel is part of an array and starts at 0 at top left and ends at 90 at top right, but I don't care how its done as long as its done and its panels and works. The colors don't need to be the same but something similar so that I can have a fullscreen color picker. If someone knows some code to take one specific color and make it brighter ten times to set the panels backColor, using Color.FromARGB or just the Color class, to then please help me out. Thank you.
(This is a app I'm making for windows tablet and is touchscreen. The purpose of the app is to be fullscreen and not reviele that its a windows tablet, There for I have to make the color picker myself and cannot use the built in color dialog.)
For best control I suggest using a color calculation function.
There are many out there; here is one I use:
Color HsvToRgb(double h, double S, double V)
{
/// Convert HSV to RGB
/// h is from 0d - 360d
/// s,v values are 0d - 1d
/// r,g,b values are 0 - 255
int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
double f = hue / 60 - Math.Floor(hue / 60);
value = value * 255;
int v = Convert.ToInt32(value);
int p = Convert.ToInt32(value * (1 - saturation));
int q = Convert.ToInt32(value * (1 - f * saturation));
int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));
if (hi == 0) return Color.FromArgb(255, v, t, p);
else if (hi == 1) return Color.FromArgb(255, q, v, p);
else if (hi == 2) return Color.FromArgb(255, p, v, t);
else if (hi == 3) return Color.FromArgb(255, p, q, v);
else if (hi == 4) return Color.FromArgb(255, t, p, v);
else return Color.FromArgb(255, v, p, q);
}
Do note the input ranges!!
Now it is easy to setup a Color array at class level:
int width = 10;
int height = 9;
Color[,] colors;
And fill it:
void loadColors()
{
colors = new Color[width, height];
// load greys
for (int i = 0; i < width; i++ ) colors[i, 0] = HsvToRgb(0f, 0f, 1f * i / width);
// load bright stripe:
for (int i = 0; i < width; i++) colors[i, 1] = HsvToRgb(i* 360f / width, 0.33f, 1f);
// load matrix:
for (int j = 2; j < height; j++)
for (int i = 0; i < width; i++)
colors[i, j] = HsvToRgb(i * 360f / width, 1f, 1f * (height - j + 2) / height);
}
From this is is a snap to set the BackColors of your Panels.
Here is a Form.Paint function, I used to create the above screenshot:
private void Form1_Paint(object sender, PaintEventArgs e)
{
int w = ClientSize.Width / width;
int h = ClientSize.Height / height;
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
{
using (SolidBrush brush = new SolidBrush(colors[i,j]))
e.Graphics.FillRectangle(brush, i * w, j * h, w, h);
}
}
Of course it is as simple as changing two numbers to make a finer grid, here 20x20:
Also note how the even spacing of hues doesn't really work well, as neither the human eye nor our common display systems are equally sensitive to changes in hues across the spectrum..
The eye is actually rather sensitive to greenish hues
the just-noticeable difference in wavelength varies from about 1 nm in
the blue-green and yellow wavelengths, to 10 nm and more in the longer
red and shorter blue wavelengths
but our monitors do a pretty bad job at creating different green hues..
Using an adapted list of perceptionally evenly spaced hues might help, depending on what you want..
Using this one-liner:
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
int hue = (int) ((Bitmap)pictureBox1.Image).GetPixel(e.X, e.Y).GetHue();
}
on the image above gives us one such list of hues:
20 32 41 50 58 72 133 163 170 177 183 190 197 206 269 288 307 324 334 346
I have modified it a little, maybe to make it work better with my monitor:
List<int> hues = new List<int>
{ 20, 32, 41, 50, 58, 72, 133, 162, 180, 188, 195, 205, 215, 223, 246, 267, 288, 300, 320, 346 };
And changing the above code (keeping width = 20) to
HsvToRgb(hues[i],..
results in this:
Update: I have replaced the HsvToRgb function by a greatly simplified one.
With this answer you'll get the possibility to use the HSB representation of a color (maybe take also a look here).
By using this you can for the first row use a random hue, a zero saturation and a brightness going from 1.0 to 0.0 in the amount of needed steps. For the other rows you have to take 1.0 for the saturation and increase the hue from 0 to 360 in the same amount of steps and also increase the saturation from 0.0 to 1.0 per row.
I just put an example together:
private void OnResize(object sender, EventArgs e)
{
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
UpdateImage(e.Graphics);
}
private void UpdateImage(Graphics graphics)
{
var columns = 10;
var rows = 8;
var hueSteps = 360 / columns;
var columnSteps = 1.0F / columns;
var width = Width / columns;
var height = Height / (rows + 1);
for (int i = 0; i < columns; i++)
{
var gray = ColorExtensions.FromAhsb(255, 0, 0, columnSteps * i);
using (var brush = new SolidBrush(gray))
{
graphics.FillRectangle(brush, width * i, 0, width, height);
}
}
for (int i = 0; i < columns; i++)
{
for (int j = 1; j <= rows; j++)
{
var color = ColorExtensions.FromAhsb(255, hueSteps * i, 1, columnSteps * j);
using (var brush = new SolidBrush(color))
{
graphics.FillRectangle(brush, width * i, height * j, width, height);
}
}
}
}
The result is not exact the same, but that would be just a matter of re-arrange the loops:
Related
The code i have made is hard coded and i want it to convert it into circle any snippet i can add or something
The code is in C sharp, The output is like the rectangle which i have to convert it into a circle
private void pictureBox1_Click(object sender, EventArgs e)
{
int length = 100;
int flag = 0;
int flag2 = 0;
int flag3 = 0;
Pen p = new Pen(Color.Red, 4);
Graphics g = pictureBox1.CreateGraphics();
Brush redBrush = new SolidBrush(Color.Red);
for (int i = 0; i < 20; i++)
{
if(i==0 || i<10)
{
g.DrawLine(p, 622 - 10 * i, 229+10*i, 623 - 10 * i, 229+10*i);
}
if(i==10)
{
flag = 1;
}
if(flag==1)
{
g.DrawLine(p, 622 - 10 * i, 419 - 10 * i, 623 - 10 * i, 419-10*i);
flag2 = 1;
}
if(flag2 == 1)
{
g.DrawLine(p, 622 - 10 * i, 29+10*i, 623 - 10 * i, 29+10*i);
flag3 = 1;
}
if (flag3 == 1)
{
g.DrawLine(p, 432 + 10 * i, 29+10*i, 433 + 10 * i, 29 + 10 *i);
}
}
There is a built-in function for this. Use g.DrawEllipse() instead.
You can do this
void DrawCircle(Graphics g, Pen p, Point centre, double radius=20, int sides = 360)
{
var angle = 2 * Math.PI / sides;
for (int i = 0; i < sides; i++)
{
Point from = new Point((int)(radius * Math.Sin(i * angle) + centre.X), (int)(radius * Math.Cos(i * angle) + centre.Y));
Point to = new Point((int)(radius * Math.Sin((i+1) * angle) + centre.X), (int)(radius * Math.Cos((i+1) * angle) + centre.Y));
g.DrawLine(p, from, to);
}
}
and to use
DrawCircle(g, p, new Point(100, 100), 50, 8); // 8 sides, an octagon
Increase the number of sides to make it more accurate.
Alternatively,
g.DrawEllipse(p, (float)(centre.X-radius), (float)(centre.Y-radius), (float)radius*2, (float)radius*2);
I have a query regarding the best approach to detect when a moving and potentially rotated rectangle passes over a yellow pixel of a Panel's background image.
I have a method which accepts an Image and a Point, and returns true if that point is that of a yellow pixel. I require this colour detection for the function of my game, which resets the car (player) if it drives over the yellow borders of the track. This method is shown below:
private Boolean isYellow(Image image, Point point)
{
Bitmap bitmap = new Bitmap(image);
Color color = bitmap.GetPixel(point.X, point.Y);
return (color.R > 220 && color.G > 220 && color.B < 200);
}
Previously, to detect if the player rectangle passes over yellow, I checked against the location of the rectangle, as provided by the X and Y values of the object. The issue with this is that the location is the top left corner of a horizontal rectangle, meaning the car can drive almost entirely off the track without detection occurring.
I'd like to fix this by checking all points covered by the rectangle. This is not as simple as it may seem as the rectangle is likely to be rotated. My drawing and movement logic is shown below:
public void draw(Graphics g)
{
int dx = rectangle.X + (rectangle.Height / 2);
int dy = rectangle.Y + (rectangle.Width / 2);
g.ScaleTransform(xScale, yScale);
g.TranslateTransform(dx, dy);
g.RotateTransform((float) ((180 * angle) / Math.PI));
g.TranslateTransform(-dx, -dy);
g.DrawImage(image, rectangle.X, rectangle.Y);
g.ResetTransform();
}
public void move(uRaceGame game, Panel panel)
{
double cos = Math.Cos(angle), sin = Math.Sin(angle);
int xLocation = 200;
int yLocation = 200;
xLocation = (int) Math.Floor(rectangle.X + (cos * game.moveDir * 60));
yLocation = (int) Math.Floor(rectangle.Y + (sin * game.moveDir * 60));
angle = (angle + (game.rotateDir * (Math.PI / 128))) % (Math.PI * 2);
if (xLocation * xScale > panel.Width - (rectangle.Width * cos) || yLocation * yScale > panel.Height - (rectangle.Width * sin) - 5 || xLocation * xScale < 0 || yLocation * yScale < 5) return;
rectangle.Location = new Point(xLocation, yLocation);
}
I tried but failed to create a method which translates the coords of the corner and figures out the middle of the rectangle, but this does not work, and the yellow detection fires in very obscure places:
public Point getCentre()
{
int cX = (int) (rectangle.X + ((rectangle.Width / 2) / xScale)), cY = (int) (rectangle.Y + ((rectangle.Height / 2) / yScale));
float tempX = (rectangle.X - cX), tempY = (rectangle.Y - cY);
double rX = (tempX * Math.Cos(angle)) - (tempY * Math.Sin(angle));
double rY = (tempX * Math.Sin(angle)) - (tempY * Math.Cos(angle));
return new Point((int) ((rX + cX) * xScale), (int) ((rY + cY) * yScale));
}
I'd really appreciate any suggestions on how to tackle this. I included the translation and yellow detection code in case I'm miles off in my attempt and someone else has a better idea.
Thank you very much.
There are two approaches that come to my mind:
You can create loops that go along the tilted sides of the car rectangle
Or you can copy the car to an untilted bitmap and loop over it normally.
Here is an example of the second approach.
It uses a LockBits method that detects Yellow with your code in a Bitmap.
And it prepares that bitmap by copying it from the original BackgroundImage un-rotated.
Here is the result, including a control Panel that shows the untilted Rectangle:
Here is the yellow finder function. It uses Lockbits for speed:
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
public bool testForYellowBitmap(Bitmap bmp)
{
Size s1 = bmp.Size;
PixelFormat fmt = new PixelFormat();
fmt = bmp.PixelFormat;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
BitmapData bmp1Data = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt);
byte bpp1 = 4;
if (fmt == PixelFormat.Format24bppRgb) bpp1 = 3;
else if (fmt == PixelFormat.Format32bppArgb) bpp1 = 4; else return false; // throw!!
int size1 = bmp1Data.Stride * bmp1Data.Height;
byte[] data1 = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
for (int y = 0; y < s1.Height; y++)
{
for (int x = 0; x < s1.Width; x++)
{
Color c1;
int index1 = y * bmp1Data.Stride + x * bpp1;
if (bpp1 == 4)
c1 = Color.FromArgb(data1[index1 + 3], data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
else c1 = Color.FromArgb(255, data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
if (c1.R > 220 && c1.G > 220 && c1.B < 200)
{ bmp.UnlockBits(bmp1Data); return true; }
}
}
bmp.UnlockBits(bmp1Data);
return false;
}
I prepare the Bitmap to compare in the MouseMove. The variables w, h, w2, h2 hold the width, height and halves of that of the car's size. The source bitmap is in drawPanel1.BackgroundImage. The current angle is in a TrackBar tr_a.Value. For further control I also display the rotated car rectangle in White.
private void drawPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
Size sz = drawPanel1.BackgroundImage.Size;
Rectangle rectSrc = new Rectangle(e.X - w2, e.Y - h2, w, h);
Rectangle rectTgt = new Rectangle(e.X - w, e.Y - h, 2 * w, 2 * h);
using (Graphics g = drawPanel1.CreateGraphics()) // start optional
{
g.TranslateTransform(e.X, e.Y);
g.RotateTransform(trb_a.Value);
g.TranslateTransform(-e.X, -e.Y);
drawPanel1.Refresh();
g.DrawRectangle(Pens.White, rectSrc);
}
using (Graphics g = drawPanel2.CreateGraphics())
{ // end optional
using (Bitmap bmp = new Bitmap(sz.Width, sz.Height))
using (Graphics g2 = Graphics.FromImage(bmp))
{
g2.TranslateTransform(e.X, e.Y);
g2.RotateTransform(-trb_a.Value);
g2.TranslateTransform(-e.X, -e.Y);
g2.DrawImage(drawPanel1.BackgroundImage, rectTgt, rectTgt,
GraphicsUnit.Pixel);
drawPanel2.Refresh();
g.DrawImage(bmp, rectSrc, rectSrc, GraphicsUnit.Pixel);
Text = testForYellowBitmap(bmp) ? "!!YELLOW!!" : "";
}
}
}
The first approach would use a similar LockBits method, but with loops inside that go along the rotated sides of the car rectangle, using floats wth the loop variables to calculate the x-coordinates. Those data should be prepared on each change of car size or angle. The code is a little longer but should be a bit faster, too.
The advantage if the second approach is that by using a ClippingRegion on the Graphics object one could check an arbitrary shape while the first method can be easily modified for concave polygons but not for curved shapes.
Here is the adapted version of the checking code for the first version:
public bool testForYellowBitmapTilt(Bitmap bmp, List<int> leftPts,
List<int> rightPts, Point topLeft)
{
Size s1 = bmp.Size;
PixelFormat fmt = new PixelFormat();
fmt = bmp.PixelFormat;
Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
BitmapData bmp1Data = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt);
byte bpp1 = 4;
if (fmt == PixelFormat.Format24bppRgb) bpp1 = 3;
else if (fmt == PixelFormat.Format32bppArgb) bpp1 = 4;
else return false; // or throw!!
if (leftPts.Count != rightPts.Count) return false; // or throw!!
int size1 = bmp1Data.Stride * bmp1Data.Height;
byte[] data1 = new byte[size1];
System.Runtime.InteropServices.Marshal.Copy(bmp1Data.Scan0, data1, 0, size1);
for (int y = 0; y < (leftPts.Count); y++)
{
for (int x = leftPts[y] + topLeft.X; x < rightPts[y] + topLeft.X; x++)
{
Color c1;
int index1 = (y + topLeft.Y) * bmp1Data.Stride + x * bpp1;
if (index1 > 0)
{
if (bpp1 == 4)
c1 = Color.FromArgb(data1[index1 + 3], data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
else c1 = Color.FromArgb(255, data1[index1 + 2],
data1[index1 + 1], data1[index1 + 0]);
if (c1.R > 220 && c1.G > 220 && c1.B < 200)
{ bmp.UnlockBits(bmp1Data); return true; }
}
}
}
bmp.UnlockBits(bmp1Data);
return false;
}
The left- and rightside coordinates are stored here:
List<int> leftPts = new List<int>();
List<int> rightPts = new List<int>();
Point top = Point.Empty;
void getOuterPoints(List<PointF> corners, out List<int> leftPts,
out List<int> rightPts, out Point top)
{
leftPts = new List<int>();
rightPts = new List<int>();
PointF left = corners.Select(x => x).OrderBy(x => x.X).First();
PointF right = corners.Select(x => x).OrderByDescending(x => x.X).First();
top = Point.Round(corners.Select(x => x).OrderBy(x => x.Y).First());
PointF bottom = corners.Select(x => x).OrderByDescending(x => x.Y).First();
int w1 = -(int)(top.X - left.X);
int w2 = -(int)(left.X - bottom.X );
int h1 = (int)(left.Y - top.Y);
int h2 = (int)(bottom.Y - left.Y);
float d1 = 1f * w1 / h1;
float d2 = 1f * w2 / h2;
for (int y = 0; y < h1; y++) leftPts.Add( (int)(y * d1) );
for (int y = 0; y < h2; y++) leftPts.Add( (int)(y * d2 + w1));
for (int y = 0; y < h2; y++) rightPts.Add( (int)(y * d2));
for (int y = 0; y < h1; y++) rightPts.Add( (int)(y * d1 + w2));
}
You need to feed in the four corners as a List<PointF> in any order; the top can be anything, it will be set in the method. The coodinates are relative to the car, so they don't change when the car moves..
I am trying to implement the Cohen-Daubechies-Feauveau-Wavelet 5/3 high pass and low pass.
I am stucking at the moment. My output image is always white because all values become 255 during my calculation. It's really hard to find any examples of this kind of wavelet. Does any one see the bug in my calculation which I am not able to find.
static double[] lowpass = {1/8d, 2/8d, 6/8d, 2/8d, -1/8};
static double[] highpass = {1/2d, 1d, -1/2d };
public static void lowPassFilter(Bitmap img)
{
int index = 0;
double R = 0.0, G = 0.0, B = 0.0;
Bitmap filteredImg = img;
// Iterate over each pixel
for (int x = 0; x < filteredImg.Width; x++)
{
for (int y = 0; y < filteredImg.Height; y++)
{
// Apply filter in x direction
for (int i = 0; i < lowpass.Length; i++)
{
index = Math.Min(Math.Max(x - (lowpass.Length / 2) + i, 0), filteredImg.Width - 1);
R += img.GetPixel(index, y).R * lowpass[i];
G += img.GetPixel(index, y).G * lowpass[i];
B += img.GetPixel(index, y).B * lowpass[i];
}
R = Math.Min(Math.Max(R, 0), 255);
G = Math.Min(Math.Max(G, 0), 255);
B = Math.Min(Math.Max(B, 0), 255);
filteredImg.SetPixel(x, y, Color.FromArgb((int)R, (int)G, (int)B));
}
}
So I'm trying to draw a layered tile based map, as the title says. I have this so far. The tiles i am using are (32, 32). It's currently drawing only 1 type of tile as the whole tile map. When it should be drawing out several different types of tiles to make a map.
for (int layers = 0; layers < map.Layers.Count; layers++) {
for (var i = 0; i < map.Layers[layers].Tiles.Count; i++) {
int gid = map.Layers[layers].Tiles[i].Gid;
if (gid != 0) {
int tileFrame = gid - 1;
int row = tileFrame / (map.Height / tileHeight);
float x = (i % map.Width) * map.TileWidth;
float y = (float)Math.Floor(i / (double)map.Width) * map.TileHeight;
Rectangle tilesetRec = new Rectangle(0, 0, 32, 32);
for (int j = 0; j < tileSets.Count; j++) {
for (int k = 0; k < tileSets[j].Tiles.Count; k++) {
spriteBatch.Draw(tileSets[j].Tiles[k].Image.Texture, new Rectangle((int)x, (int)y, 32, 32), Color.White);
}
}
}
}
}
This is not entirely my code this is someone elses that i have tried to build on apparently it worked for the person for drawing one layer. This is the original code:
for (var i = 0; i < _map.Layers[0].Tiles.Count; i++) {
int gid = _map.Layers[0].Tiles[i].Gid;
// Empty tile, do nothing
if (gid == 0) {
} else {
int tileFrame = gid - 1;
int row = tileFrame / (_tileset.Height / _tileHeight);
float x = (i % _map.Width) * _map.TileWidth;
float y = (float)Math.Floor(i / (double)_map.Width) * _map.TileHeight;
Rectangle tilesetRec = new Rectangle(_tileWidth * tileFrame, _tileHeight * row, 32, 32);
spriteBatch.Draw(_tileset, new Rectangle((int)x, (int)y, 32, 32), tilesetRec, Color.White);
}
}
Your problem is that for each tile position you seem to be drawing all tiles in all tilesets. The variables tileFrame, row and tilesetRec, which were used to render the specific tile in the original code, are not used in your first snippet.
I am using two panels for drawing ruler along the sides (top and left) of a picture box. It works, but now my requirement is to flip the direction of the ruler so that the line starts from the picture box and the text (numbers) are the top. How can I do this?
My code is as follows:
private void panel2_Paint(object sender, PaintEventArgs e)//left Panel
{
Graphics g = e.Graphics;
g.PageUnit = GraphicsUnit.Millimeter;
int step = 1;
int length = panelleft.Height / 3;
int small = 5;
int big = 10;
int number = 10;
int scale = 10;
float stroke = 2.5f;
for (int i = 0; i < length; i += step)
{
float d = 1;
if (i % small == 0)
{
if (i % big == 0)
{
d = 3;
}
else
{
d = 2;
}
}
g.DrawLine(this.pen, 0f, i,d * stroke, i);
if ((i % number) == 0)
{
string text = (i / scale).ToString();
SizeF size = g.MeasureString(text, this.Font, length, this.format);
g.DrawString(text, this.Font, Brushes.Black,d * stroke, i - size.Width-1 / 2 , this.format);
}
}
}
private void panel3_Paint(object sender, PaintEventArgs e)// top panel
{
Graphics g = e.Graphics;
g.PageUnit = GraphicsUnit.Millimeter;
int step = 1;//incremnent
int length = paneltop.Width / 3; //panelinte widthinte pakuthi mathi bcs namml oru point gap vittanu line varakunnath
int small = 5;//cheriya vark ulla length
int big = 10;//valiya vark ulla length
int number = 10;//units 1cm=10 units
float stroke = 2.5f;
for (int i = 0; i < length; i += step)
{
float d = 1;
if (i % small == 0)//cheriya line
{
if (i % big == 0)//valiya line
{
d = 3; //varyude length
}
else
{
d = 2;//varyude length
}
}
g.DrawLine(this.pen, i, 0f, i, d * stroke);//lines varakunnu
if ((i % number) == 0)//0,1,,2
{
string text = (i / number).ToString();//1,2,3 ennu ezhuthan
SizeF size = g.MeasureString(text, this.Font, length, this.format);//ezhuthuna stringnte length ariyan// one digit length 1.618635,2 digit length3.23727
g.DrawString(text, this.Font, Brushes.Black, i - size.Width / 2, d * stroke, this.format);//Y constant ayirikum (d* stroke) ennu koduthath line kazhinju string varan anu alenkil overlapp cheyum
// ( X ) ( Y )
}
}
}
I also want to show a horizontal and vertical line, and they must be pointed to the ruler when the user moves the mouse over the image.
Required output sample:
Since you have set the Graphics to mm you need to calculate the conversion factor for the controls' pixel sizes:
float dpi = e.Graphics.DpiX;
float factor = 25.4f / dpi;
with this you can simply adapt your DrawString and DrawLine calls like this:
In panel2_Paint:
float w = panelleft.Width * factor;
g.DrawLine(this.pen, w - d * stroke, i, w, i);
g.DrawString(text, this.Font, Brushes.Black,
w - d * stroke - size.Width, i - size.Width - 1 / 2, this.format);
and in panel3_Paint:
float h = paneltop.Height * factor;
g.DrawLine(this.pen, i, h - d * stroke, i, h);
g.DrawString(text, this.Font, Brushes.Black,
i - size.Width / 2, h - d * stroke - size.Height, this.format);
To show the Cursor lines you can use this:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Point mp = pictureBox1.PointToClient(Cursor.Position);
if (e.ClipRectangle.Contains(mp))
{
e.Graphics.DrawLine(Pens.Red, 0, mp.Y, e.ClipRectangle.Width, mp.Y);
e.Graphics.DrawLine(Pens.Red, mp.X, 0, mp.X, e.ClipRectangle.Height);
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
pictureBox1.Invalidate();
}
Here is the result, using a few assumptions:
panelleft = panel2;
paneltop = panel3;
format = StringFormat.GenericTypographic;
pen = new Pen(Color.Black, 0.25f);
In theory you should use dpiX and dpiY respectively to get two factors.
For the top one, you want to change your DrawLine and your DrawString calls to be inverse of what they currently are.
In the Panel3 paint:
g.DrawLine(this.pen, i, 0f, i, d * stroke);//lines varakunnu
This draws a line from (i, 0) to (i, d*stroke). We want to invert this line, so we will do:
g.DrawLine(this.pen, i, panel3.Height, i, (panel3.Height - d * stroke));//lines varakunnu
We also want to adjust the label as well, so we will change this:
g.DrawString(text, this.Font, Brushes.Black, i - size.Width / 2, d * stroke, this.format);
to
g.DrawString(text, this.Font, Brushes.Black, i - size.Width / 2, (panel3.Height - d * stroke - size.Height), this.format);
or
g.DrawString(text, this.Font, Brushes.Black, i - size.Width / 2, (panel3.Height - d * stroke), this.format);
I'm not sure if you need to compensate for size.Height or not, since I can't test your code.