2015-01-09 26 views
-1

我有一个python程序,它将一些椭圆绘制到一个窗口中。下面的Python代码使用W¯¯将DrawEllipse的PyQt实现转换为Matlab

from PyQt4.QtGui import * 

def draw_ellipse(self, center, rad_x, rad_y, angle, color): 
qp = QtGui.QPainter() 
qp.begin(self) 
qp.translate(center) 
qp.rotate(math.degrees(angle)) 
qp.setPen(QtGui.QColor(color)) 
qp.drawEllipse(QPoint(0, 0), rad_x, rad_y) 
qp.end() 

正如你可以看到我的输入参数是centerrad_xrad_yangle。这些参数是从文本文件读入的。

我想在Matlab程序中使用非常相同的参数文件。为此我需要知道drawEllipse的实现,以便我可以在Matlab中实现相同的功能。

不幸的是,我似乎没有找到drawEllipse的源代码。我发现this link用下面的代码:

03114 { 
03115 #ifdef QT_DEBUG_DRAW 
03116  if (qt_show_painter_debug_output) 
03117   printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height()); 
03118 #endif 
03119 
03120  if (!isActive()) 
03121   return; 
03122  Q_D(QPainter); 
03123  d->updateState(d->state); 
03124 
03125  QRectF rect(r.normalized()); 
03126 
03127  if (rect.isEmpty()) 
03128   return; 
03129 
03130  if (d->state->emulationSpecifier) { 
03131   if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform 
03132    && d->state->txop == QPainterPrivate::TxTranslate) { 
03133    rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy())); 
03134   } else { 
03135    QPainterPath path; 
03136    path.addEllipse(rect); 
03137    d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw); 
03138    return; 
03139   } 
03140  } 
03141 
03142  d->engine->drawEllipse(rect); 
03143 } 

这使我this代码(QPainterPath.addEllipse):

01052 void QPainterPath::addEllipse(const QRectF &boundingRect) 
01053 { 
01054 #ifndef QT_NO_DEBUG 
01055  if (qIsNan(boundingRect.x()) || qIsNan(boundingRect.y()) 
01056   || qIsNan(boundingRect.width()) || qIsNan(boundingRect.height())) 
01057   qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN, results are undefined"); 
01058 #endif 
01059  if (boundingRect.isNull()) 
01060   return; 
01061 
01062  ensureData(); 
01063  detach(); 
01064 
01065  Q_D(QPainterPath); 
01066  d->elements.reserve(d->elements.size() + 13); 
01067 
01068  QPointF pts[12]; 
01069  int point_count; 
01070  QPointF start = qt_curves_for_arc(boundingRect, 0, 360, pts, &point_count); 
01071 
01072  moveTo(start); 
01073  cubicTo(pts[0], pts[1], pts[2]);   // 0 -> 270 
01074  cubicTo(pts[3], pts[4], pts[5]);   // 270 -> 180 
01075  cubicTo(pts[6], pts[7], pts[8]);   // 180 -> 90 
01076  cubicTo(pts[9], pts[10], pts[11]);   // 90 - >0 
01077  d_func()->require_moveTo = true; 
01078 } 

让我们进入qstroker_8cpp看看qt_curves_for_arc

00722 QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, 
00723      QPointF *curves, int *point_count) 
00724 { 
00725  Q_ASSERT(point_count); 
00726  Q_ASSERT(curves); 
00727 
00728 #ifndef QT_NO_DEBUG 
00729  if (qIsNan(rect.x()) || qIsNan(rect.y()) || qIsNan(rect.width()) || qIsNan(rect.height()) 
00730   || qIsNan(startAngle) || qIsNan(sweepLength)) 
00731   qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined"); 
00732 #endif 
00733  *point_count = 0; 
00734 
00735  if (rect.isNull()) { 
00736   return QPointF(); 
00737  } 
00738 
00739  if (sweepLength > 360) sweepLength = 360; 
00740  else if (sweepLength < -360) sweepLength = -360; 
00741 
00742  // Special case fast path 
00743  if (startAngle == 0.0 && sweepLength == 360.0) { 
00744   qreal x = rect.x(); 
00745   qreal y = rect.y(); 
00746 
00747   qreal w = rect.width(); 
00748   qreal w2 = rect.width()/2; 
00749   qreal w2k = w2 * QT_PATH_KAPPA; 
00750 
00751   qreal h = rect.height(); 
00752   qreal h2 = rect.height()/2; 
00753   qreal h2k = h2 * QT_PATH_KAPPA; 
00754 
00755   // 0 -> 270 degrees 
00756   curves[(*point_count)++] = QPointF(x + w, y + h2 + h2k); 
00757   curves[(*point_count)++] = QPointF(x + w2 + w2k, y + h); 
00758   curves[(*point_count)++] = QPointF(x + w2, y + h); 
00759 
00760   // 270 -> 180 degrees 
00761   curves[(*point_count)++] = QPointF(x + w2 - w2k, y + h); 
00762   curves[(*point_count)++] = QPointF(x, y + h2 + h2k); 
00763   curves[(*point_count)++] = QPointF(x, y + h2); 
00764 
00765   // 180 -> 90 degrees 
00766   curves[(*point_count)++] = QPointF(x, y + h2 - h2k); 
00767   curves[(*point_count)++] = QPointF(x + w2 - w2k, y); 
00768   curves[(*point_count)++] = QPointF(x + w2, y); 
00769 
00770   // 90 -> 0 degrees 
00771   curves[(*point_count)++] = QPointF(x + w2 + w2k, y); 
00772   curves[(*point_count)++] = QPointF(x + w, y + h2 - h2k); 
00773   curves[(*point_count)++] = QPointF(x + w, y + h2); 
00774 
00775   return QPointF(x + w, y + h2); 
00776  } 
00777 
00778 #define ANGLE(t) ((t) * 2 * Q_PI/360.0) 
00779 #define SIGN(t) (t > 0 ? 1 : -1) 
00780  qreal a = rect.width()/2.0; 
00781  qreal b = rect.height()/2.0; 
00782 
00783  qreal absSweepLength = (sweepLength < 0 ? -sweepLength : sweepLength); 
00784  int iterations = (int)ceil((absSweepLength)/90.0); 
00785 
00786  QPointF first_point; 
00787 
00788  if (iterations == 0) { 
00789   first_point = rect.center() + QPointF(a * qCos(ANGLE(startAngle)), 
00790            -b * qSin(ANGLE(startAngle))); 
00791  } else { 
00792   qreal clength = sweepLength/iterations; 
00793   qreal cosangle1, sinangle1, cosangle2, sinangle2; 
00794 
00795   for (int i=0; i<iterations; ++i) { 
00796    qreal cangle = startAngle + i * clength; 
00797 
00798    cosangle1 = qCos(ANGLE(cangle)); 
00799    sinangle1 = qSin(ANGLE(cangle)); 
00800    cosangle2 = qCos(ANGLE(cangle + clength)); 
00801    sinangle2 = qSin(ANGLE(cangle + clength)); 
00802 
00803    // Find the start and end point of the curve. 
00804    QPointF startPoint = rect.center() + QPointF(a * cosangle1, -b * sinangle1); 
00805    QPointF endPoint = rect.center() + QPointF(a * cosangle2, -b * sinangle2); 
00806 
00807    // The derived at the start and end point. 
00808    qreal sdx = -a * sinangle1; 
00809    qreal sdy = -b * cosangle1; 
00810    qreal edx = -a * sinangle2; 
00811    qreal edy = -b * cosangle2; 
00812 
00813    // Creating the tangent lines. We need to reverse their direction if the 
00814    // sweep is negative (clockwise) 
00815    QLineF controlLine1(startPoint, startPoint + SIGN(sweepLength) * QPointF(sdx, sdy)); 
00816    QLineF controlLine2(endPoint, endPoint - SIGN(sweepLength) * QPointF(edx, edy)); 
00817 
00818    // We need to scale down the control lines to match that of the current sweeplength. 
00819    // qAbs because we only want to scale, not change direction. 
00820    qreal kappa = QT_PATH_KAPPA * qAbs(clength)/90.0; 
00821    // Adjust their length to fit the magic KAPPA length. 
00822    controlLine1.setLength(controlLine1.length() * kappa); 
00823    controlLine2.setLength(controlLine2.length() * kappa); 
00824 
00825    curves[(*point_count)++] = controlLine1.p2(); 
00826    curves[(*point_count)++] = controlLine2.p2(); 
00827    curves[(*point_count)++] = endPoint; 
00828 
00829    if (i == 0) 
00830     first_point = startPoint; 
00831   } 
00832  } 
00833 
00834  return first_point; 
00835 } 

这对于绘制简单的椭圆是相当多的代码!这感觉不对改写这一切在Matlab,如果一个简单的椭圆形可以绘制这样的:

a = rad_x; % horizontal radius 
b = rad_y; % vertical radius 
x0 = center_x; % x0, y0 ellipse centre coordinates 
y0 = center_y; 
steps = 50; 
t = linspace(0, 2*pi, steps); 
theta0 = angle; 
x = x0 + (a * sin(t - theta0)); 
y = y0 + (b * cos(t)); 

plot(x, y, '.-'), 

问:
给出上述(centerrad_xrad_y列出的四个参数angle),我在matlab中正确绘制椭圆的最简单方法是什么?与我上面的绘图matlab代码目前只适用于小角度和特定组合。

+0

你看看这个[现场](http://matlab.wikia.com/wiki/FAQ#How_do_I_create_an_ellipse.3F)? – Nemesis

+0

@网络它没有解决问题。我知道如何绘制一个椭圆,请参阅我的代码。我所缺少的是将四个参数转换为一般形式,所以我可以用matlab进行绘图。 – memyself

+0

对不起,那我就不明白你的问题了吧?通用形式是什么意思?一个函数?为什么只适用于特定情况? – Nemesis

回答

1

这样的事情呢?

a = rad_x; 
b = rad_y; 
r0 = center_x + i*center_y; % <-- origin of ellipse 

theta0=angle; % <-- angle of rotation of ellipse 

steps = 200; 

t = linspace(0, 2*pi, steps); 

r = a*sin(t) + i*b*cos(t); 


R = exp(i*theta0); 
r = R*r; 
r = r0 + r; 

figure(1), hold on 
plot(real(r), imag(r), '-r') 

使用矩阵而非复数:

a = rad_x; 
b = rad_y; 
r0 = [center_x ; center_y]; % <-- origin of ellipse 

theta0=angle; % <-- angle of rotation of ellipse 

steps = 200; 

t = linspace(0, 2*pi, steps); 

r = [a*sin(t) ; b*cos(t)]; 

R = [cos(theta0) -sin(theta0) ; sin(theta0) cos(theta0)]; % <-- note neg signs: define direction of rotation! 
r = R*r; 
r = r0*ones(1,length(t)) + r; 

figure(1) 
plot(r(1,:), r(2,:), '-r') 
+0

你可以编辑你的代码,并使用我的问题中指出的参数名称'center','rad_x','rad_y'和'angle'吗?这会让你更容易理解你的代码。 – memyself

+0

请注意,'center'是指示椭圆中心的x和y坐标的元组。 – memyself

+0

@memyself你不使用'angle'。所有其他变量都在其中,只需用您自己的定义替换等式。绘制多个椭圆的一个简单方法是遍历参数,否则您可以使用MATLAB的一个技巧来获得更简洁的表达式。 –