how to detect corners of polygon? - c#

I am making an automated floor plan generation desktop app. In this, at first I draw the polygon on points, using this method
public void DrawPolygonPointF(PaintEventArgs e) {
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create points that define polygon.
PointF point1 = new PointF(50.0F, 50.0F);
PointF point2 = new PointF(100.0F, 25.0F);
PointF point3 = new PointF(200.0F, 5.0F);
PointF point4 = new PointF(250.0F, 50.0F);
PointF point5 = new PointF(300.0F, 100.0F);
PointF point6 = new PointF(350.0F, 200.0F);
PointF point7 = new PointF(250.0F, 250.0F);
PointF[] curvePoints =
{
point1,
point2,
point3,
point4,
point5,
point6,
point7
};
// Draw polygon curve to screen.
e.Graphics.DrawPolygon(blackPen, curvePoints);
}
NOTE: These points are not actual points, they are for only demo purpose. I am reading the points from a text file.
Now I need to generate a special type of grid.
In generating the grid the first step is detect corners and extend the corner lines.
How do I detect the corners of a polygon so can i move to next step of generating grid?
Corners are marked. I need to extend corner marked with black on horizontally left side and other one is to extend on right side till its touch the line.
A screenshot is attached.
Thanks in advance

In my understanding you are trying to extend edges, not corners.
the procedure could be:
Enumerate edges (each 2 adjacent points define an edge)
For each edge find if it vertical or horizontal (abs(x1-x2) > abs(y1-y2))
Find if edge can be extended, the horizontal (left/right) and the vertical (up/bottom)
bool CheckHorizontalExtensibilityToRight(Point[] curvePoints, Point corner)
{
return curvePoints.Any(cp=>cp.Y < corner.Y && cp.X < corner.X);
}

Try this example and see if you can adapt it to solve your problem...
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
public partial class Form1 : Form
{
private struct LineSegment
{
private PointF _a, _b;
public PointF A { get { return _a; } }
public PointF B { get { return _b; } }
public LineSegment(PointF a, PointF b)
{
_a = a; _b = b;
}
public float GetLengthSquared()
{
var dx = _a.X - _b.X;
var dy = _a.Y - _b.Y;
return dx * dx + dy * dy;
}
public bool RectContains(PointF a)
{
var x = a.X;
var y = a.Y;
var x1 = _a.X;
var y1 = _a.Y;
var x2 = _b.X;
var y2 = _b.Y;
return (x1 < x2 ? x1 <= x && x2 >= x : x2 <= x && x1 >= x) && (y1 < y2 ? y1 <= y && y2 >= y : y2 <= y && y1 >= y);
}
public bool ExtendToIntersectWith(LineSegment b)
{
var x1 = _a.X;
var y1 = _a.Y;
var x2 = _b.X;
var y2 = _b.Y;
var x3 = b._a.X;
var y3 = b._a.Y;
var x4 = b._b.X;
var y4 = b._b.Y;
var a1 = y2 - y1;
var b1 = x1 - x2;
var c1 = x1 * y2 - x2 * y1;
var a2 = y4 - y3;
var b2 = x3 - x4;
var c2 = x3 * y4 - x4 * y3;
var d = a1 * b2 - b1 * a2;
if (d == 0)
return false;
var x = (c1 * b2 - b1 * c2) / d;
var y = (a1 * c2 - c1 * a2) / d;
var p = new PointF(x, y);
if (b.RectContains(p) && !RectContains(p))
{
if (new LineSegment(_a, p).GetLengthSquared() < new LineSegment(_b, p).GetLengthSquared())
_a = p;
else
_b = p;
return true;
}
return false;
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
PointF[] curvePoints =
{
/*
new PointF(50.0F, 50.0F),
new PointF(100.0F, 25.0F),
new PointF(200.0F, 5.0F),
new PointF(250.0F, 50.0F),
new PointF(300.0F, 100.0F),
new PointF(350.0F, 200.0F),
new PointF(250.0F, 250.0F)
*/
new PointF(30F, 10F),
new PointF(60F, 10F),
new PointF(60F, 20F),
new PointF(90F, 20F),
new PointF(90F, 60F),
new PointF(10F, 60F),
new PointF(10F, 40F),
new PointF(30F, 40F),
};
int n = curvePoints.Length;
LineSegment[] lineSegments = new LineSegment[n];
int i = 0;
for (; i < n - 1; ++i)
lineSegments[i] = new LineSegment(curvePoints[i], curvePoints[i + 1]);
lineSegments[i] = new LineSegment(curvePoints[i], curvePoints[0]);
for (i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
lineSegments[i].ExtendToIntersectWith(lineSegments[j]);
for (i = 0; i < n; ++i)
{
var lineSegment = lineSegments[i];
e.Graphics.DrawLine(Pens.Black, lineSegment.A, lineSegment.B);
}
//e.Graphics.DrawPolygon(Pens.Black, curvePoints);
}
}
}

Related

How to find coordinate of contour centroid in C#

I am doing image processing so that I am finding contours in the image. What I need is the centroid pixel number of the found contour in the image. To find the pixel number I am using the code given below.
After finding the pixel number I want to show it in the text boxes as x and y coordinates. But the code is not working.
Please help me. What is wrong?
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(cannyImage, contours, null, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
var cannyOut = cannyImage.ToImage<Bgr, byte>();
//CvInvoke.DrawContours(cannyOut, contours, 2, new MCvScalar(255, 0, 0),2);
VectorOfPoint approx = new VectorOfPoint();
Dictionary<int, double> shapes = new Dictionary<int, double>();
for (int i = 0; i < contours.Size; i++)
{
approx.Clear();
double perimeter = CvInvoke.ArcLength(contours[i], true);
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);
double area = CvInvoke.ContourArea(contours[i]);
if (approx.Size > 4)
{
shapes.Add(i, area);
}
}
if (shapes.Count > 0)
{
var sortedShapes = (from item in shapes
orderby item.Value ascending
select item).ToList();
for (int i = 0; i < sortedShapes.Count; i++)
{
CvInvoke.DrawContours(cannyOut, contours, sortedShapes[i].Key, new MCvScalar(255, 0, 0), 2);
var moments = CvInvoke.Moments(contours[sortedShapes[i].Key]);
int x = (int)(moments.M10 / moments.M00);
int y = (int)(moments.M01 / moments.M00);
CvInvoke.PutText(cannyOut, (i + 1).ToString(), new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyTriplex, 1.0,
new MCvScalar(255, 0, 0), 2);
//CvInvoke.PutText(cannyOut, sortedShapes[i].Value.ToString(), new Point(x, y - 30), Emgu.CV.CvEnum.FontFace.HersheyTriplex, 1.0,
// new MCvScalar(255, 0, 0), 2);
textBox1.Text = x.ToString();
textBox2.Text = y.ToString();
}
}
To find the centroid of a shape you need to split it into many triangles first.
Then for each triangle with vertices A, B, C you do the summation weighted by the area of the triangle just as so
static void Main(string[] args)
{
var shape = new List<Triangle>();
// fill shape with triangles
float area = 0f;
Vector2 centroid = Vector2.Zero;
foreach (var triangle in shape)
{
float trig_area = triangle.Area;
Vector2 trig_cen = triangle.Centroid;
area += trig_area;
centroid += trig_area * trig_cen;
}
centroid /= area;
}
For reference, a 2D triangle has the following properties
public readonly struct Triangle
{
public Triangle(Vector2 a, Vector2 b, Vector2 c) : this()
{
A = a;
B = b;
C = c;
}
public Vector2 A { get; }
public Vector2 B { get; }
public Vector2 C { get; }
public float Area { get => (Cross(A, B) + Cross(B, C) + Cross(C, A)) / 2; }
public Vector2 Centroid { get => (A + B + C) / 3; }
// helper function
static float Cross(Vector2 a, Vector2 b) => a.X * b.Y - a.Y * b.X;
}

Get List<Segment> from a PathGeometry

I draw in a canvas several shapes. I have two kinds of shapes : Ellipse, and Path.
Now when I make a click on my Canvas, I want to get the nearest Shape.
I could manage to do something for Ellipse, but for Path I don't manage to find how to get its coordinates.
Here is the code I use to generate a List, in case something is not optimum in that method :
Concretely, "percage" are drillings, if Type=12, it means I draw a slot(Path). else I draw a circle(Ellipse)
if (percage.Type == 12)
{
double r = percage.Diametre / 2;
LineSegment ligne1 = new LineSegment();
LineSegment ligne2 = new LineSegment();
Point ptCentre = new Point(dx + percage.Coor_X, this.MyScrollViewer.ActualHeight * echelle - dy - percage.Coor_Y);
double angle = percage.AnglePer;
double xLeft = ptCentre.X - r;
double xRight = ptCentre.X + r;
double yUp = ptCentre.Y - ((percage.Longueur / 2) - r);
double yDown = ptCentre.Y + ((percage.Longueur / 2) - r);
Point pt1 = new Point(xLeft, yUp);
Point pt2 = new Point(xRight, yUp);
Point pt3 = new Point(xRight, yDown);
Point pt4 = new Point(xLeft, yDown);
pt1 = Global.RotatePoint(pt1, ptCentre, angle - 90);
pt2 = Global.RotatePoint(pt2, ptCentre, angle - 90);
pt3 = Global.RotatePoint(pt3, ptCentre, angle - 90);
pt4 = Global.RotatePoint(pt4, ptCentre, angle - 90);
Path arc_path1 = new Path();
arc_path1.Stroke = Brushes.Red;
arc_path1.StrokeThickness = 2;
PathGeometry pathGeometry = new PathGeometry();
ArcSegment arc1 = new ArcSegment();
ArcSegment arc2 = new ArcSegment();
PathFigure pathfigure1 = new PathFigure();
PathFigure pathfigure2 = new PathFigure();
arc1.Point = new Point(pt2.X, pt2.Y);
arc1.Point = new Point(pt4.X, pt4.Y);
pathfigure1.StartPoint = new Point(pt1.X, pt1.Y);
pathfigure1.StartPoint = new Point(pt3.X, pt3.Y);
SweepDirection sd = SweepDirection.Counterclockwise;
if (yUp < yDown)
{
sd = SweepDirection.Clockwise;
}
arc1.Size = new Size(r, r);
arc1.SweepDirection = sd;
arc2.Size = new Size(r, r);
arc2.SweepDirection = sd;
arc1.Point = pt2;
arc2.Point = pt4;
ligne1.Point = new Point(pt3.X, pt3.Y);
ligne2.Point = new Point(pt1.X, pt1.Y);
pathfigure1.StartPoint = new Point(pt1.X, pt1.Y);
pathfigure1.Segments.Add(arc1);
pathfigure1.Segments.Add(ligne1);
pathfigure1.Segments.Add(arc2);
pathfigure1.Segments.Add(ligne2);
pathGeometry.Figures.Add(pathfigure1);
arc_path1.Data = pathGeometry;
arc_path1.Tag = percage;
percage.ListShapes.Add(arc_path1);
}
else
{
Ellipse ellipse = new Ellipse();
ellipse.Stroke = System.Windows.Media.Brushes.Red;
ellipse.StrokeThickness = 1;
ellipse.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);
ellipse.Width = percage.Diametre;
ellipse.Height = percage.Diametre;
percage.Coor_X_Graph = X1 + dx - (percage.Diametre / 2);
percage.Coor_Y_Graph = this.MyScrollViewer.ActualHeight * echelle - (Y1 + dy) - (percage.Diametre / 2);
ellipse.Margin = new System.Windows.Thickness(percage.Coor_X_Graph, percage.Coor_Y_Graph, 0, 0);
ellipse.Tag = percage;
percage.ListShapes.Add(ellipse);
}
Then, to get the nearest shape, I began that code :
For ellipse I can retrieve its coordinates, but for Path, couldn't find the List of Segments inside.
StartPoint = e.GetPosition(monDessin);
double distance=-1;
Shape selectedShape = null;
for (int i = monDessin.Children.Count - 1; i > -1; i--)
{
if (monDessin.Children[i] is Ellipse)
{
Ellipse ell = (Ellipse)monDessin.Children[i];
double x = ell.Margin.Left + Width / 2;
double y = ell.Margin.Top - ell.Height / 2;
double dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y -y) * (StartPoint.Y - y));
if(distance==-1 || dist<distance)
{
distance = dist;
}
}
else if(monDessin.Children[i] is Path)
{
Path path=(Path)monDessin.Children[i];
Geometry geometry = path.Data;
foreach(PathFigure pf in ?????)
}
}
Finally, I could do it myself looking a bit more on internet (not sure it is the best way as I began on that theme,so any other suggestion is welcome)
I found some "solution" here
But the code didn't work, got an error on the following line (without understand why, neither what it does)
string value = seralizer.ConvertToString(geomerty, null);
Finally I adapted it looking on msdn website, I found geometry.GetOutlinedPathGeometry() and pathGeometry.Figures that allowed to get list of figures. I just don't understand why all my ArcSegment became BezierSegment.
Anyway, it works fine, so I put here the code :
StartPoint = e.GetPosition(monDessin);
double distance=-1;
double dist;
Shape selectedShape = null;
for (int i = monDessin.Children.Count - 1; i > -1; i--)
{
string type = monDessin.Children[i].GetType().ToString();
if (monDessin.Children[i] is Ellipse)
{
Ellipse ell = (Ellipse)monDessin.Children[i];
double x = ell.Margin.Left + ell.Width / 2;
double y = ell.Margin.Top - ell.Height / 2;
dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y -y) * (StartPoint.Y - y));
if(distance==-1 || dist<distance)
{
distance = dist;
}
}
else if(monDessin.Children[i] is Path)
{
Path path=(Path)monDessin.Children[i];
string titi = path.Tag.GetType().ToString();
Geometry geometry = path.Data;
PathGeometry pathGeometry = geometry.GetOutlinedPathGeometry();
PathFigureCollection figures = pathGeometry.Figures;
if (figures != null)
{
foreach (PathFigure figure in figures)
{
foreach (PathSegment segment in figure.Segments)
{
//first syntax : if(segment is LineSegment)
if(segment is LineSegment)
{
LineSegment lineSegment = (LineSegment)segment;
double x = lineSegment.Point.X;
ouble y = lineSegment.Point.Y;
}
//2nd syntax :
//ArcSegment arcSegment = segment as ArcSegment;
//Then check if not null
ArcSegment arcSegment = segment as ArcSegment;
if (arcSegment != null)
{
double x = arcSegment.Point.X;
double y = arcSegment.Point.Y;
dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y - y) * (StartPoint.Y - y));
if (distance == -1 || dist < distance)
{
distance = dist;
}
}
BezierSegment bezierSegment = segment as BezierSegment;
if (bezierSegment != null)
{
double x = bezierSegment.Point3.X;
double y = bezierSegment.Point3.Y;
dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y - y) * (StartPoint.Y - y));
if (distance == -1 || dist < distance)
{
distance = dist;
}
}
}
}
}
}
}
Nota : I found two different syntaxes to check the type of segment(i.e LineSegment), I don't know which is the best approach, the first syntax seems better, but the 2nd one has the advantage to check if it is null(even if in theory it may never happen???)

Writing Letters and Numbers in C# form

I am very new to c# form and i would like to write some letters in a specific location. As you can see in the picture i have attached I've drawn a curved Line with a X and Y axis to scale it with. I would like to write the letter X on the edge of the horizontal line and Y on the top Edge of the vertical line. Also is there any possible ways to assign values on the line as well?
protected override void OnPaint(PaintEventArgs e)
{
float a = 1, b = 5, c = -4;
double x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6, x7, y7, delta;
delta = (b * b) - (4 * a * c);
x1 = ((b * (-1)) + Math.Sqrt(delta)) / (2 * a);
x6 = ((b * (-1)) - Math.Sqrt(delta)) / (2 * a);
y6 = a * (x6 * x6) + (b * (x6)) + c;
y1 = a * (x1 * x1) + (b * (x1)) + c;
x2 = 3;
y2 = a * (x2 * x2) + (b * (x2)) + c;
x3 = -3;
y3 = a * (x3 * x3) + (b * (x3)) + c;
x4 = 5;
y4 = a * (x4 * x4) + (b * (x4)) + c;
x5 = -10;
y5 = a * (x5 * x5) + (b * (x5)) + c;
x7 = 0;
y7 = a * (x7 * x7) + (b * (x7)) + c;
int cx1 = Convert.ToInt32(x1);
int cx2 = Convert.ToInt32(x2);
int cx3 = Convert.ToInt32(x3);
int cy1 = Convert.ToInt32(y1);
int cy2 = Convert.ToInt32(y2);
int cy3 = Convert.ToInt32(y3);
int cx4 = Convert.ToInt32(x4);
int cy4 = Convert.ToInt32(y4);
int cx5 = Convert.ToInt32(x5);
int cy5 = Convert.ToInt32(y5);
int cx6 = Convert.ToInt32(x6);
int cy6 = Convert.ToInt32(y6);
int cx7 = Convert.ToInt32(x7);
int cy7 = Convert.ToInt32(x7);
Graphics g = e.Graphics;
int deltaX = 300;
int deltaY = 300;
g.TranslateTransform(deltaX, deltaY);
float factor = 2.5f;
Matrix m = new Matrix();
m.Scale(factor, factor);
g.MultiplyTransform(m);
Pen aPen = new Pen(Color.Blue, 1);
aPen.DashStyle = DashStyle.DashDot;
Pen bPen = new Pen(Color.Green, 1);
bPen.EndCap = LineCap.ArrowAnchor;
Pen cPen = new Pen(Color.Green, 1);
cPen.StartCap = LineCap.DiamondAnchor;
Point point1 = new Point(cx1, -cy1);
Point point2 = new Point(cx2, -cy2);
Point point3 = new Point(cx3, -cy3);
Point point4 = new Point(cx4, -cy4);
Point point5 = new Point(cx5, -cy5);
Point point6 = new Point(cx6, -cy6);
Point pointa = new Point(20, -50);
Point pointb = new Point(40, -30);
Point pointc = new Point(60, -70);
Point[] Points = { point5, point3, point1, point2, point4 };
Point[] Pointss = { pointa, pointb,pointc };
g.DrawCurve(new Pen(Color.Red, 1), Pointss);
g.DrawCurve(aPen, Points);
g.DrawLine((cPen), new Point(cx7, -100), new Point(cx7, 100));
g.DrawLine((bPen), -100, 0, 100, 0);
check my sample. I hope it helps.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace GraphicsForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var g = e.Graphics;
var w = ClientRectangle.Width;
var h = ClientRectangle.Height;
var midY = h/2;
var midX = w/2;
var linePen = new Pen(Brushes.Red, 1)
{
StartCap = LineCap.DiamondAnchor,
EndCap = LineCap.DiamondAnchor
};
//horizontal line
g.DrawLine(linePen, 0, midY, w, midY);
var font = Font;
var measureStringX = g.MeasureString("x", font);
g.DrawString("x", font, Brushes.Black, w - measureStringX.Width - 2, midY + 2);
//vertical line
g.DrawLine(linePen, midX, 0, midX, h);
g.DrawString("y", font, Brushes.Black, midX + 2, 2);
//horizontals&vertical marks
const float marksCount = 12f;
var wx = w / marksCount;
var hx = h / marksCount;
var markPen = new Pen(Brushes.Red, 1);
for (int i = 1; i < marksCount; i++)
{
g.DrawLine(markPen, i * wx, midY, i * wx, midY + 5);
g.DrawLine(markPen, midX, hx * i, midX + 5, hx * i);
}
}
}
}
"Check out DrawString on the graphics object. https://msdn.microsoft.com/en-us/library/system.drawing.graphics.drawstring.aspx – dbugger"
Answered.

Drawing on a canvas a big pixels

I am writing an app which allow user to draw on a touch screen display. I am currently using the method below and it work very well. This method is producing a “high resolution image” since for almost every single pixel a line is drawn (e.g. 100, 100 -> 102, 103).
Here is my question. I’d like user to draw a “low resolution picture” (big pixels board) where you can intentionally see pixels of 50×50 (e.g. 100, 100 -> 150, 150). Does anybody have an idea on how to accomplish that? I am using Silverlight for Windows Phone. I was thinking about building a big grid of 50×50 pixels, but there might be too many controls.
void FingerMove(object sender, MouseEventArgs e)
{
if (this.IsDrawing)
{
this.DestinationPoint = e.GetPosition(paint);
Line line = new Line
{
Stroke = this.Color,
X1 = this.DestinationPoint.X,
Y1 = this.DestinationPoint.Y,
X2 = this.OriginPoint.X,
Y2 = this.OriginPoint.Y,
StrokeStartLineCap = PenLineCap.Round,
StrokeEndLineCap = PenLineCap.Round,
StrokeThickness = 15,
Opacity = 1,
};
Debug.WriteLine(string.Join(",", line.X1, line.Y1, line.X2, line.Y2));
paint.Children.Add(line);
}
this.OriginPoint = this.DestinationPoint;
}
#Amr has the right idea. I'll give you this code with the caveat that I haven't tested it at all. I took the line segment intersection algorithm from here.
First, you need to set up a list of Rectangles and add them to the canvas that are your "pixels":
private List<Rectangle> _rects = new List<Rectangle>();
private void GenerateRects()
{
int width = 300; // or whatever dimensions...
int height = 300;
int gridSize = 50;
for (int x = 0; x < width; x += gridSize)
{
for (int y = 0; y < height; y += gridSize)
{
var rect = new Rectangle
{
Opacity = 0,
Width = Math.Min(gridSize, width - x),
Height = Math.Min(gridSize, height - y),
};
Canvas.SetLeft(rect, x);
Canvas.SetTop(rect, y);
_rects.Add(rect);
this.paint.Children.Add(rect);
}
}
}
We'll need these helper methods:
class LineSegment
{
public double X1 { get; set; }
public double X2 { get; set; }
public double Y1 { get; set; }
public double Y2 { get; set; }
}
private static bool SegmentsIntersect(LineSegment A, LineSegment B)
{
double x1 = A.X1, x2 = A.X2, x3 = B.X1, x4 = B.X2;
double y1 = A.Y1, y2 = A.Y2, y3 = B.Y1, y4 = B.Y2;
double denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
if (denominator == 0)
return false;
double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;
return (ua > 0 && ua < 1 && ub > 0 && ub < 1);
}
private static bool RectIntersectsLine(Rect A, LineSegment B)
{
return (SegmentsIntersect(B, new LineSegment { X1 = A.X, Y1 = A.Y, X2 = A.X, Y2 = A.Y + A.Height }) ||
SegmentsIntersect(B, new LineSegment { X1 = A.X, Y1 = A.Y + A.Height, X2 = A.X + A.Width, Y2 = A.Y + A.Height }) ||
SegmentsIntersect(B, new LineSegment { X1 = A.X + A.Width, Y1 = A.Y + A.Height, X2 = A.X + A.Width, Y2 = A.Y }) ||
SegmentsIntersect(B, new LineSegment { X1 = A.X + A.Width, Y1 = A.Y, X2 = A.X, Y2 = A.Y }) ||
RectContainsPoint(A, new Point(B.X1, B.Y1)) ||
RectContainsPoint(A, new Point(B.X2, B.Y2)));
}
private static bool RectContainsPoint(Rect A, Point B)
{
return (B.X > A.X && B.X < A.X + A.Width && B.Y > A.Y && B.Y < A.Y + A.Height);
}
Then, in the FingerMove function, we loop through each Rectangle to see if it intersects. If it does, we change its color:
void FingerMove(object sender, MouseEventArgs e)
{
if (this.IsDrawing)
{
this.DestinationPoint = e.GetPosition(paint);
LineSegment line = new LineSegment
{
X1 = this.DestinationPoint.X,
Y1 = this.DestinationPoint.Y,
X2 = this.OriginPoint.X,
Y2 = this.OriginPoint.Y
};
foreach (var rect in _rects)
{
var x = Canvas.GetLeft(rect);
var y = Canvas.GetTop(rect);
if (RectIntersectsLine(new Rect(x, y, rect.Width, rect.Height) , line))
{
rect.Opacity = 1;
rect.Fill = Color;
}
}
}
this.OriginPoint = this.DestinationPoint;
}
If you simply want to make the line thicker, just experiment with possible values of StrokeThickness untill you get the desired effect.
If you want to manually draw the line by filling up large areas of the screen say (50x50) rectangles, you could do the follwing:
divide the screen into 50x50 rectangles
check which rectangles are intersected by the line drawn by the user
only draw the rectangles from step 2
This would give you the 'snap to grid' line that you want.

Help converting Python app to C#

Everyone,
here is a link to a small python app:
http://en.wikipedia.org/wiki/File:Beta-skeleton.svg
I think I've correctly converted it. (Source at bottom of post)
But, the Math.Acos always returns NaN. Is there a difference between the python version of acos and Math.Acos?
private Random rnd = new Random();
private double scale = 5;
private double radius = 10;
private double beta1 = 1.1;
private double beta2 = 0.9;
private double theta1;
private double theta2;
private Point[] points = new Point[10];
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 100; i++ )
{
points[i] = new Point((rnd.NextDouble() * scale),
(rnd.NextDouble() * scale));
}
theta1 = Math.Asin(1/beta1);
theta2 = Math.PI - Math.Asin(beta2);
}
private double Dot(Point p, Point q, Point r)
{
var pr = new Point();
var qr = new Point();
//(p[0]-r[0])
pr.X = p.X-r.X;
//(p[1]-r[1])
pr.Y = p.Y-r.Y;
//(q[0]-r[0])
qr.X = q.X-r.X;
//(q[1]-r[1])
qr.Y = q.Y-r.Y;
return (pr.X*qr.X) + (pr.Y*qr.Y);
}
private double Sharp(Point p,Point q)
{
double theta = 0;
foreach(var pnt in points)
{
if(pnt!=p && pnt!=q)
{
var dotpq = Dot(p, q, pnt);
double t = Math.Acos(dotpq);
double u = Math.Pow((dotpq * dotpq), 0.5);
var tempVal = t/u;
theta = Math.Max(theta, tempVal);
}
}
return theta;
}
private void DrawPoint(Point p)
{
var e = new Ellipse
{
Width = radius/2,
Height = radius/2,
Stroke = Brushes.Red,
Visibility = Visibility.Visible
};
Canvas.SetTop(e, p.Y + radius);
Canvas.SetLeft(e, p.X + radius);
MyCanvas.Children.Add(e);
}
private void DrawEdge1(Point p,Point q)
{
var l = new Line
{
X1 = p.X,
Y1 = p.Y,
X2 = q.X,
Y2 = q.Y,
Stroke = Brushes.Black,
Width = 1,
Visibility = Visibility.Visible
};
MyCanvas.Children.Add(l);
}
private void DrawEdge2(Point p,Point q)
{
var l = new Line
{
X1 = p.X,
Y1 = p.Y,
X2 = q.X,
Y2 = q.Y,
Stroke = Brushes.Blue,
Width = 1,
Visibility = Visibility.Visible
};
MyCanvas.Children.Add(l);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (var p in points)
{
foreach (var q in points)
{
var theta = Sharp(p, q);
if(theta < theta1) DrawEdge1(p, q);
else if(theta < theta2) DrawEdge2(p, q);
}
}
}
What you need to do to get the angle from the dot product is to take away the lengths before you acos.
What python has:
prq = acos(dot(p,q,r) / (dot(p,p,r)*dot(q,q,r))**0.5)
What you're doing is not dividing in the Acos, but dividing after.
so:
int r = pnt;
int ppr = Dot(p,p,r);
int qqr = Dot(q,q,r);
int pqr = Dot(p,q,r);
double u = Math.Acos(pqr / Math.Sqrt(ppr * qqr));
Of course change the variables, I was just trying to keep it similar to the python to help you understand :)
I think it's due to your translation of the Python expression (dot(p,q,r) / (dot(p,p,r) * dot(q,q,r)) **0.5). Exponentiation in Python has one of the lowest operators precedency-wise, so the square-root is being taken of the subterm dot(p,q,r) / (dot(p,p,r) * dot(q,q,r)). In your C# version, when calculating the value of the double 'u', you're only taking the square-root of the product of the last two terms, i.e. the (dotpq * dotpq).
The question really is what is the value of dotpq when the function gets called. It has to be a double value between -1 and 1 as stated in the docs.

Categories