diff --git a/data.cpp b/data.cpp deleted file mode 100644 index d0023c9..0000000 --- a/data.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "data.h" -#include -#include -#include -#include -#include - -Data::Data(QWindow *parent) : QQuickView( parent ) { - heading = 0; - pitch = 0; - roll = 0; - qDebug() << "[Info] Start to Show!" ; - - this->rootContext()->setContextProperty("dataSource", this); - this->rootContext()->setContextProperty("window", this); - QIcon icon = QIcon(QStringLiteral(":/img/compass.ico")); - this->setIcon(icon); - // 设置窗口缩放时,根对象也会随之缩放 - this->setResizeMode(QQuickView::SizeRootObjectToView); - this->setTitle("Compass heading pitch & roll"); - - // using a cfg file to change mode dynamically - QSettings setting( "compass.ini", QSettings::IniFormat, this ); - int mode = setting.value( "mode", 0 ).toInt(); - - QUrl source; - switch (mode) { - case 1: - source = QUrl( "qrc:/qml/Compass.qml" ); - break; - case 0: - default: - source = QUrl( "qrc:/qml/SpacePath.qml" ); - break; - } - this->setSource( source ); - - int interval = setting.value( "interval", 500 ).toInt(); - QTimer *timer = new QTimer( this ); - connect( timer, &QTimer::timeout, this, &Data::changeData ); - timer->setInterval( interval ); -// timer->start( 100 ); -} - -Data::~Data() { -} - -bool Data::event(QEvent *event) { - if( event->type() == QEvent::Close ) { - // on my deepin system, the program always quit with segment fault - // so it is used to tell Qt to delete itself without error - this->deleteLater(); - return false; - } - return QQuickView::event( event ); -} - -double Data::getHeading() { - return heading; -} - -double Data::getPitch() { - return pitch; -} - -double Data::getMagicVectorLength() { - return 10000*(4); -} - -double Data::getRoll() { - return roll; -} - -void Data::changeData() { - double weight = 0.00003; - pitch += 0.2274 + qrand() * weight; - heading += 0.5252 + qrand() * weight; - roll += 1.3417 + qrand() * weight; - emit dataChanged(); -} - diff --git a/data.h b/data.h deleted file mode 100644 index fd76f2b..0000000 --- a/data.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef DATA_H -#define DATA_H - -#include -#include -#include - -class Data : public QQuickView{ - Q_OBJECT - -public: - Data(QWindow *parent = Q_NULLPTR); - ~Data(); - bool event(QEvent *event); - Q_INVOKABLE double getHeading(); - Q_INVOKABLE double getPitch(); - Q_INVOKABLE double getRoll(); - Q_INVOKABLE double getMagicVectorLength(); - -private: - double heading; - double pitch; - double roll; - -signals: - void dataChanged(); - -public slots: - - void changeData(); -}; - -#endif // DATA_H diff --git a/examples/DataTransfer/MainWindow.cpp b/examples/DataTransfer/MainWindow.cpp index 7cc8e85..42d47d9 100644 --- a/examples/DataTransfer/MainWindow.cpp +++ b/examples/DataTransfer/MainWindow.cpp @@ -1,5 +1,6 @@ -#include "MainWindow.h" +#include "MainWindow.h" #include "ui_MainWindow.h" +#define REMOTE_PORT 16650 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), @@ -12,3 +13,55 @@ MainWindow::~MainWindow() { delete ui; } + +bool MainWindow::init() +{ + displayer = new Displayer3D(0); + bool inited = displayer->init(); + if(inited) { +// displayer->getView()->settings()->setAttribute( QWebEngineSettings::Accelerated2dCanvasEnabled, false); + displayer->show(); + QObject::connect(displayer, &Displayer3D::closed, this, &QObject::deleteLater); + + m_socket.connectToHost("localhost", REMOTE_PORT); + m_socket.write("PC:"); + QTimer::singleShot(30000, [=] { + m_socket.write("31"); + }); + connect(displayer->getView(), &QWebEngineView::loadFinished, [=] { + connect(&m_socket, &QTcpSocket::readyRead, this, &MainWindow::read); + }); + m_feeder = displayer->getDataFeeder(); + } + return inited; +} + +void MainWindow::read() +{ + QByteArray tmpData = m_socket.readAll(); // format is: { "heading": 0, "pitch": 0 ...} + QByteArrayList tmpDatas = tmpData.split('\n'); + foreach (QByteArray td, tmpDatas) { + QJsonDocument doc = QJsonDocument::fromJson(td); + QJsonObject obj = doc.object(); + // qDebug() << doc; + // qDebug() << tmpData.data(); + ui->textEdit->append(QString(tmpData)); + double heading = obj.value("heading").toDouble(); + double pitch = obj.value("pitch").toDouble(); + double roll = obj.value("roll").toDouble(); + ui->textEdit->append(QString("H: %1, P:%2").arg(heading).arg(pitch)); + m_feeder->setHprData(heading, + pitch, + roll); + } +} + +WebDataFeeder *MainWindow::feeder() const +{ + return m_feeder; +} + +void MainWindow::setFeeder(WebDataFeeder *feeder) +{ + m_feeder = feeder; +} diff --git a/examples/DataTransfer/MainWindow.h b/examples/DataTransfer/MainWindow.h index a3948a9..84d7c59 100644 --- a/examples/DataTransfer/MainWindow.h +++ b/examples/DataTransfer/MainWindow.h @@ -1,8 +1,13 @@ -#ifndef MAINWINDOW_H +#ifndef MAINWINDOW_H #define MAINWINDOW_H #include - +#include +#include +#include +#include +#include +#include namespace Ui { class MainWindow; } @@ -14,7 +19,18 @@ class MainWindow : public QMainWindow public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); +public: + bool init(); + WebDataFeeder *feeder() const; + void setFeeder(WebDataFeeder *feeder); +public Q_SLOTS: + void read(); +public: + Displayer3D *displayer; +private: + WebDataFeeder *m_feeder; + QTcpSocket m_socket; private: Ui::MainWindow *ui; }; diff --git a/examples/DataTransfer/MainWindow.ui b/examples/DataTransfer/MainWindow.ui index 6050363..48774ba 100644 --- a/examples/DataTransfer/MainWindow.ui +++ b/examples/DataTransfer/MainWindow.ui @@ -1,7 +1,8 @@ + MainWindow - - + + 0 0 @@ -9,16 +10,37 @@ 300 - + MainWindow - - - - + + + + + + + + + + + 0 + 0 + 400 + 23 + + + + + + TopToolBarArea + + + false + + + - - + diff --git a/examples/DataTransfer/main.cpp b/examples/DataTransfer/main.cpp index 9486323..3d8b58c 100644 --- a/examples/DataTransfer/main.cpp +++ b/examples/DataTransfer/main.cpp @@ -1,76 +1,21 @@ #include "MainWindow.h" #include -#include -#include -#include -#include -#include -#include -#include - -#define REMOTE_PORT 8811 /** 通过串口传递数据 */ -class DataRecver:public QObject { - -public: - bool init() { - displayer = new Displayer3D(0); - bool inited = displayer->init(); - if(inited) { - // displayer->getView()->settings()->setAttribute( QWebEngineSettings::Accelerated2dCanvasEnabled, false); - displayer->show(); - QObject::connect(displayer, &Displayer3D::closed, this, &QObject::deleteLater); - - m_socket.connectToHost("localhost", REMOTE_PORT); - connect(displayer->getView(), &QWebEngineView::loadFinished, [=] { - connect(&m_socket, &QTcpSocket::readyRead, this, &DataRecver::read); - }); - m_feeder = displayer->getDataFeeder(); - } - return inited; - } - WebDataFeeder *feeder() const; - void setFeeder(WebDataFeeder *feeder); - -public Q_SLOTS: - void read() { - QByteArray tmpData = m_socket.readAll(); // format is: { "heading": 0, "pitch": 0 ...} - QJsonDocument doc = QJsonDocument::fromJson(tmpData); - QJsonObject obj = doc.object(); -// qDebug() << doc; - m_feeder->setHprData(obj.value("heading").toDouble(), - obj.value("pitch").toDouble(), - obj.value("roll").toDouble()); - } -public: - Displayer3D *displayer; -private: - WebDataFeeder *m_feeder; - QTcpSocket m_socket; -}; -WebDataFeeder *DataRecver::feeder() const -{ - return m_feeder; -} - -void DataRecver::setFeeder(WebDataFeeder *feeder) -{ - m_feeder = feeder; -} int main(int argc, char *argv[]) { QApplication a(argc, argv); - DataRecver *dr = new DataRecver(); + MainWindow *mw = new MainWindow(); - if(dr->init()) { - QObject::connect(dr->displayer, &Displayer3D::closed, &a, &QApplication::quit); + if(mw->init()) { + mw->show(); + QObject::connect(mw->displayer, &Displayer3D::closed, &a, &QApplication::quit); int result = a.exec(); return result; } diff --git a/examples/QMLDataTransfer/DataTransfer.cpp b/examples/QMLDataTransfer/DataTransfer.cpp new file mode 100644 index 0000000..6a58798 --- /dev/null +++ b/examples/QMLDataTransfer/DataTransfer.cpp @@ -0,0 +1,69 @@ +#include "DataTransfer.h" +#include "Animation.h" +#include +#include +#include + +DataTransfer::DataTransfer(QObject *parent) : QObject(parent), + animation(new Animation) +{ + animation->setMinimumSize(QSize(800, 600)); + QUrl url(QStringLiteral("qrc:/qml/SpacePath.qml")); + animation->setSource(url); + + socket = new QUdpSocket(this); + socket->open(QUdpSocket::ReadWrite); +// socket->setSocketOption(QUdpSocket::ReuseAddressHint, 1); + connect(socket, &QUdpSocket::readyRead, this, &DataTransfer::recv); + +} + +DataTransfer::~DataTransfer() +{ + delete animation; +} + +void DataTransfer::start() +{ + socket->bind(QHostAddress::Any, 16650); + animation->show(); +} + +void DataTransfer::recv() +{ + // format is: { "heading": 0, "pitch": 0 ...} + QByteArray datagram; + while(socket->hasPendingDatagrams()) { + int size = socket->pendingDatagramSize(); + datagram.resize(size); + socket->readDatagram(datagram.data(), size); +// qDebug() << "recv" << datagram; + QJsonDocument doc = QJsonDocument::fromJson(datagram); + QJsonObject obj = doc.object(); +// qDebug() << doc; + QString type = obj.value("type").toString(); + if(type == "data") { + double heading = obj.value("heading").toDouble(); + double pitch = obj.value("pitch").toDouble(); + double roll = obj.value("roll").toDouble(); + double length = obj.value("length").toDouble() * 10000; + + animation->setParam(heading, pitch, roll, length); + } else if(type == "point") { + QString action = obj.value("action").toString(); + if(action == "remove") { + int i = obj.value("index").toInt(); + animation->removeRecordPoint(i); + } else if(action == "record") { + animation->toRecord(); + } + } else if(type == "state") { + QString title = obj.value("title").toString(); + bool threed = obj.value("threeD").toBool(); + animation->setTitle(title); + animation->threeDPropertyChanged(threed); + } + + } +} + diff --git a/examples/QMLDataTransfer/DataTransfer.h b/examples/QMLDataTransfer/DataTransfer.h new file mode 100644 index 0000000..9ada22f --- /dev/null +++ b/examples/QMLDataTransfer/DataTransfer.h @@ -0,0 +1,28 @@ +#ifndef DATATRANSFER_H +#define DATATRANSFER_H + +#include +#include + +class Animation; + +class DataTransfer : public QObject +{ + Q_OBJECT +public: + explicit DataTransfer(QObject *parent = 0); + ~DataTransfer(); + +signals: + +public slots: + void start(); +protected slots: + void recv(); + +private: + Animation *animation = 0; + QUdpSocket *socket; +}; + +#endif // DATATRANSFER_H diff --git a/examples/QMLDataTransfer/MainWindow.ui b/examples/QMLDataTransfer/MainWindow.ui new file mode 100644 index 0000000..6050363 --- /dev/null +++ b/examples/QMLDataTransfer/MainWindow.ui @@ -0,0 +1,24 @@ + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + MainWindow + + + + + + + + + + + diff --git a/examples/QMLDataTransfer/QMLDataTransfer.pro b/examples/QMLDataTransfer/QMLDataTransfer.pro new file mode 100644 index 0000000..e5ea096 --- /dev/null +++ b/examples/QMLDataTransfer/QMLDataTransfer.pro @@ -0,0 +1,39 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-06-18T20:29:46 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = QMLDataTransfer +TEMPLATE = app + +VERSION=1.0.0.0 + +RC_ICONS = ./compass.ico + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += main.cpp\ + DataTransfer.cpp + +HEADERS += \ + DataTransfer.h + +FORMS += MainWindow.ui +include($$(DISPLAYER_DIR)/libdisplayqml.pri) + +message($$(DISPLAYER_DIR)/libdisplayqml.pri) diff --git a/img/compass.ico b/examples/QMLDataTransfer/compass.ico similarity index 100% rename from img/compass.ico rename to examples/QMLDataTransfer/compass.ico diff --git a/examples/QMLDataTransfer/main.cpp b/examples/QMLDataTransfer/main.cpp new file mode 100644 index 0000000..68b83ed --- /dev/null +++ b/examples/QMLDataTransfer/main.cpp @@ -0,0 +1,21 @@ +#include "DataTransfer.h" +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QString ini = QDir::homePath() + "/compassRelative.ini"; + QSettings setting(ini, QSettings::IniFormat); + setting.beginGroup("path"); + setting.setValue("QMLDataTransfer", a.applicationFilePath()); + setting.endGroup(); + + DataTransfer dt; + dt.start(); + + return a.exec(); +} diff --git a/icon.rc b/icon.rc index f271c80..d844efe 100644 --- a/icon.rc +++ b/icon.rc @@ -1 +1 @@ -IDI_ICON1 ICON DISCARDABLE "./img/compass.ico" +IDI_ICON1 ICON DISCARDABLE "./res/img/compass.ico" diff --git a/include/Animation.h b/include/Animation.h new file mode 100644 index 0000000..35dd1ed --- /dev/null +++ b/include/Animation.h @@ -0,0 +1,69 @@ +#ifndef ANIMATION_H +#define ANIMATION_H + +#include +#include +#include + +#include "display_global.h" + +class AnimationDataObject : public QObject { + Q_OBJECT + Q_PROPERTY(double heading READ getHeading NOTIFY dataChanged) + Q_PROPERTY(double pitch READ getPitch NOTIFY dataChanged) + Q_PROPERTY(double roll READ getRoll NOTIFY dataChanged) + Q_PROPERTY(double vectorLength READ getLength NOTIFY dataChanged) + + friend class Animation; +signals: + void dataChanged(); +// void dataChanged(const MagParam ¶ms); +public: + Q_INVOKABLE double getHeading() { + return m_heading; + } + + Q_INVOKABLE double getPitch() { + return m_pitch; + } + + Q_INVOKABLE double getRoll() { + return m_roll; + } + + Q_INVOKABLE double getLength() { + return m_length; + } + +private: + double m_heading; + double m_pitch; + double m_roll; + double m_length; + +}; + +class DISPLAY_DLL_EXPORT Animation : public QQuickView +{ + Q_OBJECT +public: + explicit Animation(QWindow *parent = 0); + +public slots: + void setParam(const double heading, const double pitch, const double roll, const double length); +signals: + void toRecord(bool isCSource = false); + void removeRecordPoint(int iSet); + void threeDPropertyChanged(bool spacePath); + + void stateChanged(bool render); + +protected: + void onWindowStateChange(Qt::WindowState windowState); + void hideEvent(QHideEvent *) override; + + AnimationDataObject *ado; + +}; + +#endif // DATA_H diff --git a/libdisplay.pro b/libdisplay.pro index baac85b..c0e27c7 100644 --- a/libdisplay.pro +++ b/libdisplay.pro @@ -8,7 +8,6 @@ TARGET = display QT += core gui widgets CONFIG += c++11 -#DEFINES += QUICKVIEW DEFINES += WEBVIEW DESTDIR = $$PWD/lib/ @@ -21,32 +20,7 @@ CONFIG(debug, debug|release) { HEADERS += include/display_global.h \ include/Displayer3d.h -contains(DEFINES, QUICKVIEW) { -QT += qml quick -# Additional import path used to resolve QML modules in Qt Creator's code model -#QML_IMPORT_PATH = - -RESOURCES += qml.qrc - -SOURCES += data.cpp -HEADERS += data.h - -DISTFILES += \ - qml/Button.qml \ - qml/Pitch.qml \ - qml/MySlider.qml \ - qml/DataSource.js \ - qml/gl-matrix.js \ - qml/SpacePath.js \ - qml/Compass.qml \ - qml/ScrollBar.qml \ - qml/SpacePath.qml \ - qml/OBJLoader.js \ - qml/SPVertexCode.vsh \ - qml/SPFragCode.fsh -} # contains(DEFINES, QUICKVIEW) -contains(DEFINES, WEBVIEW) { #message($$DEFINES) QT += websockets @@ -59,7 +33,6 @@ SOURCES += src/WebDataFeeder.cpp \ HEADERS += include/WebDataFeeder.h \ include/TestFeeder.h -} #contains(DEFINES, WEBVIEW) RC_FILE = icon.rc diff --git a/libdisplayqml.pri b/libdisplayqml.pri new file mode 100644 index 0000000..b9b1d42 --- /dev/null +++ b/libdisplayqml.pri @@ -0,0 +1,27 @@ +CONFIG += c++11 +QT += printsupport +QT += qml quick + +contains(DEFINES, _NO_LINK_DISPLAY_LIB) { +} else { +LIBS += -L"$$(DISPLAYER_DIR)/lib" + +CONFIG(debug, debug|release) { + LIBS += -l"QmlLibDisplayd" + DEFINES += _DISPLAY_DEBUG +} else { + LIBS += -l"QmlLibDisplay" + DEFINES += _DISPLAY_RELEASE +}# CONFIG(debug, debug|release) +} + +INCLUDEPATH += $$PWD/include + +CONFIG += debug_and_release +DEPENDPATH += . + +MOC_DIR = ./qt/moc +RCC_DIR = ./qt/rcc/src +UI_DIR = ./qt/ui +UI_HEADERS_DIR = ./qt/ui/include +UI_SOURCES_DIR = ./qt/ui/src diff --git a/libdisplayqml.pro b/libdisplayqml.pro new file mode 100644 index 0000000..400f608 --- /dev/null +++ b/libdisplayqml.pro @@ -0,0 +1,44 @@ +DISPLAY_VER = 0.1.12 + +DEFINES += _NO_LINK_DISPLAY_LIB DISPLAY_LIBRARY +include(./libdisplayqml.pri) +TEMPLATE = lib + +QT += core gui widgets +CONFIG += c++11 + + +DESTDIR = $$PWD/lib/ +CONFIG(debug, debug|release) { + TARGET = QmlLibDisplayd +} else { + TARGET = QmlLibDisplay +} + +HEADERS += include/display_global.h \ + include/Animation.h + +# Additional import path used to resolve QML modules in Qt Creator's code model +#QML_IMPORT_PATH = + +RESOURCES += qml.qrc + +SOURCES += \ + src/Animation.cpp +HEADERS += + +DISTFILES += \ + qml/Button.qml \ + qml/Pitch.qml \ + qml/MySlider.qml \ + qml/DataSource.js \ + qml/gl-matrix.js \ + qml/SpacePath.js \ + qml/Compass.qml \ + qml/ScrollBar.qml \ + qml/SpacePath.qml \ + qml/OBJLoader.js \ + qml/SPVertexCode.vsh \ + qml/SPFragCode.fsh + +RC_FILE = icon.rc diff --git a/qml.qrc b/qml.qrc index 3134ded..91ef0b8 100644 --- a/qml.qrc +++ b/qml.qrc @@ -1,19 +1,9 @@ - img/compass_roll_circle.png - img/compass.png - img/compass.ico - img/compass_pr_base.png - img/heading.png qml/SpacePath.qml qml/MySlider.qml qml/Compass.qml qml/SpacePath.js - img/x.png - img/y.png - img/z.png - img/arrow.png - obj/craft.obj qml/ScrollBar.qml qml/webgl-obj-loader.min.js qml/SPFragCode.fsh @@ -21,5 +11,15 @@ qml/gl-matrix-min.js qml/gl-matrix.js qml/webgl-obj-loader.js + res/img/arrow.png + res/img/compass.ico + res/img/compass.png + res/img/compass_pr_base.png + res/img/compass_roll_circle.png + res/img/heading.png + res/img/x.png + res/img/y.png + res/img/z.png + res/obj/craft.obj diff --git a/qml/Compass.qml b/qml/Compass.qml index 410fb67..d4c7b9b 100644 --- a/qml/Compass.qml +++ b/qml/Compass.qml @@ -8,6 +8,8 @@ Item { height: 600 id: container + property bool draw: true + /* 矩形,用于设置背景色 */ Rectangle { z: -10 @@ -40,7 +42,7 @@ Item { width: getScaledSize(449) height: getScaledSize(449) smooth: true - source: "/img/heading.png" + source: "/res/img/heading.png" rotation: -headingItem.headingAngle } @@ -91,8 +93,8 @@ Item { // 设置俯仰角的圆的半径 property real radius: stdradius / 1000 * container.width - property string rollCircleImg : "/img/compass_roll_circle.png" // 白色基线图片 - property string baseOuterImg: "/img/compass_pr_base.png" // 指南针底部黑框 + property string rollCircleImg : "/res/img/compass_roll_circle.png" // 白色基线图片 + property string baseOuterImg: "/res/img/compass_pr_base.png" // 指南针底部黑框 property real pitch: 0 property real lastPitch: 0 // property bool pitchUp: false @@ -207,7 +209,8 @@ Item { Connections { target: dataSource onDataChanged: { - console.log("dataSource heading changed: " + dataSource.getHeading()); + if( !container.draw ) + return; var data = [0, 0, 0]; data[0] = dataSource.getHeading(); data[1] = dataSource.getPitch(); @@ -221,12 +224,8 @@ Item { Connections { target: window - onWindowStateChanged: { - if( window.visibility == window.Hidden || window.visibility == window.Minimized ) { - // it can decrease resource consuming when not minimized or hidden - console.log("[Info] windos state changed: now hidden or minimized"); - } else { - } + onStateChanged: { + container.draw = render; } } @@ -532,7 +531,7 @@ Item { if(s > minsize) { return s } - console.log("minsize:" + minsize) +// console.log("minsize:" + minsize) return minsize } diff --git a/qml/SPFragCode.fsh b/qml/SPFragCode.fsh index a965841..c7b70aa 100644 --- a/qml/SPFragCode.fsh +++ b/qml/SPFragCode.fsh @@ -1,4 +1,4 @@ -precision mediump float; +precision mediump float; varying vec3 vLight; varying vec2 vTexture; @@ -15,9 +15,9 @@ uniform sampler2D uSampler; // uniform int uEnableTexture; void main(void) { vec3 lightPos = vec3( 10, 10, 10 ); - vec3 ambientLight = vec3( 0.28, 0.28, 0.28 ); - vec3 directLightColor = vec3( 0.88, 0.88, 0.88 ); - float directional = max( dot( normalize( vNormal ), normalize( lightPos - vPosition ) ), 0.0); // 直接使用顶点的法线数据进行漫反射计算 + vec3 ambientLight = vec3( 0.48, 0.38, 0.42 ); + vec3 directLightColor = vec3( 0.78, 0.98, 0.88 ); + float directional = max( dot( normalize( vNormal ), normalize( lightPos - vPosition ) ) * 2, 0.0); // 直接使用顶点的法线数据进行漫反射计算 vec3 diffuse = directLightColor * directional; if( uHasTexture ) { diff --git a/qml/SPVertexCode.vsh b/qml/SPVertexCode.vsh index ace77fb..763861f 100644 --- a/qml/SPVertexCode.vsh +++ b/qml/SPVertexCode.vsh @@ -1,4 +1,4 @@ -precision mediump float; +precision mediump float; attribute vec3 aVertexPosition; attribute vec3 aVertexNormal; @@ -11,7 +11,7 @@ uniform mat4 uNMatrix; uniform vec3 uVertColor; uniform bool uSpecColor; -uniform vec3 uLightDirection; // 直射光的方向 +uniform vec3 uLightDirection; varying vec3 vLight; varying vec2 vTexture; varying vec3 vNormal; diff --git a/qml/SpacePath.js b/qml/SpacePath.js index f55e7e0..a5f830e 100644 --- a/qml/SpacePath.js +++ b/qml/SpacePath.js @@ -48,11 +48,6 @@ var refCircle; var recordPoint; var sphere; -function reset() { - sensorPoint.reset(); - sensorPath.resetAllPath(); - camera.reset(); -} /** * this function is copied from planets demo of qt version of threejs @@ -122,7 +117,7 @@ function initializeGL(canvas, args) { coordinate = new Coord(); sensorPoint = new SensorPoint( { color: [0.9, 0.2, 0.15] } ); sensorPoint.setScale( 0.1 ); - sensorPath = new SensorPath( { color: [0.9, 0.5, 0.2], size: 0.3 } ); + sensorPath = new SensorPath( { color: [0.1, 0.3, 0.2], size: 0.3 } ); sensorPoint.addParamCallback( function( params ) { sensorPath.onSphericalChanged( params ); }); @@ -189,6 +184,9 @@ function createArrayBuffer(data, drawtype, type) { return buffer; } +/** + * 更新缓冲区的部分数据 + */ function subBuffer(buffer, offset, data) { var type = gl.ELEMENT_ARRAY_BUFFER; if( data instanceof Float32Array ) { @@ -293,10 +291,12 @@ Camera.prototype = { /** * 重置摄像机位置 + * @param { {phi, theta} } params + * theta:[0, 180], phi:[0, 360] 均为角度制 **/ - reset : function( ) { + reset : function( params ) { // this.rotate( 45, 180, this.dis ); - this.rotate( 45, 0, this.dis ); + this.rotate( params.theta, params.phi, this.dis ); this.update(); } } @@ -427,7 +427,7 @@ Scene.prototype = { gl.attachShader(shaderProgram, vertexShader); ready = ( fragShader !== undefined ); if( ready ) { - onShaderReady(shaderProgram); + that.onShaderReady(shaderProgram); } } ); @@ -1044,7 +1044,7 @@ function Ball(props) { this.hn = (props.hn || 48) * 0.5; this.ratio = 0.25; this.size = 4; // default radius - this.drawMode = Ball.MODE_SURFACE; + this.drawMode = Ball.MODE_LINE; this.line_alpha = 0.65; this.alpha = 0.25; this.init(); @@ -1476,8 +1476,6 @@ function RecordPoint() { this.type = "RecordPoint"; this.max_vertex = this.sides * 1000; - this.vertex_count = 0; - this.index_count = 0; this.init(); } @@ -1485,26 +1483,29 @@ RecordPoint.prototype = { constructor: RecordPoint, init : function() { - this.buffers.vertex = createArrayBuffer( this.max_vertex * 4, gl.DYNAMIC_DRAW, gl.ARRAY_BUFFER ); - this.buffers.index = createArrayBuffer( this.max_vertex * 2, gl.DYNAMIC_DRAW, gl.ELEMENT_ARRAY_BUFFER ); + this.vertexBuffer = createArrayBuffer( this.max_vertex * 4, gl.DYNAMIC_DRAW, gl.ARRAY_BUFFER ); + this.vertexBuffer.length = 0; + this.vertexBuffer.count = 0; + this.indexBuffer = createArrayBuffer( this.max_vertex * 2, gl.DYNAMIC_DRAW, gl.ELEMENT_ARRAY_BUFFER ); + this.indexBuffer.value = []; }, paint : function() { // 进行采点操作 - if( this.vertex_count === 0 || !this.visible ) { + if( this.vertexBuffer.length === 0 || !this.visible ) { return; } - gl.bindBuffer(gl.ARRAY_BUFFER, this.buffers.vertex); + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.vertexAttribPointer( attributes.vertex_normal, 3, gl.FLOAT, false, 6*4, 0 ); gl.vertexAttribPointer( attributes.vertex_position, 3, gl.FLOAT, false, 6*4, 0 ); gl.vertexAttribPointer( attributes.color, 3, gl.FLOAT, false, 6*4, 3*4 ); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.buffers.index); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer ); gl.uniform1f(uniforms.alpha, this.alpha); gl.uniformMatrix4fv( uniforms.m_matrix, false, this.mMatrix ); gl.uniformMatrix4fv( uniforms.pmv_matrix, false, this.mvpMatrix ); - gl.drawElements(gl.TRIANGLES, this.index_count, gl.UNSIGNED_SHORT, 0); + gl.drawElements(gl.TRIANGLES, this.indexBuffer.value.length, gl.UNSIGNED_SHORT, 0); }, onViewChanged: function( matrix ) { @@ -1535,7 +1536,7 @@ RecordPoint.prototype = { var vertices = genVertices( point, [0.0, 0.5, 0.5] ); - var n = this.vertex_count / 6; + var n = this.vertexBuffer.length / 6; // three coordinate, three color for(i = 1; i < this.sides; i++) { index.push( n, n+i, n+i+1, n, n+i+1, n+i @@ -1544,11 +1545,13 @@ RecordPoint.prototype = { index.push( n, n+this.sides, n+1, n, n+1, n+this.sides ); - subBuffer( this.buffers.vertex, this.vertex_count * 4, new Float32Array( vertices ) ); - subBuffer( this.buffers.index, this.index_count * 2, new Uint16Array( index ) ); + subBuffer( this.vertexBuffer, this.vertexBuffer.length * 4, new Float32Array( vertices ) ); + subBuffer( this.indexBuffer, this.indexBuffer.value.length * 2, new Uint16Array( index ) ); - this.vertex_count += vertices.length; - this.index_count += index.length; +// vertices.push.apply( this.vertexBuffer.value, vertices ); + this.vertexBuffer.length += vertices.length; + index.push.apply( this.indexBuffer.value, index ); + this.vertexBuffer.count ++; }, onSphericalChanged: function(params) { @@ -1560,8 +1563,28 @@ RecordPoint.prototype = { // 重置已经打的点 reset : function() { - this.vertex_count = 0; - this.index_count = 0; + this.vertexBuffer.length = 0; + this.vertexBuffer.count = 0; + this.indexBuffer.value = []; + }, + + /** + * 移除第 i 组数据(对应图中的第 i 个点会消失) + * 并没有删除实际的顶点缓冲区,只是隐藏了圆圈 + */ + remove: function(iSet) { + if( this.vertexBuffer.count === 0 || iSet < 0 || this.vertexBuffer.count < iSet ) + return; + var icount = 6 * this.sides; + var istart = iSet * icount; + this.indexBuffer.value.splice( istart, icount ); +// var vcount = this.vertexBuffer.value.length / this.vertexBuffer.count; +// var vstart = iSet * vcount; +// this.vertexBuffer.value.splice( vstart, vcount ); + this.vertexBuffer.count --; + +// subBuffer( this.vertexBuffer, 0, new Float32Array( this.vertexBuffer.value ) ); + subBuffer( this.indexBuffer, 0, new Uint16Array( this.indexBuffer.value ) ); } } // end of RecordPoint prototype @@ -1576,7 +1599,7 @@ function Craft(props) { PaintObj.call( this ); this.type = "Craft"; - this.url = "qrc:/obj/craft.obj"; + this.url = "qrc:/res/obj/craft.obj"; var scale = props.size || 1; this.setScale( scale ); this.init(); @@ -1588,10 +1611,8 @@ Craft.prototype = { init : function() { var that = this; readFile( this.url, function(text) { -// console.log("Craft: ", text) that.mesh = new ObjLoader.OBJ.Mesh(text); ObjLoader.OBJ.initMeshBuffers(gl, that.mesh); - console.log(that.mesh.vertexBuffer.numItems, that.mesh.indexBuffer.numItems) } ); }, @@ -1621,8 +1642,8 @@ Craft.prototype = { // gl.vertexAttribPointer( attributes.texture, this.mesh.textureBuffer.itemSize, gl.FLOAT, false, 0, 0); // } -// gl.bindBuffer(gl.ARRAY_BUFFER, this.mesh.normalBuffer); -// gl.vertexAttribPointer(attributes.vertex_normal, this.mesh.normalBuffer.itemSize, gl.FLOAT, false, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, this.mesh.normalBuffer); + gl.vertexAttribPointer(attributes.vertex_normal, this.mesh.normalBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.uniformMatrix4fv( uniforms.m_matrix, false, this.mMatrix ); gl.uniformMatrix4fv(uniforms.pmv_matrix, false, this.mvpMatrix); diff --git a/qml/SpacePath.qml b/qml/SpacePath.qml index f7aab6e..a01a148 100644 --- a/qml/SpacePath.qml +++ b/qml/SpacePath.qml @@ -5,11 +5,12 @@ import QtQuick.Controls 2.0 import "SpacePath.js" as GLcode Item { + signal pointRecord + id: container width: 1400 height: 900 visible: true - Label { z: 1000 anchors { @@ -46,6 +47,8 @@ Item { contentWidth: parent.width-8 contentHeight: container.height property bool ready : false + property bool started: false + property bool spacePath: false Rectangle { id: cameraItem @@ -187,7 +190,7 @@ Item { text: "球面透明度" maxValue: 100 minValue: 1 - value: 65 + value: 25 stepSize: 5 decimal: 2 onValueChanged: { @@ -204,7 +207,7 @@ Item { text: "指示器大小:" maxValue: 100 minValue: 1 - value: 30 + value: 10 decimal: 2 onValueChanged: { @@ -221,7 +224,7 @@ Item { text: "轨迹宽度:" maxValue: 50 minValue: 1 - value: 8 + value: 3 decimal: 1 enabled: pathEnableBox.checked @@ -308,7 +311,7 @@ Item { left: parent.left leftMargin: controller.marginleft } - width: 20 + // checkable: true text: "line" // exclusiveGroup: drawModeGroup @@ -324,7 +327,7 @@ Item { left: parent.left leftMargin: controller.marginleft } - width: 20 + text: "surface" checked: true // checkable: true @@ -341,7 +344,6 @@ Item { left: parent.left leftMargin: controller.marginleft } - width: 20 text: "lessLine" // checkable: true @@ -468,20 +470,14 @@ Item { left: parent.left leftMargin: controller.marginleft } - onClicked: { - camTheta.value = 45 - camBeta.value = 90 - - onCameraRotate() - GLcode.reset(); - } + onClicked: resetCamera() } Button { id: resetPathBtn width: 100 height: 20 - text: "重置路径" + text: "重置轨迹" anchors { top: resetCameraBtn.bottom topMargin: 5 @@ -624,7 +620,7 @@ Item { text: "<" Image { id: arrowBtnImg - source: "qrc:/img/arrow.png" + source: "qrc:/res/img/arrow.png" width: parent.width height: parent.height } @@ -684,22 +680,27 @@ Item { property int mousex: 1 property int mousey: 1 onMouseXChanged: { - if(mouseListener.pressed) { - onMouseDraged( this ); - lpx = mouseListener.mouseX + if( pressed ) { + var xoffset = (mouseX - lpx) * 2 * 360 / width; + var dbeta = 540 + camBeta.value - xoffset; // - indicates that drag direction is oppsite with movement + camBeta.value = dbeta % 360 - 180; + onCameraRotate(); + lpx = mouseX; } } onMouseYChanged: { - if(mouseListener.pressed) { - onMouseDraged( this ); - lpy = mouseListener.mouseY; + if( pressed ) { + var yoffset = (mouseY - lpy) * 4 * 180 / height; + camTheta.value -= yoffset; + onCameraRotate(); + lpy = mouseY; } } /** onPressed and onReleased 实现拖拽操作 */ onPressed: { // console.log("pressed ==> " + mouseListener.mouseX + " , " + mouseListener.mouseY) - lpx = mouseListener.mouseX; - lpy = mouseListener.mouseY; + lpx = mouseX; + lpy = mouseY; } onWheel: { @@ -737,6 +738,8 @@ Item { GLcode.initializeGL(canvas3d); view.ready = true; onCameraRotate(); +// simBox.checked = true; + } // 当 canvas3d 准备好绘制下一帧时触发 @@ -752,36 +755,59 @@ Item { Connections { target: dataSource onDataChanged: { -// console.log("dataSource heading changed: " + dataSource.getHeading()); +// console.log("dataSource heading changed: " + dataSource.getHeading() + view.ready); if( view.ready ) { + var dis = dataSource.getLength()/10000; + if( view.spacePath ) { + dis = ballRadius.value / 10000; + } + GLcode.sensorPoint.setParam( { - dis: dataSource.getMagicVectorLength()/10000, - pitch: dataSource.getPitch(), + dis: dis, + pitch: dataSource.getPitch(), heading: dataSource.getHeading(), - roll: dataSource.getRoll() + roll: dataSource.getRoll() } ); + if(!view.started) { + view.started = true; + resetCamera(); + } } } + } Connections { target: window - onWindowStateChanged: { - if( window.visibility == window.Hidden || window.visibility == window.Minimized ) { - // it can decrease resource consuming when not minimized or hidden - console.log("[Info] windos state changed: now hidden or minimized"); - canvas3d.renderOnDemand = true; - } else { -// console.log("[Info] windos state changed: now visible"); - canvas3d.renderOnDemand = false; + onStateChanged: { + canvas3d.renderOnDemand = !render; +// if( window.visibility == window.Hidden || window.visibility == window.Minimized ) { +// // it can decrease resource consuming when not minimized or hidden +// console.log("[Info] windos state changed: now hidden or minimized"); +// canvas3d.renderOnDemand = true; +// } else { +//// console.log("[Info] windos state changed: now visible"); +// canvas3d.renderOnDemand = false; +// } + } + onRemoveRecordPoint: { + console.log(iSet) + GLcode.recordPoint.remove( iSet ); + } + onToRecord: { + if( isCSource ) { + GLcode.recordPoint.record(); } } + onThreeDPropertyChanged: { + view.spacePath = spacePath; + } } Timer { id: garbageCollect - interval: 3000 + interval: 5000 running: true repeat: true onTriggered: { @@ -789,8 +815,19 @@ Item { } } + Timer { + interval: 2000 + running: true + repeat: false + onTriggered: { + simBox.checked = true; + } + } + // this function is called by C++ layer and connects JS layer function recordAPoint() { +// pointRecord() + window.toRecord(); GLcode.recordPoint.record(); } @@ -827,14 +864,20 @@ Item { cameraZPos.value = GLcode.camera.pos[2]; } - function onMouseDraged(ml) { - var xoffset = (ml.mouseX - ml.lpx)*2 / ml.width; - var yoffset = (ml.mouseY - ml.lpy)*2 / ml.height; - - var dbeta = 540 + camBeta.value - xoffset*360; // - indicates that drag direction is oppsite with movement - camBeta.value = dbeta % 360 - 180; - camTheta.value -= yoffset*180; - onCameraRotate(); + function resetCamera() { + var p ; + if( calibrationBox.checked ) { + p = { theta: 90 - GLcode.sensorPoint.pitch, phi: 0 }; + } + else { + p = { theta: 45, phi: 180 }; + } + GLcode.sensorPoint.reset(); + GLcode.sensorPath.resetAllPath(); + camTheta.value = p.theta; + camBeta.value = p.phi; + onCameraRotate() + GLcode.camera.reset(p); } } diff --git a/img/arrow.png b/res/img/arrow.png similarity index 100% rename from img/arrow.png rename to res/img/arrow.png diff --git a/res/img/compass.ico b/res/img/compass.ico new file mode 100644 index 0000000..b1fa383 Binary files /dev/null and b/res/img/compass.ico differ diff --git a/img/compass.png b/res/img/compass.png similarity index 100% rename from img/compass.png rename to res/img/compass.png diff --git a/img/compass_pr_base.png b/res/img/compass_pr_base.png similarity index 100% rename from img/compass_pr_base.png rename to res/img/compass_pr_base.png diff --git a/img/compass_roll_circle.png b/res/img/compass_roll_circle.png similarity index 100% rename from img/compass_roll_circle.png rename to res/img/compass_roll_circle.png diff --git a/img/heading.png b/res/img/heading.png similarity index 100% rename from img/heading.png rename to res/img/heading.png diff --git a/img/x.png b/res/img/x.png similarity index 100% rename from img/x.png rename to res/img/x.png diff --git a/img/y.png b/res/img/y.png similarity index 100% rename from img/y.png rename to res/img/y.png diff --git a/img/z.png b/res/img/z.png similarity index 100% rename from img/z.png rename to res/img/z.png diff --git a/obj/craft.obj b/res/obj/craft.obj similarity index 100% rename from obj/craft.obj rename to res/obj/craft.obj diff --git a/src/Animation.cpp b/src/Animation.cpp new file mode 100644 index 0000000..9372354 --- /dev/null +++ b/src/Animation.cpp @@ -0,0 +1,73 @@ +#include "Animation.h" +#include +#include +#include +#include +#include + +#include "animation.h" +#include + +/*! + * \class Animation + * \author BriFuture + * \date 2018.09.06 + * + * \brief 封装好的 QML 动画管理器。 + * 简化与 QML 代码的交互 + * + * QQuickView,QWindow 不是 QWidget 的子类,因此无法直接将该对象放入 + * mdi 子窗口中,若要将动画界面置入 mdi 子窗口中,有两种方法: + * + * 1. 将 Animation 继承 QQuickWidget,QQuickWidget 是 QWidget 的子类, + * 因此可以作为 mdi 的子窗口。但 QWidget 和 QWindow 的接口有些区别,若修改 + * Animation 的继承关系,则需要对 onWindowStateChange 方法做一定修改。 + * 2. 使用 QWidget::createWindowContainer 静态方法将 Animation 对象放入 + * 一个 QWidget 对象中,然后可以将该 QWidget 对象置入 mdi 子窗口。 + * + * 但是上述方法存在一个已知的问题,要把 QWindow(及其子类)放入 mdi 子窗口中, + * 会出现层叠顺序混乱的问题,导致界面绘制时显示异常。 + */ +Animation::Animation(QWindow *parent) : QQuickView(parent), + ado(new AnimationDataObject) +{ + QQmlContext *context = rootContext(); + context->setContextProperty( "dataSource", ado ); + context->setContextProperty( "window", this ); + setResizeMode( SizeRootObjectToView ); // 设置窗口缩放时,根对象也会随之缩放 + connect(this, &QQuickView::windowStateChanged, this, &Animation::onWindowStateChange ); +} + + +/*! + * \brief 将数据传递给 QML 组件 + */ +void Animation::setParam(const double heading, const double pitch, const double roll, const double length) +{ + ado->m_heading = heading; + ado->m_pitch = pitch; + ado->m_roll = roll; + ado->m_length = length; + ado->dataChanged(); +} + + +/*! + * \brief 在窗口状态改变时发出相应信号,通知 QML 组件可以不进行绘制 + */ +void Animation::onWindowStateChange(Qt::WindowState windowState) +{ + if( windowState == Qt::WindowMinimized ) + stateChanged( false ); + else + stateChanged( true ); +} + + +/*! + * \brief 窗口隐藏事件 + */ +void Animation::hideEvent(QHideEvent *) +{ + stateChanged( false ); +} diff --git a/test.cpp b/test.cpp deleted file mode 100644 index 5f28270..0000000 --- a/test.cpp +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file