/// <summary>
/// Check sub type of a convex polygon.
/// </summary>
///
/// <param name="corners">Corners of the convex polygon to check.</param>
///
/// <returns>Return detected sub type of the specified shape.</returns>
///
/// <remarks><para>The method check corners of a convex polygon detecting
/// its subtype. Polygon's corners are usually retrieved using <see cref="IsConvexPolygon"/>
/// method, but can be any list of 3-4 points (only sub types of triangles and
/// quadrilateral are checked).</para>
///
/// <para>See <see cref="AngleError"/> and <see cref="LengthError"/> properties,
/// which set acceptable errors for polygon sub type checking.</para>
/// </remarks>
///
public PolygonSubType CheckPolygonSubType(List <IntPoint> corners)
{
PolygonSubType subType = PolygonSubType.Unknown;
// get bounding rectangle of the points list
IntPoint minXY, maxXY;
PointsCloud.GetBoundingRectangle(corners, out minXY, out maxXY);
// get cloud's size
IntPoint cloudSize = maxXY - minXY;
float maxLengthDiff = lengthError * (cloudSize.X + cloudSize.Y) / 2;
if (corners.Count == 3)
{
// get angles of the triangle
float angle1 = GeometryTools.GetAngleBetweenVectors(corners[0], corners[1], corners[2]);
float angle2 = GeometryTools.GetAngleBetweenVectors(corners[1], corners[2], corners[0]);
float angle3 = GeometryTools.GetAngleBetweenVectors(corners[2], corners[0], corners[1]);
// check for equilateral triangle
if ((Math.Abs(angle1 - 60) <= angleError) &&
(Math.Abs(angle2 - 60) <= angleError) &&
(Math.Abs(angle3 - 60) <= angleError))
{
subType = PolygonSubType.EquilateralTriangle;
}
else
{
// check for isosceles triangle
if ((Math.Abs(angle1 - angle2) <= angleError) ||
(Math.Abs(angle2 - angle3) <= angleError) ||
(Math.Abs(angle3 - angle1) <= angleError))
{
subType = PolygonSubType.IsoscelesTriangle;
}
// check for rectangled triangle
if ((Math.Abs(angle1 - 90) <= angleError) ||
(Math.Abs(angle2 - 90) <= angleError) ||
(Math.Abs(angle3 - 90) <= angleError))
{
subType = (subType == PolygonSubType.IsoscelesTriangle) ?
PolygonSubType.RectangledIsoscelesTriangle : PolygonSubType.RectangledTriangle;
}
}
}
else if (corners.Count == 4)
{
// get angles between 2 pairs of opposite sides
float angleBetween1stPair = GeometryTools.GetAngleBetweenLines(corners[0], corners[1], corners[2], corners[3]);
float angleBetween2ndPair = GeometryTools.GetAngleBetweenLines(corners[1], corners[2], corners[3], corners[0]);
// check 1st pair for parallelism
if (angleBetween1stPair <= angleError)
{
subType = PolygonSubType.Trapezoid;
// check 2nd pair for parallelism
if (angleBetween2ndPair <= angleError)
{
subType = PolygonSubType.Parallelogram;
// check angle between adjacent sides
if (Math.Abs(GeometryTools.GetAngleBetweenVectors(corners[1], corners[0], corners[2]) - 90) <= angleError)
{
subType = PolygonSubType.Rectangle;
}
// get length of 2 adjacent sides
float side1Length = (float)corners[0].DistanceTo(corners[1]);
float side2Length = (float)corners[0].DistanceTo(corners[3]);
if (Math.Abs(side1Length - side2Length) <= maxLengthDiff)
{
subType = (subType == PolygonSubType.Parallelogram) ?
PolygonSubType.Rhombus : PolygonSubType.Square;
}
}
}
else
{
// check 2nd pair for parallelism - last chence to detect trapezoid
if (angleBetween2ndPair <= angleError)
{
subType = PolygonSubType.Trapezoid;
}
}
}
return(subType);
}