objectarx开发记录(六)---实现西北角+顺时针排序多段线顶点

背景:为了保证绘制出的图形不随着起点位置的变化而变化,需要先把起点定为西北角,并按顺时针排序。

本文衔接上篇(五),添加了以西北角为起点,并顺时针排序的内容。

一、代码:


//-----------------------------------------------------------------------------
//----- 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);
//*****************处理顺时针排序***************************
		AcGePoint2d centre(0, 0);
		for (int i = 0; i < num; i++)
		{
			centre.x += pA[i].x;
			centre.y += pA[i].y;
		}
		centre.x /= num;
		centre.y /= num;

		struct Ag
		{
			double angle;
			int id;
		};

		std::vector<Ag> angle(MAX);
		for (int i = 0; i < num; i++)
		{
			angle[i].angle = atan2(pA[i].y - centre.y, pA[i].x - centre.x);
			angle[i].id = i;

			if (angle[i].angle < 0)
			{
				angle[i].angle += 2 * 3.1415926;
			}
			//acutPrintf(_T("angle(id)-angle(r):%d,%f\n"), i,angle[i].angle);
		}

		//acutPrintf(_T("****************************\n"));


		std::sort(angle.begin(), angle.end(), [](const Ag& a, const Ag& b) {return a.angle > b.angle; });//按极角值降序


		AcGePoint2d pC[MAX];
		for (int i = 0; i < num; i++)
		{
			pC[i] = pA[angle[i].id];
			//acutPrintf(_T("angle-id:%d\n"), angle[i].id);
			//acutPrintf(_T("pC[i]:%g,%g\n"), pC[i].x, pC[i].y);
		}

		//acutPrintf(_T("****************************\n"));

		AcGePoint2d aa = pA[ci];
		for (int i = 0; i < num; i++)
		{
			if (pC[i]==aa)
			{
				//acutPrintf(_T("pA-pC[ci]:%g,%g\n"), pA[ci].x, pA[ci].y);
				ci = i;
			}
		}

		//acutPrintf(_T("ci-C:%d\n"), ci);
		//acutPrintf(_T("pC[ci]:%g,%g\n"), pC[ci].x,pC[ci].y);

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

		for (int i = 0; i < ci; i++)
		{
			pB[cB] = pC[i];
			cB++;
		}

		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)

三、西北角作为起点的思路

先找到横坐标最左边的横坐标值(即最小的横坐标值),后找到纵坐标最大的纵坐标值,以此作为该多段线外接矩形的左上角点,然后逐一计算多边形各顶点坐标到该外接矩形左上角点的距离,距离最近,即为多边形的西北角点。

四、顺时针排序的思路

将所有顶点坐标的X和Y值分别求和,然后平均,得几何中心点的坐标。然后使用atan2()函数,计算每个顶点到几何中心的极角,处理负值的极角(加2π)。处理后,按照极角大小倒序排列数组,就能得到按照顺时针排序的顶点坐标。

结合步骤三过程中,得到的起点坐标(西北角点),将起点及起点之后的数组,先输出排序,然后将起点之前的数组,放在上面排序的后面,进行排序处理。最后,就能得到按西北角顺时针排序的顶点坐标数组。

随后,再进行其他操作预算,就能得到稳定的输出多边形。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值