objectarx2023开发记录(五)---直角+偶数多边形绘制

一、背景:根据任务,需要在已有地形的基础之上,绘制边长为偶数结尾的(保留2位小数)直角多边形。

二、任务解析:

(1)获取选择集,实现单选+多选+多段线;

(2)获取已有的地形数据,删除每条直线上首尾节点外的其他多余点;

(3)先计算原始各边的边长;

(4)计算从起始边开始的,沿直线前进方向左侧或右侧的下一个点的方向,得到方向数值;

(5)处理第一条边,使其在方向不变的情况下,边长为偶数;

(6)批处理多段线的中间节点,要求根据方向数值和原始边长值,计算下一条边的末点边长;

(9)处理末位边长,使其与起始边保持垂直,并计算最后的节点坐标;

(10)输出到块表区域;

(11)完成图形绘制。

三、完整代码


//-----------------------------------------------------------------------------
//----- acrxEntryPoint.cpp
//-----------------------------------------------------------------------------
#include "StdAfx.h"
#include "resource.h"

#include <vector>

//-----------------------------------------------------------------------------
#define szRDS _RXST("AB")

const int MAX = 50;

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

public:
	CArxProject4App () : 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 () {
	}
	
//*****************命令FF函数***************************
	static void ABMyGroupFF () {
		// Put your command code here

		AcGePoint2d pA[MAX];//存储多段线顶点坐标
		int num=0;//存储多段线顶点数量
		GetPolylineCoordinates(pA,num);//获取多段线顶点坐标
		//ShowCoordinates(pA, MAX);//显示获取的坐标
		//acutPrintf(_T("获取多段线顶点坐标正常执行"));

		if (num == 0)
		{
			acutPrintf(_T("失败,退出功能"));
			return;
		}

		double dis[MAX];
		CalDistance(pA, MAX, dis);//计算原始两点间距离

		int dir[MAX];
		for (int i = 0; i < MAX; i++)
		{
			dir[i] = 0;
		}

		AcDbPolyline* pl = new AcDbPolyline();
		AcDbPolyline* pd = new AcDbPolyline();
		int index = 0;

		//acutPrintf(_T("计算两点间距离正常执行"));

//*****************处理第一条边的坐标***************************

		//第一步,计算与X轴正方向的角度(弧度)
		AcGeVector2d Vab = pA[1] - pA[0];
		double Angle_ab = Vab.angle();

		//计算增量
		double dx = dis[0] * cos(Angle_ab);
		double dy = dis[0] * sin(Angle_ab);

		//计算新的B点
		AcGePoint2d ptB_1(pA[0].x + dx, pA[0].y + dy);

		//更改数组中的B点坐标
		pA[1] = ptB_1;

		//调用函数绘制起始线
		pl->addVertexAt(index, pA[0]);
		index++;
		pl->addVertexAt(index, ptB_1);
		index++;

		//acutPrintf(_T("A点坐标:%g,%g\n"), pA[0].y, pA[0].x);
		//acutPrintf(_T("B点坐标:%g,%g\n"), pA[1].y, pA[1].x);
		//acutPrintf(_T("第一条边正常执行"));
//***********************处理方向*********************************

		pd->addVertexAt(0, pA[0]);
		pd->addVertexAt(1, pA[1]);
		
		for (int i = 2; i < num; i++)
		{
			pd->addVertexAt(i, pA[i]);
		}
		Direction(pd, dir);
		pd->close();
		//acutPrintf(_T("处理方向正常执行"));

//***********************批处理中间节点*********************************
		
		for (int i = 0; i < num-2; i++)
		{
			if (dir[i] == 1)
			{
				pA[i + 2] = DrawPolyline_Left(pA[i], pA[i + 1], dis[i + 1], pl, index);
			}
			else if (dir[i] == 2)
			{
				pA[i + 2] = DrawPolyline_Right(pA[i], pA[i + 1], dis[i + 1], pl, index);
			}
		}
		//acutPrintf(_T("批处理中间节点正常执行"));
//***************************处理末位节点****************************

		int numvertex=pl->numVerts();
		//acutPrintf(_T("numvertex:%d\n"), numvertex);
		AcGePoint2d ptc;
		pl->getPointAt(numvertex - 2, ptc);
		AcGePoint2d ptd;
		pl->getPointAt(numvertex - 1, ptd);
		AcGePoint2d pta;
		pl->getPointAt(0, pta);
		AcGePoint2d ptb;
		pl->getPointAt(1, ptb);
		AcGeVector2d vecPrev = ptd - ptc;

		//acutPrintf(_T("获取末位节点正常执行"));

		//AcGeVector2d vecNext = vecPrev.perpVector();//取逆时针,前进方向的左侧
		AcGeVector2d vecNext = vecPrev.perpVector().negate();//取顺时针
		vecNext.normalize();

		AcGePoint2d ptE = ptd + vecNext * dis[num-2];

		AcGeLine2d l1(ptd, ptE);
		AcGeLine2d l2(pta, ptb);

		AcGePoint2d ii;

		int sta=l1.intersectWith(l2, ii);

		//acutPrintf(_T("ii:%g,%g"), ii.y,ii.x);

	/*	AcDbLine* pline1 = new AcDbLine(AcGePoint3d(ptd.x, ptd.y, 0), AcGePoint3d(ptE.x, ptE.y, 0));
		AcDbLine* pline2 = new AcDbLine(AcGePoint3d(ptb.x, ptb.y, 0), AcGePoint3d(pta.x, pta.y, 0));
		AcGePoint3dArray pt_intersect3d;
		pline1->intersectWith(pline2, AcDb::kOnBothOperands, pt_intersect3d);
		int ll = pt_intersect3d.length();
		if (ll >= 1)
		{
			AcGePoint2d intersect2d(pt_intersect3d[0].x, pt_intersect3d[0].y);
			pl->addVertexAt(index, intersect2d);
			pl->removeVertexAt(0);
		}*/

		pl->addVertexAt(index, ii);
		pl->removeVertexAt(0);

//****************************输入块表******************************
		//结尾代码
	
		//pl->setPointAt(0, intersect2d);

		pl->setClosed(true);//闭合多段线

		AcDbObjectId id;
		Setblocktable(pl, id);
		pl->close();
		//acutPrintf(_T("结束正常执行"));

	}
//------------------------------------------END--------------------------------------------------------


//****************************方向判断函数******************************
	static void Direction(AcDbPolyline* pl,int dir[])
	{
		int index = pl->numVerts(); int k = 0;
		//acutPrintf(_T("index:%d\n"), index);
		for (int i = 0; i < index - 2; i++)
		{
			AcGePoint2d p0;
			pl->getPointAt(i, p0);
			AcGePoint2d p1;
			pl->getPointAt(i+1, p1);
			AcGePoint2d p2;
			pl->getPointAt(i+2, p2);

			double v1_x = p1.x - p0.x;
			double v1_y = p1.y - p0.y;
			double v2_x = p2.x - p0.x;
			double v2_y = p2.y - p0.y;

			double cross = v1_x * v2_y - v1_y * v2_x;
			const double eps = 1e-8;

			if (cross > eps)
			{
				dir[k] = 1; //左侧
			}
			else if(cross<-eps)
			{
				dir[k] = 2;  //右侧
			}
			//acutPrintf(_T("方向%d:%d\n"), k, dir[k]);
			k++;

		}		
	}


//**************************添加至块表函数**********************************

	static void Setblocktable(AcDbPolyline* pl, AcDbObjectId &lineId)
	{
		AcDbBlockTable* pBlockTable = NULL;
		//获取这个图形数据库的块表
		acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable, AcDb::kForRead);

		AcDbBlockTableRecord* pBlockTableRecord;

		//获取块表的记录
		pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite);//模型空间就是一个块表记录

		//创建实体,并加入到指定的块表记录中
		pBlockTableRecord->appendAcDbEntity(lineId, pl);

		pBlockTable->close();

		pBlockTableRecord->close();
	}

//**********************绘制垂直线函数(取前进方向左侧)*************************************
	static AcGePoint2d DrawPolyline_Left(AcGePoint2d ptA, AcGePoint2d ptB,double dis,AcDbPolyline *pl,int &index)
	{
		AcGeVector2d vecPrev = ptB - ptA;

		AcGeVector2d vecNext = vecPrev.perpVector();//取逆时针,前进方向的左侧
		//AcGeVector2d vecNext = vecPrev.perpVector().negate();//取顺时针
		vecNext.normalize();


		AcGePoint2d ptC = ptB + vecNext * dis;
		//acutPrintf(TEXT("dis[0]%.6f"), dis);

		pl->addVertexAt(index,ptC);
		index++;

		return ptC;
	}

//**********************绘制垂直线函数(取前进方向右侧)*************************************
	static AcGePoint2d DrawPolyline_Right(AcGePoint2d ptA, AcGePoint2d ptB, double dis, AcDbPolyline* pl, int& index)
	{
		AcGeVector2d vecPrev = ptB - ptA;

		//AcGeVector2d vecNext = vecPrev.perpVector();//取逆时针,前进方向的左侧
		AcGeVector2d vecNext = vecPrev.perpVector().negate();//取顺时针,前进方向右侧
		vecNext.normalize();


		AcGePoint2d ptC = ptB + vecNext * dis;
		//acutPrintf(TEXT("dis[0]%.6f"), dis);

		pl->addVertexAt(index, ptC);
		index++;

		return ptC;
	}


//***********************计算两点间距离函数**********************************
	static void CalDistance(AcGePoint2d pA[], int num,double dis[])
	{
		for (int i = 0; i < num-1; i++)
		{
			dis[i]=pA[i].distanceTo(pA[i + 1]);
			//acutPrintf(TEXT("dis[0]-a:%.6f\n"), dis[i]);
			int a = static_cast<int>(dis[i] * 100);
			if (a % 2)
			{
				a=a+1;
			}
			dis[i] = double(a) / 100;
		}
	}

//***********************显示坐标函数*********************************
	static void ShowCoordinates(AcGePoint2d pA[],int num)
	{
		for (int i = 0; i < num; i++)
		{
			acutPrintf(TEXT("XY%d:%g,%g\n"), i, pA[i].x, pA[i].y);
		}
	}

//*************************获取坐标函数**********************************
	static void GetPolylineCoordinates(AcGePoint2d *pA,int &num)
	{
		ads_name ss;
		
		resbuf rb;
		rb.restype = 0;
		rb.resval.rstring = _T("LWPOLYLINE");
		rb.rbnext = NULL;

		int rt = acedSSGet(_T("-b:S"), NULL, NULL, &rb, ss);
		if (rt == RTNORM)
		{
			acutPrintf(TEXT("选择了一条多段线\n"));
			ads_name entres;
			acedSSName(ss, 0, entres);

			AcDbObjectId ssId;
			acdbGetObjectId(ssId, entres);

			AcDbEntity* pEnt;
			acdbOpenObject(pEnt, ssId, AcDb::kForRead);

			if (pEnt->isKindOf(AcDbPolyline::desc()))
			{
				AcDbPolyline* pPolyline;
				pPolyline = AcDbPolyline::cast(pEnt);
				num = pPolyline->numVerts();
				//acutPrintf(TEXT("num:%d\n"), num);

				for (int j = 0; j < num; j++)
				{
					AcGePoint2d pt;
					if (pPolyline->getPointAt(j, pt) == eOk)
					{
						*pA = pt;
						pA += 1;
						//acutPrintf(TEXT("XY:%g,%g\n"), pt.x, pt.y);
					}
				}
				pPolyline->close();
			}
			pEnt->close();
			acedSSFree(entres);
		}
		else if(rt==RTCAN)
		{
			acutPrintf(TEXT("取消\n"));
		}
		else if (rt == RTREJ)
		{
			acutPrintf(TEXT("输入无效\n"));
		}
		else
		{
			acutPrintf(TEXT("输入失效2\n"));
		}
		acedSSFree(ss);


	}

//********************************end*****************************

	static void ABMyGroupMyPickFirst () {
		ads_name result ;
		int iRet =acedSSGet (ACRX_T("_I"), NULL, NULL, NULL, result) ;
		if ( iRet == RTNORM )
		{
			// There are selected entities
			// Put your command using pickfirst set code here
		}
		else
		{
			// There are no selected entities
			// Put your command code here
		}
	}

	static void ABMyGroupMySessionCmd () {
		// Put your command code here
	}

	static int ads_MyLispFunction () {

		return (RTNORM) ;
	}
	
} ;

//-----------------------------------------------------------------------------
IMPLEMENT_ARX_ENTRYPOINT(CArxProject4App)

ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject4App, ABMyGroup, FF, FF, ACRX_CMD_MODAL, NULL)
ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject4App, ABMyGroup, MyPickFirst, MyPickFirstLocal, ACRX_CMD_MODAL | ACRX_CMD_USEPICKSET, NULL)
ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject4App, ABMyGroup, MySessionCmd, MySessionCmdLocal, ACRX_CMD_MODAL | ACRX_CMD_SESSION, NULL)
ACED_ADSSYMBOL_ENTRY_AUTO(CArxProject4App, MyLispFunction, false)

在acrxEntryPoint.cpp文件中,写入上述代码,生成解决方案即可。

四、CAD中调用上述生成的.arx插件。

绘制图形,如下:

五、工具适用场景

一般用于房产测绘中房子的绘制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值