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.

444 lines
15 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.

/************************************************************************
文件名Triangulation.h
************************************************************************/
#pragma once
#ifndef AFX_EXT_CLASS
#define AFX_EXT_CLASS Q_DECL_IMPORT
#endif
#include <vector>
#include <list>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <set>
#include <map>
#include "../GBase/point2d.h"
#include "mycurve.h"
using namespace std;
#define SCATTERPOINT_MODE 0 //散点模式
#define LINEARPOINT_MODE 1 //数据线模式
#define POLYGON_MODE 2 //多边形模式
#ifndef ZERO6
#define ZERO6 1e-6
#endif
namespace NVoronoi
{
class AFX_EXT_CLASS CTriangle
{
public:
CTriangle();
CTriangle(const CTriangle& c);
CTriangle& operator= (const CTriangle& c);
~CTriangle();
/** @brief计算得到平面系数A,B,C,D,生成三角平面*/
bool CreatePlane();
void Initial();
/** @brief判断三角形是否为空*/
bool IsEmpty();
/** @brief 求线段与三角平面的交点若无交点返回false*/
bool CrossPoint(CPoint3D& pt1, CPoint3D& pt2,CPoint3D& cspt);
/** @brief 求取指定坐标点Z值若坐标点在三角形外返回false*/
bool GetZValue(double x, double y ,double& z);
/** @brief 判断该z值是否在三角形上*/
bool IsZOnTriangle( double z );
/** @brief 计算三角形外心,即三边中垂线的交点 */
bool GetCircumCenter(CPoint3D& ccpt);
/** @brief 计算三角形的重心,即三条中线的交点*/
bool GetGravityCenter(CPoint3D& gcpt);
/** @brief 计算某一顶点在对边上的垂点*/
bool GetOrthoPoint(CPoint3D& rpt,int npt1,int npt2);
/** @brief 判断曲线与三角形在2D平面上是否有交点*/
int IsCross2D(CMyCurve& curve);
/** @brief 计算曲线与三角形在2D平面上的交点*/
int Cross2D(CMyCurve& curve, vector<CPoint3D>& listCross);
/** @brief 对三角形内部进行点加密, 加密步长step返回加密的点个数*/
int InterInfill(vector<CPoint3D*>& newPtVec, double step);
/** @brief 求取在xy平面上投影的面积*/
double GetArea2D(void);
/** @brief 求取空间三角形面积*/
double GetArea3D(void);
/** @brief 计算三角体的体积,根据闭合线与内部之间的差值计算体积*/
double Volume(double dClosedZ);
/** @brief 找到点在三角形中的位置*/
public:
CRect8 GetRect(void);
void GetRange(CRect8 &range);
BOOL IsInTriangle(CPoint2D& pt) { return IsPtInside2D(pt); } //是否在三角形内部或边线上
//辅助函数
public:
/** @brief 是否包含指定的散点索引号*/
bool IsIncludePoint(int nPointIndex);
/** @brief 判断两个三角形外接立方体是否无交汇 */
bool IsTriBodySeparated(CTriangle& tri);
/** @brief 由已知两顶点序号查找第三个顶点序号,不存在 返回-1*/
int The3rdPoint(int nt1,int nt2);
/** @brief 根据顶点序号刷新顶点指针地址 */
bool RefreshPointers(vector<CPoint3D*>& PointsVec );
/** @brief 叉积函数 */
static double CrossProduct(double& x1, double& y1, double& x2, double& y2);
/** @brief 点积函数 */
static double DotProduct(double& x1, double& y1, double x2, double& y2);
private:
/** @brief 判断两点与面的位置关系1 为同侧, 0 为异侧, 11 为点1在面上22为点2在平面上*/
int IsPtsOneSide(CPoint3D& pt1, CPoint3D& pt2);
/** @brief 将坐标代入三角平面方程求值 */
double EquationValue(double x, double y, double z);
double EquationValue(CPoint3D& pt);
/** @brief 判断点是否位于平面上 */
bool IsPtOnPlane(CPoint3D& pt);
/** @brief 判断点在XOY平面上的投影是否位于三角形在XOY面上投影的内部,返回2表示在边界线上*/
int IsPtInside2D(CPoint2D& pt);
int IsPtInside2D(double x, double y);
/** @brief 判断点是否在空间三角形内部*/
int IsPtInside3D(CPoint3D& pt);
private:
/** @brief 得到三角形各方向极值*/
bool GetExtremeValues();
/** @brief 快速排斥,判断点是否在三角外接立方体外部*/
bool IsPtOutTriBody(CPoint3D& pt);
/** @brief 快速排斥,判断点是否在三角外接正方形外部*/
bool IsPtOutTriSquare(CPoint2D& pt);
/** @brief 判断线段是否在三角形外接立方体外部 */
bool IsSegmentOutTriBody(CPoint3D& pt1, CPoint3D& pt2);
/** @brief 判断线段是否在三角形外接矩形外部 */
bool IsSegmentOutTriSquare(double x1, double y1, double x2, double y2);
//需赋值成员变量
public:
int npt[3]; //顶点序号
CPoint3D* ppt[3]; //顶点指针
int neighbor[3]; //相邻三角形序号
public:
double m_xMin, m_yMin,m_zMin,m_xMax,m_yMax,m_zMax; //三角形各坐标极值
double A,B,C,D; // 三角平面Ax+By+Cz+D = 0 的各项系数 其中A,B,C为平面法向量
};
//为了加速插值的速度,将三角网按照网格进行管理,快速定位较少的三角形,从而减小计算量
class AFX_EXT_CLASS CGridSort
{
public:
CGridSort();
virtual ~CGridSort();
virtual int Create(int numx, int numy, double x0, double y0, double dx, double dy);
double xGrid(double x); //获得网格索引号
double yGrid(double x);
double x(int i);
double y(int j);
double xmin(void) { return P0[0]; }
double ymin(void) { return P0[1]; }
double xmax(void);
double ymax(void);
LONG& xnum(void) { return num[0]; }
LONG& ynum(void) { return num[1]; }
double& dx(void) { return delt[0];}
double& dy(void) { return delt[1];}
CRect8 GetRect(int i, int j);
bool IsIndexX(int i) { if(i<0 || i>=num[0]) return false; else return true; }
bool IsIndexY(int j) { if(j<0 || j>=num[1]) return false; else return true; }
protected:
LONG num[2]; ///< 各方向网络个数
double P0[2]; ///< 原点坐标
double delt[2]; ///< 间隔
};
class AFX_EXT_CLASS CGridSortIndex
: public CGridSort
{
public:
CGridSortIndex();
virtual ~CGridSortIndex();
public:
void AttachTriangulation(void* pData) { m_pTriData = pData; }
virtual int Create(int numx, int numy, double x0, double y0, double dx, double dy);
//三角形
void SplitTriangle(); //划分三角形
int GetVectorTriangle(int i, int j, vector<CTriangle*>& tg);
//获得范围内的指针数组,将去除重复指针
int GetCombinVectorTriangle(vector<CTriangle*>& outVec, int nStartRow, int nStartCol, int nStopRow, int nStopCol);
vector<int>& GetIndexTriangle(int i, int j);
//散点
void SplitPoints(); //划分
int FindPointIndex(CPoint2D& pt, double dError = 1e-3);
int GetVectorPoints(int i, int j, vector<CPoint3D*>& tg);
//获得范围内的指针数组,将去除重复指针
int GetCombinVectorPoints(vector<CPoint3D*>& outVec, int nStartRow, int nStartCol, int nStopRow, int nStopCol);
vector<int>& GetIndexPoint(int i, int j);
protected:
class CGridOne
{
public:
CGridOne() { };
void Empty() { m_vecIndex.clear(); }
vector<int> m_vecIndex;
};
//一行一行连续保存
CGridOne* m_pGridPoints;
CGridOne* m_pGridTriangles;
void* m_pTriData; //CTriangulation*
CGridOne* GetGridPoints(int i, int j);
CGridOne* GetGridTriangle(int i, int j);
};
//三角线段类
class AFX_EXT_CLASS CTEdge
{
public:
CTEdge();
/** @brief 由给定序号生成线段*/
bool Create(int np1,int np2);
bool operator == ( const CTEdge& seg) const;
bool operator < ( const CTEdge& seg) const;
/** @brief 得到第n个点序号 */
int Pt(int n) const;
private:
int npt[2]; ///< 端点序号npt[0]<npt[1]
};
//三角网格类
typedef map<int, int* > LNOMAP; ///< 记录每条数据线对应散点的起始位置
class AFX_EXT_CLASS CTriangulation
{
public:
CTriangulation();
CTriangulation(const CTriangulation& c);
CTriangulation& operator = (const CTriangulation& c);
virtual ~CTriangulation();
/** @brief 清空类*/
virtual void ClearAll();
//读写
public:
/** @brief 将Net按格式存储到dft文件中*/
#ifndef _QT_VERSION
bool WriteFile(char* filename, char* projectname = NULL);
#endif
/** @brief 从dft文件中读取网格*/
bool ReadFile(char* filename);
/** @brief 散点数据读取函数*/
virtual int ReadPoints(vector<double>& X, vector<double>& Y,vector<double>& Z);
virtual int ReadPoints(vector<double>& X, vector<double>& Y,vector<double>& Z, vector<int>& Attr,int attrnum = 1);
int ReadPoints(int num, double* X, double* Y, double* Z);
int SetPoints(vector<CPoint3D*>& pointSet); //将pointSet中的数据移动到当前对象中
void AddPoint(double x, double y, double z);
//操作
public:
/** @brief 生成三角网参数为0表示由散点生成网格参数为1表示由点属性分组生成*/
virtual int Create(int createMode = SCATTERPOINT_MODE);
/** @brief 将三角网中三角形以dfd格式存入文件*/
void WriteTriangles(char* filename);
/** @brief 得到三角形总数目*/
int NumberOfTriangles();
/** @brief 返回散点数目*/
int NumberOfPoints();
/** @brief 求取指定坐标点Z值若坐标点在三角网外返回false*/
bool GetZValue(double x, double y ,double& z);
/** @brief 线段上插值得到Z值点坐标 */
bool GetZPoint( double z,CPoint3D& pt1, CPoint3D& pt2, CPoint3D& pt);
/** @brief 得到与第triNo个三角形相邻且邻边为npt1,npt2的三角形序号*/
int GetNeighborTriangle(int triNo,int npt1, int npt2);
/** @brief 得到所有以npt为顶点的三角形序号存入容器ntri 为初始三角形序号*/
int GetCommonPointTriangles(int npt,list<int>& tNOLST,int ntri = -1);
/** @brief 删除与边界点相关的外围三角形 */
void DeleteOuterTriangles();
/** @brief 对三角网中三角形边线加密加密步长为step,返回加密生成的新点数目 */
int InfillSegPoints(vector<CPoint3D*>& newPtVec, double step);
/** @brief 对三角网三角形内部不含边界加密加密步长为step,返回生成的新点数目 */
int InfillInterPoints(vector<CPoint3D*>& newPtVec, double step);
/** @brief 判断数据点容器是否为空*/
bool IsPointVecEmpty();
/** @brief 判断三角容器是否为空*/
bool IsTriangleVecEmpty();
/** @brief 批量销毁多个三角形,将其指针指向NULL并对m_TriangleList 做顺序上调整 */
bool DeleteMultiTriangles(list<int>& nolst);
/** @brief 重新生成三角网的轮廓线 regenerate outline, 返回轮廓点个数*/
int RegenOutline();
/** @brief 得到边界线 ,失败返回false*/
bool GetOutlineCurve(CMyCurve& curve);
//获取极值brecaltri表示是否重新计算单个三角极值
int GetExtremeValues(bool bRecalTri = false);
//对linkedmap中每一个键结点通过 linkedPtsmap中的有效值进行插值完成插值的结点移除
void InterpolateInvalidNodes(map<int, vector<int> >& linkedPtsMap, double invalidVal);
//对linkedmap中每一个键结点通过 linkedPtsmap中的有效值进行插值完成插值的结点移除
void InterpolateInvalidNodes(map<int, vector<int> >& linkedPtsMap);
/*void InterpolateInvalidNodes(vector<int>& nodeIndexs);*/
//对无效结点进行插值
void InterpolateInvalidNodes(double invalidVal);
//对无效结点插值默认z>1e20为无效点
void InterpolateInvalidNodes(void);
//获取一个与指定结点连接的所有结点
void GetLinkedNodes(int iPt,vector<int>& linkedNodes, bool bUsingSortGrid = true);
//获取一个与指定结点连接的所有结点,iTri为该结点所在的一个三角形
void GetLinkedNodes(int iPt, int iTri, vector<int>& linkedNodes);
/** @brief 所有点z值增加一个固定值dz 避免等值线穿过顶点*/
void IncreasePointZ(double dz);
/** @brief 将三角网中所有边存入容器 m_nTEdgeVec*/
int CreateAllEdges();
/** @brief 返回三角形边的数目*/
int NumberofEdges() { return (int)m_nTEdgeVec.size(); }
/** @brief 返回三角形边数组*/
vector<int>& GetEdges() { return m_nTEdgeVec; }
//删除所有无效三角形 (三个结点值均为无效值) ww 2019-3-14
void DeleteInvalidTriangles(void);
//相交部分
public:
/** @brief m_TriangleList容器中所有空指针,返回空指针个数 */
int DeleteAllNullTriangles();
/** @brief 对网格坐标进行偏移 */
void Offset(double dx, double dy);
/** @brief 根据坐标获得所在的散点索引号,没有选中时返回-1 */
int FindPointIndex(CPoint2D& pt, double dError = 1e-3);
CPoint3D* GetPoint(int nIndex) { return m_PointVec[nIndex]; }
/** @brief 获得包含指定索引散点的三角形,返回包含该点的三角形个数*/
int GetTrianglesIncludePoint(int nIndex, vector<CTriangle*>& outSet);
bool IsInRangeZ(double z0);
long SetValueZ(double a, int nModeSel);
void ScaleZ(double dScale);
int CrossCurve2D(CMyCurve& border, CPointList& listCross);
/** 与CGrid中的定义相同采用反距离加权+平均法计算*/
void Smooth(double smooth_coef = 1.0);
//插入点生成三角形
protected:
/** @brief 找到最左侧三角形顶点,返回该顶点序号,以及所属三角形序号 */
bool GetMinVertex(int& nVertex,int& nTri);
/** @brief 由已知线段和初始点得到一条闭合环,存入destClosureVec中*/
bool GetClosure(int nFristPt,list<CTEdge*>& sourEdgeLst, vector<int>& destClosureVec);
bool GetZValue(vector<CTriangle*>& tg, double x, double y ,double& z);
/** @brief 获得包含指定索引散点的三角形,返回包含该点的三角形个数*/
int GetTrianglesIncludePoint(int nIndex, vector<CTriangle*>& inSet, vector<CTriangle*>& outSet);
/** @brief 计算空间线段与三角网的交点 */
bool CrossPoint(CPoint3D& pt1, CPoint3D& pt2, CPoint3D& cspt, vector<CTriangle*>& tg);
private:
/** @brief 由相邻线生成三角网,线号存在m_pointattributevec中*/
int CreateByLine();
/** &brief 在线号为lno的多边形内部生成三角网*/
/*int CreateInPolygon(int lno = 0);*/
/** @brief 生成子网格, bno eno代表首尾数据点序号*/
int AddSubNet(int bno, int eno, int createMode );
/** @brief 将新生成的三角形与之前的三角网通过数据线lno建立相邻关系*/
int SetNeighbor(int btr, int etr,int lno);
/** @brief 两个三角形之间建立相邻关系*/
int SetNeighbor(int ntr1, int ntr2);
/** @brief 切除函数,CutMode为切除方式0为外切1为内切*/
BOOL CutNet(CMyCurve& border,int CutMode);
/** @brief 判断点是否处在包络上*/
bool IsPtOnOutline(int ptNo);
/** @brief 销毁三角网中单个三角形将其指针指向NULL */
bool NullOneTriangle(int triNo);
/** @brief 判断线段是否在三角网外接立方体之外,且不可能穿过*/
bool IsSegmentOutNetBody(CPoint3D& pt1, CPoint3D& pt2);
/** @brief 判断三角形是否在网格立体空间外 */
bool IsTriOutNetBody(CTriangle& tri);
/** @brief 删除散点数据*/
void DeletePointList();
/** @brief 删除三角数据*/
void DeleteTriangleList();
/** @brief 判断两个三角网所处立体空间是否不相交 */
bool IsNetBodySeparated(CTriangulation& tNet);
//由线生成三角形相关函数
private:
/** @brief由线号精简三角网 */
void SimplifyByLineNo();
/** @brief由线号精简部分三角网 */
void SimplifyByLineNo(int btr, int etr);
/** @brief 处理同序号三角形,和相邻三角形重新拆分*/
bool RebuildSameLineTriangles();
/** @brief 重新构建两个相邻三角形交换对角线npt1,npt2为相邻边 bVerifyNewEdgeInner为是否验证新边在四边形内部*/
bool RebuildTwoTriangles(int ntr1, int ntr2, int npt1, int npt2, bool bVerifyNewEdgeInner = true);
/** @brief 判断两个点是否共线号且相邻*/
bool IsLinearNeighbor(const int& npt1, const int& npt2);
/** @brief 生成各条线起始序号查询map*/
bool CreateLineDataMap();
/** @brief 删除现有起始序号查询map*/
void DeleteLineDataMap();
//成员变量
public:
/** @brief 散点坐标指针数组*/
vector<CPoint3D*> m_PointVec;
/** @brief 单点属性个数*/
int m_NumofPointAttributes;
/** @brief 散点属性数组*/
vector<int> m_PointAttributeVec;
/** @brief 生成的三角平面指针数组*/
vector<CTriangle*> m_TriangleVec;
/** @brief 三角网各坐标极大极小值 */
CPoint3D m_ptMax;
CPoint3D m_ptMin;
/** @brief 三角网凸包上的数据点,首尾连接 */
vector<int> m_nOutlinePoints;
void CreateGridSort();//生成快速网格管理器
//私有变量
private:
CGridSortIndex m_gridSort; ///< 仅为了加速获得相应的三角形
vector<int> m_nTEdgeVec; ///< 存储三角网格中的所有边端点序号01代表第一条
list<int> m_SameLineTriNoLst; ///< 存储3个顶点线号相同的三角形 容器
LNOMAP m_lmp; ///< 记录每条线起始点序号: key 线号, value 序号[2]
};
/** @brief 对线段进行加密加密后新生成的的点集存入CPoint3D容器中*/
int Infill(vector<CPoint3D* >& newPtVec,CPoint3D& pt1, CPoint3D& pt2,double step);
}; //namespace NTriangle
using namespace NVoronoi;