objectarx2023开发记录---边长修正(含边长标注和自由移动)

描述:该功能可保持多段线各条边方向不动的情况下,调整多段线的某一条边或某多条边为指定长度,用于修正图形。

根据提示,点选边,输入边指定长度,空格,即可得到修正后的图形。

注意:由于方向不变,某一条边的长度变化,这必然导致图形发生变化,故此,该功能只设计为垂直多边形可用,其末位点和首点之间的线段也属于垂直关系闭合。故此,其他用途图形不适应。

1、完整代码

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

#include "acedCmdNF.h"

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

const double EPS = 0.1;

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

public:
	CArxProject3_App() : 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() {
	}

	static void AAMyGroupZZ() {
		// Put your command code here

		std::vector<AcGePoint2d> pt;//存储多段线顶点坐标
		std::vector<AcGePoint2d> pick;//存储鼠标点击的位置
		AcDbPolyline* pL = new AcDbPolyline();
		int juget = 1;//用于判断循环是否结束
		double ds = 1.0;
		std::vector<double> dsInp;
		int num;//存储顶点坐标

		while (juget == 1)
		{
			ads_name ss;
			ads_point pickPt;
			int st = acedEntSel(_T("\n请选择线段:"), ss, pickPt);

			//acutPrintf(_T("st:%d\n"),st);

			if (st == RTNORM)
			{
				AcGePoint2d p = asPnt2d(pickPt);
				pick.push_back(p);

				AcDbObjectId obid;//临时值
				int len;
				acedSSLength(ss, &len);
				if (len == 0)
				{
					juget = 2;
					return;
				}

				if (acdbGetObjectId(obid, ss) == Acad::eOk)
				{
					AcDbEntity* pEnt;
					acdbOpenObject(pEnt, obid, AcDb::kForRead);

					AcDbPolyline* pl;
					pl = AcDbPolyline::cast(pEnt);

					pL = pl;

					//注记起始点
					AcGePoint2d pT;
					pL->getPointAt(0, pT);
					zhuJi(pT);

					num = pL->numVerts();

					pl->close();
					pEnt->close();
				}
				else
				{
					juget = 2;
					return;
				}


				int st2 = acedGetReal(_T("\n请输入边长:(10.0)"), &ds);
				//acutPrintf(_T("st2:%d\n"), st2);

				if (st2 == -5001)//无内容按下空格键时返回该值
				{
					//acutPrintf(_T("ds:%.5f\n"), ds);
					ds = 10.0;
					dsInp.push_back(ds);
				}
				else if (st2 == RTCAN)
				{
					juget = 2;
					return;
				}
				else if (st2 == RTNORM)
				{
					dsInp.push_back(ds);
				}
				else if (st2 == 5000)
				{
					ds = 10.0;
					dsInp.push_back(ds);
				}

			}
			else if (st == RTCAN)
			{
				juget = 2;
				return;
			}
			else if (st == -5001)//无内容按下空格键时返回该值
			{
				juget = 2;
			}
			else if (st == RTERROR)
			{
				juget = 2;
				return;
			}
			else
			{
				juget = 2;
				return;
			}

			acedSSFree(ss);

		}

		if (juget == 2 && num == 0)
		{
			acutPrintf(_T("退出,选择为空\n"));
			return;
		}


		num = pL->numVerts();
		std::vector<double> dis;//存储线段的长度
		std::vector<AcGeVector2d> v2d;//存储线段的向量

		for (int i = 0; i < num; i++)
		{
			AcGePoint2d p1;
			pL->getPointAt(i, p1);

			pt.push_back(p1);
		}
		pt.push_back(pt[0]);


		for (int i = 0; i < num; i++)
		{
			AcGePoint2d p1 = pt[i];
			AcGePoint2d p2 = pt[i + 1];

			double s = p1.distanceTo(p2);
			dis.push_back(s);

			AcGeVector2d v(p2 - p1);
			v2d.push_back(v);
		}

		std::vector<int> indexD;
		size_t num2 = pick.size();

		double S = 0; int countS = 0;
		for (double i : dis)
		{
			S += i; countS++;
		}

		S /= countS;

		double dk = S/100.0;

		if (dk < 0.5)
		{
			dk = 0.5;
		}

		acutPrintf(_T("dk:%g\n"), dk);

		for (int i = 0; i < num2; i++)
		{
			AcGePoint2d pk1(pick[i].x - dk, pick[i].y - dk);
			AcGePoint2d pk2(pick[i].x + dk, pick[i].y - dk);
			AcGePoint2d pk3(pick[i].x + dk, pick[i].y + dk);
			AcGePoint2d pk4(pick[i].x - dk, pick[i].y + dk);

			int index1 = 0; double d = 0;
			for (int j = 0; j < num; j++)
			{
				AcGePoint2d p1 = pt[j];
				AcGePoint2d p2 = pt[j + 1];

				int kk1 = KuaLi(pk1, pk2, p1, p2);
				int kk2 = KuaLi(pk1, pk4, p1, p2);
				int kk3 = KuaLi(pk3, pk2, p1, p2);
				int kk4 = KuaLi(pk3, pk4, p1, p2);

				if (kk1 == 1 || kk2 == 1 || kk3 == 1 || kk4 == 1)
				{
					//acutPrintf(_T("跨立%d\n"),j);
					index1 = j;
				}

				int b = isOnLine(p1, p2, pick[i]);
				if (b == 1)
				{
					//acutPrintf(_T("线上%d\n"), j);
					index1 = j;
				}

			}

			indexD.push_back(index1);
			//acutPrintf(_T("indexD[%d]-:%d\n"),i,index1);

		}

		size_t num3 = dsInp.size();
		size_t num4 = indexD.size();

		if (num4 == num3)
		{
			//acutPrintf(_T("进入循环,num3=num4=%d\n"), num3);
			for (int i = 0; i < num3; i++)
			{
				int k = indexD[i];
				//acutPrintf(_T("dis[k]-:%.5f\n"), dis[k]);
				dis[k] = dsInp[i];
				//acutPrintf(_T("dis[k]:%.5f\n"), dis[k]);
			}
		}
		else
		{
			//acutPrintf(_T("num3:%d\n"), num3);
			//acutPrintf(_T("num4:%d\n"), num4);
			acutPrintf(_T("退出,未检测到边\n"));
			return;
		}

		for (int i = 0; i < num - 1; i++)
		{
			AcGeVector2d v = v2d[i].normalize();
			pt[i + 1] = pt[i] + v * dis[i];
		}
//-----------------------------------------------------------
		AcGePoint2d p1 = pt[num - 2];
		AcGePoint2d p2 = pt[num - 1];
		AcGePoint2d p3 = pt[0];

		AcGeLine2d l12(p1, p2);

		AcGePointOnCurve2d p_2d;
		l12.getClosestPointTo(p3, p_2d);

		AcGePoint2d ppt = p_2d.point2d();

		pt[num - 1] = ppt;

//-------------------------------------------
		ads_point getP;
		AcGePoint2d pmove;//目标点
		int zhuangtai = acedGetPoint(NULL, _T("\n请选择绘制点:"), getP);

		if (zhuangtai == RTNORM)
		{
			pmove = asPnt2d(getP);//ads_point转AcGePoint2d
		}
		else
		{
			acutPrintf(_T("已取消\n"));
			return;
		}

//----------------------------------------------------
		AcDbPolyline* pline = new AcDbPolyline();
		int indexPline = 0;

		for (int i = 0; i < num; i++)
		{
			pline->addVertexAt(indexPline, pt[i]);
			indexPline++;
		}

		AcDbObjectId lineId;
		Setblocktable(pline, lineId);

		pline->setClosed(true);

		pL->close();
		pline->close();

//--------------------------------------------

		ads_name ss;
		acedSSAdd(NULL, NULL, ss);

		ads_name entres;
		acdbGetAdsName(entres, lineId);
		acedSSAdd(entres, ss, ss);

		AcGePoint2d pstart=pt[0];

		acedCommandS(RTSTR, _T("MOVE"), RTPICKS, ss, RTSTR, _T(""), RTPOINT ,pstart, RTPOINT, pmove, RTNONE);

		acedSSFree(entres);
		acedSSFree(ss);
//----------------------------------------------
		std::vector<AcGePoint2d> pt1;
		for (int i = 0; i < num; i++)
		{
			AcGePoint2d p1;
			pline->getPointAt(i, p1);

			pt1.push_back(p1);
		}
		pt1.push_back(pt1[0]);

		std::vector<CString> cs;
		std::vector<AcGePoint2d> pc;
		std::vector<double> angle;

		BiaoJi(cs, pc, angle, pt1, num);
		setWenzi(cs, pc, angle);

		pline->close();
		//end
	}

	static void zhuJi(AcGePoint2d pT)
	{
		AcDbText* pText = new AcDbText();
		AcGePoint3d p3d(pT.x, pT.y, 0);
		CString cst;
		cst.Format(_T("%d"), 1);
		pText->setTextString(cst);
		pText->setPosition(p3d);
		pText->setHeight(0.5);
		pText->setColorIndex(1);

		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();

	}

	static void BiaoJi(std::vector<CString>& dis,
		std::vector<AcGePoint2d>& positionC, std::vector<double>& angle,
		std::vector<AcGePoint2d> pt, int num)
	{
		//有向面积法,正-逆时针,负-顺时针
		double A = 0;
		for (int i = 0; i < num - 1; i++)
		{
			A += pt[i].x * pt[i + 1].y - pt[i + 1].x * pt[i].y;
		}


		for (int i = 0; i < num - 1; i++)
		{
			//获取每条边的极角值(弧度值)
			double angle1;
			double pi = 4 * atan(1);
			angle1 = atan2(pt[i + 1].y - pt[i].y, pt[i + 1].x - pt[i].x);
			if (angle1 < 0)
			{
				angle1 += 2 * pi;
			}

			int bb = 0, cc = 0, dd = 0;
			if (angle1 > pi / 2 && angle1 <= 1.5 * pi)
			{
				bb = 1;
			}
			if (angle1 > 2 * pi)
			{
				cc = 1;
			}

			if (cc == 1 || bb == 1)
			{
				dd = 1;
			}

			//处理文字方向
			while (dd == 1)
			{
				if (angle1 > pi / 2 && angle1 <= 1.5 * pi)
				{
					angle1 += pi;
					bb = 1;
				}
				else
				{
					bb = 0;
				}

				if (angle1 > 2 * pi)
				{
					angle1 -= 2 * pi;
					cc = 1;
				}
				else
				{
					cc = 0;
				}

				if (bb == 1 || cc == 1)
				{
					dd = 1;
				}
				else
				{
					dd = 0;
				}
			}
			angle.push_back(angle1);


			//计算距离值
			double d = pt[i].distanceTo(pt[i + 1]);
			CString a;
			a.Format(_T("%.4f"), d);
			dis.push_back(a);

			//计算插入点位置
			double x1, y1;
			x1 = pt[i].x + pt[i + 1].x;
			y1 = pt[i].y + pt[i + 1].y;

			AcGeVector2d v = pt[i + 1] - pt[i];
			AcGeVector2d v2 = v.normalize();

			x1 /= 2;
			y1 /= 2;

			AcGePoint2d pc(x1, y1);//线段中点坐标
			AcGePoint2d pz = pc + v2 * 0.2;//距离中点0.5米沿线段方向的坐标
			AcGePoint2d pE;

			if (A > 0)
			{
				//逆时针旋转90度
				AcGeVector2d vc1 = pz - pc;
				AcGeVector2d vc12(-vc1.y, vc1.x);
				pE = pc + vc12;
			}

			if (A < 0)
			{
				//顺时针旋转90度
				AcGeVector2d vc1 = pz - pc;
				AcGeVector2d vc12(vc1.y, -vc1.x);
				pE = pc + vc12;
			}

			positionC.push_back(pE);
		}
	}

	static void setWenzi(std::vector<CString> s, std::vector<AcGePoint2d> position, std::vector<double> rotation)
	{
		//获取文字样式表
		AcDbTextStyleTable* pTextStyleTab;
		acdbHostApplicationServices()->workingDatabase()
			->getTextStyleTable(pTextStyleTab, AcDb::kForWrite);

		//simsun.ttc(宋体的字体文件名称)
		AcDbTextStyleTableRecord* pTextStyleTabRcd;
		pTextStyleTabRcd = new AcDbTextStyleTableRecord();

		//获取宋体字样
		pTextStyleTab->getAt(_T("宋体"), pTextStyleTabRcd, AcDb::kForRead);

		//设置新的字体名称并关联字体文件(需放在CAD字体文件夹目录下)
		//pTextStyleTabRcd->setName(_T("宋体 常规"));//字体显示名称
		//pTextStyleTabRcd->setFileName(_T("simsun.ttc"));//字体文件名称,打开控制面板,打开字体文件夹,右键字体属性查看

		//添加到样式表
		pTextStyleTab->add(pTextStyleTabRcd);

		//获取对象ID
		AcDbObjectId styleId = pTextStyleTabRcd->objectId();

		//释放指针,不然实体无法删除等操作
		pTextStyleTabRcd->close();
		pTextStyleTab->close();

		//添加到块表中
		AcDbBlockTable* pBT;
		acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBT, AcDb::kForRead);
		AcDbBlockTableRecord* pBTR;
		pBT->getAt(ACDB_MODEL_SPACE, pBTR, AcDb::kForWrite);

		size_t cc = s.size();
		for (int i = 0; i < cc; i++)
		{
			AcDbText* ptr = new AcDbText();
			CString str = s[i];

			double height = 0.3;

			AcGePoint3d position1(position[i].x, position[i].y, 0);

			double rotation1 = rotation[i];

			ptr->setTextString(str);
			ptr->setHeight(height);
			ptr->setRotation(rotation1);

			//关联宋体样式
			ptr->setTextStyle(styleId);

			//对正模式设置--正中
			ptr->setHorizontalMode(AcDb::kTextMid);
			ptr->setVerticalMode(AcDb::kTextVertMid);

			ptr->setAlignmentPoint(position1);//设置对正模式时,需使用此函数插入点,setpositin()函数无效

			pBTR->appendAcDbEntity(ptr);
			ptr->close();
		}

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

	}

	static int KuaLi(AcGePoint2d pa, AcGePoint2d pb, AcGePoint2d pc, AcGePoint2d pd)
	{
		AcGeVector2d vab = pb - pa;
		AcGeVector2d vcd = pd - pc;

		AcGeVector2d v1 = pc - pa;
		AcGeVector2d v2 = pd - pa;
		AcGeVector2d v3 = pa - pc;
		AcGeVector2d v4 = pb - pc;

		double cross1 = Cross(v1, vab);
		double cross2 = Cross(v2, vab);
		double cross3 = Cross(v3, vcd);
		double cross4 = Cross(v4, vcd);

		//说明两线段存在线中相交,交点不在端点上,在线段两端点间
		if (((cross1 * cross2) < 0) && ((cross3 * cross4) < 0))
		{
			return 1;//跨立相交
		}
		else
		{
			return 0;//不存在跨立相交
		}

	}

	//向量叉积的结果
	static double Cross(AcGeVector2d v1, AcGeVector2d v2)
	{
		return v1.x * v2.y - v1.y * v2.x;
	}


	//判断点是否在线上(含端点)
	static int isOnLine(AcGePoint2d pa, AcGePoint2d pb, AcGePoint2d pt1)
	{
		int a = 0, b = 0, c = 0;
		AcGeVector2d v1 = pb - pa;
		AcGeVector2d v2 = pt1 - pa;

		double cross = Cross(v1, v2);

		double Xmin_ab = 0, Xmax_ab = 0, Ymin_ab = 0, Ymax_ab = 0;

		Xmin_ab = min(pa.x, pb.x);
		Xmax_ab = max(pa.x, pb.x);
		Ymin_ab = min(pa.y, pb.y);
		Ymax_ab = max(pa.y, pb.y);

		if (fabs(cross) < 1e-5)//叉乘结果为0,则表示3点共线
		{
			if (pt1.x >= Xmin_ab && pt1.x <= Xmax_ab)//判断是否在线段上,而不是线段的延长线上
			{
				if (pt1.y >= Ymin_ab && pt1.y <= Ymax_ab)
				{
					a = 1;//点在线上(含端点)
				}
			}
		}

		//考虑到计算容差问题,补充线段上两个端点与目标点重合的判断逻辑
		if (fabs(pt1.x - pa.x) < EPS && fabs(pt1.y - pa.y) < EPS)
		{
			//目标点与端点a重合
			b = 1;
		}

		if (fabs(pt1.x - pb.x) < EPS && fabs(pt1.y - pb.y) < EPS)
		{
			//目标点与端点b重合
			c = 1;
		}

		if (a == 1 || b == 1 || c == 1)
		{
			return 1;//该点位于线段上
		}
		else
		{
			return 2;//该点不在线段上
		}

	}

	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);//模型空间就是一个块表记录

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

		pBlockTable->close();

		pBlockTableRecord->close();
	}

	// Modal Command with pickfirst selection
	// ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject3_App, AAMyGroup, MyPickFirst, MyPickFirstLocal, ACRX_CMD_MODAL | ACRX_CMD_USEPICKSET)
	static void AAMyGroupMyPickFirst() {
		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
		}
	}

	// Application Session Command with localized name
	// ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject3_App, AAMyGroup, MySessionCmd, MySessionCmdLocal, ACRX_CMD_MODAL | ACRX_CMD_SESSION)
	static void AAMyGroupMySessionCmd() {
		// Put your command code here
	}

	static int ads_MyLispFunction() {
		//struct resbuf *args =acedGetArgs () ;

		// Put your command code here

		//acutRelRb (args) ;

		// Return a value to the AutoCAD Lisp Interpreter
		// acedRetNil, acedRetT, acedRetVoid, acedRetInt, acedRetReal, acedRetStr, acedRetPoint, acedRetName, acedRetList, acedRetVal

		return (RTNORM);
	}

};

//-----------------------------------------------------------------------------
IMPLEMENT_ARX_ENTRYPOINT(CArxProject3_App)

ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject3_App, AAMyGroup, ZZ, ZZ, ACRX_CMD_MODAL, NULL)
ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject3_App, AAMyGroup, MyPickFirst, MyPickFirstLocal, ACRX_CMD_MODAL | ACRX_CMD_USEPICKSET, NULL)
ACED_ARXCOMMAND_ENTRY_AUTO(CArxProject3_App, AAMyGroup, MySessionCmd, MySessionCmdLocal, ACRX_CMD_MODAL | ACRX_CMD_SESSION, NULL)
ACED_ADSSYMBOL_ENTRY_AUTO(CArxProject3_App, MyLispFunction, false)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值