本文整理汇总了C#中TriangleNet.Data.Otri.Lnext方法的典型用法代码示例。如果您正苦于以下问题:C# Otri.Lnext方法的具体用法?C# Otri.Lnext怎么用?C# Otri.Lnext使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类TriangleNet.Data.Otri
的用法示例。
在下文中一共展示了Otri.Lnext方法的8个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: Flip
/// <summary>
/// Transform two triangles to two different triangles by flipping an edge
/// counterclockwise within a quadrilateral.
/// </summary>
/// <param name="flipedge">Handle to the edge that will be flipped.</param>
/// <remarks>Imagine the original triangles, abc and bad, oriented so that the
/// shared edge ab lies in a horizontal plane, with the vertex b on the left
/// and the vertex a on the right. The vertex c lies below the edge, and
/// the vertex d lies above the edge. The 'flipedge' handle holds the edge
/// ab of triangle abc, and is directed left, from vertex a to vertex b.
///
/// The triangles abc and bad are deleted and replaced by the triangles cdb
/// and dca. The triangles that represent abc and bad are NOT deallocated;
/// they are reused for dca and cdb, respectively. Hence, any handles that
/// may have held the original triangles are still valid, although not
/// directed as they were before.
///
/// Upon completion of this routine, the 'flipedge' handle holds the edge
/// dc of triangle dca, and is directed down, from vertex d to vertex c.
/// (Hence, the two triangles have rotated counterclockwise.)
///
/// WARNING: This transformation is geometrically valid only if the
/// quadrilateral adbc is convex. Furthermore, this transformation is
/// valid only if there is not a subsegment between the triangles abc and
/// bad. This routine does not check either of these preconditions, and
/// it is the responsibility of the calling routine to ensure that they are
/// met. If they are not, the streets shall be filled with wailing and
/// gnashing of teeth.
///
/// Terminology
///
/// A "local transformation" replaces a small set of triangles with another
/// set of triangles. This may or may not involve inserting or deleting a
/// vertex.
///
/// The term "casing" is used to describe the set of triangles that are
/// attached to the triangles being transformed, but are not transformed
/// themselves. Think of the casing as a fixed hollow structure inside
/// which all the action happens. A "casing" is only defined relative to
/// a single transformation; each occurrence of a transformation will
/// involve a different casing.
/// </remarks>
internal void Flip(ref Otri flipedge)
{
Otri botleft = default(Otri), botright = default(Otri);
Otri topleft = default(Otri), topright = default(Otri);
Otri top = default(Otri);
Otri botlcasing = default(Otri), botrcasing = default(Otri);
Otri toplcasing = default(Otri), toprcasing = default(Otri);
Osub botlsubseg = default(Osub), botrsubseg = default(Osub);
Osub toplsubseg = default(Osub), toprsubseg = default(Osub);
Vertex leftvertex, rightvertex, botvertex;
Vertex farvertex;
// Identify the vertices of the quadrilateral.
rightvertex = flipedge.Org();
leftvertex = flipedge.Dest();
botvertex = flipedge.Apex();
flipedge.Sym(ref top);
// SELF CHECK
//if (top.triangle == dummytri)
//{
// logger.Error("Attempt to flip on boundary.", "Mesh.Flip()");
// flipedge.LnextSelf();
// return;
//}
//if (checksegments)
//{
// flipedge.SegPivot(ref toplsubseg);
// if (toplsubseg.ss != dummysub)
// {
// logger.Error("Attempt to flip a segment.", "Mesh.Flip()");
// flipedge.LnextSelf();
// return;
// }
//}
farvertex = top.Apex();
// Identify the casing of the quadrilateral.
top.Lprev(ref topleft);
topleft.Sym(ref toplcasing);
top.Lnext(ref topright);
topright.Sym(ref toprcasing);
flipedge.Lnext(ref botleft);
botleft.Sym(ref botlcasing);
flipedge.Lprev(ref botright);
botright.Sym(ref botrcasing);
// Rotate the quadrilateral one-quarter turn counterclockwise.
topleft.Bond(ref botlcasing);
botleft.Bond(ref botrcasing);
botright.Bond(ref toprcasing);
topright.Bond(ref toplcasing);
if (checksegments)
{
// Check for subsegments and rebond them to the quadrilateral.
//.........这里部分代码省略.........
示例2: DelaunayFixup
/// <summary>
/// Enforce the Delaunay condition at an edge, fanning out recursively from
/// an existing vertex. Pay special attention to stacking inverted triangles.
/// </summary>
/// <param name="fixuptri"></param>
/// <param name="leftside">Indicates whether or not fixuptri is to the left of
/// the segment being inserted. (Imagine that the segment is pointing up from
/// endpoint1 to endpoint2.)</param>
/// <remarks>
/// This is a support routine for inserting segments into a constrained
/// Delaunay triangulation.
///
/// The origin of fixuptri is treated as if it has just been inserted, and
/// the local Delaunay condition needs to be enforced. It is only enforced
/// in one sector, however, that being the angular range defined by
/// fixuptri.
///
/// This routine also needs to make decisions regarding the "stacking" of
/// triangles. (Read the description of ConstrainedEdge() below before
/// reading on here, so you understand the algorithm.) If the position of
/// the new vertex (the origin of fixuptri) indicates that the vertex before
/// it on the polygon is a reflex vertex, then "stack" the triangle by
/// doing nothing. (fixuptri is an inverted triangle, which is how stacked
/// triangles are identified.)
///
/// Otherwise, check whether the vertex before that was a reflex vertex.
/// If so, perform an edge flip, thereby eliminating an inverted triangle
/// (popping it off the stack). The edge flip may result in the creation
/// of a new inverted triangle, depending on whether or not the new vertex
/// is visible to the vertex three edges behind on the polygon.
///
/// If neither of the two vertices behind the new vertex are reflex
/// vertices, fixuptri and fartri, the triangle opposite it, are not
/// inverted; hence, ensure that the edge between them is locally Delaunay.
/// </remarks>
private void DelaunayFixup(ref Otri fixuptri, bool leftside)
{
Otri neartri = default(Otri);
Otri fartri = default(Otri);
Osub faredge = default(Osub);
Vertex nearvertex, leftvertex, rightvertex, farvertex;
fixuptri.Lnext(ref neartri);
neartri.Sym(ref fartri);
// Check if the edge opposite the origin of fixuptri can be flipped.
if (fartri.triangle == Mesh.dummytri)
{
return;
}
neartri.SegPivot(ref faredge);
if (faredge.seg != Mesh.dummysub)
{
return;
}
// Find all the relevant vertices.
nearvertex = neartri.Apex();
leftvertex = neartri.Org();
rightvertex = neartri.Dest();
farvertex = fartri.Apex();
// Check whether the previous polygon vertex is a reflex vertex.
if (leftside)
{
if (Primitives.CounterClockwise(nearvertex, leftvertex, farvertex) <= 0.0)
{
// leftvertex is a reflex vertex too. Nothing can
// be done until a convex section is found.
return;
}
}
else
{
if (Primitives.CounterClockwise(farvertex, rightvertex, nearvertex) <= 0.0)
{
// rightvertex is a reflex vertex too. Nothing can
// be done until a convex section is found.
return;
}
}
if (Primitives.CounterClockwise(rightvertex, leftvertex, farvertex) > 0.0)
{
// fartri is not an inverted triangle, and farvertex is not a reflex
// vertex. As there are no reflex vertices, fixuptri isn't an
// inverted triangle, either. Hence, test the edge between the
// triangles to ensure it is locally Delaunay.
if (Primitives.InCircle(leftvertex, farvertex, rightvertex, nearvertex) <= 0.0)
{
return;
}
// Not locally Delaunay; go on to an edge flip.
}
// else fartri is inverted; remove it from the stack by flipping.
Flip(ref neartri);
fixuptri.LprevSelf(); // Restore the origin of fixuptri after the flip.
// Recursively process the two triangles that result from the flip.
DelaunayFixup(ref fixuptri, leftside);
DelaunayFixup(ref fartri, leftside);
}
示例3: ScoutSegment
/// <summary>
/// Scout the first triangle on the path from one endpoint to another, and check
/// for completion (reaching the second endpoint), a collinear vertex, or the
/// intersection of two segments.
/// </summary>
/// <param name="searchtri"></param>
/// <param name="endpoint2"></param>
/// <param name="newmark"></param>
/// <returns>Returns true if the entire segment is successfully inserted, and false
/// if the job must be finished by ConstrainedEdge().</returns>
/// <remarks>
/// If the first triangle on the path has the second endpoint as its
/// destination or apex, a subsegment is inserted and the job is done.
///
/// If the first triangle on the path has a destination or apex that lies on
/// the segment, a subsegment is inserted connecting the first endpoint to
/// the collinear vertex, and the search is continued from the collinear
/// vertex.
///
/// If the first triangle on the path has a subsegment opposite its origin,
/// then there is a segment that intersects the segment being inserted.
/// Their intersection vertex is inserted, splitting the subsegment.
/// </remarks>
private bool ScoutSegment(ref Otri searchtri, Vertex endpoint2, int newmark)
{
Otri crosstri = default(Otri);
Osub crosssubseg = default(Osub);
Vertex leftvertex, rightvertex;
FindDirectionResult collinear;
collinear = FindDirection(ref searchtri, endpoint2);
rightvertex = searchtri.Dest();
leftvertex = searchtri.Apex();
if (((leftvertex.x == endpoint2.x) && (leftvertex.y == endpoint2.y)) ||
((rightvertex.x == endpoint2.x) && (rightvertex.y == endpoint2.y)))
{
// The segment is already an edge in the mesh.
if ((leftvertex.x == endpoint2.x) && (leftvertex.y == endpoint2.y))
{
searchtri.LprevSelf();
}
// Insert a subsegment, if there isn't already one there.
InsertSubseg(ref searchtri, newmark);
return true;
}
else if (collinear == FindDirectionResult.Leftcollinear)
{
// We've collided with a vertex between the segment's endpoints.
// Make the collinear vertex be the triangle's origin.
searchtri.LprevSelf();
InsertSubseg(ref searchtri, newmark);
// Insert the remainder of the segment.
return ScoutSegment(ref searchtri, endpoint2, newmark);
}
else if (collinear == FindDirectionResult.Rightcollinear)
{
// We've collided with a vertex between the segment's endpoints.
InsertSubseg(ref searchtri, newmark);
// Make the collinear vertex be the triangle's origin.
searchtri.LnextSelf();
// Insert the remainder of the segment.
return ScoutSegment(ref searchtri, endpoint2, newmark);
}
else
{
searchtri.Lnext(ref crosstri);
crosstri.SegPivot(ref crosssubseg);
// Check for a crossing segment.
if (crosssubseg.seg == Mesh.dummysub)
{
return false;
}
else
{
// Insert a vertex at the intersection.
SegmentIntersection(ref crosstri, ref crosssubseg, endpoint2);
crosstri.Copy(ref searchtri);
InsertSubseg(ref searchtri, newmark);
// Insert the remainder of the segment.
return ScoutSegment(ref searchtri, endpoint2, newmark);
}
}
}
示例4: ConstrainedEdge
/// <summary>
/// Force a segment into a constrained Delaunay triangulation by deleting the
/// triangles it intersects, and triangulating the polygons that form on each
/// side of it.
/// </summary>
/// <param name="starttri"></param>
/// <param name="endpoint2"></param>
/// <param name="newmark"></param>
/// <remarks>
/// Generates a single subsegment connecting 'endpoint1' to 'endpoint2'.
/// The triangle 'starttri' has 'endpoint1' as its origin. 'newmark' is the
/// boundary marker of the segment.
///
/// To insert a segment, every triangle whose interior intersects the
/// segment is deleted. The union of these deleted triangles is a polygon
/// (which is not necessarily monotone, but is close enough), which is
/// divided into two polygons by the new segment. This routine's task is
/// to generate the Delaunay triangulation of these two polygons.
///
/// You might think of this routine's behavior as a two-step process. The
/// first step is to walk from endpoint1 to endpoint2, flipping each edge
/// encountered. This step creates a fan of edges connected to endpoint1,
/// including the desired edge to endpoint2. The second step enforces the
/// Delaunay condition on each side of the segment in an incremental manner:
/// proceeding along the polygon from endpoint1 to endpoint2 (this is done
/// independently on each side of the segment), each vertex is "enforced"
/// as if it had just been inserted, but affecting only the previous
/// vertices. The result is the same as if the vertices had been inserted
/// in the order they appear on the polygon, so the result is Delaunay.
///
/// In truth, ConstrainedEdge() interleaves these two steps. The procedure
/// walks from endpoint1 to endpoint2, and each time an edge is encountered
/// and flipped, the newly exposed vertex (at the far end of the flipped
/// edge) is "enforced" upon the previously flipped edges, usually affecting
/// only one side of the polygon (depending upon which side of the segment
/// the vertex falls on).
///
/// The algorithm is complicated by the need to handle polygons that are not
/// convex. Although the polygon is not necessarily monotone, it can be
/// triangulated in a manner similar to the stack-based algorithms for
/// monotone polygons. For each reflex vertex (local concavity) of the
/// polygon, there will be an inverted triangle formed by one of the edge
/// flips. (An inverted triangle is one with negative area - that is, its
/// vertices are arranged in clockwise order - and is best thought of as a
/// wrinkle in the fabric of the mesh.) Each inverted triangle can be
/// thought of as a reflex vertex pushed on the stack, waiting to be fixed
/// later.
///
/// A reflex vertex is popped from the stack when a vertex is inserted that
/// is visible to the reflex vertex. (However, if the vertex behind the
/// reflex vertex is not visible to the reflex vertex, a new inverted
/// triangle will take its place on the stack.) These details are handled
/// by the DelaunayFixup() routine above.
/// </remarks>
private void ConstrainedEdge(ref Otri starttri, Vertex endpoint2, int newmark)
{
Otri fixuptri = default(Otri), fixuptri2 = default(Otri);
Osub crosssubseg = default(Osub);
Vertex endpoint1;
Vertex farvertex;
double area;
bool collision;
bool done;
endpoint1 = starttri.Org();
starttri.Lnext(ref fixuptri);
Flip(ref fixuptri);
// 'collision' indicates whether we have found a vertex directly
// between endpoint1 and endpoint2.
collision = false;
done = false;
do
{
farvertex = fixuptri.Org();
// 'farvertex' is the extreme point of the polygon we are "digging"
// to get from endpoint1 to endpoint2.
if ((farvertex.x == endpoint2.x) && (farvertex.y == endpoint2.y))
{
fixuptri.Oprev(ref fixuptri2);
// Enforce the Delaunay condition around endpoint2.
DelaunayFixup(ref fixuptri, false);
DelaunayFixup(ref fixuptri2, true);
done = true;
}
else
{
// Check whether farvertex is to the left or right of the segment being
// inserted, to decide which edge of fixuptri to dig through next.
area = Primitives.CounterClockwise(endpoint1, endpoint2, farvertex);
if (area == 0.0)
{
// We've collided with a vertex between endpoint1 and endpoint2.
collision = true;
fixuptri.Oprev(ref fixuptri2);
// Enforce the Delaunay condition around farvertex.
DelaunayFixup(ref fixuptri, false);
DelaunayFixup(ref fixuptri2, true);
done = true;
}
else
//.........这里部分代码省略.........
示例5: Unflip
/// <summary>
/// Transform two triangles to two different triangles by flipping an edge
/// clockwise within a quadrilateral. Reverses the flip() operation so that
/// the data structures representing the triangles are back where they were
/// before the flip().
/// </summary>
/// <param name="flipedge"></param>
/// <remarks>
/// See above Flip() remarks for more information.
///
/// Upon completion of this routine, the 'flipedge' handle holds the edge
/// cd of triangle cdb, and is directed up, from vertex c to vertex d.
/// (Hence, the two triangles have rotated clockwise.)
/// </remarks>
internal void Unflip(ref Otri flipedge)
{
Otri botleft = default(Otri), botright = default(Otri);
Otri topleft = default(Otri), topright = default(Otri);
Otri top = default(Otri);
Otri botlcasing = default(Otri), botrcasing = default(Otri);
Otri toplcasing = default(Otri), toprcasing = default(Otri);
Osub botlsubseg = default(Osub), botrsubseg = default(Osub);
Osub toplsubseg = default(Osub), toprsubseg = default(Osub);
Vertex leftvertex, rightvertex, botvertex;
Vertex farvertex;
// Identify the vertices of the quadrilateral.
rightvertex = flipedge.Org();
leftvertex = flipedge.Dest();
botvertex = flipedge.Apex();
flipedge.Sym(ref top);
farvertex = top.Apex();
// Identify the casing of the quadrilateral.
top.Lprev(ref topleft);
topleft.Sym(ref toplcasing);
top.Lnext(ref topright);
topright.Sym(ref toprcasing);
flipedge.Lnext(ref botleft);
botleft.Sym(ref botlcasing);
flipedge.Lprev(ref botright);
botright.Sym(ref botrcasing);
// Rotate the quadrilateral one-quarter turn clockwise.
topleft.Bond(ref toprcasing);
botleft.Bond(ref toplcasing);
botright.Bond(ref botlcasing);
topright.Bond(ref botrcasing);
if (checksegments)
{
// Check for subsegments and rebond them to the quadrilateral.
topleft.SegPivot(ref toplsubseg);
botleft.SegPivot(ref botlsubseg);
botright.SegPivot(ref botrsubseg);
topright.SegPivot(ref toprsubseg);
if (toplsubseg.seg == Mesh.dummysub)
{
botleft.SegDissolve();
}
else
{
botleft.SegBond(ref toplsubseg);
}
if (botlsubseg.seg == Mesh.dummysub)
{
botright.SegDissolve();
}
else
{
botright.SegBond(ref botlsubseg);
}
if (botrsubseg.seg == Mesh.dummysub)
{
topright.SegDissolve();
}
else
{
topright.SegBond(ref botrsubseg);
}
if (toprsubseg.seg == Mesh.dummysub)
{
topleft.SegDissolve();
}
else
{
topleft.SegBond(ref toprsubseg);
}
}
// New vertex assignments for the rotated quadrilateral.
flipedge.SetOrg(botvertex);
flipedge.SetDest(farvertex);
flipedge.SetApex(leftvertex);
top.SetOrg(farvertex);
top.SetDest(botvertex);
top.SetApex(rightvertex);
}
示例6: PreciseLocate
//.........这里部分代码省略.........
Vertex forg, fdest, fapex;
float orgorient, destorient;
bool moveleft;
// Where are we?
forg = searchtri.Org();
fdest = searchtri.Dest();
fapex = searchtri.Apex();
while (true)
{
// Check whether the apex is the point we seek.
if ((fapex.x == searchpoint.X) && (fapex.y == searchpoint.Y))
{
searchtri.LprevSelf();
return LocateResult.OnVertex;
}
// Does the point lie on the other side of the line defined by the
// triangle edge opposite the triangle's destination?
destorient = Primitives.CounterClockwise(forg, fapex, searchpoint);
// Does the point lie on the other side of the line defined by the
// triangle edge opposite the triangle's origin?
orgorient = Primitives.CounterClockwise(fapex, fdest, searchpoint);
if (destorient > 0.0)
{
if (orgorient > 0.0)
{
// Move left if the inner product of (fapex - searchpoint) and
// (fdest - forg) is positive. This is equivalent to drawing
// a line perpendicular to the line (forg, fdest) and passing
// through 'fapex', and determining which side of this line
// 'searchpoint' falls on.
moveleft = (fapex.x - searchpoint.X) * (fdest.x - forg.x) +
(fapex.y - searchpoint.Y) * (fdest.y - forg.y) > 0.0;
}
else
{
moveleft = true;
}
}
else
{
if (orgorient > 0.0)
{
moveleft = false;
}
else
{
// The point we seek must be on the boundary of or inside this
// triangle.
if (destorient == 0.0)
{
searchtri.LprevSelf();
return LocateResult.OnEdge;
}
if (orgorient == 0.0)
{
searchtri.LnextSelf();
return LocateResult.OnEdge;
}
return LocateResult.InTriangle;
}
}
// Move to another triangle. Leave a trace 'backtracktri' in case
// floating-point roundoff or some such bogey causes us to walk
// off a boundary of the triangulation.
if (moveleft)
{
searchtri.Lprev(ref backtracktri);
fdest = fapex;
}
else
{
searchtri.Lnext(ref backtracktri);
forg = fapex;
}
backtracktri.Sym(ref searchtri);
if (mesh.checksegments && stopatsubsegment)
{
// Check for walking through a subsegment.
backtracktri.SegPivot(ref checkedge);
if (checkedge.seg != Mesh.dummysub)
{
// Go back to the last triangle.
backtracktri.Copy(ref searchtri);
return LocateResult.Outside;
}
}
// Check for walking right out of the triangulation.
if (searchtri.triangle == Mesh.dummytri)
{
// Go back to the last triangle.
backtracktri.Copy(ref searchtri);
return LocateResult.Outside;
}
fapex = searchtri.Apex();
}
}
示例7: DivconqRecurse
/// <summary>
/// Recursively form a Delaunay triangulation by the divide-and-conquer method.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <param name="axis"></param>
/// <param name="farleft"></param>
/// <param name="farright"></param>
/// <remarks>
/// Recursively breaks down the problem into smaller pieces, which are
/// knitted together by mergehulls(). The base cases (problems of two or
/// three vertices) are handled specially here.
///
/// On completion, 'farleft' and 'farright' are bounding triangles such that
/// the origin of 'farleft' is the leftmost vertex (breaking ties by
/// choosing the highest leftmost vertex), and the destination of
/// 'farright' is the rightmost vertex (breaking ties by choosing the
/// lowest rightmost vertex).
/// </remarks>
void DivconqRecurse(int left, int right, int axis,
ref Otri farleft, ref Otri farright)
{
Otri midtri = default(Otri);
Otri tri1 = default(Otri);
Otri tri2 = default(Otri);
Otri tri3 = default(Otri);
Otri innerleft = default(Otri), innerright = default(Otri);
double area;
int vertices = right - left + 1;
int divider;
if (vertices == 2)
{
// The triangulation of two vertices is an edge. An edge is
// represented by two bounding triangles.
mesh.MakeTriangle(ref farleft);
farleft.SetOrg(sortarray[left]);
farleft.SetDest(sortarray[left + 1]);
// The apex is intentionally left NULL.
mesh.MakeTriangle(ref farright);
farright.SetOrg(sortarray[left + 1]);
farright.SetDest(sortarray[left]);
// The apex is intentionally left NULL.
farleft.Bond(ref farright);
farleft.LprevSelf();
farright.LnextSelf();
farleft.Bond(ref farright);
farleft.LprevSelf();
farright.LnextSelf();
farleft.Bond(ref farright);
// Ensure that the origin of 'farleft' is sortarray[0].
farright.Lprev(ref farleft);
return;
}
else if (vertices == 3)
{
// The triangulation of three vertices is either a triangle (with
// three bounding triangles) or two edges (with four bounding
// triangles). In either case, four triangles are created.
mesh.MakeTriangle(ref midtri);
mesh.MakeTriangle(ref tri1);
mesh.MakeTriangle(ref tri2);
mesh.MakeTriangle(ref tri3);
area = Primitives.CounterClockwise(sortarray[left], sortarray[left + 1], sortarray[left + 2]);
if (area == 0.0)
{
// Three collinear vertices; the triangulation is two edges.
midtri.SetOrg(sortarray[left]);
midtri.SetDest(sortarray[left + 1]);
tri1.SetOrg(sortarray[left + 1]);
tri1.SetDest(sortarray[left]);
tri2.SetOrg(sortarray[left + 2]);
tri2.SetDest(sortarray[left + 1]);
tri3.SetOrg(sortarray[left + 1]);
tri3.SetDest(sortarray[left + 2]);
// All apices are intentionally left NULL.
midtri.Bond(ref tri1);
tri2.Bond(ref tri3);
midtri.LnextSelf();
tri1.LprevSelf();
tri2.LnextSelf();
tri3.LprevSelf();
midtri.Bond(ref tri3);
tri1.Bond(ref tri2);
midtri.LnextSelf();
tri1.LprevSelf();
tri2.LnextSelf();
tri3.LprevSelf();
midtri.Bond(ref tri1);
tri2.Bond(ref tri3);
// Ensure that the origin of 'farleft' is sortarray[0].
tri1.Copy(ref farleft);
// Ensure that the destination of 'farright' is sortarray[2].
tri2.Copy(ref farright);
}
else
{
// The three vertices are not collinear; the triangulation is one
// triangle, namely 'midtri'.
//.........这里部分代码省略.........
示例8: TestTriangle
/// <summary>
/// Test a triangle for quality and size.
/// </summary>
/// <param name="testtri">Triangle to check.</param>
/// <remarks>
/// Tests a triangle to see if it satisfies the minimum angle condition and
/// the maximum area condition. Triangles that aren't up to spec are added
/// to the bad triangle queue.
/// </remarks>
public void TestTriangle(ref Otri testtri)
{
Otri tri1 = default(Otri), tri2 = default(Otri);
Osub testsub = default(Osub);
Vertex torg, tdest, tapex;
Vertex base1, base2;
Vertex org1, dest1, org2, dest2;
Vertex joinvertex;
double dxod, dyod, dxda, dyda, dxao, dyao;
double dxod2, dyod2, dxda2, dyda2, dxao2, dyao2;
double apexlen, orglen, destlen, minedge;
double angle;
double area;
double dist1, dist2;
double maxangle;
torg = testtri.Org();
tdest = testtri.Dest();
tapex = testtri.Apex();
dxod = torg.x - tdest.x;
dyod = torg.y - tdest.y;
dxda = tdest.x - tapex.x;
dyda = tdest.y - tapex.y;
dxao = tapex.x - torg.x;
dyao = tapex.y - torg.y;
dxod2 = dxod * dxod;
dyod2 = dyod * dyod;
dxda2 = dxda * dxda;
dyda2 = dyda * dyda;
dxao2 = dxao * dxao;
dyao2 = dyao * dyao;
// Find the lengths of the triangle's three edges.
apexlen = dxod2 + dyod2;
orglen = dxda2 + dyda2;
destlen = dxao2 + dyao2;
if ((apexlen < orglen) && (apexlen < destlen))
{
// The edge opposite the apex is shortest.
minedge = apexlen;
// Find the square of the cosine of the angle at the apex.
angle = dxda * dxao + dyda * dyao;
angle = angle * angle / (orglen * destlen);
base1 = torg;
base2 = tdest;
testtri.Copy(ref tri1);
}
else if (orglen < destlen)
{
// The edge opposite the origin is shortest.
minedge = orglen;
// Find the square of the cosine of the angle at the origin.
angle = dxod * dxao + dyod * dyao;
angle = angle * angle / (apexlen * destlen);
base1 = tdest;
base2 = tapex;
testtri.Lnext(ref tri1);
}
else
{
// The edge opposite the destination is shortest.
minedge = destlen;
// Find the square of the cosine of the angle at the destination.
angle = dxod * dxda + dyod * dyda;
angle = angle * angle / (apexlen * orglen);
base1 = tapex;
base2 = torg;
testtri.Lprev(ref tri1);
}
if (behavior.VarArea || behavior.fixedArea || behavior.Usertest)
{
// Check whether the area is larger than permitted.
area = 0.5 * (dxod * dyda - dyod * dxda);
if (behavior.fixedArea && (area > behavior.MaxArea))
{
// Add this triangle to the list of bad triangles.
queue.Enqueue(ref testtri, minedge, tapex, torg, tdest);
return;
}
// Nonpositive area constraints are treated as unconstrained.
if ((behavior.VarArea) && (area > testtri.triangle.area) && (testtri.triangle.area > 0.0))
{
// Add this triangle to the list of bad triangles.
queue.Enqueue(ref testtri, minedge, tapex, torg, tdest);
return;
}
// Check whether the user thinks this triangle is too large.
//.........这里部分代码省略.........