In System.Drawing there is a command called DrawLines.
https://msdn.microsoft.com/en-us/library/83k7w0zx(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
I need arrays X and Y to be plotted as a PointF in "Single Format" but with a "F" at the end of each X and Y point.
protected void Page_Load(object sender, EventArgs e)
{
double[] X = new double[]{10,15,20,25,30};
double[] Y = new double[]{100,150,200,250,300};
using (Bitmap xPanel = new Bitmap(500, 500))
{
using (Graphics objGraphicPanel = Graphics.FromImage(xPanel))
{
for (int nn = 2; nn <= 5; nn++)
{
float x1 = Convert.ToSingle(X[nn - 1]);
float y1 = Convert.ToSingle(Y[nn - 1]);
float x2 = Convert.ToSingle(X[nn]);
float y2 = Convert.ToSingle(Y[nn]);
PointF[] ptf =
{
new PointF(x1, y1),
new PointF(x2, y2)
};
objGraphicPanel.DrawLines(colorPen, ptf);
xPanel.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
}
string Imgbase64 = Convert.ToBase64String(ms.ToArray());
MyImage.Src = "data:image/png;base64," + Imgbase64;
objGraphicPanel.Dispose();
}
xPanel.Dispose();
This does not work because it must be in the format:
PointF[] ptf =
{
new PointF(10.56F, 25.78654F),
new PointF(500.123456F, 234.567F)
};
PointF requires the "float single" format but I also need the "F" at the end of each array point to get the PointF and DrawLines to work.
How do I get that "F" after or the code equivalent?
This is only an example my arrays are much larger.
The place
PointF[] ptf =
{
new PointF(x1, y1),
new PointF(x2, y2)
};
is not a problem. PointF accepts only float arguments. When you put 'F' in the end of the number you just tell the compiller that your number is float (not double). In your code values x1, x2, y1, y2 are already float, because you define them as
float x1 = ...
float y1 = ...
The problem is, that you iterate your array from 2 to 5. In C# numeration in arrays is from 0 to N-1 (N is length of the array). So you should write
for (int nn = 1; nn < 5; nn++)
or, and this is better
for (int nn = 1; nn < X.Length; nn++)
Also you save your image at each iteration. I think
xPanel.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
should be outside the cycle for.
Also when you write
using (...)
{
...
}
you don't need to dispose the item you create inside the brackets ( and ). The dispose is called automatically in the end of the using operator.
So the lines
objGraphicPanel.Dispose();
and
xPanel.Dispose();
are redundant.
Also, it is not necessary to create array ptf for drawing a single line. You can use DrawLine method:
objGraphicPanel.DrawLine(colorPen, x1, y1, x2, y2);
So, the folowing code shoud work fine
protected void Page_Load(object sender, EventArgs e)
{
double[] X = new double[]{10,15,20,25,30};
double[] Y = new double[]{100,150,200,250,300};
using (Bitmap xPanel = new Bitmap(500, 500))
{
using (Graphics objGraphicPanel = Graphics.FromImage(xPanel))
{
for (int nn = 1; nn < X.Length; nn++)
{
float x1 = Convert.ToSingle(X[nn - 1]);
float y1 = Convert.ToSingle(Y[nn - 1]);
float x2 = Convert.ToSingle(X[nn]);
float y2 = Convert.ToSingle(Y[nn]);
objGraphicPanel.DrawLine(colorPen, x1, y1, x2, y2);
}
}
xPanel.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
}
Related
I want to multiple cut one picture in c# code.the following image is my c # forum and I can select an area and cut it.
I want to multiple cut one picture in c# code
I want to repeat this process
private void btnKes_Click(object sender, EventArgs e)
{
int tiklanma = 0;
if (true)
{
tiklanma++;
}
pictureBox2.Refresh();
pictureBox2.Refresh();
Bitmap sourceBitmap = new Bitmap(pictureBox1.Image, pictureBox1.Width, pictureBox1.Height);
Graphics g = pictureBox2.CreateGraphics();
int x1, x2, y1, y2;
Int32.TryParse(txtX1.Text, out x1);
Int32.TryParse(txtX2.Text, out x2);
Int32.TryParse(txtY1.Text, out y1);
Int32.TryParse(txtY2.Text, out y2);
if ((x1 < x2 && y1 < y2))
{
rectCropArea = new Rectangle(x1, y1, x2 - x1, y2 - y1);
}
else if (x2 < x1 && y2 > y1)
{
rectCropArea = new Rectangle(x2, y1, x1 - x2, y2 - y1);
}
else if (x2 > x1 && y2 < y1)
{
rectCropArea = new Rectangle(x1, y2, x2 - x1, y1 - y2);
}
else
{
rectCropArea = new Rectangle(x2, y2, x1 - x2, y1 - y2);
}
pictureBox1.Refresh(); // This repositions the dashed box to new location as per coordinates entered.
int sayac = 40;
for (int i = 0; i < tiklanma; i++)
{
PictureBox pcBx = new PictureBox();
Size size = new Size(100, 100);
pcBx.Location();
pcBx.Size = size;
g.DrawImage(sourceBitmap, new Rectangle(0, 0, rectCropArea.Width, rectCropArea.Height), rectCropArea, GraphicsUnit.Pixel);
}
sourceBitmap.Dispose();
}
I want to select the fields more than once in the second picture and save the fields. How can I do this?
Use a FlowLayoutPanel, and every time you draw a new segment on the main image add a new PictureBox control to the layout panel.
Eventually you'll want to do other things with these picture segments, and so I also recommend immediately going a for a custom/user control here that includes a PictureBox as one part. That will make it much easier later to use buttons or context with each picture.
The specifics for all of this are out of scope for this type of question. We'd need to see more of your code to be able to use appropriate context with our answer, and the results are more than can fit well in the simple Q&A format. So go, try what you can, and then come back and ask new questions when you run into more specific problems.
I am working on a simple Random Walker program that should draw a 10p long line, then choose a random cardinal direction to draw another line (also 10p long) until a certain number of lines have been reached.
I am using four coordinates to draw the line (two coordinates for X and two for Y). The Y coordinates are pushed into a Stack after every line is drawn and they are popped out as the X coordinates. This should ensure that the starting point of every second line is the end-point of the previous line.
The program draws on a Windows Form after pushing a Button controller. As of now, the output is something like this:
This here is my event handler code block for the button:
// Graphics and Pen classes instantiated
Graphics graphics;
graphics = this.CreateGraphics();
Pen pen = new Pen(Color.Black);
pen.Width = 1;
// lineLength is 10 pixels
// gridLength and gridWidth are needed to keep the Random Path inside a 600×600 field (this is not yet implemented in the code)
// lineCount is for maximizing the number of lines to be drawn and to control the loop
int lineLength = 10;
int gridWidth = 600;
int gridLength = 600;
int lineCount = 0;
// Starting line drawn with the following coordinates:
int x1 = 20;
int x2 = 20;
int y1 = 20;
int y2 = 30;
graphics.DrawLine(pen, x1, y1, x2, y2);
lineCount++;
// Stack initialized to store "y" coordinates
// "y" coordinates should be passed on as "x" coordinates for every consecutive lines
// so that the ending point's coordinate of a line
Stack<int> stackY = new Stack<int>();
stackY.Push(y2);
stackY.Push(y1);
for (lineCount = 1; lineCount <= 64; lineCount++)
{
// X pops current Y coordinates from stack
x1 = stackY.Pop();
x2 = stackY.Pop();
// Initializing the random number (between 1 and 4) generator to choose from the cardinal directions
Random rnd = new Random();
int dir = rnd.Next(1, 5);
switch (dir)
{
// up
case 1:
y1 = y1 + lineLength; // y1 plus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2); //drawing the line
stackY.Push(y2); // pushing the current y coordinates into the stack
stackY.Push(y1);
break;
// right
case 2:
y1 = y2 + lineLength; // y2 plus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2);
stackY.Push(y2);
stackY.Push(y1);
break;
// down
case 3:
y1 = y1 - lineLength; // y1 minus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2);
stackY.Push(y2);
stackY.Push(y1);
break;
// left
case 4:
y2 = y2 - lineLength; // y2 minus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2);
stackY.Push(y2);
stackY.Push(y1);
break;
} //switch
} //for
} //event handler
I am not really sure what went wrong - I appreciate any heads-up and advices! Thank you!
You are making this far more complicated than you need to. Also you are mixing the x and y coordinates in a way that doesn't make sense.
You don't need a stack, just store the most recent points. Something like this.
int x = 20, y = 20;
int new_x = x, new_y = y;
Random rnd = new Random();
for (int i = 0; i < numLines; i++)
{
int dir = rnd.Next(1, 5);
if (dir == 1) new_x += lineLength;
if (dir == 2) new_x -= lineLength;
if (dir == 3) new_y += lineLength;
if (dir == 4) new_y -= lineLength;
graphics.DrawLine(pen, x, y, new_x, new_y);
x = new_x;
y = new_y;
}
Also you don't need to redeclare the Random object every time, just once before the loop.
I am using the Charts component in Windows Forms.
I create a straight line using
chart1.Series["Grenzwert"].Points.Add(new DataPoint(0, y));
chart1.Series["Grenzwert"].Points.Add(new DataPoint(maxwidth, y));
Also I plot a a series of points connected by a line, let's call it curve.
How do I show everything over straight line and under curve filled?
Column fills the whole area, not just above straight line.
Example:
This is late and not really short but imo it is the best way to color areas in a chart.
The Lines and also the Spline charttypes can be very precisely colored by coding the Paint event with the right data. The necessary pixel values can be obtained by the axis function ValueToPixelPosition. See here for another example!
The following code is a little longer because we need to add certain points at the start and end of both the chart and each colored area. Other than that it is very straight forward: Create GraphicsPaths by adding the pixel coordinates with AddLines and fill the GraphicsPaths in the Paint event.
For testing and for fun I have added a movable HorizontalLineAnnotation, so I can see how the areas vary when I drag it up and down..:
The Paint event is rather simple; it refers to a HorizontalLineAnnotation hl :
private void chart1_Paint(object sender, PaintEventArgs e)
{
double limit = hl.Y; // get the limit value
hl.X = 0; // reset the x value of the annotation
List<GraphicsPath> paths = getPaths(chart1.ChartAreas[0], chart1.Series[0], limit);
using (SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.Red)))
foreach (GraphicsPath gp in paths)
{ e.Graphics.FillPath(brush, gp); gp.Dispose(); }
}
The code to get the paths is obviously way too long for comfort..:
List<GraphicsPath> getPaths(ChartArea ca, Series ser, double limit)
{
List<GraphicsPath> paths = new List<GraphicsPath>();
List<PointF> points = new List<PointF>();
int first = 0;
float limitPix = (float)ca.AxisY.ValueToPixelPosition(limit);
for (int i = 0; i < ser.Points.Count; i++)
{
if ((ser.Points[i].YValues[0] > limit) && (i < ser.Points.Count - 1))
{
if (points.Count == 0) first = i; // remember group start
// insert very first point:
if (i == 0) points.Insert(0, new PointF(
(float)ca.AxisX.ValueToPixelPosition(ser.Points[0].XValue), limitPix));
points.Add( pointfFromDataPoint(ser.Points[i], ca)); // the regular points
}
else
{
if (points.Count > 0)
{
if (first > 0) points.Insert(0, median(
pointfFromDataPoint(ser.Points[first - 1], ca),
pointfFromDataPoint(ser.Points[first], ca), limitPix));
if (i == ser.Points.Count - 1)
{
if ((ser.Points[i].YValues[0] > limit))
points.Add(pointfFromDataPoint(ser.Points[i], ca));
points.Add(new PointF(
(float)ca.AxisX.ValueToPixelPosition(ser.Points[i].XValue), limitPix));
}
else
points.Add(median(pointfFromDataPoint(ser.Points[i - 1], ca),
pointfFromDataPoint(ser.Points[i], ca), limitPix));
GraphicsPath gp = new GraphicsPath();
gp.FillMode = FillMode.Winding;
gp.AddLines(points.ToArray());
gp.CloseFigure();
paths.Add(gp);
points.Clear();
}
}
}
return paths;
}
It uses two helper functions:
PointF pointfFromDataPoint(DataPoint dp, ChartArea ca)
{
return new PointF( (float)ca.AxisX.ValueToPixelPosition(dp.XValue),
(float)ca.AxisY.ValueToPixelPosition(dp.YValues[0]));
}
PointF median(PointF p1, PointF p2, float y0)
{
float x0 = p2.X - (p2.X - p1.X) * (p2.Y - y0) / (p2.Y - p1.Y);
return new PointF(x0, y0);
}
The HorizontalLineAnnotation is set up like this:
hl = new HorizontalLineAnnotation();
hl.AllowMoving = true;
hl.LineColor = Color.OrangeRed;
hl.LineWidth = 1;
hl.AnchorDataPoint = S1.Points[1];
hl.X = 0;
hl.Y = 0; // or some other starting value..
hl.Width = 100; // percent of chart..
hl.ClipToChartArea = chart1.ChartAreas[0].Name; // ..but clipped
chart1.Annotations.Add(hl);
I have an idea that use SeriesChartType.Range as follow.
private void UpdateChart(float straight_line, List<DataPoint> curve)
{
float y = straight_line; // YValue of the straight line
var list = curve.ToList(); // Clone the curve
int count = list.Count - 2;
for (int i = 0; i < count; i++) // Calculate intersection point between the straight line and a line between (x0,y0) and (x1,y1)
{
double x0 = list[i + 0].XValue;
double y0 = list[i + 0].YValues[0];
double x1 = list[i + 1].XValue;
double y1 = list[i + 1].YValues[0];
if ((y0 > y && y1 < y) || (y0 < y && y1 > y))
{
double x = (y - y0) * (x1 - x0) / (y1 - y0) + x0;
list.Add(new DataPoint(x, y));
}
}
list.Sort((a, b) => Math.Sign(a.XValue - b.XValue));
chart1.Series[0].Points.Clear();
chart1.Series[0].ChartType = SeriesChartType.Range;
chart1.Series[0].Color = Color.Red;
chart1.Series[0].BorderColor = Color.Cyan;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Interval = 1;
for (int i = 0; i < list.Count; i++)
{
double xx = list[i].XValue;
double yy = list[i].YValues[0];
if (yy > y)
{
chart1.Series[0].Points.AddXY(xx, y, yy);
}
else
{
chart1.Series[0].Points.AddXY(xx, yy, yy);
}
}
chart1.ChartAreas[0].AxisY.StripLines.Add(new StripLine { IntervalOffset = y, Interval = 0, BorderColor = Color.Orange, BorderWidth = 2 });
}
As in the below drawing to judge whether the straight line and a line between (x0,y0) and (x1,y1) intersect, case 1 is (y0 < y && y1 > y) and case 2 is (y0 > y && y1 < y) . In case 1 and case 2, they intersect each other. In case 3 and case 4, they don't intersect each other.
You can do this as follows.
Set the column fill like you did before. Everything will be red.
Create a new column graph on the same chart.
Set its values to the same as your jagged line, but capped at the y value of the straight line you already have.
Set the fill colour for the columns to white. This will block out the red fill for any areas not between the lines.
I want to draw line in SharpGl but this code does not work !
void Line_DDA(OpenGL gl,int X0, int Y0, int Xend, int Yend)
{
gl.LineWidth(2.5f);
gl.Color(1.0, 0.0, 0.0);
gl.Begin(OpenGL.GL_LINES);
int dx = Xend - X0;
int dy = Yend - Y0;
int steps, k;
float Xinc, Yinc;
float x = X0;
float y = Y0;
if (Math.Abs(dx) > Math.Abs(dy))
steps = Math.Abs(dx);
else
steps = Math.Abs(dy);
float fdx = (float)dx;
float fdy = (float)dy;
float fsteps = (float)steps;
Xinc = fdx / fsteps;
Yinc = fdy / fsteps;
gl.Vertex((int)x, (int)y);
for (k = 0; k < steps; k++)
{
x += Xinc;
y += Yinc;
gl.Vertex((int)x, (int)y);
}
gl.End();
}
and when I use
gl.Vertex(10, 100);
gl.Vertex(110, 110);
It's work!
EDIT:
This is call block in my code:
private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
{
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
// Clear the color and depth buffer.
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
// Load the identity matrix.
gl.LoadIdentity();
Line_DDA(gl, int.Parse(txtLineX1.Text), int.Parse(txtLineY1.Text), int.Parse(txtLineX2.Text), int.Parse(txtLineY2.Text));
//drawLine(gl, 110, 120, 100, 100);
}
Why this happen?
When you draw lines using GL_LINES, you need to supply 2 vertices for each line segment. Instead, your code supply a single vertex for each line segment, as if the line should be connected with the previous vertex.
Indeed, the solution would be to set the draw mode to GL_LINE_STRIP or to supply two vertices for each line segment.
However, I don't understand why you want to draw a straight line with multiple vertices when when they are needed only two points.
I have to do something like this.
When I click on a node, it expands, and this is OK (I am using Powercharts to do it).
My big problem is creating random coordinates so that when I open the subnode, it doesn't overlap with another node/subnode.
In the Powercharts I have to pass the coordinates, so the big problem is in passing it.
I have to do the random coordinates in C#.
//-------------------------------------------------------
This is what i did so far:
This is what i do, is not overlaping, but i have a problem.
how can i start do the circles from a starting point?
for example, starts in the middle (300,300) and then do circles around it. Is possible?
private void button2_Click(object sender, EventArgs e)
{
g = pictureBox1.CreateGraphics();
g.Clear(pictureBox1.BackColor);
double angle;
Circle item0 = new Circle();
item0.x=200;
item0.y=150;
item0.r=50;
listaCirculos.Add(item0);
Random randomMember = new Random();
g.DrawEllipse(pen1, 200, 150, 50, 50);
while(listaCirculos.Count!=11)
{
int[] it = GenerateNewCircle(600);
Circle item = new Circle();
item.x = it[0];
item.y = it[1];
item.r = 50;
if (circleIsAllowed(listaCirculos, item))
{
listaCirculos.Add(item);
g.DrawEllipse(pen1, Convert.ToInt32(item.x), Convert.ToInt32(item.y), 50, 50);
}
}
}
bool circleIsAllowed(List<Circle> circles, Circle newCircle)
{
foreach(Circle it in circles)
{
//double sumR = it.x + newCircle.r;
//double dx = it.x - newCircle.x;
//double dy = it.y - newCircle.y;
//double squaredDist = dx * dx + dy * dy;
double aX = Math.Pow(it.x - newCircle.x, 2);
double aY = Math.Pow(it.y - newCircle.y, 2);
double Dif = Math.Abs(aX - aY);
double ra1 = it.r / 2;
double ra2 = it.r / 2;
double raDif = Math.Pow(ra1 + ra2, 2);
if ((raDif + 1) > Dif) return false;
//if (squaredDist < sumR*sumR) return false;
}
return true; // no existing circle overlaps
}
public int[] GenerateNewCircle(int maxSize)
{
int x, y;
Random randomMember = new Random();
x = randomMember.Next(0,maxSize);
if (x - 50 < 0)
y = randomMember.Next(x + 50, maxSize);
else if (x + 50 > 600)
y = randomMember.Next(0, x - 50);
else
// in this case, x splits the range 0..n into 2 subranges.
// get a random number and skip the "gap" if necessary
y = randomMember.Next(0, maxSize - 50);
if (y > x - 50)
{
y += 20;
}
int[] abc = new int[2];
abc[0] = x;
abc[1] = y;
return abc;
}
Size sizeShape = new Size("SomeWidth" , "SomeHeight");
List<Retangle> rects = new List<Retangle>();
Random r = new Random();
while(rects.count != "someCount")
{
Point rPoint = new Point(r.Next(500) , r.Next(500))
bool isNew = true;
foreach(Rectangle r in rects)
{
if(r.contains(rPoint))
isNew = false;
}
if(isNew)
rects.Add(GetRect(rPoint , sizeShape));
}
private Rectangle GetRect(Point p , Size s)
{
return new Rectangle(p,s);
}
After than you can use from rects ,
rects has random coordinates.
Here's the link to let you know how to create Random Numbers in C#.
You have to keep in mind that you will generate random numbers, but you also have to make sure the numbers generated will not make objects overlap.
Despite this being pretty poorly worded, I believe what you are looking for is the Random class. It is instantiated as such:
Random thisRandom = new Random();
Then from there, if you want to generate a random coordinate, you need to know the maximum possible X and Y coordinates. Knowing these will allow you to generate X and Y coordinates within the given canvas as such:
int maxX = 500; //This is the maximum X value on your canvas
int maxY = 500; //This is the maximum Y value on your canvas
int newX, newY;
newX = thisRandom.Next(maxX);
newY = thisRandom.Next(maxY);
While its not the absolute best in terms of "true" randomization this should give you what you need.