Files
envi-code/SourceCode/Code2026/EarthWormCmd/stakeOper.cpp
T
2026-09-28 15:28:50 +08:00

3325 lines
88 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "stdarx.h"
#include <algorithm>
#include "stakeoper.h"
#include "dbtable.h"
#include "UITools.h"
#include "aecdbObjXDataMap.h"
#include "KTModelLayoutXData.h"
#include "UITools.h"
#include "KTSetting.h"
#include "KTCadUtility.h"
#include "KTCadUtilityEx.h"
#include <set>
#include "ZDSZDlg.h"
#include "XGLCDlg.h"
#include "AecDbEarthWorm.h"
#include "KTFKDlg.h"
#include "CTSKDlg.h"
#include "AecDbVenDoghouse.h"
#include "MakeDim.h"
#include "AecDb3dRoadAxisLine.h"
#include "TQBGDlg.h"
#include "EWCheckerData.h"
#include "GenerateStakeDlg.h"
#include "GiDrawutility.h"
#include "DGGLDlg.h"
#include "insertEqu.h"
#include "crackEntitytools.h"
extern void PushGripMessage(GripMessage& msg);
namespace
{
#define TEXT_STYLE _T("Pipe_Dim")
}
namespace
{
void split(LPCTSTR pszSrc, TCHAR sp, std::vector<CString> &vec)
{
if (!pszSrc) return;
vec.clear();
CString src(pszSrc);
CString oneString(_T(""));
TCHAR ch;
for (int i = 0; i < src.GetLength(); ++i)
{
ch = src[i];
if (ch == sp)
{
if (oneString.IsEmpty())
continue;
else
{
vec.push_back(oneString);
oneString.Empty();
}
}
else
oneString += ch;
}
if (!oneString.IsEmpty())
vec.push_back(oneString);
}
CString IDCreate()
{
CString sID = _T("");
GUID Guid;
static TCHAR szGuid[39];
RPC_WSTR pszGuid = NULL;
UuidCreate(&Guid);
if (RPC_S_OK != UuidToString(&Guid, &pszGuid))
{
return _T("");
}
lstrcpyn(szGuid, (TCHAR *)pszGuid, sizeof(szGuid));
RpcStringFree(&pszGuid);
szGuid[38] = _T('\0');
sID = szGuid;
sID.MakeUpper();
return sID;
}
void FreeBuffer(int n, const AcDbVoidPtrArray& arEntPtrs)
{
AcDbEntity* pEnt = NULL;
for (int i = n; i < arEntPtrs.length(); i++)
{
pEnt = (AcDbEntity*)arEntPtrs.at(i);
DELETE_PTR(pEnt);
}
}
Acad::ErrorStatus AddToModelSpace(AcDbEntity* pEnt, AcDbDatabase* pDb = NULL, bool bClose = true)
{
if (pDb == NULL)
pDb = acdbHostApplicationServices()->workingDatabase();
Acad::ErrorStatus es;
AcDbBlockTable* pTbl = NULL;
if (Acad::eOk == (es = pDb->getBlockTable(pTbl, AcDb::kForRead)))
{
AcDbBlockTableRecord* pBTR = NULL;
if (Acad::eOk == (es = pTbl->getAt(ACDB_MODEL_SPACE, pBTR, AcDb::kForWrite)))
{
es = pBTR->appendAcDbEntity(pEnt);
if (bClose)
pEnt->close();
pBTR->close();
}
pTbl->close();
}
return es;
}
bool AddToTableRecord(AcDbEntity* pEnt, AcDbObjectId &id, bool bClose = true)
{
if (!pEnt) return false;
OPENOBJ_BEGIN(id, AcDb::kForWrite, AcDbBlockTableRecord, pRec)
if (!pRec) return false;
pRec->appendAcDbEntity(pEnt);
if (bClose) pEnt->close();
OPENOBJ_END()
return true;
}
double getPrinterWidth()
{
AecDbObjXDataMap xDataMap;
KTModelLayoutXData::ReadModelXData(_T("EW_EARTHWORMINIT"), xDataMap);
CString w(_T("1.5"));
xDataMap.GetAt(_T("w1"), w);
return _ttof(w);
}
bool poly3D2Poly2D(AcDbObjectId &id, AcDbPolyline &poly)
{
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDb3dPolyline, p3D)
if (!p3D) return false;
AcGePoint3d ptGe;
AcGePoint3dArray pts;
CStringArray stakes;
CString strValue;
AcDbObjectIterator* pIt = p3D->vertexIterator();
if (!pIt) return false;
int i(0);
for (pIt->start(); !pIt->done(); pIt->step())
{
AcDb3dPolylineVertex* pVtx = NULL;
if (Acad::eOk != p3D->openVertex(pVtx, pIt->objectId(), AcDb::kForRead)) continue;
ptGe = pVtx->position();
poly.addVertexAt(i, ptGe.convert2d(AcGePlane::kXYPlane));
++i;
}
DELETE_PTR(pIt);
OPENOBJ_END()
return true;
}
CString pt2String(const AcGePoint3d &pt)
{
CString str(_T(""));
str.Format(_T("%.3f%.3f%.3f"), pt.x, pt.y, pt.z);
return str;
}
// 取与d最接近的,10的倍数。例:124.789 -> 130.000
double roundUpNum(const double &d, const int &base)
{
if (EQUAL_ZERO(d)) return d;
if (d < base) return base;
double dd(d);
dd /= base;
dd = (int)dd;
dd *= base;
if (EQUAL(dd, d))
return dd;
dd += base;
return dd;
}
}
namespace
{
// 得到AcDbText的插入位置,position()/alignmentPoint()
AcGePoint3d getDbTextPos(AcDbText *pTxt)
{
if (!pTxt) return AcGePoint3d::kOrigin;
if (pTxt->horizontalMode() == AcDb::kTextLeft && pTxt->verticalMode() == AcDb::kTextBase)
return pTxt->position();
else
{
AcGePoint3d pt = pTxt->alignmentPoint();
AcGePoint3d ptPos = pTxt->position();
double dRot = pTxt->rotation();
AcGeVector3d vt(AcGeVector3d::kXAxis);
vt.rotateBy(dRot, AcGeVector3d::kZAxis);
AcDbXline line;
line.setBasePoint(ptPos);
line.setUnitDir(vt);
AcGePoint3d ptRes(pt);
line.getClosestPointTo(pt, ptRes);
return ptRes;
}
return AcGePoint3d::kOrigin;
}
AcDbObjectId insert3dPoly(const std::vector<std::pair<AcGePoint3d, CString>> &pts)
{
if (pts.empty()) return AcDbObjectId::kNull;
AcDb3dPolyline *pPoly3d = new AcDb3dPolyline();
CString strPt(_T(""));
for (size_t i = 0; i < pts.size(); ++i)
{
AecDbObjXDataMap xmap;
const AcGePoint3d &pt(pts[i].first);
AcDb3dPolylineVertex *pVer = new AcDb3dPolylineVertex;
pVer->setPosition(pt);
pPoly3d->appendVertex(pVer);
pPoly3d->setColorIndex(1);
xmap.SetAt(_T("stake"), pts[i].second);
xmap.Write(pVer, _T("PL3D_STAKENO"));
}
g_LayerMgr::instance().setLayer(pPoly3d, GLTools::gLayer_ELEV);
AddToModelSpace(pPoly3d, NULL, true);
return pPoly3d->objectId();
}
void outputTXTFile(const std::vector<std::pair<AcGePoint3d, CString>> &pts, LPCTSTR pszFilter)
{
if (pts.empty()) return;
CString szFilter(pszFilter);
CFileDialog fileDlg(FALSE, _T("stl"), NULL, OFN_HIDEREADONLY, szFilter, acedGetAcadFrame());
if (fileDlg.DoModal() != IDOK) return;
CStdioFile file(fileDlg.GetPathName(), CFile::modeCreate | CFile::modeWrite);
if (!file.m_hFile) return;
CString str(_T(""));
for (size_t i = 0; i < pts.size(); ++i)
{
str.Format(_T("%s,%.3f\n"), pts[i].second, pts[i].first.z);
file.WriteString(str);
}
file.Close();
}
void generateDwgCuter(AcDbPolyline &poly, AcGePoint3d ptStart, const double &dSpace, const double &dWidth)
{
AcGePoint3d pt(AcGePoint3d::kOrigin);
AcGeVector3d vt, vtt;
std::vector<AcGePoint3d> pts(0);
std::vector<AcGeVector3d> vts(0);
double lengthS(.0), lengthE(.0), length(.0), len(.0);
poly.getEndPoint(pt);
poly.getDistAtPoint(pt, lengthE);
poly.getStartPoint(pt);
poly.getDistAtPoint(pt, lengthS);
length = abs(lengthE - lengthS);
poly.getDistAtPoint(ptStart, len);
while (len < length)
{
poly.getPointAtDist(len, pt);
len += dSpace;
pts.push_back(pt);
poly.getFirstDeriv(pt, vt);
vt.rotateBy(PI * .5, AcGeVector3d::kZAxis);
vts.push_back(vt);
}
AcDbObjectId styleID = GLTools::getTextStyle(TEXT_STYLE);
double subLen = dWidth * .08;
double textH = 3.0;
double textAngle(.0);
double textWF(.7);
double lineW = 0; getPrinterWidth();
double textW1(.0), textW2(.0);
AcGePoint3d ptS(AcGePoint3d::kOrigin)
, ptE(AcGePoint3d::kOrigin)
, ptSubS(AcGePoint3d::kOrigin)
, ptSubE(AcGePoint3d::kOrigin);
CString str1(_T("")), str2(_T(""));
for (size_t i = 0; i < vts.size(); ++i)
{
pt = pts[i];
vt = vts[i];
vt.normalize();
vt *= dWidth * .5;
ptSubS = ptS = pt + vt;
ptSubE = ptE = pt - vt;
AcDbPolyline *pLine = new AcDbPolyline;
pLine->addVertexAt(0, AcGePoint2d(ptS.x, ptS.y), 0., lineW, lineW);
pLine->addVertexAt(1, AcGePoint2d(ptE.x, ptE.y), 0., lineW, lineW);
AddToModelSpace(pLine);
vt = ptS - ptE;
vt.normalize();
vt *= subLen;
ptSubS -= vt;
ptSubE += vt;
vt.rotateBy(PI * .5, AcGeVector3d::kZAxis);
vt.normalize();
vt *= subLen * .5;
pLine = new AcDbPolyline;
pLine->addVertexAt(0, (ptSubS + vt).convert2d(AcGePlane::kXYPlane), 0., lineW, lineW);
pLine->addVertexAt(1, (ptSubS - vt).convert2d(AcGePlane::kXYPlane), 0., lineW, lineW);
AddToModelSpace(pLine);
pLine = new AcDbPolyline;
pLine->addVertexAt(0, (ptSubE + vt).convert2d(AcGePlane::kXYPlane), 0., lineW, lineW);
pLine->addVertexAt(1, (ptSubE - vt).convert2d(AcGePlane::kXYPlane), 0., lineW, lineW);
AddToModelSpace(pLine);
str1.Format(_T("%d"), i + 1);
str2.Format(_T("%d"), i + 2);
textAngle = AcGeVector3d::kXAxis.angleTo(vt, AcGeVector3d::kZAxis) + PI;
AcDbExtents ext1, ext2;
AcDbText *pText1 = new AcDbText;
pText1->setTextString(str1);
if (styleID.isValid())
pText1->setTextStyle(styleID);
pText1->setHeight(textH);
pText1->setWidthFactor(textWF);
pText1->setHorizontalMode(AcDb::kTextMid);
pText1->getGeomExtents(ext1);
pText1->setRotation(textAngle);
AcDbText *pText11 = (AcDbText*)pText1->clone();
AcDbText *pText2 = (AcDbText*)pText1->clone();
pText2->setTextString(str2);
pText2->setRotation(.0);
pText2->getGeomExtents(ext2);
pText2->setRotation(textAngle);
AcDbText *pText22 = (AcDbText*)pText1->clone();
pText22->setTextString(str2);
textW1 = ext1.maxPoint().x - ext1.minPoint().x;
textW2 = ext2.maxPoint().x - ext2.minPoint().x;
vtt = vt;
vt.normalize();
vt *= subLen * .5 + textW1 * .75;
pText1->setAlignmentPoint(ptSubS + vt);
pText11->setAlignmentPoint(ptSubE + vt);
vtt.normalize();
vtt *= subLen * .5 + textW2 * .75;
pText2->setAlignmentPoint(ptSubS - vtt);
pText22->setAlignmentPoint(ptSubE - vtt);
AddToModelSpace(pText1);
AddToModelSpace(pText11);
AddToModelSpace(pText2);
AddToModelSpace(pText22);
}
}
void getXLineByDbText(AcDbObjectId id, AcDbXline *pLine)
{
if (!pLine) return;
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, pText)
if (!pText) return;
bool b;
CString str;
double d;
AcGePoint3d pos(AcGePoint3d::kOrigin);
if (!StakeTools::readSHSStake(pText, pos, b, str, d, d))
{
AcDb::TextHorzMode hm = pText->horizontalMode();
AcDb::TextVertMode vm = pText->verticalMode();
if (hm == AcDb::kTextLeft && vm == AcDb::kTextBase)
pos = pText->position();
else
pos = pText->alignmentPoint();
}
double angle = pText->rotation();
AcGeVector3d vt(AcGeVector3d::kXAxis);
vt.rotateBy(angle, AcGeVector3d::kZAxis);
pLine->setBasePoint(pos);
pLine->setUnitDir(vt);
OPENOBJ_END()
}
void getLineByDbText(AcDbObjectId id, AcDbLine *pLine)
{
AcDbExtents ext;
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, pText)
if (!pText) return;
pText->getGeomExtents(ext);
OPENOBJ_END()
pLine->setStartPoint(ext.minPoint());
pLine->setEndPoint(ext.maxPoint());
}
CString getDbTextString(AcDbObjectId id)
{
CString s(_T(""));
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, pText)
if (!pText) return s;
s = pText->textString();
OPENOBJ_END()
return s;
}
struct _com_pnt_psz_pr
{
_com_pnt_psz_pr(AcDbXline &line):xline(line){}
bool operator()(std::pair<AcGePoint3d, CString> &a, std::pair<AcGePoint3d, CString> &b)
{
double dA(.0), dB(.0);
xline.getParamAtPoint(a.first, dA);
xline.getParamAtPoint(b.first, dB);
return dA < dB;
}
AcDbXline &xline;
};
void reverseCurve(AcDbPolyline *pL)
{
if (!pL) return;
#if ARX > 17
pL->reverseCurve();
#else
AcGePoint2d pt1(AcGePoint2d::kOrigin), pt2(AcGePoint2d::kOrigin);
double dStart1(.0), dEnd1(.0), dBulge1(.0), dStart2(.0), dEnd2(.0), dBulge2(.0);
Adesk::Int32 vertexIdentifier1(0), vertexIdentifier2(0);
int len = pL->numVerts() / 2;
int s = 0, e = pL->numVerts() - 1;
for (; s < len; ++s, --e)
{
pL->getPointAt(s, pt1);
pL->getBulgeAt(s, dBulge1);
pL->getWidthsAt(s, dStart1, dEnd1);
#if ARX > 17
pL->getVertexIdentifierAt(s, vertexIdentifier1);
#endif
pL->getPointAt(e, pt2);
pL->getBulgeAt(e, dBulge2);
pL->getWidthsAt(e, dStart2, dEnd2);
#if ARX > 17
pL->getVertexIdentifierAt(e, vertexIdentifier2);
#endif
pL->setPointAt(s, pt2);
pL->setBulgeAt(s, dBulge2 * -1);
pL->setWidthsAt(s, dStart2, dEnd2);
#if ARX > 17
pL->setVertexIdentifierAt(s, vertexIdentifier2);
#endif
pL->setPointAt(e, pt1);
pL->setBulgeAt(e, dBulge1 * -1);
pL->setWidthsAt(e, dStart1, dEnd1);
#if ARX > 17
pL->setVertexIdentifierAt(e, vertexIdentifier1);
#endif
}
return;
#endif
}
}
namespace
{
AcDbText* makeSameText(AcDbObjectId id, LPCTSTR pszContent, const AcGePoint3d &pt)
{
AcDbText *p(NULL);
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, pSrc)
if (!pSrc) return p;
p = (AcDbText *)pSrc->clone();
p->setTextString(pszContent);
AcDb::TextVertMode vmode = p->verticalMode();
AcDb::TextHorzMode hmode = p->horizontalMode();
if (vmode == AcDb::kTextBase || hmode == AcDb::kTextLeft)
p->setPosition(pt);
else
p->setAlignmentPoint(pt);
OPENOBJ_END()
return p;
}
bool Is3DPolylineNode(AcDbObjectId &id, const AcGePoint3d &pt)
{
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDb3dPolyline, p)
if (!p) return false;
AcDbObjectIterator* pIt = p->vertexIterator();
if (!pIt) return false;
AcGePoint3d pt3D(AcGePoint3d::kOrigin);
for (pIt->start(); !pIt->done(); pIt->step())
{
AcDb3dPolylineVertex* pVtx(NULL);
if (Acad::eOk != p->openVertex(pVtx, pIt->objectId(), AcDb::kForRead)) continue;
pt3D = pVtx->position();
if (pt == pt3D)
return true;
}
DELETE_PTR(pIt);
OPENOBJ_END()
return false;
}
bool findPointByStake(AcDbObjectId &id, LPCTSTR psz, AcGePoint3d &pt)
{
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDb3dPolyline, p)
if (!p) return false;
AcDbObjectIterator* pIt = p->vertexIterator();
if (!pIt) return false;
CString strValue(_T(""));
AecDbObjXDataMap xmap;
for (pIt->start(); !pIt->done(); pIt->step())
{
xmap.Empty();
AcDb3dPolylineVertex* pVtx(NULL);
if (Acad::eOk != p->openVertex(pVtx, pIt->objectId(), AcDb::kForRead)) continue;
if (!xmap.Read(pVtx, _T("PL3D_STAKENO"))) continue;
if (!xmap.GetAt(_T("stake"), strValue)) continue;
if (strValue.CompareNoCase(psz) == 0)
{
pt = pVtx->position();
return true;
}
}
DELETE_PTR(pIt);
OPENOBJ_END()
return false;
}
// 根据3DPolyline上的点 pt3D, 得到其在polyline上的投影点
AcGePoint3d get2DPtFromPolylineBy3DPt(const AcGePoint3d &pt3D, const AcDbPolyline &poly)
{
// 理论上,polyline是根据3dpolyline对xoy面投影得到的。所以pt2DOrig一定在polyline上
AcGePoint3d pt;
poly.getClosestPointTo(pt3D, AcGeVector3d::kZAxis, pt);
return pt;
}
// 根据polyline上的点ptOrig,得到一个3DPolyline上的点
AcGePoint3d get3DPtFrom3DPolyline(AcDbObjectId &id3D, const AcGePoint3d &ptOrig)
{
AcGePoint3d pt(AcGePoint3d::kOrigin);
OPENOBJ_BEGIN(id3D, AcDb::kForRead, AcDb3dPolyline, p)
if (!p) return AcGePoint3d::kOrigin;
p->getClosestPointTo(ptOrig, AcGeVector3d::kZAxis, pt);
OPENOBJ_END()
return pt;
}
void insertTo3DPolyline(AcDbObjectId &id, const AcGePoint3d &pt3D)
{
OPENOBJ_BEGIN(id, AcDb::kForWrite, AcDb3dPolyline, p)
if (!p) return;
AcDbObjectId verID(AcDbObjectId::kNull), newID(AcDbObjectId::kNull);
Acad::ErrorStatus es;
AcDbObjectIterator* pIt = p->vertexIterator();
if (!pIt) return;
double insPara(.0), prePara(.0), para(.0);
p->getParamAtPoint(pt3D, insPara);
AcDb3dPolylineVertex *pInsVert(NULL), *pPreVert(NULL);
pInsVert = new AcDb3dPolylineVertex;
pInsVert->setPosition(pt3D);
AcGePoint3d pt(AcGePoint3d::kOrigin);
for (pIt->start(); !pIt->done(); pIt->step())
{
AcDb3dPolylineVertex* pVtx(NULL);
es = p->openVertex(pVtx, pIt->objectId(), AcDb::kForRead);
if (es != Acad::eOk) continue;
pt = pVtx->position();
p->getParamAtPoint(pt, para);
// 说明此节点已存在,跳过
if (para == insPara)
{
acutPrintf(_T("\n节点存在,跳过。"));
pPreVert = pVtx;
continue;
}
if (para > insPara)
{
verID = pVtx->objectId();
break;
}
pPreVert = pVtx;
}
es = p->insertVertexAt(newID, verID, pInsVert);
pInsVert->close();
DELETE_PTR(pIt);
OPENOBJ_END()
}
void collectDbText(std::vector<AcDbObjectId> &vec)
{
ads_name ss, ent;
struct resbuf* pRb = acutBuildList(RTDXF0, _T("TEXT"), 0);
int nRes = acedSSGet(_T("A"), NULL, NULL, pRb, ss);
if (nRes != RTNORM)
{
acutPrintf(_T("\n没有发现桩号文字。"));
return;
}
AcDbObjectId id(AcDbObjectId::kNull);
Adesk::Int32 lLen = 0L;
acedSSLength(ss, &lLen);
AcString str;
for (long i = 0; i < lLen; i++)
{
if (acedSSName(ss, i, ent) != RTNORM) continue;
if (acdbGetObjectId(id, ent) != Acad::eOk) continue;
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, pTxt)
if (!pTxt) continue;
OPENOBJ_BEGIN(pTxt->blockId(), AcDb::kForRead, AcDbBlockTableRecord, pRec)
if (pRec)
{
pRec->getName(str);
if (CString(ACDB_MODEL_SPACE).CompareNoCase(str) != 0) continue;
vec.push_back(id);
}
OPENOBJ_END()
OPENOBJ_END()
}
acedSSFree(ss);
}
void addStakeForRedLine(AcDbObjectId &idRed, AcDbObjectId &idText, const double &dist)
{
// 对各个参数的保护性判断,放在调用端
AcDbPolyline poly2d;
if (!poly3D2Poly2D(idRed, poly2d))
{
acutPrintf(_T("\n曲线转换失败。"));
return;
}
AcGePoint3d pt3DStart(AcGePoint3d::kOrigin), pt3DEnd(AcGePoint3d::kOrigin);
AcGePoint3d pt2DStart(AcGePoint3d::kOrigin), pt2DEnd(AcGePoint3d::kOrigin);
// 起始/线束 桩号字符串
CString strStart(_T("")), strEnd(_T(""));
// 桩号前缀
CString prefix(_T(""));
// 开始桩号上的字符串数值
double stakeStartValue(.0);
// 开始/结束 桩号的真实距离
double startDist(.0), endDist(.0);
OPENOBJ_BEGIN(idText, AcDb::kForRead, AcDbText, pTxt)
strStart = pTxt->textString();
OPENOBJ_END()
// 找到起始点
if (!findPointByStake(idRed, strStart, pt3DStart))
{
acutPrintf(_T("\n3DPolyline线并没有和%s桩号关联。"), strStart);
return;
}
if (!StakeTools::analyStakeString(strStart, stakeStartValue, &prefix))
{
acutPrintf(_T("\n桩号形式满足要求(例:K1+123)"));
return;
}
poly2d.getClosestPointTo(pt3DStart, pt2DStart);
poly2d.getDistAtPoint(pt2DStart, startDist);
AcGePoint3d pt2D, pt3D;
CString sStake(_T(""));
startDist += dist;
stakeStartValue += dist;
poly2d.getPointAtDist(startDist, pt2D);
pt3D = get3DPtFrom3DPolyline(idRed, pt2D);
if (Is3DPolylineNode(idRed, pt3D)) return;
sStake = StakeTools::generateStakeString(stakeStartValue, prefix);
AcDbText *p = makeSameText(idText, sStake, pt3D);
AddToModelSpace(p);
}
bool getIntersectPoint(AcDbObjectId &idText, AcDbObjectId &idPoly, AcGePoint3d &pt)
{
AcDbXline xline;
getXLineByDbText(idText, &xline);
AcGePoint3dArray pts;
OPENOBJ_BEGIN(idPoly, AcDb::kForRead, AcDbCurve, pPoly)
pPoly->intersectWith(&xline, AcDb::kOnBothOperands, AcGePlane::kXYPlane, pts);
if (pts.isEmpty())
{
acutPrintf(_T("\n文字方向延长线不与选中的polyline相交。"));
return false;
}
OPENOBJ_END();
pt = pts[0];
return !pts.isEmpty();
}
Acad::ErrorStatus getDistAtPoint(AcDbObjectId id, const AcGePoint3d &pt, double &dist)
{
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbCurve, pPoly)
if (pPoly)
return pPoly->getDistAtPoint(pt, dist);
OPENOBJ_END();
return Acad::eInvalidInput;
}
Acad::ErrorStatus getPointAtDist(AcDbObjectId id, const double &dist, AcGePoint3d &pt)
{
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbCurve, pPoly)
if (pPoly)
return pPoly->getPointAtDist(dist, pt);
OPENOBJ_END();
return Acad::eInvalidInput;
}
Acad::ErrorStatus getFirstDeriv(AcDbObjectId id, const AcGePoint3d &pt, AcGeVector3d &vt)
{
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbCurve, pPoly)
if (pPoly)
return pPoly->getFirstDeriv(pt, vt);
OPENOBJ_END();
return Acad::eInvalidInput;
}
Acad::ErrorStatus getClosestPointTo(AcDbObjectId id, const AcGePoint3d &ptGive, AcGePoint3d &ptOn)
{
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbCurve, pPoly)
if (pPoly)
return pPoly->getClosestPointTo(ptGive, ptOn);
OPENOBJ_END();
return Acad::eInvalidInput;
}
AcDbObjectId getCenterRoldLine(LPCTSTR pszPrompt, LPCTSTR pszFilter)
{
double dw = CKTCadUtility::GetPickBoxSize();
ads_point pt;
ads_name ss, ent;
int nRes = acedEntSel(pszPrompt, ent, pt);
if (nRes != RTNORM) return AcDbObjectId::kNull;
ads_point pt1, pt2;
pt1[0] = pt[0] - dw;
pt1[1] = pt[1] - dw;
pt1[2] = pt[2];
pt2[0] = pt[0] + dw;
pt2[1] = pt[1] + dw;
pt2[2] = pt[2];
struct resbuf* pRb = acutBuildList(RTDXF0, pszFilter, 0);
nRes = acedSSGet(_T("C"), pt1, pt2, NULL, ss);
acutRelRb(pRb);
Adesk::Int32 len(0);
acedSSLength(ss, &len);
AcDbObjectId id(AcDbObjectId::kNull);
for (long i = 0; i < len; ++i)
{
if (acedSSName(ss, i, ent) != RTNORM) continue;
if (acdbGetObjectId(id, ent) != Acad::eOk) continue;
if (GLTools::isThisClass<AcDbPolyline>(id))
return id;
if (GLTools::isThisClass<AcDbLine>(id))
return id;
if (GLTools::isThisClass<AcDbArc>(id))
return id;
id == AcDbObjectId::kNull;
continue;
}
acedSSFree(ss);
return id;
}
bool getAllStake(std::map<double, AcDbObjectId, GLTools::compare_double> &stakes)
{
assert(false);
stakes.clear();
ads_name ss, ent;
struct resbuf* pRb = acutBuildList(RTDXF0, _T("TEXT"), 0);
int nRes = acedSSGet(_T("A"), NULL, NULL, pRb, ss);
if (nRes != RTNORM) return false;
Adesk::Int32 lLen(0L);
acedSSLength(ss, &lLen);
AcString str;
CString sTxt(_T(""));
double dist(.0);
AcDbObjectId id;
for (long i = 0; i < lLen; i++)
{
if (acedSSName(ss, i, ent) != RTNORM) continue;
if (acdbGetObjectId(id, ent) != Acad::eOk) continue;
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, pTxt)
if (!pTxt) continue;
OPENOBJ_BEGIN(pTxt->blockId(), AcDb::kForRead, AcDbBlockTableRecord, pRec)
if (pRec)
{
pRec->getName(str);
if (CString(ACDB_MODEL_SPACE).CompareNoCase(str) != 0) continue;
}
OPENOBJ_END()
sTxt = pTxt->textString();
if (!StakeTools::analyStakeString(sTxt, dist)) continue;
stakes.insert(std::make_pair(dist, id));
OPENOBJ_END()
}
acedSSFree(ss);
return !stakes.empty();
}
bool getSHSStake(LPCTSTR pszPrompt
,AcDbObjectId &idTxt
, double &dist
, CString &prefix
, bool &bStart2End
, bool &bThousands
, AcGePoint3d *ptIns = NULL
, CString *orignString = NULL )
{
return StakeTools::getSHSStake(pszPrompt, idTxt, dist, prefix, bStart2End, bThousands, ptIns, orignString);
}
}
namespace
{
typedef std::map<double, double, GLTools::compare_double> D2DMap;
void drawCircle(const AcGePoint3d &pt, const double &r = 10)
{
AcDbCircle *p = new AcDbCircle(pt, AcGeVector3d::kZAxis, r);
AddToModelSpace(p);
}
// 解析高程文件
void analyElevationFile(LPCTSTR pszFile, D2DMap &mapStake)
{
if (!pszFile) return;
if (_taccess(pszFile, 0x0) != 0x0) return;
CStdioFile file(pszFile, CFile::shareDenyRead);
CString strLine(_T("")), sStake(_T("")), sElev(_T(""));
std::vector<CString> vecs;
double dDist(.0), dElev(.0);
CString prefix(_T("K"));
while (file.ReadString(strLine))
{
split(strLine, _T(' '), vecs);
if (vecs.size() != 2)
{
vecs.clear();
split(strLine, _T(','), vecs);
if (vecs.size() != 2)
continue;
}
sStake = vecs[0];
sElev = vecs[1];
if (!StakeTools::IsDoubleString(sElev)) continue;
dElev = _convert_<double, string>((LPCTSTR)sElev);
// 直接就是桩号距离
if (StakeTools::IsDoubleString(sStake))
dDist = _convert_<double, string>((LPCTSTR)sStake);
else if (StakeTools::analyStakeString(sStake, dDist, &prefix))
{
// 空
}
else
continue;
mapStake.insert(std::make_pair(dDist, dElev));
}
file.Close();
}
// 根据桩号文字的距离,得到其高程
bool getElevationByStakeDist(const double &dist, const D2DMap &mapStake, double &elev)
{
D2DMap::const_iterator it = mapStake.find(dist);
if (it != mapStake.end())
{
elev = it->second;
return true;
}
// 如果 dist 不在集合中,则取出其前后两个高程,
D2DMap::const_iterator itLeft(mapStake.begin()), itRight(mapStake.end());
for (D2DMap::const_iterator it = mapStake.begin(); it != mapStake.end(); ++it)
{
itRight = it;
if (it->first > dist)
{
if (it == mapStake.begin())
return false;
itLeft = --it;
// 根据前后两个高程,计算出真实高程
elev = ((itRight->first - itLeft->first) - (dist - itLeft->first))
* (abs(itRight->second - itLeft->second) / (itRight->first - itLeft->first))
+ __min(itRight->second, itLeft->second);
return true;
}
}
return false;
}
void makeSameDir(AcDbObjectId &polyId, AcDbObjectId &centerId)
{
OPENOBJ_BEGIN(centerId, AcDb::kForRead, AcDbPolyline, pCenter)
if (!pCenter) return;
OPENOBJ_BEGIN(polyId, AcDb::kForWrite, AcDbPolyline, pPoly)
if (!pPoly) return;
AcGePoint3d ptCenterStart(AcGePoint3d::kOrigin), ptCenterEnd(AcGePoint3d::kOrigin);
AcGePoint3d ptPolyStart(AcGePoint3d::kOrigin), ptPolyEnd(AcGePoint3d::kOrigin);
pCenter->getStartPoint(ptCenterStart);
pCenter->getEndPoint(ptCenterEnd);
pPoly->getStartPoint(ptPolyStart);
pPoly->getEndPoint(ptPolyEnd);
AcGeVector3d vtCenter(ptCenterEnd - ptCenterStart);
AcGeVector3d vtPoly(ptPolyEnd - ptPolyStart);
if (vtCenter.dotProduct(vtPoly) >= 0) return;
acutPrintf(_T("\n选中的polyline与道路中心线方向相反。进行反转。"));
// 将 polylid 反向
#if ARX > 17
pPoly->reverseCurve();
#else
reverseCurve(pPoly);
#endif
OPENOBJ_END()
OPENOBJ_END()
}
}
namespace
{
struct STakeInfo
{
bool init(AcDbObjectId idText, const std::map<double, double, GLTools::compare_double> &dmap)
{
AcString str;
CString sTxt;
AcGePoint3d ptTxt;
OPENOBJ_BEGIN(idText, AcDb::kForRead, AcDbText, pTxt)
if (!pTxt) return false;
OPENOBJ_BEGIN(pTxt->blockId(), AcDb::kForRead, AcDbBlockTableRecord, pRec)
if (pRec)
{
pRec->getName(str);
if (CString(ACDB_MODEL_SPACE).CompareNoCase(str) != 0) return false;
}
id = idText;
OPENOBJ_END()
sTxt = pTxt->textString();
if (!StakeTools::analyStakeString(sTxt, dist)) return false;
stake = sTxt;
std::map<double, double, GLTools::compare_double>::const_iterator it = dmap.find(dist);
if (it == dmap.end()) return false;
elev = it->second;
OPENOBJ_END()
return true;
}
struct compare_dist{ bool operator () (const STakeInfo &a, const STakeInfo &b) const { return a.dist < b.dist; } };
AcDbObjectId id;
CString stake;
double dist;
double elev;
};
}
namespace
{
void mergeWithLeft(AecDbEarthWorm *pEw, AecDbEarthWorm *pLeft, bool bModifyStartElev)
{
pLeft->SetNextDir(pEw->GetHeadDir());
pEw->SetLastDir(pLeft->GetTailDir());
if (bModifyStartElev)
pEw->SetStartElevation(pLeft->EndElevation(), false);
}
void mergeWithLeft(AecDbEarthWorm *pEw, AcDbObjectId idLeft, bool bModifyStartElev)
{
OPENOBJ_BEGIN(idLeft, AcDb::kForWrite, AecDbEarthWorm, pLeft)
if (!pLeft) return;
mergeWithLeft(pEw, pLeft, bModifyStartElev);
OPENOBJ_END()
}
}
namespace
{
AcDbObjectId searchSHStakeByString(const std::vector<AcDbObjectId> &ids, LPCTSTR psz, AcDbObjectId &leftId)
{
AcDbObjectId id(AcDbObjectId::kNull);
if (!psz || ids.empty()) return id;
double dDist(.0), dDistTxt(.0);
if (!StakeTools::analyStakeString(psz, dDist)) return id;
for (size_t i = 0; i < ids.size(); ++i)
{
id = ids[i];
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, p)
if (!p) continue;
StakeTools::analyStakeString(p->textString(), dDistTxt);
if (EQUAL(dDistTxt, dDist)) break;
if (UP_ZERO(dDistTxt - dDist))
{
if (i != 0)
leftId = ids[i - 1];
id = AcDbObjectId::kNull;
break;
}
OPENOBJ_END()
}
return id;
}
void getRay(AcDbObjectId &id, AcDbRay &ray, const double &dAngle)
{
OPENOBJ_BEGIN(id, AcDb::kForWrite, AecDbEarthWorm, pEw)
AcGePoint2d pt2dS(AcGePoint2d::kOrigin), pt2dE(AcGePoint2d::kOrigin);
pt2dS = pEw->StartPoint();
pt2dE = pEw->EndPoint();
AcGeVector3d vt3d = AcGePoint3d(pt2dE.x, pt2dE.y, .0) - AcGePoint3d(pt2dS.x, pt2dS.y, .0);
vt3d.rotateBy(dAngle, AcGeVector3d::kZAxis);
ray.setBasePoint(AcGePoint3d(pt2dS.x, pt2dS.y, .0));
ray.setUnitDir(vt3d);
OPENOBJ_END()
}
void getXline(AcDbObjectId &idTxt, AcDbObjectId &idLeftTxt, AcDbXline &xline, AcDbObjectId &idPoly, LPCTSTR stake)
{
double dRot(.0);
AcGePoint3d ptBase(AcGePoint3d::kOrigin);
AcGeVector3d vtBase(AcGeVector3d::kXAxis);
if (idTxt.isValid())
{
OPENOBJ_BEGIN(idTxt, AcDb::kForRead, AcDbText, pTxt)
if (!pTxt)
{
acutPrintf(_T("\n搜索出的桩号出现问题。"));
return;
}
dRot = pTxt->rotation();
ptBase = pTxt->alignmentPoint();
vtBase.rotateBy(dRot, AcGeVector3d::kZAxis);
OPENOBJ_END()
}
else
{
if (!idLeftTxt.isValid())
{
acutPrintf(_T("\nidLeftText无效。"));
return;
}
double dLeft(.0), d(.0);
AcGeVector3d vtOld(AcGeVector3d::kXAxis);
OPENOBJ_BEGIN(idLeftTxt, AcDb::kForRead, AcDbText, pTxt)
if (!pTxt)
{
acutPrintf(_T("\n搜索出的桩号出现问题。"));
return;
}
StakeTools::analyStakeString(pTxt->textString(), dLeft);
vtOld.rotateBy(pTxt->rotation(), AcGeVector3d::kZAxis);
OPENOBJ_END()
StakeTools::analyStakeString(stake, d);
double delta(d - dLeft);
AcGePoint3d ptInsLeft(AcGePoint3d::kOrigin), ptInsNew(AcGePoint3d::kOrigin);
bool b;
CString s;
StakeTools::readSHSStake(idLeftTxt, ptInsLeft, b, s, d, d);
getDistAtPoint(idPoly, ptInsLeft, d);
getPointAtDist(idPoly, d + delta, ptBase);
getFirstDeriv(idPoly, ptBase, vtBase);
vtBase.rotateBy(PI * .5, AcGeVector3d::kZAxis);
if (vtBase.dotProduct(vtOld) < 0)
vtBase.rotateBy(PI, AcGeVector3d::kZAxis);
}
xline.setBasePoint(ptBase);
xline.setUnitDir(vtBase);
}
}
namespace
{
void GiDrawPipeTest()
{
AcDbEntity *p(NULL);
ads_name adsEnt;
ads_point adsPt;
int rt;
TCHAR szKey[131] = {};
acedInitGet(RSG_OTHER, _T("1 2 3"));
rt = acedGetKword(_T("\n请选择[通过半径壁厚绘制(1)/通过闭合polyline做为截面绘制(2)/通过region做为截面绘制(3)]<通过半径壁厚绘制(1)>:"), szKey);
if (rt == RTNONE) _tcscpy(szKey, _T("1"));
else if (rt == RTCAN) return;
if (_tcscmp(szKey, _T("1")) == 0)
{
double dR(100), dT(10);
rt = acedGetReal(_T("\n请输入管线半径<100>:"), &dR);
rt = acedGetReal(_T("\n请输入管线厚度<10>:"), &dT);
rt = acedGetPoint(NULL, _T("\n请选择起点:"), adsPt);
ads_point adsPt1;
acdbUcs2Wcs(adsPt, adsPt1, false);
if (rt != RTNORM) return;
AcGePoint3d ptS(asPnt3d(adsPt1));
rt = acedGetPoint(adsPt, _T("\n请选择终点:"), adsPt);
acdbUcs2Wcs(adsPt, adsPt1, false);
if (rt != RTNORM) return;
AcGePoint3d ptE(asPnt3d(adsPt1));
p = GiDrawUtility::DrawPipe(ptS, ptE, dR, dT);
AddToModelSpace(p);
return;
}
rt = acedEntSel(_T("\n选择一段曲线做为管线路径:"), adsEnt, adsPt);
if (rt != RTNORM) return;
AcDbObjectId id;
acdbGetObjectId(id, adsEnt);
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbCurve, pPath)
if (!pPath)
{
acutPrintf(_T("\n所选实体不是曲线。"));
return;
}
if (_tcscmp(szKey, _T("2")) == 0)
{
rt = acedEntSel(_T("\n请选择一个闭合的polyline做为管线截面:"), adsEnt, adsPt);
if (rt != RTNORM) return;
AcDbObjectId idSection;
acdbGetObjectId(idSection, adsEnt);
OPENOBJ_BEGIN(idSection, AcDb::kForRead, AcDbPolyline, pSection)
if (!pSection)
{
acutPrintf(_T("\n所选实体不是polyline。"));
return;
}
AcDbExtents ext;
pSection->getGeomExtents(ext);
AcGePoint3d ptOn((ext.maxPoint().x + ext.minPoint().x) * .5, (ext.maxPoint().y + ext.minPoint().y) * .5, (ext.maxPoint().z + ext.minPoint().z) * .5);
p = GiDrawUtility::DrawPipe(pPath, pSection, ptOn);
if (p) AddToModelSpace(p);
OPENOBJ_END()
}
else
{
rt = acedEntSel(_T("\n请选择一个region做为管线截面:"), adsEnt, adsPt);
if (rt != RTNORM) return;
AcDbObjectId idSection;
acdbGetObjectId(idSection, adsEnt);
OPENOBJ_BEGIN(idSection, AcDb::kForRead, AcDbRegion, pSection)
if (!pSection)
{
acutPrintf(_T("\n所选实体不是region。"));
return;
}
AcDbExtents ext;
pSection->getGeomExtents(ext);
AcGePoint3d ptOn((ext.maxPoint().x + ext.minPoint().x) * .5, (ext.maxPoint().y + ext.minPoint().y) * .5, (ext.maxPoint().z + ext.minPoint().z) * .5);
p = GiDrawUtility::DrawPipe(pPath, pSection, ptOn);
if (p) AddToModelSpace(p);
OPENOBJ_END()
}
OPENOBJ_END()
}
}
namespace
{
bool insertVertexForPolyline(AcDbPolyline *pPoly, const AcGePoint3d &pt)
{
if (!pPoly) return false;
if (pPoly->numVerts() <= 2) return false;
AcGePoint2d pt1, pt2, pt2D(pt.x, pt.y);
double dist, dist1(.0), dist2(.0);
pPoly->getDistAtPoint(pt, dist);
// 判断在哪个seg上
double bulge, r;
AcGeCircArc2d arc;
int negative(1);
for (int i = 0; i < pPoly->numVerts() - 1; i++)
{
pPoly->getPointAt(i, pt1);
pPoly->getPointAt(i + 1, pt2);
pPoly->getBulgeAt(i, bulge);
pPoly->getDistAtPoint(AcGePoint3d(pt1.x, pt1.y, 0.), dist1);
pPoly->getDistAtPoint(AcGePoint3d(pt2.x, pt2.y, 0.), dist2);
// 判断是否在两个端点上,如果是,走人
if (pt2D.distanceTo(pt1) < 1e-7) return true;
if (pt2D.distanceTo(pt2) < 1e-7) return true;
// 不在pt1,pt2内,走人
if (dist < dist1 || dist > dist2) continue;
if (abs(bulge) < 1e-7) // 直线
{
pPoly->addVertexAt(i+1, pt2D);
}
else // 弧线
{
negative = bulge > 0 ? 1 : -1;
pPoly->getArcSegAt(i, arc);
r = arc.radius();
pPoly->setBulgeAt(i, tan((dist - dist1) / r * .25) * negative);
pPoly->addVertexAt(i+1, pt2D, tan((dist2 - dist) / r * .25) * negative);
}
}
return true;
}
// 取出 vertex1和vertex2之间的曲线,vertex1,vertex2为节点
AcDbPolyline* cutPolyline(AcDbPolyline* pPoly, AcGePoint3d &vertex1, AcGePoint3d &vertex2)
{
if (!pPoly) return NULL;
double d(.0), d1(.0), d2(.0);
pPoly->getDistAtPoint(vertex1, d1);
pPoly->getDistAtPoint(vertex2, d2);
if (d1 > d2)
{
AcGePoint3d pt(vertex1);
vertex1 = vertex2;
vertex2 = pt;
pPoly->getDistAtPoint(vertex1, d1);
pPoly->getDistAtPoint(vertex2, d2);
}
AcGePoint2d pt(AcGePoint2d::kOrigin)
, pt1(vertex1.x, vertex1.y)
, pt2(vertex2.x, vertex2.y);
int idx1(-1), idx2(-1);
for (int i = 0; i < pPoly->numVerts(); i++)
{
pPoly->getPointAt(i, pt);
if (pt.distanceTo(pt1) <= 1e-7)
idx1 = i;
if (pt.distanceTo(pt2) <= 1e-7)
idx2 = i;
}
AcDbPolyline *p = new AcDbPolyline();
for (int i = idx1, v=0; i <= idx2; ++i, ++v)
{
pPoly->getPointAt(i, pt);
pPoly->getBulgeAt(i, d);
p->addVertexAt(v, pt, d);
}
return p;
}
AcDbPolyline* MergePolyline(AcDbPolyline *pPoly)
{
if (!pPoly) return NULL;
AcDbPolyline *pClone = (AcDbPolyline*)pPoly->clone();
if (pPoly->numVerts() <= 2) return pClone;
AcGePoint2d pt;
AcGeLineSeg2d seg1, seg2;
double bulge1(.0), bulge2(.0);
AcGeVector2d v1, v2;
for (int i = 0; i < pClone->numVerts() - 2; ++i)
{
pClone->getBulgeAt(i, bulge1);
pClone->getBulgeAt(i + 1, bulge2);
pClone->getPointAt(i + 1, pt);
if (abs(bulge1) < 1e-7 && abs(bulge2) < 1e-7) // 第1段与2段都是直线
{
pClone->getLineSegAt(i, seg1);
pClone->getLineSegAt(i + 1, seg2);
v1 = seg1.direction();
v2 = seg2.direction();
if (seg1.direction() == seg2.direction()) // 方向且相同,则去掉中间的vertex
{
pClone->removeVertexAt(i + 1);
i = -1;
}
}
continue;
}
return pClone;
}
}
//////////////////////////////////////////////////////////////////////////
namespace StakeOper
{
struct STBgs
{
// 桩号总距离,标高,曲率半径, 与上一个桩号的距离差
double distance, elevation, radius, subDistance;
};
// 取与dist最近的左右两个gbs点
void findClosed(const std::vector<STBgs> &vec, const double &dist, STBgs &big, STBgs &smal)
{
for (size_t i = 0; i < vec.size(); ++i)
{
const STBgs &bgs = vec[i];
if (bgs.distance > dist)
{
big = bgs;
if (i - 1 < 0)
{
acutPrintf(_T("\nfindClosed出现越界,请检查。"));
return;
}
smal = vec[i - 1];
break;
}
}
}
void offsetEWLine(AcDbObjectId id, double dOffset)
{
ads_point pt1, pt2;
AcGePoint3d ptFirst(AcGePoint3d::kOrigin);
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDb3dPolyline, pPoly)
if (!pPoly) return;
double len;
pPoly->getEndParam(len);
pPoly->getPointAtDist(len * .5, ptFirst);
OPENOBJ_END()
ptFirst.z = 0.;
acdbWcs2Ucs(asDblArray(ptFirst), pt2, false);
acedGetPoint(pt2, _T("\n请指定要偏移的那一侧上的点:"), pt1);
ads_point pt0, pt11;
acdbUcs2Wcs(pt2, pt0, false);
acdbUcs2Wcs(pt1, pt11, false);
AcGeVector3d vtDir = asPnt3d(pt11) - asPnt3d(pt0);
AcDbRay ray;
ray.setBasePoint(asPnt3d(pt0));
ray.setUnitDir(vtDir);
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDb3dPolyline, pPoly)
if (!pPoly) return;
AcGePoint3d ptGe;
AcGePoint3dArray pts;
CStringArray stakes;
CString strValue;
AcDbObjectIterator* pIt = pPoly->vertexIterator();
if (!pIt) return;
for (pIt->start(); !pIt->done(); pIt->step())
{
AcDb3dPolylineVertex* pVtx = NULL;
if (Acad::eOk == pPoly->openVertex(pVtx, pIt->objectId(), AcDb::kForRead))
{
AecDbObjXDataMap xmap;
if (xmap.Read(pVtx, _T("PL3D_STAKENO")));
{
ptGe = pVtx->position();
if (xmap.GetAt(_T("stake"), strValue))
{
pts.append(ptGe);
stakes.Add(strValue);
}
}
pVtx->close();
}
}
DELETE_PTR(pIt);
if (stakes.IsEmpty())
{
acutPrintf(_T("\n选择的实体没有道路中心线信息!"));
}
//点投影到xy面
AcDbPolyline* pPl = new AcDbPolyline;
pPl->setNormal(AcGeVector3d::kZAxis);
pPl->setElevation(0.0);
for (int i = 0; i < pts.length(); i++)
{
pPl->addVertexAt(i, pts.at(i).convert2d(AcGePlane::kXYPlane));
}
AcDbPolyline* pPlOffset = NULL;
Acad::ErrorStatus es;
//提取偏移线-------------------------------------------------------------------
AcDbVoidPtrArray arPlPtr1;
es = pPl->getOffsetCurves(dOffset, arPlPtr1);
if (arPlPtr1.length() == 1)
{
AcDbPolyline* pPlOffset1 = (AcDbPolyline*)arPlPtr1.first();
AcGePoint3dArray arPoints1;
es = pPlOffset1->intersectWith(&ray, AcDb::kOnBothOperands, arPoints1);
if (!arPoints1.isEmpty())
{
pPlOffset = pPlOffset1;
}
else
{
DELETE_PTR(pPlOffset1);
}
}
AcDbVoidPtrArray arPlPtr2;
es = pPl->getOffsetCurves(-dOffset, arPlPtr2);
if (arPlPtr2.length() == 1)
{
AcDbPolyline* pPlOffset2 = (AcDbPolyline*)arPlPtr2.first();
AcGePoint3dArray arPoints2;
pPlOffset2->intersectWith(&ray, AcDb::kOnBothOperands, arPoints2);
if (!arPoints2.isEmpty())
{
pPlOffset = pPlOffset2;
}
else
{
DELETE_PTR(pPlOffset2);
}
}
DELETE_PTR(pPl);
//合成新的3dpolyline ----------------------------------------------------------
if (pPlOffset != NULL)
{
AcDb3dPolyline* p3dpL = new AcDb3dPolyline;
p3dpL->setColorIndex(1);
AcGePoint3d ptGe;
for (int i = 0; i < pPlOffset->numVerts(); i++)
{
pPlOffset->getPointAt(i, ptGe);
if (i < pts.length())
{
ptGe.z = pts.at(i).z;
}
AecDbObjXDataMap xmap;
AcDb3dPolylineVertex *pVer = new AcDb3dPolylineVertex;
pVer->setPosition(ptGe);
xmap.SetAt(_T("stake"), stakes.GetAt(i));
xmap.Write(pVer, _T("PL3D_STAKENO"));
p3dpL->appendVertex(pVer);
}
AddToModelSpace(p3dpL, NULL, true);
DELETE_PTR(pPlOffset);
}
else
{
acutPrintf(_T("\n偏移道路中心线失败 (ERROR:%d)!"), es);
return;
}
OPENOBJ_END()
}
// 解析 bgs 文件
bool analyBGSFile(LPCTSTR szPath, std::vector<STBgs> &bgss)
{
if (_taccess(szPath, 0x0) != 0x0) return false;
CStdioFile file(szPath, CFile::shareDenyRead);
if (!file.m_hFile) return false;
CString strLine(_T(""));
std::vector<CString> vecs;
STBgs bgs = {.0, .0, .0};
while (file.ReadString(strLine))
{
strLine.Trim(_T('('));
strLine.Trim(_T(')'));
split(strLine, _T(' '), vecs);
if (vecs.size() < 2)
{
split(strLine, _T(','), vecs);
if (vecs.size() < 2) continue;
}
if (!StakeTools::analyStakeString(vecs[0], bgs.distance))
{
if (StakeTools::IsDoubleString(vecs[0]))
bgs.distance = _ttof(vecs[0]);
else
continue;
}
bgs.elevation = _ttof(vecs[1]);
if (vecs.size() > 2)
bgs.radius = _ttof(vecs[2]);
bgss.push_back(bgs);
}
if (!bgss.empty())
bgss[0].subDistance = bgss[0].distance;
for (size_t i = 1; i < bgss.size(); ++i)
{
STBgs &bgs0 = bgss[i - 1];
STBgs &bgs1 = bgss[i];
bgs1.subDistance = bgs1.distance - bgs0.distance;
}
file.Close();
return true;
}
// 生成参照曲线
void generateReferenceCurve()
{
return;
}
// 生成管廊红线
void generateEWLine()
{
ads_name adsName;
ads_point adsPnt;
double dSpace(20.)
, dOffset(50.)
, dStartDist(.0)
, dEndDist(.0);
AcDbObjectId refCurveID(AcDbObjectId::kNull)
, StartTxtID(AcDbObjectId::kNull)
, EndTxtID(AcDbObjectId::kNull);
CString strPrefix(_T("")), str(_T(""));
int nRes = acedEntSel(_T("\n请选择参照曲线:"), adsName, adsPnt);
if (nRes != RTNORM) return;
acdbGetObjectId(refCurveID, adsName);
if (!GLTools::isThisClass<AecDb3dRoadAxisLine>(refCurveID))
{
acutPrintf(_T("\n选择的实体不是参照曲线。"));
return;
}
nRes = acedEntSel(_T("\n请选择初始桩号<选择参照线起点>:"), adsName, adsPnt);
if (nRes != RTNORM) return;
acdbGetObjectId(StartTxtID, adsName);
if (!GLTools::isThisClass<AcDbText>(StartTxtID))
{
acutPrintf(_T("\n请选择一个文字对象。"));
return;
}
nRes = acedEntSel(_T("\n请选择结束桩号<选择参照线终点>:"), adsName, adsPnt);
if (nRes == RTNORM) acdbGetObjectId(EndTxtID, adsName);
nRes = acedGetReal(_T("\n请输入两段桩号的间距<20>:"), &dSpace);
nRes = acedGetReal(_T("\n请输入与参照曲线的偏移距离<50>:"), &dOffset);
OPENOBJ_BEGIN(StartTxtID, AcDb::kForRead, AcDbText, p)
str = p->textString();
if (!StakeTools::analyStakeString(str, dStartDist, &strPrefix))
{
acutPrintf(_T("\n选择的桩号文字内容出错,请检查是否是\"K1+123\"形式。"));
return;
}
// 处理一下 dStartDist,取整
dStartDist = roundUpNum(dStartDist, 10);
OPENOBJ_END()
OPENOBJ_BEGIN(EndTxtID, AcDb::kForRead, AcDbText, p)
if (p)
{
str = p->textString();
if (!StakeTools::analyStakeString(str, dEndDist))
{
acutPrintf(_T("\n选择的桩号文字内容出错,请检查是否是\"K1+123\"形式。"));
return;
}
}
else // 取参考线总长
{
OPENOBJ_BEGIN(refCurveID, AcDb::kForRead, AecDb3dRoadAxisLine, pL)
pL->getEndParam(dEndDist);
OPENOBJ_END()
}
OPENOBJ_END()
std::vector<std::pair<AcGePoint3d, CString>> pts(0);
double dist(dStartDist/* + dSpace*/);
AcGePoint3d pt;
OPENOBJ_BEGIN(refCurveID, AcDb::kForRead, AecDb3dRoadAxisLine, p)
while (dist < dEndDist)
{
p->getPointAtDist(dist, pt);
str = StakeTools::generateStakeString(dist);
pts.push_back(std::make_pair(pt, str));
AcDbText *pTxt = makeSameText(StartTxtID, str, pt);
pTxt->setPosition(pt);
AddToModelSpace(pTxt);
dist += dSpace;
}
AcDbObjectId redID = insert3dPoly(pts);
offsetEWLine(redID, dOffset);
OPENOBJ_BEGIN(redID, AcDb::kForWrite, AcDbEntity, pRd)
if (pRd) pRd->erase();
OPENOBJ_END()
if (AfxMessageBox(_T("是否输出管廊高程线文件?"), MB_YESNO) == IDYES)
{
outputTXTFile(pts, _T("管廊高程文件 (*.txt)|*.txt;*.txt||"));
}
OPENOBJ_END()
}
// 提取整数桩号标高
void extractStakeElevation()
{
// 读取bgs文件
CString szFilter = _T("桩号数据 (*.txt;*.bgs;*.sqx)|*.txt;*.bgs;*.sqx|所有文件(*.*)|*.*||");
CFileDialog fileDlg(TRUE, _T("桩号数据"), NULL, OFN_HIDEREADONLY, szFilter, acedGetAcadFrame());
int nRes = fileDlg.DoModal();
if (nRes != IDOK) return;
CString strFile = fileDlg.GetPathName();
std::vector<STBgs> bgss(0);
if (!analyBGSFile(strFile, bgss))
{
acutPrintf(_T("\n解析文件%s出错,请检查文件。"), strFile);
return;
}
if (bgss.empty())
{
acutPrintf(_T("\n解析文件%s出错,请检查文件。"), strFile);
return;
}
// 弹出对话框,用户选择一个桩号,输入一段间距
CAcModuleResourceOverride myResources;
CTQBGDlg dlg(bgss.rbegin()->distance, bgss.begin()->distance);
if (dlg.DoModal() != IDOK)
return;
double start = dlg.getStart();
double end = dlg.getEnd();
double Space = dlg.getSpace(); // 间距
// 取出与selBgs最近的一个整数桩号(10的倍数)
//start = roundUpNum(start, 10);
std::vector<std::pair<AcGePoint3d, CString>> pts(0);
STBgs big, smal;
double z(.0);
CString stake(_T(""));
while (start <= end)
{
// 找到与之最近的两个存在bgs桩号点,连直线,
// 沿起点移动start - bgs.distance 距离,
// 求出直线上的pt点,取其z值
findClosed(bgss, start, big, smal);
z = ((big.distance - smal.distance) - (start - smal.distance))
* (abs(big.elevation - smal.elevation) / (big.distance - smal.distance))
+ __min(big.elevation, smal.elevation);
stake = StakeTools::generateStakeString(start);
pts.push_back(std::make_pair(AcGePoint3d(0.,0.,z), stake));
start += Space;
}
// 放入最后一个
pts.push_back(std::make_pair(AcGePoint3d(0, 0, bgss.rbegin()->elevation), StakeTools::generateStakeString(bgss.rbegin()->distance)));
outputTXTFile(pts, _T("管廊高程文件 (*.txt)|*.txt||"));
}
// 提取图纸中的桩号及桩号对应的地面高程和设计高程
void extractElevationByDwg()
{
ads_point pt;
ads_name name_stake, name_ground, name_design;
AcDbObjectId idStake, idGround, idDesign;
int nRes = acedEntSel(_T("\n请选择“里程与桩号”所在行的行头。"), name_stake, pt);
if (nRes != RTNORM) return;
acdbGetObjectId(idStake, name_stake);
if (!GLTools::isThisClass<AcDbText>(idStake))
{
acutPrintf(_T("\n请选择一个文字对象。"));
return;
}
nRes = acedEntSel(_T("\n请选择“地面高程”所在行的行头。"), name_ground, pt);
if (nRes != RTNORM) return;
acdbGetObjectId(idGround, name_ground);
if (!GLTools::isThisClass<AcDbText>(idGround))
{
acutPrintf(_T("\n请选择一个文字对象。"));
return;
}
nRes = acedEntSel(_T("\n请选择“设计高程”所在行的行头。"), name_design, pt);
if (nRes != RTNORM) return;
acdbGetObjectId(idDesign, name_design);
if (!GLTools::isThisClass<AcDbText>(idDesign))
{
acutPrintf(_T("\n请选择一个文字对象。"));
return;
}
// 收集所有模型空间内文字对象
std::vector<AcDbObjectId> ids(0);
collectDbText(ids);
// 去掉三个行头文字ID
std::vector<AcDbObjectId>::iterator it = std::find(ids.begin(), ids.end(), idStake);
if (it != ids.end()) ids.erase(it);
it = std::find(ids.begin(), ids.end(), idGround);
if (it != ids.end()) ids.erase(it);
it = std::find(ids.begin(), ids.end(), idDesign);
if (it != ids.end()) ids.erase(it);
// 取出三个XLine
AcDbXline xlineStake, xlineGround, xlineDesign;
AcDbLine line;
getXLineByDbText(idStake, &xlineStake);
getXLineByDbText(idGround, &xlineGround);
getXLineByDbText(idDesign, &xlineDesign);
std::vector<std::pair<AcGePoint3d, CString>> mapStake, mapGround, mapDesign;
AcGePoint3dArray arrPnts;
CString str(_T(""));
for (size_t i = 0; i < ids.size(); ++i)
{
arrPnts.removeAll();
getLineByDbText(ids[i], &line);
str = getDbTextString(ids[i]);
// 进行桩号判断
line.intersectWith(&xlineStake, AcDb::kOnBothOperands, AcGePlane::kXYPlane, arrPnts);
if (arrPnts.length() == 1 && StakeTools::IsStakeString(str))
{
mapStake.push_back(std::make_pair(arrPnts[0], str));
continue;
}
// 进行地面高程判断
line.intersectWith(&xlineGround, AcDb::kOnBothOperands, AcGePlane::kXYPlane, arrPnts);
if (arrPnts.length() == 1 && StakeTools::IsDoubleString(str))
{
mapGround.push_back(std::make_pair(arrPnts[0], str));
continue;
}
// 进行设计高程判断
line.intersectWith(&xlineDesign, AcDb::kOnBothOperands, AcGePlane::kXYPlane, arrPnts);
if (arrPnts.length() == 1 && StakeTools::IsDoubleString(str))
{
mapDesign.push_back(std::make_pair(arrPnts[0], str));
continue;
}
}
// 排序
std::sort(mapStake.begin(), mapStake.end(), _com_pnt_psz_pr(xlineStake));
std::sort(mapGround.begin(), mapGround.end(), _com_pnt_psz_pr(xlineGround));
std::sort(mapDesign.begin(), mapDesign.end(), _com_pnt_psz_pr(xlineDesign));
// 理论上,三个集合的大小应该一至,为了容错,取出最小size
size_t count = __min(mapStake.size(), mapGround.size());
count = __min(count, mapDesign.size());
std::vector<std::pair<AcGePoint3d, CString>> ground(0), design(0);
double dG(.0), dD(.0);
for (size_t i = 0; i < count; ++i)
{
CString &stake = mapStake[i].second;
dG = _ttof(mapGround[i].second);
dD = _ttof(mapDesign[i].second);
ground.push_back(std::make_pair(AcGePoint3d(0, 0, dG), stake));
design.push_back(std::make_pair(AcGePoint3d(0, 0, dD), stake));
}
outputTXTFile(ground, _T("地面高程文件 (*.txt)|*.txt;*.txt||"));
outputTXTFile(design, _T("设计高程文件 (*.txt)|*.txt;*.txt||"));
}
void generateCenterLineOfRoad()
{
CString szFilter = _T("道路中心线数据 (*.txt)|*.txt;*.txt||");
CFileDialog fileDlg(TRUE, _T("stl"), NULL, OFN_HIDEREADONLY, szFilter, acedGetAcadFrame());
int nRes = fileDlg.DoModal();
if (nRes != IDOK) return;
CString strFile = fileDlg.GetPathName();
if (_taccess(strFile, 0x0) != 0x0) return;
CStdioFile file(strFile, CFile::shareDenyRead);
CString strLine(_T("")), sStake(_T("")), sElev(_T(""));
std::vector<CString> vecs;
std::map<double, double, GLTools::compare_double> mapStake;
double dDist(.0), dElev(.0);
CString prefix(_T("K"));
while (file.ReadString(strLine))
{
split(strLine, _T(','), vecs);
if (vecs.size() != 2) continue;
sStake = vecs[0];
sElev = vecs[1];
if (!StakeTools::IsDoubleString(sElev)) continue;
dElev = _convert_<double, string>((LPCTSTR)sElev);
// 直接就是桩号距离
if (StakeTools::IsDoubleString(sStake))
dDist = _convert_<double, string>((LPCTSTR)sStake);
else if (StakeTools::analyStakeString(sStake, dDist, &prefix))
{
// 空
}
else
continue;
mapStake.insert(std::make_pair(dDist, dElev));
}
file.Close();
// 得到全图的 acdbtext 实体。对比内容,如果内容与文件中的一致,则取文字基点的 x,y 值,且z值为文件中桩号的数据。
ads_name ss, ent;
struct resbuf* pRb = acutBuildList(RTDXF0, _T("TEXT"), 0);
nRes = acedSSGet(_T("A"), NULL, NULL, pRb, ss);
if (nRes != RTNORM)
{
acutPrintf(_T("\n没有发现桩号文字。"));
return;
}
bool b;
std::set<CString> strSet;
std::pair<std::set<CString>::iterator, bool> pr;
CString sTxt(_T(""));
AcGePoint3d ptTxt(AcGePoint3d::kOrigin);
double d;
AcDbObjectId id;
Adesk::Int32 lLen = 0L;
acedSSLength(ss,&lLen);
std::vector<std::pair<AcGePoint3d, CString>> pts(0);
AcString str;
std::map<double, AcGePoint3d, GLTools::compare_double> mapPt;
for (long i = 0; i < lLen; i++)
{
if (acedSSName(ss,i,ent) != RTNORM) continue;
if (acdbGetObjectId(id, ent) != Acad::eOk) continue;
if (!StakeTools::isSHSStake(id)) continue;
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbText, pTxt)
if (pTxt != NULL)
{
OPENOBJ_BEGIN(pTxt->blockId(), AcDb::kForRead, AcDbBlockTableRecord, pRec)
if (pRec)
{
pRec->getName(str);
if (CString(ACDB_MODEL_SPACE).CompareNoCase(str) != 0) continue;
}
OPENOBJ_END()
if (!StakeTools::readSHSStake(pTxt, ptTxt, b, sTxt, d, d)) continue;
if (!StakeTools::analyStakeString(sTxt, dDist)) continue;
mapPt.insert(std::make_pair(dDist, ptTxt));
}
OPENOBJ_END()
}
acedSSFree(ss);
std::map<double, double, GLTools::compare_double>::iterator it = mapStake.begin();
std::map<double, AcGePoint3d, GLTools::compare_double>::iterator itPt;
for (; it != mapStake.end(); ++it)
{
itPt = mapPt.find(it->first);
if (itPt == mapPt.end()) continue;
AcGePoint3d pt(itPt->second);
pt.z = it->second;
pts.push_back(std::make_pair(pt, StakeTools::generateStakeString(it->first, prefix)));
}
if (pts.empty())
{
acutPrintf(_T("\n未找到与文件匹配的桩号。"));
return;
}
insert3dPoly(pts);
}
void generateCenterLineOfRoadByPoint()
{
ads_name ent;
ads_point adsPt;
int nRes;
std::vector<std::pair<AcGePoint3d, CString>> pts(0);
AcDbObjectId id;
while ((nRes = acedEntSel(_T("\n请选择一个文字对象或块对象"), ent, adsPt)) == RTNORM)
{
acdbGetObjectId(id, ent);
OPENOBJ_BEGIN(id, AcDb::kForRead, AcDbEntity, pEnt)
if (pEnt)
{
AcDbText *pText = AcDbText::cast(pEnt);
if (pText)
pts.push_back(std::make_pair(getDbTextPos(pText), pText->textString()));
AcDbBlockReference *pRef = AcDbBlockReference::cast(pEnt);
if (pRef)
pts.push_back(std::make_pair(pRef->position(), _T("")));
}
else
acutPrintf(_T("\n所选择的实体不是文字对象或块对象,请重新选择!"));
OPENOBJ_END()
}
insert3dPoly(pts);
}
// 添加总分图线
void appendDwgCuter_ZT()
{
ads_name ent;
ads_point adsPt;
int nRes = acedEntSel(_T("\n请选择地面高程线"), ent, adsPt);
if (nRes != RTNORM) return;
// 分图线高度
double dWidth(80.0);
// 分图线间隔
double dSpace(200.0);
AcDbObjectId idPoly;
acdbGetObjectId(idPoly, ent);
AcDbPolyline poly;
if (!poly3D2Poly2D(idPoly, poly))
{
acutPrintf(_T("\n请选择由\"地高程线\"命令生成的地面高程线。"));
return;
}
if (acedGetReal(_T("\n请输入分图线高度:<80>"), &dWidth) == RTCAN) return;
if (acedGetReal(_T("\n请输入分图线间隔:<200>"), &dSpace) == RTCAN) return;
AcGePoint3d ptFirst(AcGePoint3d::kOrigin);
ads_point adsPtUCS;
poly.getStartPoint(ptFirst);
acdbWcs2Ucs(asDblArray(ptFirst), adsPtUCS, false);
nRes = acedGetPoint(adsPtUCS, _T("\n请选择地面高程线上一点,做为首个分图线的起点:"), adsPt);
if (nRes != RTNORM) return;
ads_point adsPtWCS;
acdbUcs2Wcs(adsPt, adsPtWCS, false);
AcGePoint3d ptStart(asPnt3d(adsPtWCS)), pt(AcGePoint3d::kOrigin);
if (poly.getClosestPointTo(ptStart, ptStart) != Acad::eOk)
{
acutPrintf(_T("\n所选择的点无效,请重新选择."));
return;
}
generateDwgCuter(poly, ptStart, dSpace, dWidth);
return;
}
// 添加断分图线
void appendDwgCuter_ZD()
{
ads_name ent;
ads_point adsPt;
int nRes = acedEntSel(_T("\n请选择管廊分段:"), ent, adsPt);
if (nRes != RTNORM) return;
AcDbObjectId id;
acdbGetObjectId(id, ent);
AcDbObjectIdArray ids;
OPENOBJ_BEGIN(id, AcDb::kForRead, AecDbEarthWorm, pWorm)
if (!pWorm)
{
acutPrintf(_T("\n请选择一段管廊."));
return;
}
GetConnectedWorms(pWorm, ids);
OPENOBJ_END()
// 分图线高度
double dWidth(80.0);
// 分图线间隔
double dSpace(200.0);
if (acedGetReal(_T("\n请输入分图线高度:<80>"), &dWidth) == RTCAN) return;
if (acedGetReal(_T("\n请输入分图线间隔:<200>"), &dSpace) == RTCAN) return;
AcDbPolyline *pPoly = new AcDbPolyline;
for (size_t i = 0; i < ids.length(); ++i)
{
OPENOBJ_BEGIN(ids[i], AcDb::kForRead, AecDbEarthWorm, pWorm)
if (!pWorm) continue;
pPoly->addVertexAt(i, pWorm->VStartPoint());
if (i == ids.length() - 1)
pPoly->addVertexAt(i + 1, pWorm->VEndPoint());
OPENOBJ_END()
}
pPoly->setColorIndex(1);
AcDbPolyline poly;
poly.copyFrom(pPoly);
AddToModelSpace(pPoly);
AcDbObjectId idPoly = pPoly->objectId();
AcGePoint3d ptFirst(AcGePoint3d::kOrigin);
ads_point adsPtUCS;
poly.getStartPoint(ptFirst);
acdbWcs2Ucs(asDblArray(ptFirst), adsPtUCS, false);
nRes = acedGetPoint(adsPtUCS, _T("\n请选择地面高程线上一点,做为首个分图线的起点:"), adsPt);
if (nRes != RTNORM) return;
ads_point adsPtWCS;
acdbUcs2Wcs(adsPt, adsPtWCS, false);
AcGePoint3d ptStart(asPnt3d(adsPtWCS)), pt(AcGePoint3d::kOrigin);
if (poly.getClosestPointTo(ptStart, ptStart) != Acad::eOk)
{
acutPrintf(_T("\n所选择的点无效,请重新选择."));
return;
}
generateDwgCuter(poly, ptStart, dSpace, dWidth);
OPENOBJ_BEGIN(idPoly, AcDb::kForWrite, AcDbPolyline, pL)
if (pL) pL->erase();
OPENOBJ_END()
}
// 为管廊红线批量插入桩号
void splite3DPolyline()
{
ads_name name;
ads_point adsPt;
int nRes = acedEntSel(_T("\n请选择一条3dPolyLine线。"), name, adsPt);
if (nRes != RTNORM) return;
AcDbObjectId idPoly(AcDbObjectId::kNull), idTextStart(AcDbObjectId::kNull), idTextEnd(AcDbObjectId::kNull);
acdbGetObjectId(idPoly, name);
if (!GLTools::isThisClass<AcDb3dPolyline>(idPoly))
{
acutPrintf(_T("\n选择的对象不是3DPolyLine。"));
return;
}
AcDbPolyline poly2d;
if (!poly3D2Poly2D(idPoly, poly2d))
{
acutPrintf(_T("\n曲线转换失败。"));
return;
}
#if 0
AcDbPolyline *pL = new AcDbPolyline;
pL->copyFrom(&poly2d);
pL->setColorIndex(2);
AddToModelSpace(pL);
#endif
AcGePoint3d pt3DStart(AcGePoint3d::kOrigin), pt3DEnd(AcGePoint3d::kOrigin);
AcGePoint3d pt2DStart(AcGePoint3d::kOrigin), pt2DEnd(AcGePoint3d::kOrigin);
// 起始/线束 桩号字符串
CString strStart(_T("")), strEnd(_T(""));
// 桩号前缀
CString prefix(_T(""));
// 开始桩号上的字符串数值
double stakeStartValue(.0);
// 开始/结束 桩号的真实距离
double startDist(.0), endDist(.0);
nRes = acedEntSel(_T("\n请选择一个桩号文字做为开始桩号。"), name, adsPt);
if (nRes == RTNORM)
{
acdbGetObjectId(idTextStart, name);
if (!GLTools::isThisClass<AcDbText>(idTextStart))
{
acutPrintf(_T("\n选择的对象不是文字对象。"));
return;
}
OPENOBJ_BEGIN(idTextStart, AcDb::kForRead, AcDbText, pTxt)
strStart = pTxt->textString();
OPENOBJ_END()
// 找到起始点
if (!findPointByStake(idPoly, strStart, pt3DStart))
{
acutPrintf(_T("\n3DPolyline线并没有和%s桩号关联。"), strStart);
return;
}
if (!StakeTools::analyStakeString(strStart, stakeStartValue, &prefix))
{
acutPrintf(_T("\n桩号形式满足要求(例:K1+123)"));
return;
}
poly2d.getClosestPointTo(pt3DStart, pt2DStart);
poly2d.getDistAtPoint(pt2DStart, startDist);
}
else
{
return;
}
nRes = acedEntSel(_T("\n请选择一个桩号文字做为结束桩号。<选择终点桩号>"), name, adsPt);
if (nRes == RTNORM)
{
acdbGetObjectId(idTextEnd, name);
if (!GLTools::isThisClass<AcDbText>(idTextEnd))
{
acutPrintf(_T("\n选择的对象不是文字对象。"));
return;
}
OPENOBJ_BEGIN(idTextEnd, AcDb::kForRead, AcDbText, pTxt)
strEnd = pTxt->textString();
OPENOBJ_END()
// 找到终点
if (!findPointByStake(idPoly, strEnd, pt3DEnd))
{
acutPrintf(_T("\n3DPolyline线并没有和%s桩号关联。"), strEnd);
return;
}
poly2d.getClosestPointTo(pt3DEnd, pt2DEnd);
poly2d.getDistAtPoint(pt2DEnd, endDist);
}
else
{
AcGePoint3d pt(AcGePoint3d::kOrigin);
poly2d.getEndPoint(pt);
poly2d.getDistAtPoint(pt, endDist);
}
if (startDist >= endDist)
{
acutPrintf(_T("结束桩号应该在起始桩号之后,请重新选择。"));
return;
}
double dSpace(20.0);
nRes = acedGetReal(_T("\n请输入桩号间距<20>"), &dSpace);
if (nRes == RTERROR) return;
AcGePoint3d pt2D, pt3D;
CString sStake(_T(""));
while (startDist < endDist)
{
startDist += dSpace;
stakeStartValue += dSpace;
poly2d.getPointAtDist(startDist, pt2D);
pt3D = get3DPtFrom3DPolyline(idPoly, pt2D);
if (Is3DPolylineNode(idPoly, pt3D)) continue;
sStake = StakeTools::generateStakeString(stakeStartValue, prefix);
AcDbText *p = makeSameText(idTextStart, sStake, pt3D);
AddToModelSpace(p);
//insertTo3DPolyline(idPoly, pt3D);
#if 0
AcDbCircle *pC = new AcDbCircle;
pC->setCenter(pt2D);
pC->setRadius(1);
AddToModelSpace(pC);
pC = new AcDbCircle;
pC->setCenter(pt3D);
pC->setRadius(1);
AddToModelSpace(pC);
#endif
}
}
// 为道路中心线批量插入桩号
void spliteCenterLine()
{
assert(false);
ads_point pt;
ads_name ent;
int nRes;
// 选择中心线
AcDbObjectId idCenter = getCenterRoldLine(_T("\n请选择道路中心线。"), _T("LWPOLYLINE,LINE,ARC"));
if (!idCenter.isValid())
{
acutPrintf(_T("\n未找到道路中心线,请选择一个(多段线,直线或弧线对象)。"));
return;
}
if (!GLTools::isThisClass<AcDbCurve>(idCenter)) return;
// 起始桩号,结束桩号
bool bThousands(false); // 桩号形式
CString sPrefix(_T("")); // 桩号前缀
CString sStakeStart(_T("")), sStakeEnd(_T("")); // 桩号文字
double dTextDistStart(.0), dTextDistEnd(.0); // 桩号文字所表示的距离
double dDistOnLineStart(.0), dDistOnLineEnd(.0); // 文字投射到曲线上的点的距离
AcGePoint3d ptStakeStart(AcGePoint3d::kOrigin), ptStakeEnd(AcGePoint3d::kOrigin); // 桩号文字与曲线交点
AcDbObjectId idTextStart(AcDbObjectId::kNull), idTextEnd(AcDbObjectId::kNull);
//////////////////////////////////////////////////////////////////////////
nRes = acedEntSel(_T("\n请选择起始参考桩号:"), ent, pt);
if (nRes != RTNORM) return;
acdbGetObjectId(idTextStart, ent);
if (!GLTools::isThisClass<AcDbText>(idTextStart))
{
acutPrintf(_T("\n请选择一个文字对象。"));
return;
}
sStakeStart = getDbTextString(idTextStart);
if (!StakeTools::analyStakeString(sStakeStart, dTextDistStart, &sPrefix, &bThousands))
{
acutPrintf(_T("\n选择的文字对象不是桩号。"));
return;
}
if (!getIntersectPoint(idTextStart, idCenter, ptStakeStart))
{
acutPrintf(_T("\n文字方向延长线不与选中的polyline相交。"));
return;
}
//////////////////////////////////////////////////////////////////////////
nRes = acedEntSel(_T("\n请选择结束参考桩号:"), ent, pt);
if (nRes != RTNORM) return;
acdbGetObjectId(idTextEnd, ent);
if (!GLTools::isThisClass<AcDbText>(idTextEnd))
{
acutPrintf(_T("\n请选择一个文字对象。"));
return;
}
sStakeEnd = getDbTextString(idTextEnd);
if (!StakeTools::analyStakeString(sStakeEnd, dTextDistEnd, &sPrefix))
{
acutPrintf(_T("\n选择的文字对象不是桩号。"));
return;
}
if (!getIntersectPoint(idTextEnd, idCenter, ptStakeEnd))
{
acutPrintf(_T("\n文字方向延长线不与选中的polyline相交。"));
return;
}
//////////////////////////////////////////////////////////////////////////
double dSpace(20);
acedGetReal(_T("\n请输入桩号之间距离<20>"), &dSpace);
//////////////////////////////////////////////////////////////////////////
getDistAtPoint(idCenter, ptStakeStart, dDistOnLineStart);
getDistAtPoint(idCenter, ptStakeEnd, dDistOnLineEnd);
CString newStake(_T("")); // 新桩号字符串
double newOnLineDist(.0); // 新桩号与曲线的交点在曲线上的距离
double newStakeDist(.0); // 新桩号与曲线的交点在曲线上的距离
AcGePoint3d ptIns(AcGePoint3d::kOrigin);// 新桩号插入点
AcGeVector3d vtOld(AcGeVector3d::kXAxis), vtCut(AcGeVector3d::kIdentity);
// 曲线方向与桩号方向一至
bool bSameDir((dDistOnLineEnd - dDistOnLineStart) * (dTextDistEnd - dTextDistStart) > 0);
newOnLineDist = dDistOnLineStart + (bSameDir ? 1 : -1) * dSpace;
newStakeDist = dTextDistStart + dSpace;
std::map<double, AcDbObjectId, GLTools::compare_double> mapStakes;
getAllStake(mapStakes);
while (newStakeDist < dTextDistEnd)
{
if (!bThousands)
newStake.Format(_T("%s+%.3f"), sPrefix, newStakeDist);
else
newStake = StakeTools::generateStakeString(newStakeDist, sPrefix);
if (getPointAtDist(idCenter, newOnLineDist, ptIns) != Acad::eOk)
{
acutPrintf(_T("\n根据距离取点出错。%s"), newStake);
continue;
}
newOnLineDist = newOnLineDist + (bSameDir ? 1 : -1) * dSpace;
newStakeDist = newStakeDist + dSpace;
vtOld = AcGeVector3d::kXAxis;
vtCut = AcGeVector3d::kIdentity;
if (getFirstDeriv(idCenter, ptIns, vtCut) != Acad::eOk)
{
acutPrintf(_T("\n取导数出错。%s"), newStake);
continue;
}
if (mapStakes.find(newStakeDist - dSpace) != mapStakes.end())
{
acutPrintf(_T("\n找到重复桩号%s。"), newStake);
continue;
}
AcDbText *pText(NULL);
OPENOBJ_BEGIN(idTextStart, AcDb::kForRead, AcDbText, pTxt)
pText = (AcDbText*)pTxt->clone();
vtOld.rotateBy(pTxt->rotation(), AcGeVector3d::kZAxis);
OPENOBJ_END()
// 得到文字方向
vtCut.rotateBy(PI * .5, AcGeVector3d::kZAxis);
if (vtCut.dotProduct(vtOld) < 0)
vtCut.rotateBy(PI, AcGeVector3d::kZAxis);
double angle = vtCut.angleTo(AcGeVector3d::kXAxis);
pText->setRotation(angle);
pText->setTextString(newStake);
pText->horizontalMode();
if (pText->horizontalMode() == AcDb::kTextLeft && pText->verticalMode() == AcDb::kTextBottom)
pText->setPosition(ptIns);
else
pText->setAlignmentPoint(ptIns);
AddToModelSpace(pText);
}
}
// 添加桩号
void addStake()
{
AcDbObjectId idStartTxt(AcDbObjectId::kNull), idEndTxt(AcDbObjectId::kNull), idPoly(AcDbObjectId::kNull);
ads_point pt;
int nRes;
idPoly = getCenterRoldLine(_T("\n请选择道路中心线(Polyline对象)。"), _T("LWPOLYLINE,LINE,ARC"));
if (!GLTools::isThisClass<AcDbCurve>(idPoly))
{
acutPrintf(_T("\n请选择一个Polyline对象。"));
return;
}
double dOrigStakeDistStart(.0);
CString strPrefix(_T("")), strNew(_T(""));
bool bThousands(false);
bool bStart2End(true);
AcGePoint3d ptStartStake(AcGePoint3d::kOrigin);
if (!getSHSStake(_T("\n请选择起始参考桩号:"), idStartTxt, dOrigStakeDistStart, strPrefix, bStart2End, bThousands, &ptStartStake)) return;
double dist(.0) // 用户输入距离
, dSel(.0) // 用户点选点的距离
, dOrigIntersctDistStart(.0) // 起始桩号文字对象在中心线上的距离
, dNewDist // 新桩号距离
, dOrigIntersctDistEnd(.0); // 结束桩号文字对象在中心线上的距离
AcGePoint3d ptSel(AcGePoint3d::kOrigin);
AcGeVector3d vtCut(AcGeVector3d::kIdentity);
AcGePoint3d ptIns(AcGePoint3d::kOrigin), ptEndStake(AcGePoint3d::kOrigin);
AcGePoint3dArray pts;
getDistAtPoint(idPoly, ptStartStake, dOrigIntersctDistStart);
TCHAR szKey[131] = {};
acedInitGet(RSG_OTHER, _T("D P"));
nRes = acedGetKword(_T("\n请选择[输入新桩号距离(D)/点选新桩号位置(P)]<点选新桩号位置(P)>:"), szKey);
if (nRes == RTNONE)
_tcscpy(szKey, _T("P"));
else if (nRes == RTCAN)
return;
if (_tcscmp(szKey,_T("D")) == 0)
{
nRes = acedGetReal(_T("\n请输入距此桩号的距离:"), &dist);
if (nRes != RTNORM) return;
dOrigIntersctDistStart += (bStart2End ? 1 : -1) * dist;
getPointAtDist(idPoly, dOrigIntersctDistStart, ptIns);
dNewDist = dOrigStakeDistStart + dist;
}
else
{
acdbWcs2Ucs(asDblArray(ptStartStake), pt, false);
nRes = acedGetPoint(pt, _T("\n选择新桩号位置。"), pt);
if (nRes != RTNORM) return;
acdbUcs2Wcs(pt, pt, false);
ptSel = asPnt3d(pt);
if (getClosestPointTo(idPoly, ptSel, ptSel) != Acad::eOk)
{
acutPrintf(_T("\n选择点不在polyline范围内。"));
return;
}
ptIns = ptSel;
getDistAtPoint(idPoly, ptSel, dSel);
dNewDist = dOrigStakeDistStart +(bStart2End ? 1 : -1) * (dSel - dOrigIntersctDistStart);
}
getFirstDeriv(idPoly, ptIns, vtCut);
if (!bThousands)
strNew.Format(_T("%s+%.2f"), strPrefix, dNewDist);
else
strNew = StakeTools::generateStakeString(dNewDist, strPrefix);
AcDbText *pText(NULL);
AcGeVector3d vtOld(AcGeVector3d::kXAxis), vtNew(AcGeVector3d::kXAxis);
OPENOBJ_BEGIN(idStartTxt, AcDb::kForRead, AcDbText, pTxt)
pText = (AcDbText*)pTxt->clone();
vtOld.rotateBy(pTxt->rotation(), AcGeVector3d::kZAxis);
OPENOBJ_END()
// 读批量插桩对话框缓存
CGenerateStakeDlg dlg;
CString s = dlg.m_strPrefix;
double dL = dlg.m_dStakeL * .5;
double dW = dlg.m_dStakeW;
double txtH = dlg.m_dTxtH;
int nPosition = dlg.m_nPositonOfStake; // 桩号位置(左右中,012)
int nReadDir = dlg.m_nReaderDir; // 文字阅读方向
CString style = dlg.m_strStyle;
double txtWF = dlg.m_dTxtWF;
// 得到文字方向
if (vtCut.dotProduct(vtOld) < 0)
vtCut.rotateBy(PI, AcGeVector3d::kZAxis);
vtCut.rotateBy(PI * .5, AcGeVector3d::kZAxis);
if (vtCut.dotProduct(vtOld) < 0)
vtCut.rotateBy(PI, AcGeVector3d::kZAxis);
pText->setTextString(strNew);
pText->setHeight(txtH);
AcDbObjectId styleId = GLTools::getTextStyle(style);
if (styleId.isValid())
pText->setTextStyle(styleId);
pText->setWidthFactor(txtWF);
// 插入桩线
vtCut.normalize();
AcGePoint3d ptFirst(ptIns), ptSecond(ptIns);
ptFirst += vtCut * dL;
ptSecond -= vtCut * dL;
AcDbPolyline *pL = new AcDbPolyline;
pL->addVertexAt(0, ptFirst.convert2d(AcGePlane::kXYPlane), 0, dW, dW);
pL->addVertexAt(1, ptSecond.convert2d(AcGePlane::kXYPlane), 0, dW, dW);
AcGeVector3d vtD(AcGeVector3d::kIdentity);
getFirstDeriv(idPoly, ptIns, vtD);
vtD.normalize();
AcGeVector3d vtVertical(vtD);
vtVertical.rotateBy(PI * .5, AcGeVector3d::kZAxis);
vtVertical.normalize();
double angle = AcGeVector3d::kXAxis.angleTo(vtVertical, AcGeVector3d::kZAxis) + PI;
if (nReadDir == 1) // 下至上
angle -= PI;
pText->setRotation(angle);
ptFirst = ptSecond = ptIns;
ptFirst += vtVertical * dL;
ptSecond -= vtVertical * dL;
AcGePoint3d ptTxt;
switch (nPosition)
{
case 0: // 左
pText->setHorizontalMode((nReadDir == 0) ? AcDb::kTextRight : AcDb::kTextLeft);
ptTxt = ptFirst + vtVertical * (dL + .2);
break;
case 1: // 右
pText->setHorizontalMode((nReadDir == 0) ? AcDb::kTextLeft : AcDb::kTextRight);
ptTxt = ptSecond - vtVertical * (dL + .2);
break;
case 2: // 中
pText->setHorizontalMode(AcDb::kTextCenter);
ptTxt = ptIns;
// 再沿切线方向移半个字高
ptTxt += vtD * txtH;
break;
default:
break;
}
pText->setAlignmentPoint(ptTxt);
double pointDist(.0);
getDistAtPoint(idPoly, ptIns, pointDist);
StakeTools::writeSHSStakeFlag(pText, ptIns, bStart2End, strNew, dNewDist, pointDist);
StakeTools::writeSHSStakeFlag(pL, ptIns, bStart2End, strNew, dNewDist, pointDist);
g_LayerMgr::instance().setLayer(pText, GLTools::gLayer_Stake);
g_LayerMgr::instance().setLayer(pL, GLTools::gLayer_Stake);
AddToModelSpace(pText);
AddToModelSpace(pL);
}
// 批量生成桩号
void generateStake()
{
Acad::ErrorStatus es;
// 选择中心线
AcDbObjectId idCenter = getCenterRoldLine(_T("\n请选择道路中心线。"), _T("LWPOLYLINE,LINE,ARC,AEC_ROADAXISLINE"));
if (!idCenter.isValid())
{
acutPrintf(_T("\n未找到道路中心线,请选择一个(多段线,直线或弧线或道路线实体)。"));
return;
}
ads_point adsPt;
// 选择中心线上一点做为桩号起点
int nRes = acedGetPoint(NULL, _T("选择中心线上一点做为桩号起点"), adsPt);
if (nRes != RTNORM) return;
acdbUcs2Wcs(adsPt, adsPt, false);
AcGePoint3d ptFirst(AcGePoint3d::kOrigin), ptSecond(AcGePoint3d::kOrigin), ptIns(AcGePoint3d::kOrigin);
double dSelDistFirst(.0), dSelDistSecond(.0), dCenterLen(.0);
OPENOBJ_BEGIN(idCenter, AcDb::kForWrite, AcDbCurve, pCenter)
{
if (!pCenter)
{
acutPrintf(_T("\n所选中心线有误。"));
return;
}
es = pCenter->getClosestPointTo(asPnt3d(adsPt), AcGeVector3d::kZAxis, ptFirst);
if (es != Acad::eOk)
{
acutPrintf(_T("\n所选点并不在中心线附近。"));
return;
}
AcGePoint3d ptEnd(AcGePoint3d::kOrigin);
pCenter->getEndPoint(ptEnd);
pCenter->getDistAtPoint(ptEnd, dCenterLen);
pCenter->getDistAtPoint(ptFirst, dSelDistFirst);
// 选择第二点,用来确定布置方向
acdbWcs2Ucs(asDblArray(ptFirst), adsPt, false);
int nRes = acedGetPoint(adsPt, _T("选择中心线上另外一点,用以确定布置方向。"), adsPt);
if (nRes != RTNORM) return;
acdbUcs2Wcs(adsPt, adsPt, false);
es = pCenter->getClosestPointTo(asPnt3d(adsPt), AcGeVector3d::kZAxis, ptSecond);
if (es != Acad::eOk)
{
acutPrintf(_T("\n所选点并不在中心线附近。"));
return;
}
pCenter->getDistAtPoint(ptSecond, dSelDistSecond);
if (dSelDistFirst > dSelDistSecond)
{
acutPrintf(_T("\n布置桩号方向与中心线方向相反,将反转中心线!"));
AcDbPolyline* pPl = AcDbPolyline::cast(pCenter);
if (pPl != NULL)
{
reverseCurve(pPl);
}
}
pCenter->getDistAtPoint(ptFirst, dSelDistFirst);
}
OPENOBJ_END()
//bool bStartDir = dSelDistSecond > dSelDistFirst; // ture 从中心线的起点开始布置,false 从中心线的终点开始布置
bool bStartDir = true; // ture 从中心线的起点开始布置,false 从中心线的终点开始布置
// 弹出对话框
CAcModuleResourceOverride myResources;
CGenerateStakeDlg dlg;
if (bStartDir)
dlg.m_dDistStart = dSelDistFirst;
else
dlg.m_dDistStart = dCenterLen - dSelDistFirst;
dlg.m_dDistEnd = dCenterLen;
if (dlg.DoModal() != IDOK) return;
CString strPrefix = dlg.m_strPrefix; // 桩号前缀
strPrefix += _T("K");
double distStart = dlg.m_dDistStart; // 起始桩号距离
double distEnd = dlg.m_dDistEnd; // 结束桩号距离
double dSpace = dlg.m_dSpace; // 桩号间距
double txtH = dlg.m_dTxtH; // 桩号字高
double txtWF = dlg.m_dTxtWF; // 文字宽度因子
AcDbObjectId idStyle = dlg.m_idStyle; // 文字样式
double dStakeL = dlg.m_dStakeL * .5; // 桩线长
double dStakeW = dlg.m_dStakeW; // 桩线宽
int nPosition = dlg.m_nPositonOfStake; // 桩号位置(左右中,012)
int nReadDir = dlg.m_nReaderDir; // 文字阅读方向
// 取整
// distStart = roundUpNum(distStart, 10);
// distEnd = roundUpNum(distEnd, 10);
CString strStake(_T(""));
OPENOBJ_BEGIN(idCenter, AcDb::kForRead, AcDbCurve, pCenter)
{
if (!pCenter) return;
double dist(.0), angle(.0);
AcGeVector3d vtVertical(AcGeVector3d::kIdentity), vtTangent(AcGeVector3d::kIdentity);
pCenter->getDistAtPoint(ptFirst, dist);
bool bBreak(false);
while (distStart <= distEnd)
{
if (bBreak) break;
es = pCenter->getPointAtDist(dist, ptIns);
if (es != Acad::eOk)
{
double d;
pCenter->getEndPoint(ptIns);
pCenter->getDistAtPoint(ptIns, d);
distStart -= dSpace;
dist -= dSpace;
distStart += d - dist;
dist += d - dist;
bBreak = true;
}
ptSecond = ptFirst = ptIns;
AcDbText *pText = new AcDbText();
strStake = StakeTools::generateStakeString(distStart, strPrefix);
pText->setTextString(strStake);
pText->setHeight(txtH);
pText->setTextStyle(idStyle);
pText->setVerticalMode(AcDb::kTextVertMid);
pText->setWidthFactor(txtWF);
pCenter->getFirstDeriv(ptFirst, vtTangent);
vtVertical = vtTangent;
vtVertical.rotateBy(PI * .5, AcGeVector3d::kZAxis);
angle = AcGeVector3d::kXAxis.angleTo(vtVertical, AcGeVector3d::kZAxis) + PI;
if (nReadDir == 1) // 下至上
angle -= PI;
pText->setRotation(angle);
// 生成小桩
vtVertical.normalize();
vtTangent.normalize();
ptFirst += vtVertical * dStakeL;
ptSecond -= vtVertical * dStakeL;
AcDbPolyline *pLine = new AcDbPolyline;
pLine->addVertexAt(0, ptFirst.convert2d(AcGePlane::kXYPlane), 0., dStakeW, dStakeW);
pLine->addVertexAt(1, ptSecond.convert2d(AcGePlane::kXYPlane), 0., dStakeW, dStakeW);
AcGePoint3d ptTxt;
switch (nPosition)
{
case 0: // 左
pText->setHorizontalMode((nReadDir == 0) ? AcDb::kTextRight : AcDb::kTextLeft);
ptTxt = ptFirst + vtVertical * (dStakeL + .2);
break;
case 1: // 右
pText->setHorizontalMode((nReadDir == 0) ? AcDb::kTextLeft : AcDb::kTextRight);
ptTxt = ptSecond - vtVertical * (dStakeL + .2);
break;
case 2: // 中
pText->setHorizontalMode(AcDb::kTextCenter);
ptTxt = ptIns;
// 再沿切线方向移半个字高
ptTxt += vtTangent * txtH;
break;
default:
break;
}
pText->setAlignmentPoint(ptTxt);
// 写扩展数据
StakeTools::writeSHSStakeFlag(pText, ptIns, bStartDir, strStake, distStart, dist);
StakeTools::writeSHSStakeFlag(pLine, ptIns, bStartDir, strStake, distStart, dist);
g_LayerMgr::instance().setLayer(pText, GLTools::gLayer_Stake);
g_LayerMgr::instance().setLayer(pLine, GLTools::gLayer_Stake);
AddToModelSpace(pText);
AddToModelSpace(pLine);
dist += (bStartDir ? 1 : -1) * dSpace;
if (EQUAL_ZERO(dist)) dist = .0;
distStart += dSpace;
}
}
OPENOBJ_END()
}
// 桩号高程映射
void mapStack2Polyline()
{
// 读取一个高程文件
CString szFilter = _T("高程数据文件 (*.*)|*.*;*.*||");
CFileDialog fileDlg(TRUE, _T("stl"), NULL, OFN_HIDEREADONLY, szFilter, acedGetAcadFrame());
int nRes = fileDlg.DoModal();
if (nRes != IDOK) return;
CString strFile = fileDlg.GetPathName();
std::map<double, double, GLTools::compare_double> mapStake;
analyElevationFile(strFile, mapStake);
if (mapStake.empty())
{
acutPrintf(_T("\n文件内容为空,请检查。"));
return;
}
ads_name adsName;
ads_point adsPt;
nRes = acedEntSel(_T("\n请选择要映射的polyline线。"), adsName, adsPt);
if (nRes != RTNORM) return;
AcDbObjectId idPoly(AcDbObjectId::kNull);
acdbGetObjectId(idPoly, adsName);
if (!GLTools::isThisClass<AcDbPolyline>(idPoly))
{
acutPrintf(_T("\n所选择的实体不是polyline。"));
return;
}
// 遍历模型空间中所有的文字对象,
ads_name ss, ent;
struct resbuf* pRb = acutBuildList(RTDXF0, _T("TEXT"), 0);
nRes = acedSSGet(_T("A"), NULL, NULL, pRb, ss);
if (nRes != RTNORM)
{
acutPrintf(_T("\n没有发现文字对象。"));
return;
}
CString sTxt(_T(""));
AcGePoint3d ptTxt(AcGePoint3d::kOrigin);
AcDbObjectId id;
Adesk::Int32 lLen = 0L;
acedSSLength(ss, &lLen);
AcString str;
std::map<double, std::pair<AcGePoint3d, AcDbLine>, GLTools::compare_double> mapPt;
std::vector<STakeInfo> stakes(0);
STakeInfo info;
std::set<CString> setStr;
std::pair<std::set<CString>::iterator, bool> pr;
for (long i = 0; i < lLen; i++)
{
if (acedSSName(ss, i, ent) != RTNORM) continue;
if (acdbGetObjectId(id, ent) != Acad::eOk) continue;
if (!GLTools::isThisClass<AcDbText>(id)) continue;
if (!StakeTools::isSHSStake(id)) continue;
if (!info.init(id, mapStake)) continue;
pr = setStr.insert(info.stake);
if (pr.second)
stakes.push_back(info);
}
acedSSFree(ss);
std::sort(stakes.begin(), stakes.end(), STakeInfo::compare_dist());
std::vector<std::pair<AcGePoint3d, CString>> insPts(0);
AcGePoint3dArray pts;
AcGePoint3d pt(AcGePoint3d::kOrigin);
AcDbXline line;
OPENOBJ_BEGIN(idPoly, AcDb::kForRead, AcDbPolyline, pPoly)
for (size_t i = 0; i < stakes.size(); ++i)
{
STakeInfo &st = stakes[i];
pts.removeAll();
getXLineByDbText(st.id, &line);
pPoly->intersectWith(&line, AcDb::kOnBothOperands, AcGePlane::kXYPlane, pts);
if (pts.isEmpty())
{
acutPrintf(_T("/n桩号:%s 并没有与选中的polyline相交。"), st.stake);
continue;
}
pt = pts[0];
pt.z = st.elev;
insPts.push_back(std::make_pair(pt, st.stake));
}
OPENOBJ_END()
insert3dPoly(insPts);
}
// 通过点选绘制管廊红线
void drawRedLineByCustom()
{
// 先选择由 “纵断复线” 生成的高程文件
acutPrintf(_T("\n请选择由 “纵断复线” 生成的高程文件。"));
CString szFilter = _T("高程数据文件 (*.txt)|*.txt|所有文件(*.*)|*.*||");
CFileDialog fileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, szFilter, acedGetAcadFrame());
int nRes = fileDlg.DoModal();
if (nRes != IDOK) return;
// 收集所有上华桩号
std::vector<AcDbObjectId> ids(0);
StakeTools::getSHSStakeOfAll(ids, false);
if (ids.empty())
{
acutPrintf(_T("\n未找到上华桩号。"));
return;
}
CString prefix = getDbTextString(ids[0]);
double _d;
StakeTools::analyStakeString(prefix, _d, &prefix);
CString strFile = fileDlg.GetPathName();
D2DMap mapStake;
analyElevationFile(strFile, mapStake);
if (mapStake.empty())
{
acutPrintf(_T("\n文件内容为空,请检查。"));
return;
}
AcDbObjectId centerID, polyID;
ads_name adsEnt;
ads_point adsPt;
nRes = acedEntSel(_T("\n请选择道路中心线。"), adsEnt, adsPt);
if (nRes != RTNORM) return;
acdbGetObjectId(centerID, adsEnt);
if (!GLTools::isThisClass<AcDbCurve>(centerID))
{
acutPrintf(_T("\n所选对象不是曲线对象。"));
return;
}
nRes = acedEntSel(_T("\n请选择一条polyline做为管廊的走向。"), adsEnt, adsPt);
if (nRes != RTNORM) return;
acdbGetObjectId(polyID, adsEnt);
if (!GLTools::isThisClass<AcDbPolyline>(polyID))
{
acutPrintf(_T("\n所选对象不是polyline对象。"));
return;
}
// 判断两根线方向,如果polyline不与centerline方向一至,则将polyline反转
makeSameDir(polyID, centerID);
AcGePoint3d ptOrign(AcGePoint3d::kOrigin), ptOver(AcGePoint3d::kOrigin)
, ptStart(AcGePoint3d::kOrigin), ptEnd(AcGePoint3d::kOrigin);
double stakeDistStart(.0), stakeDistEnd(.0);
double elevStart(.0), elevEnd(.0);
nRes = acedGetPoint(adsPt, _T("\n选择管廊走向polyline上的一个点,做为管廊起点。"), adsPt);
if (nRes != RTNORM) return;
acdbUcs2Wcs(adsPt, adsPt, false);
ptStart = asPnt3d(adsPt);
ptStart.z = .0;
ptOrign = ptStart;
getClosestPointTo(polyID, ptOrign, ptOrign);
getClosestPointTo(centerID, ptStart, ptStart);
if (!StakeTools::getDistByPointForCenterLine(ids, centerID, ptStart, stakeDistStart))
{
acutPrintf(_T("\n提取起点桩号失败。"));
return;
}
if (!getElevationByStakeDist(stakeDistStart, mapStake, elevStart))
{
acutPrintf(_T("\n提取起点高程失败。"));
return;
}
acdbWcs2Ucs(adsPt, adsPt, false);
nRes = acedGetPoint(adsPt, _T("\n选择管廊走向polyline上的一个点,做为管廊终点。"), adsPt);
if (nRes != RTNORM) return;
acdbUcs2Wcs(adsPt, adsPt, false);
ptEnd = asPnt3d(adsPt);
ptEnd.z = .0;
ptOver = ptEnd;
getClosestPointTo(polyID, ptOver, ptOver);
getClosestPointTo(centerID, ptEnd, ptEnd);
if (!StakeTools::getDistByPointForCenterLine(ids, centerID, ptEnd, stakeDistEnd))
{
acutPrintf(_T("\n提取终点桩号失败。"));
return;
}
if (!getElevationByStakeDist(stakeDistEnd, mapStake, elevEnd))
{
acutPrintf(_T("\n提取终点高程失败。"));
return;
}
acutPrintf(_T("\n起点桩号 距离:(%.3f) 高程:(%.3f)"), stakeDistStart, elevStart);
acutPrintf(_T("\n终点桩号 距离:(%.3f) 高程:(%.3f)"), stakeDistEnd, elevEnd);
acutPrintf(_T("\n******************************"));
double dSpace(20.);
nRes = acedGetReal(_T("\n输入间距<20>:"), &dSpace);
///
AcDbPolyline *pClonePoly(NULL);
OPENOBJ_BEGIN(polyID, AcDb::kForRead, AcDbPolyline, pL)
{
if (!pL) return;
pClonePoly = (AcDbPolyline*)pL->clone();
}
OPENOBJ_END()
if (!pClonePoly) return;
// 将选中的两点插到polyline上
insertVertexForPolyline(pClonePoly, ptOrign);
insertVertexForPolyline(pClonePoly, ptOver);
// cut
AcDbPolyline* pp = cutPolyline(pClonePoly, ptOrign, ptOver);
if (!pp) return;
DELETE_PTR(pClonePoly);
pClonePoly = pp;
pp = NULL;
// 合并polyline
pp = MergePolyline(pClonePoly);
if (!pp) return;
DELETE_PTR(pClonePoly);
pClonePoly = pp;
pp = NULL;
double dCurveLen(.0), stakeDist(.0), elev(.0)
, dLen(.0), dAng(.0), dBulge(.0), dOldLen(.0)
, d1(.0), d2(.0);
AcGePoint3d ptCurveEnd(AcGePoint3d::kOrigin)
, ptCurveStart(AcGePoint3d::kOrigin)
, ptOnCurve(AcGePoint3d::kOrigin)
, ptOnCenter(AcGePoint3d::kOrigin)
, pt(AcGePoint3d::kOrigin)
, pt1(AcGePoint3d::kOrigin)
, pt2(AcGePoint3d::kOrigin);
std::vector<std::pair<AcGePoint3d, CString>> insPts(0);
std::set<CString> setStakes;
CString strStake(_T(""));
pClonePoly->getStartPoint(ptCurveStart);
if (ptCurveStart.distanceTo(ptOrign) > 1e-7)
reverseCurve(pClonePoly);
AcGeCircArc3d arc;
AcGeLineSeg3d seg;
for (int i = 0; i < pClonePoly->numVerts() - 1; ++i)
{
pClonePoly->getBulgeAt(i, dBulge);
if (abs(dBulge) > 1e-7) // 弧
{
pClonePoly->getArcSegAt(i, arc);
dCurveLen = arc.length(arc.paramOf(arc.startPoint()), arc.paramOf(arc.endPoint()));
}
else
{
pClonePoly->getLineSegAt(i, seg);
dCurveLen = seg.length();
}
int j(0);
dLen = .0;
while (true)
{
pClonePoly->getPointAtDist(dLen + dOldLen, ptOnCurve);
ptOnCurve.z = .0;
getClosestPointTo(centerID, ptOnCurve, ptOnCenter);
if (!StakeTools::getDistByPointForCenterLine(ids, centerID, ptOnCenter, stakeDist))
{
acutPrintf(_T("\n提取桩号失败。"));
break;
}
if (!getElevationByStakeDist(stakeDist, mapStake, elev))
{
acutPrintf(_T("\n提取终点高程失败。"));
break;
}
ptOnCurve.z = elev;
strStake = StakeTools::generateStakeString(stakeDist, prefix);
//if (setStakes.insert(strStake).second)
if (insPts.empty())
insPts.push_back(std::make_pair(ptOnCurve, strStake));
else
{
if (insPts.rbegin()->first.distanceTo(ptOnCurve) > 1e-2)
insPts.push_back(std::make_pair(ptOnCurve, strStake));
}
if (EQUAL(dLen, dCurveLen)) break;
//if (insPts.size() > 1 && dLen < 1e-4)
//{
// // 判断最后两个点在curve间的距离
// pt1 = insPts[insPts.size() - 1].first;
// pt2 = insPts[insPts.size() - 2].first;
// pClonePoly->getDistAtPoint(pt1, d1);
// pClonePoly->getDistAtPoint(pt2, d2);
// if (EQUAL(abs(d2 - d1), dSpace))
// dLen += dSpace;
// else
// dLen += dSpace - abs(d2 - d1);
//}
//else
dLen += dSpace;
if (UP_ZERO(dLen - dCurveLen))
{
// 这里考虑了整段曲线长度小于dSpace的情况
if (j > 0)
insPts.pop_back();
dLen = dCurveLen;
}
j++;
}
dOldLen += dCurveLen;
}
DELETE_PTR(pClonePoly);
insert3dPoly(insPts);
}
void modifyGradient()
{
AcDbObjectIdArray idEws, idEwAll, idEwNexts, idEwPrevs;
GLTools::getConnectWorms(idEws, &idEwNexts, &idEwPrevs);
if (idEws.isEmpty()) return;
GetConnectedWorms(idEws[0], idEwAll);
double dG(.0);
if (acedGetReal(_T("\n请输入坡度百分比:"), &dG) != RTNORM) return;
double dPrevElev(.0), dNextElev(.0);
// 设置第一段管廊与前一段管廊的连接,再修改坡度
OPENOBJ_BEGIN(idEws.first(), AcDb::kForWrite, AecDbEarthWorm, pEw)
{
if (pEw && pEw->GetSegmentCount() > 0)
{
if (!idEwPrevs.isEmpty())
{
OPENOBJ_BEGIN(idEwPrevs.last(), AcDb::kForWrite, AecDbEarthWorm, pPrev)
{
if (pPrev)
{
pEw->SetLastDir(pPrev->GetTailDir());
pPrev->SetNextDir(pEw->GetHeadDir());
}
}
OPENOBJ_END()
}
pEw->SetGradientAt(0, dG);
pEw->UpdateRoomDraw();
dPrevElev = pEw->GetTailElevation();
}
}
OPENOBJ_END()
// 然后从第二段开始,修改坡度,并与其前一段相连
for (size_t i = 1; i < idEws.length(); ++i)
{
OPENOBJ_BEGIN(idEws[i - 1], AcDb::kForWrite, AecDbEarthWorm, pPrev)
{
OPENOBJ_BEGIN(idEws[i], AcDb::kForWrite, AecDbEarthWorm, pEw)
{
if (pPrev && pEw && pEw->GetSegmentCount() > 0)
{
pEw->SetGradientAt(0, dG);
pEw->SetStartElevation(dPrevElev, false);
pEw->UpdateRoomDraw();
dPrevElev = pEw->GetTailElevation();
pEw->SetLastDir(pPrev->GetTailDir());
pPrev->SetNextDir(pEw->GetHeadDir());
}
}
OPENOBJ_END()
}
OPENOBJ_END()
}
// 设置下一段管廊的坡度
if (!idEwNexts.isEmpty())
{
OPENOBJ_BEGIN(idEwNexts.first(), AcDb::kForWrite, AecDbEarthWorm, pEw)
if (pEw)
{
dG = (pEw->EndElevation() - dPrevElev) / pEw->StartPoint().distanceTo(pEw->EndPoint()) * 100;
pEw->SetStartElevation(dPrevElev, false);
pEw->SetGradientAt(0, dG);
pEw->UpdateRoomDraw();
OPENOBJ_BEGIN(idEws.last(), AcDb::kForWrite, AecDbEarthWorm, pPrev)
{
if (pPrev)
{
pEw->SetLastDir(pPrev->GetTailDir());
pPrev->SetNextDir(pEw->GetHeadDir());
// 再与下一段连接
if (idEwNexts.length() > 2)
{
OPENOBJ_BEGIN(idEwNexts[1], AcDb::kForWrite, AecDbEarthWorm, pNext)
{
if (pNext)
{
pNext->SetLastDir(pEw->GetTailDir());
pEw->SetNextDir(pNext->GetHeadDir());
}
}
OPENOBJ_END()
}
}
}
OPENOBJ_END()
}
OPENOBJ_END()
}
AcDbObjectIdArray arVIds;
CollectEarthwormForVSection(idEwAll, arVIds);
ContinueVerSection(arVIds, 1);
return;
}
void stretchEwByAngle()
{
ads_name ent;
ads_point pt;
AcDbObjectId idEw(AcDbObjectId::kNull), idPoly(AcDbObjectId::kNull);
int nRes = acedEntSel(_T("\n请选择上一段管廊:"), ent, pt);
if (nRes != RTNORM) return;
acdbGetObjectId(idEw, ent);
if (!GLTools::isThisClass<AecDbEarthWorm>(idEw))
{
acutPrintf(_T("\n选择的实体不是管廊!"));
return;
}
nRes = acedEntSel(_T("\n请选择道路中心线:"), ent, pt);
acdbGetObjectId(idPoly, ent);
if (!GLTools::isThisClass<AcDbPolyline>(idPoly))
{
acutPrintf(_T("\n选择的实体不是polyline!"));
return;
}
GripMessage msg;
msg.idHost = idEw;
msg.nType = kSegStretchDir;
// 用户输入角度,得到管廊结束桩号
double dAngle(45);
CString endStake(_T(""));
AcGePoint2d pt2dE(AcGePoint2d::kOrigin), pt2dS(AcGePoint2d::kOrigin);
OPENOBJ_BEGIN(idEw, AcDb::kForRead, AecDbEarthWorm, pEw)
if (!pEw) return;
pt2dE = pEw->EndPoint();
pt2dS = pEw->StartPoint();
acedGetReal(_T("\n请输入相对角度<45>:"), &dAngle);
dAngle = dAngle * PI / 180;
int segIdx = pEw->GetSegmentCount() - 1;
EWSegment seg;
pEw->GetSegment(segIdx, seg);
int subSegIdx = seg.nDeformationJoints - 1;
AcArray<EWFnctNode> arFncNodes;
pEw->GetFncNodeAt(segIdx, subSegIdx, arFncNodes);
if (arFncNodes.isEmpty())
pEw->GetStakeAt(segIdx, subSegIdx, endStake);
else
pEw->GetStakeAt(segIdx, subSegIdx, arFncNodes.length() - 1, endStake);
msg.nSegindex = pEw->GetSegmentCount();
msg.ptGrip.set(pt2dE.x, pt2dE.y, pEw->EndElevation());
OPENOBJ_END()
if (endStake.IsEmpty())
{
acutPrintf(_T("\n管廊末端桩号为空。"));
return;
}
// 收集所有上华桩号
std::vector<AcDbObjectId> idTxts(0);
StakeTools::getSHSStakeOfAll(idTxts, true);
AcDbRay ray;
getRay(idEw, ray, dAngle);
double dRot(.0);
AcDbObjectId idLeft(AcDbObjectId::kNull);
AcDbObjectId idStake = searchSHStakeByString(idTxts, endStake, idLeft);
AcDbXline xline;
getXline(idStake, idLeft, xline, idPoly, endStake);
#ifdef _DEBUG
AddToModelSpace((AcDbEntity*)ray.clone());
AddToModelSpace((AcDbEntity*)xline.clone());
#endif // _DEBUG
AcGePoint3dArray pts;
xline.intersectWith(&ray, AcDb::kOnBothOperands, AcGePlane::kXYPlane, pts);
if (pts.isEmpty())
{
acutPrintf(_T("\n角度方向与桩号延长线不相交。"));
return;
}
AcGeVector3d vt3d(pts[0] - AcGePoint3d(pt2dE.x, pt2dE.y, .0));
msg.vtOffset = vt3d;
msg.nSubSegIndex = 0;
_tcscpy(msg.szLockId, _T("End"));
PushGripMessage(msg);
#ifdef _DEBUG
AcDbCircle *pC = new AcDbCircle(pts[0], AcGeVector3d::kZAxis, 1);
AddToModelSpace(pC);
pC = new AcDbCircle(AcGePoint3d(pt2dS.x, pt2dS.y, 0), AcGeVector3d::kZAxis, 1);
AddToModelSpace(pC);
pC = new AcDbCircle(AcGePoint3d(pt2dE.x, pt2dE.y, 0), AcGeVector3d::kZAxis, 2);
AddToModelSpace(pC);
#endif // _DEBUG
}
void createSection(AcGePoint3d *pArr, int len, double R, double h)
{
AcGeVector3d vt(AcGeVector3d::kXAxis * R);
for (int i = 0; i < len; ++i)
{
vt = AcGeVector3d::kXAxis * R;
vt.rotateBy(i * (2*PI/len), AcGeVector3d::kZAxis);
pArr[i] = AcGePoint3d::kOrigin + vt;
pArr[i].z = h;
}
}
void ew_test()
{
}
}