objectarx2023开发记录(八)---对称处理

背景,上次实现的绘制直角+偶数边的多边形,无法实现对称边边长一致,为了改进这一功能,现在添加对称处理。

一、代码

//-----------------------------------------------------------------------------
//----- 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;
		}

		//*****************处理首点***************************
		struct XY
		{
			double value;
			int In;
		};

		AcGePoint2d pB[MAX];

		double x_p = pA[0].x;
		double y_p = pA[0].y;
		for (int i = 0; i < num; i++)
		{
			if (x_p > pA[i].x)
			{
				x_p = pA[i].x;
			}

			if (y_p < pA[i].y)
			{
				y_p = pA[i].y;
			}
		}

		//acutPrintf(_T("star:%g,%g\n"), x_p, y_p);
		AcGePoint2d start(x_p, y_p);
		double dist = start.distanceTo(pA[0]);
		int ci = 0;
		for (int i = 1; i < num; i++)
		{
			double ds = start.distanceTo(pA[i]);
			if (ds < dist)
			{
				dist = ds;
				ci = i;
			}
		}
		//acutPrintf(_T("ci-A:%d\n"), ci);
		//acutPrintf(_T("pA[ci]:%g,%g\n"), pA[ci].x, pA[ci].y);
//*****************处理顺时针排序(有向面积法)***************************

		double A = 0;
		for (int i = 0; i < num; i++)
		{
			A += pA[i].x * pA[i + 1].y - pA[i + 1].x * pA[i].y;
		}

		A += pA[num - 1].x * pA[0].y - pA[0].x * pA[num - 1].y;

		A = 0.5 * A;
		if (A < 0)//顺时针排序
		{

			int cB = 0;
			for (int i = ci; i < num; i++)
			{
				pB[cB] = pA[i];
				cB++;
				//acutPrintf(_T("pB[%d]:%g,%g\n"), cB - 1, pA[i].x, pA[i].y);
			}

			for (int i = 0; i < ci; i++)
			{
				pB[cB] = pA[i];
				cB++;
				//acutPrintf(_T("pB[%d]:%g,%g\n"), cB - 1, pA[i].x, pA[i].y);
			}
		}
		else//逆时针排序
		{
			AcGePoint2d pC[MAX]; int tc = 0; int di = 0;
			for (int i = num - 1; i >= 0; i--)
			{
				pC[tc] = pA[i];
				tc++;
				if (ci == i)
				{
					di = tc - 1;
				}
			}

			int cB = 0;
			for (int i = di; i < num; i++)
			{
				pB[cB] = pC[i];
				cB++;
				//acutPrintf(_T("pB[%d]:%g,%g\n"), cB - 1, pC[i].x, pC[i].y);
			}

			for (int i = 0; i < di; i++)
			{
				pB[cB] = pC[i];
				cB++;
				//acutPrintf(_T("pB[%d]:%g,%g\n"), cB - 1, pC[i].x, pC[i].y);
			}
		}

		for (int i = 0; i < num; i++)
		{
			pA[i] = pB[i];
		}

//*****************计算距离***************************
		double dis[MAX];
		CalDistance(pA, num, 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("计算两点间距离正常执行"));
//*****************计算文本位置***************************
		AcGePoint2d pT[MAX];
		for (int i = 0; i < num - 1; i++)
		{
			pT[i].x = (pA[i].x + pA[i + 1].x) / 2;
			pT[i].y = (pA[i].y + pA[i + 1].y) / 2;
		}

		pT[num-1].x = (pA[0].x + pA[num-1].x) / 2;
		pT[num-1].y = (pA[0].y + pA[num-1].y) / 2;

//*****************显示边长序号***************************
		
		for (int i = 0; i < num ; i++)
		{
			AcDbText* pText = new AcDbText();
			AcGePoint3d p3d(pT[i].x, pT[i].y, 0);
			CString cst;
			cst.Format(_T("%d"), i + 1);
			pText->setTextString(cst);
			pText->setPosition(p3d);
			pText->setHeight(0.5);

			pText->setLayer(_T("0"));

			AcDbBlockTable* pBT;
			acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBT, AcDb::kForRead);
			AcDbBlockTableRecord* pBTR;
			pBT->getAt(ACDB_MODEL_SPACE, pBTR, AcDb::kForWrite);
			pBTR->appendAcDbEntity(pText);

			pBT->close();
			pBTR->close();
			pText->close();
		}

//*****************************获取输入的字符串*********************************************
		int bLoop;
		TCHAR result3[50] = { 999 };
		int st3 = acedGetString(0, _T("\n对称处理[是(1)/否(2)]:"), result3);

		if (st3 == RTNORM)
		{
			if (_ttoi(&result3[0]) == 1)
			{
				bLoop = 1;
			}
			else if (_ttoi(&result3[0]) == 2)
			{
				bLoop = 0;
			}
		}
		else if (st3 == RTCAN)
		{
			acutPrintf(_T("用户取消\n"));
			return;
		}

		
		struct DC
		{
			int num1;
			int num2;
		};

		DC dd[MAX]; int index_DC=0;

		while (bLoop)
		{
			TCHAR result[50] = {999};
			TCHAR result2[50] = {999};
			int st = acedGetString(0, _T("\n对称1号边序号:"), result);

			if (st == RTCAN)
			{
				acutPrintf(_T("用户取消\n"));
				bLoop = false;
				break;
			}

			if (st == RTNORM)
			{
				if (_ttoi(&result[0]) == 0)
				{
					acutPrintf(_T("对称选择结束\n"));
					break;
				}
				else
				{
					int st2 = acedGetString(0, _T("\n对称2号边序号:"), result2);
					if ((st == RTNORM) & (st2 == RTNORM))
					{
						if (_ttoi(&result2[0]) == 0)
						{
							acutPrintf(_T("对称选择错误,退出功能\n"));
							bLoop = 3;
							break;
						}

						dd[index_DC].num1 = _ttoi(&result[0]);
						dd[index_DC].num2 = _ttoi(&result2[0]);
						index_DC++;

						//acutPrintf(_T("\ndd[index_DC-1]:%d\n"), dd[index_DC-1].num1);
						//acutPrintf(_T("dd[index_DC-2]:%d\n"), dd[index_DC-1].num2);

					}
					else if ((st == RTCAN) || (st2 == RTCAN))
					{
						acutPrintf(_T("用户取消\n"));
						bLoop = 3;
						break;
					}
					else if ((st == RTERROR) || (st2 == RTERROR))
					{
						acutPrintf(_T("输入错误\n"));
						bLoop = 3;
						break;
					}
					else if ((st == RTREJ) || (st2 == RTREJ))
					{
						acutPrintf(_T("输入无效\n"));
						bLoop = 3;
						break;
					}
				}

			}
		}

		if (bLoop == 3)
		{
			return;
		}
		//acutPrintf(_T("index_DC:%d\n"), index_DC);
//*****************************修改距离值*********************************************
		
		for (int i = 0; i < index_DC; i++)
		{
			int n1 = dd[i].num1 - 1;
			int n2 = dd[i].num2 - 1;

			if ((n1 < num - 1) & (n2 < num - 1))
			{
				//acutPrintf(_T("dis[n1]-1:%f\n"), dis[n1]);
				//acutPrintf(_T("dis[n2]-1:%f\n"), dis[n2]);

				dis[n1] = (dis[n1] + dis[n2]) / 2;

				int a = static_cast<int>(dis[n1] * 100);
				if (a % 2)
				{
					a = a + 1;
				}
				dis[n1] = double(a) / 100;

				dis[n2] = dis[n1];
				//acutPrintf(_T("dis[n1]-2:%f\n"), dis[n1]);
				//acutPrintf(_T("dis[n2]-2:%f\n"), dis[n2]);
			}

			if ((n1 == num - 1) || (n2 == num - 1))
			{
				if ((n1 == num-1)&(n2!=num-1))
				{
					dis[n2]=(pA[0].distanceTo(pA[num - 1])+ dis[n2])/2;
					int a = static_cast<int>(dis[n2] * 100);
					if (a % 2)
					{
						a = a + 1;
					}
					dis[n2] = double(a) / 100;
					//acutPrintf(_T("n1 == num-1:%d\n"), n1);
				}
				else if((n2==num-1 )& (n1 != num - 1))
				{
					dis[n1] = (pA[0].distanceTo(pA[num - 1]) + dis[n1]) / 2;
					int a = static_cast<int>(dis[n1] * 100);
					if (a % 2)
					{
						a = a + 1;
					}
					dis[n1] = double(a) / 100;
					//acutPrintf(_T("n2 == num-1:%d\n"), n2);
				}
				else if ((n2 == num - 1) & (n1 == num - 1))
				{
					acutPrintf(_T("输入错误,请核查\n"));
				}
			}

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

		//第一步,计算与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 = pta - ptb;

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

		//AcGeVector2d Vcd = ptd - ptc;
		//double Angle_cd = Vcd.angle();
		//double dx1 = dis[num - 2] * cos(Angle_cd);
		//double dy1 = dis[num - 2] * sin(Angle_cd);
		//AcGePoint2d ptE_1(ptc.x + dx1, ptc.y + dy1);


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

		AcGePoint2d ptE = pta + vecNext * 500;

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

		AcGePoint2d ii;

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

		//acutPrintf(_T("ptE:%g,%g\n"), ptE.y,ptE.x);
		//acutPrintf(_T("ii:%g,%g\n"), 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(index - 1);

		//****************************输入块表******************************
				//结尾代码

				//pl->setPointAt(0, intersect2d);

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

		Setblocktable(pl);
		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)
	{
		AcDbBlockTable* pBlockTable = NULL;
		//获取这个图形数据库的块表
		acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable, AcDb::kForRead);

		AcDbBlockTableRecord* pBlockTableRecord;

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

		//创建实体,并加入到指定的块表记录中
		AcDbObjectId lineId;
		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("已选1个\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)

二、对称处理思路

通过在图上标记边长序号,让用户输入对称两条边的序号,由此计算两条对称边的均值,然后执行之前的代码,即可。

三、效果

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值