Files
envi-code/SourceCode/Code2026/AdsXRx/aecroof.cpp
T
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

672 lines
20 KiB
C++

#include "stdafx.h"
#include "aecroof.h"
#include "XGlobalFunc.h"
#include "XScreenDc.h"
#include "XCurveInline.h"
static int g_nDbgFlag=0;
//extern int DePeriod(int nPeriod, int nIndex);
/////////////////////////////////////
// 屋顶数据类
/////////////////////////////////////
//////////////////////////////////
// 求三阶行列式
double MatrixValue(double a[3][3])
{
double nRes = a[0][0]*a[1][1]*a[2][2] + a[0][1]*a[1][2]*a[2][0] + a[0][2]*a[1][0]*a[2][1]
- a[0][2]*a[1][1]*a[2][0] - a[0][1]*a[1][0]*a[2][2] - a[0][0]*a[1][2]*a[2][1];
return nRes;
}
///////////////////////////////////////
// 求三个面的交点
int IntersectWith(const XPlanePara &plan1, const XPlanePara &plan2,
const XPlanePara &plan3, XPoint &ptInter)
{
double a[3][3]={
{plan1.nParaA, plan1.nParaB, plan1.nParaC},
{plan2.nParaA, plan2.nParaB, plan2.nParaC},
{plan3.nParaA, plan3.nParaB, plan3.nParaC},
};
double nDelta = MatrixValue(a);
if(fabs(nDelta)<1.0E-5)
return 0;
double a1[3][3] = {
{-plan1.nParaD, plan1.nParaB, plan1.nParaC},
{-plan2.nParaD, plan2.nParaB, plan2.nParaC},
{-plan3.nParaD, plan3.nParaB, plan3.nParaC},
};
double a2[3][3] = {
{plan1.nParaA, -plan1.nParaD, plan1.nParaC},
{plan2.nParaA, -plan2.nParaD, plan2.nParaC},
{plan3.nParaA, -plan3.nParaD, plan3.nParaC},
};
double a3[3][3] = {
{plan1.nParaA, plan1.nParaB, -plan1.nParaD},
{plan2.nParaA, plan2.nParaB, -plan2.nParaD},
{plan3.nParaA, plan3.nParaB, -plan3.nParaD},
};
ptInter.x = MatrixValue(a1)/nDelta;
ptInter.y = MatrixValue(a2)/nDelta;
ptInter.z = MatrixValue(a3)/nDelta;
return 1;
}
/////////////////////////////////////////////////
// 求线和面的交点,考虑了线是否为无限长
int IntersectWith(const XLine &ln, const XPlanePara &plan, XPoint &res)
{
if(!CT_inter_line_plan1(ln.StartPoint(), ln.EndPoint(),
(const plan_para *)&plan, res))
return 0;
if(ln.GetLineFlag()==LS_FINITE) {
int nFlag=(res&ln);
if(nFlag==PR_INSIDE || nFlag==PR_ONPT1 || nFlag==PR_ONPT2)
return 1;
else return 0;
}
return 1;
}
//////////////////////////////////////////////////
// XAecPlan: 空间几何平面的类
//////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// 平面内一点及法向量来初始化平面
int XPlanePara::InitPlane(const XPoint &pt0, const XVector3D &vt)
{
ASSERT(sizeof(XPlane)==sizeof(plan_para));
if(!CT_plan_equation(pt0, vt, (plan_para *)this))
return RTERROR;
return RTNORM;
}
int XPlanePara::InitPlane(const XPoint &pt1, const XPoint &pt2, const XPoint &pt3)
{
XPoint vt;
if(!CT_vector_plan3p(pt1, pt2, pt3, vt))
return RTERROR;
ASSERT(sizeof(XPlanePara)==sizeof(plan_para));
if(!CT_plan_equation(pt1, vt, (plan_para *)this))
return RTERROR;
return RTNORM;
}
//////////////////////////////////////////////////
// XAecPlan: 坡屋顶几何类
//////////////////////////////////////////////////
/////////////////////////////////////////////////////
// 用底面和倾角来初始化等坡屋顶
/*
XAecRoof::XAecRoof(const XPoly2D &poly, double nSlant)
{
InitRoof(poly, nSlant);
}
*/
//////////////////////////////////////////////////////
// 用底面和倾角初始化等坡屋顶
int XAecRoof::InitRoof(const XPoly2D &poly, double nSlant)
{
m_lstEdges.Reset();
m_lstSlopeFaces.Reset();
poly.Disperse(m_polyBoundry, 20);
for(int i=0; i<m_polyBoundry.Length(); i++) {
m_lstEdges.Append(new XRoofEdgeCompact(*m_polyBoundry[i], nSlant));
}
m_nBottomElevation = poly[0].z;
//m_polyBoundry = (XPoly2D &)poly;
return RTNORM;
}
///////////////////////////////////////////////////
// 对象的赋值
/*
XAecRoof & XAecRoof::operator = (const XAecRoof &src)
{
m_lstEdges.Reset();
m_lstSlopeFaces.Reset();
m_lstRidges.Reset();
m_nBottomElevation = src.m_nBottomElevation;
for(int i=0; i<src.GetTotalEdge(); i++) {
m_lstEdges.Append(new XRoofEdgeCompact(src.m_lstEdges[i]));
}
for(i=0; i<src.m_lstSlopeFaces.Length(); i++) {
const XPointList &srcPts=src.m_lstSlopeFaces[i];
m_lstSlopeFaces.Append(new XPointList(srcPts));
}
for(i=0; i<src.m_lstRidges.Length(); i++) {
m_lstRidges.Append(new XLine(src.m_lstRidges[i]));
}
m_polyBoundry = src.m_polyBoundry;
return *this;
}
*/
////////////////////////////////////////
// 用边的数据来建立/更新底面的数据
int XAecRoof::InitBottomPolyByEdge()
{
m_polyBoundry.Reset();
m_polyBoundry.SetFlag(1);
for(int i=0; i<m_lstEdges.Length(); i++) {
m_polyBoundry.AppendNode(m_lstEdges[i]->m_ptVertex);
}
return RTNORM;
}
////////////////////////////////////////
// 计算屋顶各个坡面
int XAecRoof::Calculate()
{
m_lstSlopeFaces.Reset();
m_lstRidges.Reset();
for(int n=0; n<GetTotalEdge(); n++) {
XLine lnRidge;
if(GetRidge(n, lnRidge, FALSE)==RTNORM)
m_lstRidges.Append(new XLine(lnRidge));
else {
m_lstSlopeFaces.Reset();
m_lstRidges.Reset();
return RTERROR;
}
}
for(int i=0; i<m_lstEdges.Length(); i++) {
XPointList *pSlopeFace = new XPointList;
int nRet=CalculateSlopeFace(i, *pSlopeFace);
if(nRet==RTNORM) {
m_lstSlopeFaces.Append(pSlopeFace);
} else {
delete pSlopeFace;
m_lstSlopeFaces.Reset();
return RTERROR;
}
}
return RTNORM;
}
//extern _T("C") void get_matrix(ads_point pt1,ads_point pt2,ads_point pt3,
// ads_matrix tran_mt);
//////////////////////////////////////
// 画出所有的斜面, 调试用
// Status: 目前没有用到
int XAecRoof::DrawSlopeFaces()
{
int nSlopeNum=m_lstSlopeFaces.Length();
for(int i=0; i<nSlopeNum; i++) {
XPointList *pPoly=m_lstSlopeFaces[i];
XPointList &ptList=*pPoly;
int nTotalVertex=ptList.Length();
for(int i=0; i<nTotalVertex; i++) {
int nNext=i+1;
if(nNext==nTotalVertex) nNext=0;
XLine ln(*ptList[i], *ptList[nNext]);
ln.Make();
}
#if 0
//XPolygonEx poly(*(XPoly*)pPoly);
if(!poly) {
adsout << _T("\nerror");
return RTNORM;
}
assert(poly.Length()>=3);
ads_matrix matTran;
get_matrix(*poly[0], *poly[1], *poly[2], matTran);
poly.TransUCS(matTran);
poly.Compress();
XTrianglePface lstTris;
if(poly.Trianglize(0, lstTris)==RTNORM) {
ads_matrix aMatTran; //逆变换
for(int n=0; n<lstTris.Length(); n++) {
XTriangle *triangle=lstTris[n];
triangle->vertex1.TransformBy(aMatTran);
triangle->vertex2.TransformBy(aMatTran);
triangle->vertex3.TransformBy(aMatTran);
}
lstTris.MakePolyface();
} else {
adsout << _T("error");
return RTERROR;
}
#endif
}
return RTNORM;
}
////////////////////////////////////////////////////////////////////////
// 功能: 求当前坡面的下一个屋脊线
// nThis, thisPlane -- 当前斜面的全局序号和当前斜面
// nLast, lastPlane -- 最近的一个轮面, 确定一待定下一个顶点, nLast>nThis
// ptLast -- 已经确定的前一个顶点,在lastPlane上
// pNextIndex, nextPlane -- 下一个轮面
// ptNext -- 待确定的点
// 如果返回RTERROR,则找不到
// 如果pNextIndex == nThis+nEdgeNum-1, 则下回不用再轮了, 因为下次将回到起点
int XAecRoof::GetNext(int nThis, const XPlanePara &thisPlane,
int nLast, const XPlanePara &lastPlane, const XPoint &ptLast,
int *pNextIndex, XPlanePara &nextPlane, XPoint &ptNext)
{
int nTotalEdge = GetTotalEdge();
ASSERT(nLast<nThis+nTotalEdge-1);
XPoint ptNext1;
XPlanePara nextPlane1;
int nNextIndex=0;
int bFindNext=0;
for(int i=nLast+1; i<nThis+nTotalEdge; i++) {
XPlanePara iPlane;
if(GetPlane(i, iPlane)!=RTNORM)
return RTERROR;
XPoint ptIntM;
if(!IntersectWith(thisPlane, lastPlane, iPlane, ptIntM))
continue;
///////////////////////////////////////
//验证交点的有效性:
// 1. 高于在底面
// 2. 在三个面的棱线内
// 3. 在边界内
if(ptIntM.z < m_nBottomElevation) //交点在底下,忽略
continue;
XPoint ptOnBottom=ptIntM;
ptOnBottom.z = m_nBottomElevation;
XCurveSegment lnRidgeStart, lnRidgeEnd;
lnRidgeStart.SetLineFlag(LS_INFINITE);
lnRidgeEnd.SetLineFlag(LS_INFINITE);
int indexArray[3]={nThis, nLast, i};
int bInsideLimits=TRUE;
for(int k=0; k<3; k++) {
if(GetRidge(indexArray[k], lnRidgeStart, 1)!=RTNORM ||
GetRidge(indexArray[k]+1, lnRidgeEnd, 1)!=RTNORM)
return RTERROR;
int prFlag=(ptOnBottom&lnRidgeStart);
int sideFlag=lnRidgeStart.OnWhichSide(ptOnBottom);
if(prFlag==PR_OUTSIDE && sideFlag==OFFSET_LEFT) {
bInsideLimits=FALSE;
break;
}
prFlag=(ptOnBottom&lnRidgeEnd);
sideFlag=lnRidgeEnd.OnWhichSide(ptOnBottom);
if(prFlag==PR_OUTSIDE && sideFlag==OFFSET_RIGHT) {
bInsideLimits=FALSE;
break;
}
}
if(!bInsideLimits)
continue;
if((ptOnBottom&m_polyBoundry)==PR_OUTSIDE)
continue;
if(!bFindNext) {
ptNext1=ptIntM;
nNextIndex=i;
nextPlane1 = iPlane;
bFindNext=TRUE;
} else if(ads_distance(ptLast, ptIntM)<ads_distance(ptLast, ptNext1)) {
ptNext1 = ptIntM;
nNextIndex=i;
nextPlane1 = iPlane;
}
}
if(!bFindNext)
return RTERROR;
*pNextIndex = nNextIndex;
nextPlane = nextPlane1;
ptNext = ptNext1;
return RTNORM;
}
/////////////////////////////////////////////////////////////
// 计算第n个坡面
int XAecRoof::CalculateSlopeFace(int n, XPointList &lstVertexes)
{
XScreenDc dc(7, 1);
XRoofEdge edge;
XPlanePara thisPlane;
if(GetEdge(n, edge)!=RTNORM || GetPlane(n, thisPlane)!=RTNORM)
return RTERROR;
lstVertexes.Reset();
lstVertexes.Append(new XPoint(edge.StartPoint()));
lstVertexes.Append(new XPoint(edge.EndPoint()));
int nTotalEdge=m_lstEdges.Length();
XPlanePara lastPlane; //初始化为底面
if(GetPlane(n+1, lastPlane)!=RTNORM)
return RTERROR;
//lastPlane.InitPlane(XPoint(0.0,0.0,nBottomElev), XVector3D(0,0,1));
//当前待定直线=thisPlane*lastPlane
int nLastIndex=n+1;
XPoint ptLast=edge.EndPoint();
while(1) {
XPoint ptNext;
XPlanePara nextPlane;
int nNextIndex;
if(GetNext(n, thisPlane, nLastIndex, lastPlane, ptLast, &nNextIndex, nextPlane, ptNext)!=RTNORM)
return RTERROR;
int nCurVertexNum=lstVertexes.Length();
//lstVertexes.Append(ptNext);
/*
XLine curLine(ptLast, ptNext, LS_FINITE); //最近的线段
for(int j=0; j<nCurVertexNum-2; j++) { //判自交叉时,不能同
XLine ln(*lstVertexes[j], *lstVertexes[j+1], LS_FINITE);
XPoint ptInter;
if(curLine.Intersection(ln, ptInter)) { //自交叉
for(int k=nCurVertexNum-2; k>=j+1; k--)
lstVertexes.Remove(k);
lstVertexes.Append(new XPoint(ptInter));
break;
}
}*/
lstVertexes.Append(new XPoint(ptNext));
if(g_nDbgFlag) {
dc << lstVertexes;
if(ads_getint(_T("\nStep: "), &nNextIndex)==RTCAN)
return RTCAN;
ads_redraw(NULL,0);
}
if(nNextIndex == n+nTotalEdge-1) // 最后一边
break;
lastPlane=nextPlane;
nLastIndex=nNextIndex;
ptLast = ptNext;
}
if(g_nDbgFlag) {
int nTemp;
dc.Draw(lstVertexes, 1);
if(ads_getint(_T("\nFinal Step: "), &nTemp)==RTCAN)
return RTCAN;
ads_redraw(NULL,0);
}
return RTNORM;
}
///////////////////////////////////////////////////
// 取得第n个坡面的几何平面
int XAecRoof::GetPlane(int n, XPlanePara &thisPlane) const
{
int nTotalEdge = GetTotalEdge();
n=DePeriod(nTotalEdge, n);
XRoofEdge edge;
if(GetEdge(n, edge)!=RTNORM)
return RTERROR;
XLine lnLeft=edge.Offset(-1000.0);
double nHeight=1000.0*tan(edge.m_nSlope);
XPoint pt3=lnLeft.StartPoint();
pt3.z += nHeight;
if(thisPlane.InitPlane(edge.StartPoint(), edge.EndPoint(), pt3)!=RTNORM)
return RTERROR;
return RTNORM;
}
/////////////////////////////////////////////////////////////////
// 取得第n条棱(屋脊线)
// bOnBottom -- 是否投影到底面
int XAecRoof::GetRidge(int n, XLine &lnRidge, int bQuickGet) const
{
if(bQuickGet) {
n = DePeriod(GetTotalEdge(), n);
ASSERT(n<m_lstRidges.Length());
lnRidge = m_lstRidges[n];
return RTNORM;
}
BOOL bOnBottom=TRUE;
XPlanePara prevPlane, curPlane;
if(GetPlane(n-1, prevPlane)!=RTNORM ||
GetPlane(n, curPlane)!=RTNORM) {
return RTERROR;
}
XPlanePara topPlane, botPlane;
botPlane.InitPlane(XPoint(0.0,0.0,m_nBottomElevation), XVector3D(0,0,1));
topPlane.InitPlane(XPoint(0.0,0.0,m_nBottomElevation+1000.0), XVector3D(0,0,1));
XPoint pt1, pt2;
if(!IntersectWith(prevPlane, curPlane, botPlane, pt1) ||
!IntersectWith(prevPlane, curPlane, topPlane, pt2) )
return RTERROR;
if(bOnBottom) {
pt1.z = pt2.z = m_nBottomElevation;
}
lnRidge.StartPoint() = pt1;
lnRidge.EndPoint() = pt2;
return RTNORM;
}
///////////////////////////////////////////////
// 取得第n条边
int XAecRoof::GetEdge(int n, XRoofEdge &edge) const
{
int nNext=n+1;
int nEdgeNum=m_lstEdges.Length();
n = DePeriod(nEdgeNum, n);
nNext = DePeriod(nEdgeNum, nNext);
edge.StartPoint() = m_lstEdges[n].m_ptVertex;
edge.m_nSlope = m_lstEdges[n].m_nSlope;
edge.EndPoint() = m_lstEdges[nNext].m_ptVertex;
return RTNORM;
}
//////////////////////////////////////////
// 求所有坡面的总面积
double XAecRoof::GetTotalSurfaceArea() const
{
double nArea = 0.0;
for(int i=0; i<m_lstSlopeFaces.Length(); i++) {
nArea += GetSlopeArea(i);
}
return nArea;
}
//////////////////////////////////////////
// 求第n个斜面的面积
double XAecRoof::GetSlopeArea(int n) const
{
//return 0.0;
if(!m_lstSlopeFaces.Length())
return 0.0;
ASSERT(n<m_lstSlopeFaces.Length());
const XPointList &slopeFace=m_lstSlopeFaces[n];
ASSERT(slopeFace.Length()>=3);
double nSlopeAngle=m_lstEdges[n].m_nSlope;
ads_matrix matTran;
get_matrix(slopeFace[0], slopeFace[1], slopeFace[2], matTran);
XPoly2D poly(1);
for(int i=0; i<slopeFace.Length(); i++) {
XPoint ptVertex = slopeFace[i];
//ptVertex.z=0;
ptVertex.TransformBy(matTran);
poly.AppendNode(ptVertex);
}
double nRes=poly.Area();
//ASSERT(nSlopeAngle>0.0);
//double nRes=((XPoly &)slopeFace).Area()/cos(nSlopeAngle);
return nRes;
}
//////////////////////////////////////////////////////////////////////////
// 求面的描述
// 由调用函数负责释放点表和面表
typedef DList<int> IntList;
int XAecRoof::GetSurfaceData(int *nVerticeNum, XPoint * &pVerticeList,
int *pFaceListLen, Adesk::Int32 * &pFaceList,
Adesk::UInt8 * &pEdgeVisArray) const
{
int nTotalFaceNum=m_lstSlopeFaces.Length();
if(!nTotalFaceNum)
return RTERROR;
int nTotalEdge=GetTotalEdge();
XPointList lstVertices;
DList<IntList> lstFaces;
DList<IntList> lstEdgeVis; //边的可见性
int nFaceListLen=0;
int nEdgeListLen=0;
for(int i=0; i<nTotalFaceNum; i++) {
if(nTotalFaceNum==nTotalEdge &&
fabs(m_lstEdges[i].m_nSlope-PI/2.0)<_angSnap)
continue;
const XPointList &slopeFace = m_lstSlopeFaces[i];
ASSERT(slopeFace.Length()>=3);
DList<int> *pFace = new DList<int>;
DList<int> *pEdge = new DList<int>;
int nLastVertex=0;
int nFirstVertexIndex=0;
double nPreSlope=m_lstEdges[DePeriod(nTotalEdge, i-1)].m_nSlope;
double nNextSlope=m_lstEdges[DePeriod(nTotalEdge, i+1)].m_nSlope;
for(int j=0; j<slopeFace.Length(); j++) {
int nCurIndex=0;
const XPoint &ptCur=slopeFace[j];
if(lstVertices.FindPoint(ptCur)) {
nCurIndex=lstVertices.CurPosition();
} else {
nCurIndex=lstVertices.Length();
lstVertices.Append(new XPoint(ptCur));
}
pFace->Append(new int(nCurIndex));
if(j==0) nFirstVertexIndex = nCurIndex;
else if(j==1) { //第2个顶点确定第一边, 底边
pEdge->Append(new int(m_bBotVisible? kAcGiVisible : kAcGiInvisible));
} else { //否则升序的边为可见
if(fabs(nPreSlope-PI/2)<_angSnap || fabs(nNextSlope-PI/2)<_angSnap) {
pEdge->Append(new int(kAcGiVisible));
} else {
if(nCurIndex>nLastVertex) pEdge->Append(new int(kAcGiVisible));
else pEdge->Append(new int(kAcGiInvisible));
}
}
nLastVertex = nCurIndex;
}
if(fabs(nPreSlope-PI/2)<_angSnap || fabs(nNextSlope-PI/2)<_angSnap) {
pEdge->Append(new int(kAcGiVisible));
} else {
//最后一边 nLastVertex->nFirstVertexIndex
if(nFirstVertexIndex>nLastVertex) pEdge->Append(new int(kAcGiVisible));
else pEdge->Append(new int(kAcGiInvisible));
}
lstFaces.Append(pFace);
lstEdgeVis.Append(pEdge);
nEdgeListLen += pEdge->Length();
nFaceListLen += slopeFace.Length()+1;
}
*nVerticeNum = lstVertices.Length();
pVerticeList = new XPoint[*nVerticeNum];
for(i=0; i<*nVerticeNum; i++) {
pVerticeList[i]=*lstVertices[i];
}
*pFaceListLen = nFaceListLen;
pFaceList = new Adesk::Int32[nFaceListLen];
Adesk::Int32 *pInt=pFaceList;
for(i=0; i<lstFaces.Length(); i++) {
DList<int> *pFace=lstFaces[i];
*pInt = pFace->Length();
pInt ++;
for(int j=0; j<pFace->Length(); j++) {
*pInt = *(*pFace)[j];
pInt ++;
}
}
pEdgeVisArray = new Adesk::UInt8[nEdgeListLen];
Adesk::UInt8 *pUInt=pEdgeVisArray;
for(i=0; i<lstEdgeVis.Length(); i++) {
DList<int> *pEdge=lstEdgeVis[i];
for(int j=0; j<pEdge->Length(); j++) {
*pUInt = *(*pEdge)[j];
pUInt ++;
}
}
return RTNORM;
}
//////////////////////////////////////////////////////////////////////////
// 求边的描述
// 由调用函数负责释放点表和面表
static int CompareForFindNode(const XIntDotPair *p1, const void *p2)
{
const XIntDotPair *pp2 = (const XIntDotPair *)p2;
if((p1->nFrom==pp2->nFrom && p1->nTo==pp2->nTo) ||
(p1->nFrom==pp2->nTo && p1->nTo==pp2->nFrom))
return 0;
return 1;
}
int XAecRoof::GetEdgeData(XPointList &lstVertices, DList<XIntDotPair> &lstEdgeData) const
{
int nTotalFaceNum=m_lstSlopeFaces.Length();
if(!nTotalFaceNum)
return RTERROR;
for(int i=0; i<nTotalFaceNum; i++) {
const XPointList &slopeFace = m_lstSlopeFaces[i];
ASSERT(slopeFace.Length()>=3);
const XPoint &ptLast=slopeFace[0];
int nLast=0;
if(lstVertices.FindPoint(ptLast)) {
nLast=lstVertices.CurPosition();
} else {
nLast=lstVertices.Length();
lstVertices.Append(new XPoint(ptLast));
}
int nFirst=nLast;
for(int j=1; j<=slopeFace.Length(); j++) {
int nCurIndex=0;
if(j==slopeFace.Length()) {
nCurIndex = nFirst;
} else {
const XPoint &ptCur=slopeFace[j];
if(lstVertices.FindPoint(ptCur)) {
nCurIndex=lstVertices.CurPosition();
} else {
nCurIndex=lstVertices.Length();
lstVertices.Append(new XPoint(ptCur));
}
}
XIntDotPair edge(nLast, nCurIndex);
if(!lstEdgeData.FindNode(&edge, CompareForFindNode))
lstEdgeData.Append(new XIntDotPair(edge));
nLast = nCurIndex;
}
}
return RTNORM;
}