在球内建一个三维坐标系,在轴上添加文本Z、X、Y,添加一根坐标线,标出线和三轴的夹角
头文件:
#ifndef QTDRAW3DCTRL_H
#define QTDRAW3DCTRL_H
#include <QtOpenGL/qgl.h>
#include <QWidget>
#include <QGridLayout>
#include <QtGui/QtGui>
#include <QtOpenGL/QtOpenGL>
#include <QtOpenGL/QGLWidget>
#include <QtWidgets/QOpenGLWidget>
#include <QtOpenGL/QGL>
#include <vector>
#include <GL/glu.h>
class QtDraw3DCtrl : public QOpenGLWidget
{
Q_OBJECT
public:
QtDraw3DCtrl(QWidget *parent = 0);
~QtDraw3DCtrl();
void setFieldData(double dField, double dTheta, double dPhi);
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseMoveEvent(QMouseEvent *event);
virtual void wheelEvent(QWheelEvent *event);
public slots:
void UpdateSlots();
private:
int m_iScloe; //滚动放大缩小尺寸
double m_dRotX;
double m_dRotY;
double m_dRotZ;
QPoint m_qpRotPosOld;
int m_iSize;
double m_dFieldX;
double m_dFieldY;
double m_dFieldZ;
void GLGrid(float pt1x, float pt1y, float pt1z, float pt2x, float pt2y, float pt2z, int num);
void drawSphere(float fX, float fY, float fZ, float fRadius, float M, float N);
void drawInnerCircular(float fX, float fY, float fZ, float fRadius, float fAngleZ, float fAngleXY, float fStepZ, float fStepXY);
void drawAxisText(float fStart[3], float fPoint[2], float fColor[3], QString strText);
void drawAllAxisText();
void drawFieldText();
void drawAllAxis();
QVector<double> SweepToAxis(double dField, double dTheta, double dPhi);
};
#endif
实现文件:
#include "qtdraw3dctrl.h"
#define PI 3.1415926
#define RADIUS 4.5
QtDraw3DCtrl::QtDraw3DCtrl(QWidget *parent) : QOpenGLWidget(parent)
{
m_iScloe = -13;
m_dRotX = 0;
m_dRotY = 0;
m_dRotZ = 0;
m_iSize = 2;
QTimer* timer = new QTimer(this);
timer->setInterval(10);
connect(timer, SIGNAL(timeout()), this, SLOT(UpdateSlots()));
timer->start();
m_dFieldX = 2.59;
m_dFieldY = 2.59;
m_dFieldZ = 2.59;
}
QtDraw3DCtrl::~QtDraw3DCtrl()
{
}
void QtDraw3DCtrl::UpdateSlots()
{
update();
}
void QtDraw3DCtrl::initializeGL()
{
glClearColor(0.92, 0.94, 0.95, 1); //#EBF0F3
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH);
}
void QtDraw3DCtrl::resizeGL(int w, int h)
{
if (h == 0) {
h = 1;
}
glViewport(0, 0, (GLint)w, (GLint)h); //重置当前的视口
glMatrixMode(GL_PROJECTION); //选择投影矩阵
glLoadIdentity(); //重置投影矩阵
gluPerspective(45, (GLfloat)w / (GLfloat)h, 0.001, 1000); //建立透视投影矩阵
glMatrixMode(GL_MODELVIEW); //选择模型观察矩阵
glLoadIdentity(); //重置模型观察矩阵
}
/* 画坐标系上的文字 */
void QtDraw3DCtrl::drawAxisText(float fStart[3], float fPoint[2], float fColor[3], QString strText)
{
QPainterPath path;
glDisable(GL_DEPTH);
path.addText(QPointF(fPoint[0], fPoint[1]), QFont("PMingLiU", 3), strText);
QList<QPolygonF> poly = path.toSubpathPolygons();
QList<QPolygonF>::iterator iter = poly.begin();
while(iter != poly.end()) {
glBegin(GL_LINE_LOOP);
QPolygonF::iterator it = (*iter).begin();
while(it != iter->end()) {
glVertex3f(fStart[0] + it->rx() * 0.1, fStart[1] - it->ry() * 0.1, fStart[2]);
glColor3f(fColor[0], fColor[1], fColor[2]);
it++;
}
glEnd();
iter++;
}
glEnable(GL_DEPTH);
}
/* 准备三个坐标系上的文字 */
void QtDraw3DCtrl::drawAllAxisText()
{
float fStart[3];
float fPoint[2];
float fColor[3];
fStart[0] = RADIUS;
fStart[1] = 0;
fStart[2] = 0;
fPoint[0] = 2.5;
fPoint[1] = 1;
fColor[0] = 1;
fColor[1] = 0;
fColor[2] = 0;
drawAxisText(fStart, fPoint, fColor, "X");
fStart[0] = 0;
fStart[1] = RADIUS;
fStart[2] = 0;
fPoint[0] = -1.2;
fPoint[1] = -2.5;
fColor[0] = 0;
fColor[1] = 1;
fColor[2] = 0;
drawAxisText(fStart, fPoint, fColor, "Y");
fStart[0] = 0;
fStart[1] = 0;
fStart[2] = RADIUS + 0.5;
fPoint[0] = -1;
fPoint[1] = 1;
fColor[0] = 0;
fColor[1] = 0;
fColor[2] = 1;
drawAxisText(fStart, fPoint, fColor, "Z");
}
/* 画磁场夹角和文本 */
void QtDraw3DCtrl::drawFieldText()
{
float fStart[3];
float fPoint[2];
float fColor[3];
float fAngleY = 0.34;
if(m_dFieldY < 0) {
fAngleY = -0.34;
}
float fAngleX = fAngleY * m_dFieldX / m_dFieldY;
float fAngleZ = fAngleY * m_dFieldZ / m_dFieldY;
glLineWidth(1.9);
glBegin(GL_LINES);
glEnable(GL_LINE_SMOOTH);
glColor3f(1, 0, 0);
glVertex3f(0, fAngleY, 0);
glVertex3f(fAngleX, fAngleY, fAngleZ);
glEnd();
glLineWidth(1.9);
glBegin(GL_LINES);
glEnable(GL_LINE_SMOOTH);
glColor3f(1, 0, 0);
glVertex3f(0, 0, 0.34);
glVertex3f(fAngleX, 0, fAngleZ);
glEnd();
fStart[0] = 0.1;
fStart[1] = 0.3;
fStart[2] = 0.1;
fPoint[0] = 0;
fPoint[1] = 0;
fColor[0] = 0;
fColor[1] = 0;
fColor[2] = 0;
drawAxisText(fStart, fPoint, fColor, QString::fromLocal8Bit("Φ"));
fStart[0] = 0.1;
fStart[1] = -0.1;
fStart[2] = 0.6;
fPoint[0] = 0;
fPoint[1] = 0;
fColor[0] = 0;
fColor[1] = 0;
fColor[2] = 0;
drawAxisText(fStart, fPoint, fColor, QString::fromLocal8Bit("Θ"));
//虚线
glLineStipple(2, 0x5555);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINE_STRIP);
glColor3f(1, 0, 0);
glVertex3f(0, 0, 0);
glVertex3f(m_dFieldX, 0, m_dFieldZ);
glVertex3f(m_dFieldX, m_dFieldY, m_dFieldZ);
glEnd();
glDisable(GL_LINE_STIPPLE);
glFlush();
}
/* 画三个坐标轴 */
void QtDraw3DCtrl::drawAllAxis()
{
GLUquadricObj *objCylinder = gluNewQuadric();
int num = 1; //一个网格
//X
glPushMatrix();
glColor3f(0.4, 0.4, 0.4);
glTranslatef(0, 0, 0);
GLGrid(0, 0, 0, RADIUS, 0, 0, num); //x轴只留一个网格
glPopMatrix();
glPushMatrix();
glColor3f(1, 0, 0);
glTranslatef(RADIUS, 0, 0);
glRotatef(90, 0, 1, 0);
gluCylinder(objCylinder, 0.1, 0, 0.2, 100, 1);
glPopMatrix();
//Y
glPushMatrix();
glTranslated(0, RADIUS, 0);
glRotatef(90, 1, 0, 0);
glColor3f(0.4, 0.4, 0.4);
GLGrid(0, 0, 0, 0, 0, RADIUS, num); //y轴只留一个网格
glPopMatrix();
glPushMatrix();
glColor3f(0, 1, 0);
glTranslatef(0, RADIUS, 0);
glRotatef(-90, 1, 0, 0);
gluCylinder(objCylinder, 0.1, 0, 0.2, 100, 1);
glPopMatrix();
//Z
glPushMatrix();
glTranslatef(0, 0, 0);
glRotatef(90, 0, 0, 1.0);
glColor3f(0.4, 0.4, 0.4);
GLGrid(0, 0, 0, 0, 0, RADIUS, num); //z只直留一个网格
glPopMatrix();
glPushMatrix();
glColor3f(0, 0, 1);
glTranslatef(0, 0, RADIUS);
glRotatef(90, 0, 0, 1);
gluCylinder(objCylinder, 0.1, 0, 0.2, 100, 1);
glPopMatrix();
}
/* ρ,Θ,Φ转换为x,y,z */
QVector<double> QtDraw3DCtrl::SweepToAxis(double dField, double dTheta, double dPhi)
{
QVector<double> vAxis(3);
vAxis[0] = dField * sin(dTheta) * sin(dPhi);
vAxis[1] = dField * sin(dTheta) * cos(dPhi);
vAxis[2] = cos(dTheta);
return vAxis;
}
void QtDraw3DCtrl::setFieldData(double dField, double dTheta, double dPhi)
{
QVector<double> vAxis = SweepToAxis(dField, dTheta, dPhi);
m_dFieldX = vAxis[0];
m_dFieldY = vAxis[1];
m_dFieldZ = vAxis[2];
}
void QtDraw3DCtrl::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存
glLoadIdentity(); //重置当前的模型观察矩阵
//旋转显示窗口
glTranslatef(0, 0, m_iScloe);
glRotatef(fabs(m_dRotY), m_dRotX, m_dRotY, m_dRotZ);
//轴
drawAllAxis();
//数据线
glLineWidth(1.9);
glBegin(GL_LINES);
glEnable(GL_LINE_SMOOTH);
glTranslatef(-m_iSize, -m_iSize, -m_iSize);
glColor3f(1, 0.5, 1);
glVertex3f(0, 0, 0);
glVertex3f(m_dFieldX, m_dFieldY, m_dFieldZ);
glEnd();
glFlush();
//球
drawSphere(0, 0, 0, RADIUS, 270, 270);
//坐标轴文本
drawAllAxisText();
//磁场文本
drawFieldText();
}
/* 绘制圆 */
void QtDraw3DCtrl::drawInnerCircular(float fX, float fY, float fZ, float fRadius, float fAngleZ, float fAngleXY, float fStepZ, float fStepXY)
{
float x[4], y[4], z[4];
x[0] = fRadius * sin(fAngleZ) * cos(fAngleXY);
y[0] = fRadius * sin(fAngleZ) * sin(fAngleXY);
z[0] = fRadius * cos(fAngleZ);
x[1] = fRadius * sin(fAngleZ + fStepZ) * cos(fAngleXY);
y[1] = fRadius * sin(fAngleZ + fStepZ) * sin(fAngleXY);
z[1] = fRadius * cos(fAngleZ + fStepZ);
x[2] = fRadius * sin(fAngleZ + fStepZ) * cos(fAngleXY + fStepXY);
y[2] = fRadius * sin(fAngleZ + fStepZ) * sin(fAngleXY + fStepXY);
z[2] = fRadius * cos(fAngleZ + fStepZ);
x[3] = fRadius * sin(fAngleZ) * cos(fAngleXY + fStepXY);
y[3] = fRadius * sin(fAngleZ) * sin(fAngleXY + fStepXY);
z[3] = fRadius * cos(fAngleZ);
for(int k = 0; k < 4; k++) {
glColor3f(0.69, 0.81, 0.92);
glBlendFunc(GL_ONE, GL_ZERO);
glTexCoord2f(0.1, 0.1);
glVertex3f(fY + y[k], fZ + z[k], fY + x[k]);
}
}
/* 绘制球体,球心坐标为(xyz),球的半径为radius,M,N分别表示球体的横纵向被分成多少份 */
void QtDraw3DCtrl::drawSphere(float fX, float fY, float fZ, float fRadius, float M, float N)
{
// 选择使用的纹理
glBindTexture(GL_TEXTURE_2D, 1);
float fStepZ = PI / M;
float fStepXY = 2 * PI / N;
int i = 0, j = 0;
glBegin(GL_QUADS);
for(i = 0; i < M; i++) {
for(j = 0; j < N; j++) {
if(j % 15 != 0) {
continue;
}
drawInnerCircular(fX, fY, fZ, fRadius, i * fStepZ, j * fStepXY, fStepZ, fStepXY);
}
}
for(i = 0; i < M; i++) {
if(i % 15 != 0) {
continue;
}
for(j = 0; j < N; j++) {
drawInnerCircular(fX, fY, fZ, fRadius, i * fStepZ, j * fStepXY, fStepZ, fStepXY);
}
}
glEnd();
}
void QtDraw3DCtrl::mousePressEvent(QMouseEvent *event)
{
QPoint pos = event->pos();
}
void QtDraw3DCtrl::mouseMoveEvent(QMouseEvent *event)
{
QPoint pos = event->pos();
if (pos.y() > m_qpRotPosOld.y()) {
m_dRotZ -= 1;
m_dRotX -= 1;
m_dRotY -= 1;
}
else if(pos.y() < m_qpRotPosOld.y()) {
m_dRotZ += 1;
m_dRotX += 1;
m_dRotY += 1;
}
m_qpRotPosOld = pos;
update();
}
void QtDraw3DCtrl::wheelEvent(QWheelEvent *event)
{
if (event->delta() < 0) {
//m_iScloe++;
}
else if (event->delta() > 0) {
//m_iScloe--;
}
update();
}
/* 画坐标轴和网格 */
void QtDraw3DCtrl::GLGrid(float pt1x, float pt1y, float pt1z, float pt2x, float pt2y, float pt2z, int num)
{
const float _xLen = (pt2x - pt1x) / num;
const float _yLen = (pt2y - pt1y) / num;
const float _zLen = (pt2z - pt1z) / num;
glLineWidth(1.9);
glBegin(GL_LINES);
glEnable(GL_LINE_SMOOTH);
int xi = 0;
int yi = 0;
int zi = 0;
//绘制平行于X的直线
for (zi = 0; zi <= num; zi++) {
float z = _zLen * zi + pt1z;
for (yi = 0; yi <= num; yi++) {
float y = _yLen * yi + pt1y;
glVertex3f(pt1x, y, z);
glVertex3f(pt2x, y, z);
}
}
//绘制平行于Y的直线
for (zi = 0; zi <= num; zi++) {
float z = _zLen * zi + pt1z;
for (xi = 0; xi <= num; xi++) {
float x = _xLen * xi + pt1x;
glVertex3f(x, pt1y, z);
glVertex3f(x, pt2y, z);
}
}
//绘制平行于Z的直线
for (yi = 0; yi <= num; yi++) {
float y = _yLen * yi + pt1y;
for (xi = 0; xi <= num; xi++) {
float x = _xLen * xi + pt1x;
glVertex3f(x, y, pt1z);
glVertex3f(x, y, pt2z);
}
}
glEnd();
}
效果如下: