You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
4.5 KiB
222 lines
4.5 KiB
//--------------------------------------------------------------------------------------------------
|
|
// qhHalfEdge.cpp
|
|
//
|
|
// Copyright(C) 2011 by D. Gregorius. All rights reserved.
|
|
//--------------------------------------------------------------------------------------------------
|
|
#include "qhHalfEdge.h"
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Utilities
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool qhHalfEdge::IsConvex( qhReal Tolerance ) const
|
|
{
|
|
return Face->Plane.Distance( Twin->Face->Centroid ) < -Tolerance;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
void qhLinkFace( qhFace* Face, int Index, qhHalfEdge* Twin )
|
|
{
|
|
qhHalfEdge* Edge = Face->Edge;
|
|
while ( Index-- > 0 )
|
|
{
|
|
Edge = Edge->Next;
|
|
}
|
|
|
|
QH_ASSERT( Edge != Twin );
|
|
Edge->Twin = Twin;
|
|
Twin->Twin = Edge;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
void qhLinkFaces( qhFace* Face1, int Index1, qhFace* Face2, int Index2 )
|
|
{
|
|
qhHalfEdge* Edge1 = Face1->Edge;
|
|
while ( Index1-- > 0 )
|
|
{
|
|
Edge1 = Edge1->Next;
|
|
}
|
|
|
|
qhHalfEdge* Edge2 = Face2->Edge;
|
|
while ( Index2-- > 0 )
|
|
{
|
|
Edge2 = Edge2->Next;
|
|
}
|
|
|
|
QH_ASSERT( Edge1 != Edge2 );
|
|
Edge1->Twin = Edge2;
|
|
Edge2->Twin = Edge1;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
void qhNewellPlane( qhFace* Face )
|
|
{
|
|
int Count = 0;
|
|
qhVector3 Centroid = QH_VEC3_ZERO;
|
|
qhVector3 Normal = QH_VEC3_ZERO;
|
|
|
|
qhHalfEdge* Edge = Face->Edge;
|
|
QH_ASSERT( Edge->Face == Face );
|
|
|
|
do
|
|
{
|
|
qhHalfEdge* Twin = Edge->Twin;
|
|
QH_ASSERT( Twin->Twin == Edge );
|
|
|
|
const qhVector3& V1 = Edge->Origin->Position;
|
|
const qhVector3& V2 = Twin->Origin->Position;
|
|
|
|
Count++;
|
|
Centroid += V1;
|
|
|
|
// This seems to be more robust than N += Cross( V1, V2 )
|
|
Normal.X += ( V1.Y - V2.Y ) * ( V1.Z + V2.Z );
|
|
Normal.Y += ( V1.Z - V2.Z ) * ( V1.X + V2.X );
|
|
Normal.Z += ( V1.X - V2.X ) * ( V1.Y + V2.Y );
|
|
|
|
Edge = Edge->Next;
|
|
}
|
|
while ( Edge != Face->Edge );
|
|
|
|
QH_ASSERT( Count > 2 );
|
|
Centroid /= qhReal( Count );
|
|
Face->Centroid = Centroid;
|
|
|
|
qhReal Area = qhLength( Normal );
|
|
QH_ASSERT( Area > qhReal( 0.0 ) );
|
|
Normal /= Area;
|
|
|
|
Face->Plane = qhPlane( Normal, Centroid );
|
|
Face->Area = Area;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool qhIsConvex( const qhFace* Face, qhReal Tolerance )
|
|
{
|
|
const qhHalfEdge* Edge = Face->Edge;
|
|
|
|
do
|
|
{
|
|
qhVector3 Tail = Edge->Origin->Position;
|
|
qhVector3 Head = Edge->Twin->Origin->Position;
|
|
|
|
qhVector3 Offset = Head - Tail;
|
|
qhVector3 Normal = qhCross( Offset, Face->Plane.Normal );
|
|
|
|
qhPlane Plane( Normal, Head );
|
|
Plane.Normalize();
|
|
|
|
qhReal Distance = Plane.Distance( Edge->Next->Twin->Origin->Position );
|
|
if ( Distance > -Tolerance )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Edge = Edge->Next;
|
|
}
|
|
while ( Edge != Face->Edge );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
int qhVertexCount( const qhFace* Face )
|
|
{
|
|
int VertexCount = 0;
|
|
|
|
const qhHalfEdge* Edge = Face->Edge;
|
|
do
|
|
{
|
|
VertexCount++;
|
|
Edge = Edge->Next;
|
|
}
|
|
while ( Edge != Face->Edge );
|
|
|
|
return VertexCount;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool qhCheckConsistency( const qhFace* Face )
|
|
{
|
|
if ( Face->Mark == QH_MARK_DELETE )
|
|
{
|
|
// Face is not on the hull
|
|
return false;
|
|
}
|
|
|
|
if ( qhVertexCount( Face ) < 3 )
|
|
{
|
|
// Invalid geometry
|
|
return false;
|
|
}
|
|
|
|
const qhHalfEdge* Edge = Face->Edge;
|
|
|
|
do
|
|
{
|
|
const qhHalfEdge* Twin = Edge->Twin;
|
|
|
|
if ( Twin == NULL )
|
|
{
|
|
// Unreflected edge
|
|
return false;
|
|
}
|
|
|
|
if ( Twin->Face == NULL )
|
|
{
|
|
// Missing face
|
|
return false;
|
|
}
|
|
|
|
if ( Twin->Face == Face )
|
|
{
|
|
// Edge is connecting the same face
|
|
return false;
|
|
}
|
|
|
|
if ( Twin->Face->Mark == QH_MARK_DELETE )
|
|
{
|
|
// Face is not on hull
|
|
return false;
|
|
}
|
|
|
|
if ( Twin->Twin != Edge )
|
|
{
|
|
// Edge reflected incorrectly
|
|
return false;
|
|
}
|
|
|
|
if ( Edge->Origin != Twin->Next->Origin )
|
|
{
|
|
// Topology error
|
|
return false;
|
|
}
|
|
|
|
if ( Twin->Origin != Edge->Next->Origin )
|
|
{
|
|
// Topology error
|
|
return false;
|
|
}
|
|
|
|
if ( Edge->Face != Face )
|
|
{
|
|
// Topology error
|
|
return false;
|
|
}
|
|
|
|
Edge = Edge->Next;
|
|
}
|
|
while ( Edge != Face->Edge );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|