You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

732 lines
26 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "FITKPolyDataTool.h"
#include "qmath.h"
#include <QVector3D>
#include <vtkCellData.h>
#include <vtkIdList.h>
#include <vtkLine.h>
#include <vtkMath.h>
#include <vtkPolyData.h>
#include <vtkIntArray.h>
#include <vtkPolygon.h>
namespace Common
{
FITKPolyDataTool::FITKPolyDataTool(vtkPolyData* poly, vtkDataArray* normal)
: _poly(poly), _normals(normal)
{
m_scanPointCoPlaneFlag = vtkIntArray::New();
m_scanPointCoPlaneFlag->SetNumberOfComponents(1);
int ptNum = _poly->GetNumberOfPoints();
for (int iPt = 0; iPt < ptNum; ++iPt)
{
QVector3D pt;
double pos[3] = { .0 };
_poly->GetPoint(iPt, pos);
pt.setX(pos[0]);
pt.setY(pos[1]);
pt.setZ(pos[2]);
_points.insert(iPt, pt);
m_scanPointCoPlaneFlag->InsertNextValue(0);
}
// 初始化数组,全部置空标识。
int nCell = _poly->GetNumberOfCells();
m_scanCellFlag = vtkIntArray::New();
m_scanCellFlag->SetNumberOfComponents(1);
m_scanCellFlag->SetNumberOfValues(nCell);
m_scanCellFlag->FillComponent(0, 0);
m_scanCellCoPlaneFlag = vtkIntArray::New();
m_scanCellCoPlaneFlag->SetNumberOfComponents(1);
m_scanCellCoPlaneFlag->SetNumberOfValues(nCell);
m_scanCellCoPlaneFlag->FillComponent(0, 0);
}
FITKPolyDataTool::~FITKPolyDataTool()
{
// 析构。
if (m_scanCellFlag)
{
m_scanCellFlag->Delete();
m_scanCellFlag = nullptr;
}
if (m_scanCellCoPlaneFlag)
{
m_scanCellCoPlaneFlag->Delete();
m_scanCellCoPlaneFlag = nullptr;
}
if (m_scanPointCoPlaneFlag)
{
m_scanPointCoPlaneFlag->Delete();
m_scanPointCoPlaneFlag = nullptr;
}
}
QList< int > FITKPolyDataTool::getCoPlanePointIDs(int seedID, double angleHold)
{
//错误输入判断
if (_poly == nullptr || angleHold < 0 || angleHold >= 180 || !m_scanPointCoPlaneFlag) return QList< int >();
vtkSmartPointer<vtkIdList> cellids = vtkSmartPointer<vtkIdList>::New();
_poly->GetPointCells(seedID, cellids);
//选择一个节点所在的单元,作为起始种子点
if (cellids->GetNumberOfIds() == 0) return QList< int >();
const int acell = cellids->GetId(0);
//获取在同一个平面的单元
QList< int > neighborCells = this->getCoPlaneCellIDs(acell, angleHold);
for (int cell : neighborCells)
{
vtkSmartPointer<vtkIdList> cellPointIds = vtkSmartPointer<vtkIdList>::New();
_poly->GetCellPoints(cell, cellPointIds);
for (vtkIdType i = 0; i < cellPointIds->GetNumberOfIds(); i++)
{
int pt = cellPointIds->GetId(i);
// Modified by CHT
//@{
m_scanPointCoPlaneFlag->SetValue(pt, 1);
// if (!cellPoints.contains(pt)) cellPoints.append(pt);
//@}
}
}
// Added by CHT
//@{
QList< int > cellPoints;
int nPt = m_scanPointCoPlaneFlag->GetNumberOfValues();
for (int i = 0; i < nPt; i++)
{
if (m_scanPointCoPlaneFlag->GetValue(i))
{
cellPoints.push_back(i);
}
}
//@}
qSort(cellPoints);
return cellPoints;
}
QList< int > FITKPolyDataTool::getCoPlaneCellIDs(int seedID, double angleHold)
{
if (_poly == nullptr || _normals == nullptr) return QList< int >();
// Modified by CHT 修改记录单元方式。
//@{
m_scanCellCoPlaneFlag->SetValue(seedID, 1);
QList< int > afWave = { seedID };
//QList< int > coPlaneIDs{ seedID };
//QList< int > scanedCell = coPlaneIDs;
//QList< int > afWave = coPlaneIDs;
//@}
while (!afWave.isEmpty())
{
QList< int > tempAF = afWave;
afWave.clear();
QList< CELLPAIR > afRound;
//计算所有最外层单元的邻接单元
for (int cellID : tempAF)
{
QList< CELLPAIR > pa = getNeighborCell(cellID/*, scanedCell*/);
afRound.append(pa);
}
//计算法向夹角,产生新的最外层单元
for (CELLPAIR p : afRound)
{
const int cell0 = p.second, cell1 = p.first;
double normal0[3] = { 0, 0, 0 }, normal1[3] = { 0, 0, 0 };
// vtkPolygon::ComputeNormal(_poly->GetCell(cell0)->GetPoints(), normal0);
_normals->GetTuple(cell0, normal0);
double norm0 = vtkMath::Norm(normal0);
// vtkPolygon::ComputeNormal(_poly->GetCell(cell1)->GetPoints(), normal1);
_normals->GetTuple(cell1, normal1);
double norm1 = vtkMath::Norm(normal1);
double numerator = normal0[0] * normal1[0] + normal0[1] * normal1[1] + normal0[2] * normal1[2];
double value = numerator / (norm0 * norm1);
value = value > 0.99999999999999 ? 0.99999999999999 : value;
double angle1 = acos(value) * 180.0 / 3.141592654;
if (angle1 <= angleHold)
{
// Modified by CHT 修改记录单元方式。
//@{
if (!m_scanCellCoPlaneFlag->GetValue(cell1)) afWave.append(cell1);
m_scanCellCoPlaneFlag->SetValue(cell1, 1);
//@}
// if (!coPlaneIDs.contains(cell1)) coPlaneIDs.append(cell1);
}
// Modified by CHT 将表示设置为true后续跳过检索。
//@{
m_scanCellFlag->SetValue(cell1, 1);
//@}
// if (!scanedCell.contains(cell1)) scanedCell.append(cell1);
}
afRound.clear();
}
// Added by CHT 通过标识数组获取共面单元。
//@{
QList<int> coPlaneIDs;
int nCell = m_scanCellCoPlaneFlag->GetNumberOfValues();
for (int i = 0; i < nCell; i++)
{
if (m_scanCellCoPlaneFlag->GetValue(i))
{
coPlaneIDs.push_back(i);
}
}
//@}
return coPlaneIDs;
}
QList< int > FITKPolyDataTool::getNormalSingularID(const int seedID, const QList< int >& eles)
{
if (_poly == nullptr || _normals == nullptr || !eles.contains(seedID)) return QList< int >();
QList< int > singualIDs;
QList< int > coPlaneIDs{ seedID };
QList< int > scanedCell = coPlaneIDs;
QList< int > afWave = coPlaneIDs;
while (!afWave.isEmpty())
{
QList< int > tempAF = afWave;
afWave.clear();
QList< CELLPAIR > afRound;
//计算所有最外层单元的邻接单元
for (int cellID : tempAF)
{
QList< CELLPAIR > pa = getNeighborCell(cellID/*, scanedCell*/);
afRound.append(pa);
}
//计算法向夹角,产生新的最外层单元
for (CELLPAIR p : afRound)
{
const int cell0 = p.second, cell1 = p.first;
if (!eles.contains(cell0) || !eles.contains(cell1))
continue;
double normal0[3] = { 0, 0, 0 }, normal1[3] = { 0, 0, 0 };
this->calculateCellNormal(cell0, normal0);
double norm0 = vtkMath::Norm(normal0);
this->calculateCellNormal(cell1, normal1);
double norm1 = vtkMath::Norm(normal1);
if (singualIDs.contains(cell0))
vtkMath::MultiplyScalar(normal0, -1);
// if (singualIDs.contains(cell1))
// vtkMath::MultiplyScalar(normal1, -1);
double numerator = normal0[0] * normal1[0] + normal0[1] * normal1[1] + normal0[2] * normal1[2];
double angle1 = acos(numerator / (norm0 * norm1)) * 180.0 / 3.141592654;
if (angle1 <= 180)
{
if (!afWave.contains(cell1)) afWave.append(cell1);
if (!coPlaneIDs.contains(cell1)) coPlaneIDs.append(cell1);
if (angle1 > 90 && !scanedCell.contains(cell1))
singualIDs.append(cell1);
}
if (!scanedCell.contains(cell1)) scanedCell.append(cell1);
}
afRound.clear();
}
return singualIDs;
}
int FITKPolyDataTool::getCellIdFromEdgePoint(int pointID, bool& isFirst)
{
if (_poly == nullptr ||
pointID < 0 ||
pointID > _poly->GetNumberOfPoints())
{
return -1;
}
auto cellNum = _poly->GetNumberOfCells();
for (int iCell = 0; iCell < cellNum; ++iCell)
{
auto cell = _poly->GetCell(iCell);
if (!cell)
{
return -1;
}
auto idList = cell->GetPointIds();
if (idList->GetNumberOfIds() != 2)
{
return -1;
}
auto id0 = idList->GetId(0);
auto id1 = idList->GetId(1);
if (id0 == pointID)
{
isFirst = true;
return iCell;
}
else if (id1 == pointID)
{
isFirst = false;
return iCell;
}
}
return -1;
}
QList< int > FITKPolyDataTool::getEdgePointsByAngle(int pointID, double angle)
{
/// 对传入参数进行合法性筛选
QSet< int > result;
if (!_poly ||
pointID < 0 ||
pointID >= _poly->GetNumberOfPoints() ||
angle < 0 ||
angle > 90)
{
return result.toList();
}
/// 获取所有该选取点所在单元
vtkSmartPointer<vtkIdList> cellIDs = vtkSmartPointer<vtkIdList>::New();
_poly->GetPointCells(pointID, cellIDs);
int iCellNum = cellIDs->GetNumberOfIds();
/// 当前在此处对正反向单元只保留一个,提高效率,后续根据业务可能需要添加逻辑
QList< QPair< int, int > > linePointRelation;
for (int iCell = 0; iCell < iCellNum; ++iCell)
{
/// 基于线单元查找线单元所在的所有单元
int cellID = cellIDs->GetId(iCell);
vtkCell* cell = _poly->GetCell(cellID);
int findCellPt0 = cell->GetPointId(0);
int findCellPt1 = cell->GetPointId(1);
QPair< int, int > direction1(findCellPt0, findCellPt1), direction2(findCellPt1, findCellPt0);
if (linePointRelation.contains(direction1) ||
linePointRelation.contains(direction2))
{
continue;
}
linePointRelation.append(direction1);
/// 基于获取的单元进行逐单元双向查找
QList< int > lines = getEdgeLinesByAngle(cellID, angle);
for (int findCellID : lines)
{
vtkCell* findCell = _poly->GetCell(findCellID);
if (!cell) { return result.toList(); }
result.insert(findCell->GetPointId(0));
result.insert(findCell->GetPointId(1));
}
}
return result.toList();
}
QList< int > FITKPolyDataTool::getEdgeLinesByAngle(int cellID, double angle)
{
/// 对输入参数进行合法性检查
QSet< int > lines;
if (!_poly ||
cellID < 0 ||
cellID >= _poly->GetNumberOfCells() ||
angle < 0 ||
angle > 90 ||
_poly->GetCell(cellID)->GetCellType() != VTK_LINE)
{
return lines.toList();
}
lines.insert(cellID);
/// 获取线单元首点方向、尾点方向向下查找的所有单元
for (int pointIndex = 0; pointIndex <= 1; ++pointIndex)
{
/// 首次进入,或单方向完成、确认查找的起始单元及查找方向
int nextPointIndex = pointIndex;
int nextCellID = cellID;
/// 循环直至该方向不存在符合条件的后续线单元
while (true)
{
int p0 = _poly->GetCell(nextCellID)->GetPointId(0);
int p1 = _poly->GetCell(nextCellID)->GetPointId(1);
nextCellID = getNextEdgeLineByAngle(nextCellID, nextPointIndex, angle);
if (nextCellID < 0) { break; }
if (lines.contains(nextCellID)) { break; }
/// 准备下一个节点向下推导
lines.insert(nextCellID);
int p2 = _poly->GetCell(nextCellID)->GetPointId(0);
int p3 = _poly->GetCell(nextCellID)->GetPointId(1);
Q_UNUSED(p3);
/// 查找到单元中不与初始单元共用的节点所在方向为下次查找方向
if (nextPointIndex == 0)
{
if (p2 == p0)
{
nextPointIndex = 1;
}
else
nextPointIndex = 0;
}
else if (nextPointIndex == 1)
{
if (p1 == p2)
{
nextPointIndex = 1;
}
else
nextPointIndex = 0;
}
}
}
return lines.toList();
}
int FITKPolyDataTool::getCellIDbyPtID(int pt1ID, int pt2ID)
{
vtkSmartPointer<vtkIdList> cellIDs = vtkSmartPointer<vtkIdList>::New();
_poly->GetPointCells(pt1ID, cellIDs);
int cellNum = cellIDs->GetNumberOfIds();
for (int iCell = 0; iCell < cellNum; ++iCell)
{
int cellID = cellIDs->GetId(iCell);
vtkCell* cell = _poly->GetCell(cellID);
int cellPt0ID = cell->GetPointId(0);
int cellPt1ID = cell->GetPointId(1);
if ((pt1ID == cellPt0ID && pt2ID == cellPt1ID) ||
(pt2ID == cellPt0ID && pt1ID == cellPt1ID))
{
return cellID;
}
}
return -1;
}
int FITKPolyDataTool::getNextEdgeLineByAngle(int cellID, int pointIndex, double angle)
{
/// 对输入变量进行有效性判定,由于是私有内部接口,上层函数中进行了校验,本函数无需校验,若需暴露外部使用,需放开
if (!_poly ||
cellID < 0 ||
cellID >= _poly->GetNumberOfCells() ||
(pointIndex != 0 && pointIndex != 1) ||
angle > 90 ||
angle < 0)
{
return -1;
}
/// 构造输入单元向量
double p0[3] = { 0 }, p1[3] = { 0 };
vtkCell* cell = _poly->GetCell(cellID);
int pt1ID = cell->GetPointId(0);
int pt2ID = cell->GetPointId(1);
_poly->GetPoint(pt1ID, p0);
_poly->GetPoint(pt2ID, p1);
double vec1[3] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] };
/// 查找推导方向上,节点所有单元
int ptID = cell->GetPointId(pointIndex);
vtkSmartPointer< vtkIdList > cellIDs = vtkSmartPointer< vtkIdList >::New();
_poly->GetPointCells(ptID, cellIDs);
int cellsNum = cellIDs->GetNumberOfIds();
QMap< double, int > nextLineDegrees;
for (int iCell = 0; iCell < cellsNum; ++iCell)
{
int findCellID = cellIDs->GetId(iCell);
/// 该单元为当前查找单元,跳过查找下一个
if (findCellID == cellID) { continue; }
/// 存在当前查找到单元使用节点相同,顺序相反情况,这种情况不能作为最优解,该单元应因正反面情况后生成的,后续是否可考虑优化掉
vtkCell* cell = _poly->GetCell(findCellID);
int findPt1ID = cell->GetPointId(0);
int findPt2ID = cell->GetPointId(1);
if ((findPt1ID == pt2ID && findPt2ID == pt1ID) ||
(findPt1ID == pt1ID && findPt2ID == pt2ID))
{
continue;
}
/// 构造查找到的线单元向量
double p2[3] = { 0 }, p3[3] = { 0 };
_poly->GetPoint(findPt1ID, p2);
_poly->GetPoint(findPt2ID, p3);
double vec2[3] = { p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2] };
/// 计算两个线单元夹角,不考虑矢量方向,按照最小夹角进行数据记录
double currentAngle = vtkMath::Dot(vec1, vec2) / (vtkMath::Norm(vec1) * vtkMath::Norm(vec2));
currentAngle = acos(currentAngle) * 180 / M_PI;
if (currentAngle >= 90)
{
currentAngle = 180 - currentAngle;
}
nextLineDegrees.insert(currentAngle, findCellID);
}
/// 返回符合角度要求的最小夹角线单元
if (nextLineDegrees.isEmpty()) { return -1; }
double minAngle = nextLineDegrees.firstKey();
if (minAngle < angle)
{
return nextLineDegrees.first();
}
return -1;
}
QList< int > FITKPolyDataTool::getEdgeLinesByDirectionAndAngle(int cellID, double angle, bool endWithCross /*= false */)
{
/// 对输入参数进行合法性检查
QList< int > lookupCellIDs, finishedCellIDs;
if (!_poly || cellID < 0 || cellID >= _poly->GetNumberOfCells() || angle < 0 || angle > 90 || _poly->GetCell(cellID)->GetCellType() != VTK_LINE) { return finishedCellIDs; }
lookupCellIDs.append(cellID);
finishedCellIDs.append(cellID);
while (!lookupCellIDs.isEmpty())
{
int current = lookupCellIDs.takeFirst();
QList< int > ids = getNextEdgeLineByDirectionAndAngle(current, true, angle, endWithCross);
for (int id : ids)
{
if (finishedCellIDs.contains(id) || id < 0) { continue; }
lookupCellIDs.append(id);
finishedCellIDs.append(id);
}
}
/// 向上查找
lookupCellIDs.append(cellID);
while (!lookupCellIDs.isEmpty())
{
int current = lookupCellIDs.takeFirst();
QList< int > ids = getNextEdgeLineByDirectionAndAngle(current, false, angle, endWithCross);
for (int id : ids)
{
if (finishedCellIDs.contains(id) || id < 0) { continue; }
lookupCellIDs.append(id);
finishedCellIDs.append(id);
}
}
return finishedCellIDs;
}
QList< int > FITKPolyDataTool::getNextEdgeLineByDirectionAndAngle(int cellID, bool down, double angle, bool endWithCross /*= false */)
{
/// 对输入变量进行有效性判定,由于是私有内部接口,上层函数中进行了校验,本函数无需校验,若需暴露外部使用,需放开
QMap< int, double > idAngles;
if (!_poly || cellID < 0 || cellID >= _poly->GetNumberOfCells() || angle > 90 || angle < 0) { return idAngles.keys(); }
/// 构造输入单元向量
double vec1[3] = { 0 };
getLineItemVector(cellID, vec1);
/// 查找推导方向上,节点所有单元
vtkCell* cell = _poly->GetCell(cellID);
int ptID = cell->GetPointId(down == true ? 1 : 0);
vtkSmartPointer<vtkIdList> cellIDs = vtkSmartPointer<vtkIdList>::New();
_poly->GetPointCells(ptID, cellIDs);
int cellsNum = cellIDs->GetNumberOfIds();
/// 相交即返回情况判定
if (endWithCross && cellsNum > 2) { return idAngles.keys(); }
for (int iCell = 0; iCell < cellsNum; ++iCell)
{
int findCellID = cellIDs->GetId(iCell);
/// 该单元为当前查找单元,跳过查找下一个
if (findCellID == cellID) { continue; }
vtkCell* cell = _poly->GetCell(findCellID);
int findPt0ID = cell->GetPointId(0);
int findPt1ID = cell->GetPointId(1);
/// 去除反向单元
if ((findPt1ID == ptID && down) || (findPt0ID == ptID && !down)) { continue; }
/// 构造查找到的线单元向量
double vec2[3] = { .0 };
getLineItemVector(findCellID, vec2);
/// 计算两个线单元夹角,不考虑矢量方向,按照最小夹角进行数据记录
double currentAngle = vtkMath::Dot(vec1, vec2) / (vtkMath::Norm(vec1) * vtkMath::Norm(vec2));
currentAngle = acos(currentAngle) * 180 / M_PI;
if (currentAngle <= angle)
{
idAngles.insert(findCellID, currentAngle);
}
}
return idAngles.keys();
}
int FITKPolyDataTool::getPointIDByPointPosition(double pos[3])
{
QVector3D pt(pos[0], pos[1], pos[2]);
return _points.key(pt);
}
QVector< int > FITKPolyDataTool::reuduceSharePointLine(QVector< int > cellIDs)
{
QVector< int > results;
QList< QPair< int, int > > pairs1;
QList< int > pairs2;
for (int current : cellIDs)
{
/// 已与前序线单元构成配对
if (pairs2.contains(current)) { continue; }
int p1Index = _poly->GetCell(current)->GetPointId(0);
int p2Index = _poly->GetCell(current)->GetPointId(1);
bool getCurrentPair = false;
for (int other : cellIDs)
{
if (current == other) { continue; }
int p3Index = _poly->GetCell(other)->GetPointId(0);
int p4Index = _poly->GetCell(other)->GetPointId(1);
/// 两条边共用节点,节点序号相反,其中一个要被去掉
if (p1Index == p4Index && p2Index == p3Index)
{
QPair< int, int > pair(current, other);
pairs1.append(pair);
pairs2.append(current);
pairs2.append(other);
getCurrentPair = true;
results.append(current);
break;
}
}
if (!getCurrentPair)
{
results.append(current);
}
}
return results;
}
QList< CELLPAIR > FITKPolyDataTool::getNeighborCell(int cellID/*, const QList< int >& scanedCellIDs*/)
{
QList< CELLPAIR > neighcells;
vtkSmartPointer<vtkIdList> cellPointIds = vtkSmartPointer<vtkIdList>::New();
_poly->GetCellPoints(cellID, cellPointIds);
QList< int > sigNeighbor{};
for (vtkIdType i = 0; i < cellPointIds->GetNumberOfIds(); i++)
{
vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
idList->InsertNextId(cellPointIds->GetId(i));
// get the neighbors of the cell
vtkSmartPointer<vtkIdList> neighborCellIds = vtkSmartPointer<vtkIdList>::New();
_poly->GetCellNeighbors(cellID, idList, neighborCellIds);
for (vtkIdType j = 0; j < neighborCellIds->GetNumberOfIds(); j++)
{
const int roundID = neighborCellIds->GetId(j);
// Modified by CHT 不通过数据包含关系判断,改用数组直接获取标识。
//@{
int flag = m_scanCellCoPlaneFlag->GetValue(roundID);
if (flag || sigNeighbor.contains(roundID)) continue;
//@}
// if (scanedCellIDs.contains(roundID) || sigNeighbor.contains(roundID)) continue;
neighcells.append(CELLPAIR(roundID, cellID));
sigNeighbor.append(roundID);
}
}
return neighcells;
}
/*bool FITKPolyDataTool::calculateCellNormal(const int cellID, double* normal)
{
if (_poly == nullptr) return false;
vtkCell* cell = _poly->GetCell(cellID);
if (cell == nullptr) return false;
const int nedge = cell->GetNumberOfEdges();
if (nedge <= 2) return false;
auto calEdgeDirection = [&](int p1, int p2, double* dir) -> bool {
if (dir == nullptr) return false;
double pcoor1[3] = { 0 }, pcoor2[3] = { 0 };
_poly->GetPoint(p1, pcoor1);
_poly->GetPoint(p2, pcoor1);
vtkMath::Subtract(pcoor2, pcoor1, dir);
return vtkMath::Norm(dir) > 1e-7;
};
const int np = cell->GetNumberOfPoints();
if (np < 3) return false;
const int p1 = cell->GetPointId(0);
const int p2 = cell->GetPointId(1);
const int p3 = cell->GetPointId(np - 1);
double dir0[3] = { 0 }, dir1[3] = { 0 };
bool ok = calEdgeDirection(p1, p2, dir0);
if (!ok) return false;
ok = calEdgeDirection(p2, p3, dir1);
if (!ok) return false;
vtkMath::Cross(dir0, dir1, normal);
return true;
}*/
bool FITKPolyDataTool::calculateCellNormal(const int cellID, double* normal)
{
vtkCell* cell = _poly->GetCell(cellID);
if (cell == nullptr) return false;
vtkPolygon::ComputeNormal(cell->GetPoints(), normal);
return true;
}
void FITKPolyDataTool::getLineItemVector(int cellID, double(&vec)[3])
{
vtkCell* cell = _poly->GetCell(cellID);
if (!cell || cell->GetCellType() != VTK_LINE) { return; }
double p1[3] = { 0 }, p2[3] = { 0 };
int pt1ID = cell->GetPointId(0);
int pt2ID = cell->GetPointId(1);
_poly->GetPoint(pt1ID, p1);
_poly->GetPoint(pt2ID, p2);
for (int iCnt = 0; iCnt < 3; ++iCnt)
{
vec[iCnt] = p2[iCnt] - p1[iCnt];
}
}
} // namespace Common