700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 图形学和计算机辅助设计(CAD)课程大作业-线对象选择与Snap

图形学和计算机辅助设计(CAD)课程大作业-线对象选择与Snap

时间:2022-01-16 12:47:31

相关推荐

图形学和计算机辅助设计(CAD)课程大作业-线对象选择与Snap

下面是计算机图形学和计算机辅助设计大作业记录,实现的是线和圆弧的pick及snap功能,绘制使用的是QPainter,参考的AutoCAD的snap逻辑,原理是计算projectPoint, 即鼠标位置和curve的距离,当小于snapbox的尺寸时,修改snapbox的位置,操作时感觉靠近曲线磁吸过去了。

QXViewWgt .h

#pragma once#include <QWidget>#include "ui_QXViewWgt.h"class QXViewWgt : public QWidget{Q_OBJECTpublic:QXViewWgt(QWidget *parent = Q_NULLPTR);~QXViewWgt();void paintEvent(QPaintEvent* event);void mouseMoveEvent(QMouseEvent* event);void mousePressEvent(QMouseEvent* event);private:Ui::QXViewWgt ui;};

QXViewWgt .cpp

#include "QXViewWgt.h"#include <QtGui/QPainter>#include <QMouseEvent>#include <Eigen/Eigen>#include <vector>#include <memory>#define _USE_MATH_DEFINES#include <math.h>const double MIN_DIST = 1e-4;namespace vege{static QPainter* s_painter = nullptr;enum CurveState{CST_DEFAULT,CST_SNAPPED,CST_PICKED};class Curve2d{protected:CurveState _state;public:Curve2d():_state(CST_DEFAULT){}virtual ~Curve2d() {}virtual bool projectPoint(Eigen::Vector2d p, Eigen::Vector2d& q) = 0;virtual void paint() = 0;virtual void setState(CurveState s) {if (_state == CST_PICKED && _state != s){int k = 0;}_state = s; };virtual bool stateIs(CurveState s){return _state == s;};};class Line2d : public Curve2d{public:Eigen::Vector2d _s;Eigen::Vector2d _e;Line2d(Eigen::Vector2d s, Eigen::Vector2d e):_s(s), _e(e){}virtual bool projectPoint(Eigen::Vector2d p, Eigen::Vector2d& q){Eigen::Vector2d d = _e - _s;double v_se_length = d.norm();d.normalize();auto v_sp = p - _s;auto v_sq_length = (p - _s).dot(d);if (fabs(v_sq_length) < MIN_DIST){q = _s;return true;}if (fabs(v_sq_length -v_se_length) < MIN_DIST){q = _e;return true;}if (v_sq_length > 0.0 && v_sq_length < v_se_length){q = _s + d * v_sq_length;return true;}q = {0, 0 };return false;}virtual void paint(){switch (_state){case CST_DEFAULT:{QPen pen0;pen0.setColor(QColor(255, 255, 255));pen0.setWidth(1);s_painter->setPen(pen0);s_painter->drawLine(_s(0), _s(1), _e(0), _e(1));}break;case CST_SNAPPED:{QPen pen0;pen0.setColor(QColor(255, 255, 255));pen0.setWidth(4);s_painter->setPen(pen0);s_painter->drawLine(_s(0), _s(1), _e(0), _e(1));pen0.setColor(QColor(0, 0, 0));pen0.setWidth(2);pen0.setStyle(Qt::DotLine);s_painter->setPen(pen0);s_painter->drawLine(_s(0), _s(1), _e(0), _e(1));}break;case CST_PICKED:{QPen pen0;pen0.setColor(QColor(255, 0, 255));pen0.setWidth(2);s_painter->setPen(pen0);s_painter->drawLine(_s(0), _s(1), _e(0), _e(1));}break;default:break;}}};class Arc2d : public Curve2d{public:Eigen::Vector2d _c;double _r;double _sang;double _eang;Arc2d(Eigen::Vector2d c, double r, double sang, double eang) :_c(c),_r(r),_sang(sang),_eang(eang){}double degToRad(double degv){return (degv*M_PI) / 180.0;}double radToDeg(double radv){return (radv*180.0) / M_PI;}Eigen::Vector2d startPoint(){return _c + Eigen::Vector2d(cos(degToRad(_sang)), sin(degToRad(_sang))) * _r;}Eigen::Vector2d endPoint(){return _c + Eigen::Vector2d(cos(degToRad(_eang)), sin(degToRad(_eang))) * _r;}double angle(){if (_eang > _sang){return _eang - _sang;}else{return 360.0 - _sang + _eang;}}virtual bool projectPoint(Eigen::Vector2d p, Eigen::Vector2d& q){Eigen::Vector2d d = p - _c;d.normalize();Eigen::Vector2d s = startPoint();if ((s - p).norm() < 1e-4){q = s;return true;}Eigen::Vector2d e = endPoint();if ((e - p).norm() < 1e-4){q = e;return true;}bool on_flag = false;double t = radToDeg(acos(d[0]));if (d[1] < 0.0){t = 360.0 - t;if (t > 360.0){t -= 360.0;}}if (_eang > _sang){if (t > _sang && t < _eang){on_flag = true;}}else{if ((t > _sang && t < 360.0) ||(t >= 0.0 && t < _eang)){on_flag = true;}}if (on_flag){q = _c + d * _r;return true;}q = {0, 0 };return false;}virtual void paint(){switch (_state){case CST_DEFAULT:{QPen pen0;pen0.setColor(QColor(255, 255, 255));pen0.setWidth(1);s_painter->setPen(pen0);s_painter->drawArc(_c[0] - _r, _c[1] - _r, 2.0*_r, 2.0*_r, -_sang*16, -angle()*16);}break;case CST_SNAPPED:{QPen pen0;pen0.setColor(QColor(255, 255, 255));pen0.setWidth(4);s_painter->setPen(pen0);s_painter->drawArc(_c[0] - _r, _c[1] - _r, 2.0*_r, 2.0*_r, -_sang * 16, -angle() * 16);pen0.setColor(QColor(0, 0, 0));pen0.setWidth(2);pen0.setStyle(Qt::DotLine);s_painter->setPen(pen0);s_painter->drawArc(_c[0] - _r, _c[1] - _r, 2.0*_r, 2.0*_r, -_sang * 16, -angle() * 16);}break;case CST_PICKED:{QPen pen0;pen0.setColor(QColor(255, 0, 255));pen0.setWidth(2);s_painter->setPen(pen0);s_painter->drawArc(_c[0] - _r, _c[1] - _r, 2.0*_r, 2.0*_r, -_sang * 16, -angle() * 16);}break;default:break;}}};}// end of namespace vegeEigen::Vector2d _mosPos(0.0,0.0);double _mosBoxHalfSize = 12;double _snapSize = 1.414*_mosBoxHalfSize;std::vector<vege::Curve2d*> _curves;vege::Curve2d* _snappedCurve = nullptr;vege::Curve2d* _pickedCurve = nullptr;using namespace vege;QXViewWgt::QXViewWgt(QWidget *parent): QWidget(parent){ui.setupUi(this);_curves.push_back(new Line2d({20,100 }, {1200,100 }));_curves.push_back(new Line2d({30,180 }, {955,800 }));_curves.push_back(new Arc2d({450,400 }, 200, 180, 45 ));}QXViewWgt::~QXViewWgt(){for (auto& curv : _curves){delete curv;}}void QXViewWgt::mousePressEvent(QMouseEvent* event){if (_snappedCurve){if (_pickedCurve == nullptr && _pickedCurve != _snappedCurve){_pickedCurve = _snappedCurve;_pickedCurve->setState(CST_PICKED);}}else{if (_pickedCurve){_pickedCurve->setState(CST_DEFAULT);_pickedCurve = nullptr;}}update();}void QXViewWgt::mouseMoveEvent(QMouseEvent* event){_mosPos(0) = event->pos().x();_mosPos(1) = event->pos().y();Curve2d* curSnapped = nullptr;for (auto& curve : _curves){QPen pen0;Eigen::Vector2d pt_q;bool issucess = curve->projectPoint(_mosPos, pt_q);if (issucess){double dist = (pt_q - _mosPos).norm();if (dist < _snapSize){_mosPos = pt_q;curSnapped = curve;break;}}}if (curSnapped){if (_pickedCurve && _pickedCurve == curSnapped){_snappedCurve = curSnapped;}else{if (_snappedCurve){if (_snappedCurve->stateIs(CST_SNAPPED)){_snappedCurve->setState(CST_DEFAULT);}}_snappedCurve = curSnapped;if (_snappedCurve->stateIs(CST_DEFAULT)){_snappedCurve->setState(CST_SNAPPED);}}}else{if (_snappedCurve){if (_snappedCurve->stateIs(CST_SNAPPED)){_snappedCurve->setState(CST_DEFAULT);}_snappedCurve = nullptr;}}this->update();}void QXViewWgt::paintEvent(QPaintEvent* event){QPainter painter(this);vege::s_painter = &painter;painter.fillRect(0, 0, this->width(), this->height(), Qt::black);// draw curvesfor (auto& curve : _curves){curve->paint();}// draw snap boxQPen pen;pen.setColor(QColor(255, 255, 255));pen.setWidth(2);painter.setPen(pen);painter.drawRect(_mosPos(0) - _mosBoxHalfSize, _mosPos(1) - _mosBoxHalfSize, _mosBoxHalfSize * 2, _mosBoxHalfSize * 2);painter.end();}

截图

1.绘制一些线和圆弧

2.当鼠标靠近线,线高亮,同时鼠标吸到线上,鼠标在snapbox范围轻微移动,将保持吸靠到线不变

3.此时单击线将被选中

4.单击空白处,将取消选中的线,整个操作逻辑符合AutoCAD的pick-snap风格

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。