【问题标题】:Polygon splitted by 4 parts多边形分成 4 部分
【发布时间】:2014-08-05 05:43:46
【问题描述】:

我有一个任意的凸多边形。它被两条垂直线分割(它们的向量是(0,1)和(1,0))。是否有任何算法可以通过较小的数字(S1、S2、S3、S4)计算面积。我所能做的就是计算线穿过多边形的点,然后计算面积,但有没有更好的优化?

我将所有顶点存储在数组double **v; 然后我计算所有点,我的多边形穿过 X 和 Y 轴:

void cross() {       //calculates buf (crossing with Y)
    act = 0;
    for (int i = 0; i < n; ++i) {
        buf[act][0]=v[i][0];
        buf[act][1]=v[i][1];
        act++;
        if (v[i][0]*v[(i+1)%n][0] < 0) {
            buf[act][0] = 0;
            buf[act][1] = v[i][1] + std::abs(v[i][0])*(v[(i+1)%n][1]-v[i][1])/(std::abs(v[i][0])+std::abs(v[(i+1)%n][0]));
        act++;
        }
    }

}

void vert() {      /calculates buf2 (crossing with X)
    act2 =0;
    for (int i = 0; i < act; ++i) {
        buf2[act2][0]=buf[i][0];
        buf2[act2][1]=buf[i][1];
        act2++;
        if (buf[i][1]*buf[(i+1)%act][1] < 0) {
            buf2[act2][1] = 0;
            buf2[act2][0] = buf[i][0] + std::abs(buf[i][1])*(buf[(i+1)%act][0] - buf[i][0])/ (std::abs(buf[i][1])+std::abs(buf[(i+1)%act][1]));
            act2++;

        }

    }
}

调用cross()后;顶点()​​;我得到一个数组 buf2 和 act2 的元素数量; 在此之后,我正在对多边形进行三角剖分并检测在什么小队中进行了训练。

 double s_trian (double a, double b, double c, double d) { 
//area of triangle
double s =0;
s=0.5*std::abs((a)*(d)-(c)*(b));
return s;
} 
void triang() {  //calculate areas of s1,s2,s3,s4 by  
                 //triangulating
bool rotation;
double temror;
s1=0, s2 =0, s3 =0, s4 =0;
int a,b;
for (int i =0; i < act2; ++i) {
 a=i%act2;
 b=(i+1)%act2;
 temror = s_trian(buf2[a][0], buf2[a][1], buf2[b][0], buf2[b][1]);
 if ((buf2[a][0]+buf2[b][0]) > 0) {
     if((buf2[a][1]+buf2[b][1] > 0)) 
         s1+=temror;
     else
         s4+=temror;
 } else {
      if ((buf2[a][1]+buf2[b][1] > 0))  
         s2+=temror;
      else
         s3+=temror;
  }

}
}

我可以在这里优化一些东西吗?

【问题讨论】:

  • 我不知道你怎么能做得更好,尽管如果你有三个较小数字的面积和整体,你可以取不同的面积来获得最后一个象限的面积。
  • 实际上,再想一想 - 如果所有三角形都由边和原点组成,那么计算面积如何?在边与轴相交的地方,计算两个部分并分配给右侧四边形。
  • 这个问题比较适合math.stackexchange.com

标签: algorithm geometry


【解决方案1】:

鉴于您的多边形是凸的,只需在多边形内选择任意点 P 并将其拆分为三角形,其中一个角在 P 中。

然后计算每个三角形的面积:http://www.mathopenref.com/heronsformula.html 并求和。

【讨论】:

  • 我不需要多边形的多边形,我想按四分之一计算面积
  • 然后将“P”放在 origo 中,并将穿过轴的每条线分成两条线。 :-)
【解决方案2】:

你可以做得更好。

首先忽略 X。

水平投影 Y 上的每个顶点。这样,您可以定义梯形。这些梯形的代数面积之和给出了总面积。在单独的累加器中添加正面积和负面积,这将为您提供 Y 两侧的面积。但有些梯形会穿过 Y 并倾斜:计算两个三角形的面积并在适当的地方累加。

现在要处理水平轴,类似地,您会将贡献添加到正/负累加器,或同时添加到两者。

总共将有四个累加器,用于所有标志组合,为您提供四个请求的区域。

此过程将花费您每边多一点的积累,而不是四次。它可以在一个循环中完成,无需计算和存储四个子多边形。

【讨论】:

    【解决方案3】:

    [跟进我昨天的评论;与 Dan Bystrom 的回答有很多共同点。]

    遍历所有边,并计算由边和原点组成的三角形的面积。添加到适当的四边形区域。在边与轴相交的地方,计算截距并分割三角形。计算两个三角形区域部分并将每个部分添加到适当的四边形中。

    使用原点作为三角形顶点的点,使得基于叉积的三角形区域公式非常快速和简单。如果您注意以正确的顺序传递参数,您甚至不需要调用fabs()

    此代码未处理顶点位于轴上的问题或给定象限中没有点的情况。

    struct Point
    {
        double x;
        double y;
    };
    
    double areaOfTriangle(double ax, double ay, double bx, double by)
    {
        return fabs(by*ax - bx *ay)/2;
    }
    
    unsigned getQuad(double x, double y)
    {
        int xPos = (x > 0) ? 0 : 1;
        int yPos = (y > 0) ? 0 : 1 ;
        int quad = xPos + yPos;
        if (!xPos && yPos)
            quad = 3;
        return quad;
    
    }
    
    Point getIntercept(const Point& a, const Point& b)
    {
        Point intercept;
        if ( (a.x * b.x) < 0)
        {
            // Crosses y axis.
            intercept.x = 0;
            intercept.y = a.y - (b.y - a.y) / (b.x - a.x)*a.x;
        }
        else
        {   
            // Crosses x axis.
            intercept.y = 0;
            intercept.x = a.x - (b.x - a.x) / (b.y - a.y)*a.y;
        }
        return intercept;
    }
    
    void getAreaOfQuads(double* retQuadArea, const Point* points, unsigned numPts)
    {
        for (unsigned i = 0; i != 4; ++i)
            retQuadArea[i] = 0;
        const Point* a = &points[numPts - 1];
        unsigned quadA = getQuad(a->x, a->y);
        for (unsigned i = 0; i != numPts; ++i)
        {
    
    
            const Point* b = &points[i];
            unsigned quadB = getQuad(b->x, b->y);
            if (quadA == quadB)
            {
                retQuadArea[quadA] += areaOfTriangle(a->x, a->y, b->x, b->y);
            }
            else
            {
                // The side a->b crosses an axis.
                // First, find out where.
                Point c = getIntercept(*a, *b);
                retQuadArea[quadA] += areaOfTriangle(a->x, a->y, c.x, c.y);
                retQuadArea[quadB] += areaOfTriangle(c.x, c.y, b->x, b->y);
            }
            a = b;
            quadA = quadB;
        }
    }
    
    void test(Point* polygon, unsigned n)
    {
        double areas[4] = {};
        getAreaOfQuads(areas, polygon, n);
        for (unsigned i = 0; i != 4; ++i)
            std::cout << areas[i] << ",  ";
        std::cout << std::endl;
    }
    
    Point polygon[]
    {
        {0.6, 0.2},
        { 0.2, 0.8 },
        { -0.2, 0.7 },
        { -0.6, 0.6 },
        { -1.0, 0.1 },
        { -0.6, -0.5 },
        { 0.1, -0.5 },
        { 0.9, -0.1 }
    
    };
    Point square[]
    {
        {1, 1},
        { -1, 1 },
        { -1, -1 },
        { 1, -1 }
    
    };
    
    int main()
    {
        test(square, 4);
        test(polygon, 8);
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-02-08
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 2011-05-09
      • 2020-11-02
      • 1970-01-01
      • 2023-04-08
      相关资源
      最近更新 更多