281 lines
10 KiB
C#
281 lines
10 KiB
C#
using System;
|
|
using GeometryUtility;
|
|
|
|
namespace PolygonCuttingEar
|
|
{
|
|
/// <summary>
|
|
/// Summary description for Class1.
|
|
/// </summary>
|
|
public class CPolygonShape
|
|
{
|
|
private readonly CPoint2D[] _aInputVertices;
|
|
private CPoint2D[] _aUpdatedPolygonVertices;
|
|
|
|
private readonly System.Collections.ArrayList _alEars
|
|
=new System.Collections.ArrayList();
|
|
private CPoint2D[][] _aPolygons;
|
|
|
|
public int NumberOfPolygons
|
|
{
|
|
get
|
|
{
|
|
return _aPolygons.Length;
|
|
}
|
|
}
|
|
|
|
public CPoint2D[] Polygons(int index)
|
|
{
|
|
if (index< _aPolygons.Length)
|
|
return _aPolygons[index];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
public CPolygonShape(CPoint2D[] vertices)
|
|
{
|
|
int nVertices=vertices.Length;
|
|
if (nVertices<3)
|
|
{
|
|
System.Diagnostics.Trace.WriteLine("To make a polygon, "
|
|
+ " at least 3 points are required!");
|
|
return;
|
|
}
|
|
|
|
//initalize the 2D points
|
|
_aInputVertices=new CPoint2D[nVertices];
|
|
|
|
for (int i=0; i<nVertices; i++)
|
|
_aInputVertices[i] =vertices[i];
|
|
|
|
//make a working copy, _aUpdatedPolygonVertices are
|
|
//in count clock direction from user view
|
|
SetUpdatedPolygonVertices();
|
|
}
|
|
|
|
/****************************************************
|
|
To fill _aUpdatedPolygonVertices array with input array.
|
|
|
|
_aUpdatedPolygonVertices is a working array that will
|
|
be updated when an ear is cut till _aUpdatedPolygonVertices
|
|
makes triangle (a convex polygon).
|
|
******************************************************/
|
|
private void SetUpdatedPolygonVertices()
|
|
{
|
|
int nVertices=_aInputVertices.Length;
|
|
_aUpdatedPolygonVertices=new CPoint2D[nVertices];
|
|
|
|
for (int i=0; i< nVertices; i++)
|
|
_aUpdatedPolygonVertices[i] =_aInputVertices[i];
|
|
|
|
//_aUpdatedPolygonVertices should be in count clock wise
|
|
if (CPolygon.PointsDirection(_aUpdatedPolygonVertices)
|
|
==PolygonDirection.Clockwise)
|
|
CPolygon.ReversePointsDirection(_aUpdatedPolygonVertices);
|
|
}
|
|
|
|
/**********************************************************
|
|
To check the Pt is in the Triangle or not.
|
|
If the Pt is in the line or is a vertex, then return true.
|
|
If the Pt is out of the Triangle, then return false.
|
|
|
|
This method is used for triangle only.
|
|
***********************************************************/
|
|
private bool TriangleContainsPoint(CPoint2D[] trianglePts, CPoint2D pt)
|
|
{
|
|
if (trianglePts.Length!=3)
|
|
return false;
|
|
|
|
for (int i=trianglePts.GetLowerBound(0);
|
|
i<trianglePts.GetUpperBound(0); i++)
|
|
{
|
|
if (pt.EqualsPoint(trianglePts[i]))
|
|
return true;
|
|
}
|
|
|
|
bool bIn=false;
|
|
|
|
CLineSegment line0=new CLineSegment(trianglePts[0],trianglePts[1]);
|
|
CLineSegment line1=new CLineSegment(trianglePts[1],trianglePts[2]);
|
|
CLineSegment line2=new CLineSegment(trianglePts[2],trianglePts[0]);
|
|
|
|
if (pt.InLine(line0)||pt.InLine(line1)
|
|
||pt.InLine(line2))
|
|
bIn=true;
|
|
else //point is not in the lines
|
|
{
|
|
double dblArea0=CPolygon.PolygonArea(new CPoint2D[]
|
|
{trianglePts[0],trianglePts[1], pt});
|
|
double dblArea1=CPolygon.PolygonArea(new CPoint2D[]
|
|
{trianglePts[1],trianglePts[2], pt});
|
|
double dblArea2=CPolygon.PolygonArea(new CPoint2D[]
|
|
{trianglePts[2],trianglePts[0], pt});
|
|
|
|
if (dblArea0>0)
|
|
{
|
|
if ((dblArea1 >0) &&(dblArea2>0))
|
|
bIn=true;
|
|
}
|
|
else if (dblArea0<0)
|
|
{
|
|
if ((dblArea1 < 0) && (dblArea2< 0))
|
|
bIn=true;
|
|
}
|
|
}
|
|
return bIn;
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
To check whether the Vertex is an ear or not based updated Polygon vertices
|
|
|
|
ref. www-cgrl.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian
|
|
/algorithm1.html
|
|
|
|
If it is an ear, return true,
|
|
If it is not an ear, return false;
|
|
*****************************************************************/
|
|
private bool IsEarOfUpdatedPolygon(CPoint2D vertex )
|
|
{
|
|
CPolygon polygon=new CPolygon(_aUpdatedPolygonVertices);
|
|
|
|
if (polygon.PolygonVertex(vertex))
|
|
{
|
|
bool bEar=true;
|
|
if (polygon.PolygonVertexType(vertex)==VertexType.ConvexPoint)
|
|
{
|
|
CPoint2D pi=vertex;
|
|
CPoint2D pj=polygon.PreviousPoint(vertex); //previous vertex
|
|
CPoint2D pk=polygon.NextPoint(vertex);//next vertex
|
|
|
|
for (int i=_aUpdatedPolygonVertices.GetLowerBound(0);
|
|
i<_aUpdatedPolygonVertices.GetUpperBound(0); i++)
|
|
{
|
|
CPoint2D pt = _aUpdatedPolygonVertices[i];
|
|
if ( !(pt.EqualsPoint(pi)|| pt.EqualsPoint(pj)||pt.EqualsPoint(pk)))
|
|
{
|
|
if (TriangleContainsPoint(new CPoint2D[] {pj, pi, pk}, pt))
|
|
bEar=false;
|
|
}
|
|
}
|
|
} //ThePolygon.getVertexType(Vertex)=ConvexPt
|
|
else //concave point
|
|
bEar=false; //not an ear/
|
|
return bEar;
|
|
}
|
|
else //not a polygon vertex;
|
|
{
|
|
System.Diagnostics.Trace.WriteLine("IsEarOfUpdatedPolygon: "+
|
|
"Not a polygon vertex");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/****************************************************
|
|
Set up _aPolygons:
|
|
add ears and been cut Polygon togather
|
|
****************************************************/
|
|
private void SetPolygons()
|
|
{
|
|
int nPolygon=_alEars.Count + 1; //ears plus updated polygon
|
|
_aPolygons=new CPoint2D[nPolygon][];
|
|
|
|
for (int i=0; i<nPolygon-1; i++) //add ears
|
|
{
|
|
CPoint2D[] points=(CPoint2D[])_alEars[i];
|
|
|
|
_aPolygons[i]=new CPoint2D[3]; //3 vertices each ear
|
|
_aPolygons[i][0]=points[0];
|
|
_aPolygons[i][1]=points[1];
|
|
_aPolygons[i][2]=points[2];
|
|
}
|
|
|
|
//add UpdatedPolygon:
|
|
_aPolygons[nPolygon-1]=new
|
|
CPoint2D[_aUpdatedPolygonVertices.Length];
|
|
|
|
for (int i=0; i<_aUpdatedPolygonVertices.Length;i++)
|
|
{
|
|
_aPolygons[nPolygon-1][i] = _aUpdatedPolygonVertices[i];
|
|
}
|
|
}
|
|
|
|
/********************************************************
|
|
To update _aUpdatedPolygonVertices:
|
|
Take out Vertex from _aUpdatedPolygonVertices array, add 3 points
|
|
to the _aEars
|
|
**********************************************************/
|
|
private void UpdatePolygonVertices(CPoint2D vertex)
|
|
{
|
|
System.Collections.ArrayList alTempPts=new System.Collections.ArrayList();
|
|
|
|
for (int i=0; i< _aUpdatedPolygonVertices.Length; i++)
|
|
{
|
|
if (vertex.EqualsPoint(
|
|
_aUpdatedPolygonVertices[i])) //add 3 pts to FEars
|
|
{
|
|
CPolygon polygon=new CPolygon(_aUpdatedPolygonVertices);
|
|
CPoint2D pti = vertex;
|
|
CPoint2D ptj = polygon.PreviousPoint(vertex); //previous point
|
|
CPoint2D ptk = polygon.NextPoint(vertex); //next point
|
|
|
|
CPoint2D[] aEar=new CPoint2D[3]; //3 vertices of each ear
|
|
aEar[0]=ptj;
|
|
aEar[1]=pti;
|
|
aEar[2]=ptk;
|
|
|
|
_alEars.Add(aEar);
|
|
}
|
|
else
|
|
{
|
|
alTempPts.Add(_aUpdatedPolygonVertices[i]);
|
|
} //not equal points
|
|
}
|
|
|
|
if (_aUpdatedPolygonVertices.Length
|
|
- alTempPts.Count==1)
|
|
{
|
|
int nLength=_aUpdatedPolygonVertices.Length;
|
|
_aUpdatedPolygonVertices=new CPoint2D[nLength-1];
|
|
|
|
for (int i=0; i<alTempPts.Count; i++)
|
|
_aUpdatedPolygonVertices[i]=(CPoint2D)alTempPts[i];
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************
|
|
To cut an ear from polygon to make ears and an updated polygon:
|
|
*******************************************************/
|
|
public void CutEar()
|
|
{
|
|
new CPolygon(_aUpdatedPolygonVertices);
|
|
bool bFinish=_aUpdatedPolygonVertices.Length==3;
|
|
|
|
CPoint2D pt=new CPoint2D();
|
|
while (bFinish==false) //UpdatedPolygon
|
|
{
|
|
int i=0;
|
|
bool bNotFound=true;
|
|
while (bNotFound
|
|
&& (i<_aUpdatedPolygonVertices.Length)) //loop till find an ear
|
|
{
|
|
pt=_aUpdatedPolygonVertices[i];
|
|
if (IsEarOfUpdatedPolygon(pt))
|
|
bNotFound=false; //got one, pt is an ear
|
|
else
|
|
i++;
|
|
} //bNotFount
|
|
//An ear found:}
|
|
if (pt !=null)
|
|
UpdatePolygonVertices(pt);
|
|
|
|
new CPolygon(_aUpdatedPolygonVertices);
|
|
//if ((polygon.GetPolygonType()==PolygonType.Convex)
|
|
// && (_aUpdatedPolygonVertices.Length==3))
|
|
if (_aUpdatedPolygonVertices.Length==3)
|
|
bFinish=true;
|
|
} //bFinish=false
|
|
SetPolygons();
|
|
}
|
|
}
|
|
}
|