找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1695|回复: 14

[求助]:求多边形形心坐标的算法

[复制链接]
发表于 2003-5-22 21:45:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
求多边形形心坐标的算法。已知一组坐标点(多边形的顶点),
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 145个

财富等级: 日进斗金

发表于 2003-5-22 21:54:16 | 显示全部楼层

Re: [求助]:求多边形形心坐标的算法

最初由 xb4270293 发布
[B]求多边形形心坐标的算法。已知一组坐标点(多边形的顶点), [/B]


你可以利用ARX对象库完成.

根据顶点表,先得到AcDbPolyline 的临时内存实体对象, 然后转换成AcDbRegion临时实体对象,然后利用

  1. <normalfont>
  2. AcDbRegion::getAreaProp Function virtual Acad::ErrorStatus

  3. getAreaProp(

  4. const AcGePoint3d& origin,

  5. const AcGeVector3d& xAxis,

  6. const AcGeVector3d& yAxis,

  7. double& perimeter,

  8. double& area,

  9. AcGePoint2d& centroid,

  10. double momInertia[2],

  11. double& prodInertia,

  12. double prinMoments[2],

  13. AcGeVector2d prinAxes[2],

  14. double radiiGyration[2],

  15. AcGePoint2d& extentsLow,

  16. AcGePoint2d& extentsHigh) const;

  17. origin Input origin of the region
  18. xAxis Input X axis of the region
  19. yAxis Input Y axis of the region
  20. perimeter Returns perimeter of the region
  21. area Returns area of the region
  22. centroid Returns centroid of the region
  23. momInertia[2] Returns moment of inertia of the region
  24. prodInertia Returns product of inertia of the region
  25. prinMoments[2] Returns principal moments of the region
  26. prinAxes[2] Returns principle axes of the region
  27. radiiGyration[2] Returns radii of gyration of the region
  28. extentsLow Returns minimum extents point of the region
  29. extentsHigh Returns maximum extents point of the region

  30. This function calculates the area properties of the region. All the values
  31. are in the World Coordinate System (WCS). The function validates the
  32. origin, xAxis, and yAxis parameters to ensure that the axes are of unit
  33. length and are perpendicular to each other, and that the axes and the
  34. origin lie in the same plane as the region.

  35. Returns Acad::eOk if successful.

  36. If there is an error in the ACIS modeler, then Acad::eGeneralModelingFailure is returned.

  37. </normalfont>


最后别忘了delete 临时的实体对象.
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2003-5-24 00:27:20 | 显示全部楼层
按照XD的方法,写了一个函数如下:
//计算多边形的形心坐标
BOOL GetPolyCentroid(AcDbPolyline * pPline, AcGePoint2d centroid)
{
        AcDbRegion * pRegion = new AcDbRegion();

        AcDbVoidPtrArray Segments, regions;
        AcGePoint3d LinePt0, LinePt1;
        AcGePoint3d origin;
        AcGeVector3d xAxis, yAxis;
        double perimeter, area, prodInertia;
        double momInertia[2], prinMoments[2], radiiGyration[2];
        AcGeVector2d prinAxes[2];
        AcGePoint2d extentsLow, extentsHigh;
       
        Segments.append(pPline);

        if (pRegion->createFromCurves(Segments,        regions) != Acad::eOk){
                ads_printf("\n创建临时区域对象失败!");
                delete pRegion;
                return FALSE;
        }
        if (pRegion->getAreaProp(
                origin, xAxis, yAxis,
                perimeter, area, centroid, momInertia, prodInertia, prinMoments, prinAxes, radiiGyration,
                extentsLow, extentsHigh) != Acad::eOk){
                ads_printf("\n获取区域对象属性失败!");
                delete pRegion;
                return FALSE;
        }
        ads_printf("\n区域面积: %.3f, 周长:%.3f, 形心:X=%.3f, Y=%.3f", area, perimeter, centroid.x, centroid.y);
        delete pRegion;
        return TRUE;
}

运行结果显示:"面积:0.000,  周长:0.000, 形心:X=0.000, Y=0.000"

后将折线分解为直线段:
        for (unsigned int i = 0; i < pPline->numVerts() - 1; i++){
                pPline->getPointAt(i, LinePt0);
                pPline->getPointAt(i + 1, LinePt1);
                AcDbLine * pLine = new AcDbLine(LinePt0, LinePt1);
                Segments.append(pLine);
        }
依然无法得到正确结果。望得到大家的帮助。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 145个

财富等级: 日进斗金

发表于 2003-5-24 07:55:38 | 显示全部楼层
最初由 xb4270293 发布
[B]按照XD的方法,写了一个函数如下:
//计算多边形的形心坐标
BOOL GetPolyCentroid(AcDbPolyline * pPline, AcGePoint2d centroid)
{
        AcDbRegion * pRegion = new AcDbRegion();

        AcDbVoidPtrArray Segments,... [/B]


POLYLINE或者最后分解的LINE组,是否闭合? 多义线是否是闭合的AcDbPolyline?

你试着用region 命令,看看是否能把你的这些LINE变成REGION.
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2003-5-24 10:41:24 | 显示全部楼层
最初由 xb4270293 发布
[B]按照XD的方法,写了一个函数如下:
//计算多边形的形心坐标
BOOL GetPolyCentroid(AcDbPolyline * pPline, AcGePoint2d centroid)
{
    AcDbRegion * pRegion = new AcDbRegion();
    //...
    if (pRegion->createFromCurves(Segments, regions) != Acad::eOk){
[/B]

  1. static Acad::ErrorStatus createFromCurves(
  2.                                          const AcDbVoidPtrArray& curveSegments,
  3.                                          AcDbVoidPtrArray& regions);
复制代码

createFromCurves得到的Region在regions里,而且它还是一个Class Static 函数. 你的用法错误
用法示例:
  1. // Function name        : Curves2Region
  2. // Description        : 曲线(选择集)转AcDbRegion
  3. // Return type        : AcDbRegion*  
  4. // Argument                       : ads_name ssCurves
  5. AcDbRegion* Curves2Region(ads_name ssCurves)
  6. {
  7.         long ssLen,i,j;
  8.        
  9.         AcDbVoidPtrArray regions;

  10.         if (RTNORM!=acedSSLength(ssCurves,&ssLen))
  11.         {
  12.                 acedPrompt("\nSSLength Error!\n");
  13.                 return NULL;
  14.         }
  15.        
  16.         if (ssLen < 1)
  17.         {
  18.                 acedPrompt("\n未选中任何实体!\n");
  19.                 return NULL;
  20.         }

  21.         Acad::ErrorStatus es;
  22.         AcDbVoidPtrArray curveSegments;
  23.        
  24.         ads_name rtEnt;//选中实体
  25.         AcDbCurve *pCurve = NULL;
  26.         AcDbObjectId ObjId;

  27.         for(i = 0; i < ssLen; i++){
  28.                 acedSSName(ssCurves,i,rtEnt);
  29.                 acdbGetObjectId(ObjId,rtEnt);
  30.                 if (acdbOpenObject(pCurve,ObjId,AcDb::kForRead) != Acad::eOk)
  31.                 {//无法打开
  32.                         acdbFail("\n无法打开!");
  33.                         for(j = 0; j < i; j++){
  34.                                 ((AcDbCurve *)curveSegments[j])->close();
  35.                         }
  36.                         return NULL;
  37.                 }else
  38.                         curveSegments.append(pCurve);
  39.         }
  40.        
  41.         [color=blue]es=AcDbRegion::createFromCurves(curveSegments,regions);[/color]

  42.         for(j = 0; j < curveSegments.length(); j++)
  43.                         ((AcDbCurve *)curveSegments[j])->close();

  44.         int nCount = regions.length();

  45.         if (es == Acad::eOk)
  46.         {
  47.                 if ( nCount == 1)
  48.                         [color=blue]return ((AcDbRegion *)regions[0]);[/color]
  49.                 else
  50.                 {
  51.                         // 多个 AcDbRegion , 无法确定应该返回哪一个,干脆返回NULL;
  52.                         for(int i = 0; i < nCount; i++)
  53.                         {
  54.                                 delete (AcDbRegion *)regions[i];
  55.                         }
  56.                         return NULL;
  57.                 }
  58.         }
  59.         else
  60.         {
  61.                 // 删除在错误发生之前生成的 AcDbRegion
  62.                 for(int i = 0; i < nCount; i++)
  63.                 {
  64.                         delete (AcDbRegion *)regions[i];
  65.                 }
  66.                 return NULL;
  67.         }
  68. }
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2003-5-24 14:38:47 | 显示全部楼层
感谢大家的帮助,程序基本调通,现将程序写给大家,请提意见:
//计算多边形的形心坐标
BOOL GetPolyCentroid(AcDbPolyline * pPline, ads_point CenPt)
{
        unsigned int i, iCount = 0;
        AcDbVoidPtrArray curveSegments, regions;
        AcGePoint3d LinePt0, LinePt1;
        AcGePoint3d origin;
        AcGeVector3d xAxis, yAxis;
        double perimeter, area, prodInertia;
        double momInertia[2], prinMoments[2], radiiGyration[2];
        AcGePoint2d centroid;
        AcGeVector2d prinAxes[2];
        AcGePoint2d extentsLow, extentsHigh;
       
        if (pPline->isClosed() != Adesk::kTrue)        {
                ads_printf("\n折线不封闭, 无法形成正确的区域。");
                return FALSE;
        }
        curveSegments.append((AcDbCurve *) pPline);

        if (AcDbRegion::createFromCurves(curveSegments, regions) != Acad::eOk){
                ads_printf("\n创建临时区域对象失败!");
//清除Region, 应第9 贴的指点,即使createFromCurves错误,也应清除之;
iCount = regions.length();
for(i = 0; i < iCount; i++)
                        delete (AcDbRegion *)regions.at(i);

                return FALSE;
        }
        AcDbRegion * pRegion;
        if ((iCount = regions.length()) == 0){
                ads_printf("\n创建临时区域对象为空!");
                return FALSE;
        }
        if (iCount  > 1){
                // 多个 AcDbRegion , 无法确定应该返回哪一个,干脆返回NULL;
                ads_printf("\n多个区域实体。");
                for(i = 0; i < iCount; i++)
                        delete (AcDbRegion *)regions.at(i);
                return FALSE;
        }
        pRegion = (AcDbRegion *) regions.at(0);

        origin.set(0,0,0); //设置原点坐标
        xAxis.set(1,0,0);  //设置X Y轴,
        yAxis.set(0,1,0);
       
        if (pRegion->getAreaProp(
                origin, xAxis, yAxis,
                perimeter, area, centroid, momInertia, prodInertia, prinMoments, prinAxes, radiiGyration,
                extentsLow, extentsHigh) !=  Acad::eOk ){
                ads_printf("\n区域面积: %.3f, 周长:%.3f", area, perimeter);
                ads_printf("\n获取区域对象属性失败!");
                delete pRegion;
                return FALSE;
        }
        XYZ_POINT(CenPt, centroid.x, centroid.y, 0);  //得到形心坐标
        ads_printf("\n区域面积: %.3f, 周长:%.3f", area, perimeter);
        pRegion->close();
        delete pRegion;

        return TRUE;
}//清除Region, 应第9 贴的指点,即使createFromCurves错误,也应清除之;[/COLOR]
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 145个

财富等级: 日进斗金

发表于 2003-5-24 14:43:26 | 显示全部楼层
最初由 xb4270293 发布
[B]感谢大家的帮助,程序基本调通,现将程序写给大家,请提意见:
//计算多边形的形心坐标
BOOL GetPolyCentroid(AcDbPolyline * pPline, ads_point CenPt)
{
        unsigned int i, iCount = 0;
        AcDbVoidPtrArray cur... [/B]


你说下最初的问题主要出在哪里吧, 这样大家以后印象能深刻些.谢谢!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2003-5-24 15:16:20 | 显示全部楼层
前面定义折线或拆分为直线,都是可行的,当然折线必须封闭,因此有一个isClosed的判断;

问题1:使用AcDbRegion::createFromCurves(curveSegments, regions) ;得到regions实体组;
而不是使用pRegion->createFromCurves(curveSegments, regions) ;得到pRegion实体;
得到regions实体组后,实际上可能得到多个区域,例如:当折线为8字形,则会得到两个区域。

问题2:使用getAreaProp函数获取区域的属性前,应定义:原点、XY轴,这些数据用于计算惯性矩等参数使用,由于我的程序仅需要形心的坐标,因此,简单作了如下定义:
origin.set(0,0,0); //设置原点坐标
xAxis.set(1,0,0); //设置X Y轴,
yAxis.set(0,1,0);
最后别忘了delete pRegion;
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2003-5-24 21:49:16 | 显示全部楼层
AcDbRegion::createFromCurves(curveSegments, regions) 还有一种可能需要注意,即生成n个Region后在生成第n+1个Region时出错,它并不会清理(delete)前面已经生成的Region。
所以你的这部分代码并不干净
  1. if (AcDbRegion::createFromCurves(curveSegments, regions) != Acad::eOk){
  2. ads_printf("\n创建临时区域对象失败!");
  3. // 需要清理Regions
  4. return FALSE;
  5. }
复制代码
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2003-11-14 09:32:11 | 显示全部楼层
可否把XYZ_POINT(CenPt, centroid.x, centroid.y, 0); //得到形心坐标函数贴上来
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2003-11-15 11:21:16 | 显示全部楼层
是呀!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2004-8-8 17:41:35 | 显示全部楼层
我有N组多边形要优选,如果都这么一个个先画出来再求最后删掉那不是效率很低?哪位朋友有数学求法的源代码么?

[iframe h=600]http://www.ccea.zju.edu.cn/htms/yanjiushenghui/BBS/showtopic.asp?TOPIC_ID=20&Forum_ID=53[/iframe]
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2006-6-3 15:26:44 | 显示全部楼层
太复杂,看了半天还没有明白!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2006-6-4 12:20:33 | 显示全部楼层
提出一个问题, 如果 给定的点组成的是 凹多边形, 你计算的形心 一定在这个面里面吗,我记得我试验过,会生成在图形的外部。(我用一个专门的GIS开发包 (ESRI),他就提供了一个能肯定能在面里的函数,当图形的形心在面里面就用这个点。当这个点落到图形外面的时候,就采用另外一种算法将他移动到图形里面,但是视觉上感觉也是 一个比较接近中心的点。

还有,我个人感觉使用 Region 速度会比较慢,特别是数据量很大的时候,譬如如果我有 100000个封闭的多边形需要计算,速度大致能多少呢。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2006-6-4 19:37:29 | 显示全部楼层
俺是新手、、来学习学习、支持一下楼主@!!谢了
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-6-10 03:11 , Processed in 0.500083 second(s), 60 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表