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, 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 = 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)

二、结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值