//----------------------------------------------------------------------------- //----- 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)