How to identify the polygone is triangle in wpf - c#

I have 'n' number of polygons as like below.
<Polygon Points="544,245,544,175,568,175,568,175" Stroke="Black" StrokeThickness="1" />
<Polygon Points="2,223,96,223,96,153,96,153" Stroke="Black" StrokeThickness="1" />
<Polygon Points="350,315,350,333,306,333,306,395,306,395" Stroke="Black" StrokeThickness="1" />
<Polygon Points="164,53,160,53,160,51,160,55,160,55" Stroke="Black" StrokeThickness="1" />
<Polygon Points="264,63,264,58,264,68,264,63,267,63,267,60,267,66,267,63,270,63,270,58,270,68,270,68" Stroke="Black" StrokeThickness="1" />
<Polygon Points="8,63,444,63,444,168,444,168" Stroke="Black" StrokeThickness="1" />
<Polygon Points="212,169,212,93,285,93,285,63,285,63" Stroke="Black" StrokeThickness="1" />
<Polygon Points="26,93,127,93,127,148,29,148,29,148" Stroke="Black" StrokeThickness="1" />
<Polygon Points="152,116,152,132,212,132,212,132" Stroke="Black" StrokeThickness="1" />
<Polygon Points="121,316,121,333,70,333,70,366,70,366" Stroke="Black" StrokeThickness="1" />
<Polygon Points="464,395,488,395,488,284,527,284,527,284" Stroke="Black" StrokeThickness="1" />
<Polygon Points="168,63,168,67,180,59,180,67,168,59,168,59" Stroke="Black" StrokeThickness="1" />
<Polygon Points="173,62,173,56,165,56,165,51,175,51,175,61,175,61" Stroke="Black" StrokeThickness="1" />
<Polygon Points="3,285,121,285,121,316,211,316,211,304,211,304" Stroke="Black" StrokeThickness="1" />
Please help me to identify what are the triangles in these polygons
I have tried to identify the vertices like below..
Polygon polygon = new Polygon();
polygon.Points = new System.Windows.Media.PointCollection()
{
new Point(446,134),
new Point(442,134),
new Point(444,140),
new Point(444,140),
};
List<double> verticesPoints = new List<double>();
for (int i = 0; i < polygon.Points.Count - 1; i++)
{
var point1 = polygon.Points[i];
var point2 = polygon.Points[i + 1];
//calculate delta x and delta y between the two points
var deltaX = Math.Pow((point2.X - point1.X), 2);
var deltaY = Math.Pow((point2.Y - point1.Y), 2);
//pythagras theorem for distance
var distance = Math.Sqrt(deltaY + deltaX);
//distance is zero..then same point
if (distance != 0)
{
verticesPoints.Add(distance);
}
}
///Here is the code to calculate angle and consider the triangle
///three vertices then it might be triangle.
if (verticesPoints.Count == 3)
{
///use The Law of Cosines
///cos(C) = a2 + b2 − c2 /2ab
///cos(A) = b2 + c2 − a2 /bc
///cos(B) = c2 + a2 − b2 /ca
var a = ((Math.Pow(verticesPoints[1], 2)) + (Math.Pow(verticesPoints[2], 2)) - (Math.Pow(verticesPoints[0], 2)))
/ (2 * verticesPoints[1] * verticesPoints[2]);
var b = ((Math.Pow(verticesPoints[0], 2)) + (Math.Pow(verticesPoints[2], 2)) - (Math.Pow(verticesPoints[1], 2)))
/ (2 * verticesPoints[0] * verticesPoints[2]);
var c = ((Math.Pow(verticesPoints[0], 2)) + (Math.Pow(verticesPoints[1], 2)) - (Math.Pow(verticesPoints[2], 2)))
/ (2 * verticesPoints[0] * verticesPoints[1]);
///Inverse of cos
var radians1 = Math.Acos(a);
///Convert radian to degree
double degrees1 = (radians1 * 180.0) / Math.PI;
///Inverse of cos
var radians2 = Math.Acos(b);
//Convert radian to degree
double degrees2 = (radians2 * 180.0) / Math.PI;
///Inverse of cos
var radians3 = Math.Acos(c);
///Convert radian to degree
double degrees3 = (radians3 * 180.0) / Math.PI;
var totalDegrees = degrees1 + degrees2 + degrees3;
if (totalDegrees == 180)
{
// Consider triangle
}
}
But above code is not working for <Polygon Points="446,134,442,134,444,140,444,140" Stroke="Black" StrokeThickness="1" /> it is giving only two vertices but it is a triangle and some scenario getting 3 vertices but totalDegrees is not as 180

This code here iterates through the points and calculates the gradient between each of them. If the gradient is the same for two sequential points they must be the same line, so the noOfPoints is not incremented otherwise it is incremented.
The first gradient is stored in firstGradient in order to check if the gradient connecting the last and first point is the same as the gradient between the first and second point.
Polygon polygon = new Polygon();
polygon.Points = new System.Windows.Media.PointCollection()
{
new Point(446,134),
new Point(442,134),
new Point(444,140),
new Point(444,140),
};
List<double> verticesPoints = new List<double>();
double? firstGradient = null;
double? gradient = null;
double? newGradient = null;
int noOfSides = 1;
for (int i = 0; i < polygon.Points.Count - 1; i++)
{
var point1 = polygon.Points[i];
var point2 = polygon.Points[i + 1];
if(point1 == point2) { continue;}
//calculate delta x and delta y between the two points
var deltaX = point2.X - point1.X;
var deltaY = point2.Y - point1.Y;
//calculate gradient
newGradient = (deltaY / deltaX);
if (i == 0)
{
firstGradient = newGradient;
}
if ((gradient != newGradient) && (i != polygon.Points.Count - 2))
{
noOfSides++;
}
else if (i == polygon.Points.Count - 2)
{
if ((gradient != newGradient) && (firstGradient != newGradient)) //This now checks the gradient between the last and first point.
{
point1 = polygon.Points[i+1];
point2 = polygon.Points[0];
if (point1 == point2) { continue; }
//calculate delta x and delta y between the two points
deltaX = point2.X - point1.X;
deltaY = point2.Y - point1.Y;
//calculate gradient
newGradient = (deltaY / deltaX);
if(newGradient != firstGradient)
{
noOfSides++;
}
}
gradient = newGradient;
}

I have solved the above problem using "AForge.NET"
Polygon polygon = new Polygon();
polygon.Points = new PointCollection()
{
new Point(446,134),
new Point(442,134),
new Point(444,140),
new Point(444,140),
};
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
List<IntPoint> edgePoints = new List<IntPoint>();
List<IntPoint> corners;
for (int i = 0; i <= polygon.Points.Count - 1; i++)
{
edgePoints.Add(new IntPoint((int)polygon.Points[i].X, (int)polygon.Points[i].Y));
}
shapeChecker.MinAcceptableDistortion = 0.2f;
shapeChecker.LengthError = 0;
shapeChecker.AngleError = 5;
shapeChecker.RelativeDistortionLimit = 0;
if (shapeChecker.IsTriangle(edgePoints, out corners))
{
//shape is triangle
}
Need to add below namespace
using AForge;
using AForge.Math.Geometry;
Reference :http://aforgenet.com/articles/shape_checker/

Related

Draw and scale an external image

I've found downloaded and converted into XAML some vertor picture:
<Canvas Width="0" Height="0" ClipToBounds="True">
<Path Fill="#FF000000" Stroke="#FF000000" StrokeMiterLimit="4" Name="path26">
<Path.Data>
<PathGeometry FillRule="Nonzero" Figures="M51.688,5.25C46.261,5.1091 ... 51.344,83.125z" />
</Path.Data>
</Path>
</Canvas>
and now, i'd like to draw this picture on my custom drawing:
private void Draw()
{
DrawingGroup aDrawingGroup = new DrawingGroup();
for (int DrawingStage = 0; DrawingStage < 10; DrawingStage++)
{
GeometryDrawing drw = new GeometryDrawing();
GeometryGroup gg = new GeometryGroup();
if (DrawingStage == 1)
{
drw.Brush = Brushes.Beige;
drw.Pen = new Pen(Brushes.LightGray, 0.01);
RectangleGeometry myRectGeometry = new RectangleGeometry();
myRectGeometry.Rect = new Rect(0, 0, 3, 2.3);
gg.Children.Add(myRectGeometry);
}
if (DrawingStage == 2)
{
drw.Pen = new Pen(Brushes.Black, 0.02);
for (int i = 5; i < 16; i++)
{
LineGeometry myRectGeometry = new LineGeometry(new Point(2.9, i * 0.1), new Point(0.1, i * 0.1));
gg.Children.Add(myRectGeometry);
}
}
drw.Geometry = gg;
aDrawingGroup.Children.Add(drw);
}
noteImage.Source = new DrawingImage(aDrawingGroup);
}
How could i draw and scale this an external picture?

Restrict Panning in specific border

I need help to bound the path or canvas in a boundary. What I want is, when I click the mouse-left-button, holding it and move for panning. It should not move when mouse pointer reach some boundary as BORDER. I'll add code here please help me out
XAML code:
<Border x:Name="OutMoastBorder" Height="820" Width="820" ClipToBounds="True" BorderThickness="2" BorderBrush="Black" Block.IsHyphenationEnabled="True">
<Border x:Name="clipBorder" Height="810" Width="810" BorderThickness="2" BorderBrush="Black" ClipToBounds="True">
<Canvas x:Name="CanvasPanel" Height="800" Width="800" Background="Beige">
</Canvas>
</Border>
</Border>
<Grid>
<Button Content="Original Size" Height="23" Name="btn_Original" Width="75" Click="btn_Original_Click" Margin="4,4,921,973" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="4,59,0,0" Name="txtNoOfZones" VerticalAlignment="Top" Width="120" MaxLength="2" PreviewTextInput="txtNoOfZones_PreviewTextInput" />
<Label Content="Enter a number below for No. of Zones" Height="28" HorizontalAlignment="Left" Margin="4,33,0,0" Name="label1" VerticalAlignment="Top" Width="220" FontFamily="Vijaya" FontSize="15" FontWeight="Bold" FontStyle="Normal" />
<Button Content="Zones" Height="23" HorizontalAlignment="Left" Margin="130,58,0,0" Name="btnNoOfZones" VerticalAlignment="Top" Width="41" Click="btnNoOfZones_Click" />
</Grid>
</Grid>
Code behind for zooming and panning:
void Zoom_MouseWheel(object sender, MouseWheelEventArgs e)
{
Point p = e.MouseDevice.GetPosition(((Path)sender));
Matrix m = CanvasPanel.RenderTransform.Value;
if (e.Delta > 0)
m.ScaleAtPrepend(1.1, 1.1, p.X, p.Y);
else
m.ScaleAtPrepend(1 / 1.1, 1 / 1.1, p.X, p.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
// CanvasPanel.RenderTransformOrigin = new Point(0.5, 0.5);
}
private Point origin;
private Point start;
void Pan_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (((Path)sender).IsMouseCaptured) return;
((Path)sender).CaptureMouse();
start = e.GetPosition(clipBorder);
origin.X = CanvasPanel.RenderTransform.Value.OffsetX;
origin.Y = CanvasPanel.RenderTransform.Value.OffsetY;
}
void Pan_MouseLeftBtnUp(object sender, MouseButtonEventArgs e)
{
((Path)sender).ReleaseMouseCapture();
}
void Pan_MouseMove(object sender, MouseEventArgs e)
{
if (!((Path)sender).IsMouseCaptured) return;
Point p = e.MouseDevice.GetPosition(clipBorder);
Matrix m = CanvasPanel.RenderTransform.Value;
m.OffsetX = origin.X + (p.X - start.X);
m.OffsetY = origin.Y + (p.Y - start.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
}
private const int NoOfSectors = 180;
private const int NoOfZones = 5;
void OnLoaded(object sender, RoutedEventArgs args)
{
const double PIES = 2 * Math.PI / NoOfSectors;
Point center = new Point(CanvasPanel.ActualWidth / 2, CanvasPanel.ActualHeight / 2); // center (x,y) Co-ordinates to get center of canvas
double radius = 0.1 * Math.Min(CanvasPanel.ActualWidth, CanvasPanel.ActualHeight);
for (int s = 0; s <= NoOfSectors; s++)
{
for (int z = 1; z <= NoOfZones; z++)
{
Path path = new Path();
PathGeometry pathGeo = new PathGeometry();
PathFigure pathFig = new PathFigure();
double radians = 2 * Math.PI * s / NoOfSectors;
double outerRadius = radius * z;
double innerRadius = radius * ((z - 1));
Size outerArcSize = new Size(outerRadius, outerRadius);
Size innerArcSize = new Size(innerRadius, innerRadius);
Point p1_1st_LineSegment; //------------------------------> Points variable, to store each iterate point in these.
Point p2_1st_ArcSegment;
Point p3_2nd_LineSegment;
Point p4_2nd_ArcSegment;
p1_1st_LineSegment = new Point(center.X + innerRadius * Math.Cos(radians - PIES), center.Y - innerRadius * Math.Sin(radians - PIES)); // point for LINE from Center
p2_1st_ArcSegment = new Point(center.X + innerRadius * Math.Cos(radians), center.Y - innerRadius * Math.Sin(radians)); // point for ARC after the 1st LINE formation
p3_2nd_LineSegment = new Point(center.X + outerRadius * Math.Cos(radians), center.Y - outerRadius * Math.Sin(radians)); // Point for 2nd LINE after forming both LINE abd ARC
p4_2nd_ArcSegment = new Point(center.X + outerRadius * Math.Cos(radians - PIES), center.Y - outerRadius * Math.Sin(radians - PIES)); // Point for 2nd ARC which is Counter-CLockwise that closes a path
pathFig.StartPoint = center;
pathFig.Segments.Add(new LineSegment(p1_1st_LineSegment, true));
pathFig.Segments.Add(new ArcSegment(p2_1st_ArcSegment, innerArcSize, 1, false, SweepDirection.Clockwise, true));
pathFig.Segments.Add(new LineSegment(p3_2nd_LineSegment, true));
pathFig.Segments.Add(new ArcSegment(p4_2nd_ArcSegment, outerArcSize, 1, false, SweepDirection.Counterclockwise, true));
pathFig.IsClosed = false; //false because, path has to be close with ARC, not with LINE
pathFig.IsFilled = true;
pathGeo.Figures.Add(pathFig); // binding data to a Geometry
pathGeo.FillRule = FillRule.Nonzero;
path.Data = pathGeo; // binding whole geometry data to a path
path.Stroke = Brushes.Black;
path.Fill = Brushes.Silver;
path.StrokeThickness = 0.1;
// CanvasPanel.RenderTransformOrigin = new Point(0.5, 0.5); //--------------------> this makes "Canvas" to be Zoom from center
CanvasPanel.Children.Add(path); // binding to a CanvasPanel as a children
path.MouseLeftButtonDown += MouseLeftButtonClick; // calling Mouse-click-event
path.MouseWheel += Zoom_MouseWheel;
path.MouseLeftButtonDown += Pan_MouseLeftButtonDown;
path.MouseLeftButtonUp += Pan_MouseLeftBtnUp;
path.MouseMove += Pan_MouseMove;
}
}
Please help me out.
Regards,
Viswanath.
PLz replace the MouseMove event with this following code in code behind.
void Pan_MouseMove(object sender, MouseEventArgs e)
{
if (!((Path)sender).IsMouseCaptured) return;
Point p = e.MouseDevice.GetPosition(clipBorder);
if (p.X > 0 && p.Y > 0 && p.X < clipBorder.ActualWidth && p.Y < clipBorder.ActualHeight)
{
Matrix m = CanvasPanel.RenderTransform.Value;
m.OffsetX = origin.X + (p.X - start.X);
m.OffsetY = origin.Y + (p.Y - start.Y);
CanvasPanel.RenderTransform = new MatrixTransform(m);
}
}
I have tested, this will surely solve this.
regards,
Viswa

Blurry LineGeometry in WPF

I'm using the code below to draw LineGeometry objects. But somehow I'm getting blurry lines. Any idea why this is happening?
public Window1()
{
InitializeComponent();
var x = 0;
var y = 0;
var n = 0;
while (n<1000)
{
x = x + 20;
if (x > 1200)
{
x = 0;
y = y + 20;
}
var l = new LineGeometry
{
StartPoint = new Point(x, y),
EndPoint = new Point(x, y + 15)
};
MyGroup.Children.Add(l);
n++;
}
}
<Canvas x:Name="MyCanvas" Width="1200" Height="700">
<Path x:Name="MyPath" Stroke="Wheat" SnapsToDevicePixels="True">
<Path.Data>
<GeometryGroup x:Name="MyGroup" >
</GeometryGroup>
</Path.Data>
</Path>
</Canvas>
Here is the result I get:
Here is the solution I found for this:
XAML
<Window x:Class="LearnDrawing.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="700" Width="1200" Background="Black">
<Grid>
<Grid Width="1200" Height="700">
<Path x:Name="MyPath">
<Path.Data>
<GeometryGroup x:Name="MyGroup">
</GeometryGroup>
</Path.Data>
</Path>
</Grid>
</Grid>
</Window>
Code Behind
var x = 0;
var y = 0;
var n = 0;
while (n < 1000)
{
x = x + 20;
if (x > 600)
{
x = 0;
y = y + 20;
}
var myLineGeometry = new LineGeometry
{
StartPoint = new Point(x, y),
EndPoint = new Point(x, y + 15)
};
MyGroup.Children.Add(myLineGeometry);
n++;
}
MyPath.Stroke = Brushes.White;
MyPath.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
MyPath.Data = MyGroup;
Result

Arc Segment between two points and a radius

I am trying to paint an arc segment using WPF, but I somehow cannot figure out how to do this using the ArcSegment-Element.
I have two points of the arc given (P1 and P2) and I also have the center of the circle and the radius.
I know this is a little old, but here goes a code version for a center and two angles - can be adapted to start and end points easily:
Outline:
Make a path and set the "top left" to 0,0 (You can still have center be negative if you want - this is just for path reference)
Set up the boiler plate PathGeo and PathFigure (these are building blocks of the multi-segment path in Word etc.)
Do angle checking
If it is > 180 deg (pi radians), call it a "large angle"
Find begining and end points and set them
Based upon the math, it is a clockwise rotation (remember that positive Y is down, positive X is right)
Set to canvas
public void DrawArc(ref Path arc_path, Vector center, double radius, double start_angle, double end_angle, Canvas canvas)
{
arc_path = new Path();
arc_path.Stroke = Brushes.Black;
arc_path.StrokeThickness = 2;
Canvas.SetLeft(arc_path, 0);
Canvas.SetTop(arc_path, 0);
start_angle = ((start_angle % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);
end_angle = ((end_angle % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);
if(end_angle < start_angle){
double temp_angle = end_angle;
end_angle = start_angle;
start_angle = temp_angle;
}
double angle_diff = end_angle - start_angle;
PathGeometry pathGeometry = new PathGeometry();
PathFigure pathFigure = new PathFigure();
ArcSegment arcSegment = new ArcSegment();
arcSegment.IsLargeArc = angle_diff >= Math.PI;
//Set start of arc
pathFigure.StartPoint = new Point(center.X + radius * Math.Cos(start_angle), center.Y + radius * Math.Sin(start_angle));
//set end point of arc.
arcSegment.Point = new Point(center.X + radius * Math.Cos(end_angle), center.Y + radius * Math.Sin(end_angle));
arcSegment.Size = new Size(radius, radius);
arcSegment.SweepDirection = SweepDirection.Clockwise;
pathFigure.Segments.Add(arcSegment);
pathGeometry.Figures.Add(pathFigure);
arc_path.Data = pathGeometry;
canvas.Children.Add(arc_path);
}
Create a PathFigure with P1 as StartPoint and an ArcSegment with P2 as Point and a quadratic Size that contains the radius.
Example: P1 = (150,100), P2 = (50,50), Radius = 100, i.e. Size=(100,100):
<Path Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="150,100">
<ArcSegment Size="100,100" Point="50,50"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
or shorter:
<Path Stroke="Black" Data="M150,100 A100,100 0 0 0 50,50"/>

Draw vertical lines in wpf

I have written following code for generating lines on canvas
XAML
<Canvas HorizontalAlignment="Left"
x:Name="canvas1" Height="219"
Margin="10,10,0,0" Grid.Row="1"
VerticalAlignment="Top" Width="365"/>
C#
private void Draw()
{
canvas1.Children.Clear();
for (int i = 0; i < data.Length; i++)
{
data[i] = i;
lines[i] = new Line()
{
X1 = leftMargin,
Y1 = i * scale,
X2 = i * scale,
Y2 = i * scale,
StrokeThickness = 2,
Stroke = new SolidColorBrush(Colors.Black)
};
canvas1.Children.Add(lines[i]);
}
}
But I want to draw lines as below.How I can rotatle the canvas to achieve the desired output
x = 0 and y = 0 is upper left corner (not lower left) so y is like up side down
private void Draw()
{
Line[] lines = new Line[100];
int scale = 3;
canvas1.Children.Clear();
int yStart = 290;
for (int i = 0; i < lines.Length; i++)
{
//data[i] = i;
lines[i] = new Line()
{
X1 = i * scale,
Y1 = yStart,
X2 = i * scale,
Y2 = 300 - (i * scale),
StrokeThickness = 1,
Stroke = new SolidColorBrush(Colors.Black)
};
canvas1.Children.Add(lines[i]);
}
}
<Canvas.RenderTransform>
<RotateTransform CenterX="110" CenterY="183" Angle="270" />
</Canvas.RenderTransform>
or by code:
Canvas.RenderTransform = new RotateTransform(270, 109.5, 182.5);
Something like this?
If you want to rotate the canvas, you can simply apply a transform on it:
<Canvas.RenderTransform>
<RotateTransform CenterX="110" CenterY="183" Angle="270" />
</Canvas.RenderTransform>
If you want to do as John Willemse suggested change your code to this :
X1 = i * scale,
Y1 = bottomMargin,
X2 = i * scale,
Y2 = i * scale,

Categories