Files
FC1/CryAISystem/GraphUtility.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1167 lines
32 KiB
C++

#include "stdafx.h"
#include "Graph.h"
#include "Heuristic.h"
#include "CAISystem.h"
#if !defined(LINUX)
#include <assert.h>
#endif
#include "Cry_Math.h"
#include <ISystem.h>
#include <Cry_Camera.h>
#include <IRenderer.h>
#include <ILog.h>
#include <I3DEngine.h>
#include <algorithm>
#include <IConsole.h>
#include "IPhysics.h"
//
//--------------------------------------------------------------------------------------------------
int CGraph::Rearrange( ListNodes& nodesList, const Vec3d& cutStart, const Vec3d& cutEnd )
{
int counter=0;
GraphNode *curNode;
ListNodes::iterator it;
int ndNumber=0;
for(it=nodesList.begin(); it!=nodesList.end(); it++, ndNumber++)
{
int counter=0;
curNode = (*it);
// VectorOfLinks::iterator vi;
if( curNode->vertex.size()!=3 || curNode == m_pSafeFirst)
{
nodesList.erase( it );
it=nodesList.begin();
}
}
counter = ProcessMegaMerge( nodesList, cutStart, cutEnd );
return counter;
}
//
//--------------------------------------------------------------------------------------------------
int CGraph::ProcessMegaMerge( ListNodes& nodesList, const Vec3d& vCutStart, const Vec3d& vCutEnd )
{
ListNodes leftSideNodes;
ListNodes rightSideNodes;
int Counter=0;
Vec3d cutDirection = vCutEnd-vCutStart;
//Obstacles leftOutline;
//Obstacles rightOutline;
ObstacleIndexList leftOutline;
ObstacleIndexList rightOutline;
//ListPositions leftOutline;
//ListPositions rightOutline;
GraphNode *curNode;
VectorOfLinks::iterator vi;
ObstacleData tmpObst;
tmpObst.vPos = vCutEnd;
int cutEnd = m_pAISystem->m_VertexList.FindVertex( tmpObst );
tmpObst.vPos = vCutStart;
int cutStart = m_pAISystem->m_VertexList.FindVertex( tmpObst );
if( cutStart<0 || cutEnd<0 )
{
m_pAISystem->m_pSystem->GetILog()->Log("\001 CGraph::ProcessMegaMerge cut is not in m_VertexList %d %d", cutStart, cutEnd);
AIWarning( "CGraph::ProcessMegaMerge cut is not in m_VertexList %d %d", cutStart, cutEnd);
assert(0);
return 0;
}
if( nodesList.empty() )
return 0;
ListNodes::iterator it;
DbgCheckList( nodesList );
Vec3d cutN = cutDirection.normalized();
for(it=nodesList.begin(); it!=nodesList.end(); it++)
{
curNode = (*it);
if (std::find(rightSideNodes.begin(),rightSideNodes.end(),curNode) != rightSideNodes.end()) // already in list - skip
continue;
if (std::find(leftSideNodes.begin(),leftSideNodes.end(),curNode) != leftSideNodes.end()) // already in list - skip
continue;
GraphLink* pNewLink = curNode->FindNewLink();
if( pNewLink )
{
GraphNode *nbrNode = pNewLink->pLink;
VectorOfLinks::iterator nbrVi;
float curCross = curNode->GetCross( vCutStart, cutN, *pNewLink );
for (nbrVi=nbrNode->link.begin();nbrVi!=nbrNode->link.end();nbrVi++)
if((*nbrVi).pLink == curNode )
break;
// mark neighbor - it's a new link in edge
(*nbrVi).fMaxRadius = -1.f;
float nbrCross = nbrNode->GetCross( vCutStart, cutN, (*nbrVi) );
if( fabs(nbrCross) > fabs(curCross) )
curCross = -nbrCross;
if( curCross<0 )
{
leftSideNodes.push_back( curNode );
rightSideNodes.push_back( nbrNode );
}
else
{
leftSideNodes.push_back( nbrNode );
rightSideNodes.push_back( curNode );
}
}
}
if(leftSideNodes.size()!=rightSideNodes.size())
{
assert(0); // triangulation optimisation error -- newly-marked nodes are not simmetrical
return 0;
}
DbgCheckList( nodesList );
for(it=nodesList.begin(); it!=nodesList.end(); it++)
{
curNode = (*it);
if (std::find(leftSideNodes.begin(),leftSideNodes.end(),curNode) != leftSideNodes.end()) // already in list - skip
continue;
if (std::find(rightSideNodes.begin(),rightSideNodes.end(),curNode) != rightSideNodes.end()) // already in list - skip
continue;
if( ( curNode->vertex[0] == cutStart ) ||
( curNode->vertex[1] == cutStart ) ||
( curNode->vertex[2] == cutStart ) ||
( curNode->vertex[0] == cutEnd ) ||
( curNode->vertex[1] == cutEnd ) ||
( curNode->vertex[2] == cutEnd ) )
continue; // don't touch begin/end of cut
bool bHasPointOnEdge=false;
int vIdx( 0 );
for( ; vIdx<3 && !bHasPointOnEdge; vIdx++ )
{
for(ListNodes::iterator li=rightSideNodes.begin();li!=rightSideNodes.end() && !bHasPointOnEdge;li++)
{
GraphNode *refNode = (*li);
GraphLink *pNewLink = refNode->FindNewLink();
if( !pNewLink )
continue;
if( refNode->vertex[pNewLink->nStartIndex] == curNode->vertex[vIdx] ||
refNode->vertex[pNewLink->nEndIndex] == curNode->vertex[vIdx] )
// found it - it's on cut - add the hode to outline
bHasPointOnEdge = true;
}
}
if( !bHasPointOnEdge )
continue;
vIdx--;
// so just check now if it's left or right side and add to appropriate list
int otherVertexIdx1 = 2 - vIdx;
int otherVertexIdx2 = 3 - (otherVertexIdx1 + vIdx);
Vec3d theOtherVertex = m_pAISystem->m_VertexList.GetVertex(curNode->vertex[otherVertexIdx1]).vPos
- vCutStart;
theOtherVertex.normalize();
float curCross = cutN.x * theOtherVertex.y - cutN.y * theOtherVertex.x;
theOtherVertex = m_pAISystem->m_VertexList.GetVertex(curNode->vertex[otherVertexIdx2]).vPos
- vCutStart;
theOtherVertex.normalize();
float cross2 = cutN.x * theOtherVertex.y - cutN.y * theOtherVertex.x;
if( fabs(curCross) < fabs(cross2) )
curCross = cross2;
if( curCross<0 )
leftSideNodes.push_back( curNode );
else
rightSideNodes.push_back( curNode );
/*
Vec3d theOtherVertex = m_pAISystem->m_VertexList.GetVertex(
curNode->vertex[3-((*vi).nStartIndex + (*vi).nEndIndex)]).vPos
- vCutStart;
float cross = cutDirection.x * theOtherVertex.y - cutDirection.y * theOtherVertex.x;
if( cross<0 )
{
if (std::find(leftSideNodes.begin(),leftSideNodes.end(),(*vi).pLink) != leftSideNodes.end())
{
bool hasPointOnEdge = false;
for(ListNodes::iterator li=leftSideNodes.begin();li!=leftSideNodes.end() && !hasPointOnEdge;li++)
{
GraphNode *refNode = (*li);
VectorOfLinks::iterator refLinks;
for(refLinks=refNode->link.begin();refLinks!=refNode->link.end();refLinks++)
if((*refLinks).IsNewLink())
{
if( ( refNode->vertex[(*refLinks).nStartIndex] == curNode->vertex[(*vi).nStartIndex] ) ||
( refNode->vertex[(*refLinks).nStartIndex] == curNode->vertex[(*vi).nEndIndex] ) ||
( refNode->vertex[(*refLinks).nEndIndex] == curNode->vertex[(*vi).nStartIndex] ) ||
( refNode->vertex[(*refLinks).nEndIndex] == curNode->vertex[(*vi).nEndIndex] )
)
{
hasPointOnEdge = true;
}
break;
}
}
if( hasPointOnEdge )
{
leftSideNodes.push_back( curNode );
startFromBeginning = true;
break;
}
// break;
}
}
else
if (std::find(rightSideNodes.begin(),rightSideNodes.end(),(*vi).pLink) != rightSideNodes.end())
{
bool hasPointOnEdge = false;
for(ListNodes::iterator li=rightSideNodes.begin();li!=rightSideNodes.end() && !hasPointOnEdge;li++)
{
GraphNode *refNode = (*li);
VectorOfLinks::iterator refLinks;
for(refLinks=refNode->link.begin();refLinks!=refNode->link.end();refLinks++)
if((*refLinks).IsNewLink())
{
if( (refNode->vertex[(*refLinks).nStartIndex] == curNode->vertex[(*vi).nStartIndex] ) ||
(refNode->vertex[(*refLinks).nStartIndex] == curNode->vertex[(*vi).nEndIndex] ) ||
(refNode->vertex[(*refLinks).nEndIndex] == curNode->vertex[(*vi).nStartIndex] ) ||
(refNode->vertex[(*refLinks).nEndIndex] == curNode->vertex[(*vi).nEndIndex] )
)
{
hasPointOnEdge = true;
}
break;
}
}
if( hasPointOnEdge )
{
//curNode->data.fSlope = 1111;
rightSideNodes.push_back( curNode );
startFromBeginning = true;
break;
}
// break;
}
*/
// }
// if( startFromBeginning )
// it=nodesList.begin();
// else
// it++;
}
//return 0;
if( leftSideNodes.size() > 1 )
{
// create left outline
leftOutline.push_front( cutEnd );
leftOutline.push_front( cutStart );
if(!CreateOutline( leftSideNodes, nodesList, leftOutline ))
return 0; // some strange problems (see CreateOutline) - don't optimize this segment, return
}
else
leftSideNodes.clear();
DbgCheckList( nodesList );
if( rightSideNodes.size() > 1 )
{
// create right outline
rightOutline.push_front( cutEnd );
rightOutline.push_front( cutStart );
if(!CreateOutline( rightSideNodes, nodesList, rightOutline ))
return 0; // some strange problems (see CreateOutline) - don't optimize this segment, return
}
else
rightSideNodes.clear();
m_DEBUG_outlineListL.clear();
// m_DEBUG_outlineListL.insert(m_DEBUG_outlineListL.begin(),leftOutline.begin(), leftOutline.end() );
m_DEBUG_outlineListR.clear();
// m_DEBUG_outlineListR.insert(m_DEBUG_outlineListR.begin(),rightOutline.begin(), rightOutline.end() );
DbgCheckList( nodesList );
for( it=leftSideNodes.begin(); !leftSideNodes.empty() && it!=leftSideNodes.end(); it++)
{
curNode = (*it);
curNode->data.fSlope = 1111;
Disconnect( curNode );
ListNodes::iterator itList = std::find(nodesList.begin(),nodesList.end(),curNode);
nodesList.erase( itList );
}
DbgCheckList( nodesList );
for( it=rightSideNodes.begin(); !rightSideNodes.empty() && it!=rightSideNodes.end(); it++)
{
curNode = (*it);
Disconnect( curNode );
ListNodes::iterator itList = std::find(nodesList.begin(),nodesList.end(),curNode);
nodesList.erase( itList );
}
//*/
//return 0;
//DbgCheckList( nodesList );
// ProcessRearrange( nodesList, cutStart, cutEnd );
DbgCheckList( nodesList );
TriangulateOutline( nodesList, leftOutline, false );
//return 0;
DbgCheckList( nodesList );
TriangulateOutline( nodesList, rightOutline, true );
DbgCheckList( nodesList );
ConnectNodes( nodesList );
DbgCheckList( nodesList );
for( it=nodesList.begin(); it!=nodesList.end(); it++)
{
curNode = (*it);
for (vi=curNode->link.begin();vi!=curNode->link.end();vi++)
if( (*vi).fMaxRadius<0.0f ||
// (curNode->vertex[(*vi).nStartIndex].vPos.x==cutStart.x &&
// curNode->vertex[(*vi).nStartIndex].vPos.y==cutStart.y &&
/// curNode->vertex[(*vi).nEndIndex].vPos.x==cutEnd.x &&
// curNode->vertex[(*vi).nEndIndex].vPos.y==cutEnd.y ) ||
// (curNode->vertex[(*vi).nEndIndex].vPos.x==cutStart.x &&
// curNode->vertex[(*vi).nEndIndex].vPos.y==cutStart.y &&
// curNode->vertex[(*vi).nStartIndex].vPos.x==cutEnd.x &&
// curNode->vertex[(*vi).nStartIndex].vPos.y==cutEnd.y )
// )
(curNode->vertex[(*vi).nStartIndex]==cutStart &&
curNode->vertex[(*vi).nEndIndex]==cutEnd) ||
(curNode->vertex[(*vi).nEndIndex]==cutStart&&
curNode->vertex[(*vi).nStartIndex]==cutEnd)
)
(*vi).fMaxRadius = -10.0f;
}
DbgCheckList( nodesList );
return Counter;
}
//
//--------------------------------------------------------------------------------------------------
// creates outline of insideNodes, removes all triangles in outline from nodesList
bool CGraph::CreateOutline( ListNodes& insideNodes, ListNodes& nodesList, ObstacleIndexList& outline)
{
ListNodes::iterator it;
VectorOfLinks::iterator vi;
GraphNode *curNode;
//GraphNode *prevNode;
Vec3d curOtherVertex;
bool doneHere = false;
ListNodes insideNodesCurrent = insideNodes;
for(it=insideNodesCurrent.begin(); !doneHere; it++)
//for(it=insideNodesCurrent.begin(); it!=insideNodesCurrent.end(); it++)
{
if( it==insideNodesCurrent.end() )
{
m_pAISystem->m_pSystem->GetILog()->Log("\001 CGraph::CreateOutline can't find OutlineBegin ");
AIWarning( "CGraph::CreateOutline can't find OutlineBegin ");
assert( 0 );
return false;
}
curNode = (*it);
for (vi=curNode->link.begin();vi!=curNode->link.end();vi++)
{
if( (*vi).IsNewLink() ) // it's on the edge - it's a new node
if( (curNode->vertex[(*vi).nStartIndex] == (*outline.begin()) ) ||
(curNode->vertex[(*vi).nEndIndex] == (*outline.begin()) ) )
{
int theOtherVertexIdx = curNode->vertex[3-((*vi).nStartIndex + (*vi).nEndIndex)];
// Vec3d theOtherVertex = m_pAISystem->m_VertexList.GetVertex(theOtherVertexIdx).vPos;
if( std::find( outline.begin(), outline.end(),theOtherVertexIdx ) == outline.end())
outline.push_front( theOtherVertexIdx );
// else
// assert(0);
it = insideNodesCurrent.erase( it );
doneHere=true;
break;
}
}
if (doneHere)
break;
}
// assert(curNode); //
if( !curNode )
{
m_pAISystem->m_pSystem->GetILog()->Log("\001 CGraph::CreateOutline curNode is NULL ");
AIWarning( "CGraph::CreateOutline curNode is NULL ");
assert( 0 );
return false;
}
while( !insideNodesCurrent.empty() )
{
GraphNode *nextCandidate = NULL;
// Vec3d theOtherVertex;
// Vec3d nextOtherVertex;
int theOtherVertexIdx;
int nextOtherVertexIdx=0;
bool bAddVertex = true;
for (vi=curNode->link.begin(); vi!=curNode->link.end()&&bAddVertex; vi++)
if((*vi).IsNewLink())
bAddVertex = false;
//
// if has links on base
for (vi=curNode->link.begin();vi!=curNode->link.end();vi++)
{
GraphNode *nextNode = (*vi).pLink;
if ((it=std::find(insideNodesCurrent.begin(),insideNodesCurrent.end(),nextNode)) != insideNodesCurrent.end())
{
VectorOfLinks::iterator viNext;
for (viNext=nextNode->link.begin();viNext!=nextNode->link.end();viNext++)
if( (*viNext).IsNewLink() )
{
nextCandidate = nextNode;
insideNodesCurrent.erase( it );
break;
}
}
}
//
// if has noBase links
for (vi=curNode->link.begin();vi!=curNode->link.end();vi++)
{
GraphNode *nextNode = (*vi).pLink;
if ((it=std::find(insideNodesCurrent.begin(),insideNodesCurrent.end(),nextNode)) != insideNodesCurrent.end())
{
VectorOfLinks::iterator viNext;
for (viNext=nextNode->link.begin();viNext!=nextNode->link.end();viNext++)
if( (*viNext).pLink == curNode )
{
if( !nextCandidate ) // no base link - use this one
{
nextCandidate = nextNode;
insideNodesCurrent.erase( it );
nextOtherVertexIdx = nextNode->vertex[3-((*viNext).nStartIndex + (*viNext).nEndIndex)];
}
else
bAddVertex = false;
break;
}
}
}
if(bAddVertex)
{
if( std::find( outline.begin(), outline.end(),theOtherVertexIdx ) == outline.end())
outline.push_front( theOtherVertexIdx );
}
theOtherVertexIdx = nextOtherVertexIdx;
// assert(nextCandidate); //
if( !nextCandidate )
{
m_pAISystem->m_pSystem->GetILog()->Log("\001 CGraph::CreateOutline nextCandidate is NULL ");
AIWarning( "CGraph::CreateOutline nextCandidate is NULL ");
assert( 0 );
return false;
}
curNode = nextCandidate;
}
return true;
}
//
//--------------------------------------------------------------------------------------------------
void CGraph::TriangulateOutline( ListNodes& nodesList, ObstacleIndexList& outline, bool orientation )
{
if(outline.empty())
return;
//ListPositions::reverse_iterator crItr=outline.rbegin();
//Vec3d vCut1 = *crItr++;
//Vec3d vCut2 = *crItr;
GraphNode *candidateNode;
ObstacleData obst;
GraphNode tmpNode;
ObstacleIndexList originalOutline;
originalOutline.insert(originalOutline.begin(), outline.begin(), outline.end());
//m_DEBUG_outlineListR.clear();
while(outline.size()>3)
{
// GraphNode tmpNode;
// ListPositions::iterator candidateRemove=outline.end();
ObstacleIndexList::iterator candidateRemove=outline.end();
bool notGood=false;
float candidateDegeneracy=-1.0f;
candidateNode = CreateNewNode();
int cntr=1;
for(ObstacleIndexList::iterator curItr=outline.begin(); curItr!=outline.end(); curItr++,cntr++)
{
ObstacleIndexList::iterator vItr1=curItr;
ObstacleIndexList::iterator vItr2=curItr;
if( cntr==outline.size() )
{
vItr1 = outline.begin();
vItr2 = vItr1;
++vItr2;
}
else if( cntr==outline.size()-1 )
{
vItr2 = outline.begin();
++vItr1;
}
else
{
++vItr1;
++vItr2;
++vItr2;
}
tmpNode.vertex.clear();
// obst.vPos = *curItr;
tmpNode.vertex.push_back( *curItr );
// obst.vPos = *vItr1;
tmpNode.vertex.push_back( *vItr1 );
// obst.vPos = *vItr2;
tmpNode.vertex.push_back( *vItr2 );
notGood = false;
if(tmpNode.IsAntiClockwise()!=orientation)
notGood = true;
tmpNode.MakeAntiClockwise();
// check if enithing inside the curremt triangle
for(ObstacleIndexList::iterator tmpItr=originalOutline.begin(); tmpItr!=originalOutline.end() && !notGood; tmpItr++)
if (
// IsEquivalent()
*tmpItr == *curItr || *tmpItr == *vItr1 || *tmpItr == *vItr2 )
continue;
// else if(PointInTriangle(*tmpItr, &tmpNode))
else if(PointInTriangle(m_pAISystem->m_VertexList.GetVertex(*tmpItr).vPos, &tmpNode))
notGood = true;
if( notGood ) // this triangle can't be used
continue;
float dVal = tmpNode.GetDegeneracyValue();
/*
if( (vCut1==*curItr && vCut2==*vItr1) ||
(vCut2==*curItr && vCut1==*vItr1) ||
(vCut1==*curItr && vCut2==*vItr2) ||
(vCut2==*curItr && vCut1==*vItr2) ||
(vCut1==*vItr1 && vCut2==*vItr2) ||
(vCut2==*vItr1 && vCut1==*vItr2) )
dVal += 100;
*/
if( dVal>candidateDegeneracy ) // better candidate
{
candidateDegeneracy = dVal;
candidateNode->vertex = tmpNode.vertex;
candidateRemove = vItr1;
}
}
//
//add the best candidate - remove vertex from outline
candidateNode->MakeAntiClockwise();
FillGraphNodeData( candidateNode );
nodesList.push_back( candidateNode );
assert(candidateRemove != outline.end());
outline.erase( candidateRemove );
}
//
// add the last triangle
candidateNode = CreateNewNode();
// obst.vPos = outline.front();
// outline.pop_front();
candidateNode->vertex.push_back( outline.front() );
outline.pop_front();
// obst.vPos = outline.back();
candidateNode->vertex.push_back( outline.back() );
// obst.vPos = outline.front();
candidateNode->vertex.push_back( outline.front() );
candidateNode->MakeAntiClockwise();
FillGraphNodeData( candidateNode );
nodesList.push_back( candidateNode );
}
/*
*
//
//--------------------------------------------------------------------------------------------------
void CGraph::TriangulateOutline( ListNodes& nodesList, ListPositions& outline, bool orientation )
{
if(outline.empty())
return;
GraphNode *candidateNode;
ObstacleData obst;
GraphNode tmpNode;
while(outline.size()>3)
{
// GraphNode tmpNode;
ListPositions::iterator candidateRemove=outline.end();
ListPositions::iterator tmpVertex;
ListPositions::reverse_iterator tmpLastVertex;
bool notGood=false;
float candidateDegeneracy=-1.0f;
candidateNode = CreateNewNode();
//
// first triangle - begin-next-next
tmpNode.vertex.clear();
tmpVertex = outline.begin();
obst.vPos = *tmpVertex;
tmpNode.vertex.push_back( obst );
tmpVertex++;
obst.vPos = *tmpVertex;
tmpNode.vertex.push_back( obst );
tmpVertex++;
obst.vPos = *tmpVertex;
tmpNode.vertex.push_back( obst );
notGood = false;
if(tmpNode.IsAntiClockwise()!=orientation)
notGood = true;
tmpNode.MakeAntiClockwise();
// check if enithing inside the curremt triangle
for(tmpVertex++; tmpVertex!=outline.end()&&!notGood;tmpVertex++)
if(PointInTriangle(*tmpVertex, &tmpNode))
notGood = true;
if(!notGood)
{
float dVal = tmpNode.GetDegeneracyValue();
if( dVal>candidateDegeneracy ) // better candidate
{
candidateDegeneracy = dVal;
candidateNode->vertex = tmpNode.vertex;
candidateRemove = ++outline.begin();
}
}
//
// second triangle - begin-next-end
tmpNode.vertex.clear();
tmpVertex = outline.begin();
obst.vPos = *tmpVertex;
tmpNode.vertex.push_back( obst );
tmpVertex++;
obst.vPos = *tmpVertex;
tmpNode.vertex.push_back( obst );
obst.vPos = *(outline.rbegin());
tmpNode.vertex.push_back( obst );
notGood = false;
if(tmpNode.IsAntiClockwise()!=orientation)
notGood = true;
tmpNode.MakeAntiClockwise();
// check if enithing inside the curremt triangle
tmpLastVertex = outline.rbegin();
tmpLastVertex++;
for(tmpVertex++;
//*tmpVertex!= *tmpLastVertex;
!IsEquivalent(*tmpVertex,*tmpLastVertex,VEC_EPSILON)
&& !notGood ;
tmpVertex++
)
if(PointInTriangle(*tmpVertex, &tmpNode))
notGood = true;
if(!notGood)
{
float dVal = tmpNode.GetDegeneracyValue();
if( dVal>candidateDegeneracy ) // better candidate
{
candidateDegeneracy = dVal;
candidateNode->vertex = tmpNode.vertex;
candidateRemove = outline.begin();
}
}
//
// third triangle - begin-end-preend
tmpNode.vertex.clear();
obst.vPos = *outline.begin();
tmpNode.vertex.push_back( obst );
tmpLastVertex = outline.rbegin();
tmpLastVertex++; // get preend
obst.vPos = *tmpLastVertex;
tmpNode.vertex.push_back( obst );
tmpLastVertex = outline.rbegin(); // get end
obst.vPos = *tmpLastVertex;
tmpNode.vertex.push_back( obst );
notGood = false;
if(tmpNode.IsAntiClockwise()!=orientation)
notGood = true;
tmpNode.MakeAntiClockwise();
tmpLastVertex = outline.rbegin();
tmpLastVertex++; // set to preend
// check if enithing inside the curremt triangle
for(tmpLastVertex++;
//*tmpLastVertex!=*outline.begin()
!IsEquivalent(*tmpLastVertex,*outline.begin(),VEC_EPSILON)
&&!notGood;
tmpLastVertex++
)
if(PointInTriangle(*tmpLastVertex, &tmpNode))
notGood = true;
if(!notGood)
{
float dVal = tmpNode.GetDegeneracyValue();
if( dVal>candidateDegeneracy ) // better candidate
{
candidateDegeneracy = dVal;
candidateNode->vertex = tmpNode.vertex;
candidateRemove = (++outline.rbegin()).base();
}
}
//
// last triangle - end-preend-prepreend
tmpNode.vertex.clear();
tmpLastVertex = outline.rbegin();
tmpLastVertex++;
tmpLastVertex++; // pre-preend
obst.vPos = *tmpLastVertex;
tmpNode.vertex.push_back( obst );
tmpLastVertex--; // pre-end
obst.vPos = *tmpLastVertex;
tmpNode.vertex.push_back( obst );
tmpLastVertex--; // end
obst.vPos = *tmpLastVertex;
tmpNode.vertex.push_back( obst );
notGood = false;
if(tmpNode.IsAntiClockwise()!=orientation)
notGood = true;
tmpNode.MakeAntiClockwise();
tmpLastVertex++;
tmpLastVertex++; // set to pre-preend
// check if enithing inside the curremt triangle
for(tmpLastVertex++; tmpLastVertex!=(outline.rend())&&!notGood;tmpLastVertex++)
if(PointInTriangle(*tmpLastVertex, &tmpNode))
notGood = true;
if(!notGood)
{
float dVal = tmpNode.GetDegeneracyValue();
if( dVal>candidateDegeneracy ) // better candidate
{
candidateDegeneracy = dVal;
candidateNode->vertex = tmpNode.vertex;
candidateRemove = (++(++outline.rbegin())).base();
// candidateRemove--;
}
}
//
//add the best candidate - remove vertex from outline
candidateNode->MakeAntiClockwise();
FillGraphNodeData( candidateNode );
nodesList.push_back( candidateNode );
assert(candidateRemove != outline.end());
ListPositions::iterator dbg=std::find(m_DEBUG_outlineListR.begin(), m_DEBUG_outlineListR.end(), *candidateRemove);
if(dbg!=m_DEBUG_outlineListR.end())
(*dbg).z = -500;
outline.erase( candidateRemove );
}
//
// add the last triangle
candidateNode = CreateNewNode();
obst.vPos = outline.front();
// obst.bOccupied = false;
outline.pop_front();
candidateNode->vertex.push_back( obst );
obst.vPos = outline.back();
// obst.bOccupied = false;
candidateNode->vertex.push_back( obst );
obst.vPos = outline.front();
//obst.bOccupied = false;
candidateNode->vertex.push_back( obst );
candidateNode->MakeAntiClockwise();
FillGraphNodeData( candidateNode );
nodesList.push_back( candidateNode );
}
*/
//
//--------------------------------------------------------------------------------------------------
int CGraph::ProcessRearrange( ListNodes& nodesList, const Vec3d& cutStart, const Vec3d& cutEnd )
{
return 0;
/*
int counter = 0;
ListNodes::iterator it;
VectorOfLinks::iterator vi;
Obstacles::iterator oi;
int dbgcounter=0;
for(it=nodesList.begin();it!=nodesList.end();it++)
{
dbgcounter++;
GraphNode *curNode = (*it);
// if(curNode->link.empty())
if(curNode->link.size()!=3)
continue;
bool onCut = false;
for (oi=curNode->vertex.begin();oi!=curNode->vertex.end(); oi++)
if( IsEquivalent((*oi).vPos,cutStart,VEC_EPSILON) || IsEquivalent((*oi).vPos,cutEnd,VEC_EPSILON) )
{
onCut = true;
break;
}
if(!onCut)
continue;
for (vi=curNode->link.begin();vi!=curNode->link.end();vi++)
{
if ( (*vi).fMaxRadius<0.0f ) // it's cut edge
continue;
if ((*vi).pLink->link.size()!=3)
continue;
if (std::find(nodesList.begin(),nodesList.end(),(*vi).pLink) != nodesList.end()) // link is in list as well
{
DbgCheckList( nodesList );
if(ProcessRearrange( curNode, (*vi).pLink, nodesList ))
{
it=nodesList.begin();
counter++;
DbgCheckList( nodesList );
break;
}
DbgCheckList( nodesList );
// break;
}
}
}
return counter;
*/
}
//
//--------------------------------------------------------------------------------------------------
bool CGraph::ProcessRearrange( GraphNode *node1, GraphNode *node2, ListNodes& nodesList )
{
return false;
/*
float dValue;
float dValue1 = node1->GetDegeneracyValue();
float dValue2 = node2->GetDegeneracyValue();
GraphNode tmpNode;
ObstacleData obst[4];
unsigned int other1VertexIdx;
unsigned int other2VertexIdx;
if(dValue1>dValue2)
dValue1 = dValue2;
if( dValue1>.02f )
return false;
VectorOfLinks::iterator vi;
for (vi=node2->link.begin();vi!=node2->link.end();vi++)
if( (*vi).pLink == node1 )
{
other2VertexIdx = 3 - ((*vi).nStartIndex + (*vi).nEndIndex);
break;
}
for (vi=node1->link.begin();vi!=node1->link.end();vi++)
if( (*vi).pLink == node2 )
{
other1VertexIdx = 3 - ((*vi).nStartIndex + (*vi).nEndIndex);
break;
}
//check if it is possible configuration for rearranement
Vec3d newEdge = node1->vertex[other1VertexIdx].vPos - node2->vertex[other2VertexIdx].vPos;
Vec3d v1 = node1->vertex[(*vi).nStartIndex].vPos - node2->vertex[other2VertexIdx].vPos;
Vec3d v2 = node1->vertex[(*vi).nEndIndex].vPos - node2->vertex[other2VertexIdx].vPos;
float cross1 = v1.x * newEdge.y - v1.y * newEdge.x;
float cross2 = v2.x * newEdge.y - v2.y * newEdge.x;
if( cross1<0 && cross2<0 || cross1>0 && cross2>0 )
return false; // can't rearrange this two triangles
obst[0] = node1->vertex[other1VertexIdx];
obst[1] = node1->vertex[(*vi).nStartIndex];
obst[2] = node2->vertex[other2VertexIdx];
obst[3] = node1->vertex[(*vi).nEndIndex];
// obst[0].bOccupied = false;
// obst[1].bOccupied = false;
// obst[2].bOccupied = false;
// obst[3].bOccupied = false;
tmpNode.vertex.push_back( obst[0] );
tmpNode.vertex.push_back( obst[1] );
tmpNode.vertex.push_back( obst[2] );
dValue = tmpNode.GetDegeneracyValue();
if( dValue<=dValue1 )
return false;
tmpNode.vertex.clear();
tmpNode.vertex.push_back( obst[0] );
tmpNode.vertex.push_back( obst[2] );
tmpNode.vertex.push_back( obst[3] );
dValue = tmpNode.GetDegeneracyValue();
if( dValue<=dValue1 )
return false;
DbgCheckList( nodesList );
Disconnect( node1, true );
//DbgCheckList( nodesList );
Disconnect( node2, true );
//( nodesList );
ListNodes::iterator nIt = std::find(nodesList.begin(),nodesList.end(),node1);
if(nIt == nodesList.end())
DbgCheckList( nodesList );
// if( nIt!=nodesList.end() )
nodesList.erase( nIt );
nIt = std::find(nodesList.begin(),nodesList.end(),node2);
if(nIt == nodesList.end())
DbgCheckList( nodesList );
nodesList.erase( nIt );
DbgCheckList( nodesList );
node1 = CreateNewNode();
node1->vertex.push_back( obst[0] );
node1->vertex.push_back( obst[1] );
node1->vertex.push_back( obst[2] );
node1->MakeAntiClockwise();
FillGraphNodeData( node1 );
node2 = CreateNewNode();
node2->vertex.push_back( obst[0] );
node2->vertex.push_back( obst[2] );
node2->vertex.push_back( obst[3] );
node2->MakeAntiClockwise();
FillGraphNodeData( node2 );
nodesList.push_front( node1 );
nodesList.push_front( node2 );
return true;
*/
}
//
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
float GraphNode::GetDegeneracyValue()
{
CVertexList *pVList = &GetAISystem()->m_VertexList;
Vec3d firstE = pVList->GetVertex(vertex[1]).vPos - pVList->GetVertex(vertex[0]).vPos;
Vec3d secondE = pVList->GetVertex(vertex[2]).vPos - pVList->GetVertex(vertex[0]).vPos;
firstE.Normalize();
secondE.Normalize();
float cosAngle0 = 1.0f - firstE.Dot( secondE );
firstE = pVList->GetVertex(vertex[0]).vPos - pVList->GetVertex(vertex[1]).vPos;
secondE = pVList->GetVertex(vertex[2]).vPos - pVList->GetVertex(vertex[1]).vPos;
firstE.Normalize();
secondE.Normalize();
float cosAngle1 = 1.0f - firstE.Dot( secondE );
firstE = pVList->GetVertex(vertex[0]).vPos - pVList->GetVertex(vertex[2]).vPos;
secondE = pVList->GetVertex(vertex[1]).vPos - pVList->GetVertex(vertex[2]).vPos;
firstE.Normalize();
secondE.Normalize();
float cosAngle2 = 1.0f - firstE.Dot( secondE );
if( cosAngle0<=cosAngle1 && cosAngle0<=cosAngle2 )
return cosAngle0;
if( cosAngle1<=cosAngle2 && cosAngle1<=cosAngle0 )
return cosAngle1;
return cosAngle2;
}
//
//--------------------------------------------------------------------------------------------------
void GraphNode::MakeAntiClockwise()
{
if (vertex.size() < 3)
return;
CVertexList *pVList = &GetAISystem()->m_VertexList;
int od1 = vertex[0];
int od2 = vertex[1];
int od3 = vertex[2];
Vec3d one = pVList->GetVertex(od2).vPos - pVList->GetVertex(od1).vPos;
Vec3d two = pVList->GetVertex(od3).vPos - pVList->GetVertex(od2).vPos;
float fcrossz = one.x * two.y - two.x * one.y;
if (fcrossz<0)
{
// rearrange the first and second
vertex.clear();
vertex.push_back(od2);
vertex.push_back(od1);
vertex.push_back(od3);
// MakeAntiClockwise();
}
}
//
//--------------------------------------------------------------------------------------------------
bool GraphNode::IsAntiClockwise()
{
if (vertex.size() < 3)
return false;
CVertexList *pVList = &GetAISystem()->m_VertexList;
int od1 = vertex[0];
int od2 = vertex[1];
int od3 = vertex[2];
Vec3d one = pVList->GetVertex(od2).vPos - pVList->GetVertex(od1).vPos;
Vec3d two = pVList->GetVertex(od3).vPos - pVList->GetVertex(od2).vPos;
float fcrossz = one.x * two.y - two.x * one.y;
if (fcrossz<0)
return false;
return true;
}
//
//--------------------------------------------------------------------------------------------------
bool CGraph::DbgCheckList( ListNodes& nodesList ) const
{
bool isGood = true;
GraphNode *curNode;
ListNodes::iterator it;
int ndNumber=0;
for(it=nodesList.begin(); it!=nodesList.end(); it++, ndNumber++)
{
int counter=0;
curNode = (*it);
VectorOfLinks::iterator vi;
for (vi=curNode->link.begin();vi!=curNode->link.end();vi++)
if( (*vi).IsNewLink() ) // it's on the edge - it's a new node
counter++;
if(counter > 1)
isGood = false;
if( curNode->vertex.size()<3 )
isGood = false;
if (curNode->nRefCount>1 && curNode->nRefCount<4)
isGood = false;
ListNodes::iterator li;
ListNodes::iterator itnext = it;
if (++itnext != nodesList.end())
{
li = std::find(itnext,nodesList.end(),(*it));
if (li!=nodesList.end())
isGood = false;
}
}
return isGood;
}
//
//--------------------------------------------------------------------------------------------------
float GraphNode::GetCross( const Vec3d &vCutStart, const Vec3d &vDir, const GraphLink &theLink )
{
Vec3d theOtherVertex = GetAISystem()->m_VertexList.GetVertex(vertex[3-(theLink.nStartIndex + theLink.nEndIndex)]).vPos
- vCutStart;
theOtherVertex.normalize();
return vDir.x * theOtherVertex.y - vDir.y * theOtherVertex.x;
}
//
//--------------------------------------------------------------------------------------------------
GraphLink* GraphNode::FindNewLink()
{
VectorOfLinks::iterator vi;
for (vi=link.begin();vi!=link.end();vi++)
if( (*vi).IsNewLink() ) // it's on the edge - it's a new node
return &(*vi);
return NULL;
}
//
//--------------------------------------------------------------------------------------------------