diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..f7122ec --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,106 @@ +name: Build and Test + +on: + push: + branches: + - main + tags: + - 'v*' + pull_request: + branches: + - main + +defaults: + run: + shell: bash + +env: + SOURCE_DIR: ${{ github.workspace }} + QT_VERSION: 5.15.2 + ARTIFACT: FlexiFlightVis + +jobs: + build: + runs-on: ubuntu-20.04 + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: ${{ env.QT_VERSION }} + host: linux + target: desktop + dir: ${{ runner.temp }} + + - name: Install dependencies + run: sudo apt-get install -y libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev + + - name: Create build directory + run: | + mkdir ${{ runner.temp }}/shadow_build_dir + mkdir ${{ runner.temp }}/shadow_app_dir + + - name: Build + working-directory: ${{ runner.temp }}/shadow_build_dir + run: | + qmake ${SOURCE_DIR}/FlexiFlightVis.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug + make + + - name: Download linuxdeployqt + working-directory: ${{ runner.temp }}/shadow_app_dir + run: | + wget -c --quiet "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" + chmod a+x linuxdeployqt-continuous-x86_64.AppImage + + - name: Create AppImage + working-directory: ${{ runner.temp }}/shadow_app_dir + run: | + cp ${SOURCE_DIR}/deploy/FlexiFlightVis.desktop.desktop ${{ runner.temp }}/shadow_build_dir/ + cp ${SOURCE_DIR}/deploy/FlexiFlightVis.png ${{ runner.temp }}/shadow_build_dir/ + ./linuxdeployqt-continuous-x86_64.AppImage ../shadow_build_dir/FlexiFlightVis -appimage + + - name: Save artifact + uses: actions/upload-artifact@main + with: + name: ${{ env.ARTIFACT }} + path: ${{ runner.temp }}/shadow_app_dir/${{ env.ARTIFACT }}-x86_64.AppImage + + release: + if: github.event_name == 'push' && github.ref_type == 'tag' + name: Release + runs-on: ubuntu-20.04 + needs: build + steps: + - name: Download artifact + uses: actions/download-artifact@v3 + with: + name: ${{ env.ARTIFACT }} + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + draft: false + prerelease: false + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - name: Test + run: | + echo $RELEASE_VERSION + echo ${{ env.RELEASE_VERSION }} + - name: Upload release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./FlexiFlightVis-x86_64.AppImage + asset_name: FlexiFlightVis-${{ env.RELEASE_VERSION }}.AppImage + asset_content_type: application + diff --git a/FlexiFlightVis.pro b/FlexiFlightVis.pro new file mode 100644 index 0000000..f068598 --- /dev/null +++ b/FlexiFlightVis.pro @@ -0,0 +1,36 @@ +QT += core gui opengl network + +LIBS += -lGLU + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked 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 it uses 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 += \ + src/aircraft.cpp \ + src/main.cpp \ + src/mainwindow.cpp \ + src/myudp.cpp \ + src/structWithFieldnames.cpp + +HEADERS += \ + src/aircraft.h \ + src/mainwindow.h \ + src/myudp.h \ + src/structWithFieldnames.h + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d5c795 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# FlexiFlightVis + +FlexiFlightVis is a program for a technical visualization of flexible airplanes. +It is intended to run the simulation of the flexible airplane in Matlab/Simulink. +However, since Matlab/Simulink has limited capabilities for 3D visualization, FlexiFlightVis can be used for visualization. +Therefore, the state of the airplane must be transferred from Matlab/Simulink to FlexiFlightVis via UDP for real-time visualization. +Because of the UDP interface, FlexiFlightVis can run on a different computer than the Matlab/Simulink simulation. +FlexiFlightVis assumes a certain organization of the aircraft state (struct). +Take a look at the example to see how it works. + + +## Installation + +- Linux: + Download and run the AppImage in the Releases. + +- Windows: + Currently not supported (but you can try to build from source). + + +## Example + +FlexiFlightVis is used in the following research project: +[https://github.com/iff-gsc/SE2A_Aviation_2023](https://github.com/iff-gsc/SE2A_Aviation_2023) + + +## Build from source (Linux) + +- Install Qt5: + ``` + sudo apt-get install qt5-default + ``` +- Install dependencies: + ``` + sudo apt-get install -y libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev + ``` +- Clone FlexiFlightVis: + ``` + git clone https://github.com/iff-gsc/flexiflightvis.git + ``` +- Compile the program from Qt Creator or from terminal: + ``` + mkdir build + cd build + qmake ../FlexiFlightVis/FlexiFlightVis.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug + make + ``` diff --git a/deploy/FlexiFlightVis.desktop.desktop b/deploy/FlexiFlightVis.desktop.desktop new file mode 100644 index 0000000..2f227f3 --- /dev/null +++ b/deploy/FlexiFlightVis.desktop.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=FlexiFlightVis +Comment=Aeroelastic Airplane Visualization +Exec=FlexiFlightVis +Icon=FlexiFlightVis +Categories=Office; diff --git a/deploy/FlexiFlightVis.png b/deploy/FlexiFlightVis.png new file mode 100644 index 0000000..e44d210 Binary files /dev/null and b/deploy/FlexiFlightVis.png differ diff --git a/src/aircraft.cpp b/src/aircraft.cpp new file mode 100644 index 0000000..d811ae2 --- /dev/null +++ b/src/aircraft.cpp @@ -0,0 +1,817 @@ +#include "aircraft.h" + + +bool Property::isProperty(QString string_) { + bool propertyFound = false; + for (int i=0; i fieldnames = state.getSubStructNames(); + for (int i=0; i wind_identifier = {"external"}; + for (int j=0; j V_Wb_i = windStruct.getSubData("V_Wb"); + m_V_Wb_i = Math::reshape2Matrix(V_Wb_i); + break; + } + } + } +} + +void Wind::setScaling(double velocity) { + m_scaling = 50 / velocity; +} + +double RigidBody::getVelocity() { + double velocity = m_V_Kb.length(); + // double velocity = -m_V_Kb.x(); + // double velocity = 15.0f; + return velocity; +} + +void Wing::setVelocity(double velocity) { + m_velocity = velocity; +} + +void Fuselage::setVelocity(double velocity) { + m_velocity = velocity; +} + +void Wind::plot(double downShift, QVector> pos, double velocity) { + // draw fuselage geometry + + QVector3D start_pt; + QVector3D end_pt; + + int length; + if (m_V_Wb_i.isEmpty()) { + length = 0; + } + else { + length = m_V_Wb_i[0].length(); + } + + glColor3f(143.0/255.0,169.0/255.0,186.0/255.0); + + QVector3D shift(0,0,downShift); + QGenericMatrix<3,3,double> rotationMatrix; + rotationMatrix.setToIdentity(); + + setScaling(velocity); + + for (int i=0; i < length; i++) { + + // duplicate (to do) + start_pt.setX(pos[0][i]); + start_pt.setY(pos[1][i]); + start_pt.setZ(0); + + start_pt = Math::local2Global(start_pt,shift,rotationMatrix); + + end_pt.setX(pos[0][i]+m_scaling*m_V_Wb_i[0][i]); + end_pt.setY(pos[1][i]+m_scaling*m_V_Wb_i[1][i]); + end_pt.setZ(0+m_scaling*m_V_Wb_i[2][i]); + end_pt = Math::local2Global(end_pt,shift,rotationMatrix); + + //glPointSize ( 1.0f ); + glBegin ( GL_POINTS ); + glVertex3f ( start_pt.x(), start_pt.y(), start_pt.z() ); + glEnd(); + + glBegin(GL_LINE_STRIP); + glVertex3f(start_pt.x(),start_pt.y(),start_pt.z()); + glVertex3f(end_pt.x(),end_pt.y(),end_pt.z()); + glEnd(); + } +} + +void RigidBody::setRigidBody(StructWithFieldnames rigidBody) { + QVector q_bg = rigidBody.getSubData("q_bg"); + QVector V_Kb = rigidBody.getSubData("V_Kb"); + m_q_bg.setScalar(q_bg[0]); + m_q_bg.setX(q_bg[1]); + m_q_bg.setY(q_bg[2]); + m_q_bg.setZ(q_bg[3]); + m_V_Kb.setX(V_Kb[0]); + m_V_Kb.setY(V_Kb[1]); + m_V_Kb.setZ(V_Kb[2]); +} + +void Wing::setWing(QString name, Vortex vortex, Cntrl_pt cntrl_pt) { + // m_name = Property::m_name; + Property::setName(name); + m_vortex = vortex; + m_cntrl_pt = cntrl_pt; +} + +void Vortex::setVortex(StructWithFieldnames vortex) { + QVector fieldNames = vortex.getSubDataNames(); + for (int i=0; i pos = vortex.getSubData(fieldName); + int num_points = pos.length()/3; + for (int i=0; i fieldNames = cntrl_pt.getSubDataNames(); + for (int i=0; i pos = cntrl_pt.getSubData(fieldname); + int num_points = pos.length()/3; + for (int i=0; i fieldNames = coeffLocal.getSubDataNames(); + for (int i=0; i array; + QVector> array2D(3); + int k = 0; + if (fieldname=="c_XYZ_b") { + array = coeffLocal.getSubData(fieldname); + int arrayLength = array.length(); + int subArrayLength = arrayLength/3; + for (int i=0; i<3; i++) { + QVector subArray(subArrayLength); + k = i; + for (int j=0; j subArray(subArrayLength); + k = i; + for (int j=0; j fieldNames = wing.getSubStructNames(); + StructWithFieldnames geometry = wing.getSubStruct("geometry"); + StructWithFieldnames vortex = geometry.getSubStruct("line_25"); + StructWithFieldnames cntrl_pt = geometry.getSubStruct("ctrl_pt"); + StructWithFieldnames aero = wing.getSubStruct("aero"); + StructWithFieldnames coeffLocal = aero.getSubStruct("coeff_loc"); + StructWithFieldnames segments = geometry.getSubStruct("segments"); + StructWithFieldnames actuators = wing.getSubStruct("actuators"); + StructWithFieldnames segments2 = actuators.getSubStruct("segments"); + QVector origin = geometry.getSubData("origin"); + StructWithFieldnames unsteady = aero.getSubStruct("unsteady"); + this->m_vortex.setVortex(vortex); + this->m_cntrl_pt.setCntrlPt(cntrl_pt); + this->m_coeffLocal.setCoeffLocal(coeffLocal); + this->m_flap_depth = segments.getSubData("flap_depth"); + QVector flap_deflection_2x = segments2.getSubData("pos"); + for (int i=0; i X = unsteady.getSubData("X"); + for (int i=0; isetOrigin(origin); + this->wind.setWind(wing); +} + +void Wing::setWing(StructWithFieldnames wing, QString name) { + this->setWing(wing); + this->setName(name); +} + +void Wing::setOrigin(QVector origin) { + m_origin.setX(origin[0]); + m_origin.setY(origin[1]); + m_origin.setZ(origin[2]); +} + +QVector3D Wing::getPointLeadAt(int i) { + QVector3D vortex_i( m_vortex.m_x[i], m_vortex.m_y[i], m_vortex.m_z[i] ); + // shift the point + vortex_i = vortex_i + m_origin + m_shift; + double chord_i = m_vortex.m_c[i]; + double twist_i; + if (i==0) { + twist_i = m_cntrl_pt.m_local_incidence[0]; + } + else if (i==m_vortex.m_x.length()-1) { + twist_i = m_cntrl_pt.m_local_incidence.last(); + } + else { + twist_i = ( m_cntrl_pt.m_local_incidence[i-1] + m_cntrl_pt.m_local_incidence[i] ) / 2; + } + QGenericMatrix<1,3,double> pointLeadMat; + pointLeadMat(0,0) = vortex_i.x()+chord_i/4*cos(twist_i); + pointLeadMat(1,0) = vortex_i.y(); + pointLeadMat(2,0) = vortex_i.z()-chord_i/4*sin(twist_i); + + // rotate the point + pointLeadMat = m_rotationMatrix * pointLeadMat; + + QVector3D pointLead(pointLeadMat(0,0),pointLeadMat(1,0),pointLeadMat(2,0)); + + return pointLead; +} + +QVector3D Wing::getPointTrailAt(int i, int side) { + QVector3D vortex_i( m_vortex.m_x[i], m_vortex.m_y[i], m_vortex.m_z[i] ); + // shift the point + vortex_i = vortex_i + m_origin + m_shift; + double chord_i = m_vortex.m_c[i]; + double twist_i; + if (i==0) { + twist_i = m_cntrl_pt.m_local_incidence[0]; + } + else if (i==m_vortex.m_x.length()-1) { + twist_i = m_cntrl_pt.m_local_incidence.last(); + } + else { + twist_i = ( m_cntrl_pt.m_local_incidence[i-1] + m_cntrl_pt.m_local_incidence[i] ) / 2; + } + QGenericMatrix<1,3,double> pointTrailMat; + int flap_idx = 0; + if ( (side == 0) & (i > 0)) { + flap_idx = i-1; + } + else if (side == 1) { + if (i <= m_cntrl_pt.m_x.length()) { + flap_idx = i; + } + else { + flap_idx = m_cntrl_pt.m_x.length(); + } + } + double rel_shift = 0.75 - m_flap_depth[flap_idx]; + pointTrailMat(0,0) = vortex_i.x()-chord_i*rel_shift*cos(twist_i); + pointTrailMat(1,0) = vortex_i.y(); + pointTrailMat(2,0) = vortex_i.z()+chord_i*rel_shift*sin(twist_i); + // rotate the point + pointTrailMat = m_rotationMatrix * pointTrailMat; + + QVector3D pointTrail(pointTrailMat(0,0),pointTrailMat(1,0),pointTrailMat(2,0)); + + return pointTrail; +} + +QVector3D Wing::getPointFlapAt(int i, int side) { + QVector3D vortex_i( m_vortex.m_x[i], m_vortex.m_y[i], m_vortex.m_z[i] ); + // shift the point + vortex_i = vortex_i + m_origin + m_shift; + double chord_i = m_vortex.m_c[i]; + double twist_i; + if (i==0) { + twist_i = m_cntrl_pt.m_local_incidence[0]; + } + else if (i==m_vortex.m_x.length()-1) { + twist_i = m_cntrl_pt.m_local_incidence.last(); + } + else { + twist_i = ( m_cntrl_pt.m_local_incidence[i-1] + m_cntrl_pt.m_local_incidence[i] ) / 2; + } + QGenericMatrix<1,3,double> pointFlapMat; + int flap_idx = 0; + if ( (side == 0) & (i > 0)) { + flap_idx = i-1; + } + else if (side == 1) { + if (i <= m_cntrl_pt.m_x.length()) { + flap_idx = i; + } + else { + flap_idx = m_cntrl_pt.m_x.length(); + } + } + double rel_shift = 0.75 - m_flap_depth[flap_idx]; + double rel_shift_flap = m_flap_depth[flap_idx]; + int ii; + if (i>m_cntrl_pt.m_x.length()) { + ii = m_cntrl_pt.m_x.length(); + } + else { + ii = i; + } + // rotate about flap rotation axis + QVector3D axis = this->getPointTrailAt(ii+1,0) - this->getPointTrailAt(ii,1); + QQuaternion flap_quat = QQuaternion::fromAxisAndAngle(axis,m_flap_deflection[flap_idx]+57.3*twist_i); + QVector3D flap_vector; + flap_vector.setX(-rel_shift_flap*chord_i); + flap_vector.setY(0); + flap_vector.setZ(0); + QVector3D flap_vector_rotated = flap_quat.rotatedVector(flap_vector); + pointFlapMat(0,0) = vortex_i.x() - chord_i*rel_shift*cos(twist_i) + flap_vector_rotated.x(); + pointFlapMat(1,0) = vortex_i.y() + flap_vector_rotated.y(); + pointFlapMat(2,0) = vortex_i.z() + chord_i*rel_shift*sin(twist_i) + flap_vector_rotated.z(); + // rotate the point + pointFlapMat = m_rotationMatrix * pointFlapMat; + + QVector3D pointFlap(pointFlapMat(0,0),pointFlapMat(1,0),pointFlapMat(2,0)); + + return pointFlap; +} + +QVector3D Wing::getCenterOfPressureAt(int i) { + QVector3D cntrl_pt_i( m_cntrl_pt.m_x[i], m_cntrl_pt.m_y[i], m_cntrl_pt.m_z[i] ); + QVector3D cop_i; + QGenericMatrix<1,3,double> cop_i_Mat; + // shift the point + cntrl_pt_i = cntrl_pt_i + m_origin + m_shift; + // shift the point from control point to center of pressure + float chord = ( m_vortex.m_c[i] + m_vortex.m_c[i+1] ) / 2; + float distance = m_coeffLocal.m_c_m_airfoil[i] / sqrt( pow(m_coeffLocal.m_c_XYZ_b[0][i],2) + pow(m_coeffLocal.m_c_XYZ_b[1][i],2) + pow(m_coeffLocal.m_c_XYZ_b[2][i],2) ) * chord; + if (distance>chord/4) { + distance = chord/4; + } + else if (distance < -chord*3/4) { + distance = -chord*3/4; + } + // shift from control point to c/4 + distance = distance + chord/2; + cop_i.setX( cntrl_pt_i.x() + distance * cos(m_cntrl_pt.m_local_incidence[i]) ); + cop_i.setY(cntrl_pt_i.y()); + cop_i.setZ( cntrl_pt_i.z() - distance * sin(m_cntrl_pt.m_local_incidence[i]) ); + + // rotate (wow) + cop_i_Mat(0,0) = cop_i.x(); + cop_i_Mat(1,0) = cop_i.y(); + cop_i_Mat(2,0) = cop_i.z(); + cop_i_Mat = m_rotationMatrix * cop_i_Mat; + cop_i.setX(cop_i_Mat(0,0)); + cop_i.setY(cop_i_Mat(1,0)); + cop_i.setZ(cop_i_Mat(2,0)); + + return cop_i; +} + +void Wing::plot(QVector3D shift, QQuaternion rotation) { + m_shift = shift; + m_rotationMatrix = Math::quaternion2RotationMatrix(rotation); + this->plot(); +} + +void Wing::plot() { + + // draw aerodynamic forces + QVector3D pointCop; + QVector3D pointCopPlusForce; + QVector3D pointCopPlusLadForce; + for (int i=0; i < m_cntrl_pt.m_x.length(); i++) { + pointCop = this->getCenterOfPressureAt(i); + pointCopPlusForce = pointCop; + pointCopPlusLadForce = pointCop; + QVector3D forceVector( m_coeffLocal.m_c_XYZ_b[0][i], m_coeffLocal.m_c_XYZ_b[1][i], m_coeffLocal.m_c_XYZ_b[2][i] ); + QVector3D ladForceVector( 0, 0, -m_cL_act2[i] ); + + // rotate (wow) + QGenericMatrix<1,3,double> forceVectorMat; + forceVectorMat(0,0) = forceVector.x(); + forceVectorMat(1,0) = forceVector.y(); + forceVectorMat(2,0) = forceVector.z(); + forceVectorMat = m_rotationMatrix * forceVectorMat; + forceVector.setX(forceVectorMat(0,0)); + forceVector.setY(forceVectorMat(1,0)); + forceVector.setZ(forceVectorMat(2,0)); + QGenericMatrix<1,3,double> ladForceVectorMat; + ladForceVectorMat(0,0) = ladForceVector.x(); + ladForceVectorMat(1,0) = ladForceVector.y(); + ladForceVectorMat(2,0) = ladForceVector.z(); + ladForceVectorMat = m_rotationMatrix * ladForceVectorMat; + ladForceVector.setX(ladForceVectorMat(0,0)); + ladForceVector.setY(ladForceVectorMat(1,0)); + ladForceVector.setZ(ladForceVectorMat(2,0)); + + pointCopPlusForce = pointCop + forceVector * (m_vortex.m_c[i]+m_vortex.m_c[i+1])/2 * 5; + pointCopPlusLadForce = pointCop + ladForceVector * (m_vortex.m_c[i]+m_vortex.m_c[i+1])/2 * 5; + QVector3D pointSeparationHelp = pointCop + (1-m_trailing_edge_sep_pt[i])*(pointCopPlusForce-pointCop); + // pointCopPlusForce = pointCop + forceVector * 10; + glBegin(GL_LINE_STRIP); + glColor4f(m_forceColor[0],m_forceColor[1],m_forceColor[2],m_forceAlpha); + glVertex3f(pointCop.x(),pointCop.y(),pointCop.z()); + glColor4f(m_forceColor[0],m_forceColor[1],m_forceColor[2],m_forceAlpha); + glVertex3f(pointSeparationHelp.x(),pointSeparationHelp.y(),pointSeparationHelp.z()); + glColor4f(m_stallColor[0],m_stallColor[1],m_stallColor[2],m_stallAlpha); + glVertex3f(pointCopPlusForce.x(),pointCopPlusForce.y(),pointCopPlusForce.z()); + glEnd(); + glColor4f(m_ladForceColor[0],m_ladForceColor[1],m_ladForceColor[2],m_ladForceAlpha); + glBegin(GL_LINE_STRIP); + glVertex3f(pointCop.x(),pointCop.y(),pointCop.z()); + glVertex3f(pointCopPlusLadForce.x(),pointCopPlusLadForce.y(),pointCopPlusLadForce.z()); + glEnd(); + } + // draw wing geometry + QVector3D pointLeadLeft; + QVector3D pointTrailLeft; + QVector3D pointLeadRight; + QVector3D pointTrailRight; + QVector3D pointFlapLeft; + QVector3D pointFlapRight; + QVector3D cntrl_pt; + QVector> cntrl_pos{3}; + + for (int i=0; i < m_cntrl_pt.m_x.length(); i++) { + pointLeadRight = this->getPointLeadAt(i+1); + pointTrailRight = this->getPointTrailAt(i+1,0); + pointLeadLeft = this->getPointLeadAt(i); + pointTrailLeft = this->getPointTrailAt(i,1); + glColor4f(m_faceColor[0],m_faceColor[1],m_faceColor[2],m_faceAlpha); + glBegin(GL_QUADS); + glVertex3f(pointLeadLeft.x(),pointLeadLeft.y(),pointLeadLeft.z()); + glVertex3f(pointLeadRight.x(),pointLeadRight.y(),pointLeadRight.z()); + glVertex3f(pointTrailRight.x(),pointTrailRight.y(),pointTrailRight.z()); + glVertex3f(pointTrailLeft.x(),pointTrailLeft.y(),pointTrailLeft.z()); + glEnd(); + glColor4f(m_lineColor[0],m_lineColor[1],m_lineColor[2],m_lineAlpha); + glBegin(GL_LINE_STRIP); + glVertex3f(pointLeadLeft.x(),pointLeadLeft.y(),pointLeadLeft.z()); + glVertex3f(pointLeadRight.x(),pointLeadRight.y(),pointLeadRight.z()); + glVertex3f(pointTrailRight.x(),pointTrailRight.y(),pointTrailRight.z()); + glVertex3f(pointTrailLeft.x(),pointTrailLeft.y(),pointTrailLeft.z()); + glVertex3f(pointLeadLeft.x(),pointLeadLeft.y(),pointLeadLeft.z()); + glEnd(); + cntrl_pt.setX(m_cntrl_pt.m_x[i]); + cntrl_pt.setY(m_cntrl_pt.m_y[i]); + cntrl_pt.setZ(m_cntrl_pt.m_z[i]); + cntrl_pt = Math::local2Global(cntrl_pt,m_origin+m_shift,m_rotationMatrix); + cntrl_pos[0].append(cntrl_pt[0]); + cntrl_pos[1].append(cntrl_pt[1]); + cntrl_pos[2].append(cntrl_pt[2]); + } + + for (int i=0; i < m_cntrl_pt.m_x.length()-1; i++) { + pointTrailRight = this->getPointTrailAt(i+1,0); + pointFlapRight = this->getPointFlapAt(i+1,0); + pointFlapLeft = this->getPointFlapAt(i,1); + pointTrailLeft = this->getPointTrailAt(i,1); + glColor4f(m_flapLineColor[0],m_flapLineColor[1],m_flapLineColor[2],m_flapLineAlpha); + glBegin(GL_LINE_STRIP); + glVertex3f(pointTrailLeft.x(),pointTrailLeft.y(),pointTrailLeft.z()); + glVertex3f(pointTrailRight.x(),pointTrailRight.y(),pointTrailRight.z()); + glVertex3f(pointFlapRight.x(),pointFlapRight.y(),pointFlapRight.z()); + glVertex3f(pointFlapLeft.x(),pointFlapLeft.y(),pointFlapLeft.z()); + glVertex3f(pointTrailLeft.x(),pointTrailLeft.y(),pointTrailLeft.z()); + glEnd(); + glColor4f(m_flapFaceColor[0],m_flapFaceColor[1],m_flapFaceColor[2],m_flapFaceAlpha); + glBegin(GL_QUADS); + glVertex3f(pointTrailLeft.x(),pointTrailLeft.y(),pointTrailLeft.z()); + glVertex3f(pointTrailRight.x(),pointTrailRight.y(),pointTrailRight.z()); + glVertex3f(pointFlapRight.x(),pointFlapRight.y(),pointFlapRight.z()); + glVertex3f(pointFlapLeft.x(),pointFlapLeft.y(),pointFlapLeft.z()); + glEnd(); + } + + this->wind.plot(20,cntrl_pos,m_velocity); + +} + + +void Fuselage::setFuselage(StructWithFieldnames fuselage) { + QVector fieldNames = fuselage.getSubStructNames(); + StructWithFieldnames geometry = fuselage.getSubStruct("geometry"); + QVector cntrl_pos = geometry.getSubData("cntrl_pos"); + QVector border_pos = geometry.getSubData("border_pos"); + m_width = geometry.getSubData("width"); + StructWithFieldnames aero = fuselage.getSubStruct("aero"); + QVector c_XYZ_b_i = aero.getSubData("C_XYZ_b_i"); + QVector R_Ab_i = aero.getSubData("R_Ab_i"); + + m_cntrl_pt = Math::reshape2Matrix(cntrl_pos); + m_border_pt = Math::reshape2Matrix(border_pos); + m_c_XYZ_b_i = Math::reshape2Matrix(c_XYZ_b_i); + m_R_Ab_i = Math::reshape2Matrix(R_Ab_i); + + m_wind.setWind(fuselage); +} + +void Fuselage::setFuselage(StructWithFieldnames fuselage, QString name) { + this->setFuselage(fuselage); + this->setName(name); +} + +QVector> Math::reshape2Matrix(QVector vector) { + QVector> array2D(3); + int arrayLength = vector.length(); + int subArrayLength = arrayLength/3; + for (int i=0; i<3; i++) { + QVector subArray(subArrayLength); + int k = i; + for (int j=0; j Math::quaternion2RotationMatrix(QQuaternion rotationQuaternion) { + QGenericMatrix<3,3,double> rotationMatrix; + float *dataMat = rotationQuaternion.toRotationMatrix().data(); + int k = 0; + for (int i=0; i<3; i++) { + for (int j=0; j<3; j++) { + rotationMatrix(j,i) = *(dataMat + k++); + } + } + return rotationMatrix; +} + +void Fuselage::plot(QVector3D shift, QQuaternion rotation) { + m_shift = shift; + m_rotationMatrix = Math::quaternion2RotationMatrix(rotation); + this->plot(); +} + +void Fuselage::plot() { + + QVector3D cntrl_pt; + QVector3D border_pt; + QVector3D next_border_pt; + QVector3D R_Ab_i_end; + + QVector> border_pos = m_border_pt; + + QVector> cycle1; + QVector> cycle2; + + int length; + if (m_border_pt.isEmpty()) { + length = 0; + } + else { + length = m_border_pt[0].length(); + } + for (int i=0; i < length-1; i++) { + border_pt.setX(m_border_pt[0][i]); + border_pt.setY(m_border_pt[1][i]); + border_pt.setZ(m_border_pt[2][i]); + border_pt = Math::local2Global(border_pt,m_shift,m_rotationMatrix); + + border_pos[0][i] = border_pt.x(); + border_pos[1][i] = border_pt.y(); + border_pos[2][i] = border_pt.z(); + + next_border_pt.setX(m_border_pt[0][i+1]); + next_border_pt.setY(m_border_pt[1][i+1]); + next_border_pt.setZ(m_border_pt[2][i+1]); + next_border_pt = Math::local2Global(next_border_pt,m_shift,m_rotationMatrix); + + cntrl_pt.setX(m_cntrl_pt[0][i]); + cntrl_pt.setY(m_cntrl_pt[1][i]); + cntrl_pt.setZ(m_cntrl_pt[2][i]); + cntrl_pt = Math::local2Global(cntrl_pt,m_shift,m_rotationMatrix); + + // scaling = (m_width[i]+m_width[i+1])/2; + double scaling = 5; + R_Ab_i_end.setX(m_cntrl_pt[0][i]+scaling*m_c_XYZ_b_i[0][i]*(m_width[i]+m_width[i+1])/2); + R_Ab_i_end.setY(m_cntrl_pt[1][i]+scaling*m_c_XYZ_b_i[1][i]*(m_width[i]+m_width[i+1])/2); + R_Ab_i_end.setZ(m_cntrl_pt[2][i]+scaling*m_c_XYZ_b_i[2][i]*(m_width[i]+m_width[i+1])/2); + R_Ab_i_end = Math::local2Global(R_Ab_i_end,m_shift,m_rotationMatrix); + + // draw fuselage geometry: center line + glColor4f(m_lineColor[0],m_lineColor[1],m_lineColor[2],m_lineAlpha); + glBegin(GL_LINE_STRIP); + glVertex3f(border_pt.x(),border_pt.y(),border_pt.z()); + glVertex3f(cntrl_pt.x(),cntrl_pt.y(),cntrl_pt.z()); + glVertex3f(next_border_pt.x(),next_border_pt.y(),next_border_pt.z()); + glEnd(); + + // draw aerodynamic forces + glColor4f(m_forceColor[0],m_forceColor[1],m_forceColor[2],m_forceAlpha); + glBegin(GL_LINE_STRIP); + glVertex3f(cntrl_pt.x(),cntrl_pt.y(),cntrl_pt.z()); + glVertex3f(R_Ab_i_end.x(),R_Ab_i_end.y(),R_Ab_i_end.z()); + glEnd(); + + // draw fuselage geometry: cycles + glColor4f(m_lineColor[0],m_lineColor[1],m_lineColor[2],m_lineAlpha); + cycle1 = drawHollowCircle(border_pt,m_rotationMatrix,m_width[i]/2); + cycle2 = drawHollowCircle(next_border_pt,m_rotationMatrix,m_width[i+1]/2); + + // draw fuselage geometry: conic faces + glColor4f(m_faceColor[0],m_faceColor[1],m_faceColor[2],m_faceAlpha); + drawConicFace(cycle1, cycle2); + + } + + m_wind.plot(20,border_pos,m_velocity); + +} + + +QVector> Fuselage::drawHollowCircle(QVector3D position, QGenericMatrix<3,3,double> orientation, double radius){ + int i; + + double PI = 3.14159; + + //GLfloat radius = 0.8f; //radius + double twicePi = 2.0f * PI; + + QVector> positionMat; + QVector positionSub (3); + + QGenericMatrix<1,3,double> circlePt; + + glBegin(GL_LINE_LOOP); + for(i = 0; i <= m_lineAmount;i++) { + circlePt(2,0) = (radius * cos(i * twicePi / m_lineAmount)); + circlePt(1,0) = (radius * sin(i * twicePi / m_lineAmount)); + circlePt(0,0) = 0; + circlePt = orientation * circlePt; + circlePt(0,0) += position.x(); + circlePt(1,0) += position.y(); + circlePt(2,0) += position.z(); + glVertex3f( circlePt(0,0), circlePt(1,0), circlePt(2,0) ); + positionSub[0] = circlePt(0,0); + positionSub[1] = circlePt(1,0); + positionSub[2] = circlePt(2,0); + positionMat.append(positionSub); + } + glEnd(); + return positionMat; +} + +void Fuselage::drawConicFace(QVector> positionMat1, QVector> positionMat2){ + int i; + + QGenericMatrix<1,3,double> circlePt; + + for(i = 0; i <= m_lineAmount-1;i++) { + glBegin(GL_QUADS); + glVertex3f( positionMat1[i][0], positionMat1[i][1], positionMat1[i][2] ); + glVertex3f( positionMat1[i+1][0], positionMat1[i+1][1], positionMat1[i+1][2] ); + glVertex3f( positionMat2[i+1][0], positionMat2[i+1][1], positionMat2[i+1][2] ); + glVertex3f( positionMat2[i][0], positionMat2[i][1], positionMat2[i][2] ); + glEnd(); + } +} + + +QVector3D Math::local2Global(QVector3D vector, QVector3D shift, QGenericMatrix<3,3,double> rotationMatrix ) { + + vector = vector + shift; + + QGenericMatrix<1,3,double> vectorMat; + + vectorMat(0,0) = vector.x(); + vectorMat(1,0) = vector.y(); + vectorMat(2,0) = vector.z(); + + vectorMat = rotationMatrix * vectorMat; + + vector.setX(vectorMat(0,0)); + vector.setY(vectorMat(1,0)); + vector.setZ(vectorMat(2,0)); + + return vector; +} + + +void Aircraft::setPart(Wing wing_){ + bool replaced = false; + for (int i=0; i fieldnames = aircraft.getSubStructNames(); + for (int i=0; i wing_identifier = m_wing_array[0].m_name_identifier; + for (int j=0; j fuselage_identifier = m_fuselage_array[0].m_name_identifier; + for (int j=0; j rigidBody_identifier = m_rigidBody.m_name_identifier; + for (int j=0; j pos_ref = config.getSubData("xyz_ref_c"); + m_posRef[0] = -pos_ref[0]; + m_posRef[1] = -pos_ref[1]; + m_posRef[2] = -pos_ref[2]; + double velocity = m_rigidBody.getVelocity(); + for (int i = 0; i +#include +#include +#include +#include +#include + +#include "structWithFieldnames.h" + + + +class Property { +public: + Property(QVector name_identifier) { + for (int i=0; i m_name_identifier; + QString getName(); + void setName(QString name); + bool isProperty(QString string_); +private: + QString m_name; +}; + +class Wind { + friend class Math; + friend class Aircraft; +public: + void setScaling(double velocity); + void setWind(StructWithFieldnames wind); + void plot(double downShift, QVector> pos, double velocity); +private: + QVector> m_V_Wb_i; + double m_scaling = 1; + double m_downShift = 20; +}; + +class Math { +public: + static QVector3D local2Global(QVector3D vector, QVector3D shift, QGenericMatrix<3,3,double> rotationMatrix ); + static QVector> reshape2Matrix(QVector vector); + static QGenericMatrix<3,3,double> quaternion2RotationMatrix(QQuaternion rotationQuaternion); +}; + +class Vortex : public Property { + friend class Wing; +public: + Vortex() : Property({"vortex"}) {}; + void setVortex(StructWithFieldnames vortex); +private: + QVector m_x; + QVector m_y; + QVector m_z; + QVector m_c; +}; + +class Cntrl_pt : public Property { + friend class Wing; +public: + Cntrl_pt() : Property({"cntrl_pt"}) {}; + void setCntrlPt(StructWithFieldnames cntrl_pt); +private: + QVector m_x; + QVector m_y; + QVector m_z; + QVector m_local_incidence; +}; + +class CoeffLocal : public Property { + friend class Wing; +public: + CoeffLocal() : Property({"coeff_loc","coeffLocal"}) {}; + void setCoeffLocal(StructWithFieldnames coeffLocal); +private: + QVector> m_c_XYZ_b; + QVector> m_c_lmn_b; + QVector m_c_m_airfoil; +}; + + +class Wing : public Property { +public: + Wing() : Property({"wing","htp","vtp","plane"}) { + m_rotationMatrix.setToIdentity(); + m_shift={0,0,0}; + }; + void setWing(QString name, Vortex vortex, Cntrl_pt cntrl_pt); + void setWing(StructWithFieldnames wing); + void setWing(StructWithFieldnames wing, QString name); + void setOrigin(QVector origin); + QVector3D getPointLeadAt(int i); + QVector3D getPointTrailAt(int i, int side); + QVector3D getPointFlapAt(int i, int side); + QVector3D getCenterOfPressureAt(int i); + void plot(); + void plot(QVector3D shift, QQuaternion rotation); + void setVelocity(double velocity); +private: + Vortex m_vortex; + Cntrl_pt m_cntrl_pt; + CoeffLocal m_coeffLocal; + QVector m_cL_act2; + QVector3D m_origin; + QGenericMatrix<3,3,double> m_rotationMatrix; + QVector3D m_shift; + QVector m_flap_depth; + QVector m_flap_deflection; + Wind wind; + double m_velocity; + QVector m_trailing_edge_sep_pt; + float m_lineColor[3] = {0.1,0.1,0.1}; + float m_lineAlpha = 1.0; + float m_faceColor[3] = {0.99,0.99,0.99}; + float m_faceAlpha = 0.5; + float m_forceColor[3] = {76.0/255.0,212.0/255.,38.0/255.0}; + float m_forceAlpha = 1.0; + float m_flapLineColor[3] = {0.1,0.1,0.1}; + float m_flapLineAlpha = 1.0; + float m_flapFaceColor[3] = {0.65,0.65,0.65}; + float m_flapFaceAlpha = 0.5; + float m_stallColor[3] = {247.0/255.0,132.0/255.0,17.0/255.0}; + float m_stallAlpha = 0.7; + float m_ladForceColor[3] = {0.7,0.45,0.9}; + float m_ladForceAlpha = 1; +}; + + +class Fuselage : public Property { + friend class Math; +public: + Fuselage() : Property({"fuselage"}) {}; + void setFuselage(StructWithFieldnames fuselage); + void setFuselage(StructWithFieldnames fuselage, QString name); + void plot(); + void plot(QVector3D shift, QQuaternion rotation); + QVector> drawHollowCircle(QVector3D position, QGenericMatrix<3,3,double> orientation, double radius); + void drawConicFace(QVector> positionMat1, QVector> positionMat2); + void setVelocity(double velocity); +private: + QVector> m_cntrl_pt; + QVector> m_border_pt; + QVector> m_c_XYZ_b_i; + QVector> m_R_Ab_i; + QVector m_width; + QVector3D m_shift; + QGenericMatrix<3,3,double> m_rotationMatrix; + Wind m_wind; + double m_velocity; + int m_lineAmount = 100; + float m_lineColor[3] = {0.1,0.1,0.1}; + float m_lineAlpha = 1.0; + float m_faceColor[3] = {0.99,0.99,0.99}; + float m_faceAlpha = 0.5; + float m_forceColor[3] = {76.0/255.0,212.0/255.,38.0/255.0}; + float m_forceAlpha = 1.0; +}; + + +class RigidBody : public Property { +public: + RigidBody() : Property({"body"}) {}; + void setRigidBody(StructWithFieldnames name); + QQuaternion m_q_bg; + QVector3D m_V_Kb; + double getVelocity(); +}; + + +class Aircraft{ +public: + Aircraft() { + m_wing_array.append(Wing()); + m_fuselage_array.append(Fuselage()); + }; + void setPart(Wing wing_); + void setPart(Fuselage fuselage_); + void setAircraft(StructWithFieldnames aircraft); + void plot(); + void plot(QQuaternion rotation); + QVector3D m_posRef; +private: + QVector m_wing_array; + QVector m_fuselage_array; + RigidBody m_rigidBody; +}; + + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ed4064a --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,14 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.setTitle("FlexiFlightVis - Aeroelastic Flight Dynamics Visualization"); + w.resize(1280, 960); + w.show(); + + return a.exec(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..f511f17 --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,184 @@ +#include "mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) +{ + setSurfaceType(QWindow::OpenGLSurface); + + QSurfaceFormat format; + format.setProfile(QSurfaceFormat::CompatibilityProfile); + format.setVersion(2,1); + setFormat(format); + + context = new QOpenGLContext; + context->setFormat(format); + context->create(); + context->makeCurrent(this); + + openGLFunctions = context->functions(); + + QTimer *timer = new QTimer(this); + + connect(timer, SIGNAL(timeout()), this, SLOT(UpdateAnimation())); + + timer->start(); + +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::initializeGL() +{ + glEnable(GL_DEPTH_TEST); + resizeGL(this->width(), this->height()); + frameTime.start(); +} + +void MainWindow::resizeGL(int w, int h) +{ + // Set viewport + glViewport(0,0,w,h); + qreal aspectratio = qreal(w)/qreal(h); + + // Initialize projection matrix + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + gluPerspective(75, aspectratio, 0.1, 400000000); + + // Initialize model view matrix + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + +} + +void MainWindow::paintGL() +{ + + glClearColor(182.0/255.0,201.0/255.0,214.0/255.0, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glEnable( GL_BLEND ); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + // Reset model view matrix + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // 3D transformation + glTranslatef(0.0, 0.0, -50.0*zoomScale); + QCursor cursor; + if (mouseHold) { + MainWindow::mouseHoldEvent(&cursor); + } + // rotation axis and angle are needed for glRotateF function + QVector3D rotationAxis; + float rotationAngle; + rotationQuatTotal.getAxisAndAngle(&rotationAxis,&rotationAngle); + glRotatef( rotationAngle, rotationAxis[0], rotationAxis[1], rotationAxis[2] ); + + + glLineWidth(2.0f); + glPointSize(4.0f); + + m_client.m_aircraft.plot(); + + + // draw axis frame + QVector3D point0 = {0,0,0}; + QVector3D pointX = {1,0,0}; + QVector3D pointY = {0,1,0}; + QVector3D pointZ = {0,0,1}; + + glBegin(GL_LINE_STRIP); + glColor3f(1,0,0); + glVertex3f(point0.x(),point0.y(),point0.z()); + glVertex3f(pointX.x(),pointX.y(),pointX.z()); + glEnd(); + glBegin(GL_LINE_STRIP); + glColor3f(0,1,0); + glVertex3f(point0.x(),point0.y(),point0.z()); + glVertex3f(pointY.x(),pointY.y(),pointY.z()); + glEnd(); + glBegin(GL_LINE_STRIP); + glColor3f(0,0,1); + glVertex3f(point0.x(),point0.y(),point0.z()); + glVertex3f(pointZ.x(),pointZ.y(),pointZ.z()); + glEnd(); + + + ++frameCount; + + if (frameTime.elapsed() >= 1000) + { + fps = frameCount / ((double)frameTime.elapsed()/1000.0); + } + + // qInfo() << "FPS: " + QString::number(fps); + + glFlush(); +} + +void MainWindow::resizeEvent(QResizeEvent *event) +{ + resizeGL(this->width(), this->height()); + this->update(); +} + +void MainWindow::paintEvent(QPaintEvent *event) +{ + paintGL(); +} + +void MainWindow::UpdateAnimation() +{ + this->update(); +} + +void MainWindow::mousePressEvent(QMouseEvent *event) +{ + mouseHold = true; + mouseHoldFirstCall = true; +} + +void MainWindow::mouseReleaseEvent(QMouseEvent *event) +{ + mouseHold = false; +} + +void MainWindow::mouseHoldEvent(QCursor *cursor) +{ + // reset mouse position when the mouse is pressed + if (mouseHoldFirstCall) { + mousePos = cursor->pos(); + lastMousePos = mousePos; + mouseHoldFirstCall = false; + } + // incrementation + else { + lastMousePos = mousePos; + mousePos = cursor->pos(); + rotationQuatLast = rotationQuatTotal; + } + + // rotation axis and angle update + QPoint diff = mousePos - lastMousePos; + qreal distance = qSqrt(pow(diff.x(),2)+pow(diff.y(),2)); + float rotationAngleUpdate = distance * 0.5; + QVector3D rotationAxisCurrent = QVector3D(diff.y(), diff.x(), 0.0).normalized(); + // rotation relative to last rotation + QQuaternion rotationQuatUpdate = QQuaternion::fromAxisAndAngle(rotationAxisCurrent,rotationAngleUpdate); + + // combined rotation (by quaternion multiplication) + rotationQuatTotal = rotationQuatUpdate * rotationQuatLast; +} + +void MainWindow::wheelEvent(QWheelEvent *event) +{ + QPoint numDegrees = event->angleDelta(); + if (numDegrees.y()<0) zoomScale = zoomScale*1.1; + if (numDegrees.y()>0) zoomScale = zoomScale/1.1; +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..cdb610e --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,62 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include "myudp.h" +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QOpenGLWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +protected: + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseHoldEvent(QCursor *cursor); + void wheelEvent(QWheelEvent *event) override; + virtual void initializeGL() override; + virtual void resizeGL(int w, int h) override; + virtual void paintGL() override; + void resizeEvent(QResizeEvent *event) override; + void paintEvent(QPaintEvent *event) override; + QQuaternion quatMultiply(QQuaternion q_left, QQuaternion q_right); + + +public slots: + void UpdateAnimation(); + +private: + // Ui::MainWindow *ui; + QOpenGLContext *context; + QOpenGLFunctions *openGLFunctions; + + MyUDP m_client; + + bool mouseHold = false; + bool mouseHoldFirstCall; + QPoint mousePos; + QPoint lastMousePos; + QQuaternion rotationQuatTotal = QQuaternion::fromEulerAngles({110,0,220}); + QQuaternion rotationQuatLast = rotationQuatTotal; + float zoomScale = 1; + + int frameCount = 0; + QTime frameTime; + double fps; + +}; +#endif // MAINWINDOW_H diff --git a/src/myudp.cpp b/src/myudp.cpp new file mode 100644 index 0000000..671d3f3 --- /dev/null +++ b/src/myudp.cpp @@ -0,0 +1,118 @@ +#include "myudp.h" + +MyUDP::MyUDP(QObject *parent) : QObject(parent), + // m_senderHostAddress(QHostAddress::LocalHost), + m_senderHostAddress(QHostAddress::Any), + // m_senderHostAddress("192.168.11.13"), + m_port(4321) +{ + // create a QUDP socket + socket = new QUdpSocket(this); + + // The most common way to use QUdpSocket class is to bind it to an address and port using bind() + // bool QAbstractSocket::bind(const QHostAddress & address, + // quint16 port = 0, BindMode mode = DefaultForPlatform) + socket->bind(m_senderHostAddress, m_port); + + socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption,1250000); + // Connect the signal of the QUdpSocket with the slot of this MyUDP class + // If a package is available for the specified Host and Port, call the function readyRead of this class + connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + +void MyUDP::getPoints(QVector &x, QVector &y, QVector &z) { + x = m_x; + y = m_y; + z = m_z; +} + +int16_t MyUDP::getNumberOfDataPoints() { + return m_numberOfDataPoints; +} + +void MyUDP::setHostAddressAndPort(QString hostAddress, quint16 port) +{ + m_senderHostAddress = QHostAddress(hostAddress); + m_port = port; + socket->close(); + socket->bind(m_senderHostAddress, m_port); + + connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + +QString MyUDP::getHostAddress() +{ + return m_senderHostAddress.toString(); +} + +quint16 MyUDP::getHostPort() +{ + return m_port; +} + +int i = 0; + +/***************************************************************************** + * This function is called, when a package is available + *****************************************************************************/ +void MyUDP::readyRead() { + // Create a QByteArray as a buffer + QByteArray buffer; + buffer.resize(socket->pendingDatagramSize()); + + // Create variables for the Host address and the Port of the sender + QHostAddress sender; + quint16 senderPort; + + // qint64 QUdpSocket::readDatagram(char * data, qint64 maxSize, + // QHostAddress * address = 0, quint16 * port = 0) + // Receives a datagram no larger than maxSize bytes and stores it in data. + // The sender's host address and port is stored in *address and *port + // (unless the pointers are 0). + qint64 dataGramSize = socket->readDatagram(buffer.data(), buffer.size(), + &sender, &senderPort); + + // Check if receiving of data was successful + if (dataGramSize != -1) { + // Create QDataStream to read serialized of binary data stored in buffer + QDataStream stream(buffer); + // Set the QDataStream to write data in little endian, because "Simulink UDP Receive Binary" block receives only + // little endian + stream.setByteOrder(QDataStream::LittleEndian); + + stream.setFloatingPointPrecision(QDataStream::SinglePrecision); + + /* + StructWithFieldnames test; + test.setFromStream(stream); + + QVector subStructNames = test.getSubStructNames(); + StructWithFieldnames sub = test.getSubStruct(subStructNames[0]); + */ + + + + StructWithFieldnames aircraftStruct; + aircraftStruct.setFromStream(stream); + + m_aircraft = Aircraft(); + m_aircraft.setAircraft(aircraftStruct); + + + + if (i>30) { + i = 0; + } + else { + i++; + } + + qInfo() << i; + // qInfo() << subStructNames[0]; + + } + else { + std::cout << "An ERROR occures while receiving datagram!" << std::endl; + } + emit receivedValues(); +} diff --git a/src/myudp.h b/src/myudp.h new file mode 100644 index 0000000..d763d9f --- /dev/null +++ b/src/myudp.h @@ -0,0 +1,39 @@ +#ifndef MYUDP_H +#define MYUDP_H + +#include +#include +#include +#include +#include +#include "aircraft.h" + + +class MyUDP : public QObject { + Q_OBJECT +public: + explicit MyUDP(QObject *parent = 0); + void getPoints(QVector &m_x, QVector &m_y, QVector &m_z); + int16_t getNumberOfDataPoints(); + void setHostAddressAndPort(QString hostAddress, quint16 port); + QString getHostAddress(); + quint16 getHostPort(); + Aircraft m_aircraft; +signals: + void receivedValues(); + void numberOfDataPointsChanged(); + +public slots: + void readyRead(); + + +private: + QUdpSocket *socket; + QVector m_x, m_y, m_z; + int16_t m_numberOfDataPoints = 0; + QHostAddress m_senderHostAddress; + quint16 m_port; + QDataStream m_stream; +}; + +#endif // MYUDP_H diff --git a/src/structWithFieldnames.cpp b/src/structWithFieldnames.cpp new file mode 100644 index 0000000..5a86304 --- /dev/null +++ b/src/structWithFieldnames.cpp @@ -0,0 +1,304 @@ +#include "structWithFieldnames.h" + + +QVector StructWithFieldnames::getSubStructNames() { + QVector subStructNames; + for (int i=0; i StructWithFieldnames::getSubDataNames() { + QVector subDataNames; + for (int i=0; i StructWithFieldnames::getSubNames() { + QVector subNames; + for (int i=0; i StructWithFieldnames::getSubData(QString structName) { + QVector subData; + int varIndex = -1; + for (int i=0; i=0) { + QVector assignmentIndex = m_assignmentIndex[varIndex]; + for (int i=0; i dataIndex; + int16_t numberOfDataPoints = 0; + typeudp numberOfDataPointsD = 0; + QString field_name; + QVector field_val; + QVector assignmentIndex; + QVector init_asgnmt_idx = {-1}; + typeudp val = 0; + bool new_struct = false; + bool read_name = false; + int read_name_idx; + bool read_data = false; + int field_name_length; + + // the very first element of the stream is the length + stream >> numberOfDataPointsD; + numberOfDataPoints = (int) round(numberOfDataPointsD); + + // decode the stream from the first element to the last + for (int i=0; i> val; + // the first element is the identifier + if (i==0) { + identifier = val; + currentIdentifier = identifier; + } + // did we find an identifier? + if (round(val)>=identifier && round(val)<=currentIdentifier+1) { + new_struct = true; + read_data = false; + dataIndex.clear(); + // did the level increase? + if (round(val)==currentIdentifier+1) { + currentIdentifier++; + // ... then the last element was a struct (exept it was the first one) + if (m_level.size()>0) { + m_isStruct.append(true); + } + } + // did the level decrease? + else if (round(val)=0; j--) { + if (m_level[j]==m_level.last()-l) { + assignmentIndex.prepend(j); + } + if (m_level[j]0) { + m_isStruct.append(false); + } + } + } + // no identifier was detected, so we read the data (there are 3 states) + else { + if (read_data) { + // 3rd state: read data of variable + // set data to the member variable + m_data.append((double) val); + // overwrite first element (from initialization) or append vector + if (m_assignmentIndex[m_varIndex.last()].first()==init_asgnmt_idx.first()) { + m_assignmentIndex[m_varIndex.last()].first() = m_data.length()-1; + } + else { + m_assignmentIndex[m_varIndex.last()].append(m_data.length()-1); + } + // the very last variable can not be a struct + if (i==numberOfDataPoints-1) { + m_isStruct.append(false); + // depending on how many levels it has decreased, we now can assign the indices of all structs that are now entirely read + // (copy paste) + int num_finished_structs = m_level.last()-1; + for (int l=0; l=0; j--) { + if (m_level[j]==m_level.last()-l) { + assignmentIndex.prepend(j); + } + if (m_level[j]=0) { + index = getIndexFromAssignmentIndex(m_assignmentIndex[varIndex][i]); + nextLayer.m_varName.append(m_varName[index]); + nextLayer.m_level.append(m_level[index]); + nextLayer.m_isStruct.append(m_isStruct[index]); + nextLayer.m_varIndex.append(m_varIndex[index]); + nextLayer.m_assignmentIndex.append(m_assignmentIndex[index]); + } + } + } + return nextLayer; +} + +int StructWithFieldnames::getIndexFromAssignmentIndex(int assigmentIndex) { + int index = -1; + for (int i=0; i +#include +#include +#include +#include + +typedef float typeudp; + + +class StructWithFieldnames { +public: + void setFromStream(QDataStream & stream); + QVector getSubStructNames(); + QVector getSubDataNames(); + QVector getSubNames(); + StructWithFieldnames getSubStruct(QString structName); + QVector getSubData(QString dataName); + + // to do + //StructWithFieldnames getSubStruct(QVector strucNames); + // QVector getSubData(QVector dataNames); + +private: + // variables + QVector m_varName; + QVector m_varIndex; + QVector m_level; + QVector m_isStruct; + QVector> m_assignmentIndex; + QVector m_data; + + // functions + int getNumberOfFurtherLevels(); + int getNumberOfFurtherLevels(QVector structNames); + + int getIndexFromAssignmentIndex(int assigmentIndex); + StructWithFieldnames getNextLayerInfo(int varIndex); + StructWithFieldnames getNextLayerInfoRecursive(int varIndex); + void sortIndices(); + + /* + // to do + QVector getAllNestedStructIndices(); + QVector getAllNestedStructIndices(QString structName); + QVector getAllNestedStructIndices(QVector structNames); + + QVector getAllNestedStructNames(); + QVector getAllNestedStructNames(QString structNames); + QVector getAllNestedStructNames(QVector structNames); + + QVector getAllNamesAtLevel(int level); // not important + QVector getAllStructNamesAtLevel(int level); // not important + QVector getAllDataNamesAtLevel(int level); // not important + */ + +}; + +