我有一个任意凸多边形。并且它由2条垂直线分开(它们的矢量是(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()后; VERT();我得到一个数组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;
}
}
}
我可以在这里优化一下吗?
答案 0 :(得分:1)
你可以做得更好。
首先忽略X.
水平投影Y上的每个顶点。这样,您可以定义梯形。这些梯形的代数区域的总和给出了总表面。在单独的累加器中添加正面和负面区域,这将为您提供Y两侧的区域。但是一些梯形将穿过Y并且倾斜:计算两个三角形的面积并在适当的位置累积。
现在要处理水平轴,类似地,您将贡献添加到正/负累加器,或两者。
对于所有符号组合,总共会有四个累加器,为您提供四个请求区域。
这个程序每次会花费你多于一次积累,而不是四次。它可以在一个循环中完成,无需计算和存储四个子多边形。
答案 1 :(得分:1)
假设您的多边形是凸的,只需选择多边形内的任意点P,然后将其拆分为三角形,其中一个角位于P中。
然后计算每个三角形的面积:http://www.mathopenref.com/heronsformula.html并总结它们。
答案 2 :(得分:1)
[跟我昨天的评论;与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;
}