//-----------------------------------------------------------------------------+ // Copyright (C), 1998-2007, SH Software Co. Ltd. // = FileName : XArcWallUnit.cpp // = Version : ver2.0 // = Author : zjq // = CreateDate : 2002-09-09 // = Description: 类的定义 // = Maintainers: // //-----------------------------------------------------------------------------+ #include "StdAfx.h" #include "XArcWallUnit.h" #include "XTrianglePface.h" #include "XPrivateGlobalFunc.h" static int CompareDouble(double x1, double x2) { if (fabs(x1 - x2) < _DIST_SNAP) { return 0; } if (x1 < x2) { return -1; } return 1; } static int ComparePointByX(const XPoint *p1, const XPoint *p2) { if (fabs(p1->x - p2->x) < _DIST_SNAP) { return 0; } if (p1->x < p2->x) { return -1; } return 1; } XArcWallUnit::XArcWallUnit() : lstHoles(FALSE),xWallBeg(0),xHoleBeg(0),xHoleEnd(0),nRadius(0) { } XArcWallUnit::XArcWallUnit(double rad, double wBeg, double hBeg, double hEnd) : lstHoles(FALSE), nRadius(rad), xWallBeg(wBeg), xHoleBeg(hBeg), xHoleEnd(hEnd) { } XArcWallUnit::~XArcWallUnit() { } // 对一系列3dface进行镶嵌 // 对lstFaces,根据xBeg开始,以nStep的步长进行num次镶嵌 // 结果存入lstSectFaces,lstFaces在镶嵌后扣除 void XArcWallUnit::Tessellate(double xBeg, double nStep, int num, DList &lstFaces, DList &lstSectFaces) { for(int n = 0; n < num; n++) { double xSect = xBeg + (1 + n) * nStep; //切割位置 int nFaceNum = lstFaces.Length(); for(int k = 0; k= 0) { //无切割发生 } else { //发生切割 double x1 = face.GetVertex(0).x, x2 = face.GetVertex(1).x, x3 = face.GetVertex(2).x; double y1 = face.GetVertex(0).y, y2 = face.GetVertex(1).y, y3 = face.GetVertex(2).y; double x = xSect; X3DFace *newFace = new X3DFace(face); int nFlag = face.GetFlag(); int nFlagNew = newFace->GetFlag(); if (nFlag2 > 0) { //切割第一点, 三角形 + 四边形 nFlagNew |= 0x02 + 0x08; double y = ((x-x1) * y2 + y1 * (x2-x)) / (x2-x1); newFace->SetVertex(1, XPoint(x, y)); y = ((x-x1) * y3 + y1 * (x3-x)) / (x3-x1); newFace->SetVertex(2, XPoint(x, y)); face.SetVertex(0, newFace->GetVertex(1)); face.SetVertex(3, newFace->GetVertex(2)); nFlag |= 0x08; nFlag &= ~FLAG_TRIANGLE; } else if (nFlag2 == 0) { // 三角形+三角形 nFlagNew |= 0x02 + 0x08; double y = ((x - x1) * y3 + y1 * (x3 - x)) / (x3 - x1); newFace->SetVertex(2, XPoint(x, y)); nFlag |= 0x01 + 0x08; face.SetVertex(0, XPoint(x, y)); face.SetVertex(3, XPoint(x, y)); } else { // 四边形 + 三角形 double y = ((x - x3) * y2 + y3 * (x2 - x)) / (x2 - x3); nFlagNew |= 0x04; newFace->SetVertex(2, XPoint(x,y)); y = ((x - x1) * y3 + y1 * (x3 - x)) / (x3 - x1); newFace->SetVertex(3, XPoint(x,y)); if (nFlag & 0x04) { nFlagNew |= 0x08; } else { nFlagNew &= ~0x08; } face.SetVertex(0, newFace->GetVertex(3)); face.SetVertex(3, newFace->GetVertex(3)); face.SetVertex(1, newFace->GetVertex(2)); nFlag |= 0x01 + 0x08; } face.SetFlag(nFlag); newFace->SetFlag(nFlagNew); lstSectFaces.Append(newFace); } } else { //4边形,已经切割过 int nFlag2 = CompareDouble(face.GetVertex(1).x, xSect); int nFlag3 = CompareDouble(face.GetVertex(2).x, xSect); // 分4种情况 if (nFlag3 <= 0) { //整个输出 lstSectFaces.Append(new X3DFace(face)); lstFaces.Remove(k); k--; nFaceNum--; } else { double x1 = face.GetVertex(0).x, x2 = face.GetVertex(1).x, x3 = face.GetVertex(2).x, x4 = face.GetVertex(3).x; double y1 = face.GetVertex(0).y, y2 = face.GetVertex(1).y, y3 = face.GetVertex(2).y, y4 = face.GetVertex(3).y; double x = xSect; X3DFace *newFace = new X3DFace(face); int nFlag = face.GetFlag(); int nFlagNew = newFace->GetFlag(); if (nFlag2 > 0) { // 2个四边形 nFlagNew |= 0x02; double y = ((x - x1) * y2 + y1 * (x2 - x)) / (x2 - x1); newFace->SetVertex(1, XPoint(x, y)); y = ((x - x3) * y4 + y3 * (x4 - x)) / (x4 - x3); newFace->SetVertex(2, XPoint(x, y)); face.SetVertex(0, newFace->GetVertex(1)); face.SetVertex(3, newFace->GetVertex(2)); } else if (nFlag2 == 0) { // 4边形+三角形 nFlagNew |= 0x02; double y = ((x - x3) * y4 + y3 * (x4 - x)) / (x4 - x3); newFace->SetVertex(2, XPoint(x, y)); face.SetVertex(0, XPoint(x, y)); face.SetVertex(3, XPoint(x, y)); nFlag |= 0x01 + 0x08; nFlag |= FLAG_TRIANGLE; } else if (nFlag2 < 0) { // 5边形+三角形 double y = ((x - x3) * y2 + y3 * (x2 - x)) / (x2 - x3); double yy = ((x - x3) * y4 + y3 * (x4 - x)) / (x4 - x3); newFace->SetVertex(2, XPoint(x, yy)); nFlagNew |= 0x02; X3DFace *pp = new X3DFace(face); pp->SetVertex(0, XPoint(x, yy)); pp->SetVertex(3, XPoint(x, yy)); pp->SetVertex(2, XPoint(x, y)); int nFlagP = pp->GetFlag(); nFlagP |= 0x01 + 0x04 + 0x08; pp->SetFlag(nFlagP); lstSectFaces.Append(pp); face.SetVertex(0, XPoint(x, yy)); face.SetVertex(3, XPoint(x, yy)); nFlag |= 0x01; nFlag |= FLAG_TRIANGLE; face.SetVertex(1, XPoint(x, y)); } face.SetFlag(nFlag); newFace->SetFlag(nFlagNew); lstSectFaces.Append(newFace); } } // end if Triangle } // end for k } // end for n } void XArcWallUnit::Tessellate(DList &lstSectFaces, double nHeight, BOOL bHasTop, BOOL bHasBot, BOOL bHasLeft, BOOL bHasRight) { double xMin = xHoleBeg, xMax = xHoleEnd; double xBeg = xWallBeg; int nCirDiv = GetCirDivNum(nRadius, _AS_SYS_UNIT(g_nCirDeviation)); //整圆的分段数目 //1. 输出xBeg~xMin的一段墙(四边形) if (xMin-xBeg > _DIST_SNAP) { int nDivNum = AS_INT((xMin - xBeg) / (2.0 * PI * nRadius) * nCirDiv); nDivNum = max(1, nDivNum); double nStep = (xMin - xBeg) / nDivNum; Tessellate(lstSectFaces, xBeg, nStep, nDivNum, nHeight, bHasTop, bHasBot, bHasLeft, (bHasRight && (xMax - xMin) < _DIST_SNAP)); } if (xMax - xMin < _DIST_SNAP) { return; } //2. 输出xMin~xMax的一段墙(包含洞口) XPolygonEx polyOut; //外轮廓-展开坐标系 polyOut.AppendNode(XPoint(xMin,0), bHasBot); polyOut.AppendNode(XPoint(xMax, 0), bHasRight); polyOut.AppendNode(XPoint(xMax, nHeight), bHasTop); polyOut.AppendNode(XPoint(xMin, nHeight), (bHasLeft && fabs(xMin - xBeg) < _DIST_SNAP)); //在展开坐标系,分解为三角形 DList lstFaces; AsTriangleFaces(polyOut, lstHoles, lstFaces); // 根据x坐标排序顶点(可能导致顺时针顶点方向) for(int i = 0; i < lstFaces.Length(); i++) { X3DFace *pFace = lstFaces[i]; SortVertex(pFace); } //3. 在展开坐标系,用分弧精度切割三角形,形成三角形或4边形 int num = AS_INT((xMax - xMin) / (2.0 * PI * nRadius) * nCirDiv); num = max(1, num); double nStep = (xMax - xMin) / num; Tessellate(xMin, nStep, num, lstFaces, lstSectFaces); } // 对xBeg开始,以步长nStep共nDivNum步,高度为nHeight,进行镶嵌, // 结果存入lstSectFaces。bHasTop, bHasBot, bHasLeft, bHasRight,外围边的可见性 void XArcWallUnit::Tessellate(DList &lstSectFaces, double xBeg, double nStep, int nDivNum, double nHeight, BOOL bHasTop, BOOL bHasBot, BOOL bHasLeft, BOOL bHasRight) { double nPrev = xBeg; for (int n = 1; n <= nDivNum; n++) { double nNext = xBeg + n * nStep; X3DFace *pFace = new X3DFace; int nFlag = pFace->GetFlag(); // 底-右-顶-左 if (!bHasBot) { nFlag |= 0x01; } if (bHasRight && n == nDivNum) { ; } else { nFlag |= 0x02; } if (!bHasTop) { nFlag |= 0x04; } if (bHasLeft && n == 1) { ; } else { nFlag |= 0x08; } pFace->SetFlag(nFlag); pFace->SetVertex(0, XPoint(nPrev, 0.0)); pFace->SetVertex(1, XPoint(nNext, 0.0)); pFace->SetVertex(2, XPoint(nNext, nHeight)); pFace->SetVertex(3, XPoint(nPrev, nHeight)); lstSectFaces.Append(pFace); nPrev = nNext; } } // 把平面(含洞口)的模型,化解为三角形 // z坐标全部为0 int XArcWallUnit::AsTriangleFaces(const XPolygonEx &polyOut, const DList &lstHoles, DList &lstFaces) { XTrianglePface lstTris; if (Triangulate(polyOut, lstHoles, lstTris)) { int nFlag = 0; for (int n = 0; n < lstTris.Length(); n++) { XTriangle *triangle = lstTris[n]; ASSERT(triangle); X3DFace *pFace = new X3DFace; nFlag = triangle->m_nFlag; pFace->SetVertex(0, triangle->vertex1); pFace->SetVertex(1, triangle->vertex2); pFace->SetVertex(2, triangle->vertex3); pFace->SetVertex(3, triangle->vertex1); nFlag |= FLAG_TRIANGLE; pFace->SetFlag(nFlag); lstFaces.Append(pFace); } return RTNORM; } return RTERROR; } // 把平面(含洞口)的模型,化解为三角形 // z坐标全部为0 int XArcWallUnit::AsTriangleFaces(const XPoly2D &polyOut, const DList &lstHoles, DList &lstFaces) { XPoly poly1; ((XPoly2D &)polyOut).MapToPolygon1(poly1, _AS_SYS_UNIT(g_nCirDeviation)); ASSERT(poly1.Length() > 2); XPolygonEx polyEx1(poly1); if (polyEx1.PathArea() > 0.0) { polyEx1.Reverse(); } return AsTriangleFaces(polyEx1, lstHoles, lstFaces); } void XArcWallUnit::SortVertex(X3DFace *pFace) { ASSERT(pFace); DList vertices; BOOL bInvis1 = ((pFace->GetFlag() & 0x01) != 0); BOOL bInvis2 = ((pFace->GetFlag() & 0x02) != 0); BOOL bInvis3 = ((pFace->GetFlag() & 0x04) != 0); vertices.Append(new XPoint(pFace->GetVertex(0).x, pFace->GetVertex(0).y, bInvis1)); vertices.Append(new XPoint(pFace->GetVertex(1).x, pFace->GetVertex(1).y, bInvis2)); vertices.Append(new XPoint(pFace->GetVertex(2).x, pFace->GetVertex(2).y, bInvis3)); vertices.QuickSort(ComparePointByX); XPoint ver0 = *vertices[0], ver1 = *vertices[1], ver2 = *vertices[2]; XVector3D vtOld = pFace->GetNormal(); pFace->GetVertex(0).x = ver0.x; pFace->GetVertex(0).y = ver0.y; pFace->GetVertex(1).x = ver1.x; pFace->GetVertex(1).y = ver1.y; pFace->GetVertex(2).x = ver2.x; pFace->GetVertex(2).y = ver2.y; pFace->GetVertex(3) = pFace->GetVertex(0); bInvis1 = (ver0.z > 1.0E-3); bInvis2 = (ver1.z > 1.0E-3); bInvis3 = (ver2.z > 1.0E-3); XVector3D vtNew = pFace->GetNormal(); if ((vtNew & vtOld) < 0) { // 可见标记也要反转 BOOL b1 = bInvis1, b2 = bInvis2, b3 = bInvis3; bInvis1 = b2; bInvis2 = b3; bInvis3 = b1; } int nFlag = pFace->GetFlag(); if (bInvis1) { nFlag |= 0x01; } else { nFlag &= ~0x01; } if (bInvis2) { nFlag |= 0x02; } else { nFlag &= ~0x02; } if (bInvis3) { nFlag |= 0x04; } else { nFlag &= ~0x04; } pFace->SetFlag(nFlag); }