我试图在简化的完美圆形轨道上绘制天体。我还绘制了这些物体将采取的投射轨道路径。然而,问题在于物体采用的实际路径与足够紧密放大的投影不一致。
视频演示了该问题: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);
}
}
结果并不令人鼓舞:
除了不那么看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);
}
}
答案 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没有理由做它做的事情。我必须追查这段代码,看看它为什么会失败。
唯一的解决方法是让您实现自己的椭圆项目,并根据渲染时的视口大小选择离散化步骤和开始/结束角度。
qreal
是double
- 所以除非Qt配置了-qreal float
,否则不应该成为问题。