Files
envi-code/SourceCode/Code2026/EarthWormCmd/terrainAnalysis.cpp
T

1613 lines
41 KiB
C++
Raw Normal View History

2026-10-04 00:04:20 +08:00
#include "StdAfx.h"
2026-09-28 15:28:50 +08:00
#include "terrainAnalysis.h"
#include "UITools.h"
#include <sstream>
#include "ktcadutility.h"
#include <set>
#include "dbobjptr.h"
#include "aecdbterrain.h"
#include "KTSetting.h"
#include "coretools.h"
#if ARX > 17
#include "dbsubd.h"
namespace
{
static void AcDbSubDMeshfromAcDb3dSolid(void)
{
Acad::ErrorStatus err;
ads_name name;
ads_point pt;
if (acedEntSel(L"Select a solid", name, pt) != RTNORM) return;
AcDbObjectId id;
acdbGetObjectId(id, name);
AcDbObjectPointer<AcDb3dSolid> ptrSolid(id, AcDb::kForRead);
AcDbFaceterSettings settings;
AcGePoint3dArray pts;
AcArray<Adesk::Int32> faces;
AcGiFaceData* faceData;
err = acdbGetObjectMesh(ptrSolid, &settings, pts, faces, faceData);
if (faceData)
{
delete[] faceData->trueColors();
delete[] faceData->materials();
DELETE_PTR(faceData);
}
AcDbObjectPointer<AcDbSubDMesh> ptrMesh;
ptrMesh.create();
ptrMesh->setSubDMesh(pts, faces, 0);
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
AcDbBlockTableRecordPointer ptrMS(ACDB_MODEL_SPACE, pDb, AcDb::kForWrite);
ptrMS->appendAcDbEntity(ptrMesh);
}
struct Face
{
Face(): num(0), vertices(0){}
int num;
std::vector<AcGePoint3d> vertices;
};
struct FacePoint
{
AcGePoint3d pt;
Face face;
void setFace(const Face &f)
{
face = f;
AcGePlane pln(f.vertices[0], f.vertices[1], f.vertices[2]);
AcGePoint3d ptClosed = pln.closestPointTo(pt);
pt.z = ptClosed.z;
}
};
struct com_pt_z{ bool operator () (AcGePoint3d &pt1, AcGePoint3d &pt2) { return pt1.z < pt2.z; } };
double crossProduct(const AcGeVector2d v1, const AcGeVector2d &v2) { return v1.x*v2.y - v1.y*v2.x; }
bool isInTriangle(const AcGePoint2d &pt0
, const AcGePoint2d &pt1
, const AcGePoint2d &pt2
, const AcGePoint2d &pt )
{
AcGeVector2d v0(pt0 - pt), v1(pt1 - pt), v2(pt2 - pt);
double d01 = crossProduct(v0, v1);
double d12 = crossProduct(v1, v2);
double d20 = crossProduct(v2, v0);
return (d01 * d12 >= 0) && (d01 * d20 >= 0);
}
bool isInFace(const AcGePoint3d &pt, const Face &f)
{
if (f.num < 3) return false;
AcGePoint2d pt0(f.vertices[0].x, f.vertices[0].y)
, pt1(f.vertices[1].x, f.vertices[1].y)
, pt2(f.vertices[2].x, f.vertices[2].y)
, pt2d(pt.x, pt.y);
return isInTriangle(pt0, pt1, pt2, pt2d);
}
bool isDouble(LPCTSTR psz, double &d)
{
std::wstringstream ss(psz);
TCHAR c;
if (!(ss >> d))
return false;
if (ss >> c)
return false;
return true;
}
void polyline2PointArray(const AcDbPolyline &poly, std::vector<AcGePoint3d> &ar, const double &dElev)
{
AcGePoint3d pt;
double dParam(.0);
std::set<double> params;
AcGeLineSeg3d seg3d;
AcGeCircArc3d arc3d;
AcDbPolyline::SegType st(AcDbPolyline::kEmpty);
for (int i(0); i < poly.numVerts(); ++i)
{
st = poly.segType(i);
if (st == AcDbPolyline::kLine)
{
poly.getLineSegAt(i, seg3d);
poly.getParamAtPoint(seg3d.startPoint(), dParam);
params.insert(dParam);
poly.getParamAtPoint(seg3d.endPoint(), dParam);
params.insert(dParam);
}
else if (st == AcDbPolyline::kArc)
{
double dS(.0), dE(.0);
poly.getArcSegAt(i, arc3d);
poly.getParamAtPoint(arc3d.startPoint(), dS);
poly.getParamAtPoint(arc3d.endPoint(), dE);
double dStep(abs((dS - dE) * .01));
for (int i(0); i < 100; ++i)
{
params.insert(dS + i * dStep);
}
params.insert(dE);
}
}
std::set<double>::const_iterator it(params.begin());
for (; it != params.end(); ++it)
{
if (poly.getPointAtParam(*it, pt) == Acad::eOk)
ar.push_back(AcGePoint3d(pt.x, pt.y, dElev));
}
}
void circle2PointArray(const AcDbCircle &circle, std::vector<AcGePoint3d> &ar, const double &dElev)
{
std::set<double> params;
double dS(.0), dE(.0);
circle.getStartParam(dS);
circle.getEndParam(dE);
double dStep(abs((dS - dE) * .01));
for (int i(0); i < 100; ++i)
{
params.insert(dS + i * dStep);
}
params.insert(dE);
AcGePoint3d pt;
std::set<double>::const_iterator it(params.begin());
for (; it != params.end(); ++it)
{
if (circle.getPointAtParam(*it, pt) == Acad::eOk)
ar.push_back(AcGePoint3d(pt.x, pt.y, dElev));
}
}
void setBlockAttri(AcDbBlockReference *pRef, LPCTSTR str)
{
if (!pRef) return;
AcDbObjectIterator *pIt = pRef->attributeIterator();
if (!pIt) return;
AcDbAttribute *pAttr(NULL);
for (pIt->start(); !pIt->done(); pIt->step())
{
AcDbObjectId id = pIt->objectId();
pRef->openAttribute(pAttr, id, AcDb::kForWrite);
if (pAttr)
{
pAttr->setTextString(str);
pAttr->close();
break;
}
}
DELETE_PTR(pIt);
return;
}
void getBlockAttri(AcDbBlockReference *pRef, std::set<CString> &tags, std::set<CString> &texts)
{
if (!pRef) return;
AcDbObjectIterator *pIt = pRef->attributeIterator();
if (!pIt) return;
CString str(_T(""));
AcDbAttribute *pAttr(NULL);
for (pIt->start(); !pIt->done(); pIt->step())
{
AcDbObjectId id = pIt->objectId();
pRef->openAttribute(pAttr, id, AcDb::kForRead);
if (pAttr)
{
str = pAttr->tag();
tags.insert(pAttr->tag());
texts.insert(pAttr->textString());
pAttr->close();
}
}
DELETE_PTR(pIt);
return;
}
2026-10-04 00:04:20 +08:00
// 判断 idDest 所代表的标高是否再 dMax 与 dMin 之间
2026-09-28 15:28:50 +08:00
bool modifyElevObj(AcDbObjectId idDest, const double &dMax, const double &dMin)
{
OPENOBJ_BEGIN(idDest, AcDb::kForWrite, AcDbEntity, pDest)
{
if (!pDest) return false;
AcDbBlockReference *pRef2 = AcDbBlockReference::cast(pDest);
AcDbPoint *pPnt2 = AcDbPoint::cast(pDest);
AcDbText *pTxt2 = AcDbText::cast(pDest);
AcDbMText *pMTxt2 = AcDbMText::cast(pDest);
AcGePoint3d pt(AcGePoint3d::kOrigin);
int prec(2);
2026-10-04 00:04:20 +08:00
// 图块
2026-09-28 15:28:50 +08:00
if (pRef2)
{
2026-10-04 00:04:20 +08:00
// 比较属性
2026-09-28 15:28:50 +08:00
std::set<CString> attr2, text2;
getBlockAttri(pRef2, attr2, text2);
pt = pRef2->position();
if (isDouble(*text2.begin(), pt.z))
{
if (pt.z > dMax)
{
pt.z = dMax;
pRef2->setPosition(pt);
setBlockAttri(pRef2, TypeConvert::d2s(pt.z, &prec));
}
else if (pt.z < dMin)
{
pt.z = dMin;
pRef2->setPosition(pt);
setBlockAttri(pRef2, TypeConvert::d2s(pt.z, &prec));
}
return true;
}
return true;
}
2026-10-04 00:04:20 +08:00
else if (pPnt2) // 点
2026-09-28 15:28:50 +08:00
{
pt = pPnt2->position();
if (pt.z > dMax)
{
pt.z = dMax;
pPnt2->setPosition(pt);
}
else if ( pt.z < dMin)
{
pt.z = dMin;
pPnt2->setPosition(pt);
}
return true;
}
2026-10-04 00:04:20 +08:00
else if (pTxt2) // 单行文字
2026-09-28 15:28:50 +08:00
{
pt = pTxt2->position();
if (isDouble(pTxt2->textString(), pt.z))
{
if (pt.z > dMax)
{
pt.z = dMax;
pTxt2->setPosition(pt);
pTxt2->setTextString(TypeConvert::d2s(pt.z, &prec));
}
else if (pt.z < dMin)
{
pt.z = dMin;
pTxt2->setPosition(pt);
pTxt2->setTextString(TypeConvert::d2s(pt.z, &prec));
}
return true;
}
return false;
}
2026-10-04 00:04:20 +08:00
else if (pMTxt2) // 多行文字
2026-09-28 15:28:50 +08:00
{
pt = pMTxt2->location();
if (isDouble(pMTxt2->contents(), pt.z))
{
if (pt.z > dMax)
{
pt.z = dMax;
pMTxt2->setLocation(pt);
pMTxt2->setContents(TypeConvert::d2s(pt.z, &prec));
}
else if (pt.z < dMin)
{
pt.z = dMin;
pMTxt2->setLocation(pt);
pMTxt2->setContents(TypeConvert::d2s(pt.z, &prec));
}
return true;
}
return false;
}
return false;
}
OPENOBJ_END()
}
2026-10-04 00:04:20 +08:00
// 分析高程对象
// idOrig是示例对象,判断idDest是否和idOrig一样
// 如果返回false,说明不是高程点
2026-09-28 15:28:50 +08:00
bool analyElevObj(AcDbObjectId idOrig, AcDbObjectId idDest, AcGePoint3d &pt)
{
//if (idOrig == idDest) return false;
AcDbObjectId idLay1, idLay2, idLt1, idLt2;
AcDb::LineWeight lw1, lw2;
AcCmColor cm1, cm2;
AcCmTransparency ct1, ct2;
2026-10-04 00:04:20 +08:00
// 目前只支持3种,块参照 文字对象 点对象
2026-09-28 15:28:50 +08:00
OPENOBJ_BEGIN(idOrig, AcDb::kForRead, AcDbEntity, pOrig)
{
if (!pOrig) return false;
idLay1 = pOrig->layerId();
idLt1 = pOrig->linetypeId();
lw1 = pOrig->lineWeight();
cm1 = pOrig->color();
ct1 = pOrig->transparency();
if (!pOrig) return false;
AcDbBlockReference *pRef1 = AcDbBlockReference::cast(pOrig);
AcDbPoint *pPnt1 = AcDbPoint::cast(pOrig);
AcDbText *pTxt1 = AcDbText::cast(pOrig);
AcDbMText *pMTxt1 = AcDbMText::cast(pOrig);
OPENOBJ_BEGIN(idDest, AcDb::kForRead, AcDbEntity, pDest)
{
if (!pDest) return false;
idLay2 = pDest->layerId();
idLt2 = pDest->linetypeId();
lw2 = pDest->lineWeight();
cm2 = pDest->color();
ct2 = pDest->transparency();
if (idLay1 != idLay2) return false;
if (idLt1 != idLt2) return false;
if (lw1 != lw2) return false;
if (cm1 != cm2) return false;
if (ct1 != ct2) return false;
2026-10-04 00:04:20 +08:00
// 下面分别对图块,点,文字对象进行比较
2026-09-28 15:28:50 +08:00
AcDbBlockReference *pRef2 = AcDbBlockReference::cast(pDest);
AcDbPoint *pPnt2 = AcDbPoint::cast(pDest);
AcDbText *pTxt2 = AcDbText::cast(pDest);
AcDbMText *pMTxt2 = AcDbMText::cast(pDest);
2026-10-04 00:04:20 +08:00
// 图块
2026-09-28 15:28:50 +08:00
if (pRef1 && pRef2)
{
if (pRef1->scaleFactors() != pRef2->scaleFactors()) return false;
if (pRef1->rotation() != pRef2->rotation()) return false;
if (pRef1->blockTableRecord() != pRef2->blockTableRecord()) return false;
2026-10-04 00:04:20 +08:00
// 比较属性
2026-09-28 15:28:50 +08:00
std::set<CString> attr1, attr2, text1, text2;
getBlockAttri(pRef1, attr1, text1);
getBlockAttri(pRef2, attr2, text2);
if (attr1 != attr2) return false;
2026-10-04 00:04:20 +08:00
// 能走到这里,说明都有属性,或都没有属性
2026-09-28 15:28:50 +08:00
AcGePoint3d _pt;
2026-10-04 00:04:20 +08:00
// 如果 ref1 有属性,并且有数字属性值(就判断第一个)
if (!attr1.empty()) // 说明都有属性
2026-09-28 15:28:50 +08:00
{
2026-10-04 00:04:20 +08:00
// 如果ref1 的属性值是数字,那么,ref2 属性值必须是数字(就判断第一个)
2026-09-28 15:28:50 +08:00
if (isDouble(*text1.begin(), _pt.z))
{
pt = pRef2->position();
if (!text2.empty() && isDouble(*text2.begin(), pt.z))
{
return true;
}
else
return false;
}
2026-10-04 00:04:20 +08:00
else // 如果ref1属性值不是数字,那么直接返回ref2的插入点算逑
2026-09-28 15:28:50 +08:00
{
pt = pRef2->position();
return true;
}
return false;
}
2026-10-04 00:04:20 +08:00
// 都没有属性,直接取插入点
2026-09-28 15:28:50 +08:00
else
{
pt = pRef2->position();
return true;
}
}
2026-10-04 00:04:20 +08:00
else if (pPnt1 && pPnt2) // 点
2026-09-28 15:28:50 +08:00
{
pt = pPnt2->position();
return true;
}
2026-10-04 00:04:20 +08:00
else if (pTxt1 && pTxt2) // 单行文字
2026-09-28 15:28:50 +08:00
{
if (pTxt1->textStyle() != pTxt2->textStyle()) return false;
if (pTxt1->horizontalMode() != pTxt2->horizontalMode()) return false;
if (pTxt1->verticalMode() != pTxt2->verticalMode()) return false;
if (pTxt1->rotation() != pTxt2->rotation()) return false;
if (pTxt1->thickness() != pTxt2->thickness()) return false;
if (pTxt1->widthFactor() != pTxt2->widthFactor()) return false;
if (pTxt1->height() != pTxt2->height()) return false;
if (pTxt1->oblique() != pTxt2->oblique()) return false;
if (pTxt1->isMirroredInX() != pTxt2->isMirroredInX()) return false;
if (pTxt1->isMirroredInY() != pTxt2->isMirroredInY()) return false;
pt = pTxt2->position();
return isDouble(pTxt2->textString(), pt.z);
}
2026-10-04 00:04:20 +08:00
else if (pMTxt1 && pMTxt2) // 多行文字
2026-09-28 15:28:50 +08:00
{
if (pMTxt1->actualHeight() != pMTxt2->actualHeight()) return false;
if (pMTxt1->actualWidth() != pMTxt2->actualWidth()) return false;
if (pMTxt1->ascent() != pMTxt2->ascent()) return false;
if (pMTxt1->attachment() != pMTxt2->attachment()) return false;
if (pMTxt1->descent() != pMTxt2->descent()) return false;
if (pMTxt1->direction() != pMTxt2->direction()) return false;
if (pMTxt1->flowDirection() != pMTxt2->flowDirection()) return false;
AcCmColor cm11, cm22;
if (pMTxt1->getBackgroundFillColor(cm11) == Acad::eOk
&& pMTxt2->getBackgroundFillColor(cm22) == Acad::eOk)
{
if (cm11 != cm22) return false;
}
AcCmTransparency ct11, ct22;
if (pMTxt1->getBackgroundTransparency(ct11) == Acad::eOk
&& pMTxt2->getBackgroundTransparency(ct22) == Acad::eOk)
{
if (ct11 != ct22) return false;
}
double d1, d2;
if (pMTxt1->getBackgroundScaleFactor(d1) == Acad::eOk
&& pMTxt2->getBackgroundScaleFactor(d2) == Acad::eOk)
{
if (!EQUAL(d1, d2)) return false;
}
// AcGePoint3dArray ar1, ar2;
// pMTxt1->getBoundingPoints(ar1);
// pMTxt2->getBoundingPoints(ar2);
// if (ar1 != ar2) return false;
if (pMTxt1->lineSpacingFactor() != pMTxt2->lineSpacingFactor()) return false;
if (pMTxt1->lineSpacingStyle() != pMTxt2->lineSpacingStyle()) return false;
if (pMTxt1->width() != pMTxt2->width()) return false;
if (pMTxt1->rotation() != pMTxt2->rotation()) return false;
if (pMTxt1->textStyle() != pMTxt2->textStyle()) return false;
if (pMTxt1->textHeight() != pMTxt2->textHeight()) return false;
pt = pMTxt2->location();
return isDouble(pMTxt2->contents(), pt.z);
}
return false;
}
OPENOBJ_END()
}
OPENOBJ_END()
return false;
}
2026-10-04 00:04:20 +08:00
// 交互:用户选取离散点
2026-09-28 15:28:50 +08:00
bool getElevPoints(Geometry::GePoint3dArray &arPts, AcDbObjectIdArray &ids)
{
ads_name adsNames, adsName;
AcDbObjectId id(AcDbObjectId::kNull), idOrig(AcDbObjectId::kNull);
Adesk::Int32 count(0);
struct resbuf* pRb = acutBuildList(RTDXF0, _T("INSERT,POINT,TEXT,MTEXT"), 0);
2026-10-04 00:04:20 +08:00
int nRes = CKTCadUtility::SelectEntity(_T("\n请选择一个“图块”、“点”、“文字”对象,做为参考对象:"), adsName, pRb);
2026-09-28 15:28:50 +08:00
acutRelRb(pRb);
if (nRes != RTNORM) return false;
acdbGetObjectId(id, adsName);
CString sFilter(_T("INSERT"));
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbEntity, pEnt)
{
if (!pEnt) return false;
AcDbBlockReference *pRef = AcDbBlockReference::cast(pEnt);
AcDbPoint *pPnt = AcDbPoint::cast(pEnt);
AcDbText *pTxt = AcDbText::cast(pEnt);
AcDbMText *pMTxt = AcDbMText::cast(pEnt);
if (pRef)
sFilter = _T("INSERT");
else if (pPnt)
sFilter = _T("POINT");
else if (pTxt)
sFilter = _T("TEXT");
else if (pMTxt)
sFilter = _T("MTEXT");
else
return false;
}
OPENOBJ_END()
2026-10-04 00:04:20 +08:00
// 在这里判断是用户选择,还是选一个样例,然后选中dwg中的所有与样例相同的实体
2026-09-28 15:28:50 +08:00
TCHAR szKey[131] = {_T('S'),};
acedInitGet(RSG_OTHER, _T("S A"));
2026-10-04 00:04:20 +08:00
nRes = acedGetKword(_T("\n请选择[手动选择高程数据(S)/选择图中全部高程数据(A)]<手动选择高程数据(S)>:"), szKey);
2026-09-28 15:28:50 +08:00
if (nRes == RTCAN)
return false;
if (nRes == RTNONE) _tcscpy(szKey, _T("S"));
if (_tcscmp(szKey, _T("S")) == 0)
{
struct resbuf* pRb = acutBuildList(RTDXF0, sFilter, 0);
2026-10-04 00:04:20 +08:00
nRes = CKTCadUtility::SelectEntities(_T("\n请选择“图块”、“点”、“文字”对象:"), adsNames, pRb);
2026-09-28 15:28:50 +08:00
acutRelRb(pRb);
if (nRes != RTNORM) return false;
acedSSLength(adsNames, &count);
if (!count) return false;
}
else
{
pRb = acutBuildList(RTDXF0, sFilter, 0);
acedSSGet(_T("X"), NULL, NULL, pRb, adsNames);
acutRelRb(pRb);
acedSSLength(adsNames, &count);
if (!count) return false;
}
AcGePoint3d pt(AcGePoint3d::kOrigin);
for (size_t i = 0; i < count; i++)
{
acedSSName(adsNames, i, adsName);
if (Acad::eOk != acdbGetObjectId(idOrig, adsName)) continue;
if (analyElevObj(id, idOrig, pt))
{
arPts.push_back(pt);
ids.append(idOrig);
}
}
acedSSFree(adsNames);
return !arPts.empty();
}
CString getUserSelectType(AcDbObjectId &id)
{
ads_name adsName;
Adesk::Int32 count(0);
struct resbuf *pRb = acutBuildList(RTDXF0, _T("INSERT,POINT,TEXT,MTEXT"), 0);
2026-10-04 00:04:20 +08:00
int nRes = CKTCadUtility::SelectEntity(_T("\n请选择一个“图块”、“点”、“文字”对象,做为参考对象:"), adsName, pRb);
2026-09-28 15:28:50 +08:00
acutRelRb(pRb);
if (nRes != RTNORM) return _T("");
acdbGetObjectId(id, adsName);
CString sFilter(_T("INSERT"));
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbEntity, pEnt)
{
if (!pEnt) return _T("");
AcDbBlockReference *pRef = AcDbBlockReference::cast(pEnt);
AcDbPoint *pPnt = AcDbPoint::cast(pEnt);
AcDbText *pTxt = AcDbText::cast(pEnt);
AcDbMText *pMTxt = AcDbMText::cast(pEnt);
if (pRef)
sFilter = _T("INSERT");
else if (pPnt)
sFilter = _T("POINT");
else if (pTxt)
sFilter = _T("TEXT");
else if (pMTxt)
sFilter = _T("MTEXT");
else
return _T("");
}
OPENOBJ_END()
return sFilter;
}
bool getPointsInArea(LPCTSTR pszFilter
, AcDbObjectId idOrig
, Geometry::GePoint3dArray &arPts
, AcDbObjectIdArray &ids
, Geometry::GePoint3dArray &area)
{
if (!pszFilter) return false;
ads_name ss, ent;
struct resbuf *pRb = acutBuildList(RTDXF0, pszFilter, 0);
2026-10-04 00:04:20 +08:00
// 转成UCS
2026-09-28 15:28:50 +08:00
Geometry::GePoint3dArray _area(area);
for (int i(0); i < _area.size(); ++i)
CoreTools::WCS2UCS(_area[i], _area[i]);
struct resbuf *pRbFence = CoreTools::MakeFence(_area);
int nRes = acedSSGet(_T("CP"), pRbFence, NULL, pRb, ss);
acutRelRb(pRb);
acutRelRb(pRbFence);
if (nRes != RTNORM)
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n区域内没有需要选择的标高对象!"));
2026-09-28 15:28:50 +08:00
return false;
}
AcDbObjectId id;
Adesk::Int32 count(0);
acedSSLength(ss, &count);
AcGePoint3d pt(AcGePoint3d::kOrigin);
for (size_t i = 0; i < count; i++)
{
acedSSName(ss, i, ent);
if (Acad::eOk != acdbGetObjectId(id, ent)) continue;
if (analyElevObj(idOrig, id, pt))
{
arPts.push_back(pt);
ids.append(id);
}
}
acedSSFree(ss);
return true;
}
void getPolyPoints(AcDbPolyline *pPoly
, const AcGePoint3d &ptS
, const AcGePoint3d &ptE
, const double &step
, std::vector<AcGePoint3d> &pts)
{
if (!pPoly) return;
AcGePoint3d pt(AcGePoint3d::kOrigin), _ptS(ptS), _ptE(ptE);
double distS(0.), distE(.0), len(.0);
pPoly->getEndPoint(pt);
pPoly->getDistAtPoint(pt, len);
if (Acad::eOk != pPoly->getDistAtPoint(ptS, distS))
{
distS = 0.;
pPoly->getStartPoint(_ptS);
}
if (Acad::eOk != pPoly->getDistAtPoint(ptE, distE))
{
distE = len;
pPoly->getEndPoint(_ptE);
}
while (distE > distS)
{
pPoly->getPointAtDist(distS, pt);
pts.push_back(pt);
distS += step;
}
pts.push_back(_ptE);
}
2026-10-04 00:04:20 +08:00
// 从ptS开始以1米为间隔,逼近到ptE
2026-09-28 15:28:50 +08:00
AcDbSubDMesh* polyline2SubDMesh(AcDbObjectId idPoly, const double &dH, const AcGePoint3d &ptS, const AcGePoint3d &ptE)
{
AcGePoint3dArray arBottoms(0), arTops(0);
OPENOBJ_BEGIN(idPoly, AcDb::kForRead, AcDbPolyline, pPoly)
{
if (!pPoly) return NULL;
AcGePoint3d pt(AcGePoint3d::kOrigin), _ptS(ptS), _ptE(ptE);
double distS(0.), distE(.0), len(.0);
pPoly->getEndPoint(pt);
pPoly->getDistAtPoint(pt, len);
if (Acad::eOk != pPoly->getDistAtPoint(ptS, distS))
{
distS = 0.;
pPoly->getStartPoint(_ptS);
}
if (Acad::eOk != pPoly->getDistAtPoint(ptE, distE))
{
distE = len;
pPoly->getEndPoint(_ptE);
}
while (distE > distS)
{
pPoly->getPointAtDist(distS, pt);
arBottoms.append(pt);
arTops.append(AcGePoint3d(pt.x, pt.y, pt.z + dH));
distS += 1;
}
arBottoms.append(_ptE);
arTops.append(AcGePoint3d(_ptE.x, _ptE.y, _ptE.z + dH));
}
OPENOBJ_END()
arBottoms.append(arTops);
int count_of_vertex = arBottoms.length();
int count_of_vertex_half = (int)( count_of_vertex* .5);
int count_of_face = count_of_vertex_half - 1;
AcArray<Adesk::Int32> faces;
for (int i = 0; i < count_of_face; ++i)
{
faces.append(4);
faces.append(i);
faces.append(faces.last() + 1);
faces.append(faces.last() + count_of_vertex_half);
faces.append(faces.last() - 1);
}
AcDbSubDMesh *pMesh = new AcDbSubDMesh;
pMesh->setSubDMesh(arBottoms, faces, 0);
return pMesh;
}
void getSubDMeshFaces(AcDbSubDMesh *pFaceMesh, std::vector<Face> &fs)
{
AcGePoint3dArray arV;
AcArray<Adesk::Int32> arF;
Adesk::Int32 countF;
pFaceMesh->getFaceArray(arF);
pFaceMesh->getVertices(arV);
pFaceMesh->numOfFaces(countF);
int count_of_v(arV.length());
int count_of_f(arF.length());
/*
2026-10-04 00:04:20 +08:00
arF结构如下 第1个数字n为构成一个面的顶点数量,其后n个数字为顶点在arV中的索引
2026-09-28 15:28:50 +08:00
*/
Face f;
for (int i = 0; i < count_of_f;)
{
f.num = abs(arF[i]);
f.vertices.clear();
2026-10-04 00:04:20 +08:00
// 加1,跳到顶点索引开始
2026-09-28 15:28:50 +08:00
++i;
2026-10-04 00:04:20 +08:00
// 将索引取出
2026-09-28 15:28:50 +08:00
for (int j = 0; j < f.num; ++j)
{
if (i + j < count_of_f)
{
Adesk::Int32 &vIdx(arF[i + j]);
if (vIdx < count_of_v)
f.vertices.push_back(arV[vIdx]);
}
}
fs.push_back(f);
2026-10-04 00:04:20 +08:00
// 跳到下一个面
2026-09-28 15:28:50 +08:00
i += f.num;
}
}
double calcAverageZ(const Geometry::GePoint3dArray &pts)
{
double dElev(.0);
for (size_t i(0); i < pts.size(); ++i)
dElev += pts[i].z;
dElev /= pts.size();
return dElev;
}
void setZ(Geometry::GePoint3dArray &pts, const double &z)
{
for (size_t i(0); i < pts.size(); ++i)
pts[i].z = z;
}
AecDbTerrain* makeTerrain( const Geometry::GePoint3dArray &arPts
, const Geometry::GePoint3dArray &arOuter )
{
if (arPts.empty()) return NULL;
AecDbTerrain *pTer = new AecDbTerrain();
pTer->setPoints(arPts);
if (!arOuter.empty())
pTer->setOuter(arOuter);
return pTer;
}
void getAllOfPoints(LPCTSTR pszFilter
, AcDbObjectId idOrig
, Geometry::GePoint3dArray &arPoints
, AcDbObjectIdArray &arIds)
{
Adesk::Int32 count(0);
ads_name adsNames, adsName;
AcDbObjectId id(AcDbObjectId::kNull);
struct resbuf *pRb = acutBuildList(RTDXF0, pszFilter, 0);
acedSSGet(_T("X"), NULL, NULL, pRb, adsNames);
acutRelRb(pRb);
acedSSLength(adsNames, &count);
if (!count) return;
AcGePoint3d pt(AcGePoint3d::kOrigin);
for (size_t i = 0; i < count; i++)
{
acedSSName(adsNames, i, adsName);
if (Acad::eOk != acdbGetObjectId(id, adsName)) continue;
if (analyElevObj(idOrig, id, pt))
{
arIds.append(id);
arPoints.push_back(pt);
}
}
acedSSFree(adsNames);
}
int getPointsInAreaByUser(LPCTSTR pszFilter
, AcDbObjectId idOrig
, std::vector<Geometry::GePoint3dArray> &arArraysOfPoint
, std::vector<Geometry::GePoint3dArray> &arOuters
, std::vector<AcDbObjectIdArray> &arArraysOfId )
{
Adesk::Int32 count(0);
ads_name adsNames, adsName;
struct resbuf *pRb = acutBuildList(RTDXF0, _T("LWPOLYLINE,CIRCLE"), 0);
2026-10-04 00:04:20 +08:00
int nRes = CKTCadUtility::SelectEntities(_T("\n请选择由“多段线”或“圆”构成的闭合区域:"), adsNames, pRb);
2026-09-28 15:28:50 +08:00
acutRelRb(pRb);
if (nRes != RTNORM) return nRes;
acedSSLength(adsNames, &count);
if (!count) return RTNONE;
AcDbObjectIdArray ids;
Geometry::GePoint3dArray arOuter, arPts;
for (int i(0); i < count; ++i)
{
arOuter.clear();
arPts.clear();
ids.removeAll();
acedSSName(adsNames, i, adsName);
OPENOBJ_BEGIN(adsName, AcDb::kForRead, AcDbEntity, pEnt)
{
if (!pEnt) continue;
AcDbPolyline *pPL = AcDbPolyline::cast(pEnt);
AcDbCircle *pC = AcDbCircle::cast(pEnt);
if (pPL)
{
polyline2PointArray(*pPL, arOuter, .0);
}
else if (pC)
{
circle2PointArray(*pC, arOuter, .0);
}
getPointsInArea(pszFilter, idOrig, arPts, ids, arOuter);
if (!ids.isEmpty())
{
arArraysOfId.push_back(ids);
arArraysOfPoint.push_back(arPts);
arOuters.push_back(arOuter);
}
}
OPENOBJ_END()
}
acedSSFree(adsNames);
if (arArraysOfId.empty())
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n选中的区域没有符合特征的实体!"));
2026-09-28 15:28:50 +08:00
return RTNONE;
}
return RTNORM;
}
2026-10-04 00:04:20 +08:00
// 0 取消 1 区域 2 全部
2026-09-28 15:28:50 +08:00
int IsSelectAllPoint()
{
2026-10-04 00:04:20 +08:00
// 在这里判断是用户选择,还是选一个样例,然后选中dwg中的所有与样例相同的实体
2026-09-28 15:28:50 +08:00
TCHAR szKey[131] = { _T('S'), };
acedInitGet(RSG_OTHER, _T("S A"));
2026-10-04 00:04:20 +08:00
int nRes = acedGetKword(_T("\n请选择[手动选择高程区域(S)/选择图中全部高程数据(A)]<手动选择高程区域(S)>:"), szKey);
2026-09-28 15:28:50 +08:00
if (nRes == RTCAN)
return 0;
if (nRes == RTNONE)
return 1;
return _tcscmp(szKey, _T("S")) == 0 ? 1 : 2;
}
}
void TERRAIN::generateTerrainMesh()
{
AcDbObjectId idOrig(AcDbObjectId::kNull);
CString sFilter(getUserSelectType(idOrig));
if (sFilter.IsEmpty()) return;
int nSelType(IsSelectAllPoint());
if (nSelType == 0) return;
AcDbObjectId layerId = KTSetting::InitLayer(_T("LAY_FACTORY_LAND"), false);
if (nSelType == 1)
{
std::vector<Geometry::GePoint3dArray> arArraysOfPoint;
std::vector<Geometry::GePoint3dArray> arOuters;
std::vector<AcDbObjectIdArray> arArraysOfId;
int nRes = getPointsInAreaByUser(sFilter, idOrig, arArraysOfPoint, arOuters, arArraysOfId);
if (nRes != RTNORM) return;
if (!arArraysOfId.empty()
&& !arArraysOfPoint.empty()
&& !arOuters.empty()
&& arArraysOfId.size() == arArraysOfPoint.size()
&& arArraysOfId.size() == arOuters.size())
{
for (size_t i = 0; i < arArraysOfId.size(); ++i)
{
//AcDbObjectIdArray &ids(arArraysOfId[i]);
Geometry::GePoint3dArray &arPts(arArraysOfPoint[i]);
Geometry::GePoint3dArray &arOuter(arOuters[i]);
setZ(arOuter, calcAverageZ(arPts));
AecDbTerrain *pTer(makeTerrain(arPts, arOuter));
if (pTer)
{
if (layerId.isValid()) pTer->setLayer(layerId);
CoreTools::AddToModelSpace(pTer);
}
}
return;
}
}
else
{
Geometry::GePoint3dArray arPts(0);
AcDbObjectIdArray ids;
getAllOfPoints(sFilter, idOrig, arPts, ids);
AecDbTerrain *pTer(makeTerrain(arPts, Geometry::GePoint3dArray()));
if (pTer)
{
if (layerId.isValid()) pTer->setLayer(layerId);
CoreTools::AddToModelSpace(pTer);
return;
}
}
return;
}
void TERRAIN::setSmoothLevelForTerrainMesh()
{
ads_name entTerrain;
struct resbuf *pRb = acutBuildList(RTDXF0, _T("AEC_DBTERRAIN"), 0);
2026-10-04 00:04:20 +08:00
int nRes = CKTCadUtility::SelectEntity(_T("\n选择一个上华地形实体:"), entTerrain, pRb);
2026-09-28 15:28:50 +08:00
if (RTNORM != nRes) return;
acutRelRb(pRb);
OPENOBJ_BEGIN(entTerrain, AcDb::kForWrite, AecDbTerrain, pTer)
{
if (!pTer) return;
int iSm(pTer->getSmoothLevel());
CString str(_T(""));
2026-10-04 00:04:20 +08:00
str.Format(_T("\n请输入平滑度(1-4)<%d>:"), iSm);
2026-09-28 15:28:50 +08:00
acedGetInt(str, &iSm);
pTer->setSmoothLevel(iSm);
}
OPENOBJ_END()
}
void TERRAIN::delHoldForTerrainMesh()
{
ads_name entTerrain;
struct resbuf *pRb = acutBuildList(RTDXF0, _T("AEC_DBTERRAIN"), 0);
2026-10-04 00:04:20 +08:00
int nRes = CKTCadUtility::SelectEntity(_T("\n选择一个上华地形实体:"), entTerrain, pRb);
2026-09-28 15:28:50 +08:00
if (RTNORM != nRes) return;
acutRelRb(pRb);
TCHAR szKey[131] = { _T('S'), };
acedInitGet(RSG_OTHER, _T("S A"));
2026-10-04 00:04:20 +08:00
nRes = acedGetKword(_T("\n请选择[删除单独的洞口(S)/删除全部洞口(A)]<删除单独的洞口(S)>:"), szKey);
2026-09-28 15:28:50 +08:00
if (nRes == RTCAN) return;
if (nRes == RTNONE) _tcscpy(szKey, _T("S"));
if (_tcscmp(szKey, _T("S")) == 0)
{
ads_point adsPt;
2026-10-04 00:04:20 +08:00
if (acedGetPoint(NULL, _T("\n请在要删除的洞口内部选择一点:"), adsPt) != RTNORM) return;
2026-09-28 15:28:50 +08:00
AcGePoint3d ptInput(asPnt3d(adsPt));
CoreTools::UCS2WCS(ptInput, ptInput);
OPENOBJ_BEGIN(entTerrain, AcDb::kForWrite, AecDbTerrain, pTer)
{
if (!pTer) return;
if (pTer->deleteHold(ptInput))
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n删除地形上的洞口成功!"));
2026-09-28 15:28:50 +08:00
else
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n删除地形上的洞口失败!"));
2026-09-28 15:28:50 +08:00
}
OPENOBJ_END()
}
else
{
OPENOBJ_BEGIN(entTerrain, AcDb::kForWrite, AecDbTerrain, pTer)
{
if (!pTer) return;
if (pTer->clearHolds())
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n地形上的洞口全部删除完毕!"));
2026-09-28 15:28:50 +08:00
else
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n全部删除地形上的洞口失败!"));
2026-09-28 15:28:50 +08:00
}
OPENOBJ_END()
}
}
void TERRAIN::addHoldToTerrainMesh()
{
ads_name entTerrain, ssHolds, ent;
struct resbuf *pRb = acutBuildList(RTDXF0, _T("AEC_DBTERRAIN"), 0);
2026-10-04 00:04:20 +08:00
int nRes = CKTCadUtility::SelectEntity(_T("\n选择一个上华地形实体:"), entTerrain, pRb);
2026-09-28 15:28:50 +08:00
if (RTNORM != nRes) return;
acutRelRb(pRb);
AcDbObjectIdArray ids;
CString psz(_T("LWPOLYLINE,CIRCLE"));
resbuf *pRb2 = acutBuildList(RTDXF0, psz, 0);
2026-10-04 00:04:20 +08:00
if (CKTCadUtility::SelectEntities(_T("\n请选择洞口闭合曲线(多段线或圆):"), ssHolds, pRb2) != RTNORM) return;
2026-09-28 15:28:50 +08:00
acutRelRb(pRb2);
AcDbObjectId id;
Adesk::Int32 lLen(0L);
acedSSLength(ssHolds, &lLen);
ids.removeAll();
for (long i = 0; i < lLen; ++i)
{
if (acedSSName(ssHolds, i, ent) != RTNORM) continue;
if (acdbGetObjectId(id, ent) != Acad::eOk) continue;
ids.append(id);
}
acedSSFree(ssHolds);
std::vector<AcGePoint3d> pts;
OPENOBJ_BEGIN(entTerrain, AcDb::kForWrite, AecDbTerrain, pTer)
{
if (!pTer) return;
double dElev(pTer->getElev());
CString str(_T(""));
2026-10-04 00:04:20 +08:00
str.Format(_T("\n请输入洞口标高(单位与高程数据一致),默认为地形平均标高< % .2f>:"), dElev);
2026-09-28 15:28:50 +08:00
acedGetReal(str, &dElev);
for (int i(0); i < ids.length(); ++i)
{
OPENOBJ_BEGIN(ids[i], AcDb::kForRead, AcDbEntity, pHold)
{
if (!pHold) continue;
pts.clear();
AcDbPolyline *pPoly = AcDbPolyline::cast(pHold);
AcDbCircle *pCir = AcDbCircle::cast(pHold);
if (pPoly)
polyline2PointArray(*pPoly, pts, dElev);
else if (pCir)
circle2PointArray(*pCir, pts, dElev);
if (!pts.empty())
pTer->addHold(pts);
}
OPENOBJ_END()
}
}
OPENOBJ_END()
}
void TERRAIN::addHoldForSubDMesh(const AcGePoint3dArray &arPt
, const Geometry::GePolyArray3d &arHold)
{
Geometry::GePoint3dArray pts;
for (int i(0); i < arPt.length(); ++i)
pts.push_back(arPt[i]);
AcGePoint3dArray vertexArray;
AcArray<Adesk::Int32> faceArray;
Geometry::delaunayTriangulationMeshWithHolds(pts, arHold, vertexArray, faceArray);
AcDbSubDMesh *pSubDMesh = new AcDbSubDMesh;
AcDbObjectId layerID(AcDbObjectId::kNull);
g_LayerMgr::instance().getLayer(GLTools::gLayer_DS, layerID);
if (layerID.isValid())
pSubDMesh->setLayer(layerID);
pSubDMesh->setSubDMesh(vertexArray, faceArray, 0);
CoreTools::AddToModelSpace(pSubDMesh);
return;
}
void TERRAIN::getHull()
{
Geometry::GePoint3dArray arPt3Ds(0);
AcDbObjectIdArray ids;
if (!getElevPoints(arPt3Ds, ids)) return;
Geometry::GePoint2dArray ar2d, arOuter;
for (size_t i(0); i < arPt3Ds.size(); ++i)
{
ar2d.push_back(AcGePoint2d(arPt3Ds[i].x, arPt3Ds[i].y));
}
Geometry::calcConvexHull2D(ar2d, arOuter);
AcDbPolyline *pPolyline = new AcDbPolyline();
for (size_t i(0); i < arOuter.size(); ++i)
{
pPolyline->addVertexAt(i, arOuter[i]);
}
pPolyline->setClosed(1);
CoreTools::AddToModelSpace(pPolyline);
}
void TERRAIN::levelTerrainMesh()
{
Geometry::GePoint3dArray arPt3Ds(0);
AcDbObjectId idOrig(AcDbObjectId::kNull);
CString sFilter(getUserSelectType(idOrig));
if (sFilter.IsEmpty()) return;
double dMax(.0), dMin(.0);
2026-10-04 00:04:20 +08:00
if (acedGetReal(_T("\n请输入需要平整的地形的最大标高(单位:米):"), &dMax) != RTNORM) return;
if (acedGetReal(_T("\n请输入需要平整的地形的最小标高(单位:米):"), &dMin) != RTNORM) return;
2026-09-28 15:28:50 +08:00
if (dMin > dMax)
{
double d(dMin);
dMin = dMax;
dMax = d;
}
bool bGenerateTerrain = true;
TCHAR szKey2[131] = { _T('Y'), };
acedInitGet(RSG_OTHER, _T("Y N"));
2026-10-04 00:04:20 +08:00
int nRes = acedGetKword(_T("\n平整成功后,是否立即生成地形?[是(Y)/否(N)]<是(Y)>:"), szKey2);
2026-09-28 15:28:50 +08:00
if (nRes == RTNONE) _tcscpy(szKey2, _T("Y"));
if (_tcscmp(szKey2, _T("Y")) != 0)
bGenerateTerrain = false;
AcDbObjectId layerId = KTSetting::InitLayer(_T("LAY_FACTORY_LAND"), false);
int nSelType(IsSelectAllPoint());
if (nSelType == 0) return;
if (nSelType == 1)
{
std::vector<Geometry::GePoint3dArray> arArraysOfPoint;
std::vector<Geometry::GePoint3dArray> arOuters;
std::vector<AcDbObjectIdArray> arArraysOfId;
nRes = getPointsInAreaByUser(sFilter, idOrig, arArraysOfPoint, arOuters, arArraysOfId);
if (nRes != RTNORM) return;
if (!arArraysOfId.empty()
&& !arArraysOfPoint.empty()
&& !arOuters.empty()
&& arArraysOfId.size() == arArraysOfPoint.size()
&& arArraysOfId.size() == arOuters.size())
{
for (size_t i = 0; i < arArraysOfId.size(); ++i)
{
AcDbObjectIdArray &ids(arArraysOfId[i]);
Geometry::GePoint3dArray &arOuter(arOuters[i]);
2026-10-04 00:04:20 +08:00
// 修改标高
2026-09-28 15:28:50 +08:00
for (int j(0); j < ids.length(); ++j)
modifyElevObj(ids[j], dMax, dMin);
if (bGenerateTerrain)
{
arPt3Ds.clear();
2026-10-04 00:04:20 +08:00
// 修改后重新分析标高
2026-09-28 15:28:50 +08:00
AcGePoint3d pt(AcGePoint3d::kOrigin);
for (int i(0); i < ids.length(); ++i)
{
if (analyElevObj(ids.first(), ids[i], pt))
arPt3Ds.push_back(pt);
}
2026-10-04 00:04:20 +08:00
// 重新为外轮廓设置标高
2026-09-28 15:28:50 +08:00
setZ(arOuter, calcAverageZ(arPt3Ds));
2026-10-04 00:04:20 +08:00
// 生成
2026-09-28 15:28:50 +08:00
AecDbTerrain *pTer(makeTerrain(arPt3Ds, arOuter));
if (pTer)
{
if (layerId.isValid()) pTer->setLayer(layerId);
CoreTools::AddToModelSpace(pTer);
}
}
}
return;
}
}
else
{
Geometry::GePoint3dArray arPts(0);
AcDbObjectIdArray ids;
getAllOfPoints(sFilter, idOrig, arPts, ids);
2026-10-04 00:04:20 +08:00
// 修改标高
2026-09-28 15:28:50 +08:00
for (int i(0); i < ids.length(); ++i)
modifyElevObj(ids[i], dMax, dMin);
if (bGenerateTerrain)
{
arPt3Ds.clear();
2026-10-04 00:04:20 +08:00
// 修改后重新分析标高
2026-09-28 15:28:50 +08:00
AcGePoint3d pt(AcGePoint3d::kOrigin);
for (int i(0); i < ids.length(); ++i)
{
if (analyElevObj(ids.first(), ids[i], pt))
arPt3Ds.push_back(pt);
}
AecDbTerrain *pTer(makeTerrain(arPts, Geometry::GePoint3dArray()));
if (pTer)
{
if (layerId.isValid()) pTer->setLayer(layerId);
CoreTools::AddToModelSpace(pTer);
return;
}
}
return;
}
}
void TERRAIN::extractElevtionData()
{
ads_name adsName;
ads_point adsPt;
2026-10-04 00:04:20 +08:00
int nRes = acedEntSel(_T("\n请选择一个多面网格对象:"), adsName, adsPt);
2026-09-28 15:28:50 +08:00
if (nRes != RTNORM) return;
AcDbObjectId idMesh(AcDbObjectId::kNull);
acdbGetObjectId(idMesh, adsName);
if (!GLTools::isThisClass<AcDbSubDMesh>(idMesh))
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n请选择一个多面网格对象!"));
2026-09-28 15:28:50 +08:00
return;
}
2026-10-04 00:04:20 +08:00
nRes = acedEntSel(_T("\n请选择一个多段线对象:"), adsName, adsPt);
2026-09-28 15:28:50 +08:00
if (nRes != RTNORM) return;
AcDbObjectId idPoly(AcDbObjectId::kNull);
acdbGetObjectId(idPoly, adsName);
if (!GLTools::isThisClass<AcDbPolyline>(idPoly))
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n请选择一个多段线对象!"));
2026-09-28 15:28:50 +08:00
return;
}
2026-10-04 00:04:20 +08:00
nRes = acedEntSel(_T("\n请选择起始桩号:"), adsName, adsPt);
2026-09-28 15:28:50 +08:00
if (nRes != RTNORM) return;
AcDbObjectId StartTxtID(AcDbObjectId::kNull);
acdbGetObjectId(StartTxtID, adsName);
if (!GLTools::isThisClass<AcDbText>(StartTxtID) || !StakeTools::isSHSStake(StartTxtID))
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n请选择一个上华桩号对象。"));
2026-09-28 15:28:50 +08:00
return;
}
2026-10-04 00:04:20 +08:00
nRes = acedEntSel(_T("\n请选择结束桩号:"), adsName, adsPt);
2026-09-28 15:28:50 +08:00
if (nRes != RTNORM) return;
AcDbObjectId EndTxtID(AcDbObjectId::kNull);
acdbGetObjectId(EndTxtID, adsName);
if (!GLTools::isThisClass<AcDbText>(EndTxtID) || !StakeTools::isSHSStake(EndTxtID))
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n请选择一个上华桩号对象。"));
2026-09-28 15:28:50 +08:00
return;
}
2026-10-04 00:04:20 +08:00
// 取出网格和路线的拷贝
2026-09-28 15:28:50 +08:00
AcDbSubDMesh *pCloneMesh(NULL);
OPENOBJ_BEGIN(idMesh, AcDb::kForRead, AcDbSubDMesh, pFaceMesh)
{
if (!pFaceMesh) return;
pCloneMesh = (AcDbSubDMesh*)pFaceMesh->clone();
}
OPENOBJ_END()
AcDbPolyline *pClonePoly(NULL);
OPENOBJ_BEGIN(idPoly, AcDb::kForRead, AcDbPolyline, pPoly)
{
if (!pPoly)
{
DELETE_PTR(pCloneMesh);
return;
}
pClonePoly = (AcDbPolyline*)pPoly->clone();
}
OPENOBJ_END()
bool bS2E;
CString strTemp;
double dTemp;
AcGePoint3d ptStart(AcGePoint3d::kOrigin), ptEnd(AcGePoint3d::kOrigin);
StakeTools::readSHSStake(StartTxtID, ptStart, bS2E, strTemp, dTemp, dTemp);
StakeTools::readSHSStake(EndTxtID, ptEnd, bS2E, strTemp, dTemp, dTemp);
CString strPrefix(_T(""));
StakeTools::analyStakeString(strTemp, dTemp, &strPrefix);
if (!bS2E)
{
AcGePoint3d ptT(ptStart);
ptStart = ptEnd;
ptEnd = ptT;
}
AcDbExtents ext;
pCloneMesh->getGeomExtents(ext);
if ( ptStart.x > ext.maxPoint().x || ptStart.y > ext.maxPoint().y
|| ptStart.x < ext.minPoint().x || ptStart.y < ext.minPoint().y
|| ptEnd.x > ext.maxPoint().x || ptEnd.y > ext.maxPoint().y
|| ptEnd.x < ext.minPoint().x || ptEnd.y < ext.minPoint().y )
{
2026-10-04 00:04:20 +08:00
acutPrintf(_T("\n起起桩号与结束桩号之间的范围大于地形网格的范围。"));
2026-09-28 15:28:50 +08:00
return;
}
if (!EQUAL_ZERO(pClonePoly->elevation()))
pClonePoly->setElevation(.0);
std::vector<AcGePoint3d> pts(0);
getPolyPoints(pClonePoly, ptStart, ptEnd, 1., pts);
std::vector<Face> fs(0);
getSubDMeshFaces(pCloneMesh, fs);
std::vector<FacePoint> fps;
FacePoint fp;
for (size_t i = 0; i < pts.size(); ++i)
{
fp.pt = pts[i];
for (size_t f = 0; f < fs.size(); ++f)
{
Face &face(fs[f]);
if (isInFace(fp.pt, face))
{
fp.setFace(face);
fps.push_back(fp);
break;
}
}
}
std::map<double, CString> mapResult;
int prec(3);
AcGePoint3d ptClosed(AcGePoint3d::kOrigin);
double dist(.0);
for (size_t i = 0; i < fps.size(); ++i)
{
AcGePoint3d &pt(fps[i].pt);
if (Acad::eOk != pClonePoly->getClosestPointTo(pt, ptClosed)) continue;
if (Acad::eOk != pClonePoly->getDistAtPoint(ptClosed, dist)) continue;
mapResult.insert(std::make_pair(dist, TypeConvert::f2s(pt.z, &prec)));
}
if (mapResult.empty())
{
DELETE_PTR(pClonePoly);
DELETE_PTR(pCloneMesh);
return;
}
2026-10-04 00:04:20 +08:00
CString szFilter = _T("纵断数据文件 (*.txt)|*.txt;*.txt||");
CFileDialog fileDlg(FALSE, _T("txt"), _T("纵断数据文件"), OFN_HIDEREADONLY, szFilter, acedGetAcadFrame());
2026-09-28 15:28:50 +08:00
if (fileDlg.DoModal() != IDOK)
{
DELETE_PTR(pClonePoly);
DELETE_PTR(pCloneMesh);
return;
}
CStdioFile file(fileDlg.GetPathName(), CFile::modeCreate|CFile::modeWrite);
if (!file.m_hFile)
{
DELETE_PTR(pClonePoly);
DELETE_PTR(pCloneMesh);
return;
}
std::map<double, CString>::iterator it = mapResult.begin();
CString str(_T(""));
for (; it != mapResult.end(); ++it)
{
str.Format(_T("%s %s\n"), StakeTools::generateStakeString(it->first, strPrefix), it->second);
file.WriteString(str);
}
file.Close();
DELETE_PTR(pClonePoly);
DELETE_PTR(pCloneMesh);
return;
}
#endif
namespace
{
class DBRule: public AcDbEntity
{
public:
DBRule() : entitys(0) { }
~DBRule() { clear(); }
void clear()
{
for (size_t i = 0; i < entitys.size(); ++i)
{
AcDbEntity *p(entitys[i]);
DELETE_PTR(p);
}
entitys.clear();
}
virtual Adesk::Boolean subWorldDraw(AcGiWorldDraw* pWd)
{
for (size_t i = 0; i < entitys.size(); i++)
{
AcDbEntity *p(entitys[i]);
if (p) p->worldDraw(pWd);
}
return Adesk::kTrue;
}
void setEntitys(const std::vector<AcDbEntity*> &ents)
{
clear();
entitys.assign(ents.begin(), ents.end());
}
public:
std::vector<AcDbEntity*> entitys;
};
void drawRule(const AcGePoint3d &ptS
, const AcGePoint3d &ptE
, const double &dElev
, std::vector<AcDbEntity*> &lines)
{
2026-10-04 00:04:20 +08:00
// 刻度1分米
2026-09-28 15:28:50 +08:00
double delta = .1;
AcGeVector3d vtX(ucsXDir()), vtY(ucsYDir());
vtX.normalize();
vtY.normalize();
2026-10-04 00:04:20 +08:00
// 沿ucsX方向画刻度, ucsY方向画数轴
2026-09-28 15:28:50 +08:00
AcGeVector3d vt = ptE - ptS;
int iNegative(1);
if (vt.dotProduct(vtY) < 0)
iNegative = -1;
//delta *= iNegative;
vtY *= iNegative;
double length(vt.length());
lines.push_back(new AcDbLine(ptS, ptS + (vtY * length)));
int step(0), prec(3);
double dist(.0), angle(.0);
AcGePoint3d pt(AcGePoint3d::kOrigin);
while (dist < length)
{
pt = ptS + (vtY * dist);
if (!(step % 10))
{
lines.push_back(new AcDbLine(pt, pt + (vtX * .05)));
AcDbText *pTxt = new AcDbText();
pTxt->setHorizontalMode(AcDb::kTextRight);
pTxt->setVerticalMode(AcDb::kTextVertMid);
pTxt->setAlignmentPoint(pt);
pTxt->setHeight(.04);
pTxt->setTextString(TypeConvert::f2s(dElev + step * .1 * iNegative, &prec));
angle = AcGeVector3d::kXAxis.angleTo(vtX, AcGeVector3d::kZAxis);
pTxt->setRotation(angle);
lines.push_back(pTxt);
}
else if (!(step % 5))
{
lines.push_back(new AcDbLine(pt, pt + (vtX * .03)));
}
else
lines.push_back(new AcDbLine(pt, pt + (vtX * .01)));
dist += delta;
++step;
}
return;
}
class RuleJig :public AcEdJig
{
public:
RuleJig(const AcGePoint3d &ptS, const double &dElev)
: m_pRule(NULL)
, m_ptS(ptS)
, m_dElev(dElev) { m_pRule = new DBRule(); }
~RuleJig() { DELETE_PTR(m_pRule); }
AcEdJig::DragStatus doIt()
{
2026-10-04 00:04:20 +08:00
setDispPrompt(_T("请选择一点做为标尺终点,来确定标尺方向与长度:"));
2026-09-28 15:28:50 +08:00
AcEdJig::DragStatus st = drag();
return st;
}
void getEntitys(std::vector<AcDbEntity*> &ents)
{
for (size_t i = 0; i < m_pRule->entitys.size(); ++i)
ents.push_back((AcDbEntity*)m_pRule->entitys[i]->clone());
}
protected:
virtual AcEdJig::DragStatus sampler()
{
AcEdJig::DragStatus st = acquirePoint(m_ptPos);
return st;
}
virtual Adesk::Boolean update()
{
if (!m_pRule) return Adesk::kFalse;
std::vector<AcDbEntity*> ents(0);
drawRule(m_ptS, m_ptPos, m_dElev, ents);
2026-10-04 00:04:20 +08:00
// 在setEntitys()回收内存
2026-09-28 15:28:50 +08:00
m_pRule->setEntitys(ents);
return Adesk::kTrue;
}
virtual AcDbEntity* entity() const { return m_pRule; }
private:
DBRule *m_pRule;
2026-10-04 00:04:20 +08:00
AcGePoint3d m_ptPos; // 选中点
AcGePoint3d m_ptS; // 开始点
double m_dElev; // 起始标高
2026-09-28 15:28:50 +08:00
};
}
void TERRAIN::GenerateScaleplate()
{
ads_point adsPt;
2026-10-04 00:04:20 +08:00
int nRes = acedGetPoint(NULL, _T("\n请选择一点做为标尺起点:"), adsPt);
2026-09-28 15:28:50 +08:00
if (nRes != RTNORM) return;
acdbUcs2Wcs(adsPt, adsPt, false);
AcGePoint3d ptOrig(asPnt3d(adsPt));
double dElev(.0);
2026-10-04 00:04:20 +08:00
nRes = acedGetReal(_T("\n请输入起点标高<0>:"), &dElev);
2026-09-28 15:28:50 +08:00
if (nRes == RTCAN) return;
RuleJig *pJig = new RuleJig(ptOrig, dElev);
if (pJig->doIt() != AcEdJig::kNormal)
{
DELETE_PTR(pJig);
return;
}
std::vector<AcDbEntity*> lines;
pJig->getEntitys(lines);
AcDbObjectIdArray ids(0);
AcDbObjectId id(AcDbObjectId::kNull);
for (size_t i = 0; i < lines.size(); ++i)
{
if (CoreTools::AddToModelSpace(lines[i], 0, true, &id) == Acad::eOk)
ids.append(id);
}
CoreTools::generateGroup(NULL, ids);
DELETE_PTR(pJig);
}