/************************************************************************ 文件名:Triangulation.h ************************************************************************/ #pragma once #ifndef AFX_EXT_CLASS #define AFX_EXT_CLASS Q_DECL_IMPORT #endif #include #include #include #include #include #include #include #include #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& listCross); /** @brief 对三角形内部进行点加密, 加密步长step,返回加密的点个数*/ int InterInfill(vector& 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& 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& tg); //获得范围内的指针数组,将去除重复指针 int GetCombinVectorTriangle(vector& outVec, int nStartRow, int nStartCol, int nStopRow, int nStopCol); vector& GetIndexTriangle(int i, int j); //散点 void SplitPoints(); //划分 int FindPointIndex(CPoint2D& pt, double dError = 1e-3); int GetVectorPoints(int i, int j, vector& tg); //获得范围内的指针数组,将去除重复指针 int GetCombinVectorPoints(vector& outVec, int nStartRow, int nStartCol, int nStopRow, int nStopCol); vector& GetIndexPoint(int i, int j); protected: class CGridOne { public: CGridOne() { }; void Empty() { m_vecIndex.clear(); } vector 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] 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& X, vector& Y,vector& Z); virtual int ReadPoints(vector& X, vector& Y,vector& Z, vector& Attr,int attrnum = 1); int ReadPoints(int num, double* X, double* Y, double* Z); int SetPoints(vector& 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& tNOLST,int ntri = -1); /** @brief 删除与边界点相关的外围三角形 */ void DeleteOuterTriangles(); /** @brief 对三角网中三角形边线加密,加密步长为step,返回加密生成的新点数目 */ int InfillSegPoints(vector& newPtVec, double step); /** @brief 对三角网三角形内部(不含边界)加密,加密步长为step,返回生成的新点数目 */ int InfillInterPoints(vector& newPtVec, double step); /** @brief 判断数据点容器是否为空*/ bool IsPointVecEmpty(); /** @brief 判断三角容器是否为空*/ bool IsTriangleVecEmpty(); /** @brief 批量销毁多个三角形,将其指针指向NULL,并对m_TriangleList 做顺序上调整 */ bool DeleteMultiTriangles(list& nolst); /** @brief 重新生成三角网的轮廓线 regenerate outline, 返回轮廓点个数*/ int RegenOutline(); /** @brief 得到边界线 ,失败返回false*/ bool GetOutlineCurve(CMyCurve& curve); //获取极值,brecaltri表示是否重新计算单个三角极值 int GetExtremeValues(bool bRecalTri = false); //对linkedmap中每一个键结点通过 linkedPtsmap中的有效值进行插值,完成插值的结点移除 void InterpolateInvalidNodes(map >& linkedPtsMap, double invalidVal); //对linkedmap中每一个键结点通过 linkedPtsmap中的有效值进行插值,完成插值的结点移除 void InterpolateInvalidNodes(map >& linkedPtsMap); /*void InterpolateInvalidNodes(vector& nodeIndexs);*/ //对无效结点进行插值 void InterpolateInvalidNodes(double invalidVal); //对无效结点插值,默认z>1e20为无效点 void InterpolateInvalidNodes(void); //获取一个与指定结点连接的所有结点 void GetLinkedNodes(int iPt,vector& linkedNodes, bool bUsingSortGrid = true); //获取一个与指定结点连接的所有结点,iTri为该结点所在的一个三角形 void GetLinkedNodes(int iPt, int iTri, vector& linkedNodes); /** @brief 所有点z值增加一个固定值dz 避免等值线穿过顶点*/ void IncreasePointZ(double dz); /** @brief 将三角网中所有边存入容器 m_nTEdgeVec*/ int CreateAllEdges(); /** @brief 返回三角形边的数目*/ int NumberofEdges() { return (int)m_nTEdgeVec.size(); } /** @brief 返回三角形边数组*/ vector& 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& 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& sourEdgeLst, vector& destClosureVec); bool GetZValue(vector& tg, double x, double y ,double& z); /** @brief 获得包含指定索引散点的三角形,返回包含该点的三角形个数*/ int GetTrianglesIncludePoint(int nIndex, vector& inSet, vector& outSet); /** @brief 计算空间线段与三角网的交点 */ bool CrossPoint(CPoint3D& pt1, CPoint3D& pt2, CPoint3D& cspt, vector& 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 m_PointVec; /** @brief 单点属性个数*/ int m_NumofPointAttributes; /** @brief 散点属性数组*/ vector m_PointAttributeVec; /** @brief 生成的三角平面指针数组*/ vector m_TriangleVec; /** @brief 三角网各坐标极大极小值 */ CPoint3D m_ptMax; CPoint3D m_ptMin; /** @brief 三角网凸包上的数据点,首尾连接 */ vector m_nOutlinePoints; void CreateGridSort();//生成快速网格管理器 //私有变量 private: CGridSortIndex m_gridSort; ///< 仅为了加速获得相应的三角形 vector m_nTEdgeVec; ///< 存储三角网格中的所有边端点,序号0,1代表第一条 list m_SameLineTriNoLst; ///< 存储3个顶点线号相同的三角形 容器 LNOMAP m_lmp; ///< 记录每条线起始点序号: key 线号, value 序号[2] }; /** @brief 对线段进行加密,加密后新生成的的点集存入CPoint3D容器中*/ int Infill(vector& newPtVec,CPoint3D& pt1, CPoint3D& pt2,double step); }; //namespace NTriangle using namespace NVoronoi;