给定矩形的一边计算其他边

时间:2018-03-28 20:21:47

标签: c++ geometry

我正在努力解决一个我认为应该很容易解决的问题:

我给出了两个点x1,x2和一个宽度值。如何计算与x1和x2平行的另外两个点,使其形成一个矩形?

我在这里12尝试了答案。虽然两种解决方案都没有。

作为背景:这是关于将图像投影到真实世界坐标中。因此,我需要找到I&#m; m提供的平行线,以便两条线的点都创建一个矩形。我不想自己申请轮换。

这是一张显示我想要实现的目标的图: enter image description here

在示例中,您可以看到x1,x2和宽度I' m。我正在寻找x3和x4,以便这些点形成一个矩形。

如果可能,我正在寻找C ++实现。

1 https://gamedev.stackexchange.com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilted-rectangle

2 Calculating vertices of a rotated rectangle

这是我实施的代码。正如您所看到的,我使用了我提供的右上角和左上角坐标。但我宁愿找到与提供的点平行的线:

   double distance = 77.5;//[self normalizedDistanceWithCRS:crs p1:topLeft p2:topRight];

    // calculate the rotated coordinates for bottom right and bottom left with provided height
    double angle = atan2(sinuTL.y - sinuTR.y, sinuTL.x - sinuTR.x); //  * 180 / M_PI

    double x = distance;
    double y = height;
    double xBRTrans = x*cos(angle) - y*sin(angle);
    xBRTrans = sinuTL.x - xBRTrans;
    double yBRTrans = x*sin(angle) + y*cos(angle);
    yBRTrans = sinuTL.y - yBRTrans;

    x = 0;
    y = height;
    double xBLTrans = x*cos(angle) - y*sin(angle);
    xBLTrans += sinuTL.x;
    double yBLTrans = x*sin(angle) + y*cos(angle);
    yBLTrans = sinuTL.y - yBLTrans;

**更新**

我已经调整了下面提供的解决方案中的代码,结果仍然不是我所期望的。给出左边的两个点,计算右边的两个点。你可以看到有一个偏移(这些点应该在建筑物的角落。也忽略中间的蓝点 - 它对这个问题毫无意义):

enter image description here

代码:

double height = 57;
// get coords from provided input
double x1x=629434.24373957072, x1y=5476196.7595944777, x2x=629443.08914538298, x2y=5476120.1852802411;
// x2x3 = Vector from point x2 to point x3, assume x value as 1
double x2x3x = 1;
// calculate y-value, using the fact that dot-product of orthogonal vectors is 0
double x2x3y = x2x*x2x3x / (-1 * x2y);
// calculate length of vector x2x3
double length_e_vec_x2_x3 = sqrt(pow(x2x3x,2) + pow(x2x3y,2));
// stretch vector to provided witdh
x2x3x = x2x3x*height / length_e_vec_x2_x3;
x2x3y = x2x3y*height / length_e_vec_x2_x3;
// since x2x3 and x1x4 are equal, simple addition remains
double x3x, x3y, x4x, x4y;
x3x = x2x + x2x3x;
x3y = x2y + x2x3y;
x4x = x1x + x2x3x;
x4y = x1y + x2x3y;

更新

实际上,所有答案以及我自己的代码都按预期工作。不幸的是,我被蒙住眼睛,并没有注意到这个问题是由于这个区域使用了不适当的地理投影。因此坐标来自WGS84长/纬,并且在计算完成之前将其转换为正弦投影,然后再转换回WGS84。正弦投影保留了该区域(等面积投影) - 但会扭曲区域内的形状。你不能只是添加一些米,然后转换回来。我应该早点意识到这一点,并且正在寻找错误的地方。

我会选择最精彩的答案作为"胜利者"。虽然经过测试后我可以说所有提供的解决方案确实有效。

2 个答案:

答案 0 :(得分:1)

一般推荐:

如果我是你,我会为向量构建类,并为所需的操作构建函数,但是这个例子应该按照你的意愿行事。

向量,绝对和相对坐标:

重要提示:您正在使用坐标,这是一种非常简化的方法。如果为您提供解决方案的人将给定的点设置为0/0,即原点,则您不能仅仅更改此项。我更改了下面的代码,以适应您对提供的输入所做的更改。

double width = 35;

// get coords from provided input
double x1x=0, x1y=0, x2x=x, x2y=y;
// x2x3 = Vector from point x2 to point x3, assume x value as 1
double x2x3x = 1;
// calculate y-value, using the fact that dot-product of orthogonal vectors is 0
double x2x3y = x2x*x2x3x / (-1 * x2y);
// calculate length of vector x2x3
double length_e_vec_x2_x3 = sqrt(pow(x2x3x,2) + pow(x2x3y,2));
// stretch vector to provided witdh
x2x3x = x2x3x*width / length_e_vec_x2_x3;
x2x3y = x2x3y*width / length_e_vec_x2_x3;
// since x2x3 and x1x4 are equal, simple addition remains
double x3x, x3y, x4x, x4y;
x3x = x2x + x2x3x;
x3y = x2y + x2x3y;
x4x = x1x + x2x3x;
x4y = x1y + x2x3y;

// check results
cout << "X1: " << x1x << "/" << x1y << endl;
cout << "X2: " << x2x << "/" << x2y << endl;
cout << "X3: " << x3x << "/" << x3y << endl;
cout << "X4: " << x4x << "/" << x4y << endl;

<强>输出:

X1: 629434/5.4762e+06
X2: 629443/5.47612e+06
X3: 629500/5.47613e+06
X4: 629491/5.4762e+06

<强>验证

如该代码的注释中所述,如果这些向量彼此正交,则两个向量的点积将返回0。通过使用它,可以验证提供的结果。 添加少量代码以验证结果:

// verify results
cout << "Dotproduct should be 0: " << (x2x*x2x3x)+(x2y*x2x3y) << endl;

验证输出

Dotproduct should be 0: 5.68434e-14

打印0,因此代码正在做它应该做的事情。

<强>改进

然而,由于你使用相当大的数字,使用浮点而不是双精度可能会有所帮助。将x1转换为小系统的原点也可能会改善它。 最后,我们将赞赏更合适的数据结构。

// using x1 as origin:
double x1x0 = 0, x1y0 = 0, x2x0 = x2x - x1x, x2y0 = x2y - x1y;

double x2x3x0 = 1;
// calculate y-value, using the fact that dot-product of orthogonal vectors is 0
double x2x3y0 = x2x0*x2x3x0 / (-1 * x2y0);
// calculate length of vector x2x3
double length_e_vec_x2_x30 = sqrt(pow(x2x3x0, 2) + pow(x2x3y0, 2));
// stretch vector to provided witdh
x2x3x0 = x2x3x0*width / length_e_vec_x2_x30;
x2x3y0 = x2x3y0*width / length_e_vec_x2_x30;
// since x2x3 and x1x4 are equal, simple addition remains
double x3x0, x3y0, x4x0, x4y0;
x3x0 = x2x0 + x2x3x0;
x3y0 = x2y0 + x2x3y0;
x4x0 = x1x0 + x2x3x0;
x4y0 = x1y0 + x2x3y0;

// check results
cout << "X1: " << x1x0 << "/" << x1y0 << endl;
cout << "X2: " << x2x0 << "/" << x2y0 << endl;
cout << "X3: " << x3x0 << "/" << x3y0 << endl;
cout << "X4: " << x4x0 << "/" << x4y0 << endl;

// verify results
cout << "Dotproduct should be 0: " << (x2x0*x2x3x0) + (x2y0*x2x3y0) << endl;

// compare results (adding offset before comparing):
cout << "X3 to X30: " << x3x0+x1x-x3x << "/" << x3y0+x1y-x3y << endl;
cout << "X4 to X40: " << x4x0 +x1x-x4x << "/" << x4y0 +x1y-x4y << endl;

结果:

X1: 0/0
X2: 8.84541/-76.5743
X3: 65.4689/-70.0335
X4: 56.6235/6.5408
Dotproduct should be 0: 5.68434e-14
X3 to X30: 0/0
X4 to X40: 0/0

现在输出使用浮点数:

X1: 629434/5.4762e+06
X2: 629443/5.47612e+06
X3: 629500/5.47613e+06
X4: 629491/5.4762e+06
Dotproduct should be 0: 0
X1: 0/0
X2: 8.8125/-77
X3: 65.4428/-70.5188
X4: 56.6303/6.48123
Dotproduct should be 0: 0
X3 to X30: 0/0
X4 to X40: 0/0

使整个事情变得不那么混乱:

using namespace std;

class vector2D
{
protected:
    bool equal(vector2D& param) { return this->X == param.X && this->Y == param.Y; }
    vector2D absAlVal() { return vector2D(abs(X), abs(Y)); }

public:
    float X, Y;

    vector2D(float x, float y) : X(x), Y(y) {};
    vector2D() : X(0), Y(0) {};

    vector2D operator+ (vector2D& param) { return vector2D(this->X+param.X,this->Y+param.Y); }
    vector2D operator- (vector2D& param) { return vector2D(this->X - param.X, this->Y - param.Y); }
    bool operator!=(vector2D& param) { return this->equal(param); }


    vector2D getUnitVector()
    {
        return vector2D(this->X / this->getLength(), this->Y / this->getLength());
    }
    bool parallel(vector2D& param) { return (this->getUnitVector()).equal(param.getUnitVector()); }
    bool colinear(vector2D& param) { return (this->getUnitVector().absAlVal()).equal(param.getUnitVector().absAlVal()); }

    float dotproduct(vector2D vec)
    {
        return this->X * vec.X + this->Y * vec.Y;
    }
    vector2D dotproduct(float scalar)
    {
        return vector2D(this->X * scalar, this->Y * scalar);
    }
    float getLength(void)
    {
        return sqrt(pow(this->X, 2) + pow(this->Y, 2));
    }

};

void main()
{
    // get coords from provided input
    float x1x = 629434.24373957072, x1y = 5476196.7595944777, x2x = 629443.08914538298, x2y = 5476120.1852802411;
    float width = 35;

    // Build vectors
    vector2D X1 = vector2D(x1x, x1y), X2 = vector2D(x2x, x2y), X3, X4, X2X3, X1X2=X2-X1;
    // assum x-direction for X2X3 is positive, chosing 1
    X2X3.X = 1;
    // calculate y-direction using dot-product
    X2X3.Y = X1X2.X*X2X3.X / (-1 * X1X2.Y);
    //check if assumtion is correct:
    cout << "Evaluate wether vector has been build accordingly or not:" << endl;
    cout << "Dotproduct of X1X2 * X2X3 should be 0 -> Result:" << X1X2.dotproduct(X2X3) << endl;
    // stretch X2X3 to width
    X2X3=X2X3.getUnitVector().dotproduct(width);

    // Create X3 and X4 by simple addition:
    X3 = X2 + X2X3;
    X4 = X1 + X2X3;

    // print Points:
    cout << "Summary of Points X / Y coordinates:" << endl;
    cout << "X1: " << X1.X << "/" << X1.Y << endl;
    cout << "X2: " << X2.X << "/" << X2.Y << endl;
    cout << "X3: " << X3.X << "/" << X3.Y << endl;
    cout << "X4: " << X4.X << "/" << X4.Y << endl;
    // compare sides
    cout << "\n" << "Lenght of sides:" << endl;
    cout << "X1X2: " << (X2 - X1).getLength() << " -> should be same length as X3X4" << endl;
    cout << "X2X3: " << (X3 - X2).getLength() << " -> should be same length as X4X1 and with, which is:" << width << endl;
    cout << "X3X4: " << (X4 - X3).getLength() << " -> should be same length as X1X2" << endl;
    cout << "X4X1: " << (X1 - X4).getLength() << " -> should be same length as X2X3, which is:" << width << endl;
}

答案 1 :(得分:1)

给定一个向量conda info --envs,方向(x, y)相对于它顺时针旋转90度。这正是我们需要执行的旋转,以便从(y, -x)获取边x1 -> x4的方向。

x1 -> x2

请注意,我的代码原则上与之前的答案类似,但稍微更优化,并且(希望)修复了方向问题。