zltangent 发表于 2011-9-20 21:42:42

ARX直线打断(可打断直线、弧线、多线段)

本帖最后由 zltangent 于 2011-9-20 21:42 编辑

前阵子发的贴子只可以打断单个直线,且打断方式是重新绘制直线,实现打断效果。这样理解比较容易,但是带来的问题也比较多,首先内存的开辟,一根没事,多根线打断就是问题了;再者打断前如果线在某个涂层,而且有多种属性,则靠重新绘制的方法要考虑很多东西,而且容易出错。

鉴于以上问题,可以用打断命令来处理。打断命令函数如下:
ads_command(
RTSTR, _T("BREAK"),
RTLB,
RTENAME,
(LONG_PTR*)entSel,
RT3DPOINT, pt1,
RTLE,
RTSTR, _T("F"),
RT3DPOINT, pt1,
RT3DPOINT, pt2,
RTNONE)
注:ads_point pt1, pt2;(或者用AcGePoint3d ptS, ptE; 但是要取地址才行。)

现在的代码,可以打断直线、弧线、多线段。可以单独处理它们,也可以综合处理他们。综合处理的根据是AcDbLine\AcDbArc\AcDbPolyline的基类均是AcDbCurve,所以可以用处理曲线的方式来统一处理直线、弧线和多线段。
现把BreakLine命令函数内主要代码分享如下:

// 添加实体进G-DB
AcDbObjectId PostToModelSpace(AcDbEntity* pEnt);   
// This is command 'BREAKLINE'
// AcDbLine\AcDbArc\AcDbPolyline->AcDbCurve,用曲线处理直线段、弧线、多线段
void T4BreakLine()
{
// 关闭对象捕捉
struct resbuf os1, os2;
ads_getvar(_T("osmode"), &os1);          // acedGetVar("osmode", &os1);
os2.restype = RTSHORT;            // 设置系统变量数据类型
os2.resval.rint = 0;            // 设置系统变量新值
ads_setvar(_T("osmode"), &os2);

CAcModuleResourceOverride resOverride;      // 防止资源冲突

if(NULL == pDlg)
{
pDlg = new CBreakLineLenDlg(acedGetAcadFrame());
pDlg->Create(IDD_LINELENGTH);
pDlg->ShowWindow(SW_SHOW);
}
else
{
// 防止用户按下Esc隐藏对话框,在此若隐藏则显示出来
pDlg->ShowWindow(SW_SHOW);
}

ads_point ptPick1,ptPick2;         // 给一个起点,终点
AcGePoint3d ptS, ptE;            // 线段始末点

AcDbLine* pLine = NULL;            // 实体对象      
AcDbObjectId IdCur;             // 当前线段ID

double breakLen = 0;

ads_name ssname;             // 选择集

// 主循环
while(1)
{
// 第一个点
if(RTNORM != acedGetPoint(NULL, _T("\n输入第一个点:"), ptPick1))
{
   break;
}
ptS = asPnt3d(ptPick1);

// 第二个点
if(RTNORM != acedGetPoint(ptPick1, _T("\n输入第二个点:"), ptPick2))
{
   break;
}
ptE = asPnt3d(ptPick2);

// 生成线段
pLine = new AcDbLine;
pLine->setStartPoint(ptS);
pLine->setEndPoint(ptE);
IdCur = PostToModelSpace(pLine);      // 添加实体进G-DB
pLine = NULL;             // 使用后先赋值NULL
ads_name CurName;            // 当前线name
acdbGetAdsName(CurName, IdCur);         
   
if (!pDlg->IsBreak())
{
   continue;
}
// 接收长度
breakLen = atof(pDlg->GetBreakLen());      

ads_name entName;
long ssLen = 0;             // 记录选择集长度

AcDbEntity* pEnt = NULL;          // 目标实体
AcDbCurve* pLinePre = NULL;          // 目标line(AcDbLine\AcDbArc\AcDbPolyline)
AcDbObjectId linePreId;         // 目标实体ID
   
AcGePoint3dArray ArsNodPt;          // 交点数组
   
// 选择0图层上的与当前线始末点坐标连成的区域相交的线
resbuf* ptLst = ads_buildlist(RTPOINT, ptPick1, RTPOINT, ptPick2, NULL);
ads_ssget(_T("F"), ptLst, NULL, NULL, ssname);

// 获取选择集长度
ads_sslength(ssname, &ssLen);

// 过滤、求交点、打断处理
for(; ssLen > 0; )
{
   // 获取当前线
   acdbOpenObject(pLine, IdCur, AcDb::kForRead);
   
   // 判断当前线是否有效
   if(pLine)
   {
    // 遍历选择集提取当前的前一个实体ID,并由此ID获取其实体
    // 多线段的话总是提取处理后的剩余部分
    ads_ssname(ssname, 0, entName);         
    acdbGetObjectId(linePreId, entName);
    acdbOpenObject(pEnt, linePreId, AcDb::kForWrite);
    if(pEnt)
    {
   // 直线、曲线、多线段均属于曲线,直接转换
   pLinePre = AcDbCurve::cast(pEnt);
   if(pLinePre)
   {
      // 获取交点
      ArsNodPt.setLogicalLength(0);
      pLine->intersectWith(pLinePre, AcDb::kOnBothOperands, ArsNodPt);
      pEnt->close();
      
      // 有交点处理
      int iNum = ArsNodPt.length();
      if(iNum > 0)
      {
       // 获取打断点
       AcGePoint3d AptS, AptE;         // 弧线打断始末点
       double Alen;         // 一段线长      
       pLinePre->getDistAtPoint(ArsNodPt, Alen);   // 获取线起点到交点距离
       pLinePre->getPointAtDist(Alen - breakLen / 2, AptS); // 获取线打断点
       pLinePre->getPointAtDist(Alen + breakLen / 2, AptE); // 获取线远打断点
      
       // 从选择集中除去即将处理的实体
       ads_ssdel(entName,ssname);
      
       // 打断处理
       ads_command(RTSTR, _T("BREAK"),
      RTLB, RTENAME, (LONG*)entName, RT3DPOINT, &AptS,
      RTLE, RTSTR, _T("F"), RT3DPOINT, &AptS, RT3DPOINT, &AptE, RTNONE);      
      
       // 多点处理,重建选择集
       if(iNum > 1)
       {
      // 首先释放先前选择集
      ads_ssfree(ssname);
      
      // 重建选择集
      ads_ssget(_T("F"), ptLst, NULL, NULL, ssname);
      
      // 除去当前线
      ads_ssdel(CurName, ssname);
       }
      
       // 重新计算选择集内元素个数
       ads_sslength(ssname, &ssLen);
      }
      else
      {
       break;
      }
      
      // 还原对象捕捉
      ads_setvar(_T("osmode"), &os1);      
   }
   else
   {
      // 转换失败处理
      pEnt->close();
      continue;
   }
    } // end of if(pEnt)
   
    pLine->close();
   } // end of if(pLine)
   
} // end of for(过滤、求交点、打断)
acutRelRb(ptLst);
} // end of while(主循环)
// 命令结束,资源释放
ads_ssfree(ssname);

// 打断结束关闭对话框
pDlg->CloseDialog();
}
// 添加实体进G-DB
AcDbObjectId PostToModelSpace(AcDbEntity* pEnt)
{
// 获取当前活动G-DB的块表指针
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable,
AcDb::kForRead);
// 获取块表记录指针
AcDbBlockTableRecord *pBlockTableRecord;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite);
// 添加实体进G-DB
AcDbObjectId entId;
pBlockTableRecord->appendAcDbEntity(entId, pEnt);
// last-close
pBlockTable->close();
pBlockTableRecord->close();
pEnt->close();
return entId;
}

打断效果贴图如下:

刚接触不久,不清楚的地方还很多,请大家多批评指正,O(∩_∩)O~。
有问题随时交流,zltangent@163.com

tth02 发表于 2011-10-25 20:30:57

不错。居然没人顶。

luowy 发表于 2011-10-28 09:40:30

AcDbCurve下面,有个叫getSplitCurves,专门对付这些,
楼主的思路是从lsp中来的

zltangent 发表于 2011-11-3 22:47:40

luowy 发表于 2011-10-28 09:40 static/image/common/back.gif
AcDbCurve下面,有个叫getSplitCurves,专门对付这些,
楼主的思路是从lsp中来的

啊,lsp我不懂啊,没接触那个东西O(∩_∩)O~;AcDbCurve::getSplitCurves Function 比较长,回头慢慢看了,呵呵,其实我之前想单独处理,后来主管帮我的,才改写成这样。不过会留意这个函数,当时看网上提到这个函数很多次。具体怎么用还没整过。

xgready 发表于 2011-11-10 10:00:58

确实,还是感觉用getSplitCurves函数来写比较好,尤其是拉框之类裁切大数据量的时候。

Fred0612 发表于 2011-11-16 21:42:45

不错,很好的东西,可以借鉴……

vlisp2012 发表于 2011-11-28 21:13:48

好程序,一定要顶啊!

cbuttonst 发表于 2011-12-17 22:25:06

楼主犀利!!!

c735023723 发表于 2012-1-4 21:06:46

这个必须顶!

tianyi1230 发表于 2012-4-16 09:53:14

很好的东西不错,顶楼主
页: [1] 2
查看完整版本: ARX直线打断(可打断直线、弧线、多线段)