I Have a bresenham algorithm which I wrote it in class Line
I Can draw lines Now I wanted to draw polygons so I wrote it's function(void Polygon)
I should store coordinates of each click in an array and then my function should get them
I don't know how to store each click
Radiobutton1 is for draw line and radiobutton2 is for drawing polygons
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
if(radioButton1.Checked)
if (firstClick)
{
firstX = e.X;
firstY = e.Y;
firstClick = false;
}
else
{
Line l = new Line(firstX, firstY, e.X, e.Y, panel1.CreateGraphics(), Convert.ToInt32(textBox1.Text));
firstClick = true;
}
if(radioButton2.Checked)
{
//how to write here so as to store each click in array
}
}
private void button1_Click(object sender, EventArgs e)
{
int n = Convert.ToInt32(textBox2.Text);
Polygon(n, coor);
}
void Polygon(int n,int[] coordinates)
{
if(n>=2)
{
Line l=new Line(coordinates[0],coordinates[1],coordinates[2],coordinates[3],panel1.CreateGraphics(), Convert.ToInt32(textBox1.Text));
for(int count=1;count<(n-1);count++)
l=new Line(coordinates[(count*2)],coordinates[((count*2)+1)],coordinates[((count+1)*2)],coordinates[(((count+1)*2)+1)],panel1.CreateGraphics(), Convert.ToInt32(textBox1.Text));
}
You can make a point of the click coordinates:
Point p = new Point(e.x, e.y);
Save the points you get in a List:
// Declaration:
List<Point> myPoints = new List<Point>();
// in the method:
if (radioButton2.Checked) {
myPoints.Add(new Point(e.x, e.y));
}
An array will not be a good idea, because you normally don't have any idea how many clicks there will be. A List is of variable length, so it's useful in this situation.
Related
This question already has an answer here:
Why does my program draw all the lines from the top left corner? How to change this?
(1 answer)
Closed last month.
I am trying to make a program that will draw lines between 10 coordinates, determined by mouseclicks.
i can not get it to work.
code:
EDIT:
i figured out i have to define the coordinates making x and y values.
only it is still unclear how to do this.
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Point[] punten = new Point[2];
int index = 0;
int kliks = 0;
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
Point[] punten = new Point[2];
int index = 0;
int kliks = 0;
kliks = kliks + 1;
index = kliks;
punten[index] = e.Location;
if (index < 2)
{
punten[index] = e.Location;
}
else
{
Pen pen = new Pen(Color.Blue);
Graphics papier = pictureBox1.CreateGraphics();
papier.DrawLines(pen, punten);
}
}
I have re read the textbook 10 times.. its unclear where to create the variables intially, but if i dont create them under pictureBox1 mouse click, i also cant use them.
Any help is appreciated.
greetings, Stefan.
i got it to work!
i need to keep telling my damn self: its all in the textbook...
with the explanations given by you guys (declaring variables at class level)
the instructions in the textbook work..
code:
public partial class Form1 : Form
{
Point[] punten = new Point[10];
private int kliks = 0;
private int lijst = 0;
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
kliks = kliks + 1;
lijst = kliks;
punten[lijst] = e.Location;
if (lijst < 5)
{
punten[lijst] = e.Location;
}
else
{
Pen pen = new Pen(Color.Blue);
Graphics papier = pictureBox1.CreateGraphics();
papier.DrawLines(pen, punten);
}
}
}
}
The Scope a variables is defined determines its accessibility within the process. You need to declare the punten array and the kliks int variables at the class level so they can be maintained across the button clicks.
public Form1()
{
InitializeComponent();
}
// create variables at class scope so they are
// accessible by all methods in this class and state is maintained
// across button clicks
private Point[] punten;
private int kliks;
private void Form1_Load(object sender, EventArgs e)
{
// initialize class level variables at form load
punten = new Point[10];
kliks = 0;
}
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
int index = kliks;
if(index == 9) // arrays are zero based so our 10 items are at indexes 0 through 9
{
// append last mouse point clicked to list of points
punten[index] = new Point(e.Location.X, e.Location.Y);
// draw lines between all points
Pen pen = new Pen(Color.Blue);
Graphics papier = pictureBox1.CreateGraphics();
papier.DrawLines(pen, punten);
punten = new Point[10];
kliks = 0;
}
else
{
// append mouse point clicked to list of points
punten[index] = new Point(e.Location.X, e.Location.Y);
kliks = kliks + 1;
}
}
I want to click on points that I drew.
It would be also cool if a window would popup and I could do something with that. But the general thing i want to do is clicking on a drawn point. I want to make it work, that i can click on the map on points that I drew.
Example image:
public partial class Form1 : Form
{
Graphics g;
Pen p;
Point cursor;
int k = 0;
Point[] points = new Point[50];
public Form1()
{
InitializeComponent();
g = pbxkarte.CreateGraphics();
p = new Pen(Color.DeepSkyBlue, 3);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Pbxkarte_Click(object sender, EventArgs e)
{
if (drawmodecbx.Checked == true)
{
g.DrawEllipse(p, cursor.X - 10, cursor.Y - 10, 20, 20);
points[k++] = new Point(cursor.X, cursor.Y);
lbxDrawnPoints.Items.Add("X:" + cursor.X + "Y:" + cursor.Y);
}
}
private void Pbxkarte_MouseMove(object sender, MouseEventArgs e)
{
cursor = this.PointToClient(Cursor.Position);
xydisplay.Text = "X:" + cursor.X + "Y:" + cursor.Y;
}
}
}
Example code:
Two class level variables and a helper function:
List<Point> dots = new List<Point>();
int dotSize = 12;
Rectangle fromPoint(Point pt, int size)
{
return new Rectangle(pt.X - size/ 2, pt.Y - size / 2, size, size);
}
The mouseclick (as opposed to the click event) contains the location:
private void Pbxkarte_MouseClick(object sender, MouseEventArgs e)
{
if (!dots.Contains(e.Location))
{
dots.Add(e.Location);
Pbxkarte.Invalidate(); // show the dots
}
}
You could add code to remove dots or change the properties, esp. if you create a dot class. - If you want to avoid overlapping dots you can to use code like the one in the mousemove to detect this. But. Don't repeat the code! Instead factor out a boolOrPoint IsDotAt(Point) function you can use both times!!
In the mousemove I only show the hit state. You do your thing..
private void Pbxkarte_MouseMove(object sender, MouseEventArgs e)
{
bool hit = false;
foreach (var dot in dots)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(fromPoint(dot, dotSize));
if (gp.IsVisible(e.Location))
{
hit = true; break;
}
}
}
Cursor = hit ? Cursors.Hand : Cursors.Default;
}
All dot in the list must get shown every time anything changes, both in the list or in the system.:
private void Pbxkarte_Paint(object sender, PaintEventArgs e)
{
foreach (var dot in dots)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(fromPoint(dot, dotSize));
e.Graphics.FillPath(Brushes.Red, gp);
}
}
}
If you want more properties, like texts or colors do create a class dot and use a List<dot> !
(New to this and playing around with a basic paint application) Ive found detailed instructions to code a flood-fill but as i am new it is very hard to understand every bits of it, and instead of copying, i would like to try to make my own simple(small scale) flood-fill.
Would it be possible to use fillpath as a flood-fill? i would draw paths and use my mouse to determine my x,y, on screen and have the graphicspath find out if it has borders(points from the drawn paths) and if so, fill these paths with a color?
this is what ive come up with but obviously it doesnt work, so how would i go about to make this working?
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
Graphics g;
readonly Pen pen = new Pen(Color.Navy, 2);
Point oldCoords;
GraphicsPath graphicsPaths = new GraphicsPath();
bool spaceFound = false;
public Form1()
{
InitializeComponent();
g = panel1.CreateGraphics();
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
Point mousePt = new Point(e.X, e.Y);
if (e.Button == MouseButtons.Right &&
graphicsPaths.IsVisible(mousePt))
{
spaceFound = true;
}
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (oldCoords.IsEmpty)
graphicsPaths.StartFigure();
else
{
graphicsPaths.AddLine(oldCoords, new Point(e.X, e.Y));
g.DrawPath(pen, graphicsPaths);
}
oldCoords = new Point(e.X, e.Y);
}
else
oldCoords = Point.Empty;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
g.DrawPath(pen, graphicsPaths);
if(spaceFound == true)
{
g.FillPath(Brushes.AliceBlue, graphicsPaths);
}
}
}
}
Yes, this is quite possible; of course you would want to store the path in a List<GraphicsPath> in the MouseUp event to allow for more filled shapes..
You need to correct a few issues in your code:
Set the path.FillMode to Winding
Never cache a Graphics object
Never use control.CreateGraphics()
Don't cache Pens or Brushes
Only draw in the Paint event, unless you do not want the drawing to persist
The last point might actually apply here: Maybe you don't want the currently drawing outline to stay visible? In that, and only that case you can stick with drawing it in the MouseMove with a Graphics object created there on the fly.
Here is a corrected version:
Point oldCoords;
GraphicsPath graphicsPaths = new GraphicsPath() { FillMode = FillMode.Winding };
bool spaceFound = false;
private void drawPanel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && graphicsPaths.IsVisible(e.Location))
{
spaceFound = true;
drawPanel1.Invalidate();
}
}
private void drawPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (oldCoords.IsEmpty) graphicsPaths.StartFigure();
else
{
graphicsPaths.AddLine(oldCoords, new Point(e.X, e.Y));
drawPanel1.Invalidate();
}
oldCoords = new Point(e.X, e.Y);
}
else oldCoords = Point.Empty;
}
private void drawPanel1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Black, 2f))
e.Graphics.DrawPath(pen, graphicsPaths);
if (spaceFound == true)
{
e.Graphics.FillPath(Brushes.AliceBlue, graphicsPaths);
}
}
Note that it will fill your path but not in the way of a true floodfill, i.e. it will always fill the whole path, not just the innermost segment you have clicked in. For a true floodfill much more involved code is needed that actually goes over all neighbouring pixels starting at the click location..
Examples of a true floodfill are here and here
Any suggestions how to create a line by clicking two new points then draw a line between them?
I am trying to create a distance tool like the one in adobe acrobat.
Image Example
Problem Solved!
EDIT:
Here's the code:
private Point p1, p2;
List<Point> p1List = new List<Point>();
List<Point> p2List = new List<Point>();
private void Panel1_MouseDown(object sender, MouseEventArgs e)
{
if (p1.X == 0)
{
p1.X = e.X;
p1.Y = e.Y;
}
else
{
p2.X = e.X;
p2.Y = e.Y;
p1List.Add(p1);
p2List.Add(p2);
Invalidate();
p1.X = 0;
}
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
using(var p = new Pen(Color.Blue, 4))
{
for(int x = 0; x<p1List.Count; x++){
e.Graphics.DrawLine(p, p1List[x], p2List[x]);
}
}
}
You can handle the mouse click event on the panel (for example) and retrieve the location of the click (using the event args). Store this location in an attribute. Do that for as many points as you need.
In the panel paint event, call the parent paint, then draw the lines between your points.
Something like this should do it:
Point firstPoint;
Point seondPoint;
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (this.firstPoint == null) {
this.firstPoint = e.Location;
}
if (this.secondPoint == null) {
this.secondPoint = e.Location;
}
panel1.Invalidate();
}
private void panel1_Paint_1(object sender, PaintEventArgs e)
{
Using (pn as new Pen(Color.Blue, 5))
{
e.Graphics.DrawLine(pn, firstPoint, secondPoint);
}
}
EDIT: You also dont need to do CreateGraphics to draw the line - in the Paint event you have a graphics object already.
I'm trying to draw a single line using OnMouseMove() event. My Problem is that everytime I move the mouse It leaves a trail. I tried to use the refresh method, but when I stop moving the mouse the line is gone. I don't want the line to be drawn OnPaint();, Just want to draw it OnMouseMove().
EDIT: I'm using a transparent panel(cp.ExStyle |= 0x20;), so I cant use the graphics.Clear() and BackColor()
Here's a Sample Image without the Refresh():
Here's my code:
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
Graphics g = panel1.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
using (var p = new Pen(Color.Black, 3))
{
p.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
p.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
g.DrawLine(p, st, e.Location);
}
Thread.Sleep(30);
Invalidate();
//this.Refresh();
g.Dispose();
}
Regards
The following works for me. Basically keep track of the last line drawn and draw over it with the background color of the panel (gives the effect of clearing it).
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private const int PEN_WIDTH = 3;
private const LineCap START_CAP = LineCap.ArrowAnchor;
private const LineCap END_CAP = LineCap.ArrowAnchor;
Point mAnchorPoint = new Point(10, 10);
Point mPreviousPoint = Point.Empty;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
using (Graphics g = panel1.CreateGraphics())
{
// Clear last line drawn
using (Pen clear_pen = new Pen(panel1.BackColor, PEN_WIDTH))
{
clear_pen.StartCap = START_CAP;
clear_pen.EndCap = END_CAP;
g.DrawLine(clear_pen, mAnchorPoint, mPreviousPoint);
}
// Update previous point
mPreviousPoint = e.Location;
// Draw the new line
using (Pen draw_pen = new Pen(Color.Black, PEN_WIDTH))
{
draw_pen.StartCap = START_CAP;
draw_pen.EndCap = END_CAP;
g.DrawLine(draw_pen, mAnchorPoint, e.Location);
}
}
}
}
If you panel's background color is set to Transparent, you will need to change panel1.BackColor to panel1.Parent.BackColor
If the Transparent Panel is not working, you could use the DrawReversibleLine function (although this doesn't allow the color or thickness of the line to be changed, it should have no issues with drawing/erasing even if the panel is Transparent:
Point mAnchorPoint = new Point(200, 200);
Point mPreviousPoint = Point.Empty;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (mPreviousPoint != Point.Empty)
{
// Clear last line drawn
ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink);
}
// Update previous point
mPreviousPoint = e.Location;
mPreviousPoint.Offset(myPanel1.Location);
// Draw the new line
ControlPaint.DrawReversibleLine(PointToScreen(mAnchorPoint), PointToScreen(mPreviousPoint), Color.Pink);
}
Another simple way to draw a line with mouse in C#:
public partial class Form1 : Form
{
Options_c o = new Options_c();
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
o.Allow = false;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
o.Allow = true;
o.X = e.X;
o.Y = e.Y;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (o.Allow == true)
{
Graphics g = pictureBox1.CreateGraphics();
Pen p1 = new Pen(o.color, 5);
g.DrawLine(p1, o.X,o.Y, e.X, e.Y);
o.X = e.X;
o.Y = e.Y;
}
}
}
class Options_c
{
public Boolean Allow = false;
public Int32 X;
public Int32 Y;
public Color color = Color.Bisque;
}
After
g.DrawLine(p, st, e.Location);
put:
st = e.Location;
Does that fix the problem?
The problem with the line disappearing is that when the panel is repainted, the line is not redrawn. What you really need is to update the end-point of the line-segment when the mouse is moved across the panel and to invalidate the panel. Of course, this will mean that you do handle the Paint event on the panel.
Code here, without the event-handler registration:
Point endPoint;
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
using (var p = new Pen(Color.Black, 3))
{
p.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
p.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
g.DrawLine(p, st, endPoint);
}
Thread.Sleep(30);
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
endPoint = e.Location;
panel1.Invalidate();
}
OKaie, i got it! If you have to draw a line between two geopoint
location on tocuhing these two location, then u have to use the
overlay class in this shape... MY CODE IS :
in Main activity write this code also:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapView1);
mapView.setBuiltInZoomControls(true);
mapOverlays = mapView.getOverlays();//it get the mapview all overlays...
mc = mapView.getController();
mc.setZoom(13);
GeoPoint p = new GeoPoint(34159000,73220000);//starting point Abbottabad
GeoPoint p1 = new GeoPoint(41159000,43220000);//starting point Abbottabad
List<Overlay> mapOverlays2 ;
mapOverlays2 = mapView.getOverlays();
projection = mapView.getProjection();
myoverlay = new MarkerOverlay(p,p1);
mapOverlays2.add(myoverlay);//*/
}
class MarkerOverlay extends Overlay
{
GeoPoint p,p1;
private GeoPoint pa;
public MarkerOverlay(GeoPoint p,GeoPoint p1)
{
this.p = p;
this.p1=p1;
Toast.makeText(GoogleMapShowActivity.this, "point value is "+p +"-->"+p1, Toast.LENGTH_LONG).show();
}
public void draw(Canvas canvas, MapView mapView,boolean shadow)//), long when)
{
super.draw(canvas, mapView, shadow);
Paint mPaint = new Paint();
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(4);
GeoPoint gP1 = new GeoPoint(p.getLatitudeE6(),p.getLongitudeE6());//starting point Abbottabad
GeoPoint gP2 = new GeoPoint(p1.getLatitudeE6(),p1.getLongitudeE6());//(33695043,73050000);//End point Islamabad
Point p1 = new Point();
Point p2 = new Point();
Path path1 = new Path();
projection.toPixels(gP1, p1); //changing the latitude into the screen pixels.
projection.toPixels(gP2, p2);
path1.moveTo(p1.x, p1.y);//Moving to Abbottabad location
path1.lineTo(p2.x,p2.y);//Path till Islamabad
canvas.drawPath(path1, mPaint);//Actually drawing the path from Abbottabad to Islamabad
}
//--------------------------//
public boolean onTouchEvent(MotionEvent event, MapView mapView)
{
location_touch++;//this is called two times before executing other codes in thsi method(),
// Toast.makeText(GoogleMapShowActivity.this, "this is mmmm"+location_touch, Toast.LENGTH_LONG).show();
if (event.getAction() == 1)
{
// Toast.makeText(GoogleMapShowActivity.this, "this is me ..."+location_touch, Toast.LENGTH_LONG).show();
GeoPoint p = mapView.getProjection().fromPixels((int) event.getX(), (int) event.getY());
if((location_touch%2)!=0)
{
location_touch=0;
Toast.makeText(GoogleMapShowActivity.this, "VALUE 2..."+location_touch+"gp is "+p+",,"+p1, Toast.LENGTH_LONG).show();
mapView.getOverlays().add(new MarkerOverlay(p,pa));
mapView.invalidate();
}
else //if((location_touch==0 ))
{
pa=p;
Toast.makeText(GoogleMapShowActivity.this, "VALUE 1.."+location_touch+",,,"+p1, Toast.LENGTH_LONG).show();
location_touch++;
}