当前位置:网站首页>七夕专属博文-使用QGraphics画“红心“或“黑心“(含数学模型讲解)
七夕专属博文-使用QGraphics画“红心“或“黑心“(含数学模型讲解)
2022-08-01 15:34:00 【IT1995】
说明
实现的效果是这样的,使用QGraphicsEllipseItem和QGraphicsPolygonItem画“心”。
比如来个红心

再来个“黑心”:

“心形”模型详解
这里需要用到高中数学。
①要了解圆的参数方程,其公式是这样的:
x = a + r · cosθ 和 y = b + r · sinθ
其中(a, b)为圆心的坐标,r为圆的半径,θ是角度取值范围为[0, 2π]。
②在C++或各种语言里面有专门的sin、cos函数,在Qt框架里面使用QtMath的头文件。这里传的参数需要弧度,所以,而在数学里面,圆的参数方程里面传入的参数是角度,所以还要需要了解,角度转弧度公式:
弧度 = 角度 · (π / 180)
了解了公式后,下面来说下,这个爱心的画法:
首先是画两个带角度的圆。
左边的圆:角度是从0度到225度。
右边的圆:角度是从-45度到180度。
如下图:

然后找到2个圆心点,用圆的参数方程,找边上的2个点

再到两圆之间找法线上找任意一点:

通过这5个点构造多边形,如下:

这样将这3个图形组合起来,就是一个“心”了。

代码解析
程序结构如下:

源码如下:
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QGraphicsScene;
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void drawCricle(int x, int y, int height, int width, int startAngle, int endAngle);
void drawPolygon();
private:
Ui::Widget *ui;
QGraphicsScene *m_scene;
};
#endif // WIDGET_H
main.cpp
#include "Widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Widget.cpp
#include "Widget.h"
#include "ui_Widget.h"
#include <QGraphicsEllipseItem>
#include <QGraphicsPolygonItem>
#include <QPolygonF>
#include <QPen>
#include <iostream>
#include <QtMath>
#include <QGraphicsScene>
#include <QDebug>
#include <QPoint>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->graphicsView->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
m_scene = new QGraphicsScene;
ui->graphicsView->setScene(m_scene);
drawCricle(-100, 0, 200, 200, 0, 360 * 10);
drawCricle(100, 0, 200, 200, 360 * 14, 360 * 10);
drawPolygon();
this->setWindowTitle("it1995.cn Designed by FengFanChen");
}
Widget::~Widget()
{
delete m_scene;
delete ui;
}
void Widget::drawCricle(int x, int y, int height, int width, int startAngle, int endAngle)
{
auto item(new QGraphicsEllipseItem(x, y, height, width));
item->setBrush(Qt::red);
item->setStartAngle(startAngle);
item->setSpanAngle(endAngle);
item->setPen(QPen(Qt::red));
m_scene->addItem(item);
}
void Widget::drawPolygon()
{
double oneCricleHeartX = -2.5;
double oneCricleHeartY = 95;
double oneX = oneCricleHeartX + 100 * cos(135 * ( M_PI /180));
double oneY = oneCricleHeartY + 100 * sin(135 * ( M_PI /180));
double endX = 100;
double endY = 100 + 200;
// auto item(new QGraphicsEllipseItem(x, y, 10, 10));
//auto item(new QGraphicsEllipseItem(100 - 5, 100 - 5 + 100, 10, 10));
// auto item(new QGraphicsEllipseItem(endX, endY, 10, 10));
// item->setBrush(Qt::blue);
// m_scene->addItem(item);
// auto line1Item(new QGraphicsLineItem(oneX, oneY + 2.5, endX + 1, endY + 1));
// m_scene->addItem(line1Item);
//第二个
double twoCricleHeartX = 200;
double twoCricleHeartY = 95;
// auto item(new QGraphicsEllipseItem(twoCricleHeartX - 5, twoCricleHeartY, 10, 10));
// item->setBrush(Qt::blue);
// m_scene->addItem(item);
double twoX = twoCricleHeartX + 100 * cos(45 * ( M_PI /180));
double twoY = twoCricleHeartY + 100 * sin(45 * ( M_PI /180));
// auto item(new QGraphicsEllipseItem(twoX - 5, twoY, 10, 10));
// item->setBrush(Qt::blue);
// m_scene->addItem(item);
// auto line2Item(new QGraphicsLineItem(twoX, twoY + 5, endX + 1, endY + 1));
// m_scene->addItem(line2Item);
auto polygonItem = (new QGraphicsPolygonItem());
QPolygonF pf;
pf.append(QPoint(endX + 1, endY + 1));
pf.append(QPoint(oneX + 2, oneY + 5));
pf.append(QPoint(oneCricleHeartX, oneCricleHeartY + 5));
pf.append(QPoint(twoCricleHeartX, twoCricleHeartY + 5));
pf.append(QPoint(twoX, twoY + 5));
polygonItem->setPolygon(pf);
polygonItem->setPen(QPen(Qt::red));
polygonItem->setBrush(Qt::red);
m_scene->addItem(polygonItem);
}有几个关键点要说:
①QGraphic的坐标系和数学里面的不一样,他和屏幕里面的坐标一样,y轴下方为正,y轴上方为负。
②在QGraphicsEllipseItem中有按角度画圆的函数:
void QGraphicsEllipseItem::setStartAngle(int angle)
Sets the start angle for an ellipse segment to angle, which is in 16ths of a degree. This angle is used together with spanAngle() for representing an ellipse segment (a pie). By default, the start angle is 0.从官方文档可以知道,他扩大了16倍,也就是说360 * 16是直角坐标系的360,所以如果是90度的角度,就是90 * 16。
③代码里面的这些代码:
QPolygonF pf;
pf.append(QPoint(endX + 1, endY + 1));
pf.append(QPoint(oneX + 2, oneY + 5));
pf.append(QPoint(oneCricleHeartX, oneCricleHeartY + 5));
pf.append(QPoint(twoCricleHeartX, twoCricleHeartY + 5));
pf.append(QPoint(twoX, twoY + 5));这些+1,+2,+5是用来调节的,避免算点时因为精度丢失,导致要画的“心”不好看。
源码打包下载
地址如下:
边栏推荐
猜你喜欢
随机推荐
SSM入门
【Untitled】
Timezone setting in MySQL
LeetCode50天刷题计划(Day 10—— 三数之和(20.50-22.40)
2.8K 120Hz touch dual-screen blessing Lingyao X dual-screen Pro 2022 makes the office without fear of imagination
JSON数据转换总结(VIP典藏版)
MySQL中字符串比较大小(日期字符串比较问题)
给网站增加离开页面改变网站标题效果
mysql 面试题
你真的会测试用户登录吗?
主流定时任务解决方案全横评
【LeetCode】37、解数独
Range query based on date in MySQL
全网最全音视频媒体流
kubelet node pressure eviction
百图生科卓越开发者计划全面升级暨《计算免疫问题白皮书》发布
wordpress模板函数说明备注整理收藏
Chapter 13 Manually create a REST service (1)
未来小间距竞争的着力点在哪里
行程排序(暑假每日一题 12)









