使用QPainter画一个3D正方体

本文实例为大家分享了QPainter画一个3D正的具体代码,供大家参考,具体内容如下

My3DBox .h

#include <Eigen/Geometry>
using namespace Eigen;

#define SQUARE_LENGTH 200//是一个边长200的正方体
#define CAMERA_DISTANCE 300//视点距离

class My3DBox : public QWidget
{
  Q_OBJECT
public:
  explicit My3DBox(QWidget *parent = 0);
protected:
  QPoint m_mousePos;
  Vector3d m_vector[8];//正方形8个点坐标

  void mouseMoveEvent(QMouseEvent *);
  void paintEvent(QPaintEvent *);

  void drawPlane(const QPoint *points,QPainter &painter);
  Matrix3d getMartix();
  QPoint ToPoint(Vector3d vector);
  void drawUp(QPoint *points,QPainter &painter);//正方体面的绘制
  void drawDown(QPoint *points,QPainter &painter);
  void drawLeft(QPoint *points,QPainter &painter);
  void drawRight(QPoint *points,QPainter &painter);
};

My3DBox .cpp

#include "widget.h"

#define PI 3.1415926

My3DBox::My3DBox(QWidget *parent) :
  QWidget(parent),m_mousePos(0,0)
{
  setMouseTracking(true);//在任何情况下启用mouseMoveEvent
  setGeometry(400,200,500,500);

  m_vector[0] << -100,100,100;//设置正方体顶点初始位置
  m_vector[1] << 100,100,100;
  m_vector[2] << -100,-100,100;
  m_vector[3] << 100,-100,100;
  m_vector[4] << -100,100,-100;
  m_vector[5] << 100,100,-100;
  m_vector[6] << -100,-100,-100;
  m_vector[7] << 100,-100,-100;
}

void My3DBox::mouseMoveEvent(QMouseEvent *e)//此处把坐标原点从左上角变换至屏幕中心
{
  if(e->pos().x() < 0)
    m_mousePos.setX(-width()/2);
  else if(e->pos().x() > width())
    m_mousePos.setX(width()/2);
  else
    m_mousePos.setX(e->pos().x() - width()/2);

  if(e->pos().y() < 0)
    m_mousePos.setY(height()/2);
  else if(e->pos().y() > height())
    m_mousePos.setY(-height()/2);
  else
    m_mousePos.setY(-e->pos().y() + height()/2);

  update();
}

void My3DBox::paintEvent(QPaintEvent *)
{
  QPainter painter(this);
  painter.setRenderHint(QPainter::Antialiasing);
  painter.setRenderHint(QPainter::SmoothPixmapTransform);
  painter.setPen(Qt::NoPen);

  painter.fillRect(rect(),QColor(3,22,52));

  Vector3d vector[8];
  Matrix3d matrix = getMartix();//获取变换矩阵

  QPoint points[8];//正面0123 左面4062 右面1537 上面4501 下面 2367(以观察者的方向为主)
  for(int i = 0;i < 8;++i)//计算变换后坐标
  {
    vector[i] = matrix*m_vector[i];
    points[i] = ToPoint(vector[i]);

    points[i].setX(points[i].x()+width()/2);//将坐标系原点变换至左上角
    points[i].setY(-points[i].y()+height()/2);
  }

  //一共要画5个面,最后画正面
  if(qAbs(m_mousePos.x()) > qAbs(m_mousePos.y()))
  {
    if(m_mousePos.x() > 0)
    {
      if(m_mousePos.y() > 0)
        drawDown(points,painter);
      else
        drawUp(points,painter);
      drawLeft(points,painter);
    }
    else
    {
      if(m_mousePos.y() > 0)
        drawDown(points,painter);
      else
        drawUp(points,painter);
      drawRight(points,painter);
    }
  }
  else
  {
    if(m_mousePos.y() > 0)
    {
      if(m_mousePos.x() > 0)
        drawLeft(points,painter);
      else
        drawRight(points,painter);
      drawDown(points,painter);
    }
    else
    {
      if(m_mousePos.x() > 0)
        drawLeft(points,painter);
      else
        drawRight(points,painter);
      drawUp(points,painter);
    }
  }
  //画正面
  QPoint point[4] =
  {
    points[0],
    points[1],
    points[3],
    points[2]
  };
  drawPlane(point,painter);
}

void My3DBox::drawPlane(const QPoint *points,QPainter &painter)
{
  QLinearGradient linearGradient(points[1],points[3]);//设置渐变色
  linearGradient.setColorAt(0.0,QColor(150,150,250));
  linearGradient.setColorAt(1.0,QColor(170,170,255));
  painter.setBrush(QBrush(linearGradient));
  painter.drawConvexPolygon(points,4);
}

Matrix3d My3DBox::getMartix()
{
  double unit_x = 0;//同方向单位向量的x和y
  double unit_y = 0;
  double z = 0;

  if(m_mousePos.x() != 0 || m_mousePos.y() != 0)
  {
    unit_x = m_mousePos.x()/qSqrt(m_mousePos.x()*m_mousePos.x() + m_mousePos.y()*m_mousePos.y());
    unit_y = m_mousePos.y()/qSqrt(m_mousePos.x()*m_mousePos.x() + m_mousePos.y()*m_mousePos.y());
    z = qSqrt(m_mousePos.x()*m_mousePos.x() + m_mousePos.y()*m_mousePos.y())/qSqrt(width()*width()/4 + height()*height()/4);
  }

  Matrix3d M_Z;
  if(unit_x == 0 && unit_y == 0)
    M_Z << 1,0,0,
        0,1,0,
        0,0,1;
  else
    M_Z << unit_y,-unit_x,0,
        unit_x,unit_y,0,
        0,0,1;

  Matrix3d M_X;
  if(z == 0)
    M_X << 1,0,0,
        0,1,0,
        0,0,1;
  else
    M_X << 1,0,0,
        0,cos(z*PI/2.6),sin(z*PI/2.6),
        0,-sin(z*PI/2.6),cos(z*PI/2.6);//为什么PI/2大于90度?因为没画背面所以必须小于90度(偷懒)

  return M_Z.inverse()*M_X*M_Z;
}

QPoint My3DBox::ToPoint(Vector3d vector)//将3d坐标投影至平面上
{
  QPoint point;

  point.setX(CAMERA_DISTANCE*vector[0]/(CAMERA_DISTANCE-vector[2]));
  point.setY(CAMERA_DISTANCE*vector[1]/(CAMERA_DISTANCE-vector[2]));

  return point;
}

void My3DBox::drawUp(QPoint *points,QPainter &painter)
{
  QPoint point[4] =
  {
    points[4],
    points[5],
    points[1],
    points[0]
  };
  drawPlane(point,painter);
}

void My3DBox::drawDown(QPoint *points,QPainter &painter)
{
  QPoint point[4] =
  {
    points[2],
    points[3],
    points[7],
    points[6]
  };
  drawPlane(point,painter);
}

void My3DBox::drawLeft(QPoint *points,QPainter &painter)
{
  QPoint point[4] =
  {
    points[4],
    points[0],
    points[2],
    points[6]
  };
  drawPlane(point,painter);
}

void My3DBox::drawRight(QPoint *points,QPainter &painter)
{
  QPoint point[4] =
  {
    points[1],
    points[5],
    points[7],
    points[3]
  };
  drawPlane(point,painter);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Qt5.9画五角星的方法

    本文实例为大家分享了Qt5.9画五角星的具体代码,供大家参考,具体内容如下 今天记录一下画图部分的程序,比较简单,容易操作,为接下来打好基础: 先说界面吧: 里面的图位置跟图像学有点关系,多多理解一下: 对应的头文件: #ifndef WIDGET_H #define WIDGET_H #include <QWidget> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT protected: voi

  • Qt 实现钢笔画线效果示例及详细原理

    前言 上一篇文章:Qt 实现画线笔锋效果详细原理,根据这篇介绍的实现笔锋效果的原理,我们很容易实现另外一种笔效:钢笔. 所谓的钢笔笔效,就是真实还原钢笔书写出来的线条效果,其特征就是:根据笔的绘制速度而线条的宽度会逐渐变化,写得越快,线条越细,并且在收笔时带有笔锋效果. 那么,在上一篇文章的基础上,稍微修改一下,就可以实现这个效果,看下效果图: 实现原理 从上一篇文章我们知道,绘制的曲线是通过每两个点形成一条贝塞尔曲线,所以在不松手的情况下连续画线,整条线段是包含很多条path组合而成的.而要实

  • Qt 实现画线笔锋效果详细原理及示例代码

    前言 之前写过一篇文章介绍Qt中绘制平滑曲线的两种方式,文章在这里.这篇文章详细介绍了绘制的原理和实现方式,那么,如果要在此曲线上实现笔锋效果怎么做呢? 所谓的笔锋效果,就是钢笔书写抬笔时的笔尖,也就是说,绘制曲线抬笔时形成一个笔尖的效果. 话不多说,直接来看效果: 动画效果如下: 实现原理 要实现该效果,需要完成以下几个关键步骤: 1.每两个点形成一个贝塞尔曲线path进行绘制 2.最新的一条path绘制细线(笔锋最细处的宽度) 3.倒数第二条path绘制粗线(正常的线条宽度) 4.在两条pa

  • 使用QPainter画一个3D正方体

    本文实例为大家分享了QPainter画一个3D正的具体代码,供大家参考,具体内容如下 My3DBox .h #include <Eigen/Geometry> using namespace Eigen; #define SQUARE_LENGTH 200//是一个边长200的正方体 #define CAMERA_DISTANCE 300//视点距离 class My3DBox : public QWidget { Q_OBJECT public: explicit My3DBox(QWidg

  • 利用three.js画一个3D立体的正方体示例代码

    简介 three.js 是一款WebGL框架,WebGL可以让我们在canvas上实现3D效果.实现3D效果在国内来说还算是比较新的东西,可供查阅的资料也不多.这篇文章仅是一个入门篇,介绍如何绘制一个3D正方体. Three.js中的基本概念 Three.js包含3个基本概念:场景(Scene).相机(Camera)和渲染器(Renderer). 场景就是需要绘制的对象,相机代表取景的视角,渲染器是绘制的载体(可以挂靠到浏览器的DOM元素中), 也就是我们通过相机拍摄场景然后绘制到目标介质中去.

  • 如何用C语言画一个“圣诞树”

    如何用C语言画一个"圣诞树",我使用了左右镜像的Sierpinski triangle,每层减去上方一小块,再用符号点缀.可生成不同层数的「圣诞树」,如下图是5层的结果 #include <stdlib.h> int main(int argc, char* argv[]) { int n = argc > 1 ? atoi(argv[1]) : 4; for (int j = 1; j <= n; j++) { int s = 1 << j, k

  • Android自定义view之3D正方体效果实例

    目录 前言 一.小提 二.将传感器改成事件分发机制 三.使用 四.源码 总结 前言 在之前写了一篇关于3D效果的文章,借助传感器展示,有小伙伴问可不可以改成手势滑动操作(事件分发),所以出一篇文章 传感器相关文章链接:Android 3D效果的实现 一.小提 相对于常见的自定义view而言,继承的GLSurfaceView只有两个构造函数.可以理解为没有提供获取自定义属性的方法. public TouchSurfaceView(Context context) { super(context);

  • python之用Numpy和matplotlib画一个魔方

    目录 前言 开搞! 构建体素 制作间隙效果 为每个面赋不同的颜色 完整代码 瞎鼓捣系列~ Numpy + matplotlib 画一个魔方 前言 NumPy是Python科学计算的基本包.它是一个Python库,提供了多维数组对象.各种派生对象(如掩码数组和矩阵),以及用于对数组进行快速操作的各种例程,包括数学.逻辑.形状操作.排序.选择.I/O.离散傅里叶变换.基本线性代数.基本的统计运算,随机模拟等等. github 官方文档 最近项目中有个码垛规划的需求,Numpy中的三维数组特别好用,就

  • 教你使用html+css制作一个3D立体相册

    目录 前言 一.先看效果 二.实现步骤 总结 前言 用css的transform属性做一个3D相册~~~值translate表示偏移:scale表示缩放:rotate就是转动. 一.先看效果 二.实现步骤 1.我们知道一个正方体有6个面,所以定义一个父亲元素然后定义6个子元素作为6个面.每个面放一张图片.里面q1表示前面,h2表示后面,以此类推,就是首拼音. <div class="baba"> <div class="q1"> <im

  • Python使用matplotlib实现在坐标系中画一个矩形的方法

    本文实例讲述了Python使用matplotlib实现在坐标系中画一个矩形的方法.分享给大家供大家参考.具体实现方法如下: import matplotlib.pyplot as plt from matplotlib.patches import Rectangle class Annotate(object): def __init__(self): self.ax = plt.gca() self.rect = Rectangle((0,0), 1, 1) self.x0 = None s

  • vue+vuex+axios+echarts画一个动态更新的中国地图的方法

    本文介绍了vue+vuex+axios+echarts画一个动态更新的中国地图的方法,分享给大家,具体如下: 一. 生成项目及安装插件 # 安装vue-cli npm install vue-cli -g # 初始化项目 vue init webpack china-map # 切到目录下 cd china-map # 安装项目依赖 npm install # 安装 vuex npm install vuex --save # 安装 axios npm install axios --save

  • python turtle库画一个方格和圆实例

    使用python的turtle库画一个方格和圆 打开python编译器,导入turtle库 from turtle import * 首先画一个距离为100的横线 forward(100) 顺时针旋转90度,前进100 在通过两次的旋转和平移得到方格,使用for循环重复两次 抬起笔,直接到方格的中间,也就是(50,0)坐标 penup() goto(50,0) 开始画半径为50的圆,放下笔 pendown() circle(50) 在圆的中心画个圆心点 goto(50,50) dot() 最后隐

  • python 图像处理画一个正弦函数代码实例

    这篇文章主要介绍了python 图像处理画一个正弦函数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 import numpy as np from PIL import Image import matplotlib.pyplot as plt import math size = 300 new_im = Image.new("RGBA",(size,size)) #创建一个空的图片 a_img = np.array(ne

随机推荐