Commit 123be959 authored by Armin Erraji's avatar Armin Erraji

Added CombinationalEngine for propagation path with reflection and diffraction components.

parent 43c1093b
#include<ITAPropagationPathSim/CombinationalEngine/PropagationShapes.h>
// ITA includes
#include <ITAGeo/Base.h>
#include <ITAGeo/Halfedge/MeshModel.h>
#include <ITAGeo/Utils.h>
namespace ITAPropagationPathSim
{
namespace CombinationalEngine
{
using namespace ITAGeo;
class PathConstruct
{
public:
//Constructor
PathConstruct(shared_ptr<const ITAGeo::Halfedge::CMeshModelList> pMeshModelList);
void CreatePropagationTree(shared_ptr<const CEmitter> pEmitter, const int iMaxDiffractions = DiffractionOrder::DIFFRACTION_ORDER_2,const int iMaxReflections = ReflectionOrder::SPECULAR_REFLECTION_ORDER_2, const int iMaxCombinedOrder = Order::ORDER_3);
void RecursiveAddChildrenToTree(const CPropagationShapeShared & pPropagationShapeChildIn, CPropagationShapeShared& vpShapeChildCopyOut, int iReflectionOrder, int iDiffractionOrder, int iCombinedOrder);
private:
vector<CPropagationShapeShared> m_vpPropagationShapes; //!< Vector of all propagation shapes
shared_ptr<const ITAGeo::Halfedge::CMeshModelList> m_pMeshModelList; //!< Copy of propagation model list
CShapesMap m_mvpShapeVisibilityMap; //!< Map of which shape can illuminate which ones
vector<CPropagationShapeShared> m_vpPropagationTree; //!< Vector of all propagation shapes (as well as its children) visible to the emitter
shared_ptr<const CEmitter> m_pEmitter; //!< Const pointer to emitter
shared_ptr<const CSensor> m_pSensor; //!< Const pointer to sensor
unique_ptr<const int> m_pMaxReflectionOrder; //!< Const pointer to maximum reflection order
unique_ptr<const int> m_pMaxDiffractionOrder; //!< Const pointer to maximum diffraction order
unique_ptr<const int> m_pMaxCombinedOrder; //!< Const pointer to maximum order of combined diffractions and reflections
void CreateVisibilityMap();
bool CanPointIlluminateFace(const VistaVector3D & v3Point, const string & sMeshModelName, CITAMesh::FaceHandle hFace);
void CanEdgeIlluminateFace(bool & bCanEdgeIlluminateFaceOut, ITAPropagationPathSim::CombinationalEngine::CPropagationFaceShared & pPropagationFace, ITAPropagationPathSim::CombinationalEngine::CPropagationEdgeShared & pPropagationEdge);
void CanFaceIlluminateEdge(bool & bCanFaceIlluminateEdgeOut, CPropagationFaceShared & pPropagationFace, CPropagationEdgeShared & pPropagationEdge);
void CanFaceIlluminateFace(bool & bCanFaceIlluminateFaceOut, CPropagationFaceShared & pPropagationFaceStart, CPropagationFaceShared & pPropagationFaceEnd);
void CanEdgeIlluminateEdge(bool & bCanEdgeIlluminateEdgeOut, CPropagationEdgeShared & pPropagationEdgeStart, CPropagationEdgeShared & pPropagationEdgeEnd);
void GetPropagationShapes(std::vector<ITAPropagationPathSim::CombinationalEngine::CPropagationShapeShared> &vpPropagationShapes);
};
}
}
\ No newline at end of file
#include <ITAPropagationPathSim/Definitions.h>
// ITA includes
#include <ITAGeo/Base.h>
#include <ITAGeo/Halfedge/MeshModel.h>
#include <ITAGeo/Utils.h>
// Used Namespaces
using namespace std;
namespace ITAPropagationPathSim
{
namespace CombinationalEngine
{
// Typedefs
class CPropagationShape;
class CPropagationFace;
class CPropagationEdge;
typedef shared_ptr<CPropagationShape> CPropagationShapeShared;
typedef shared_ptr<CPropagationFace> CPropagationFaceShared;
typedef shared_ptr<CPropagationEdge> CPropagationEdgeShared;
typedef OpenMesh::PolyMesh_ArrayKernelT<> CITAMesh;
typedef map <CPropagationShapeShared, vector<CPropagationShapeShared>> CShapesMap;
class CPropagationShape
{
public:
//Public member variables
enum EShapeType
{
INVALID = -1, //!< Invalid shape
POINT = 0, //!< Propagation point (acoustic source, receiver)
EDGE, //!< Propagation edge (for diffraction)
FACE, //!< Propagation face (for reflection)
LAST_ELEMENT //!< Last element of EShapeType
} iShapeType; //! Type of Shape
//!< Point of interaction
unique_ptr<VistaVector3D> v3InteractionPoint;
//!< Parent shape(previous shape)
CPropagationShapeShared pParent;
//!< Child(ren) shape(s)
CPropagationShapeShared pChild; //Shape used in propagation paths
vector <CPropagationShapeShared> vpChildren;//Shapes used in propagation trees
shared_ptr<string> sMeshModelName;
//Public member functions
void CopyFrom(const CPropagationShape& oPropagationShapeIn);
private:
};
class CPropagationFace : public CPropagationShape
{
public:
//Public member variables
CITAMesh::FaceHandle hFace;
vector<shared_ptr<VistaVector3D>> vv3Vertices;
shared_ptr<VistaVector3D> v3ImageSource;
shared_ptr<VistaVector3D> v3ImageReceiver;
//Public member functions
void CopyFrom(const CPropagationFace& oPropagationFaceIn);
};
class CPropagationEdge : public CPropagationShape
{
public:
//Public member variables
CITAMesh::HalfedgeHandle hHalfedge;
CITAMesh::EdgeHandle hEdge;
CITAMesh::FaceHandle hMainFace;
CITAMesh::FaceHandle hOppositeFace;
shared_ptr<VistaVector3D> v3FromVertex;//!< Start vertex of corresponding halfedge
shared_ptr<VistaVector3D> v3ToVertex;//!< End vertex of corresponding halfedge
shared_ptr<VistaVector3D> v3MainFaceNormal;//!< Face normal of main face
shared_ptr<VistaVector3D> v3OppositeFaceNormal;//!< Face normal of opposing face
shared_ptr<VistaVector3D> v3FromVertexMirrored;
shared_ptr<VistaVector3D> v3ToVertexMirrored;
//!< Position of interaction point relative to the ray starting at v3FromVertex and showing in direction of (v3ToVertex - v3FromVertex)
//!< If the relative position lies between 0.0(at v3FromVertex) and 1.0(at v3ToVertex), the interaction point is on the edge
unique_ptr<float> pRelativeInteractionPoint;
//Public member functions
void CopyFrom(const CPropagationEdge& oPropagationEdgeIn);
};
}
}
\ No newline at end of file
# $Id:$
set( RelativeDir "include/ITAPropagationPathSim/CombinationalEngine" )
set( RelativeSourceGroup "Header Files\\ITAPropagationPathSim\\CombinationalEngine" )
set( DirFiles
DiffractionApertures.h
ImageConstructor.h
PropagationBase.h
PropagationConstructor.h
PropagationShapes.h
ReflectionApertures.h
)
set( DirFiles_SourceGroup "${RelativeSourceGroup}" )
set( LocalSourceGroupFiles )
foreach( File ${DirFiles} )
list( APPEND LocalSourceGroupFiles "${RelativeDir}/${File}" )
list( APPEND ProjectSources "${RelativeDir}/${File}" )
endforeach()
source_group( ${DirFiles_SourceGroup} FILES ${LocalSourceGroupFiles} )
......@@ -2,7 +2,7 @@
set( RelativeDir "include/ITAPropagationPathSim" )
set( RelativeSourceGroup "Header Files\\ITAPropagationPathSim" )
set( SubDirs MirrorImage ConvexDiffraction BaseEngine UrbanEngine)
set( SubDirs MirrorImage ConvexDiffraction CombinationalEngine BaseEngine UrbanEngine)
set( DirFiles
Definitions.h
......
......@@ -23,7 +23,7 @@ CSource::CSource(shared_ptr<const ITAGeo::Halfedge::CMeshModelList> vpMeshModelL
//Copy to mesh model vector
for(int i = 0; i< vpMeshModelList->GetNumMeshes(); i++)
{
// Calculate mesh face normals
// Calculate mesh face normals
CITAMesh* pMesh = m_vpMeshModelList->at(i)->GetMesh()->pMesh;
pMesh->request_face_normals();
pMesh->update_face_normals();
......
#include <ITAPropagationPathSim\CombinationalEngine\PropagationBase.h>
//Typedefs
typedef OpenMesh::PolyMesh_ArrayKernelT<> CITAMesh;
struct CITAMeshPtr
{
CITAMesh* pMesh;
};
ITAPropagationPathSim::CombinationalEngine::PathConstruct::PathConstruct(shared_ptr<const ITAGeo::Halfedge::CMeshModelList> pMeshModelList)
{
m_pMeshModelList = pMeshModelList;
for (int i = 0; i < m_pMeshModelList->GetNumMeshes(); i++)
{
// Calculate mesh normals
CITAMesh* pMesh = m_pMeshModelList->at(i)->GetMesh()->pMesh;
pMesh->request_face_normals();
pMesh->update_face_normals();
pMesh->request_halfedge_normals();
pMesh->request_vertex_normals();
}
CreateVisibilityMap();
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::CreatePropagationTree(shared_ptr<const ITAGeo::CEmitter> pEmitter, const int iMaxDiffractions, const int iMaxReflections, const int iMaxCombinedOrder)
{
//Set emitter
m_pEmitter = pEmitter;
//Set orders
m_pMaxDiffractionOrder = make_unique<const int>(iMaxDiffractions);
m_pMaxReflectionOrder = make_unique<const int>(iMaxReflections);
m_pMaxCombinedOrder = make_unique<const int> (iMaxCombinedOrder);
//Set initial values for number of diffractions/reflections
for (const auto& pPropagationShape : m_vpPropagationShapes)
{
// If iMaxCombined order is zero, no paths are added
if (iMaxCombinedOrder <= 0)
break;
switch (pPropagationShape->iShapeType)
{
case CPropagationShape::FACE:
{
//Only add reflection paths if iMaxReflections is at least one
if (iMaxReflections >= 1 )
{
CPropagationFaceShared pFaceCopy;
pFaceCopy->CopyFrom(*static_pointer_cast<CPropagationFace>(pPropagationShape));
bool bCanIlluminated = CanPointIlluminateFace(m_pEmitter->v3InteractionPoint, *pFaceCopy->sMeshModelName, pFaceCopy->hFace);
if (bCanIlluminated)
{
//Add face copy to propagation tree
m_vpPropagationTree.push_back(pFaceCopy);
//Add further propagation shapes if higher order than one is allowed
if (*m_pMaxCombinedOrder > 1)
{
for (const auto& pPropagationShapeChild : m_mvpShapeVisibilityMap[pPropagationShape])
{
CPropagationShapeShared vpShapeChildCopy;
RecursiveAddChildrenToTree(pPropagationShapeChild, vpShapeChildCopy, 1, 0, 1);
if (vpShapeChildCopy != nullptr)
{
vpShapeChildCopy->pParent = pFaceCopy;
pFaceCopy->vpChildren.push_back(vpShapeChildCopy);
}
}
}
}
}
break;
}
case CPropagationShape::EDGE:
{
//Only add reflection paths if iMaxDiffractions is at least one
if (iMaxDiffractions >= 1)
{
CPropagationEdgeShared pEdgeCopy;
pEdgeCopy->CopyFrom(*static_pointer_cast<CPropagationEdge>(pPropagationShape));
ITA_EXCEPT_NOT_IMPLEMENTED;
m_vpPropagationTree.push_back(pEdgeCopy);
bool bCanIlluminated = CanPointIlluminateFace(m_pEmitter->v3InteractionPoint, *pEdgeCopy->sMeshModelName, pEdgeCopy->hMainFace);
bCanIlluminated =bCanIlluminated || CanPointIlluminateFace(m_pEmitter->v3InteractionPoint, *pEdgeCopy->sMeshModelName, pEdgeCopy->hOppositeFace);
if (bCanIlluminated)
{
//Add edge copy to propagation tree
m_vpPropagationTree.push_back(pEdgeCopy);
//Add further propagation shapes if higher order than one is allowed
if (*m_pMaxCombinedOrder > 1)
{
for (const auto& pPropagationShapeChild : m_mvpShapeVisibilityMap[pPropagationShape])
{
CPropagationShapeShared vpShapeChildCopy;
RecursiveAddChildrenToTree(pPropagationShapeChild, vpShapeChildCopy, 0, 1, 1);
if (vpShapeChildCopy != nullptr)
{
vpShapeChildCopy->pParent = pEdgeCopy;
pEdgeCopy->vpChildren.push_back(vpShapeChildCopy);
}
}
}
}
}
break;
}
}
}
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::RecursiveAddChildrenToTree(const CPropagationShapeShared & pPropagationShapeChildIn, CPropagationShapeShared& vpShapeChildCopyOut, int iReflectionOrder, int iDiffractionOrder, int iCombinedOrder)
{
switch (pPropagationShapeChildIn->iShapeType)
{
case CPropagationShape::FACE:
{
//Only add child if max reflection order is not reached yet
if (iReflectionOrder < *m_pMaxReflectionOrder)
{
//Cast shape as face and copy shape
CPropagationFaceShared pFaceChildCopy;
pFaceChildCopy->CopyFrom(*static_pointer_cast<CPropagationFace>(pPropagationShapeChildIn));
//Set output parameter
vpShapeChildCopyOut = pFaceChildCopy;
//Add further children, if max order is not reached yet
if (iCombinedOrder + 1 < *m_pMaxCombinedOrder)
{
for (const auto& pShapeChildChild : m_mvpShapeVisibilityMap[pPropagationShapeChildIn])
{
CPropagationShapeShared vpShapeChildChildCopy;
RecursiveAddChildrenToTree(pShapeChildChild, vpShapeChildChildCopy, iReflectionOrder + 1, iDiffractionOrder, iCombinedOrder + 1);
if (vpShapeChildChildCopy != nullptr)
{
vpShapeChildChildCopy->pParent = vpShapeChildCopyOut;
vpShapeChildCopyOut->vpChildren.push_back(vpShapeChildChildCopy);
}
}
}
}
break;
}
case CPropagationShape::EDGE:
{
//Only add child if max diffraction order is not reached yet
if (iDiffractionOrder < *m_pMaxDiffractionOrder)
{
//Cast shape as edge and copy shape
CPropagationEdgeShared pEdgeChildCopy;
pEdgeChildCopy->CopyFrom(*static_pointer_cast<CPropagationEdge>(pPropagationShapeChildIn));
//Set output parameter
vpShapeChildCopyOut = pEdgeChildCopy;
//Add further children, if max order is not reached yet
if (iCombinedOrder + 1 < *m_pMaxCombinedOrder)
{
for (const auto& pShapeChildChild : m_mvpShapeVisibilityMap[pPropagationShapeChildIn])
{
CPropagationShapeShared vpShapeChildChildCopy;
RecursiveAddChildrenToTree(pShapeChildChild, vpShapeChildChildCopy, iReflectionOrder, iDiffractionOrder + 1, iCombinedOrder + 1);
if (vpShapeChildChildCopy != nullptr)
{
vpShapeChildChildCopy->pParent = vpShapeChildCopyOut;
vpShapeChildCopyOut->vpChildren.push_back(vpShapeChildChildCopy);
}
}
}
}
break;
}
}
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::CreateVisibilityMap()
{
vector<CPropagationShapeShared> vpPropagationShapes;
//Get all propagation shapes of the mesh model list
GetPropagationShapes(vpPropagationShapes);
//Create a visibility map
for (auto& pPropagationShapeFrom : vpPropagationShapes)
{
for (auto& pPropagationShapeTo : vpPropagationShapes)
{
if (pPropagationShapeFrom == pPropagationShapeTo)
continue;
bool bCanIlluminate = false;
if (pPropagationShapeFrom->iShapeType == CPropagationShape::FACE)
{
auto pPropagationFaceFrom = static_pointer_cast<CPropagationFace>(pPropagationShapeFrom);
if (pPropagationShapeTo->iShapeType == CPropagationShape::FACE)
{
auto pPropagationFaceTo = static_pointer_cast<CPropagationFace>(pPropagationShapeTo);
//Start illumination test for both directions
CanFaceIlluminateFace(bCanIlluminate, pPropagationFaceTo, pPropagationFaceFrom);
if (bCanIlluminate)
CanFaceIlluminateFace(bCanIlluminate, pPropagationFaceFrom, pPropagationFaceTo);
}
else if (pPropagationShapeTo->iShapeType == CPropagationShape::EDGE)
{
auto pPropagationEdgeTo = static_pointer_cast<CPropagationEdge>(pPropagationShapeTo);
//Start illumination test for both directions
CanEdgeIlluminateFace(bCanIlluminate, pPropagationFaceFrom, pPropagationEdgeTo);
if (bCanIlluminate)
CanFaceIlluminateEdge(bCanIlluminate, pPropagationFaceFrom, pPropagationEdgeTo);
}
}
else if (pPropagationShapeFrom->iShapeType == CPropagationShape::EDGE)
{
auto pPropagationEdgeFrom = static_pointer_cast<CPropagationEdge>(pPropagationShapeFrom);
if (pPropagationShapeTo->iShapeType == CPropagationShape::FACE)
{
auto pPropagationFaceTo = static_pointer_cast<CPropagationFace>(pPropagationShapeTo);
//Start illumination test for both directions
CanEdgeIlluminateFace(bCanIlluminate, pPropagationFaceTo, pPropagationEdgeFrom);
if (bCanIlluminate)
CanFaceIlluminateEdge(bCanIlluminate, pPropagationFaceTo, pPropagationEdgeFrom);
}
else if (pPropagationShapeTo->iShapeType == CPropagationShape::EDGE)
{
auto pPropagationEdgeTo = static_pointer_cast<CPropagationEdge>(pPropagationShapeTo);
//Start illumination test for both directions
CanEdgeIlluminateEdge(bCanIlluminate, pPropagationEdgeFrom, pPropagationEdgeTo);
if (bCanIlluminate)
CanEdgeIlluminateEdge(bCanIlluminate, pPropagationEdgeFrom, pPropagationEdgeTo);
}
}
if (bCanIlluminate)
m_mvpShapeVisibilityMap[pPropagationShapeFrom].push_back(pPropagationShapeTo);
}
}
}
bool ITAPropagationPathSim::CombinationalEngine::PathConstruct::CanPointIlluminateFace(const VistaVector3D& v3Point, const string& sMeshModelName, CITAMesh::FaceHandle hFace)
{
auto& pFaceMesh = m_pMeshModelList->GetMeshModel(sMeshModelName)->GetMesh()->pMesh;
return ITAGeoUtils::CanFaceBeIlluminated(*pFaceMesh, hFace, v3Point);
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::CanEdgeIlluminateFace(bool &bCanEdgeIlluminateFaceOut, CPropagationFaceShared & pPropagationFace, CPropagationEdgeShared & pPropagationEdge)
{
auto& pFaceMesh = m_pMeshModelList->GetMeshModel(*pPropagationFace->sMeshModelName)->GetMesh()->pMesh;
bCanEdgeIlluminateFaceOut = ITAGeoUtils::CanFaceBeIlluminated(*pFaceMesh, pPropagationFace->hFace, *pPropagationEdge->v3FromVertex);
bCanEdgeIlluminateFaceOut |= ITAGeoUtils::CanFaceBeIlluminated(*pFaceMesh, pPropagationFace->hFace, *pPropagationEdge->v3ToVertex);
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::CanFaceIlluminateEdge(bool &bCanFaceIlluminateEdgeOut, CPropagationFaceShared & pPropagationFace, CPropagationEdgeShared & pPropagationEdge)
{
auto& pEdgeMesh = m_pMeshModelList->GetMeshModel(*pPropagationEdge->sMeshModelName)->GetMesh()->pMesh;
//Iterate over all vertices of the face. If at least one vertex is in the illuminable range of the edge, return true
bCanFaceIlluminateEdgeOut = false;
for (auto& pVertex : pPropagationFace->vv3Vertices)
{
bCanFaceIlluminateEdgeOut |= ITAGeoUtils::CanFaceBeIlluminated(*pEdgeMesh, pPropagationEdge->hMainFace, *pVertex);
bCanFaceIlluminateEdgeOut |= ITAGeoUtils::CanFaceBeIlluminated(*pEdgeMesh, pPropagationEdge->hOppositeFace, *pVertex);
if (bCanFaceIlluminateEdgeOut)
return;
}
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::CanFaceIlluminateFace(bool &bCanFaceIlluminateFaceOut, CPropagationFaceShared & pPropagationFaceStart, CPropagationFaceShared & pPropagationFaceEnd)
{
auto& pFaceEndMesh = m_pMeshModelList->GetMeshModel(*pPropagationFaceEnd->sMeshModelName)->GetMesh()->pMesh;
//Iterate over all vertices of the face. If at least one vertex is in the illuminable range of the edge, return true
bCanFaceIlluminateFaceOut = false;
for (auto& pVertex : pPropagationFaceStart->vv3Vertices)
{
bCanFaceIlluminateFaceOut |= ITAGeoUtils::CanFaceBeIlluminated(*pFaceEndMesh, pPropagationFaceEnd->hFace, *pVertex);
if (bCanFaceIlluminateFaceOut)
return;
}
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::CanEdgeIlluminateEdge(bool &bCanEdgeIlluminateEdgeOut, CPropagationEdgeShared & pPropagationEdgeStart, CPropagationEdgeShared & pPropagationEdgeEnd)
{
auto& pEdgeEndMesh = m_pMeshModelList->GetMeshModel(*pPropagationEdgeEnd->sMeshModelName)->GetMesh()->pMesh;
bCanEdgeIlluminateEdgeOut = ITAGeoUtils::CanFaceBeIlluminated(*pEdgeEndMesh, pPropagationEdgeEnd->hMainFace, *pPropagationEdgeStart->v3FromVertex);
bCanEdgeIlluminateEdgeOut |= ITAGeoUtils::CanFaceBeIlluminated(*pEdgeEndMesh, pPropagationEdgeEnd->hMainFace, *pPropagationEdgeStart->v3ToVertex);
bCanEdgeIlluminateEdgeOut |= ITAGeoUtils::CanFaceBeIlluminated(*pEdgeEndMesh, pPropagationEdgeEnd->hOppositeFace, *pPropagationEdgeStart->v3FromVertex);
bCanEdgeIlluminateEdgeOut |= ITAGeoUtils::CanFaceBeIlluminated(*pEdgeEndMesh, pPropagationEdgeEnd->hOppositeFace, *pPropagationEdgeStart->v3ToVertex);
}
void ITAPropagationPathSim::CombinationalEngine::PathConstruct::GetPropagationShapes(vector<CPropagationShapeShared> &vpPropagationShapesOut)
{
for (auto& pMeshModel : *m_pMeshModelList)
{
CITAMesh* pMesh = pMeshModel->GetMesh()->pMesh;
auto psMeshModelName = make_shared<string>(pMeshModel->GetName());
//Iterate over all faces of current mesh
CITAMesh::ConstFaceIter cf_it = pMesh->faces_begin();
while (cf_it != pMesh->faces_end())
{
CITAMesh::FaceHandle hFace(*cf_it++);
CPropagationFaceShared pPropagationFace = make_shared<CPropagationFace>();
pPropagationFace->iShapeType = CPropagationShape::FACE;
pPropagationFace->sMeshModelName = psMeshModelName;
pPropagationFace->hFace = hFace;
//Get vertices
//Iterate over all vertices of current face
CITAMesh::ConstFaceVertexIter cfv_it = pMesh->cfv_begin(hFace);
while (cfv_it != pMesh->cfv_end(hFace))
{
CITAMesh::VertexHandle hVertex(*cfv_it++);
pPropagationFace->vv3Vertices.push_back(make_shared<VistaVector3D>(pMesh->point(hVertex).data()));
}
vpPropagationShapesOut.push_back(pPropagationFace);
}
//Iterate over all edges of current mesh
CITAMesh::ConstEdgeIter cf_et = pMesh->edges_begin();
while (cf_et != pMesh->edges_end())
{
CITAMesh::EdgeHandle hEdge(*cf_et++);
CPropagationEdgeShared pPropagationEdge = make_shared<CPropagationEdge>();
pPropagationEdge->iShapeType = CPropagationShape::EDGE;
pPropagationEdge->sMeshModelName = psMeshModelName;
pPropagationEdge->hEdge = hEdge;
pPropagationEdge->hHalfedge = pMesh->halfedge_handle(hEdge, 0