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[X] + BORDEROFFSET,ptDetail[Y] - BORDEROFFSET);
pl->addVertexAt(1,ptDetail);


////左边竖线
ptDetail.set(ptDetail[X] ,ptDetail[Y] - 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[X] + road,ptDetail[Y]);
pl->addVertexAt(index,ptDetail);


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


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


//绘制表格中部---------------
ptDetail.set(ptDetail[X] - BORDEROFFSET,ptDetail[Y] - 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[X],ptDetail[Y] - 3 * BORDEROFFSET);
pl2->addVertexAt(index,ptDetail);
index ++;
////车道
ptDetail.set(ptDetail[X]-road,ptDetail[Y]);
pl2->addVertexAt(index,ptDetail);
index++;
////左边线
ptDetail.set(ptDetail[X],ptDetail[Y] + 3 * BORDEROFFSET);
pl2->addVertexAt(index,ptDetail);
index ++;
}


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


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


//绘制文字-------距离底部.25border文字宽度0.5BORDER---------------------
double fontSize = BORDEROFFSET * 0.3;
ptDetail.set(ptDetail[X] - BORDEROFFSET,ptDetail[Y] + 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[X] - offset,ptDetail[Y]);
InsertText(ptDetail[X],ptDetail[Y],0,strSize,fontSize);
}


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


ptDetail.set(ptDetail[X] - fstRoad/ 2 - BORDEROFFSET ,ptDetail[Y] - 2.25 * BORDEROFFSET);


pl3->addVertexAt(0,ptDetail);


ptDetail.set(ptDetail[X] + BORDEROFFSET,ptDetail[Y]);
pl3->addVertexAt(1,ptDetail);


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


ptDetail.set(ptDetail[X] + totalRoad,ptDetail[Y]);
pl3->addVertexAt(4,ptDetail);


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


ptDetail.set(ptDetail[X],ptDetail[Y] - 2 * BORDEROFFSET);
pl3->addVertexAt(6,ptDetail);


ptDetail.set(ptDetail[X] + BORDEROFFSET,ptDetail[Y]);
pl3->addVertexAt(7,ptDetail);


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


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


ptDetail.set(ptDetail[X] ,ptDetail[Y] - 2.25 * BORDEROFFSET);
InsertText(ptDetail[X],ptDetail[Y],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[X] > pt3d[X])
{
ptMin = pt3d;
}
else if(ptMin[X] == pt3d[X])
{
if(ptMin[Y] > pt3d[Y])
{
ptMin = pt3d;
}
}
if(ptMax[X] < pt3d[X])
{
ptMax = pt3d;
pMaxCur = pCur;
}
else if(ptMax[X] == pt3d[X])
{
if(ptMax[Y] < pt3d[Y])
{
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)[Y];
double latY = arr.at(j + 1)[Y];
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)[X];
double latX = arr.at(j + 1)[X];
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[X] == 0)////竖直
{
Sort2dArr(pntArr,true);
v2.set(1,0,0);
}
else
{
if(v1[Y] == 0)
{
Sort2dArr(pntArr,false);
v2.set(0,1,0);
}
else
{
Sort2dArr(pntArr,true);
v2.set(1,-v1[X] / v1[Y],0);
}
}


AcGePoint3d ptSecFst = pntArr.at(0);////第一个交点
////计算单位向量
AcGeVector3d vNorm = v2.normalize();
vNorm[X] = abs(vNorm[X]);
vNorm[Y] = vNorm[Y];
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[X] == 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[X],plPtS[Y],0,strName,height,-angle,fontSize,AcDb::TextHorzMode::kTextLeft,AcDb::TextVertMode::kTextBottom);
InsertText(plPtE[X],plPtE[Y],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[X],pt[Y],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)



你可能感兴趣的:(object,struct,null,扩展,dependencies)