mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-13 03:33:48 +00:00
Profile editor for the meshRoad object
credit to Ryan Mounts (RDM) found originally at http://www.garagegames.com/community/forums/viewthread/105391
This commit is contained in:
parent
76c5e30869
commit
973fd44c6a
12 changed files with 2501 additions and 201 deletions
580
Engine/source/math/util/decomposePoly.cpp
Normal file
580
Engine/source/math/util/decomposePoly.cpp
Normal file
|
|
@ -0,0 +1,580 @@
|
|||
#include "math/util/decomposePoly.h"
|
||||
|
||||
// twoIndices Methods
|
||||
|
||||
twoIndices::twoIndices()
|
||||
{
|
||||
i1 = i2 = 0;
|
||||
}
|
||||
|
||||
twoIndices::twoIndices(U8 a, U8 b)
|
||||
{
|
||||
i1 = a;
|
||||
i2 = b;
|
||||
}
|
||||
|
||||
// decompTri Methods
|
||||
|
||||
decompTri::decompTri()
|
||||
{
|
||||
mVertIdx[0] = 0;
|
||||
mVertIdx[1] = 0;
|
||||
mVertIdx[2] = 0;
|
||||
}
|
||||
|
||||
void decompTri::orderVerts()
|
||||
{
|
||||
// Bubble sort, smallest to largest
|
||||
U8 temp;
|
||||
|
||||
for (U8 i = 2; i > 0; i--)
|
||||
{
|
||||
for (U8 j = 0; j < i; j++)
|
||||
{
|
||||
if (mVertIdx[j] > mVertIdx[j + 1])
|
||||
{
|
||||
temp = mVertIdx[j];
|
||||
mVertIdx[j] = mVertIdx[j + 1];
|
||||
mVertIdx[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decompTri::setVert(U8 val, U8 idx)
|
||||
{
|
||||
if(idx < 3)
|
||||
mVertIdx[idx] = val;
|
||||
}
|
||||
|
||||
U8 decompTri::getVert(U8 idx)
|
||||
{
|
||||
if(idx < 3)
|
||||
return mVertIdx[idx];
|
||||
|
||||
return mVertIdx[2];
|
||||
}
|
||||
|
||||
twoIndices decompTri::getOtherVerts(U8 idx)
|
||||
{
|
||||
if(idx == mVertIdx[0])
|
||||
return twoIndices(mVertIdx[1], mVertIdx[2]);
|
||||
|
||||
if(idx == mVertIdx[1])
|
||||
return twoIndices(mVertIdx[0], mVertIdx[2]);
|
||||
|
||||
if(idx == mVertIdx[2])
|
||||
return twoIndices(mVertIdx[0], mVertIdx[1]);
|
||||
|
||||
return twoIndices(0,0);
|
||||
}
|
||||
|
||||
// decompPoly Methods
|
||||
|
||||
void decompPoly::addVert(Point3F &newVert)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for(U8 i = 0; i < mVertList.size(); i++)
|
||||
{
|
||||
if(newVert == mVertList[i])
|
||||
found = true;
|
||||
}
|
||||
|
||||
if(!found)
|
||||
mVertList.push_back(newVert);
|
||||
}
|
||||
|
||||
void decompPoly::initEdgeList()
|
||||
{
|
||||
mEdgeList.clear();
|
||||
|
||||
S32 next = 0;
|
||||
|
||||
for(S32 i = 0; i < mVertList.size(); i++)
|
||||
{
|
||||
if(i == mVertList.size()-1)
|
||||
next = 0;
|
||||
else
|
||||
next = i+1;
|
||||
|
||||
mEdgeList.push_back(twoIndices(i, next));
|
||||
}
|
||||
}
|
||||
|
||||
bool decompPoly::sameSide(Point3F &p1, Point3F &p2, Point3F &l1, Point3F &l2)
|
||||
{
|
||||
return ((p1.x-l1.x)*(l2.y-l1.y)-(l2.x-l1.x)*(p1.y-l1.y))*((p2.x-l1.x)*(l2.y-l1.y)-(l2.x-l1.x)*(p2.y-l1.y)) > 0;
|
||||
}
|
||||
|
||||
bool decompPoly::isInside(decompTri &tri, U8 vertIdx)
|
||||
{
|
||||
Point3F a(mVertList[tri.getVert(0)]);
|
||||
Point3F b(mVertList[tri.getVert(1)]);
|
||||
Point3F c(mVertList[tri.getVert(2)]);
|
||||
Point3F p(mVertList[vertIdx]);
|
||||
|
||||
return (sameSide(p,a,b,c) && sameSide(p,b,a,c) && sameSide(p,c,a,b));
|
||||
}
|
||||
|
||||
U8 decompPoly::leftmost()
|
||||
{
|
||||
F32 xMin = 9999999.f;
|
||||
U8 idx = 0;
|
||||
|
||||
for(U8 i = 0; i < mVertList.size(); i++)
|
||||
{
|
||||
if(mVertList[i].x < xMin && isVertInEdgeList(i))
|
||||
{
|
||||
xMin = mVertList[i].x;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
U8 decompPoly::rightmost()
|
||||
{
|
||||
F32 xMax = -9999999.f;
|
||||
U8 idx = 0;
|
||||
|
||||
for(U8 i = 0; i < mVertList.size(); i++)
|
||||
{
|
||||
if(mVertList[i].x > xMax && isVertInEdgeList(i))
|
||||
{
|
||||
xMax = mVertList[i].x;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
U8 decompPoly::uppermost()
|
||||
{
|
||||
F32 yMax = -9999999.f;
|
||||
U8 idx = 0;
|
||||
|
||||
for(U8 i = 0; i < mVertList.size(); i++)
|
||||
{
|
||||
if(mVertList[i].y > yMax && isVertInEdgeList(i))
|
||||
{
|
||||
yMax = mVertList[i].y;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
U8 decompPoly::lowermost()
|
||||
{
|
||||
F32 yMin = 9999999.f;
|
||||
U8 idx = 0;
|
||||
|
||||
for(U8 i = 0; i < mVertList.size(); i++)
|
||||
{
|
||||
if(mVertList[i].y < yMin && isVertInEdgeList(i))
|
||||
{
|
||||
yMin = mVertList[i].y;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
twoIndices decompPoly::findEdges(U8 vertIdx, bool ¬Unique)
|
||||
{
|
||||
U8 found = 0;
|
||||
U8 edgeIdx[2];
|
||||
|
||||
for(U8 i = 0; i < mEdgeList.size(); i++)
|
||||
{
|
||||
if(mEdgeList[i].i1 == vertIdx || mEdgeList[i].i2 == vertIdx)
|
||||
{
|
||||
edgeIdx[found++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
notUnique = found > 2;
|
||||
|
||||
return twoIndices(edgeIdx[0], edgeIdx[1]);
|
||||
}
|
||||
|
||||
decompTri decompPoly::formTriFromEdges(U8 idx1, U8 idx2)
|
||||
{
|
||||
decompTri tri;
|
||||
|
||||
tri.setVert(mEdgeList[idx1].i1, 0);
|
||||
tri.setVert(mEdgeList[idx1].i2, 1);
|
||||
|
||||
if(mEdgeList[idx2].i1 == tri.getVert(0) || mEdgeList[idx2].i1 == tri.getVert(1))
|
||||
{
|
||||
tri.setVert(mEdgeList[idx2].i2, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
tri.setVert(mEdgeList[idx2].i1, 2);
|
||||
}
|
||||
|
||||
return tri;
|
||||
}
|
||||
|
||||
twoIndices decompPoly::leftmostInsideVerts(U8 idx1, U8 idx2)
|
||||
{
|
||||
F32 xMin = 9999999.f;
|
||||
S32 left[] = {-1, -1};
|
||||
|
||||
for(U8 i = 0; i < 2; i++)
|
||||
{
|
||||
for(U8 j = 0; j < mInsideVerts.size(); j++)
|
||||
{
|
||||
if(mVertList[mInsideVerts[j]].x < xMin && mInsideVerts[j] != left[0])
|
||||
{
|
||||
xMin = mVertList[mInsideVerts[j]].x;
|
||||
left[i] = mInsideVerts[j];
|
||||
}
|
||||
}
|
||||
|
||||
if(mVertList[idx1].x < xMin && idx1 != left[0])
|
||||
{
|
||||
xMin = mVertList[idx1].x;
|
||||
left[i] = idx1;
|
||||
}
|
||||
|
||||
if(mVertList[idx2].x < xMin && idx2 != left[0])
|
||||
{
|
||||
xMin = mVertList[idx2].x;
|
||||
left[i] = idx2;
|
||||
}
|
||||
|
||||
xMin = 9999999.f;
|
||||
}
|
||||
|
||||
return twoIndices(left[0], left[1]);
|
||||
}
|
||||
|
||||
twoIndices decompPoly::rightmostInsideVerts(U8 idx1, U8 idx2)
|
||||
{
|
||||
F32 xMax = -9999999.f;
|
||||
S32 right[] = {-1, -1};
|
||||
|
||||
for(U8 i = 0; i < 2; i++)
|
||||
{
|
||||
for(U8 j = 0; j < mInsideVerts.size(); j++)
|
||||
{
|
||||
if(mVertList[mInsideVerts[j]].x > xMax && mInsideVerts[j] != right[0])
|
||||
{
|
||||
xMax = mVertList[mInsideVerts[j]].x;
|
||||
right[i] = mInsideVerts[j];
|
||||
}
|
||||
}
|
||||
|
||||
if(mVertList[idx1].x > xMax && idx1 != right[0])
|
||||
{
|
||||
xMax = mVertList[idx1].x;
|
||||
right[i] = idx1;
|
||||
}
|
||||
|
||||
if(mVertList[idx2].x > xMax && idx2 != right[0])
|
||||
{
|
||||
xMax = mVertList[idx2].x;
|
||||
right[i] = idx2;
|
||||
}
|
||||
|
||||
xMax = -9999999.f;
|
||||
}
|
||||
|
||||
return twoIndices(right[0], right[1]);
|
||||
}
|
||||
|
||||
twoIndices decompPoly::uppermostInsideVerts(U8 idx1, U8 idx2)
|
||||
{
|
||||
F32 yMax = -9999999.f;
|
||||
S32 up[] = {-1, -1};
|
||||
|
||||
for(U8 i = 0; i < 2; i++)
|
||||
{
|
||||
for(U8 j = 0; j < mInsideVerts.size(); j++)
|
||||
{
|
||||
if(mVertList[mInsideVerts[j]].y > yMax && mInsideVerts[j] != up[0])
|
||||
{
|
||||
yMax = mVertList[mInsideVerts[j]].y;
|
||||
up[i] = mInsideVerts[j];
|
||||
}
|
||||
}
|
||||
|
||||
if(mVertList[idx1].y > yMax && idx1 != up[0])
|
||||
{
|
||||
yMax = mVertList[idx1].y;
|
||||
up[i] = idx1;
|
||||
}
|
||||
|
||||
if(mVertList[idx2].y > yMax && idx2 != up[0])
|
||||
{
|
||||
yMax = mVertList[idx2].y;
|
||||
up[i] = idx2;
|
||||
}
|
||||
|
||||
yMax = -9999999.f;
|
||||
}
|
||||
|
||||
return twoIndices(up[0], up[1]);
|
||||
}
|
||||
|
||||
twoIndices decompPoly::lowermostInsideVerts(U8 idx1, U8 idx2)
|
||||
{
|
||||
F32 yMin = 9999999.f;
|
||||
S32 down[] = {-1, -1};
|
||||
|
||||
for(U8 i = 0; i < 2; i++)
|
||||
{
|
||||
for(U8 j = 0; j < mInsideVerts.size(); j++)
|
||||
{
|
||||
if(mVertList[mInsideVerts[j]].y < yMin && mInsideVerts[j] != down[0])
|
||||
{
|
||||
yMin = mVertList[mInsideVerts[j]].y;
|
||||
down[i] = mInsideVerts[j];
|
||||
}
|
||||
}
|
||||
|
||||
if(mVertList[idx1].y < yMin && idx1 != down[0])
|
||||
{
|
||||
yMin = mVertList[idx1].y;
|
||||
down[i] = idx1;
|
||||
}
|
||||
|
||||
if(mVertList[idx2].y < yMin && idx2 != down[0])
|
||||
{
|
||||
yMin = mVertList[idx2].y;
|
||||
down[i] = idx2;
|
||||
}
|
||||
|
||||
yMin = 9999999.f;
|
||||
}
|
||||
|
||||
return twoIndices(down[0], down[1]);
|
||||
}
|
||||
|
||||
void decompPoly::findPointsInside()
|
||||
{
|
||||
mInsideVerts.clear();
|
||||
|
||||
for(U8 i = 0; i < mVertList.size(); i++)
|
||||
{
|
||||
if(i != mTestTri.getVert(0) && i != mTestTri.getVert(1) && i != mTestTri.getVert(2))
|
||||
{
|
||||
if(isInside(mTestTri, i))
|
||||
{
|
||||
mInsideVerts.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decompPoly::addRemoveEdge(U8 idx1, U8 idx2)
|
||||
{
|
||||
twoIndices edge1(idx1, idx2);
|
||||
|
||||
if(!mEdgeList.remove(edge1))
|
||||
mEdgeList.push_back(edge1);
|
||||
}
|
||||
|
||||
void decompPoly::newPoly()
|
||||
{
|
||||
mVertList.clear();
|
||||
mEdgeList.clear();
|
||||
mInsideVerts.clear();
|
||||
mTris.clear();
|
||||
}
|
||||
|
||||
bool decompPoly::isVertInEdgeList(U8 idx)
|
||||
{
|
||||
for(U8 i = 0; i < mEdgeList.size(); i++)
|
||||
{
|
||||
if(mEdgeList[i].i1 == idx || mEdgeList[i].i2 == idx)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Point3F decompPoly::getVert(U8 idx)
|
||||
{
|
||||
if(idx < mVertList.size())
|
||||
return mVertList[idx];
|
||||
|
||||
return Point3F(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
U8 decompPoly::getTriIdx(U32 tri, U8 idx)
|
||||
{
|
||||
if(tri < mTris.size() && idx < 3)
|
||||
return mTris[tri].getVert(idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool decompPoly::checkEdgeLength(F32 len)
|
||||
{
|
||||
Point3F p1, p2;
|
||||
|
||||
for(U8 i = 0; i < mEdgeList.size(); i++)
|
||||
{
|
||||
p1 = mVertList[mEdgeList[i].i1];
|
||||
p2 = mVertList[mEdgeList[i].i2];
|
||||
|
||||
p1 = p2 - p1;
|
||||
|
||||
if(p1.len() < len)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
// Concave polygon decomposition into triangles
|
||||
//
|
||||
// Based upon this resource:
|
||||
// http://www.siggraph.org/education/materials/HyperGraph/scanline/outprims/polygon1.htm
|
||||
//
|
||||
// 1. Find leftmost vertex in polygon (smallest value along x-axis).
|
||||
// 2. Find the two edges adjacent to this vertex.
|
||||
// 3. Form a test tri by connecting the open side of these two edges.
|
||||
// 4. See if any of the vertices in the poly, besides the ones that form the test tri, are inside the
|
||||
// test tri.
|
||||
// 5. If there are verts inside, find the 3 leftmost of the inside verts and the test tri verts, form
|
||||
// a new test tri from these verts, and repeat from step 4. When no verts are inside, continue.
|
||||
// 6. Save test tri as a valid triangle.
|
||||
// 7. Remove the edges that the test tri and poly share, and add the new edges from the test tri to
|
||||
// the poly to form a new closed poly with the test tri subtracted out.
|
||||
//
|
||||
// Note: our polygon can contain no more than 255 verts. Complex polygons can create situations where
|
||||
// a vertex has more than 2 adjacent edges, causing step 2 to fail. This method improves on the resource
|
||||
// listed above by not limiting the decomposition to the leftmost side only. If step 2 fails, the
|
||||
// algorithm also tries to decompose the polygon from the top, right, and bottom until one succeeds or
|
||||
// they all fail. If they all fail, the polygon is too complex to be decomposed with this method.
|
||||
|
||||
bool decompPoly::decompose()
|
||||
{
|
||||
// Must have at least 3 verts to form a poly
|
||||
if(mVertList.size() < 3)
|
||||
return false;
|
||||
|
||||
// Clear out any previously stored tris
|
||||
mTris.clear();
|
||||
|
||||
// Initialize the edge list with the default edges
|
||||
initEdgeList();
|
||||
|
||||
twoIndices otherVerts, outerVerts2;
|
||||
U32 counter = 0;
|
||||
U8 uniqueVertAttempt = 0;
|
||||
U8 formTriAttempt = 0;
|
||||
bool notUnique = false;
|
||||
|
||||
// The main decomposition loop
|
||||
while(mEdgeList.size() > 3)
|
||||
{
|
||||
// Find outermost vert in poly, LMV
|
||||
U8 outerVertIdx;
|
||||
|
||||
switch(uniqueVertAttempt)
|
||||
{
|
||||
case 0: outerVertIdx = leftmost(); break;
|
||||
case 1: outerVertIdx = rightmost(); break;
|
||||
case 2: outerVertIdx = uppermost(); break;
|
||||
case 3: outerVertIdx = uppermost(); break;
|
||||
default: outerVertIdx = leftmost();
|
||||
}
|
||||
|
||||
// Find edges that share LMV
|
||||
twoIndices edgesIdx = findEdges(outerVertIdx, notUnique);
|
||||
|
||||
// If vert shares more than two edges, try decomposing from different direction
|
||||
if(notUnique)
|
||||
{
|
||||
if(uniqueVertAttempt < 4)
|
||||
{
|
||||
uniqueVertAttempt++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
newPoly();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if(edgesIdx.i1 >= mEdgeList.size() || edgesIdx.i2 >= mEdgeList.size())
|
||||
{
|
||||
newPoly();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Form the test tri from these 2 edges
|
||||
mTestTri = formTriFromEdges(edgesIdx.i1, edgesIdx.i2);
|
||||
|
||||
// See if there are any other poly verts inside the test tri
|
||||
findPointsInside();
|
||||
|
||||
// If there are verts inside, repeat procedure until there are none
|
||||
while(mInsideVerts.size() > 0 && formTriAttempt++ < mVertList.size())
|
||||
{
|
||||
// Get the two verts of the test tri that are not the LMV
|
||||
otherVerts = mTestTri.getOtherVerts(outerVertIdx);
|
||||
|
||||
// Get the 2 outermost verts of the inside and test tri verts (excluding LMV)
|
||||
switch(uniqueVertAttempt)
|
||||
{
|
||||
case 0: outerVerts2 = leftmostInsideVerts(otherVerts.i1, otherVerts.i2); break;
|
||||
case 1: outerVerts2 = rightmostInsideVerts(otherVerts.i1, otherVerts.i2); break;
|
||||
case 2: outerVerts2 = uppermostInsideVerts(otherVerts.i1, otherVerts.i2); break;
|
||||
case 3: outerVerts2 = uppermostInsideVerts(otherVerts.i1, otherVerts.i2); break;
|
||||
default: outerVerts2 = leftmostInsideVerts(otherVerts.i1, otherVerts.i2);
|
||||
}
|
||||
|
||||
// Form a new test tri from LMV, and the 2 new leftmost verts above
|
||||
mTestTri.setVert(outerVerts2.i1, 0);
|
||||
mTestTri.setVert(outerVertIdx, 1);
|
||||
mTestTri.setVert(outerVerts2.i2, 2);
|
||||
|
||||
// See if there are verts inside this new test tri
|
||||
findPointsInside();
|
||||
}
|
||||
|
||||
// We have found a valid tri
|
||||
mTris.push_back(mTestTri);
|
||||
|
||||
// Remove edges common to test tri and poly... add unique edges from test tri to poly
|
||||
addRemoveEdge(mTestTri.getVert(0), mTestTri.getVert(1));
|
||||
addRemoveEdge(mTestTri.getVert(1), mTestTri.getVert(2));
|
||||
addRemoveEdge(mTestTri.getVert(0), mTestTri.getVert(2));
|
||||
|
||||
// This should never take 255 iterations... we must be stuck in an infinite loop
|
||||
if(counter++ > 255)
|
||||
{
|
||||
newPoly();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset attempts
|
||||
formTriAttempt = 0;
|
||||
uniqueVertAttempt = 0;
|
||||
}
|
||||
|
||||
// The last tri
|
||||
mTris.push_back(formTriFromEdges(0,1));
|
||||
|
||||
// The verts need to be ordered to draw correctly
|
||||
for(U8 i = 0; i < mTris.size(); i++)
|
||||
{
|
||||
mTris[i].orderVerts();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue