admin 发表于 2024-5-2 22:42:33

OBJECT ARX 绘制道路横切面 实例

//-----------------------------------------------------------------------------
//----- acrxEntryPoint.cpp
//-----------------------------------------------------------------------------
#include "StdAfx.h"
#include "resource.h"
//-----------------------------------------------------------------------------
#define szRDS 采用RXST("HY")


const double BORDEROFFSET = 5 ;边线距离端点2mm
const double BANDER1PTCOUNT = 4;//1块板交点数量
const double BANDER2PTCOUNT = 6;//2块板交点数量
const double BANDER3PTCOUNT = 8;//3块板交点数量
const double BANDER4PTCOUNT = 10;//4块板交点数量
const double PI = 3.1415926536;


//-----------------------------------------------------------------------------
//----- ObjectARX EntryPoint
class CArxProject3App : public AcRxArxApp
{


public:


CArxProject3App () : AcRxArxApp () {}


virtual AcRx::AppRetCode On采用kInitAppMsg (void *pkt)
{
// TODO: Load dependencies here.


// You *must* call On采用kInitAppMsg here
AcRx::AppRetCode retCode =AcRxArxApp::On采用kInitAppMsg (pkt) ;


// TODO: Add your initialization code here


return (retCode) ;
}


virtual AcRx::AppRetCode On采用kUnloadAppMsg (void *pkt)
{
// TODO: Add your code here


// You *must* call On采用kUnloadAppMsg here
AcRx::AppRetCode retCode =AcRxArxApp::On采用kUnloadAppMsg (pkt) ;


// TODO: Unload dependencies here


return (retCode) ;
}


virtual void RegisterServerComponents ()
{
}


//加载一个实体到数据库,返回实体ID,是否关闭实体
static AcDbObjectId LoadEntity(AcDbEntity* entity,bool autoClose)
{


AcDbBlockTable* pBlockTable;
acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable,AcDb::kForRead);


AcDbBlockTableRecord* pBlockTableRecord;
pBlockTable->getAt(ACDB采用MODEL采用SPACE,pBlockTableRecord,AcDb::kForWrite);


AcDbObjectId Id;
pBlockTableRecord->appendAcDbEntity(Id,entity);


pBlockTable->close();


pBlockTableRecord->close();


if(autoClose)
{
entity->close();
}
return Id;
}


插入文字
参数依次为:X,Y,Z坐标
要插入的文字
文字大小
static void InsertText(double x,double y,double z,CString strTxt,double weight)
{
默认不做旋转不加粗
InsertText(x,y,z,strTxt,weight,0,0,AcDb::TextHorzMode::kTextMid,AcDb::TextVertMode::kTextBottom);
}


插入文字
参数依次为:X,Y,Z坐标
要插入的文字
文字高度
文字旋转角度
文字加粗大小
横向显示的模式
纵向显示模式
static void InsertText(double x,double y,double z,CString strTxt,double height,double rotation,
double size,AcDb::TextHorzMode hm,AcDb::TextVertMode vm)
{
AcGePoint3d ptInsert(x,y,z);
AcDbText* pText = new AcDbText(ptInsert,strTxt,AcDbObjectId::kNull,height,rotation);


注意这里的先后顺序,要先设置停靠的模式后设置停靠坐标,否则赋值不上去
pText->setHorizontalMode(hm);
pText->setVerticalMode(vm);
pText->setAlignmentPoint(ptInsert);
设置加粗比例
pText->setWidthFactor(size);


LoadEntity(pText,true);
}


//显示道路的详细信息
参数依次:道路宽度数组,道路名称,显示比例
static void ShowRoadDetail(AcGeDoubleArray& roadArr,const CString& strName,double ratio)
{
选择显示的位置
ads采用point ptInput;
if(acedGetPoint(NULL,采用T("\n选择显示断面符号的位置"),ptInput) != RTNORM)
{
return;
}


AcGePoint2d ptDetail;
ptDetail = asPnt2d(ptInput);


AcDbPolyline* pl = new AcDbPolyline();绘制表格上部分
AcDbPolyline* pl2 = new AcDbPolyline();表格中间部分
AcDbPolyline* plMid = new AcDbPolyline();表格中间线
AcDbPolyline* pl3 = new AcDbPolyline();表格底部直线


double totalRoad = 0.0;
int len = roadArr.length();
for (int i = 0;i < len; i++)
{
roadArr.setAt(i,roadArr.at(i) * ratio);
}


pl->addVertexAt(0,ptDetail);
左边斜线
ptDetail.set(ptDetail + BORDEROFFSET,ptDetail - BORDEROFFSET);
pl->addVertexAt(1,ptDetail);


左边竖线
ptDetail.set(ptDetail ,ptDetail - 2 * BORDEROFFSET);
pl->addVertexAt(2,ptDetail);
int index = 2;
bool isUp = true;先高后低
for(int i = 0;i < len;i ++)
{
double road = roadArr.at(i);
totalRoad += road;
index ++;
ptDetail.set(ptDetail + road,ptDetail);
pl->addVertexAt(index,ptDetail);


if(i != len - 1)
{
index ++;
if(isUp)凹进去
{
ptDetail.set(ptDetail,ptDetail - BORDEROFFSET / 4);
pl->addVertexAt(index,ptDetail);
isUp = false;
}
else凸起来
{
ptDetail.set(ptDetail,ptDetail + BORDEROFFSET / 4);
pl->addVertexAt(index,ptDetail);
isUp = true;
}
}
}


index++;
右边竖线
ptDetail.set(ptDetail,ptDetail + 2* BORDEROFFSET);
pl->addVertexAt(index,ptDetail);
index ++;
右边斜线
ptDetail.set(ptDetail + BORDEROFFSET,ptDetail + BORDEROFFSET);
pl->addVertexAt(index,ptDetail);


//绘制表格中部---------------
ptDetail.set(ptDetail - BORDEROFFSET,ptDetail - 3.5 * BORDEROFFSET);
pl2->addVertexAt(0,ptDetail);


index = 1;
for(int i = 0;i < len; i++)
{
double road = roadArr.at(len - i - 1);
右边线
ptDetail.set(ptDetail,ptDetail - 3 * BORDEROFFSET);
pl2->addVertexAt(index,ptDetail);
index ++;
车道
ptDetail.set(ptDetail-road,ptDetail);
pl2->addVertexAt(index,ptDetail);
index++;
左边线
ptDetail.set(ptDetail,ptDetail + 3 * BORDEROFFSET);
pl2->addVertexAt(index,ptDetail);
index ++;
}


//绘制中间线---------两边各多出1BORDEROFFSET----------
ptDetail.set(ptDetail- BORDEROFFSET,ptDetail - 3 * BORDEROFFSET);
plMid->addVertexAt(0,ptDetail);


ptDetail.set(ptDetail+ 2 * BORDEROFFSET + totalRoad,ptDetail);
plMid->addVertexAt(1,ptDetail);


//绘制文字-------距离底部.25border文字宽度0.5BORDER---------------------
double fontSize = BORDEROFFSET * 0.3;
ptDetail.set(ptDetail - BORDEROFFSET,ptDetail + 0.5 * BORDEROFFSET);
double curRoad = 0.0;
double latRoad = 0.0;
double offset = 0.0;
for(int i = 0;i < len;i ++)
{
latRoad = curRoad;
curRoad = roadArr.at(len - i - 1);
double offset = (curRoad + latRoad) / 2;


CString strSize;
double r = curRoad/ratio;
strSize.Format(采用T("%.1f"),r);
ptDetail.set(ptDetail - offset,ptDetail);
InsertText(ptDetail,ptDetail,0,strSize,fontSize);
}


//绘制底线-------高度2border----------------
double fstRoad = roadArr.at(0);


ptDetail.set(ptDetail - fstRoad/ 2 - BORDEROFFSET ,ptDetail - 2.25 * BORDEROFFSET);


pl3->addVertexAt(0,ptDetail);


ptDetail.set(ptDetail + BORDEROFFSET,ptDetail);
pl3->addVertexAt(1,ptDetail);


ptDetail.set(ptDetail,ptDetail + 2 * BORDEROFFSET);
pl3->addVertexAt(2,ptDetail);
ptDetail.set(ptDetail,ptDetail - 2 * BORDEROFFSET);
pl3->addVertexAt(3,ptDetail);


ptDetail.set(ptDetail + totalRoad,ptDetail);
pl3->addVertexAt(4,ptDetail);


ptDetail.set(ptDetail,ptDetail + 2 * BORDEROFFSET);
pl3->addVertexAt(5,ptDetail);


ptDetail.set(ptDetail,ptDetail - 2 * BORDEROFFSET);
pl3->addVertexAt(6,ptDetail);


ptDetail.set(ptDetail + BORDEROFFSET,ptDetail);
pl3->addVertexAt(7,ptDetail);


绘制底部文字
ptDetail.set(ptDetail- BORDEROFFSET - (totalRoad) / 2 ,ptDetail + 0.5 * BORDEROFFSET);
CString strTotal;
strTotal.Format(采用T("%.1f"),totalRoad/ratio);
InsertText(ptDetail,ptDetail,0,strTotal,fontSize);


最下面,显示出截面的名称
CString str;
str.Format(采用T("%s-%s"),strName,strName);


ptDetail.set(ptDetail ,ptDetail - 2.25 * BORDEROFFSET);
InsertText(ptDetail,ptDetail,0,str, 4 * fontSize,0,1,AcDb::TextHorzMode::kTextMid,AcDb::TextVertMode::kTextBottom);


LoadEntity(pl,true);
LoadEntity(pl2,true);
LoadEntity(plMid,true);
LoadEntity(pl3,true);
}


遍历曲线实体,取出XDATA,判断strName是否已存在其他曲线的XDATA中
static bool XDataIsExist(const CString& strName)
{
ads采用name ssName;选择集名称
添加过滤条件
resbuf* filter = acutBuildList(-3, 1001, 采用T("RNAME"), 0);
acedSSGet(采用T("X"),NULL,NULL,filter,ssName);
long len = 0;
acedSSLength(ssName,&len);


ads采用name entName;
AcDbObjectId id;
AcDbEntity* pEnt = NULL;
AcDbCurve* pCur = NULL;


CString outS;
for (int i=0;i<len;i++)
{
if (acedSSName(ssName, i, entName) != RTNORM)
{
continue;
}
acdbGetObjectId(id,entName);


以读模式打开,根据ID索引到对象,并打开ENTITY
acdbOpenObject(pEnt,id,AcDb::OpenMode::kForRead);
if (!pEnt->isKindOf(AcDbCurve::desc()))
{
continue;
}
pCur = (AcDbCurve*)pEnt;
struct resbuf* rb;
rb = pCur->xData(采用T("RNAME"));


if(rb == NULL)
{
continue;
}
struct resbuf* pTemp;
pTemp = rb;


首先要跳过应用程序名称
pTemp = pTemp->rbnext;


if(pTemp!= NULL && pTemp->restype ==AcDb::kDxfXdAsciiString && pTemp->resval.rstring !=NULL)
{
CString str1(pTemp->resval.rstring);
if(str1.Compare(strName) == 0)
{
return true;
}
}

acutRelRb(rb);
pCur->close();
}
acedSSFree(ssName);
return false;
}


//把横截面名称保存到扩展数据中
参数:多段线实体,名称
static void SavePlineXData(AcDbCurve* pLine,const CString strName)
{
//扩展数据的内容
struct resbuf* pRb;


注册应用程序名称
acdbRegApp(采用T("RNAME"));


CString strAppName(采用T("RNAME"));


创建结果缓冲区链表
pRb = acutBuildList(
AcDb::kDxfRegAppName,strAppName,
kDxfXdAsciiString,strName,
RTNONE);


添加扩展数据
struct resbuf* pTemp ;
pTemp = pLine->xData(采用T("RNAME"));


//如果已经包含扩展数据,不再重复添加
if (pTemp != NULL)
{
acutRelRb(pTemp);
acutPrintf(采用T("它已经包含了扩展数据"));
}
else
{
pLine->setXData(pRb);
acutPrintf(采用T("\n扩展数据已赋值"));
}


acutRelRb(pRb);
}


显示扩展数据
参数:多段线实体
static void ViewPlineXData(AcDbCurve* pLine)
{
struct resbuf* pRb;
pRb = pLine->xData(采用T("RNAME"));


if (pRb != NULL)
{
在命令行显示所有的扩展数据
struct resbuf* pTemp;
pTemp = pRb;
首先要跳过应用程序名称
pTemp = pTemp->rbnext;
acutPrintf(采用T("\n横截面的名称是:%s\n"),pTemp->resval.rstring);


acutRelRb(pRb);
}
else
{
acutPrintf(采用T("\n此实体没有任何扩展数据.\n"));
}
}


给图形实体,返回与选择的点之间的,与这个直线实体相交的交点数组、直线方向向量
参数:曲线实体,指定选择的点集,放到resbuf里面,2dpoint数组,三维向量
static void GetLineNum(AcDbCurve* pLine,resbuf* ptLst,AcGePoint3dArray& ptArr,AcGeVector3d& v,double& roadWidth,bool& success)
{
遍历所有实体
ads采用name ssName;选择集名称
acedSSGet(采用T("F"),ptLst,NULL,NULL,ssName);
long len = 0;
acedSSLength(ssName,&len);


if(len == 0)
{
success = false;
return;
}


ads采用name entName;
AcDbObjectId id;
AcDbEntity* pEnt = NULL;
AcDbCurve* pCur = NULL;
AcGePoint3dArray ptSecArr;交点集合
AcGePoint3d ptMin(0,0,0);
AcGePoint3d ptMax(0,0,0);
AcDbCurve* pMaxCur = NULL;
for (int i=0;i<len;i++)
{
if (acedSSName(ssName, i, entName) != RTNORM)
{
continue;
}


根据名称得到ID
acdbGetObjectId(id,entName);


以读模式打开,根据ID索引到对象,并打开ENTITY
acdbOpenObject(pEnt,id,AcDb::OpenMode::kForRead);
if (pEnt == NULL || !pEnt->isKindOf(AcDbCurve::desc()))
{
continue;
}


pCur = (AcDbCurve*)pEnt;
pCur->intersectWith(pLine,AcDb::Intersect::kOnBothOperands,ptSecArr);
if (ptSecArr.length() <= 0)
{
continue;
}
拿出第一个交点(两直线相交只可能有这一个交点)
AcGePoint3d pt3d (ptSecArr.at(0));
添加交点
ptArr.append(pt3d);
ptSecArr.removeAll();
pCur->getFirstDeriv(pt3d,v);


if(i == 0)
{
ptMin = ptArr.at(0);
ptMax = ptArr.at(0);
pMaxCur = pCur;
}
else
{
if(ptMin > pt3d)
{
ptMin = pt3d;
}
else if(ptMin == pt3d)
{
if(ptMin > pt3d)
{
ptMin = pt3d;
}
}
if(ptMax < pt3d)
{
ptMax = pt3d;
pMaxCur = pCur;
}
else if(ptMax == pt3d)
{
if(ptMax < pt3d)
{
ptMax = pt3d;
pMaxCur = pCur;
}
}
}
}


pMaxCur->getClosestPointTo(ptMin,ptMax);
roadWidth = ptMax.distanceTo(ptMin);
acutPrintf(采用T("road width is %.2f"),roadWidth);
pMaxCur->close();
success = true;
要及时释放选择集,一共只能同时打开128个选择集
acedSSFree(ssName);
}


对2dpoint数组排序,默认为X坐标从左到右,如果竖直,Y坐标从下到上
static void Sort2dArr(AcGePoint3dArray& arr,bool isHorizon)
{
double len = arr.length();


对于竖直情况,对Y坐标进行排序
if(!isHorizon)
{
for (int i = len - 1;i > 0; i --)
{
for(int j = 0;j < i; j++)
{
double preY = arr.at(j);
double latY = arr.at(j + 1);
if(preY > latY)
{
arr.swap(j,j+1);
}
}
}


}
else
{
for (int i = len - 1;i > 0; i --)
{
for(int j = 0;j < i; j++)
{
double preX = arr.at(j);
double latX = arr.at(j + 1);
if(preX > latX)
{
arr.swap(j,j+1);
}
}
}
}
}


画道路测试命令
static void TESTroadcmd()
{


输入坐标部分==============================
ads采用point inputStart;
ads采用point inputEnd;


AcGePoint2d ptStart;
AcGePoint2d ptEnd;


用户输入要画的坐标
if (acedGetPoint(NULL,采用T("\n起始点:"),inputStart) != RTNORM)
{
acutPrintf(采用T("\n未指定起始点"));
return;
}
ptStart = asPnt2d(inputStart);


if (acedGetPoint(NULL,采用T("\n终点:"),inputEnd) != RTNORM)
{
acutPrintf(采用T("\n未指定终点"));
return;
}


ptEnd = asPnt2d(inputEnd);


resbuf* ptList = NULL;
ptList = acutBuildList(RTPOINT,ptStart,RTPOINT,ptEnd,NULL);


这条线求交点,不用画出来
AcDbPolyline* pLine = new AcDbPolyline();
pLine->addVertexAt(0,ptStart);
pLine->addVertexAt(1,ptEnd);


AcGePoint3dArray pntArr;交点的数组
AcGeVector3d v1;道路方向


道路宽度
double roadWidth;
bool isSuc = false;是否成功取到了交点
GetLineNum(pLine,ptList,pntArr,v1,roadWidth,isSuc);
if(!isSuc)
{
acutPrintf(采用T("\n交点数量不合法"));


acutRelRb(ptList);
delete pLine;
return;
}
delete pLine;


int ptCount = pntArr.length();交点数量


如果交点数量不合法,退出
if(ptCount != BANDER1PTCOUNT&& ptCount != BANDER2PTCOUNT
&& ptCount != BANDER3PTCOUNT && ptCount != BANDER4PTCOUNT )
{
acutPrintf(采用T("\n两点之间的直线数须为{4,6,8,10}."));
return;
}
acutPrintf(采用T("\n交点个数:%d"),ptCount);


//输入名称部分,改用xData判断========================
CString strName;
AcDbObjectId pVerLineId = NULL;
ads采用name name;
while (true)
{
if(acedGetString(0,采用T("\n输入横断面名称:\n"),strName.GetBuffer(20))!= RTNORM)
{
return;
}
用完buffer记得release!!
strName.ReleaseBuffer();
if(strName.GetLength() > 2)
{
acutPrintf(采用T("\n输入的字符数太多,请重新输入"));
continue;
}
if(!XDataIsExist(strName))
{
break;
}
else
{
acutPrintf(采用T("\n已存在名称,请重新输入"));
}


}


///=========画垂线部分=============================
AcGeVector3d v2;横截面直线的方向向量


if(v1 == 0)竖直
{
Sort2dArr(pntArr,true);
v2.set(1,0,0);
}
else
{
if(v1 == 0)
{
Sort2dArr(pntArr,false);
v2.set(0,1,0);
}
else
{
Sort2dArr(pntArr,true);
v2.set(1,-v1 / v1,0);
}
}


AcGePoint3d ptSecFst = pntArr.at(0);第一个交点
计算单位向量
AcGeVector3d vNorm = v2.normalize();
vNorm = abs(vNorm);
vNorm = vNorm;
double len = 3 * BORDEROFFSET;
AcGePoint3d ptEnd1;
AcGePoint3d ptEnd2;


ptEnd1 = ptSecFst - 3*BORDEROFFSET * vNorm;
ptEnd2 = ptSecFst + (3 * BORDEROFFSET + roadWidth) * vNorm ;
AcGePoint3dArray arr;
arr.append(ptEnd1);
arr.append(ptEnd2);


AcDb3dPolyline* plVer = new AcDb3dPolyline(AcDb::Poly3dType::k3dSimplePoly,arr);
plVer->setLineWeight(AcDb::LineWeight::kLnWt030);


AcDbObjectId lineId = LoadEntity(plVer,true);


================绘制详细信息部分============================
acdbOpenObject(plVer,lineId,AcDb::OpenMode::kForWrite);因为要添加扩展数据所以要以写模式再次打开


//获得垂线与道路的交点集合
AcGePoint3dArray pntVerArr;
bool isOk = false;
GetLineNum(plVer,ptList,pntVerArr,v1,roadWidth,isOk);


释放链表空间
acutRelRb(ptList);


if(!isOk)
{
acutPrintf(采用T("\n垂线交点数量不合法"));
plVer->close();
return;
}
acutPrintf(采用T("\n垂线交点个数%d"),pntVerArr.length());


if(v2 == 0)
{
Sort2dArr(pntVerArr,false);
}
else
{
Sort2dArr(pntVerArr,true);
}


int ptVerCount = pntVerArr.length();


AcGeDoubleArray roadArr;
double roadLen;
AcGePoint3d prePt;
AcGePoint3d latPt;
for(int i = 0;i < ptVerCount - 1;i ++)
{
prePt = pntVerArr.at(i);
latPt = pntVerArr.at(i + 1);
roadLen = prePt.distanceTo(latPt);
roadArr.append(roadLen);
}


显示详细信息表格,宽度比例1:2,1:1时会导致字符超出边
ShowRoadDetail(roadArr,strName,2);


// //绘制横断面名称===============
double fontSize = 2 * BORDEROFFSET;
LocateWords(plVer,strName,fontSize,1);


保存扩展数据
SavePlineXData(plVer,strName);
查看一下保存的扩展数据
ViewPlineXData(plVer);


最后记得关闭polyline3d
plVer->close();
}


放置截面名称的文字
参数:多段线实体,文字,文字高度,文字加粗大小
static void LocateWords(AcDbCurve* plVer,const CString& strName,double height,double fontSize)
{
AcGePoint3d plPtS;
plVer->getStartPoint(plPtS);
AcGePoint3d plPtE;
plVer->getEndPoint(plPtE);


AcGeVector3d v;
plVer->getFirstDeriv(plPtS,v);


AcGeVector3d vX(1,0,0);
AcGeVector3d vZ(0,0,1);
double angle = v.angleTo(vX,vZ);
acutPrintf(采用T("\nangle is %.2f"),angle);


InsertText(plPtS,plPtS,0,strName,height,-angle,fontSize,AcDb::TextHorzMode::kTextLeft,AcDb::TextVertMode::kTextBottom);
InsertText(plPtE,plPtE,0,strName,height, -angle,fontSize,AcDb::TextHorzMode::kTextRight,AcDb::TextVertMode::kTextBottom);
}


static void TESTnormcmd()
{


}
static void TESTtestcmd()
{
ads采用real num;
if(RTNORM != acedGetReal(采用T("放大倍数"),&num))
{
return;
}
ads采用real angle;
if(RTNORM != acedGetReal(采用T("旋转角度"),&angle))
{
return;
}


ads采用point pt;
if(RTNORM!= acedGetPoint(NULL,采用T("选择一点"),pt))
{
acutPrintf(采用T("\nerror select"));
return;
}


InsertText(pt,pt,0,采用T("aaa"),num * BORDEROFFSET,angle,3,AcDb::TextHorzMode::kTextRight,AcDb::TextVertMode::kTextBottom);
}


} ;




//-----------------------------------------------------------------------------
IMPLEMENT采用ARX采用ENTRYPOINT(CArxProject3App)


ACED采用ARXCOMMAND采用ENTRY采用AUTO(CArxProject3App, TEST, roadcmd, roadcmd, ACRX采用CMD采用MODAL, NULL)
ACED采用ARXCOMMAND采用ENTRY采用AUTO(CArxProject3App, TEST, testcmd, testcmd, ACRX采用CMD采用MODAL, NULL)
ACED采用ARXCOMMAND采用ENTRY采用AUTO(CArxProject3App, TEST, normcmd, normcmd, ACRX采用CMD采用MODAL, NULL)
页: [1]
查看完整版本: OBJECT ARX 绘制道路横切面 实例