C# Draw multiple Lines - c#

I'm drawing multiple lines by using this code, but I feel there is a better way of doing this.
E.g. by using a multidimensional array? or a list?
private void drawLines()
{
int[] x1 = { 0, 0, 112, 222, 0, 333, 0, 1};
int[] x2 = { 334, 334, 112, 222, 334, 333, 334, 1 };
int[] y1 = { 100, 200, 300, 300, 1, 300, 300, 300 };
int[] y2 = { 100, 200, 0, 0, 1, 0, 300, 0 };
for (int i = 0; i < x1.Length; i++)
{
Line line = new Line();
Grid myGrid = gg;
line.Stroke = Brushes.Black;
line.X1 = x1[i];
line.X2 = x2[i];
line.Y1 = y1[i];
line.Y2 = y2[i];
line.StrokeThickness = 2;
myGrid.Children.Add(line);
}
}

I would make a Line class having start and end point of the line in struct Point and make list of that class instead of having four arrays.
public class MyLine
{
public Point StartPoint {get; set;}
public Point EndPoint {get; set;}
public void DrawLine()
{
//Draw line code goes here
}
}
Now you have line class with required field and method to draw line. You drawLines method that might be in some other class will create list of MyLine class and can draw that list of Lines using Line class method DrawLine
private void DrawLines()
{
List<MyLine> listMyLines = new List<MyLine>();
listMyLines.Add(new MyLine{StartPoint = new Point(0, 100), EndPoint = new Point(334, 100)});
for (int i = 0; i < listMyLines.Count; i++)
{
listMyLines[i].DrawLine();
}
}

This might be better.
private void drawLInes()
{
drawLines(
new int[] { 0, 334, 100, 100 },
new int[] { 0, 334, 200, 200 },
new int[] { 112, 112, 300, 0 }
// ...
);
}
private void drawLines(params int[][] lines)
{
for (int i = 0; i < lines.Length; i++)
{
Line line = new Line();
Grid myGrid = gg;
line.Stroke = Brushes.Black;
line.X1 = lines[i][0];
line.X2 = lines[i][1];
line.Y1 = lines[i][2];
line.Y2 = lines[i][3];
line.StrokeThickness = 2;
myGrid.Children.Add(line);
}
}

Related

How to draw a line of collection of parallelograms

For reasons of aesthetics, I want to create a line composed of parallelograms like this:
But it turns out that the OnPaint override event only allows you to draw rectangles:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle[] rectangles = new Rectangle[]
{
new Rectangle(0, 0, 100, 30),
new Rectangle(100, 0, 100, 30),
new Rectangle(200, 0, 100, 30),
new Rectangle(300, 0, 100, 30),
new Rectangle(400, 0, 100, 30),
};
e.Graphics.DrawRectangles(new Pen(Brushes.Black), rectangles);
}
My problem is that I need to convert the rectangles into parallelograms, and give each one a different color.
The FillPolygon can do the job:
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.Clear(Color.White);
int x = 10;
int y = 10;
int width = 148;
int height = 64;
int lean = 36;
Color[] colors = new[] { Color.FromArgb(169, 198, 254),
Color.FromArgb(226, 112, 112),
Color.FromArgb(255, 226, 112),
Color.FromArgb(112, 226, 112),
Color.FromArgb(165, 142, 170)};
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
for (int i = 0; i < colors.Length; ++i) {
using (SolidBrush br = new SolidBrush(colors[i])) {
e.Graphics.FillPolygon(br, new Point[] { new Point(x, y),
new Point(x + lean, y + height),
new Point(x + lean + width, y + height),
new Point(x + width, y)});
x += width;
}
}
}

How can I do Hough Transform in OpenCV and C#?

Regarding this Opencv Tutorial, the following C++ code snippet:
vector<Vec4i> lines;
// Find hough lines
HoughLinesP(edges, lines, 1, CV_PI / 180, 100, 100, 10);
// Prepare blank mat with same sizes as image
Mat Blank(image.rows, image.cols, CV_8UC3, Scalar(0, 0, 0));
// Draw lines into image and Blank images
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i l = lines[i];
line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 0), 2, CV_AA);
line(Blank, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(255, 255, 255), 2, CV_AA);
}
has been translated into C# like this:
private void openFileDialogButton_Click(object sender, EventArgs e)
{
try
{
const string filename = #"E:\___MSc in Computer Systems & Network\EMSC1,2,3\lena.png";
Mat image = Cv2.ImRead(filename, LoadMode.GrayScale);
Mat edges = new Mat();
Cv2.Canny(image, edges, 95, 100);
Cv2.ImWrite("edges.jpg", edges);
Mat dx = new Mat();
Mat dy = new Mat();
Cv2.Sobel(edges, dx, MatType.CV_32F, 1, 0);
Cv2.Sobel(edges, dy, MatType.CV_32F, 0, 1);
Cv2.ImWrite("dx.jpg", dx);
Cv2.ImWrite("dy.jpg", dy);
Mat linesssssss = new Mat();
Cv.HoughLines2((CvArr)linesssssss.ToIplImage(),
(CvMat)edges,
HoughLinesMethod.Standard,
1,
Math.PI / 180,
100, 100, 10);
//Cv2.HoughLinesP(edges, lines, 1, Math.PI / 180, 100, 100, 10);
List<Vec4i> lines = IntPtrToList(linesssssss.Data);
Mat Blank = new Mat(image.Rows, image.Cols, MatType.CV_8UC3, new Scalar(0, 0, 0));
for (int i = 0; i < lines.Count; i++)
{
Vec4i l = lines[i];
Cv2.Line(image, new OpenCvSharp.CPlusPlus.Point(l[0], l[1]), new OpenCvSharp.CPlusPlus.Point(l[2], l[3]), new Scalar(0, 0, 0), 2, Cv.AA);
Cv2.Line(Blank, new OpenCvSharp.CPlusPlus.Point(l[0], l[1]), new OpenCvSharp.CPlusPlus.Point(l[2], l[3]), new Scalar(255, 255, 255), 2, Cv.AA);
}
//Cv2.ImWrite("houg.jpg", image);
//Cv2.ImShow("Edges", image);
//Cv2.ImWrite("houg2.jpg", Blank);
//Cv2.ImShow("Edges Structure", Blank);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Unfortunately, it seems to be not working. It is giving the following exception:
Nonpositive cols or rows
This is the original image from the article:
Based on Github's sample code for HoughLinesP:
static void Main(string[] args)
{
string filename = "Alliance.jpg";
Mat imageIn = Cv2.ImRead(filename, ImreadModes.GrayScale).Resize(new Size(800, 600));
Mat edges = new Mat();
Cv2.Canny(imageIn, edges, 95, 100);
//HoughLinesP
LineSegmentPoint[] segHoughP = Cv2.HoughLinesP(edges, 1, Math.PI / 180, 100, 100, 10);
Mat imageOutP = imageIn.EmptyClone();
foreach (LineSegmentPoint s in segHoughP)
imageOutP.Line(s.P1, s.P2, Scalar.White, 1, LineTypes.AntiAlias, 0);
using (new Window("Edges", WindowMode.AutoSize, edges))
using (new Window("HoughLinesP", WindowMode.AutoSize, imageOutP))
{
Window.WaitKey(0);
}
}

Converting a List defined in a Struct into Int[ , ]

I am struggling a bit with a list which is defined in a particular way. This is the situation:
I have a Struct called Edge that is formed by two Points defined in the struct Point in the code (below).
My input list is called "EDGE". Using that list I would like to produce two outputs:
List POINTS : contains the non-repeated points that appear in the list "EDGE".
Int[,] edgeIndices: represents the same thing as the input list "EDGE" but instead of the points, I want the indices of such points as defined in the list "POINTS" previously created.
Can you please help me on this?
Please note that it is very important to use a List and a Int[,] and not other types.
Many thanks!
using System;
using System.Collections.Generic;
namespace Test
{
struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
struct Edge
{
public Point First;
public Point Second;
public Edge(Point First, Point Second)
{
this.First = First;
this.Second = Second;
}
}
class Program
{
static void Main(string[] args)
{
///////////////////////////INPUT////////////////////////////////////
var EDGES = new List<Edge>();
EDGES.Add(new Edge(new Point(5, 50), new Point(20, 100))); //EDGE 01
EDGES.Add(new Edge(new Point(20, 100), new Point(30, 50))); //EDGE 12
EDGES.Add(new Edge(new Point(30, 50), new Point(10, 0))); //EDGE 23
EDGES.Add(new Edge(new Point(5, 50), new Point(30, 50))); //EDGE 02
EDGES.Add(new Edge(new Point(5, 50), new Point(10, 0))); //EDGE 03
EDGES.Add(new Edge(new Point(20, 100), new Point(80, 100))); //EDGE 14
EDGES.Add(new Edge(new Point(10, 0), new Point(80, 100))); //EDGE 34
///////////////////////EXPECTED OUTPUTS/////////////////////////////
///
///POINTS (EXPECTED) as List<double[]>
///Index X Y
/// 0 5 50
/// 1 20 100
/// 2 30 50
/// 3 10 0
/// 4 80 100
///
///MULTIARRAY (EXPECTED)
///static int[,] edgeIndices =
/// {
/// {0, 1}, {1, 2}, {2, 3}, {0, 2},
/// {0, 3}, {1, 4}, {3, 4}
/// };
}
}
}
I suggest you to store distinct point values in List(). You can use following code to achieve it:
using System;
using System.Collections.Generic;
namespace Test
{
struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
struct Edge
{
public Point First;
public Point Second;
public Edge(Point First, Point Second)
{
this.First = First;
this.Second = Second;
}
}
class Program
{
static void Main(string[] args)
{
///////////////////////////INPUT////////////////////////////////////
var EDGES = new List<Edge>();
EDGES.Add(new Edge(new Point(5, 50), new Point(20, 100))); //EDGE 01
EDGES.Add(new Edge(new Point(20, 100), new Point(30, 50))); //EDGE 12
EDGES.Add(new Edge(new Point(30, 50), new Point(10, 0))); //EDGE 23
EDGES.Add(new Edge(new Point(5, 50), new Point(30, 50))); //EDGE 02
EDGES.Add(new Edge(new Point(5, 50), new Point(10, 0))); //EDGE 03
EDGES.Add(new Edge(new Point(20, 100), new Point(80, 100))); //EDGE 14
EDGES.Add(new Edge(new Point(10, 0), new Point(80, 100))); //EDGE 34
//FLL POINTS CACHE
var distinctPoints = new List<Point>();
foreach (Edge edge in EDGES)
{
if (!distinctPoints.Contains(edge.First))
distinctPoints.Add(edge.First);
if (!distinctPoints.Contains(edge.Second))
distinctPoints.Add(edge.Second);
}
//POINTS LIST OUTPUT
for (int i = 0; i < distinctPoints.Count; i++)
{
Console.WriteLine("{0} {1} {2}", i, distinctPoints[i].X, distinctPoints[i].Y);
}
//FILL 2D ARRAY OF INDICES
int[,] edgeIndices = new int[EDGES.Count, 2];
for (int i = 0; i < EDGES.Count; i++)
{
edgeIndices[i, 0] = distinctPoints.IndexOf(EDGES[i].First);
edgeIndices[i, 1] = distinctPoints.IndexOf(EDGES[i].Second);
}
//2D ARRAY OUTPUT
for (int i = 0; i < edgeIndices.GetLength(0); i++)
{
Console.WriteLine("({0}, {1})", edgeIndices[i, 0], edgeIndices[i, 1]);
}
Console.ReadKey();
}
}
}
Here is my output:
Here is mine implementation:
using System;
using System.Collections.Generic;
namespace Test{
struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
struct Edge
{
public Point First;
public Point Second;
public Edge(Point First, Point Second)
{
this.First = First;
this.Second = Second;
}
}
class Program
{
static void Main(string[] args)
{
///////////////////////////INPUT////////////////////////////////////
var EDGES = new List<Edge>();
EDGES.Add(new Edge(new Point(5, 50), new Point(20, 100))); //EDGE 01
EDGES.Add(new Edge(new Point(20, 100), new Point(30, 50))); //EDGE 12
EDGES.Add(new Edge(new Point(30, 50), new Point(10, 0))); //EDGE 23
EDGES.Add(new Edge(new Point(5, 50), new Point(30, 50))); //EDGE 02
EDGES.Add(new Edge(new Point(5, 50), new Point(10, 0))); //EDGE 03
EDGES.Add(new Edge(new Point(20, 100), new Point(80, 100))); //EDGE 14
EDGES.Add(new Edge(new Point(10, 0), new Point(80, 100))); //EDGE 34
var POINTS = new List<double[]>(EDGES.Count * 2);
FillPoints(EDGES, ref POINTS);
for (int i = 0; i < POINTS.Count; i++)
{
Console.WriteLine("{0} {1} {2}", i, POINTS[i][0], POINTS[i][1]);
}
Console.WriteLine();
var edgeIndices = new int[EDGES.Count, 2];
FillEdges(EDGES, POINTS, ref edgeIndices);
for (int i = 0; i < edgeIndices.GetLength(0); i++)
{
Console.WriteLine("({0}, {1})", edgeIndices[i, 0], edgeIndices[i, 1]);
}
Console.ReadKey(true);
}
static bool ListContainsPoint(List<double[]> POINTS, double[] POINT)
{
bool found = false;
for (int i = 0; i < POINTS.Count; i++)
{
var current = POINTS[i];
if (current[0] == POINT[0] && current[1] == POINT[1])
{
found = true;
break;
}
}
return found;
}
static int FindFirst(List<double[]> POINTS, double[] POINT)
{
int index = -1;
for (int i = 0; i < POINTS.Count; i++)
{
if (POINTS[i][0] == POINT[0] && POINTS[i][1] == POINT[1])
{
index = i;
break;
}
}
return index;
}
static void FillPoints(List<Edge> EDGES, ref List<double[]> POINTS)
{
for (int i = 0; i < EDGES.Count; i++)
{
var current = EDGES[i];
var firstPoint = new double[]{current.First.X, current.First.Y};
var secondPoint = new double[]{current.Second.X, current.Second.Y};
var firstCheck = ListContainsPoint(POINTS, firstPoint);
var secondCheck = ListContainsPoint(POINTS, secondPoint);
if (!firstCheck) POINTS.Add(firstPoint);
if (!secondCheck) POINTS.Add(secondPoint);
}
}
static void FillEdges(List<Edge> EDGES, List<double[]> POINTS, ref int[,] edgeIndices)
{
for (int i = 0; i < EDGES.Count; i++)
{
edgeIndices[i, 0] = FindFirst(POINTS, new double[] { EDGES[i].First.X, EDGES[i].First.Y });
edgeIndices[i, 1] = FindFirst(POINTS, new double[] { EDGES[i].Second.X, EDGES[i].Second.Y });
}
}
}
}

Add image to rectangle array - C#

I've got the following code and wanted to know whether there was a way for me to assign the brickImage property to the array featured in my code. If so, how do I achieve this? I basically want to create an array of bricks to be displayed in multiple rows etc.
public class Brick
{
private int x, y, width, height;
private Image brickImage;
private Rectangle brickRec;
private Rectangle[] brickRecs;
public Rectangle BrickRec
{
get { return brickRec; }
}
public Brick()
{
x = 0;
y = 0;
width = 60;
height = 20;
brickImage = Breakout.Properties.Resources.brick_fw;
brickRec = new Rectangle(x, y, width, height);
Rectangle[] brickRecs =
{
new Rectangle(0, 0, 60, 20),
new Rectangle(0, 0, 121, 20),
new Rectangle(0, 0, 242, 20)
};
}
public void drawBrick(Graphics paper)
{
paper.DrawImage(brickImage, brickRec);
//paper.DrawImage(brickImage, brickRecs);
}
}
if you want to attach an image to a rectangle simply create your own class:
public class MyBrick
{
public Image Image {get; set;}
public Point[] Locations {get; set;}
}
then add this somewhere in your code
MyBrick[] brickRecs =
{
new MyBrick()
{
Locations =
{
new Point(60, 20),
new Point(10, 10),
//....
},
Image = ... // ADD IMAGE REFERENCE HERE
},
new MyBrick()
{
Locations =
{
new Point(90, 90),
new Point(5, 5),
//....
},
Image = ...
},
};

C# clip linesegment with clipper library

I am using clipper for performing a bunch of operations on polygons which represent the outlines of objects in my program. The thing is, I now want to clip a grid of line segments to fill these outlines but I am struggling to do this with Clipper.
At the moment I am converting my lines to rectangles with a thickness of 2 units which I then do an intersection operation with and then finally I need to revert the new polygons back to line segments. This is quite inefficient though and produces quite a few errors.
Can this be done with Clipper, if not is there something else that I can use or do I need to implement my own line segment clipper?
Using Clipper ver 6 ...
using ClipperLib;
using Path = List<IntPoint>;
using Paths = List<List<IntPoint>>;
static Polygon IntsToPolygon(Int64[] ints)
{
int len1 = ints.Length / 2;
Polygon result = new Polygon(len1);
for (int i = 0; i < len1; i++)
result.Add(new IntPoint(ints[i * 2], ints[i * 2 + 1]));
return result;
}
static void Main(string[] args)
{
Paths clip = new Paths(); //clipping polygon(s)
//make a polygon in the shape of a pentagram
//with center (200,200) and radius 100 ...
Int64[][] ints1 = new Int64[][]
{
new Int64[]{222, 169, 295, 169, 236, 212, 259, 281, 200, 238,
141, 281, 164, 212, 105, 169, 178, 169, 200, 100}
};
clip.Add(IntsToPolygon(ints1[0]));
Paths subj = new Paths(); //subject paths, could be open or closed here
int gridWidth = 5;
int loopCnt = 200 / gridWidth;
//now make grid lines and add them to subj ready for clipping ...
//add horizontal grid lines ...
for (int i = 0; i <= loopCnt; i++)
{
Path gridLine = new Path(2);
gridLine.Add(new IntPoint(100, 100 + i * gridWidth));
gridLine.Add(new IntPoint(300, 100 + i * gridWidth));
subj.Add(gridLine);
}
//add vertical grid lines ...
for (int i = 0; i <= loopCnt; i++)
{
Path gridLine = new Path(2);
gridLine.Add(new IntPoint(100 + i * gridWidth, 100));
gridLine.Add(new IntPoint(100 + i * gridWidth, 300));
subj.Add(gridLine);
}
//now clip the gridlines (subj) with the pentagram (clip) ...
Clipper c = new Clipper();
PolyTree solution = new PolyTree();
c.AddPaths(subj, PolyType.ptSubject, false); //ie paths NOT closed
c.AddPaths(clip, PolyType.ptClip, true); //nb: clip paths MUST be closed
c.Execute(ClipType.ctIntersection,
solution, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);
Paths clippedGrids = Clipper.PolyTreeToPaths(solution);
//Display the result (sorry, make your own display function) ...
//Display(Paths p, Color stroke, Color brush, PolyFillType pft, bool IsClosed)
Display(subj, Color.FromArgb(0x18, 0, 0, 0x9c),
Color.Blue, PolyFillType.NonZero, false); //unclipped grid
Display(clippedGrids, FromArgb(0, 0, 0, 0),
Color.Red, false); //clipped grid
}

Categories