如何使手动计算的轨道路径与Qt的椭圆绘制方法一致?

时间:2014-04-07 16:15:17

标签: c++ qt trigonometry qgraphicsview qgraphicsscene

我试图在简化的完美圆形轨道上绘制天体。我还绘制了这些物体将采取的投射轨道路径。然而,问题在于物体采用的实际路径与足够紧密放大的投影不一致。

视频演示了该问题:https://www.youtube.com/watch?v=ALSVfx48zXw

如果缩小,则问题不存在,因为偏差太小。偏差的表观尺寸似乎主要受到圆的可见曲率的影响 - 注意卫星的路径如何与它们的运动一致。如果要放大,那么卫星就可以了。投影路径看起来接近直线,它们将具有与行星显示的相同的偏差模式。

协调计算方法:

double getX (long int time) {
    return orbit * cos(offset + time * speed);
}
double getY (long int time) {
    return orbit * sin(offset + time * speed);
}

预计轨道绘图:

ellipse = scene->addEllipse(system.starX-body.orbit,
                            system.starY-body.orbit,
                             body.orbit*2,body.orbit*2,greenPen,transBrush); 

绘制实际出现的天体:

ellipse = scene->addEllipse(-body.radius,
                            -body.radius,
                            body.radius*2,body.radius*2,blackPen,greenBrush); 
ellipse->setFlag(QGraphicsItem::ItemIgnoresTransformations);
ellipse->setPos(system.starX+body.getX(date2days(game.date)),
                system.starY+body.getY(date2days(game.date)));

如何解决这个问题,以便天体总是在预测的曲线上?

EDIT1:
我尝试使用建议的算法绘制自己的椭圆。适用于Qt I的版本在此重现:

QPoint get_point(double a, double b, double theta, QPoint center)
{
    QPoint point;
    point.setX(center.x() + a * cos(theta));
    point.setY(center.y() + b * sin(theta));
    return point;
}

void draw_ellipse(double a, double b, QPoint center, double zoom_factor, QGraphicsScene * scene, QPen pen)
{
    double d_theta = 1.0d / zoom_factor;
    double theta = 0.0d;
    int count = 2.0d * 3.14159265358979323846 / d_theta;

    QPoint p1, p2;
    p1 = get_point(a, b, 0.0f, center);
    for (int i = 0; i <= count; i++)
    {
        theta += d_theta;
        p2 = p1;
        p1 = get_point(a, b, theta, center);

        scene->addLine(p1.x(),p1.y(),p2.x(),p2.y(),pen);
    }
}

结果并不令人鼓舞:

Not pretty

除了不那么看zoom_factor 360之外,应用程序运行得非常缓慢,使用的资源比以前多得多。

EDIT2:
改进版本提供了更好的结果,但仍然很慢。这是代码:

QPointF get_point(qreal a, qreal b, qreal theta, QPointF center)
{
    QPointF point;
    point.setX(center.x() + a * cos(theta));
    point.setY(center.y() + b * sin(theta));
    return point;
}

void draw_ellipse(qreal a, qreal b, QPointF center, qreal zoom_factor, QGraphicsScene * scene, QPen pen)
{
    qreal d_theta = 1.0d / zoom_factor;
    qreal theta = 0.0d;
    int count = 2.0d * 3.14159265358979323846 / d_theta;

    QPointF p1, p2;
    p1 = get_point(a, b, 0.0f, center);
    for (int i = 0; i <= count; i++)
    {
        theta = i * d_theta;
        p2 = p1;
        p1 = get_point(a, b, theta, center);

        scene->addLine(p1.x(),p1.y(),p2.x(),p2.y(),pen);
    }
}

2 个答案:

答案 0 :(得分:1)

Qt似乎没有自动调整绘图精度或“采样分辨率”。

您可以尝试通过绘制一条线来自行绘制椭圆。放大时增加图形的样本分辨率 - 即使采样点彼此更接近。

取椭圆的参数方程

x = cos(theta),y = b sin(theta)

其中a和b是椭圆的半长轴和半短轴,并用它对点进行采样:

(伪C ++ - 样式代码)

point get_point(float theta, point center)
{
    return point(center.x + a * cos(theta), center.y + b * sin(theta));
}

void draw_ellipse(float a, float b, point center, float zoom_factor)
{
    float d_theta = 1.0f / zoom_factor;
    float theta = 0.0f;
    int count = 2.0f * PI / d_theta;

    point p1, p2;
    p1 = get_point(0.0f, center);
    for (int i = 0; i < count; i++)
    {
        theta += d_theta;
        p2 = p1;
        p1 = get_point(theta, center);

        drawline(p1, p2);
    }
}

很抱歉,如果代码看起来是任意的(我不熟悉Qt),但你明白了。

答案 1 :(得分:1)

假设您传递给addEllipse的所有参数都具有足够的分辨率,问题似乎与Qt渲染椭圆的方式有关。椭圆绘制中使用的离散化不依赖于视图的变换矩阵。

在视图中呈现QGraphicsItem时,其paint方法当然可以访问绘图设备(在本例中为:小部件)。它当然可以确定角度方面的正确离散步骤。即使使用常规画家调用渲染图形项目,画家也具有相同的信息,并且绘图设备当然完整地具有此信息。因此,我认为Qt没有理由做它做的事情。我必须追查这段代码,看看它为什么会失败。

唯一的解决方法是让您实现自己的椭圆项目,并根据渲染时的视口大小选择离散化步骤和开始/结束角度。

qrealdouble - 所以除非Qt配置了-qreal float,否则不应该成为问题。