Compare commits

..

62 Commits

Author SHA1 Message Date
e6bf1fea9b Revert "Merge pull request #20 from cthunter01/propagator"
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc-13, g++-13, ubuntu-latest) (push) Has been cancelled
This reverts commit 6280d9fb0184275843a8f4406c7293e41e65a639, reversing
changes made to 3c9c8b8c6a2b2e7430ff09efdc2cc0c1996b16ca.
2025-04-16 18:23:28 -06:00
152907beb2 Revert "adding testfile to test repo mirroring from gitea to github"
This reverts commit 8af70eef399a5a237c2c8c006f3f58e56fe15e47.
2025-04-16 18:22:05 -06:00
d2ac30118b Revert "second test of gitea push mirroring"
This reverts commit c14697eddf0a15a2b5938f66fde6c12ca5fe840f.
2025-04-16 18:21:48 -06:00
cc9ba15320 Revert "third test of gitea push mirroring"
This reverts commit 1e04c362ce24c44c400f2ab21fc6ed75239b080b.
2025-04-16 18:21:16 -06:00
9432848310 Revert "remove temporary test file"
This reverts commit 60610150e277710f6751b09ed8db6a7c090dab06.
2025-04-16 18:20:47 -06:00
60610150e2 remove temporary test file
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc-13, g++-13, ubuntu-latest) (push) Has been cancelled
2025-04-16 18:15:55 -06:00
1e04c362ce third test of gitea push mirroring
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc-13, g++-13, ubuntu-latest) (push) Has been cancelled
2025-04-05 19:19:41 -06:00
c14697eddf second test of gitea push mirroring
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc-13, g++-13, ubuntu-latest) (push) Has been cancelled
2025-04-05 19:18:47 -06:00
8af70eef39 adding testfile to test repo mirroring from gitea to github
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc-13, g++-13, ubuntu-latest) (push) Has been cancelled
2025-04-05 19:05:21 -06:00
7fd12b6e0c
Merge pull request #21 from cthunter01/propagator
Merge pull request #1 from qtrocket/development
2025-04-05 18:54:24 -06:00
ae72cf63a8
Merge pull request #1 from qtrocket/development
update
2025-04-05 18:53:20 -06:00
6280d9fb01
Merge pull request #20 from cthunter01/propagator
Propagator
2025-04-05 18:52:14 -06:00
6ddba41dd6 WIP 2024-08-16 18:18:49 -06:00
cb1a8c379b Initial commit of propagator test branch 2024-08-16 16:18:35 -06:00
3c9c8b8c6a
Merge pull request #19 from cthunter01/development
Fix build failures and add github CI actions. Automated builds on Ubuntu and Windows
2024-08-14 18:28:54 -06:00
ead8d1dc01
Merge branch 'qtrocket:development' into development 2024-08-14 18:27:26 -06:00
86587dc435
Update README.md 2024-08-14 18:25:52 -06:00
5a332ec060 Substantial refactor and cleanup of Propagator and Rocket class (now RocketModel class) 2024-03-17 10:19:39 -06:00
46eca1136f Remove model::Stage for now. It'll be good in the future, but makes initial development more complex. Prototype with single stage rocket for now while working out the physics engine 2024-03-17 08:13:24 -06:00
63a5b8995f Update CTest infrastructure to automatically run qtrocket unit tests 2024-03-15 15:17:26 -06:00
e0f3eb1c45 Exclude ubuntu-latest clang build since it's broken (not my breakage, Github's config of ubuntu-latest) 2024-03-15 13:29:30 -06:00
b72d6ff67f Add unit tests to workflow. Disable clang for now because it's broken in ubuntu-latest build container 2024-03-15 13:27:05 -06:00
1a29d0b04e Tweaking workflow. Trying to use gcc-13 on ubuntu 2024-03-15 12:58:37 -06:00
f938d5e21c fix typo in windows-latest.yml action 2024-03-15 12:41:12 -06:00
78bfecd8a3 Split github actions by OS 2024-03-15 12:39:40 -06:00
903b0ee8e6
Update cmake-multi-platform.yml 2024-03-15 12:08:08 -06:00
fb7e267bb4
Test gcc13 on ubuntu-latest: Update cmake-multi-platform.yml 2024-03-15 11:58:14 -06:00
17e87e2c40
Update cmake-multi-platform.yml 2024-03-15 11:20:38 -06:00
46c5caa1ab
Add "install Qt" to github actions: Update cmake-multi-platform.yml 2024-03-15 11:17:44 -06:00
bf83ffc9ec
Add github actions: Create cmake-multi-platform.yml 2024-03-15 11:01:15 -06:00
5db186e8da Fixed build on Fedora with boost. I'm not sure why it worked on FreeBSD but in Fedora 39 CMake didn't set boost up properly, or maybe the FetchContent(Boost) just never worked and it always found the installed boost library? But it fetches and sets up dynamically now... 2024-03-15 10:50:00 -06:00
e5c068ddf7 Remove external dependency on fmtlib in favor of std::format. Begin transition of model::Part into an interface 2024-03-14 18:06:05 -06:00
6a015d9797 Fix crash on motor load 2024-03-14 07:05:16 -06:00
f4e560fcd9 quick cleanup 2024-02-18 16:38:22 -07:00
5da279a8e6 Cleanup 2024-02-18 16:25:45 -07:00
d9cc4e4aec Remove CMakeLists.txt.user 2024-02-18 09:03:51 -07:00
9517b5b682 Added first model tests. Super basic Part test 2023-10-20 17:03:52 -06:00
41183b8397 WIP. Added Stage objects, and made Stage and Rocket a Propagatable. Changed Propagator to propagate a Propagatable instead of a Rocket. This is to allow for propagating dropped stages 2023-10-20 14:48:35 -06:00
9b807d53a4 Fixed US Standard Atmosphere class and tests 2023-10-19 10:58:01 -06:00
9391b85a07 WIP. Started building model/Part component 2023-10-19 08:33:34 -06:00
4da21707b6 Building and running again 2023-10-16 17:40:33 -06:00
505a66a1be WIP 2023-10-16 14:55:31 -06:00
d8e0341742 merge 2023-05-18 20:02:18 -06:00
22c4e79f52 WIP 2023-05-18 19:58:34 -06:00
c7b453d253 added googletest and a USStandardAtmosphereTest 2023-05-15 18:36:47 -06:00
d307bf47c6 Split large CMakeLists into multiple subdirectory libraries. This will make unit testing easier on a per-component basis 2023-05-10 21:03:02 -06:00
558211e9fe Removed the Propagator from the Rocket. It shouldn't really be there, now the Propagator belongs to QtRocket, and is paired with a particular Rocket model, but doesn't belong to that model 2023-05-06 09:20:42 -06:00
8e620cf0c1 Added Eigen dependency, so now QtRocket Vectors (and matrices and quaternions) are backed by Eigen. Cleaned up unused files also 2023-05-06 08:53:56 -06:00
821df8905a Now reads motor delays 2023-05-05 08:01:59 -06:00
42298ca801 merge with upstream 2023-05-04 16:40:20 -06:00
10c552e086 Added QtRocket custome Motor Database format (xml) 2023-05-04 16:31:51 -06:00
47919b661f Fix for motor mass curve calculation 2023-05-03 18:46:14 -06:00
c58edfa30f
Update README.md 2023-05-03 09:09:46 -06:00
6c294969fc
Update README.md 2023-05-03 09:06:35 -06:00
4e9bcb9158
Merge pull request #18 from cthunter01/development
Changing https to http in ThrustCurveAPI to work around issue in Wind…
2023-05-03 08:51:12 -06:00
14878705cc Changing https to http in ThrustCurveAPI to work around issue in Windows where curl isn't being built with SSL support 2023-05-03 08:50:19 -06:00
8b982ee598
Merge pull request #17 from cthunter01/development
Now building under windows 10 with VS 2019
2023-05-02 21:11:39 -06:00
36996abab8 Now building under windows 10 with VS 2019 2023-05-02 20:56:23 -06:00
cea4d13e6c Change SimulationOptions to Environment 2023-04-28 10:49:29 -06:00
697ef8d643
Update README.md 2023-04-27 20:38:47 -06:00
36c43b1f26 Thrustcurve.org fix, motors now load. Also cleanup to not use implicit callbacks, now all signals/slots are explicitly connected 2023-04-27 20:36:45 -06:00
6f033c3a55 Now a real README.md 2023-04-27 19:11:23 -06:00
82 changed files with 3427 additions and 1366 deletions

View File

@ -0,0 +1,86 @@
# This starter workflow is for a CMake project running on multiple platforms. There is a different
# starter workflow if you just want a single platform.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
name: CMake on multiple platforms
on:
push:
branches: [ "development" ]
pull_request:
branches: [ "development" ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations.
# Consider changing this to true when your workflow is stable.
fail-fast: false
# Set up a matrix to run the following 3 configurations:
# 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator>
# 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator>
# 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator>
#
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
matrix:
os: [ubuntu-latest, windows-latest]
build_type: [Release]
c_compiler: [gcc-13, clang, cl]
include:
- os: windows-latest
c_compiler: cl
cpp_compiler: cl
- os: ubuntu-latest
c_compiler: gcc-13
cpp_compiler: g++-13
#- os: ubuntu-latest
#c_compiler: clang
#cpp_compiler: clang++
exclude:
- os: windows-latest
c_compiler: gcc-13
- os: windows-latest
c_compiler: clang
- os: ubuntu-latest
c_compiler: cl
# Clang is broken on ubuntu-latest. C++20 brings in inconsistent libraries
- os: ubuntu-latest
c_compiler: clang
steps:
- uses: actions/checkout@v3
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: 6.6.2
target: desktop
- name: Set reusable strings
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-S ${{ github.workspace }}
- name: Build
# Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
- name: Test
working-directory: ${{ steps.strings.outputs.build-output-dir }}
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest --build-config ${{ matrix.build_type }} -R 'qtrocket_*'

3
.gitignore vendored
View File

@ -38,7 +38,8 @@ build/
docs/doxygen/*
# IDE
.vscode/
*.swp
qtrocket.pro.user
.qmake.stash
CMakeLists.txt.user

17
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/g++",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
}

View File

@ -2,17 +2,85 @@ cmake_minimum_required(VERSION 3.16)
project(qtrocket VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
enable_testing()
include(FetchContent)
# Google Test framework
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest
GIT_TAG v1.13.0)
if(WIN32)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
FetchContent_MakeAvailable(googletest)
# fmtlib dependency
#FetchContent_Declare(fmt
# GIT_REPOSITORY https://github.com/fmtlib/fmt
# GIT_TAG 9.1.0)
#FetchContent_MakeAvailable(fmt)
# jsoncpp dependency
FetchContent_Declare(jsoncpp
GIT_REPOSITORY https://github.com/open-source-parsers/jsoncpp
GIT_TAG 1.9.5)
set(JSONCPP_WITH_TESTS OFF)
set(JSONCPP_WITH_EXAMPLE OFF)
set(JSONCPP_WITH_PKGCONFIG_SUPPORT OFF)
set(JSONCPP_BUILD_SHARED_LIBS OFF)
set(JSONCPP_BUILD_OBJECT_LIBS OFF)
set(JSONCPP_BUILD_STATIC_LIBS ON)
FetchContent_MakeAvailable(jsoncpp)
# curl dependency
FetchContent_Declare(CURL
GIT_REPOSITORY https://github.com/curl/curl
GIT_TAG curl-8_0_1)
set(BUILD_CURL_EXE OFF)
set(BUILD_SHARED_LIBS OFF)
set(HTTP_ONLY ON)
set(SSL_ENABLED ON)
if(WIN32)
set(CURL_USE_SCHANNEL ON)
endif()
FetchContent_MakeAvailable(CURL)
# eigen dependency
FetchContent_Declare(Eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen
GIT_TAG 3.4.0)
FetchContent_MakeAvailable(Eigen)
# boost dependency
FetchContent_Declare(Boost
GIT_REPOSITORY https://github.com/boostorg/boost
GIT_TAG boost-1.84.0)
set(BOOST_INCLUDE_LIBRARIES property_tree)
FetchContent_MakeAvailable(Boost)
# Add qtrocket subdirectories. These are components that will be linked in
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(WIN32)
set(CMAKE_PREFIX_PATH $ENV{QTDIR})
# include_directories("C:\\boost\\boost_1_82_0\\")
# find_package(Qt6Core REQUIRED)
# find_package(Qt6Widgets REQUIRED)
endif()
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools PrintSupport)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools PrintSupport)
find_package(CURL)
find_package(fmt)
find_package(Qt6 REQUIRED COMPONENTS Widgets LinguistTools PrintSupport)
#find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools PrintSupport)
#find_package(CURL)
#find_package(fmt)
set(TS_FILES qtrocket_en_US.ts)
@ -41,59 +109,6 @@ set(PROJECT_SOURCES
gui/ThrustCurveMotorSelector.ui
gui/qcustomplot.cpp
gui/qcustomplot.h
model/MotorCase.cpp
model/MotorCase.h
model/MotorModel.cpp
model/MotorModel.h
model/MotorModelDatabase.cpp
model/MotorModelDatabase.h
model/Rocket.cpp
model/Rocket.h
model/ThrustCurve.cpp
model/ThrustCurve.h
sim/AtmosphericModel.h
sim/ConstantAtmosphere.h
sim/ConstantGravityModel.cpp
sim/ConstantGravityModel.h
sim/DESolver.h
sim/GeoidModel.h
sim/GravityModel.cpp
sim/GravityModel.h
sim/Propagator.cpp
sim/Propagator.h
sim/RK4Solver.h
sim/SimulationOptions.h
sim/SphericalGeoidModel.cpp
sim/SphericalGeoidModel.h
sim/SphericalGravityModel.cpp
sim/SphericalGravityModel.h
sim/StateData.cpp
sim/StateData.h
sim/USStandardAtmosphere.cpp
sim/USStandardAtmosphere.h
sim/WindModel.cpp
sim/WindModel.h
utils/BinMap.cpp
utils/BinMap.h
utils/CurlConnection.cpp
utils/CurlConnection.h
utils/Logger.cpp
utils/Logger.h
utils/RSEDatabaseLoader.cpp
utils/RSEDatabaseLoader.h
utils/ThreadPool.cpp
utils/ThreadPool.h
utils/ThrustCurveAPI.cpp
utils/ThrustCurveAPI.h
utils/Triplet.h
utils/TSQueue.h
utils/math/Constants.h
utils/math/Quaternion.cpp
utils/math/Quaternion.h
utils/math/UtilityMathFunctions.cpp
utils/math/UtilityMathFunctions.h
utils/math/Vector3.cpp
utils/math/Vector3.h
${TS_FILES}
)
@ -122,10 +137,26 @@ else()
)
endif()
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()
target_link_libraries(qtrocket PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${Qt_VERSION_MAJOR}::PrintSupport curl jsoncpp fmt::fmt-header-only)
add_subdirectory(utils)
add_subdirectory(sim)
add_subdirectory(model)
#target_link_libraries(qtrocket PRIVATE
# Qt6::Widgets
# Qt6::PrintSupport
# libcurl
# jsoncpp_static
# fmt::fmt-header-only
# eigen)
target_link_libraries(qtrocket PRIVATE
Qt6::Widgets
Qt6::PrintSupport
utils
sim
model)
set_target_properties(qtrocket PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com

View File

@ -1,416 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 10.0.0, 2023-04-26T18:22:10. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{126c64d7-12e8-468a-ad3f-06f0fbdaeca1}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="qlonglong">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">6</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt6</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt6</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{834bc66d-170a-454c-a2b0-c17798dc7b12}</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="CMake.Build.Type">Debug</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=Debug
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="CMake.Build.Type">Release</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=Release
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-RelWithDebInfo</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.4">
<value type="QString" key="CMake.Build.Type">MinSizeRel</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=MinSizeRel
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-MinSizeRel</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">5</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">qtrocket</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.qtrocket</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">qtrocket</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/travis/build-qtrocket-Desktop_Qt6-Debug</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="qlonglong">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@ -1,4 +1,3 @@
/// \cond
// C headers
// C++ headers
@ -12,6 +11,7 @@
// qtrocket headers
#include "QtRocket.h"
#include "utils/Logger.h"
#include "gui/MainWindow.h"
// Initialize static member data
@ -23,6 +23,8 @@ bool QtRocket::initialized = false;
// The gui worker thread
void guiWorker(int argc, char* argv[], int& ret)
{
utils::Logger* logger = utils::Logger::getInstance();
logger->info("Starting QApplication");
QApplication a(argc, argv);
a.setWindowIcon(QIcon(":/qtrocket.png"));
@ -42,6 +44,7 @@ void guiWorker(int argc, char* argv[], int& ret)
// Go!
MainWindow w(QtRocket::getInstance());
logger->debug("Showing MainWindow");
w.show();
ret = a.exec();
@ -61,6 +64,7 @@ void QtRocket::init()
std::lock_guard<std::mutex> lck(mtx);
if(!initialized)
{
utils::Logger::getInstance()->debug("Instantiating new QtRocket");
instance = new QtRocket();
initialized = true;
}
@ -71,13 +75,25 @@ QtRocket::QtRocket()
logger = utils::Logger::getInstance();
running = false;
// Need to set some sane defaults for Simulation Options
// The default constructor for SimulationOptions will do that for us, so just use that
setSimulationOptions(std::make_shared<sim::SimulationOptions>());
// Need to set some sane defaults for the Environment
// The default constructor for Environment will do that for us, so just use that
setEnvironment(std::make_shared<sim::Environment>());
rocket =
std::make_shared<Rocket>();
rocket.first =
std::make_shared<model::RocketModel>();
rocket.second =
std::make_shared<sim::Propagator>(rocket.first);
motorDatabase = std::make_shared<utils::MotorModelDatabase>();
logger->debug("Initial states vector size: " + std::to_string(states.capacity()) );
// Reserve at least 1024 spaces for StateData
if(states.capacity() < 1024)
{
states.reserve(1024);
}
logger->debug("New states vector size: " + std::to_string(states.capacity()) );
}
int QtRocket::run(int argc, char* argv[])
@ -94,11 +110,21 @@ int QtRocket::run(int argc, char* argv[])
return 0;
}
void QtRocket::launchRocket()
{
// initialize the propagator
rocket.first->clearStates();
rocket.second->setCurrentTime(0.0);
// start the rocket motor
rocket.first->launch();
// run the propagator until it terminates
rocket.second->runUntilTerminate();
}
void QtRocket::addMotorModels(std::vector<model::MotorModel>& m)
{
for(const auto& i : m)
{
motorModels.push_back(i);
}
motorDatabase->addMotorModels(m);
// TODO: Now clear any duplicates?
}

View File

@ -7,17 +7,19 @@
#include <atomic>
#include <memory>
#include <mutex>
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "model/MotorModel.h"
#include "model/Rocket.h"
#include "sim/AtmosphericModel.h"
#include "sim/GravityModel.h"
#include "sim/SimulationOptions.h"
#include "model/RocketModel.h"
#include "sim/Environment.h"
#include "sim/Propagator.h"
#include "utils/Logger.h"
#include "utils/MotorModelDatabase.h"
#include "utils/math/MathTypes.h"
/**
* @brief The QtRocket class is the master controller for the QtRocket application.
@ -38,18 +40,31 @@ public:
void runSim();
std::shared_ptr<sim::GravityModel> getGravityModel() { return simOptions->getGravityModel(); }
std::shared_ptr<sim::AtmosphericModel> getAtmosphereModel() { return simOptions->getAtmosphericModel(); }
double getTimeStep() { return simOptions->getTimeStep(); }
std::shared_ptr<Rocket> getRocket() { return rocket; }
std::shared_ptr<sim::Environment> getEnvironment() { return environment; }
void setTimeStep(double t) { rocket.second->setTimeStep(t); }
std::shared_ptr<model::RocketModel> getRocket() { return rocket.first; }
std::shared_ptr<utils::MotorModelDatabase> getMotorDatabase() { return motorDatabase; }
void addMotorModels(std::vector<model::MotorModel>& m);
const std::vector<model::MotorModel>& getMotorModels() const { return motorModels; }
void addRocket(std::shared_ptr<model::RocketModel> r) { rocket.first = r; rocket.second = std::make_shared<sim::Propagator>(r); }
void addRocket(std::shared_ptr<Rocket> r) { rocket = r; }
void setEnvironment(std::shared_ptr<sim::Environment> e) { environment = e; }
void setSimulationOptions(std::shared_ptr<sim::SimulationOptions> options) { simOptions = options; }
void launchRocket();
/**
* @brief getStates returns a vector of time/state pairs generated during launch()
* @return vector of pairs of doubles, where the first value is a time and the second a state vector
*/
const std::vector<std::pair<double, StateData>>& getStates() const { return rocket.first->getStates(); }
/**
* @brief setInitialState sets the initial state of the Rocket.
* @param initState initial state vector (x, y, z, xDot, yDot, zDot, pitch, yaw, roll, pitchDot, yawDot, rollDot)
*/
void setInitialState(const StateData& initState) { rocket.first->setInitialState(initState); }
private:
QtRocket();
@ -61,14 +76,20 @@ private:
static std::mutex mtx;
static QtRocket* instance;
// Motor "database(s)"
std::vector<model::MotorModel> motorModels;
utils::Logger* logger;
std::shared_ptr<Rocket> rocket;
using Rocket = std::pair<std::shared_ptr<model::RocketModel>, std::shared_ptr<sim::Propagator>>;
Rocket rocket;
std::shared_ptr<sim::SimulationOptions> simOptions;
std::shared_ptr<sim::Environment> environment;
std::shared_ptr<utils::MotorModelDatabase> motorDatabase;
// Launch site
// ECEF coordinates
Vector3 launchSitePosition{0.0, 0.0, 0.0};
// Table of state data
std::vector<StateData> states;
};

View File

@ -1,3 +1,2 @@
# qtrocket
Soon to be model Rocket Simulator written in C++ and Qt Toolkit
An open source model Rocket Simulator written in C++ and Qt Toolkit, coming soon

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,11 @@ AboutWindow::AboutWindow(QWidget *parent) :
ui->setupUi(this);
setWindowTitle(QString("About QtRocket"));
connect(ui->okButton,
SIGNAL(clicked()),
this,
SLOT(onButton_okButton_clicked()));
}
AboutWindow::~AboutWindow()
@ -16,7 +21,7 @@ AboutWindow::~AboutWindow()
delete ui;
}
void AboutWindow::on_pushButton_clicked()
void AboutWindow::onButton_okButton_clicked()
{
this->close();
}

View File

@ -29,7 +29,7 @@ public:
~AboutWindow();
private slots:
void on_pushButton_clicked();
void onButton_okButton_clicked();
private:
Ui::AboutWindow *ui;

View File

@ -29,7 +29,7 @@
<string>Copyright (c) 2023 by Travis Hunter</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<widget class="QPushButton" name="okButton">
<property name="geometry">
<rect>
<x>250</x>

View File

@ -14,11 +14,17 @@ AnalysisWindow::AnalysisWindow(QWidget *parent) :
this->hide();
this->show();
connect(ui->plotAltitudeBtn, SIGNAL(clicked()), this, SLOT(plotAltitude()));
//connect(ui->plotAtmosphereBtn, SIGNAL(clicked()), this, SLOT(plotAtmosphere()));
connect(ui->plotVelocityBtn, SIGNAL(clicked()), this, SLOT(plotVelocity()));
connect(ui->plotMotorCurveBtn, SIGNAL(clicked()), this, SLOT(plotMotorCurveBtn()));
connect(ui->plotAltitudeBtn,
SIGNAL(clicked()),
this,
SLOT(onButton_plotAltitude_clicked()));
connect(ui->plotVelocityBtn,
SIGNAL(clicked()),
this,
SLOT(onButton_plotVelocity_clicked()));
connect(ui->plotMotorCurveBtn,
SIGNAL(clicked()),this,
SLOT(onButton_plotMotorCurve_clicked()));
}
@ -27,10 +33,10 @@ AnalysisWindow::~AnalysisWindow()
delete ui;
}
void AnalysisWindow::plotAltitude()
void AnalysisWindow::onButton_plotAltitude_clicked()
{
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
const std::vector<std::pair<double, std::vector<double>>>& res = rocket->getStates();
QtRocket* qtRocket = QtRocket::getInstance();
const std::vector<std::pair<double, StateData>>& res = qtRocket->getStates();
auto& plot = ui->plotWidget;
plot->clearGraphs();
plot->setInteraction(QCP::iRangeDrag, true);
@ -40,7 +46,7 @@ void AnalysisWindow::plotAltitude()
for (int i = 0; i < tData.size(); ++i)
{
tData[i] = res[i].first;
zData[i] = res[i].second[2];
zData[i] = res[i].second.position[2];
}
// create graph and assign data to it:
plot->addGraph();
@ -54,10 +60,10 @@ void AnalysisWindow::plotAltitude()
plot->replot();
}
void AnalysisWindow::plotVelocity()
void AnalysisWindow::onButton_plotVelocity_clicked()
{
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
const std::vector<std::pair<double, std::vector<double>>>& res = rocket->getStates();
QtRocket* qtRocket = QtRocket::getInstance();
const std::vector<std::pair<double, StateData>>& res = qtRocket->getStates();
auto& plot = ui->plotWidget;
plot->clearGraphs();
plot->setInteraction(QCP::iRangeDrag, true);
@ -68,7 +74,7 @@ void AnalysisWindow::plotVelocity()
for (int i = 0; i < tData.size(); ++i)
{
tData[i] = res[i].first;
zData[i] = res[i].second[5];
zData[i] = res[i].second.velocity[2];
}
// create graph and assign data to it:
plot->addGraph();
@ -83,10 +89,10 @@ void AnalysisWindow::plotVelocity()
}
void AnalysisWindow::plotMotorCurveBtn()
void AnalysisWindow::onButton_plotMotorCurve_clicked()
{
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
model::MotorModel motor = rocket->getCurrentMotorModel();
std::shared_ptr<model::RocketModel> rocket = QtRocket::getInstance()->getRocket();
model::MotorModel motor = rocket->getMotorModel();
ThrustCurve tc = motor.getThrustCurve();

View File

@ -38,10 +38,9 @@ public:
private slots:
void plotAltitude();
//void plotAtmosphere();
void plotVelocity();
void plotMotorCurveBtn();
void onButton_plotAltitude_clicked();
void onButton_plotVelocity_clicked();
void onButton_plotMotorCurve_clicked();
private:
Ui::AnalysisWindow *ui;

View File

@ -88,24 +88,7 @@
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>plotAltitudeBtn</sender>
<signal>clicked()</signal>
<receiver>AnalysisWindow</receiver>
<slot>plotAltitude()</slot>
<hints>
<hint type="sourcelabel">
<x>78</x>
<y>61</y>
</hint>
<hint type="destinationlabel">
<x>88</x>
<y>17</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
<slots>
<slot>plotAltitude()</slot>
</slots>

View File

@ -20,7 +20,7 @@
#include "gui/MainWindow.h"
#include "gui/ThrustCurveMotorSelector.h"
#include "gui/SimOptionsWindow.h"
#include "model/Rocket.h"
#include "model/RocketModel.h"
#include "utils/RSEDatabaseLoader.h"
@ -49,6 +49,10 @@ MainWindow::MainWindow(QtRocket* _qtRocket, QWidget *parent)
SLOT(onMenu_Edit_SimulationOptions_triggered()));
// Tools Menu Actions
connect(ui->actionSaveMotorDatabase,
SIGNAL(triggered()),
this,
SLOT(onMenu_Tools_SaveMotorDatabase()));
// Help Menu Actions
connect(ui->actionAbout,
@ -79,6 +83,7 @@ MainWindow::MainWindow(QtRocket* _qtRocket, QWidget *parent)
this,
SLOT(onButton_getTCMotorData_clicked()));
ui->calculateTrajectory_btn->setDisabled(true);
}
MainWindow::~MainWindow()
@ -95,6 +100,11 @@ void MainWindow::onMenu_Help_About_triggered()
}
void MainWindow::onMenu_Tools_SaveMotorDatabase()
{
qtRocket->getMotorDatabase()->saveMotorDatabase("qtrocket_motors.qmd");
}
void MainWindow::onButton_calculateTrajectory_clicked()
{
@ -113,12 +123,16 @@ void MainWindow::onButton_calculateTrajectory_clicked()
double initialVelocityX = initialVelocity * std::cos(initialAngle / 57.2958);
double initialVelocityZ = initialVelocity * std::sin(initialAngle / 57.2958);
std::vector<double> initialState = {0.0, 0.0, 0.0, initialVelocityX, 0.0, initialVelocityZ, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
//std::vector<double> initialState = {0.0, 0.0, 0.0, initialVelocityX, 0.0, initialVelocityZ, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
StateData initialState;
initialState.position = {0.0, 0.0, 0.0};
initialState.velocity = {initialVelocityX, 0.0, initialVelocityZ};
auto rocket = QtRocket::getInstance()->getRocket();
rocket->setInitialState(initialState);
rocket->setMass(mass);
rocket->setDragCoefficient(dragCoeff);
rocket->launch();
qtRocket->setInitialState(initialState);
qtRocket->launchRocket();
AnalysisWindow aWindow;
aWindow.setModal(false);
@ -177,7 +191,13 @@ void MainWindow::onButton_setMotor_clicked()
QString motorName = ui->engineSelectorComboBox->currentText();
model::MotorModel mm = rseDatabase->getMotorModelByName(motorName.toStdString());
QtRocket::getInstance()->getRocket()->setMotorModel(mm);
QtRocket::getInstance()->addMotorModels(rseDatabase->getMotors());
// Now that we have a motor selected, we can enable the calculateTrajectory button
ui->calculateTrajectory_btn->setDisabled(false);
/// TODO: Figure out if this is the right place to populate the motor database
/// or from RSEDatabaseLoader where it currently is populated.
//QtRocket::getInstance()->addMotorModels(rseDatabase->getMotors());
}

View File

@ -51,6 +51,8 @@ private slots:
void onMenu_File_Quit_triggered();
void onMenu_Tools_SaveMotorDatabase();
private:
Ui::MainWindow* ui;
QtRocket* qtRocket;

View File

@ -253,6 +253,7 @@
<property name="title">
<string>Tools</string>
</property>
<addaction name="actionSaveMotorDatabase"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
@ -345,6 +346,11 @@
<string>Simulation Options</string>
</property>
</action>
<action name="actionSaveMotorDatabase">
<property name="text">
<string>Save Motor Database</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -11,7 +11,7 @@
#include "SimOptionsWindow.h"
#include "ui_SimOptionsWindow.h"
#include "sim/SimulationOptions.h"
#include "sim/Environment.h"
SimOptionsWindow::SimOptionsWindow(QWidget *parent) :
QMainWindow(parent),
@ -19,9 +19,19 @@ SimOptionsWindow::SimOptionsWindow(QWidget *parent) :
{
ui->setupUi(this);
connect(ui->buttonBox,
SIGNAL(rejected()),
this,
SLOT(on_buttonBox_rejected()));
connect(ui->buttonBox,
SIGNAL(accepted()),
this,
SLOT(on_buttonBox_accepted()));
// populate the combo boxes
std::shared_ptr<sim::SimulationOptions> options(new sim::SimulationOptions);
std::shared_ptr<sim::Environment> options(new sim::Environment);
std::vector<std::string> atmosphereModels = options->getAvailableAtmosphereModels();
std::vector<std::string> gravityModels = options->getAvailableGravityModels();
@ -50,12 +60,12 @@ void SimOptionsWindow::on_buttonBox_accepted()
{
QtRocket* qtrocket = QtRocket::getInstance();
std::shared_ptr<sim::SimulationOptions> options(new sim::SimulationOptions);
std::shared_ptr<sim::Environment> environment(new sim::Environment);
options->setTimeStep(ui->timeStep->text().toDouble());
options->setGravityModel(ui->gravityModelCombo->currentText().toStdString());
options->setAtmosphereModel(ui->atmosphereModelCombo->currentText().toStdString());
qtrocket->setSimulationOptions(options);
qtrocket->setTimeStep(ui->timeStep->text().toDouble());
environment->setGravityModel(ui->gravityModelCombo->currentText().toStdString());
environment->setAtmosphereModel(ui->atmosphereModelCombo->currentText().toStdString());
qtrocket->setEnvironment(environment);
this->close();

View File

@ -17,6 +17,23 @@ ThrustCurveMotorSelector::ThrustCurveMotorSelector(QWidget *parent) :
tcApi(new utils::ThrustCurveAPI)
{
ui->setupUi(this);
connect(ui->getMetadata,
SIGNAL(clicked()),
this,
SLOT(onButton_getMetadata_clicked()));
connect(ui->searchButton,
SIGNAL(clicked()),
this,
SLOT(onButton_searchButton_clicked()));
connect(ui->setMotor,
SIGNAL(clicked()),
this,
SLOT(onButton_setMotor_clicked()));
this->setWindowModality(Qt::NonModal);
this->hide();
this->show();
@ -27,7 +44,7 @@ ThrustCurveMotorSelector::~ThrustCurveMotorSelector()
delete ui;
}
void ThrustCurveMotorSelector::on_getMetadata_clicked()
void ThrustCurveMotorSelector::onButton_getMetadata_clicked()
{
// When the user clicks "Get Metadata", we want to pull in Metadata from thrustcurve.org
// and populate the Manufacturer, Diameter, and Impulse Class combo boxes
@ -50,7 +67,7 @@ void ThrustCurveMotorSelector::on_getMetadata_clicked()
}
void ThrustCurveMotorSelector::on_searchButton_clicked()
void ThrustCurveMotorSelector::onButton_searchButton_clicked()
{
//double diameter = ui->diameter->
@ -75,7 +92,7 @@ void ThrustCurveMotorSelector::on_searchButton_clicked()
}
void ThrustCurveMotorSelector::on_setMotor_clicked()
void ThrustCurveMotorSelector::onButton_setMotor_clicked()
{
//asdf
std::string commonName = ui->motorSelection->currentText().toStdString();

View File

@ -30,11 +30,11 @@ public:
~ThrustCurveMotorSelector();
private slots:
void on_getMetadata_clicked();
void onButton_getMetadata_clicked();
void on_searchButton_clicked();
void onButton_searchButton_clicked();
void on_setMotor_clicked();
void onButton_setMotor_clicked();
private:
Ui::ThrustCurveMotorSelector *ui;

View File

@ -1,11 +1,9 @@
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
#include "QtRocket.h"
#include "utils/Logger.h"
@ -14,54 +12,16 @@ int main(int argc, char *argv[])
// Instantiate logger
utils::Logger* logger = utils::Logger::getInstance();
logger->setLogLevel(utils::Logger::DEBUG);
logger->setLogLevel(utils::Logger::PERF_);
logger->info("Logger instantiated at PERF level");
// instantiate QtRocket
logger->debug("Starting QtRocket");
QtRocket* qtrocket = QtRocket::getInstance();
// Run QtRocket. This'll start the GUI thread and block until the user
// exits the program
logger->debug("QtRocket->run()");
int retVal = qtrocket->run(argc, argv);
logger->debug("Returning");
return retVal;
}
/*
* This was the old main when it directly started the QtGui. It worked. The new way of
* starting the gui through QtRocket->run() also seems to work, but I'm leaving this here for
* now in case there are unforeseen issues with starting the gui in a separate thread via
* QtRocket::run()
*
#include "gui/MainWindow.h"
#include <QApplication>
#include <QLocale>
#include <QTranslator>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
a.setWindowIcon(QIcon(":/qtrocket.png"));
// Start translation component.
// TODO: Only support US English at the moment. Anyone want to help translate?
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages)
{
const QString baseName = "qtrocket_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName))
{
a.installTranslator(&translator);
break;
}
}
// Go!
MainWindow w;
w.show();
return a.exec();
}
*/

20
model/CMakeLists.txt Normal file
View File

@ -0,0 +1,20 @@
add_library(model
MotorModel.cpp
MotorModel.h
MotorModelDatabase.cpp
MotorModelDatabase.h
Part.cpp
Part.h
Propagatable.cpp
Propagatable.h
RocketModel.cpp
RocketModel.h
ThrustCurve.cpp
ThrustCurve.h
InertiaTensors.h)
target_link_libraries(model PRIVATE
utils)
# Unit tests
add_subdirectory(tests)

70
model/InertiaTensors.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef INERTIATENSORS_H
#define INERTIATENSORS_H
#include "utils/math/MathTypes.h"
namespace model
{
/**
* @brief The InertiaTensors class provides a collection of methods to
* deliver some common inertia tensors centered about the center of mass
*/
class InertiaTensors
{
public:
/**
* @brief SolidSphere
* @param radius (meters)
* @return
*/
static Matrix3 SolidSphere(double radius)
{
double xx = 0.4*radius*radius;
double yy = xx;
double zz = xx;
return Matrix3{{xx, 0, 0},
{0, yy, 0},
{0, 0, zz}};
}
/**
* @brief HollowSphere
* @param radius (meters)
* @return
*/
static Matrix3 HollowSphere(double radius)
{
double xx = (2.0/3.0)*radius*radius;
double yy = xx;
double zz = xx;
return Matrix3{{xx, 0, 0},
{0, yy, 0},
{0, 0, zz}};
}
/**
* @brief Tube - The longitudinal axis is the z-axis. Can also be used for a solid cylinder
* when innerRadius = 0.0
* @param innerRadius (meters)
* @param outerRadius (meters)
* @param length (meters)
* @return
*/
static Matrix3 Tube(double innerRadius, double outerRadius, double length)
{
double xx = (1.0/12.0)*(3.0*(innerRadius*innerRadius + outerRadius*outerRadius) + length*length);
double yy = xx;
double zz = (1.0/2.0)*(innerRadius*innerRadius + outerRadius*outerRadius);
return Matrix3{{xx, 0.0, 0.0},
{0.0, yy, 0.0},
{0.0, 0.0, zz}};
}
};
}
#endif // INERTIATENSORS_H

View File

@ -1 +0,0 @@
#include "MotorCase.h"

View File

@ -1,17 +0,0 @@
#ifndef MODEL_MOTORCASE_H
#define MODEL_MOTORCASE_H
namespace model
{
class MotorCase
{
public:
MotorCase();
~MotorCase();
private:
};
} // namespace model
#endif // MODEL_MOTORCASE_H

View File

@ -60,6 +60,7 @@ double MotorModel::getMass(double simTime) const
double propMassEnd = i->second;
double slope = (propMassEnd - propMassStart) / (tEnd - tStart);
double currentMass = emptyMass + propMassStart + (thrustTime - tStart) * slope;
utils::Logger::getInstance()->info("simTime: " + std::to_string(simTime) + ": motor mass: " + std::to_string(currentMass));
return currentMass;
}
@ -89,6 +90,17 @@ double MotorModel::getThrust(double simTime)
void MotorModel::setMetaData(const MetaData& md)
{
data = md;
computeMassCurve();
}
void MotorModel::moveMetaData(MetaData&& md)
{
data = std::move(md);
computeMassCurve();
}
void MotorModel::computeMassCurve()
{
emptyMass = data.totalWeight - data.propWeight;
// Calculate the Isp for the motor, as we'll need this for the computing the mass flow rate.
@ -115,13 +127,5 @@ void MotorModel::setMetaData(const MetaData& md)
propMass -= thrust.getThrust(t + i*timeStep) * timeStep * data.propWeight / data.totalImpulse;
}
massCurve.push_back(std::make_pair(data.burnTime, 0.0));
}
void MotorModel::moveMetaData(MetaData&& md)
{
data = std::move(md);
}
} // namespace model

View File

@ -134,7 +134,7 @@ public:
* @brief str Returns a string representation of AVAILABILITY enum
* @return string representation
*/
std::string str()
std::string str() const
{
if(availability == AVAILABILITY::REGULAR)
return std::string("regular");
@ -176,7 +176,7 @@ public:
* @brief str Returns a string representation of CERTORG enum
* @return string representation
*/
std::string str()
std::string str() const
{
if(org == CERTORG::AMRS)
return std::string("Austrialian Model Rocket Society Inc.");
@ -235,7 +235,7 @@ public:
* @brief str Returns a string representation of MOTORTYPE enum
* @return string representation
*/
std::string str()
std::string str() const
{
if(type == MOTORTYPE::SU)
return std::string("Single Use");
@ -253,10 +253,12 @@ public:
static MOTORTYPE toEnum(const std::string& name)
{
if(name == "SU" ||
name == "Single Use")
name == "Single Use" ||
name == "single-use")
return MOTORTYPE::SU;
else if(name == "reload" ||
name == "Reload")
name == "Reload" ||
name == "reloadable")
return MOTORTYPE::RELOAD;
else // It's a hybrid
return MOTORTYPE::HYBRID;
@ -284,7 +286,7 @@ public:
* @brief str Returns a string representation of MOTORMANUFACTURER enum
* @return string representation
*/
std::string str()
std::string str() const
{
switch(manufacturer)
{
@ -413,6 +415,8 @@ private:
std::vector<std::pair<double, double>> massCurve;
void computeMassCurve();
};
} // namespace model

109
model/Part.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "Part.h"
#include "utils/Logger.h"
namespace model
{
Part::Part(const std::string& n,
const Matrix3& I,
double m,
const Vector3& centerMass)
: parent(nullptr),
name(n),
inertiaTensor(I),
compositeInertiaTensor(I),
mass(m),
compositeMass(m),
cm(centerMass),
needsRecomputing(false),
childParts()
{ }
Part::~Part()
{}
Part::Part(const Part& orig)
: parent(orig.parent),
name(orig.name),
inertiaTensor(orig.inertiaTensor),
compositeInertiaTensor(orig.compositeInertiaTensor),
mass(orig.mass),
compositeMass(orig.compositeMass),
cm(orig.cm),
needsRecomputing(orig.needsRecomputing),
childParts()
{
// We are copying the whole tree. If the part we're copying itself has child
// parts, we are also copying all of them! This may be inefficient and not what
// is desired, but it is less likely to lead to weird bugs with the same part
// appearing in multiple locations of the rocket
utils::Logger::getInstance()->debug("Calling model::Part copy constructor. Recursively copying all child parts. Check Part names for uniqueness");
for(const auto& i : orig.childParts)
{
Part& x = *std::get<0>(i);
std::shared_ptr<Part> tempPart = std::make_shared<Part>(x);
childParts.emplace_back(tempPart, std::get<1>(i));;
}
}
double Part::getChildMasses(double t)
{
double childMasses{0.0};
for(const auto& i : childParts)
{
childMasses += std::get<0>(i)->getMass(t);
}
return childMasses;
}
void Part::addChildPart(const Part& childPart, Vector3 position)
{
double childMass = childPart.compositeMass;
Matrix3 childInertiaTensor = childPart.compositeInertiaTensor;
std::shared_ptr<Part> newChild = std::make_shared<Part>(childPart);
// Set the parent pointer
newChild->parent = this;
// Recompute inertia tensor
childInertiaTensor += childMass * ( position.dot(position) * Matrix3::Identity() - position*position.transpose());
compositeInertiaTensor += childInertiaTensor;
compositeMass += childMass;
childParts.emplace_back(std::move(newChild), std::move(position));
if(parent)
{
parent->markAsNeedsRecomputing();
parent->recomputeInertiaTensor();
}
}
void Part::recomputeInertiaTensor()
{
if(!needsRecomputing)
{
return;
}
// recompute the whole composite inertia tensor
// Reset the composite inertia tensor
compositeInertiaTensor = inertiaTensor;
compositeMass = mass;
for(auto& [child, pos] : childParts)
{
child->recomputeInertiaTensor();
compositeInertiaTensor += child->compositeInertiaTensor + child->compositeMass * ( pos.dot(pos) * Matrix3::Identity() - pos*pos.transpose());
compositeMass += child->compositeMass;
}
needsRecomputing = false;
}
} // namespace model

136
model/Part.h Normal file
View File

@ -0,0 +1,136 @@
#ifndef MODEL_PART_H
#define MODEL_PART_H
/// \cond
// C headers
// C++ headers
#include <vector>
#include <memory>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "utils/math/MathTypes.h"
namespace model
{
class Part
{
public:
Part(const std::string& name,
const Matrix3& I,
double m,
const Vector3& centerMass);
virtual ~Part();
Part(const Part&);
Part& operator=(Part other)
{
if(this != &other)
{
std::swap(parent, other.parent);
std::swap(name, other.name);
std::swap(inertiaTensor, other.inertiaTensor);
std::swap(compositeInertiaTensor, other.compositeInertiaTensor);
std::swap(mass, other.mass);
std::swap(compositeMass, other.compositeMass);
std::swap(cm, other.cm);
std::swap(needsRecomputing, other.needsRecomputing);
std::swap(childParts, other.childParts);
}
return *this;
}
Part& operator=(Part&& other)
{
parent = std::move(other.parent);
name = std::move(other.name);
inertiaTensor = std::move(other.inertiaTensor);
compositeInertiaTensor = std::move(other.compositeInertiaTensor);
mass = std::move(other.mass);
compositeMass = std::move(other.compositeMass);
cm = std::move(other.cm);
needsRecomputing = std::move(other.needsRecomputing);
childParts = std::move(other.childParts);
return *this;
}
void setMass(double m) { mass = m; }
// Set the inertia tensor
void setI(const Matrix3& I) { inertiaTensor = I; }
Matrix3 getI() { return inertiaTensor; }
Matrix3 getCompositeI() { return compositeInertiaTensor; }
void setCm(const Vector3& x) { cm = x; }
// Special version of setCM that assumes the cm lies along the body x-axis
void setCm(double x) { cm = {x, 0.0, 0.0}; }
double getMass(double t)
{
return mass;
}
double getCompositeMass(double t)
{
return compositeMass;
}
/**
* @brief Add a child part to this part.
*
* @param childPart Child part to add
* @param position Relative position of the child part's center-of-mass w.r.t the
* parent's center of mass
*/
void addChildPart(const Part& childPart, Vector3 position);
/**
* @brief Recomputes the inertia tensor. If the change is due to the change in inertia
* of a child part, an optional name of the child part can be given to
* only recompute that change rather than recompute all child inertia
* tensors
*
* @param name Optional name of the child part to recompute. If empty, it will
* recompute all child inertia tensors
*/
//void recomputeInertiaTensor(std::string name = "");
void recomputeInertiaTensor();
private:
// This is a pointer to the parent Part, if it has one. Purpose is to be able to
// tell the parent if it needs to recompute anything if this part changes. e.g.
// if a change to this part's inertia tensor occurs, the parent needs to recompute
// it's total inertia tensor.
Part* parent{nullptr};
std::string name;
double getChildMasses(double t);
void markAsNeedsRecomputing()
{ needsRecomputing = true; if(parent) { parent->markAsNeedsRecomputing(); }}
// Because a part is both a simple part and the composite of itself with all of it's children,
// we will keep track of this object's inertia tensor (without children), and the composite
// one with all of it's children attached
Matrix3 inertiaTensor; // moment of inertia tensor with respect to the part's center of mass and
Matrix3 compositeInertiaTensor;
double mass; // The moment of inertia tensor also has this, so don't double compute
double compositeMass; // The mass of this part along with all attached parts
Vector3 cm; // center of mass wrt middle of component
bool needsRecomputing{false};
/// @brief child parts and the relative positions of their center of mass w.r.t.
/// the center of mass of this part
std::vector<std::tuple<std::shared_ptr<Part>, Vector3>> childParts;
};
}
#endif // MODEL_PART_H

0
model/Propagatable.cpp Normal file
View File

58
model/Propagatable.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef MODEL_PROPAGATABLE_H
#define MODEL_PROPAGATABLE_H
/// \cond
// C headers
// C++ headers
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "sim/Aero.h"
#include "sim/StateData.h"
#include "utils/math/MathTypes.h"
namespace model
{
class Propagatable
{
public:
Propagatable() {}
virtual ~Propagatable() {}
virtual Vector3 getForces(double t) = 0;
virtual Vector3 getTorques(double t) = 0;
virtual double getMass(double t) = 0;
virtual Matrix3 getInertiaTensor(double t) = 0;
virtual bool terminateCondition(double t) = 0;
void setCurrentState(const StateData& st) { currentState = st; }
const StateData& getCurrentState() { return currentState; }
const StateData& getInitialState() { return initialState; }
void setInitialState(const StateData& init) { initialState = init; }
void appendState(double t, const StateData& st) { states.emplace_back(t, st); }
const std::vector<std::pair<double, StateData>>& getStates() { return states; }
void clearStates() { states.clear(); }
protected:
sim::Aero aeroData;
StateData initialState;
StateData currentState;
StateData nextState;
std::vector<std::pair<double, StateData>> states;
};
}
#endif // MODEL_PROPAGATABLE_H

View File

@ -1,35 +0,0 @@
#include "Rocket.h"
#include "QtRocket.h"
Rocket::Rocket() : propagator(this)
{
}
void Rocket::launch()
{
propagator.setTimeStep(QtRocket::getInstance()->getTimeStep());
propagator.clearStates();
propagator.setCurrentTime(0.0);
mm.startMotor(0.0);
propagator.runUntilTerminate();
}
void Rocket::setMotorModel(const model::MotorModel& motor)
{
mm = motor;
}
bool Rocket::terminateCondition(const std::pair<double, std::vector<double>>& cond)
{
// Terminate propagation when the z coordinate drops below zero
if(cond.second[2] < 0)
return true;
else
return false;
}
double Rocket::getThrust(double t)
{
return mm.getThrust(t);
}

View File

@ -1,119 +0,0 @@
#ifndef ROCKET_H
#define ROCKET_H
/// \cond
// C headers
// C++ headers
#include <memory>
#include <string>
#include <utility> // std::move
// 3rd party headers
/// \endcond
// qtrocket headers
#include "model/ThrustCurve.h"
#include "model/MotorModel.h"
#include "sim/Propagator.h"
/**
* @brief The Rocket class holds all rocket components
*
*/
class Rocket
{
public:
/**
* @brief Rocket class constructor
*/
Rocket();
/**
* @brief launch Propagates the Rocket object until termination,
* normally when altitude crosses from positive to negative
*/
void launch();
/**
* @brief getStates returns a vector of time/state pairs generated during launch()
* @return vector of pairs of doubles, where the first value is a time and the second a state vector
*/
const std::vector<std::pair<double, std::vector<double>>>& getStates() const { return propagator.getStates(); }
/**
* @brief setInitialState sets the initial state of the Rocket.
* @param initState initial state vector (x, y, z, xDot, yDot, zDot, pitch, yaw, roll, pitchDot, yawDot, rollDot)
*/
void setInitialState(const std::vector<double>& initState) { propagator.setInitialState(initState); }
/**
* @brief getMass returns the current mass of the rocket. This is the sum of all components' masses
* @return total current mass of the Rocket
*/
double getMass() const { return mass; }
/**
* @brief setMass sets the current total mass of the Rocket
* @param m total Rocket mass
* @todo This should be dynamically computed, not set. Fix this
*/
void setMass(double m) { mass = m;}
/**
* @brief setDragCoefficient sets the current total drag coefficient of the Rocket
* @param d drag coefficient
* @todo This should be dynamically computed, not set. Fix this
*/
void setDragCoefficient(double d) { dragCoeff = d; }
/**
* @brief getDragCoefficient returns the current drag coefficient
*
* This is intended to be called by the propagator during propagation.
* @return the coefficient of drag
*/
double getDragCoefficient() const { return dragCoeff; }
/**
* @brief getThrust returns current motor thrust
* @param t current simulation time
* @return thrust in Newtons
*/
double getThrust(double t);
/**
* @brief setMotorModel
* @param motor
*/
void setMotorModel(const model::MotorModel& motor);
/**
* @brief Returns the current motor model.
* @return The current motor model
*/
const model::MotorModel& getCurrentMotorModel() const { return mm; }
/**
* @brief terminateCondition returns true or false, whether the passed-in time/state matches the terminate condition
* @param cond time/state pair
* @return true if the passed-in time/state satisfies the terminate condition
*/
bool terminateCondition(const std::pair<double, std::vector<double>>& cond);
/**
* @brief setName sets the rocket name
* @param n name to set the Rocket
*/
void setName(const std::string& n) { name = n; }
private:
std::string name; /// Rocket name
sim::Propagator propagator; /// propagator
double dragCoeff; /// @todo get rid of this, should be dynamically calculated
double mass; /// @todo get rid of this, should be dynamically computed, but is the current rocket mass
model::MotorModel mm; /// Current Motor Model
};
#endif // ROCKET_H

79
model/RocketModel.cpp Normal file
View File

@ -0,0 +1,79 @@
// qtrocket headers
#include "RocketModel.h"
#include "QtRocket.h"
#include "InertiaTensors.h"
namespace model
{
RocketModel::RocketModel()
: topPart("NoseCone", InertiaTensors::SolidSphere(1.0), 1.0, {0.0, 0.0, 1.0})
{
}
double RocketModel::getMass(double t)
{
double mass = mm.getMass(t);
mass += topPart.getCompositeMass(t);
return mass;
}
Matrix3 RocketModel::getInertiaTensor(double)
{
return topPart.getCompositeI();
}
bool RocketModel::terminateCondition(double)
{
// Terminate propagation when the z coordinate drops below zero
if(currentState.position[2] < 0)
return true;
else
return false;
}
Vector3 RocketModel::getForces(double t)
{
// Get thrust
// Assume that thrust is always through the center of mass and in the rocket's Z-axis
Vector3 forces{0.0, 0.0, mm.getThrust(t)};
// Get gravity
auto gravityModel = QtRocket::getInstance()->getEnvironment()->getGravityModel();
Vector3 gravity = gravityModel->getAccel(currentState.position)*getMass(t);
forces += gravity;
// Calculate aero forces
return forces;
}
Vector3 RocketModel::getTorques(double t)
{
return Vector3{0.0, 0.0, 0.0};
}
double RocketModel::getThrust(double t)
{
return mm.getThrust(t);
}
void RocketModel::launch()
{
mm.startMotor(0.0);
}
void RocketModel::setMotorModel(const model::MotorModel& motor)
{
mm = motor;
}
} // namespace model

116
model/RocketModel.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef ROCKETMODEL_H
#define ROCKETMODEL_H
/// \cond
// C headers
// C++ headers
#include <vector>
#include <memory>
#include <string>
#include <utility> // std::move
// 3rd party headers
/// \endcond
// qtrocket headers
#include "model/Part.h"
#include "sim/Propagator.h"
#include "model/MotorModel.h"
#include "model/Propagatable.h"
// Not yet
//#include "model/Stage.h"
namespace model
{
/**
* @brief The Rocket class holds all rocket components
*
*/
class RocketModel : public Propagatable
{
public:
/**
* @brief Rocket class constructor
*/
RocketModel();
/**
* @brief Rocket class destructor
*
*/
virtual ~RocketModel() {}
/**
* @brief launch Propagates the Rocket object until termination,
* normally when altitude crosses from positive to negative
*/
void launch();
Vector3 getForces(double t) override;
Vector3 getTorques(double t) override;
/**
* @brief getMass returns current rocket mass
* @param t current simulation time
* @return mass in kg
*/
double getMass(double t) override;
/**
* @brief terminateCondition returns true or false, whether the passed-in time/state matches the terminate condition
* @param cond time/state pair
* @return true if the passed-in time/state satisfies the terminate condition
*/
bool terminateCondition(double t) override;
Matrix3 getInertiaTensor(double t) override;
/**
* @brief getThrust returns current motor thrust
* @param t current simulation time
* @return thrust in Newtons
*/
double getThrust(double t);
/**
* @brief setMotorModel
* @param motor
*/
void setMotorModel(const model::MotorModel& motor);
/**
* @brief getMotorModel
*/
MotorModel getMotorModel() { return mm; }
/**
* @brief Returns the current motor model.
* @return The current motor model
*/
//const model::MotorModel& getCurrentMotorModel() const { return mm; }
/**
* @brief setName sets the rocket name
* @param n name to set the Rocket
*/
void setName(const std::string& n) { name = n; }
double getDragCoefficient() { return 1.0; }
void setDragCoefficient(double d) { }
void setMass(double m) { }
private:
std::string name; /// Rocket name
model::MotorModel mm; /// Current Motor Model
model::Part topPart;
};
} // namespace model
#endif // ROCKETMODEL_H

View File

@ -8,8 +8,6 @@
/// \endcond
#include "model/ThrustCurve.h"
#include "utils/Logger.h"
ThrustCurve::ThrustCurve(std::vector<std::pair<double, double>>& tc)
: thrustCurve(tc),

View File

@ -0,0 +1,16 @@
add_executable(model_tests
PartTests.cpp
)
target_link_libraries(model_tests PRIVATE
model
utils
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(model_tests)
add_test(NAME qtrocket_model_tests COMMAND model_tests)

70
model/tests/PartTests.cpp Normal file
View File

@ -0,0 +1,70 @@
#include <gtest/gtest.h>
#include "model/Part.h"
class PartTest : public testing::Test
{
protected:
// Per-test-suite set-up.
// Called before the first test in this test suite.
// Can be omitted if not needed.
static void SetUpTestSuite()
{
//shared_resource_ = new ...;
// If `shared_resource_` is **not deleted** in `TearDownTestSuite()`,
// reallocation should be prevented because `SetUpTestSuite()` may be called
// in subclasses of FooTest and lead to memory leak.
//
// if (shared_resource_ == nullptr) {
// shared_resource_ = new ...;
// }
}
// Per-test-suite tear-down.
// Called after the last test in this test suite.
// Can be omitted if not needed.
static void TearDownTestSuite()
{
//delete shared_resource_;
//shared_resource_ = nullptr;
}
// You can define per-test set-up logic as usual.
void SetUp() override { }
// You can define per-test tear-down logic as usual.
void TearDown() override { }
// Some expensive resource shared by all tests.
//static T* shared_resource_;
};
//T* FooTest::shared_resource_ = nullptr;
TEST(PartTest, CreationTests)
{
Matrix3 inertia;
inertia << 1, 0, 0,
0, 1, 0,
0, 0, 1;
Vector3 cm{1, 0, 0};
model::Part testPart("testPart",
inertia,
1.0,
cm);
Matrix3 inertia2;
inertia2 << 1, 0, 0,
0, 1, 0,
0, 0, 1;
Vector3 cm2{1, 0, 0};
model::Part testPart2("testPart2",
inertia2,
1.0,
cm2);
Vector3 R{2.0, 2.0, 2.0};
testPart.addChildPart(testPart2, R);
}

0
sim/Aero.cpp Normal file
View File

40
sim/Aero.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef SIM_AERO_H
#define SIM_AERO_H
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
// qtrocket headers
#include "utils/math/MathTypes.h"
namespace sim
{
class Aero
{
public:
private:
Vector3 cp; /// center of pressure
double Cx; /// longitudinal coefficient
double Cy; /// These are probably the same for axial symmetric
double Cz; /// rockets. The coeffients in the y and z body directions
double Cl; // roll moment coefficient
double Cm; // pitch moment coefficient
double Cn; // yaw moment coefficient
double baseCd; // coefficient of drag due to base drag
double Cd; // total coeffient of drag
};
}
#endif // SIM_AERO_H

View File

@ -13,6 +13,10 @@ public:
virtual double getDensity(double altitude) = 0;
virtual double getPressure(double altitude) = 0;
virtual double getTemperature(double altitude) = 0;
virtual double getSpeedOfSound(double altitude) = 0;
virtual double getDynamicViscosity(double altitude) = 0;
};
} // namespace sim

28
sim/CMakeLists.txt Normal file
View File

@ -0,0 +1,28 @@
add_library(sim
Aero.cpp
Aero.h
AtmosphericModel.h
ConstantAtmosphere.h
ConstantGravityModel.h
DESolver.h
Environment.h
GeoidModel.h
GravityModel.h
Propagator.cpp
Propagator.h
RK4Solver.h
SphericalGeoidModel.cpp
SphericalGeoidModel.h
SphericalGravityModel.cpp
SphericalGravityModel.h
StateData.h
USStandardAtmosphere.cpp
USStandardAtmosphere.h
WindModel.cpp
WindModel.h)
target_link_libraries(sim PRIVATE
utils)
# Unit tests
add_subdirectory(tests)

View File

@ -15,6 +15,10 @@ public:
double getDensity(double) override { return 1.225; }
double getPressure(double) override { return 101325.0; }
double getTemperature(double) override { return 288.15; }
double getSpeedOfSound(double) override { return 340.294; }
double getDynamicViscosity(double) override { return 1.78938e-5; }
};
} // namespace sim

View File

@ -1,10 +0,0 @@
#include "ConstantGravityModel.h"
namespace sim {
ConstantGravityModel::ConstantGravityModel()
{
}
} // namespace sim

View File

@ -3,18 +3,21 @@
// qtrocket headers
#include "sim/GravityModel.h"
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim {
class ConstantGravityModel : public GravityModel
{
public:
ConstantGravityModel();
ConstantGravityModel() {}
virtual ~ConstantGravityModel() {}
TripletD getAccel(double, double, double) override { return TripletD(0.0, 0.0, -9.8); }
Vector3 getAccel(double, double, double) override
{
return Vector3(0.0, 0.0, -9.8);
}
};
} // namespace sim

View File

@ -4,14 +4,17 @@
/// \cond
// C headers
// C++ headers
#include <vector>
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
namespace sim
{
template<typename T>
class DESolver
{
public:
@ -19,7 +22,17 @@ public:
virtual ~DESolver() {}
virtual void setTimeStep(double ts) = 0;
virtual void step(double t, const std::vector<double>& curVal, std::vector<double>& res ) = 0;
/**
* @brief
*
* @param curVal
* @param res
* @param t Optional parameter, but not used in QtRocket. Some generic solvers take time as
* a parameter to ODEs, but QtRocket's kinematic equations don't. Since I wrote
* the RK4 solver independently as a general tool, this interface is needed
* here unfortunately.
*/
virtual std::pair<T, T> step(T& state, T& rate) = 0;
};
} // namespace sim

View File

@ -1,24 +1,20 @@
#ifndef SIMULATIONOPTIONS_H
#define SIMULATIONOPTIONS_H
#ifndef SIM_ENVIRONMENT_H
#define SIM_ENVIRONMENT_H
/// \cond
// C headers
// C++ headers
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <iterator>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "sim/GravityModel.h"
#include "sim/SphericalGravityModel.h"
#include "sim/ConstantGravityModel.h"
#include "sim/SphericalGravityModel.h"
#include "sim/AtmosphericModel.h"
#include "sim/ConstantAtmosphere.h"
#include "sim/USStandardAtmosphere.h"
@ -26,22 +22,23 @@ namespace sim
{
/**
* @brief The SimulationOptions class holds the available simulation options and environmental models
* @brief Holds simulation environment information, such as the gravity model, atmosphere model,
* Geoid model
*
*/
class SimulationOptions
class Environment
{
public:
SimulationOptions()
Environment()
{
setTimeStep(0.01);
setGravityModel("Constant Gravity");
setAtmosphereModel("Constant Atmosphere");
}
~SimulationOptions() = default;
SimulationOptions(const SimulationOptions&) = delete;
SimulationOptions(SimulationOptions&&) = delete;
SimulationOptions& operator=(const SimulationOptions&) = delete;
SimulationOptions& operator=(SimulationOptions&&) = delete;
~Environment() = default;
Environment(const Environment&) = delete;
Environment(Environment&&) = delete;
Environment& operator=(const Environment&) = delete;
Environment& operator=(Environment&&) = delete;
std::vector<std::string> getAvailableGravityModels()
{
@ -59,7 +56,6 @@ public:
return retVal;
}
void setTimeStep(double t) { timeStep = t; }
void setGravityModel(const std::string& model)
{
if(model == "Constant Gravity")
@ -94,7 +90,6 @@ public:
return retVal;
}
std::shared_ptr<sim::GravityModel> getGravityModel() { return gravityModels[gravityModel]; }
double getTimeStep() { return timeStep; }
private:
@ -106,12 +101,11 @@ private:
{"Constant Gravity", std::shared_ptr<sim::GravityModel>()},
{"Spherical Gravity", std::shared_ptr<sim::GravityModel>()}};
double timeStep{0.01};
std::string gravityModel{"Constant Gravity"}; /// Constant Gravity Model is the default
std::string atmosphereModel{"Constant Atmosphere"}; /// Constant Atmosphere Model is the default
};
}
} // namespace sim
#endif // SIMULATIONOPTIONS_H
#endif // SIM_ENVIRONMENT_H

View File

@ -1,14 +0,0 @@
#include "GravityModel.h"
namespace sim
{
GravityModel::GravityModel()
{
}
GravityModel::~GravityModel()
{
}
} // namespace sim

View File

@ -2,7 +2,7 @@
#define SIM_GRAVITYMODEL_H
// qtrocket headers
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim
{
@ -10,11 +10,11 @@ namespace sim
class GravityModel
{
public:
GravityModel();
virtual ~GravityModel();
GravityModel() {}
virtual ~GravityModel() {}
virtual TripletD getAccel(double x, double y, double z) = 0;
TripletD getAccel(const TripletD& t) { return this->getAccel(t.x1, t.x2, t.x3); }
virtual Vector3 getAccel(double x, double y, double z) = 0;
Vector3 getAccel(const Vector3& t) { return this->getAccel(t.x(), t.y(), t.z()); }
};
} // namespace sim

View File

@ -2,7 +2,6 @@
/// \cond
// C headers
// C++ headers
#include <cmath>
#include <chrono>
#include <iostream>
#include <sstream>
@ -14,46 +13,35 @@
// qtrocket headers
#include "Propagator.h"
#include "QtRocket.h"
#include "model/Rocket.h"
#include "sim/RK4Solver.h"
#include "utils/Logger.h"
namespace sim {
Propagator::Propagator(Rocket* r)
: integrator(),
rocket(r)
namespace sim
{
Propagator::Propagator(std::shared_ptr<model::Propagatable> r)
: linearIntegrator(),
object(r),
saveStates(true),
timeStep(0.01)
{
// Linear velocity and acceleration
std::function<std::pair<Vector3, Vector3>(Vector3&, Vector3&)> linearODEs = [this](Vector3& state, Vector3& rate) -> std::pair<Vector3, Vector3>
{
Vector3 dPosition;
Vector3 dVelocity;
// dx/dt
dPosition = rate;
// This is a little strange, but I have to populate the integrator unique_ptr
// with reset. make_unique() doesn't work because the compiler can't seem to
// deduce the template parameters correctly, and I don't want to specify them
// manually either. RK4Solver constructor is perfectly capable of deducing it's
// template types, and it derives from DESolver, so we can just reset the unique_ptr
// and pass it a freshly allocated RK4Solver pointer
// dvx/dt
dVelocity = object->getForces(currentTime) / object->getMass(currentTime);
// The state vector has components of the form:
// (x, y, z, xdot, ydot, zdot, pitch, yaw, roll, pitchRate, yawRate, rollRate)
integrator.reset(new RK4Solver(
/* dx/dt */ [](double, const std::vector<double>& s) -> double {return s[3]; },
/* dy/dt */ [](double, const std::vector<double>& s) -> double {return s[4]; },
/* dz/dt */ [](double, const std::vector<double>& s) -> double {return s[5]; },
/* dvx/dt */ [this](double, const std::vector<double>& ) -> double { return getForceX() / getMass(); },
/* dvy/dt */ [this](double, const std::vector<double>& ) -> double { return getForceY() / getMass(); },
/* dvz/dt */ [this](double, const std::vector<double>& ) -> double { return getForceZ() / getMass(); },
/* dpitch/dt */ [](double, const std::vector<double>& s) -> double { return s[9]; },
/* dyaw/dt */ [](double, const std::vector<double>& s) -> double { return s[10]; },
/* droll/dt */ [](double, const std::vector<double>& s) -> double { return s[11]; },
/* dpitchRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueP() - s[7] * s[8] * (getIroll() - getIyaw())) / getIpitch(); },
/* dyawRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueQ() - s[6] * s[9] * (getIpitch() - getIroll())) / getIyaw(); },
/* drollRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueR() - s[6] * s[7] * (getIyaw() - getIpitch())) / getIroll(); }));
return std::make_pair(dPosition, dVelocity);
};
linearIntegrator.reset(new RK4Solver<Vector3>(linearODEs));
linearIntegrator->setTimeStep(timeStep);
integrator->setTimeStep(timeStep);
saveStates = true;
}
@ -66,17 +54,27 @@ void Propagator::runUntilTerminate()
std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point endTime;
Vector3 currentPosition;
Vector3 currentVelocity;
Vector3 nextPosition;
Vector3 nextVelocity;
while(true)
{
// tempRes gets overwritten
integrator->step(currentTime, currentState, tempRes);
currentPosition = object->getCurrentState().position;
currentVelocity = object->getCurrentState().velocity;
std::tie(nextPosition, nextVelocity) = linearIntegrator->step(currentPosition, currentVelocity);
StateData nextState;
nextState.position = nextPosition;
nextState.velocity = nextVelocity;
object->setCurrentState(nextState);
std::swap(currentState, tempRes);
if(saveStates)
{
states.push_back(std::make_pair(currentTime, currentState));
object->appendState(currentTime, nextState);
}
if(rocket->terminateCondition(std::make_pair(currentTime, currentState)))
if(object->terminateCondition(currentTime))
break;
currentTime += timeStep;
@ -90,34 +88,4 @@ void Propagator::runUntilTerminate()
}
double Propagator::getMass()
{
return rocket->getMass();
}
double Propagator::getForceX()
{
QtRocket* qtrocket = QtRocket::getInstance();
return (currentState[3] >= 0 ? -1.0 : 1.0) * qtrocket->getAtmosphereModel()->getDensity(currentState[2])/ 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState[3]* currentState[3];
}
double Propagator::getForceY()
{
QtRocket* qtrocket = QtRocket::getInstance();
return (currentState[4] >= 0 ? -1.0 : 1.0) * qtrocket->getAtmosphereModel()->getDensity(currentState[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState[4]* currentState[4];
}
double Propagator::getForceZ()
{
QtRocket* qtrocket = QtRocket::getInstance();
double gravity = (qtrocket->getGravityModel()->getAccel(currentState[0], currentState[1], currentState[2])).x3;
double airDrag = (currentState[5] >= 0 ? -1.0 : 1.0) * qtrocket->getAtmosphereModel()->getDensity(currentState[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState[5]* currentState[5];
double thrust = rocket->getThrust(currentTime);
return gravity + airDrag + thrust;
}
double Propagator::getTorqueP() { return 0.0; }
double Propagator::getTorqueQ() { return 0.0; }
double Propagator::getTorqueR() { return 0.0; }
} // namespace sim

View File

@ -5,17 +5,22 @@
// C headers
// C++ headers
#include <memory>
#include <vector>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "sim/DESolver.h"
#include "sim/RK4Solver.h"
#include "utils/math/MathTypes.h"
#include "sim/StateData.h"
#include "model/Propagatable.h"
// Forward declare
namespace model
{
class Rocket;
}
class QtRocket;
namespace sim
@ -24,22 +29,17 @@ namespace sim
class Propagator
{
public:
Propagator(Rocket* r);
Propagator(std::shared_ptr<model::Propagatable> o);
~Propagator();
void setInitialState(const std::vector<double>& initialState)
void setInitialState(const StateData& initialState)
{
currentState.resize(initialState.size());
for(std::size_t i = 0; i < initialState.size(); ++i)
{
currentState[i] = initialState[i];
object->setInitialState(initialState);
}
}
const std::vector<double>& getCurrentState() const
const StateData& getCurrentState() const
{
return currentState;
return object->getCurrentState();
}
void runUntilTerminate();
@ -49,41 +49,21 @@ public:
saveStates = s;
}
const std::vector<std::pair<double, std::vector<double>>>& getStates() const { return states; }
void clearStates() { states.clear(); }
void setCurrentTime(double t) { currentTime = t; }
void setTimeStep(double ts) { timeStep = ts; }
void setSaveStats(bool s) { saveStates = s; }
private:
double getMass();
double getForceX();
double getForceY();
double getForceZ();
double getTorqueP();
double getTorqueQ();
double getTorqueR();
std::unique_ptr<sim::RK4Solver<Vector3>> linearIntegrator;
// std::unique_ptr<sim::RK4Solver<Quaternion>> orientationIntegrator;
double getIpitch() { return 1.0; }
double getIyaw() { return 1.0; }
double getIroll() { return 1.0; }
std::shared_ptr<model::Propagatable> object;
//private:
std::unique_ptr<sim::DESolver> integrator;
Rocket* rocket;
std::vector<double> currentState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
std::vector<double> tempRes{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
bool saveStates{true};
double currentTime{0.0};
double timeStep{0.01};
std::vector<std::pair<double, std::vector<double>>> states;
};
} // namespace sim

View File

@ -4,10 +4,8 @@
/// \cond
// C headers
// C++ headers
#include <cmath>
#include <functional>
#include <limits>
#include <vector>
// 3rd party headers
@ -16,84 +14,80 @@
// qtrocket headers
#include "sim/DESolver.h"
#include "utils/Logger.h"
#include "utils/math/MathTypes.h"
namespace sim {
template<typename... Ts>
class RK4Solver : public DESolver
/**
* @brief Runge-Kutta 4th order coupled ODE solver.
* @note This was written outside of the context of QtRocket, and it is very generic. There are
* some features of this solver that are note used by QtRocket, for example, it can solve
* and arbitrarily large system of coupled ODEs, but QtRocket only makes use of a system
* of size 6 (x, y, z, xDot, yDot, zDot) at a time.
*
* @tparam Ts
*/
template<typename T>
class RK4Solver : public DESolver<T>
{
public:
RK4Solver(Ts... funcs)
RK4Solver(std::function<std::pair<T, T>(T&, T&)> func)
{
(odes.push_back(funcs), ...);
temp.resize(sizeof...(Ts));
// This only works for Eigen Vector types.
// TODO: Figure out how to make this slightly more generic, but for now
// we're only using this for Vector3 and Quaternion types
static_assert(std::is_same<T, Vector3>::value
|| std::is_same<T, Quaternion>::value,
"You can only use Vector3 or Quaternion valued functions in RK4Solver");
odes = func;
}
virtual ~RK4Solver() {}
void setTimeStep(double inTs) override { dt = inTs; halfDT = dt / 2.0; }
void step(double t, const std::vector<double>& curVal, std::vector<double>& res) override
std::pair<T, T> step(T& state, T& rate) override
{
std::pair<T, T> res;
if(dt == std::numeric_limits<double>::quiet_NaN())
{
utils::Logger::getInstance()->error("Calling RK4Solver without setting dt first is an error");
res[0] = std::numeric_limits<double>::quiet_NaN();
return res;
}
for(size_t i = 0; i < len; ++i)
{
k1[i] = odes[i](t, curVal);
}
std::tie(k1State, k1Rate) = odes(state, rate);
// compute k2 values. This involves stepping the current values forward a half-step
// based on k1, so we do the stepping first
for(size_t i = 0; i < len; ++i)
{
temp[i] = curVal[i] + k1[i]*dt / 2.0;
}
for(size_t i = 0; i < len; ++i)
{
k2[i] = odes[i](t + halfDT, temp);
}
// repeat for k3
for(size_t i = 0; i < len; ++i)
{
temp[i] = curVal[i] + k2[i]*dt / 2.0;
}
for(size_t i = 0; i < len; ++i)
{
k3[i] = odes[i](t + halfDT, temp);
}
std::tie(tempState, tempRate) = std::make_pair(state + k1State*halfDT, rate + k1Rate*halfDT);
std::tie(k2State, k2Rate) = odes(tempState, tempRate);
// now k4
for(size_t i = 0; i < len; ++i)
{
temp[i] = curVal[i] + k3[i]*dt;
}
for(size_t i = 0; i < len; ++i)
{
k4[i] = odes[i](t + dt, temp);
}
std::tie(tempState, tempRate) = std::make_pair(state + k2State*halfDT, rate + k2Rate*halfDT);
std::tie(k3State, k3Rate) = odes(tempState, tempRate);
// now compute the result
for(size_t i = 0; i < len; ++i)
{
res[i] = curVal[i] + (dt / 6.0)*(k1[i] + 2.0*k2[i] + 2.0*k3[i] + k4[i]);
}
std::tie(tempState, tempRate) = std::make_pair(state + k3State*dt, rate + k3Rate*dt);
std::tie(k4State, k4Rate) = odes(tempState, tempRate);
res = std::make_pair(state + (dt / 6.0)*(k1State + 2.0*k2State + 2.0*k3State + k4State),
rate + (dt / 6.0)*(k1Rate + 2.0*k2Rate + 2.0*k3Rate + k4Rate));
return res;
}
private:
std::vector<std::function<double(double, const std::vector<double>&)>> odes;
std::function<std::pair<T, T>(T&, T&)> odes;
static constexpr size_t len = sizeof...(Ts);
double k1[len];
double k2[len];
double k3[len];
double k4[len];
T k1State;
T k2State;
T k3State;
T k4State;
T k1Rate;
T k2Rate;
T k3Rate;
T k4Rate;
std::vector<double> temp;
T tempState;
T tempRate;
double dt = std::numeric_limits<double>::quiet_NaN();
double halfDT = 0.0;

View File

@ -25,7 +25,7 @@ SphericalGravityModel::~SphericalGravityModel()
}
TripletD SphericalGravityModel::getAccel(double x, double y, double z)
Vector3 SphericalGravityModel::getAccel(double x, double y, double z)
{
// Convert x, y, z from meters to km. This is to avoid potential precision losses
// with using the earth's gravitation parameter in meters (14 digit number).
@ -43,7 +43,7 @@ TripletD SphericalGravityModel::getAccel(double x, double y, double z)
double ay = accelFactor * y_km * 1000.0;
double az = accelFactor * z_km * 1000.0;
return TripletD(ax, ay, az);
return Vector3(ax, ay, az);
}

View File

@ -2,7 +2,7 @@
#define SIM_SPHERICALGRAVITYMODEL_H
// qtrocket headers
#include "GravityModel.h"
#include "sim/GravityModel.h"
namespace sim
{
@ -13,7 +13,7 @@ public:
SphericalGravityModel();
virtual ~SphericalGravityModel();
TripletD getAccel(double x, double y, double z) override;
Vector3 getAccel(double x, double y, double z) override;
};
} // namespace sim

View File

@ -1,6 +0,0 @@
#include "StateData.h"
StateData::StateData()
{
}

View File

@ -1,9 +1,15 @@
#ifndef STATEDATA_H
#define STATEDATA_H
/// \cond
// C headers
// C++ headers
#include <vector>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "utils/math/Vector3.h"
#include "utils/math/Quaternion.h"
#include "utils/math/MathTypes.h"
/**
* @brief The StateData class holds physical state data. Things such as position, velocity,
@ -13,20 +19,76 @@
class StateData
{
public:
StateData();
StateData() {}
~StateData() {}
StateData(const StateData&) = default;
StateData(StateData&&) = default;
StateData& operator=(const StateData& rhs)
{
if(this != &rhs)
{
position = rhs.position;
velocity = rhs.velocity;
orientation = rhs.orientation;
orientationRate = rhs.orientationRate;
dcm = rhs.dcm;
eulerAngles = rhs.eulerAngles;
}
return *this;
}
StateData& operator=(StateData&& rhs)
{
if(this != &rhs)
{
position = std::move(rhs.position);
velocity = std::move(rhs.velocity);
orientation = std::move(rhs.orientation);
orientationRate = std::move(rhs.orientationRate);
dcm = std::move(rhs.dcm);
eulerAngles = std::move(rhs.eulerAngles);
}
return *this;
}
std::vector<double> getPosStdVector() const
{
return std::vector<double>{position[0], position[1], position[2]};
}
std::vector<double> getVelStdVector() const
{
return std::vector<double>{velocity[0], velocity[1], velocity[2]};
}
private:
math::Vector3 position{0.0, 0.0, 0.0};
math::Vector3 velocity{0.0, 0.0, 0.0};
/// TODO: Put these behind an interface
//Vector3 getPosition() const
//{
// return position;
//}
math::Quaternion orientation{0.0, 0.0, 0.0, 0.0}; // roll, pitch, yaw
math::Quaternion orientationRate{0.0, 0.0, 0.0, 0.0}; // roll-rate, pitch-rate, yaw-rate
// Necessary?
//math::Vector3 orientationAccel;
//Vector3 getVelocity() const
//{
// return velocity;
//}
// private:
// This is an array because the integrator expects it
double data[6];
// Intended to be used as world state data
Vector3 position{0.0, 0.0, 0.0};
Vector3 velocity{0.0, 0.0, 0.0};
// Orientation of body coordinates w.r.t. world coordinates
Quaternion orientation{0.0, 0.0, 0.0, 0.0}; /// (vector, scalar)
Quaternion orientationRate{0.0, 0.0, 0.0, 0.0}; /// (vector, scalar)
Matrix3 dcm{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
/// Euler angles are yaw-pitch-roll, and (3-2-1) order
/// yaw - psi
/// pitch - theta
/// roll - phi
Vector3 eulerAngles{0.0, 0.0, 0.0};
};

View File

@ -10,6 +10,7 @@
// qtrocket headers
#include "sim/USStandardAtmosphere.h"
#include "utils/math/Constants.h"
#include "utils/math/UtilityMathFunctions.h"
using namespace utils::math;
@ -17,9 +18,9 @@ namespace sim
{
// Populate static data
utils::BinMap initTemps()
utils::Bin initTemps()
{
utils::BinMap map;
utils::Bin map;
map.insert(std::make_pair(0.0, 288.15));
map.insert(std::make_pair(11000.0, 216.65));
map.insert(std::make_pair(20000.0, 216.65));
@ -32,9 +33,9 @@ utils::BinMap initTemps()
}
utils::BinMap initLapseRates()
utils::Bin initLapseRates()
{
utils::BinMap map;
utils::Bin map;
map.insert(std::make_pair(0.0, 0.0065));
map.insert(std::make_pair(11000.0, 0.0));
map.insert(std::make_pair(20000.0, -0.001));
@ -46,9 +47,9 @@ utils::BinMap initLapseRates()
return map;
}
utils::BinMap initDensities()
utils::Bin initDensities()
{
utils::BinMap map;
utils::Bin map;
map.insert(std::make_pair(0.0, 1.225));
map.insert(std::make_pair(11000.0, 0.36391));
map.insert(std::make_pair(20000.0, 0.08803));
@ -60,11 +61,24 @@ utils::BinMap initDensities()
return map;
}
utils::BinMap USStandardAtmosphere::temperatureLapseRate(initLapseRates());
utils::BinMap USStandardAtmosphere::standardTemperature(initTemps());
utils::BinMap USStandardAtmosphere::standardDensity(initDensities());
utils::Bin initPressures()
{
utils::Bin map;
map.insert(std::make_pair(0.0, 101325));
map.insert(std::make_pair(11000.0, 22632.1));
map.insert(std::make_pair(20000.0, 5474.89));
map.insert(std::make_pair(32000.0, 868.02));
map.insert(std::make_pair(47000.0, 110.91));
map.insert(std::make_pair(51000.0, 66.94));
map.insert(std::make_pair(71000.0, 3.96));
return map;
}
utils::Bin USStandardAtmosphere::temperatureLapseRate(initLapseRates());
utils::Bin USStandardAtmosphere::standardTemperature(initTemps());
utils::Bin USStandardAtmosphere::standardDensity(initDensities());
utils::Bin USStandardAtmosphere::standardPressure(initPressures());
USStandardAtmosphere::USStandardAtmosphere()
{
@ -78,31 +92,64 @@ USStandardAtmosphere::~USStandardAtmosphere()
double USStandardAtmosphere::getDensity(double altitude)
{
if(temperatureLapseRate[altitude] == 0.0)
if(utils::math::floatingPointEqual(temperatureLapseRate[altitude], 0.0))
{
return standardDensity[altitude] * std::exp((-Constants::g0 * Constants::airMolarMass * (altitude - standardDensity.getBinBase(altitude)))
return standardDensity[altitude] * std::exp(
(-Constants::g0 * Constants::airMolarMass * (altitude - standardDensity.getBinBase(altitude)))
/ (Constants::Rstar * standardTemperature[altitude]));
}
else
{
double base = standardTemperature[altitude] /
(standardTemperature[altitude] + temperatureLapseRate[altitude] * (altitude - standardDensity.getBinBase(altitude)));
double base = (standardTemperature[altitude] - temperatureLapseRate[altitude] *
(altitude - standardDensity.getBinBase(altitude))) / standardTemperature[altitude];
double exponent = 1 + (Constants::g0 * Constants::airMolarMass) /
(Constants::Rstar * temperatureLapseRate[altitude]);
double exponent = (Constants::g0 * Constants::airMolarMass) /
(Constants::Rstar * temperatureLapseRate[altitude]) - 1.0;
return standardDensity[altitude] * std::pow(base, exponent);
}
}
double USStandardAtmosphere::getTemperature(double /*altitude*/)
double USStandardAtmosphere::getTemperature(double altitude)
{
return 0.0;
double baseTemp = standardTemperature[altitude];
double baseAltitude = standardTemperature.getBinBase(altitude);
return baseTemp - (altitude - baseAltitude) * temperatureLapseRate[altitude];
}
double USStandardAtmosphere::getPressure(double /* altitude */)
double USStandardAtmosphere::getPressure(double altitude)
{
return 0.0;
if(utils::math::floatingPointEqual(temperatureLapseRate[altitude], 0.0))
{
return standardPressure[altitude] * std::exp(
(-Constants::g0 * Constants::airMolarMass * (altitude - standardPressure.getBinBase(altitude)))
/ (Constants::Rstar * standardTemperature[altitude]));
}
else
{
double base = (standardTemperature[altitude] - temperatureLapseRate[altitude] *
(altitude - standardPressure.getBinBase(altitude))) / standardTemperature[altitude];
double exponent = (Constants::g0 * Constants::airMolarMass) /
(Constants::Rstar * temperatureLapseRate[altitude]);
return standardPressure[altitude] * std::pow(base, exponent);
}
}
double USStandardAtmosphere::getSpeedOfSound(double altitude)
{
return std::sqrt( (Constants::gamma * Constants::Rstar * getTemperature(altitude))
/
Constants::airMolarMass);
}
double USStandardAtmosphere::getDynamicViscosity(double altitude)
{
double temperature = getTemperature(altitude);
return (Constants::beta * std::pow(temperature, 1.5)) / ( temperature + Constants::S);
}
} // namespace sim

View File

@ -3,7 +3,7 @@
// qtrocket headers
#include "sim/AtmosphericModel.h"
#include "utils/BinMap.h"
#include "utils/Bin.h"
namespace sim
{
@ -28,10 +28,15 @@ public:
double getPressure(double altitude) override;
double getTemperature(double altitude) override;
double getSpeedOfSound(double altitude) override;
double getDynamicViscosity(double altitude) override;
private:
static utils::BinMap temperatureLapseRate;
static utils::BinMap standardTemperature;
static utils::BinMap standardDensity;
static utils::Bin temperatureLapseRate;
static utils::Bin standardTemperature;
static utils::Bin standardDensity;
static utils::Bin standardPressure;
};

View File

@ -13,9 +13,9 @@ WindModel::~WindModel()
{
}
TripletD WindModel::getWindSpeed(double /* x */, double /* y */ , double /* z */)
Vector3 WindModel::getWindSpeed(double /* x */, double /* y */ , double /* z */)
{
return TripletD(0.0, 0.0, 0.0);
return Vector3(0.0, 0.0, 0.0);
}
} // namespace sim

View File

@ -2,7 +2,7 @@
#define SIM_WINDMODEL_H
// qtrocket headers
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim
{
@ -13,7 +13,7 @@ public:
WindModel();
virtual ~WindModel();
virtual TripletD getWindSpeed(double x, double y, double z);
virtual Vector3 getWindSpeed(double x, double y, double z);
};

15
sim/tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
add_executable(sim_tests
USStandardAtmosphereTests.cpp
)
target_link_libraries(sim_tests
sim
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(sim_tests)
add_test(NAME qtrocket_sim_tests COMMAND sim_tests)

View File

@ -0,0 +1,90 @@
#include <gtest/gtest.h>
#include "sim/USStandardAtmosphere.h"
TEST(USStandardAtmosphereTests, DensityTests)
{
sim::USStandardAtmosphere atmosphere;
// Test that the calucated values are with 0.1% of the published values in the NOAA report
EXPECT_NEAR(atmosphere.getDensity(0.0) / 1.225, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(1000.0) / 1.112, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(2000.0) / 1.007, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(3000.0) / 0.9093, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(4000.0) / 0.8194, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(5000.0) / 0.7364, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(6000.0) / 0.6601, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(7000.0) / 0.5900, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(15000.0) / 0.19367, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(20000.0) / 0.088035, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(25000.0) / 0.039466, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(30000.0) / 0.018012, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(40000.0) / 0.0038510, 1.0, 0.001);
// These are generally accurate to ~0.5%. Slight deviation of calculated
// density from the given density in the report table
EXPECT_NEAR(atmosphere.getDensity(8000.0) / 0.52579, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(9000.0) / 0.46706, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(10000.0) / 0.41351, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(50000.0) / 0.00097752, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(60000.0) / 0.00028832, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(70000.0) / 0.000074243, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(80000.0) / 0.000015701, 1.0, 0.005);
}
TEST(USStandardAtmosphereTests, PressureTests)
{
sim::USStandardAtmosphere atmosphere;
// Test that the calucated values are with 0.1% of the published values in the NOAA report
EXPECT_NEAR(atmosphere.getPressure(0.0) / 101325.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(1000.0) / 89876.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(2000.0) / 79501.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(3000.0) / 70108.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(4000.0) / 61640.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(5000.0) / 54019.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(6000.0) / 47181.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(7000.0) / 41060.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(8000.0) / 35599.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(9000.0) / 30742.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(10000.0) / 26436.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(15000.0) / 12044.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(20000.0) / 5474.8, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(25000.0) / 2511.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(30000.0) / 1171.8, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(40000.0) / 277.52, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(50000.0) / 75.944, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(60000.0) / 20.314, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(70000.0) / 4.6342, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(80000.0) / 0.88627, 1.0, 0.001);
}
TEST(USStandardAtmosphereTests, TemperatureTests)
{
sim::USStandardAtmosphere atmosphere;
// Test that the calucated values are with 0.1% of the published values in the NOAA report
EXPECT_NEAR(atmosphere.getTemperature(0.0) / 288.15, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(1000.0) / 281.651, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(2000.0) / 275.154, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(3000.0) / 268.659, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(4000.0) / 262.166, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(5000.0) / 255.676, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(6000.0) / 249.187, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(7000.0) / 242.7, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(8000.0) / 236.215, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(9000.0) / 229.733, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(10000.0) / 223.252, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(15000.0) / 216.65, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(20000.0) / 216.65, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(25000.0) / 221.552, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(30000.0) / 226.509, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(40000.0) / 251.05, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(50000.0) / 270.65, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(60000.0) / 245.45, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(70000.0) / 217.450, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(80000.0) / 196.650, 1.0, 0.001);
}

View File

@ -3,15 +3,14 @@
// C headers
// C++ headers
#include <algorithm>
#include <sstream>
#include <format>
#include <stdexcept>
// 3rd party headers
#include <fmt/core.h>
/// \endcond
// qtrocket headers
#include "BinMap.h"
#include "Bin.h"
// TODO: Check on the availability of this in Clang.
// Replace libfmt with format when LLVM libc++ supports it
@ -20,33 +19,33 @@
namespace utils
{
BinMap::BinMap()
Bin::Bin()
: bins()
{
}
BinMap::BinMap(BinMap&& o)
Bin::Bin(Bin&& o)
: bins(std::move(o.bins))
{
}
BinMap::~BinMap()
Bin::~Bin()
{
}
// TODO: Very low priority, but if anyone wants to make this more efficient it could be
// interesting
void BinMap::insert(const std::pair<double, double>& toInsert)
void Bin::insert(const std::pair<double, double>& toInsert)
{
bins.push_back(toInsert);
std::sort(bins.begin(), bins.end(),
[](const auto& a, const auto& b){ return a.first < b.first; });
}
double BinMap::operator[](double key)
double Bin::operator[](double key)
{
auto iter = bins.begin();
// If the key is less than the lowest bin value, then it is out of range
@ -56,12 +55,12 @@ double BinMap::operator[](double key)
if(key < iter->first)
{
throw std::out_of_range(
fmt::format("{} less than lower bound {} of BinMap", key, iter->first));
std::format("{} less than lower bound {} of BinMap", key, iter->first));
}
// Increment it and start searching If we reach the end without finding an existing key
// greater than our search term, then we've just hit the last bin and return that
iter++;
double retVal = bins.end()->second;
double retVal = bins.back().second;
while(iter != bins.end())
{
if(key < iter->first)
@ -74,7 +73,7 @@ double BinMap::operator[](double key)
return retVal;
}
double BinMap::getBinBase(double key)
double Bin::getBinBase(double key)
{
auto iter = bins.begin();
// If the key is less than the lowest bin value, then it is out of range
@ -84,7 +83,7 @@ double BinMap::getBinBase(double key)
if(key < iter->first)
{
throw std::out_of_range(
fmt::format("{} less than lower bound {} of BinMap", key, iter->first));
std::format("{} less than lower bound {} of BinMap", key, iter->first));
}
// Increment it and start searching If we reach the end without finding an existing key
// greater than our search term, then we've just hit the last bin and return that

View File

@ -1,5 +1,5 @@
#ifndef UTILS_BINMAP_H
#define UTILS_BINMAP_H
#ifndef UTILS_BIN_H
#define UTILS_BIN_H
/// \cond
// C headers
@ -22,12 +22,12 @@ namespace utils {
* @todo Make this class behave more like a proper STL container. Templetize it for one
*
*/
class BinMap
class Bin
{
public:
BinMap();
BinMap(BinMap&& o);
~BinMap();
Bin();
Bin(Bin&& o);
~Bin();
void insert(const std::pair<double, double>& toInsert);
double operator[](double key);
@ -40,4 +40,4 @@ private:
} // namespace utils
#endif // UTILS_BINMAP_H
#endif // UTILS_BIN_H

30
utils/CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
add_library(utils
Bin.cpp
Bin.h
CurlConnection.cpp
CurlConnection.h
Logger.cpp
Logger.h
MotorModelDatabase.cpp
MotorModelDatabase.h
RSEDatabaseLoader.cpp
RSEDatabaseLoader.h
ThreadPool.cpp
ThreadPool.h
ThrustCurveAPI.cpp
ThrustCurveAPI.h
TSQueue.h
math/Constants.h
math/MathTypes.h
math/UtilityMathFunctions.h)
#target_include_directories(utils PRIVATE
# ${Boost_INCLUDE_DIRS})
target_link_libraries(utils PUBLIC
libcurl
Boost::property_tree
jsoncpp_static
eigen)

View File

@ -40,22 +40,29 @@ void Logger::log(std::string_view msg, const LogLevel& lvl)
// all levels at or lower than the current level.
switch(currentLevel)
{
case DEBUG:
if(lvl == DEBUG)
case PERF_:
if(lvl == PERF_)
{
outFile << "[PERF] " << msg << std::endl;
std::cout << "[PERF] " << msg << "\n";
}
[[fallthrough]];
case DEBUG_:
if(lvl == DEBUG_)
{
outFile << "[DEBUG] " << msg << std::endl;
std::cout << "[DEBUG] " << msg << "\n";
}
[[fallthrough]];
case INFO:
if(lvl == INFO)
case INFO_:
if(lvl == INFO_)
{
outFile << "[INFO] " << msg << std::endl;
std::cout << "[INFO] " << msg << "\n";
}
[[fallthrough]];
case WARN:
if(lvl == WARN)
case WARN_:
if(lvl == WARN_)
{
outFile << "[WARN] " << msg << std::endl;
std::cout << "[WARN] " << msg << "\n";
@ -64,7 +71,7 @@ void Logger::log(std::string_view msg, const LogLevel& lvl)
// Regardless of what level is set, ERROR is always logged, so
// rather than explicitly check for the ERROR case, we just use default case
default:
if(lvl == ERROR)
if(lvl == ERROR_)
{
outFile << "[ERROR] " << msg << std::endl;
std::cout << "[ERROR] " << msg << "\n";

View File

@ -22,10 +22,11 @@ class Logger
public:
enum LogLevel
{
ERROR,
WARN,
INFO,
DEBUG
ERROR_,
WARN_,
INFO_,
DEBUG_,
PERF_
};
static Logger* getInstance();
@ -38,16 +39,11 @@ public:
void setLogLevel(const LogLevel& lvl);
/*
std::function<void(std::string_view)> error;
std::function<void(std::string_view)> warn;
std::function<void(std::string_view)> info;
std::function<void(std::string_view)> debug;
*/
inline void error(std::string_view msg) { log(msg, ERROR); }
inline void warn(std::string_view msg) { log(msg, WARN); }
inline void info(std::string_view msg) { log(msg, INFO); }
inline void debug(std::string_view msg) { log(msg, DEBUG); }
inline void error(std::string_view msg) { log(msg, ERROR_); }
inline void warn(std::string_view msg) { log(msg, WARN_); }
inline void info(std::string_view msg) { log(msg, INFO_); }
inline void debug(std::string_view msg) { log(msg, DEBUG_); }
inline void perf(std::string_view msg) { log(msg, PERF_); }
void log(std::ostream& o, const std::string& msg);

View File

@ -0,0 +1,134 @@
// class header
#include "utils/MotorModelDatabase.h"
/// \cond
// C headers
// C++ headers
// 3rd party headers
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
/// \endcond
// qtrocket project headers
#include "QtRocket.h"
namespace utils
{
MotorModelDatabase::MotorModelDatabase()
: motorModelMap()
{
}
MotorModelDatabase::~MotorModelDatabase()
{
}
void MotorModelDatabase::addMotorModel(const model::MotorModel& m)
{
utils::Logger* logger = QtRocket::getInstance()->getLogger();
std::string name = m.data.commonName;
if(motorModelMap.find(name) != motorModelMap.end())
{
logger->debug("Replacing MotorModel " + name + " in MotorModelDatabase");
}
else
{
logger->info("Adding MotorModel " + name + " to MotorModelDatabase");
}
motorModelMap[name] = m;
}
void MotorModelDatabase::addMotorModels(const std::vector<model::MotorModel>& models)
{
utils::Logger* logger = QtRocket::getInstance()->getLogger();
for(const auto& i : models)
{
addMotorModel(i);
}
}
std::optional<model::MotorModel> MotorModelDatabase::getMotorModel(const std::string& name)
{
auto mm = motorModelMap.find(name);
if(mm == motorModelMap.end())
{
Logger::getInstance()->debug("Unable to locate " + name + " in MotorModel database");
return std::nullopt;
}
else
{
Logger::getInstance()->debug("Retrieved " + name + " from MotorModel database");
return motorModelMap[name];
}
}
void MotorModelDatabase::saveMotorDatabase(const std::string& filename)
{
namespace pt = boost::property_tree;
// top-level tree
pt::ptree tree;
tree.put("QtRocketMotorDatabase.<xmlattr>.version", "0.1");
for(const auto& i : motorModelMap)
{
pt::ptree motor;
const auto& m = i.second;
motor.put("<xmlattr>.name", m.data.commonName);
motor.put("availability", m.data.availability.str());
motor.put("avgThrust", m.data.avgThrust);
motor.put("burnTime", m.data.burnTime);
motor.put("certOrg", m.data.certOrg.str());
motor.put("commonName", m.data.commonName);
motor.put("designation", m.data.designation);
motor.put("diameter", m.data.diameter);
motor.put("impulseClass", m.data.impulseClass);
motor.put("infoUrl", m.data.infoUrl);
motor.put("length", m.data.length);
motor.put("manufacturer", m.data.manufacturer.str());
motor.put("maxThrust", m.data.maxThrust);
motor.put("motorIdTC", m.data.motorIdTC);
motor.put("propType", m.data.propType);
motor.put("sparky", m.data.sparky ? "true" : "false");
motor.put("totalImpulse", m.data.totalImpulse);
motor.put("totalWeight", m.data.totalWeight);
motor.put("type", m.data.type.str());
motor.put("lastUpdated", m.data.lastUpdated);
// delays tag is in the form of a csv string
std::stringstream delays;
for (std::size_t i = 0; i < m.data.delays.size() - 1; ++i)
{
delays << std::to_string(m.data.delays[i]) << ",";
}
delays << std::to_string(m.data.delays[m.data.delays.size() - 1]);
motor.put("delays", delays.str());
// thrust data
{
pt::ptree tc;
std::vector<std::pair<double, double>> thrust = m.getThrustCurve().getThrustCurveData();
for(const auto& j : thrust)
{
pt::ptree thrustNode;
thrustNode.put("<xmlattr>.time", j.first);
thrustNode.put("<xmlattr>.force", j.second);
tc.add_child("thrust", thrustNode);
}
motor.add_child("thrustCurve", tc);
}
tree.add_child("QtRocketMotorDatabase.MotorModels.motor", motor);
}
pt::xml_writer_settings<std::string> settings(' ', 2);
pt::write_xml(filename, tree, std::locale(), settings);
}
void MotorModelDatabase::loadMotorDatabase(const std::string& filename)
{
}
} // namespace utils

View File

@ -0,0 +1,77 @@
#ifndef UTILS_MOTORMODELDATABASE_H
#define UTILS_MOTORMODELDATABASE_H
/// \cond
// C headers
// C++ headers
#include <vector>
#include <string>
#include <map>
#include <optional>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "model/MotorModel.h"
namespace utils
{
/**
* @brief MotorModelDatabase is a simple storage, search, and retrieval mechanism for Model Rocket
* motors.
*
*/
class MotorModelDatabase
{
public:
MotorModelDatabase();
~MotorModelDatabase();
// No copies
MotorModelDatabase(const MotorModelDatabase&) = delete;
MotorModelDatabase(MotorModelDatabase&&) = delete;
MotorModelDatabase& operator=(const MotorModelDatabase&) = delete;
MotorModelDatabase& operator=(MotorModelDatabase&&) = delete;
/**
* @brief Adds a single MotorModel to the database. If that MotorModel already exists, it is
* replaced.
*
* @param model MotorModel to add
*
*/
void addMotorModel(const model::MotorModel& m);
/**
* @brief Adds multiple motor models at once. Any duplicates already in the datbase are replaced.
*
* @param model MotorModels to add
*
*/
void addMotorModels(const std::vector<model::MotorModel>& models);
/**
* @brief Get the Motor Model by Common Name
*
* @param name Motor Common name
* @return std::optional<model::MotorModel>
*/
std::optional<model::MotorModel> getMotorModel(const std::string& name);
void saveMotorDatabase(const std::string& filename);
void loadMotorDatabase(const std::string& filename);
private:
// The "database" is really just a map. :)
/// motorModelMap is keyed off of the motor commonName
std::map<std::string, model::MotorModel> motorModelMap;
};
} // namespace utils
#endif // UTILS_MOTORMODELDATABASE_H

View File

@ -5,6 +5,7 @@
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
// 3rd party headers
#include <boost/property_tree/xml_parser.hpp>
@ -58,6 +59,16 @@ void RSEDatabaseLoader::buildAndAppendMotorModel(boost::property_tree::ptree& v)
mm.commonName = v.get<std::string>("<xmlattr>.code", "");
// mm.delays = extract vector from csv list
std::string delays = v.get<std::string>("<xmlattr>.delays", "1000");
std::size_t pos{0};
std::string tok;
while ((pos = delays.find(",")) != std::string::npos)
{
tok = delays.substr(0, pos);
mm.delays.push_back(std::atoi(tok.c_str()));
delays.erase(0, pos + 1);
}
mm.delays.push_back(std::atoi(delays.c_str()));
// mm.designation = What is this?
@ -71,7 +82,8 @@ void RSEDatabaseLoader::buildAndAppendMotorModel(boost::property_tree::ptree& v)
mm.length = v.get<double>("<xmlattr>.len", 0.0);
mm.manufacturer = model::MotorModel::MotorManufacturer::toEnum(v.get<std::string>("<xmlattr>.mfg", ""));
mm.maxThrust = v.get<double>("<xmlattr>.peakThrust", 0.0);
mm.propWeight = v.get<double>("<xmlattr>.propWt", 0.0);
mm.totalWeight = v.get<double>("<xmlattr>.initWt", 0.0) / 1000.0; // convert g -> kg
mm.propWeight = v.get<double>("<xmlattr>.propWt", 0.0) / 1000.0; // convert g -> kg
mm.totalImpulse = v.get<double>("<xmlattr>.Itot", 0.0);
mm.type = model::MotorModel::MotorType::toEnum(v.get<std::string>("<xmlattr>.Type"));

View File

@ -4,6 +4,7 @@
// C++ headers
// 3rd party headers
#include <json/json.h>
#include <optional>
/// \endcond
// qtrocket headers
@ -25,6 +26,58 @@ ThrustCurveAPI::~ThrustCurveAPI()
}
std::optional<ThrustCurve> ThrustCurveAPI::getThrustCurve(const std::string& id)
{
std::stringstream endpoint;
endpoint << hostname << "api/v1/download.json?motorId=" << id << "&data=samples";
std::vector<std::string> extraHeaders = {};
std::string res = curlConnection.get(endpoint.str(), extraHeaders);
model::MotorModel mm;
if(!res.empty())
{
try
{
Json::Reader reader;
Json::Value jsonResult;
reader.parse(res, jsonResult);
std::vector<std::pair<double, double>> samples;
for(Json::ValueConstIterator iter = jsonResult["results"].begin();
iter != jsonResult["results"].end();
++iter)
{
// if there are more than 1 items in the results list, we only want the RASP data
// Otherwise just take whatever is there
if(std::next(iter) != jsonResult["results"].end())
{
if( (*iter)["format"].asString() != "RASP")
continue;
}
for(Json::ValueConstIterator samplesIter = (*iter)["samples"].begin();
samplesIter != (*iter)["samples"].end();
++samplesIter)
{
samples.push_back(std::make_pair((*samplesIter)["time"].asDouble(),
(*samplesIter)["thrust"].asDouble()));
}
}
return ThrustCurve(samples);
}
catch(const std::exception& e)
{
std::string err("Unable to parse JSON from Thrustcurve motor data request. Error: ");
err += e.what();
Logger::getInstance()->error(err);
}
}
return std::nullopt;
}
model::MotorModel ThrustCurveAPI::getMotorData(const std::string& motorId)
{
@ -182,7 +235,9 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
{
Json::Reader reader;
Json::Value jsonResult;
Logger::getInstance()->debug("1");
reader.parse(result, jsonResult);
Logger::getInstance()->debug("2");
for(Json::ValueConstIterator iter = jsonResult["results"].begin();
iter != jsonResult["results"].end();
@ -191,6 +246,7 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
model::MotorModel motorModel;
model::MotorModel::MetaData mm;
mm.commonName = (*iter)["commonName"].asString();
Logger::getInstance()->debug("3");
std::string availability = (*iter)["availability"].asString();
if(availability == "regular")
@ -200,6 +256,7 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
mm.avgThrust = (*iter)["avgThrustN"].asDouble();
mm.burnTime = (*iter)["burnTimeS"].asDouble();
Logger::getInstance()->debug("4");
// TODO fill in certOrg
// TODO fill in delays
mm.designation = (*iter)["designation"].asString();
@ -226,7 +283,14 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
else
mm.type = model::MotorModel::MotorType(model::MotorModel::MOTORTYPE::HYBRID);
Logger::getInstance()->debug("5");
auto tc = getThrustCurve(mm.motorIdTC);
motorModel.moveMetaData(std::move(mm));
Logger::getInstance()->debug("6");
if(tc)
{
motorModel.addThrustCurve(*tc);
}
retVal.push_back(motorModel);
}
}

View File

@ -7,6 +7,7 @@
// C++ headers
#include <map>
#include <string>
#include <optional>
// 3rd party headers
/// \endcond
@ -91,6 +92,8 @@ private:
const std::string hostname;
CurlConnection curlConnection;
std::optional<ThrustCurve> getThrustCurve(const std::string& id);
// no extra headers, but CurlConnection library wants them
const std::vector<std::string> extraHeaders{};
};

View File

@ -1,21 +0,0 @@
#ifndef TRIPLET_H
#define TRIPLET_H
/**
* The purpose of this class is to get rid of using std::tuple for coordinate triplets.
*/
template<typename T>
struct Triplet
{
Triplet(const T& a, const T& b, const T& c)
: x1(a), x2(b), x3(c)
{}
T x1;
T x2;
T x3;
};
using TripletD = Triplet<double>;
#endif // TRIPLET_H

View File

@ -6,9 +6,19 @@ namespace utils::math
namespace Constants
{
constexpr double Rstar = 8.3144598;
constexpr double Rstar = 8.31432;
constexpr const double g0 = 9.80665;
constexpr const double airMolarMass = 0.0289644;
// gamma is the ratio of the specific heat of air at constant pressure to that at
// constant volume. Used in computing the speed of sound
constexpr const double gamma = 1.4;
// beta is used in calculating the dynamic viscosity of air. Based on the 1976 US Standard
// Atmosphere report, it is empirically measured to be:
constexpr const double beta = 1.458e-6;
// Sutherland's constant
constexpr const double S = 110.4;
constexpr const double standardTemperature = 288.15;
constexpr const double standardDensity = 1.2250;
constexpr const double meanEarthRadiusWGS84 = 6371008.8;

74
utils/math/MathTypes.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef UTILS_MATH_MATHTYPES_H
#define UTILS_MATH_MATHTYPES_H
#include <Eigen/Dense>
#include <vector>
/// This is not in any namespace. These typedefs are intended to be used throughout QtRocket,
/// so keeping them in the global namespace seems to make sense.
template <int Size>
using MyMatrix = Eigen::Matrix<double, Size, Size>;
template <int Size>
using MyVector = Eigen::Matrix<double, Size, 1>;
typedef Eigen::Quaterniond Quaternion;
using Matrix3 = MyMatrix<3>;
using Matrix4 = MyMatrix<4>;
using Vector3 = MyVector<3>;
using Vector6 = MyVector<6>;
/*
namespace utils
{
std::vector<double> myVectorToStdVector(const Vector3& x)
{
return std::vector<double>{x.coeff(0), x.coeff(1), x.coeff(2)};
}
std::vector<double> myVectorToStdVector(const Vector6& x)
{
return std::vector<double>{x.coeff(0),
x.coeff(1),
x.coeff(2),
x.coeff(3),
x.coeff(4),
x.coeff(5)};
}
}
class Vector3 : public MyVector<3>
{
public:
template<typename... Args>
Vector3(Args&&... args) : MyVector<3>(std::forward<Args>(args)...)
{}
operator std::vector<double>()
{
return std::vector<double>{this->coeff(0), this->coeff(1), this->coeff(2)};
}
};
class Vector6 : public MyVector<6>
{
public:
template<typename... Args>
Vector6(Args&&... args) : MyVector<6>(std::forward<Args>(args)...)
{}
operator std::vector<double>()
{
return std::vector<double>{this->coeff(0),
this->coeff(1),
this->coeff(2),
this->coeff(3),
this->coeff(4),
this->coeff(5)};
}
};
*/
#endif // UTILS_MATH_MATHTYPES_H

View File

@ -1,25 +0,0 @@
// qtrocket headers
#include "utils/math/Quaternion.h"
namespace math
{
Quaternion::Quaternion()
{
}
Quaternion::Quaternion(double r, const Vector3& i)
: real(r),
imag(i)
{
}
Quaternion::Quaternion(double r, double i1, double i2, double i3)
: real(r),
imag(i1, i2, i3)
{
}
} // namespace math

View File

@ -1,63 +0,0 @@
#ifndef MATH_QUATERNION_H
#define MATH_QUATERNION_H
/// \cond
// C headers
// C++ headers
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "Vector3.h"
namespace math
{
class Quaternion
{
public:
Quaternion();
~Quaternion() {}
Quaternion(double r, const Vector3& i);
Quaternion(double r, double i1, double i2, double i3);
Quaternion(const Quaternion&) = default;
Quaternion(Quaternion&&) = default;
Quaternion& operator=(const Quaternion& rhs)
{
if(this == &rhs)
return *this;
real = rhs.real;
imag = rhs.imag;
return *this;
}
Quaternion& operator=(Quaternion&& rhs)
{
if(this == &rhs)
return *this;
real = std::move(rhs.real);
imag = std::move(rhs.imag);
return *this;
}
/*
Quaternion operator-() {}
Quaternion operator-(const Quaternion& ) {}
Quaternion operator+(const Quaternion& ) {}
Quaternion operator*(double ) {}
Quaternion operator*(const Quaternion& ) {}
*/
private:
double real;
Vector3 imag;
};
} // namespace math
#endif // MATH_QUATERNION_H

View File

@ -1,15 +0,0 @@
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
namespace utils
{
namespace math
{
} // namespace math
} // namespace utils

View File

@ -1,68 +0,0 @@
// qtrocket headers
#include "utils/math/Vector3.h"
namespace math
{
Vector3::Vector3()
: x1(0.0),
x2(0.0),
x3(0.0)
{
}
Vector3::Vector3(const double& inX1,
const double& inX2,
const double& inX3)
: x1(inX1),
x2(inX2),
x3(inX3)
{
}
Vector3::Vector3(const Vector3& o)
: x1(o.x1),
x2(o.x2),
x3(o.x3)
{
}
Vector3::~Vector3()
{}
Vector3 Vector3::operator=(const Vector3& rhs)
{
return Vector3(rhs.x1, rhs.x2, rhs.x3);
}
Vector3 Vector3::operator-()
{
return Vector3(-x1, -x2, -x3);
}
Vector3 Vector3::operator-(const Vector3& rhs)
{
return Vector3(x1 - rhs.x1,
x2 - rhs.x2,
x3 - rhs.x3);
}
Vector3 Vector3::operator+(const Vector3& rhs)
{
return Vector3(x1 + rhs.x1,
x2 + rhs.x2,
x3 + rhs.x3);
}
Vector3 Vector3::operator*(const double& s)
{
return Vector3(x1 * s,
x2 * s,
x3 * s);
}
} // namespace math

View File

@ -1,40 +0,0 @@
#ifndef MATH_VECTOR3_H
#define MATH_VECTOR3_H
namespace math
{
class Vector3
{
public:
Vector3();
Vector3(const double& inX1,
const double& inX2,
const double& inX3);
Vector3(const Vector3& o);
~Vector3();
Vector3 operator=(const Vector3& rhs);
Vector3 operator-();
Vector3 operator-(const Vector3& rhs);
Vector3 operator+(const Vector3& rhs);
Vector3 operator*(const double& s);
double getX1() { return x1; }
double getX2() { return x2; }
double getX3() { return x3; }
//private:
double x1;
double x2;
double x3;
};
} // namespace math
#endif // MATH_VECTOR3_H