本文整理汇总了C#中TriangleNet.Data.Otri.Apex方法的典型用法代码示例。如果您正苦于以下问题:C# Otri.Apex方法的具体用法?C# Otri.Apex怎么用?C# Otri.Apex使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类TriangleNet.Data.Otri
的用法示例。
在下文中一共展示了Otri.Apex方法的11个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的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: RightOfHyperbola
bool RightOfHyperbola(ref Otri fronttri, Point newsite)
{
Vertex leftvertex, rightvertex;
double dxa, dya, dxb, dyb;
Statistic.HyperbolaCount++;
leftvertex = fronttri.Dest();
rightvertex = fronttri.Apex();
if ((leftvertex.y < rightvertex.y) ||
((leftvertex.y == rightvertex.y) &&
(leftvertex.x < rightvertex.x)))
{
if (newsite.x >= rightvertex.x)
{
return true;
}
}
else
{
if (newsite.x <= leftvertex.x)
{
return false;
}
}
dxa = leftvertex.x - newsite.x;
dya = leftvertex.y - newsite.y;
dxb = rightvertex.x - newsite.x;
dyb = rightvertex.y - newsite.y;
return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya);
}
示例3: SegmentIntersection
/// <summary>
/// Find the intersection of an existing segment and a segment that is being
/// inserted. Insert a vertex at the intersection, splitting an existing subsegment.
/// </summary>
/// <param name="splittri"></param>
/// <param name="splitsubseg"></param>
/// <param name="endpoint2"></param>
/// <remarks>
/// The segment being inserted connects the apex of splittri to endpoint2.
/// splitsubseg is the subsegment being split, and MUST adjoin splittri.
/// Hence, endpoints of the subsegment being split are the origin and
/// destination of splittri.
///
/// On completion, splittri is a handle having the newly inserted
/// intersection point as its origin, and endpoint1 as its destination.
/// </remarks>
private void SegmentIntersection(ref Otri splittri, ref Osub splitsubseg, Vertex endpoint2)
{
Osub opposubseg = default(Osub);
Vertex endpoint1;
Vertex torg, tdest;
Vertex leftvertex, rightvertex;
Vertex newvertex;
InsertVertexResult success;
double ex, ey;
double tx, ty;
double etx, ety;
double split, denom;
// Find the other three segment endpoints.
endpoint1 = splittri.Apex();
torg = splittri.Org();
tdest = splittri.Dest();
// Segment intersection formulae; see the Antonio reference.
tx = tdest.x - torg.x;
ty = tdest.y - torg.y;
ex = endpoint2.x - endpoint1.x;
ey = endpoint2.y - endpoint1.y;
etx = torg.x - endpoint2.x;
ety = torg.y - endpoint2.y;
denom = ty * ex - tx * ey;
if (denom == 0.0)
{
logger.Error("Attempt to find intersection of parallel segments.",
"Mesh.SegmentIntersection()");
throw new Exception("Attempt to find intersection of parallel segments.");
}
split = (ey * etx - ex * ety) / denom;
// Create the new vertex.
newvertex = new Vertex(
torg.x + split * (tdest.x - torg.x),
torg.y + split * (tdest.y - torg.y),
splitsubseg.seg.boundary,
this.nextras);
newvertex.hash = this.hash_vtx++;
newvertex.id = newvertex.hash;
// Interpolate its attributes.
for (int i = 0; i < nextras; i++)
{
newvertex.attributes[i] = torg.attributes[i] + split * (tdest.attributes[i] - torg.attributes[i]);
}
vertices.Add(newvertex.hash, newvertex);
// Insert the intersection vertex. This should always succeed.
success = InsertVertex(newvertex, ref splittri, ref splitsubseg, false, false);
if (success != InsertVertexResult.Successful)
{
logger.Error("Failure to split a segment.", "Mesh.SegmentIntersection()");
throw new Exception("Failure to split a segment.");
}
// Record a triangle whose origin is the new vertex.
newvertex.tri = splittri;
if (steinerleft > 0)
{
steinerleft--;
}
// Divide the segment into two, and correct the segment endpoints.
splitsubseg.SymSelf();
splitsubseg.Pivot(ref opposubseg);
splitsubseg.Dissolve();
opposubseg.Dissolve();
do
{
splitsubseg.SetSegOrg(newvertex);
splitsubseg.NextSelf();
} while (splitsubseg.seg != Mesh.dummysub);
do
{
opposubseg.SetSegOrg(newvertex);
opposubseg.NextSelf();
} while (opposubseg.seg != Mesh.dummysub);
// Inserting the vertex may have caused edge flips. We wish to rediscover
// the edge connecting endpoint1 to the new intersection vertex.
//.........这里部分代码省略.........
示例4: TriangulatePolygon
/// <summary>
/// Find the Delaunay triangulation of a polygon that has a certain "nice" shape.
/// This includes the polygons that result from deletion of a vertex or insertion
/// of a segment.
/// </summary>
/// <param name="firstedge">The primary edge of the first triangle.</param>
/// <param name="lastedge">The primary edge of the last triangle.</param>
/// <param name="edgecount">The number of sides of the polygon, including its
/// base.</param>
/// <param name="doflip">A flag, wether to perform the last flip.</param>
/// <param name="triflaws">A flag that determines whether the new triangles should
/// be tested for quality, and enqueued if they are bad.</param>
/// <remarks>
// This is a conceptually difficult routine. The starting assumption is
// that we have a polygon with n sides. n - 1 of these sides are currently
// represented as edges in the mesh. One side, called the "base", need not
// be.
//
// Inside the polygon is a structure I call a "fan", consisting of n - 1
// triangles that share a common origin. For each of these triangles, the
// edge opposite the origin is one of the sides of the polygon. The
// primary edge of each triangle is the edge directed from the origin to
// the destination; note that this is not the same edge that is a side of
// the polygon. 'firstedge' is the primary edge of the first triangle.
// From there, the triangles follow in counterclockwise order about the
// polygon, until 'lastedge', the primary edge of the last triangle.
// 'firstedge' and 'lastedge' are probably connected to other triangles
// beyond the extremes of the fan, but their identity is not important, as
// long as the fan remains connected to them.
//
// Imagine the polygon oriented so that its base is at the bottom. This
// puts 'firstedge' on the far right, and 'lastedge' on the far left.
// The right vertex of the base is the destination of 'firstedge', and the
// left vertex of the base is the apex of 'lastedge'.
//
// The challenge now is to find the right sequence of edge flips to
// transform the fan into a Delaunay triangulation of the polygon. Each
// edge flip effectively removes one triangle from the fan, committing it
// to the polygon. The resulting polygon has one fewer edge. If 'doflip'
// is set, the final flip will be performed, resulting in a fan of one
// (useless?) triangle. If 'doflip' is not set, the final flip is not
// performed, resulting in a fan of two triangles, and an unfinished
// triangular polygon that is not yet filled out with a single triangle.
// On completion of the routine, 'lastedge' is the last remaining triangle,
// or the leftmost of the last two.
//
// Although the flips are performed in the order described above, the
// decisions about what flips to perform are made in precisely the reverse
// order. The recursive triangulatepolygon() procedure makes a decision,
// uses up to two recursive calls to triangulate the "subproblems"
// (polygons with fewer edges), and then performs an edge flip.
//
// The "decision" it makes is which vertex of the polygon should be
// connected to the base. This decision is made by testing every possible
// vertex. Once the best vertex is found, the two edges that connect this
// vertex to the base become the bases for two smaller polygons. These
// are triangulated recursively. Unfortunately, this approach can take
// O(n^2) time not only in the worst case, but in many common cases. It's
// rarely a big deal for vertex deletion, where n is rarely larger than
// ten, but it could be a big deal for segment insertion, especially if
// there's a lot of long segments that each cut many triangles. I ought to
// code a faster algorithm some day.
/// </remarks>
private void TriangulatePolygon(Otri firstedge, Otri lastedge,
int edgecount, bool doflip, bool triflaws)
{
Otri testtri = default(Otri);
Otri besttri = default(Otri);
Otri tempedge = default(Otri);
Vertex leftbasevertex, rightbasevertex;
Vertex testvertex;
Vertex bestvertex;
int bestnumber = 1;
// Identify the base vertices.
leftbasevertex = lastedge.Apex();
rightbasevertex = firstedge.Dest();
// Find the best vertex to connect the base to.
firstedge.Onext(ref besttri);
bestvertex = besttri.Dest();
besttri.Copy(ref testtri);
for (int i = 2; i <= edgecount - 2; i++)
{
testtri.OnextSelf();
testvertex = testtri.Dest();
// Is this a better vertex?
if (Primitives.InCircle(leftbasevertex, rightbasevertex, bestvertex, testvertex) > 0.0)
{
testtri.Copy(ref besttri);
bestvertex = testvertex;
bestnumber = i;
}
}
if (bestnumber > 1)
{
// Recursively triangulate the smaller polygon on the right.
//.........这里部分代码省略.........
示例5: FindDirection
/// <summary>
/// Find the first triangle on the path from one point to another.
/// </summary>
/// <param name="searchtri"></param>
/// <param name="searchpoint"></param>
/// <returns>
/// The return value notes whether the destination or apex of the found
/// triangle is collinear with the two points in question.</returns>
/// <remarks>
/// Finds the triangle that intersects a line segment drawn from the
/// origin of 'searchtri' to the point 'searchpoint', and returns the result
/// in 'searchtri'. The origin of 'searchtri' does not change, even though
/// the triangle returned may differ from the one passed in. This routine
/// is used to find the direction to move in to get from one point to
/// another.
/// </remarks>
private FindDirectionResult FindDirection(ref Otri searchtri, Vertex searchpoint)
{
Otri checktri = default(Otri);
Vertex startvertex;
Vertex leftvertex, rightvertex;
double leftccw, rightccw;
bool leftflag, rightflag;
startvertex = searchtri.Org();
rightvertex = searchtri.Dest();
leftvertex = searchtri.Apex();
// Is 'searchpoint' to the left?
leftccw = Primitives.CounterClockwise(searchpoint, startvertex, leftvertex);
leftflag = leftccw > 0.0;
// Is 'searchpoint' to the right?
rightccw = Primitives.CounterClockwise(startvertex, searchpoint, rightvertex);
rightflag = rightccw > 0.0;
if (leftflag && rightflag)
{
// 'searchtri' faces directly away from 'searchpoint'. We could go left
// or right. Ask whether it's a triangle or a boundary on the left.
searchtri.Onext(ref checktri);
if (checktri.triangle == Mesh.dummytri)
{
leftflag = false;
}
else
{
rightflag = false;
}
}
while (leftflag)
{
// Turn left until satisfied.
searchtri.OnextSelf();
if (searchtri.triangle == Mesh.dummytri)
{
logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().1");
throw new Exception("Unable to find a triangle on path.");
}
leftvertex = searchtri.Apex();
rightccw = leftccw;
leftccw = Primitives.CounterClockwise(searchpoint, startvertex, leftvertex);
leftflag = leftccw > 0.0;
}
while (rightflag)
{
// Turn right until satisfied.
searchtri.OprevSelf();
if (searchtri.triangle == Mesh.dummytri)
{
logger.Error("Unable to find a triangle on path.", "Mesh.FindDirection().2");
throw new Exception("Unable to find a triangle on path.");
}
rightvertex = searchtri.Dest();
leftccw = rightccw;
rightccw = Primitives.CounterClockwise(startvertex, searchpoint, rightvertex);
rightflag = rightccw > 0.0;
}
if (leftccw == 0.0)
{
return FindDirectionResult.Leftcollinear;
}
else if (rightccw == 0.0)
{
return FindDirectionResult.Rightcollinear;
}
else
{
return FindDirectionResult.Within;
}
}
示例6: 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);
}
}
}
示例7: 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);
}
示例8: PreciseLocate
/// <summary>
/// Find a triangle or edge containing a given point.
/// </summary>
/// <param name="searchpoint">The point to locate.</param>
/// <param name="searchtri">The triangle to start the search at.</param>
/// <param name="stopatsubsegment"> If 'stopatsubsegment' is set, the search
/// will stop if it tries to walk through a subsegment, and will return OUTSIDE.</param>
/// <returns>Location information.</returns>
/// <remarks>
/// Begins its search from 'searchtri'. It is important that 'searchtri'
/// be a handle with the property that 'searchpoint' is strictly to the left
/// of the edge denoted by 'searchtri', or is collinear with that edge and
/// does not intersect that edge. (In particular, 'searchpoint' should not
/// be the origin or destination of that edge.)
///
/// These conditions are imposed because preciselocate() is normally used in
/// one of two situations:
///
/// (1) To try to find the location to insert a new point. Normally, we
/// know an edge that the point is strictly to the left of. In the
/// incremental Delaunay algorithm, that edge is a bounding box edge.
/// In Ruppert's Delaunay refinement algorithm for quality meshing,
/// that edge is the shortest edge of the triangle whose circumcenter
/// is being inserted.
///
/// (2) To try to find an existing point. In this case, any edge on the
/// convex hull is a good starting edge. You must screen out the
/// possibility that the vertex sought is an endpoint of the starting
/// edge before you call preciselocate().
///
/// On completion, 'searchtri' is a triangle that contains 'searchpoint'.
///
/// This implementation differs from that given by Guibas and Stolfi. It
/// walks from triangle to triangle, crossing an edge only if 'searchpoint'
/// is on the other side of the line containing that edge. After entering
/// a triangle, there are two edges by which one can leave that triangle.
/// If both edges are valid ('searchpoint' is on the other side of both
/// edges), one of the two is chosen by drawing a line perpendicular to
/// the entry edge (whose endpoints are 'forg' and 'fdest') passing through
/// 'fapex'. Depending on which side of this perpendicular 'searchpoint'
/// falls on, an exit edge is chosen.
///
/// This implementation is empirically faster than the Guibas and Stolfi
/// point location routine (which I originally used), which tends to spiral
/// in toward its target.
///
/// Returns ONVERTEX if the point lies on an existing vertex. 'searchtri'
/// is a handle whose origin is the existing vertex.
///
/// Returns ONEDGE if the point lies on a mesh edge. 'searchtri' is a
/// handle whose primary edge is the edge on which the point lies.
///
/// Returns INTRIANGLE if the point lies strictly within a triangle.
/// 'searchtri' is a handle on the triangle that contains the point.
///
/// Returns OUTSIDE if the point lies outside the mesh. 'searchtri' is a
/// handle whose primary edge the point is to the right of. This might
/// occur when the circumcenter of a triangle falls just slightly outside
/// the mesh due to floating-point roundoff error. It also occurs when
/// seeking a hole or region point that a foolish user has placed outside
/// the mesh.
///
/// WARNING: This routine is designed for convex triangulations, and will
/// not generally work after the holes and concavities have been carved.
/// However, it can still be used to find the circumcenter of a triangle, as
/// long as the search is begun from the triangle in question.</remarks>
public LocateResult PreciseLocate(Point searchpoint, ref Otri searchtri,
bool stopatsubsegment)
{
Otri backtracktri = default(Otri);
Osub checkedge = default(Osub);
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
//.........这里部分代码省略.........
示例9: MergeHulls
/// <summary>
/// Merge two adjacent Delaunay triangulations into a single Delaunay triangulation.
/// </summary>
/// <param name="farleft">Bounding triangles of the left triangulation.</param>
/// <param name="innerleft">Bounding triangles of the left triangulation.</param>
/// <param name="innerright">Bounding triangles of the right triangulation.</param>
/// <param name="farright">Bounding triangles of the right triangulation.</param>
/// <param name="axis"></param>
/// <remarks>
/// This is similar to the algorithm given by Guibas and Stolfi, but uses
/// a triangle-based, rather than edge-based, data structure.
///
/// The algorithm walks up the gap between the two triangulations, knitting
/// them together. As they are merged, some of their bounding triangles
/// are converted into real triangles of the triangulation. The procedure
/// pulls each hull's bounding triangles apart, then knits them together
/// like the teeth of two gears. The Delaunay property determines, at each
/// step, whether the next "tooth" is a bounding triangle of the left hull
/// or the right. When a bounding triangle becomes real, its apex is
/// changed from NULL to a real vertex.
///
/// Only two new triangles need to be allocated. These become new bounding
/// triangles at the top and bottom of the seam. They are used to connect
/// the remaining bounding triangles (those that have not been converted
/// into real triangles) into a single fan.
///
/// On entry, 'farleft' and 'innerleft' are bounding triangles of the left
/// triangulation. The origin of 'farleft' is the leftmost vertex, and
/// the destination of 'innerleft' is the rightmost vertex of the
/// triangulation. Similarly, 'innerright' and 'farright' are bounding
/// triangles of the right triangulation. The origin of 'innerright' and
/// destination of 'farright' are the leftmost and rightmost vertices.
///
/// On completion, the origin of 'farleft' is the leftmost vertex of the
/// merged triangulation, and the destination of 'farright' is the rightmost
/// vertex.
/// </remarks>
void MergeHulls(ref Otri farleft, ref Otri innerleft, ref Otri innerright,
ref Otri farright, int axis)
{
Otri leftcand = default(Otri), rightcand = default(Otri);
Otri nextedge = default(Otri);
Otri sidecasing = default(Otri), topcasing = default(Otri), outercasing = default(Otri);
Otri checkedge = default(Otri);
Otri baseedge = default(Otri);
Vertex innerleftdest;
Vertex innerrightorg;
Vertex innerleftapex, innerrightapex;
Vertex farleftpt, farrightpt;
Vertex farleftapex, farrightapex;
Vertex lowerleft, lowerright;
Vertex upperleft, upperright;
Vertex nextapex;
Vertex checkvertex;
bool changemade;
bool badedge;
bool leftfinished, rightfinished;
innerleftdest = innerleft.Dest();
innerleftapex = innerleft.Apex();
innerrightorg = innerright.Org();
innerrightapex = innerright.Apex();
// Special treatment for horizontal cuts.
if (useDwyer && (axis == 1))
{
farleftpt = farleft.Org();
farleftapex = farleft.Apex();
farrightpt = farright.Dest();
farrightapex = farright.Apex();
// The pointers to the extremal vertices are shifted to point to the
// topmost and bottommost vertex of each hull, rather than the
// leftmost and rightmost vertices.
while (farleftapex.y < farleftpt.y)
{
farleft.LnextSelf();
farleft.SymSelf();
farleftpt = farleftapex;
farleftapex = farleft.Apex();
}
innerleft.Sym(ref checkedge);
checkvertex = checkedge.Apex();
while (checkvertex.y > innerleftdest.y)
{
checkedge.Lnext(ref innerleft);
innerleftapex = innerleftdest;
innerleftdest = checkvertex;
innerleft.Sym(ref checkedge);
checkvertex = checkedge.Apex();
}
while (innerrightapex.y < innerrightorg.y)
{
innerright.LnextSelf();
innerright.SymSelf();
innerrightorg = innerrightapex;
innerrightapex = innerright.Apex();
}
farright.Sym(ref checkedge);
checkvertex = checkedge.Apex();
while (checkvertex.y > farrightpt.y)
{
//.........这里部分代码省略.........
示例10: TriangleIsBlinded
/// <summary>
/// Check if given triangle is blinded by given segment.
/// </summary>
/// <param name="tri">Triangle.</param>
/// <param name="seg">Segments</param>
/// <returns>Returns true, if the triangle is blinded.</returns>
private bool TriangleIsBlinded(ref Otri tri, ref Osub seg)
{
Point c, pt;
Vertex torg = tri.Org();
Vertex tdest = tri.Dest();
Vertex tapex = tri.Apex();
Vertex sorg = seg.Org();
Vertex sdest = seg.Dest();
c = this.points[tri.triangle.id];
if (SegmentsIntersect(sorg, sdest, c, torg, out pt, true))
{
return true;
}
if (SegmentsIntersect(sorg, sdest, c, tdest, out pt, true))
{
return true;
}
if (SegmentsIntersect(sorg, sdest, c, tapex, out pt, true))
{
return true;
}
return false;
}
示例11: 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.
//.........这里部分代码省略.........