Compare commits

..

1 Commits

Author SHA1 Message Date
8d503e3a3a doesn't build 2023-10-04 12:35:04 -06:00
46 changed files with 940 additions and 1126 deletions

View File

@ -1,86 +0,0 @@
# 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_*'

2
.gitignore vendored
View File

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

View File

@ -5,8 +5,6 @@ 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
@ -19,10 +17,10 @@ endif()
FetchContent_MakeAvailable(googletest)
# fmtlib dependency
#FetchContent_Declare(fmt
# GIT_REPOSITORY https://github.com/fmtlib/fmt
# GIT_TAG 9.1.0)
#FetchContent_MakeAvailable(fmt)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt
GIT_TAG 9.1.0)
FetchContent_MakeAvailable(fmt)
# jsoncpp dependency
FetchContent_Declare(jsoncpp
@ -50,18 +48,11 @@ endif()
FetchContent_MakeAvailable(CURL)
# eigen dependency
FetchContent_Declare(Eigen
FetchContent_Declare(eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen
GIT_TAG 3.4.0)
FetchContent_MakeAvailable(Eigen)
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
@ -72,7 +63,7 @@ set(CMAKE_AUTORCC ON)
if(WIN32)
set(CMAKE_PREFIX_PATH $ENV{QTDIR})
# include_directories("C:\\boost\\boost_1_82_0\\")
include_directories("C:\\boost\\boost_1_82_0\\")
# find_package(Qt6Core REQUIRED)
# find_package(Qt6Widgets REQUIRED)
endif()

416
CMakeLists.txt.user Normal file
View File

@ -0,0 +1,416 @@
<?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,3 +1,4 @@
/// \cond
// C headers
// C++ headers
@ -44,7 +45,7 @@ void guiWorker(int argc, char* argv[], int& ret)
// Go!
MainWindow w(QtRocket::getInstance());
logger->debug("Showing MainWindow");
logger->info("Showing MainWindow");
w.show();
ret = a.exec();
@ -64,7 +65,7 @@ void QtRocket::init()
std::lock_guard<std::mutex> lck(mtx);
if(!initialized)
{
utils::Logger::getInstance()->debug("Instantiating new QtRocket");
utils::Logger::getInstance()->info("Instantiating new QtRocket");
instance = new QtRocket();
initialized = true;
}
@ -80,20 +81,13 @@ QtRocket::QtRocket()
setEnvironment(std::make_shared<sim::Environment>());
rocket.first =
std::make_shared<model::RocketModel>();
std::make_shared<Rocket>();
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[])
@ -113,7 +107,7 @@ int QtRocket::run(int argc, char* argv[])
void QtRocket::launchRocket()
{
// initialize the propagator
rocket.first->clearStates();
rocket.second->clearStates();
rocket.second->setCurrentTime(0.0);
// start the rocket motor

View File

@ -14,12 +14,13 @@
// qtrocket headers
#include "model/MotorModel.h"
#include "model/RocketModel.h"
#include "model/Rocket.h"
#include "sim/AtmosphericModel.h"
#include "sim/GravityModel.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.
@ -43,13 +44,13 @@ public:
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<Rocket> getRocket() { return rocket.first; }
std::shared_ptr<utils::MotorModelDatabase> getMotorDatabase() { return motorDatabase; }
void addMotorModels(std::vector<model::MotorModel>& m);
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.first = r; }
void setEnvironment(std::shared_ptr<sim::Environment> e) { environment = e; }
@ -58,13 +59,18 @@ public:
* @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(); }
const std::vector<std::pair<double, Vector6>>& getStates() const { return rocket.second->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); }
void setInitialState(const std::vector<double>& initialPos,
const std::vector<double>& initialVel,
const std::vector<double>& initialOri,
const std::vector<double>& initialOriRate)
{ rocket.second->setInitialState(initialPos, initialVel, initialOri, initialOriRate); }
private:
QtRocket();
@ -78,19 +84,11 @@ private:
utils::Logger* logger;
using Rocket = std::pair<std::shared_ptr<model::RocketModel>, std::shared_ptr<sim::Propagator>>;
Rocket rocket;
std::pair<std::shared_ptr<Rocket>, std::shared_ptr<sim::Propagator>> rocket;
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;
};
#endif // QTROCKET_H

View File

@ -1,2 +1,71 @@
# qtrocket
An open source model Rocket Simulator written in C++ and Qt Toolkit, coming soon
An open source model Rocket Simulator written in C++ and Qt Toolkit, coming soon!
## Why?
Because it's fun! Model and High Power rocketry are enjoyable hobbies that teach model building
and inspire people to keep learning. For me, part of that learning process includes learning more
about the aerodynamics of rocket flight, and what better way to learn than write a simulator?
There are already open source rocket simulators out there (e.g. OpenRocket), but this is another
take on that idea. For one, this is written in C++ and OpenRocket is written in Java, but more
importantly, I hope to engineer this in a way that is as modular as possible from the standpoint
of the parts, components, and concepts involved in modeling a rocket. That way, this can serve not
only as a model rocket design program, but a platform for people to learn about how rockets fly by
building and integrating their own test parts and models easily. This way QtRocket may serve as a
learning platform not just for me, but for others as well.
### Why Release An Unfinished Product?
Well, first of all it isn't actually *released* yet. But it is public because I'm always interested in getting any feedback others may have. I'm doing this to learn as well, and if you have any
pointers, I'd love to hear them! And if you want to contribute, well, please do! Let's talk :)
## External Build Dependencies
* Boost libraries. On Windows this is hardcoded to v1.82.0, but only because I'm not sure how dependencies work on Windows
* Qt6 (You can download it for free for Open Source use here: https://www.qt.io/download)
* Other dependencies are handled within the CMake build system
* Maybe something else I'm forgetting about? If you find something not listed that isn't a standard install, let me know
## How To Use It
First, it's still in the very early stages of development, but it *can* propagate objects through
an atomosphere with a given coefficient of drag, mass, and motor.
When you first open qtrocket, you're presented with the main window:
![Main Window](resources/screenshots/MainWindow.png)
The main window thus far has been centered around testing the core physics engin. As you can see,
there are several fields that you can edit:
* Initial Velocity - This is an initial vertical velocity off the launch rod or rail
* Angle - Currently disabled. If the rocket launches at an angle, this would be it. Currently
it is disabled and set at 90 degrees from horizontal, aka vertical.
* mass - The mass of the rocket in kilograms (not including the motor)
* Cd - The coefficient of drag of the rocket
* Time Step - The time step used by the simulator, in seconds. Defaults to 0.01 seconds.
Once you fill out these fields (or just accept their defaults), you are ready to load a motor. The
"Load RSE Database File" button will open a file browser to allow you to select a RockSim
engine database file. One is included in the data/ directory of qtrocket that holds some AeroTech
motors. After selecting a motor, you can click on the "Set Motor" button. This will add the selected
motor to the rocket, and use it to launch the rocket.
Once you have selected and added the rocket motor, click "Calculate Trajectory". A new dialog will
appear (if the plot is empty, just click the "Plot Altitude" button):
![Alt text](resources/screenshots/Altitude.png)
From here you can also plot velocity by clicking "Plot Velocity":
![Alt text](resources/screenshots/Velocity.png)
And, plot the thrust curve of the motor you selected.
## Thrustcurve.org integration
There is another feature, in that qtrocket integrates with the excellent online motor database thrustcurve.org. From the main window, click "Get Thrustcurve Motor Data". A new window will open:
![Alt text](resources/screenshots/ThrustCurveWindow.png)
In order to use it, you first must click "Get Metadata". Then you can select the manufacturer, motor diameter, and impulse class.
After filling out those combo boxes, click "Search". From there, you can search all available
motors with those criteria. After choosing one in the combo box, click "setMotor", and that
motor's thrust curve will be displayed in the plot.
## Known Issues
* It doesn't do much
* I know, but it's just a little fella and it's still growing ;)

View File

@ -36,7 +36,7 @@ AnalysisWindow::~AnalysisWindow()
void AnalysisWindow::onButton_plotAltitude_clicked()
{
QtRocket* qtRocket = QtRocket::getInstance();
const std::vector<std::pair<double, StateData>>& res = qtRocket->getStates();
const std::vector<std::pair<double, Vector6>>& res = qtRocket->getStates();
auto& plot = ui->plotWidget;
plot->clearGraphs();
plot->setInteraction(QCP::iRangeDrag, true);
@ -46,7 +46,7 @@ void AnalysisWindow::onButton_plotAltitude_clicked()
for (int i = 0; i < tData.size(); ++i)
{
tData[i] = res[i].first;
zData[i] = res[i].second.position[2];
zData[i] = res[i].second[2];
}
// create graph and assign data to it:
plot->addGraph();
@ -63,7 +63,7 @@ void AnalysisWindow::onButton_plotAltitude_clicked()
void AnalysisWindow::onButton_plotVelocity_clicked()
{
QtRocket* qtRocket = QtRocket::getInstance();
const std::vector<std::pair<double, StateData>>& res = qtRocket->getStates();
const std::vector<std::pair<double, Vector6>>& res = qtRocket->getStates();
auto& plot = ui->plotWidget;
plot->clearGraphs();
plot->setInteraction(QCP::iRangeDrag, true);
@ -74,7 +74,7 @@ void AnalysisWindow::onButton_plotVelocity_clicked()
for (int i = 0; i < tData.size(); ++i)
{
tData[i] = res[i].first;
zData[i] = res[i].second.velocity[2];
zData[i] = res[i].second[5];
}
// create graph and assign data to it:
plot->addGraph();
@ -91,8 +91,8 @@ void AnalysisWindow::onButton_plotVelocity_clicked()
void AnalysisWindow::onButton_plotMotorCurve_clicked()
{
std::shared_ptr<model::RocketModel> rocket = QtRocket::getInstance()->getRocket();
model::MotorModel motor = rocket->getMotorModel();
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
model::MotorModel motor = rocket->getCurrentMotorModel();
ThrustCurve tc = motor.getThrustCurve();

View File

@ -20,7 +20,7 @@
#include "gui/MainWindow.h"
#include "gui/ThrustCurveMotorSelector.h"
#include "gui/SimOptionsWindow.h"
#include "model/RocketModel.h"
#include "model/Rocket.h"
#include "utils/RSEDatabaseLoader.h"
@ -123,15 +123,15 @@ 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};
StateData initialState;
initialState.position = {0.0, 0.0, 0.0};
initialState.velocity = {initialVelocityX, 0.0, initialVelocityZ};
std::vector<double> initialPos = {0.0, 0.0, 0.0};
std::vector<double> initialVel = {initialVelocityX, 0.0, initialVelocityZ};
std::vector<double> initialOri = {0.0, 0.0, 0.0};
std::vector<double> initialOriRate = {0.0, 0.0, 0.0};
auto rocket = QtRocket::getInstance()->getRocket();
rocket->setMass(mass);
rocket->setDragCoefficient(dragCoeff);
qtRocket->setInitialState(initialState);
qtRocket->setInitialState(initialPos, initialVel, initialOri, initialOriRate);
qtRocket->launchRocket();
AnalysisWindow aWindow;

View File

@ -1,9 +1,11 @@
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
#include "QtRocket.h"
#include "utils/Logger.h"
@ -12,15 +14,12 @@ int main(int argc, char *argv[])
// Instantiate logger
utils::Logger* logger = utils::Logger::getInstance();
logger->setLogLevel(utils::Logger::PERF_);
logger->info("Logger instantiated at PERF level");
logger->setLogLevel(utils::Logger::DEBUG_);
// 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;

View File

@ -3,18 +3,10 @@ add_library(model
MotorModel.h
MotorModelDatabase.cpp
MotorModelDatabase.h
Part.cpp
Part.h
Propagatable.cpp
Propagatable.h
RocketModel.cpp
RocketModel.h
Rocket.cpp
Rocket.h
ThrustCurve.cpp
ThrustCurve.h
InertiaTensors.h)
ThrustCurve.h)
target_link_libraries(model PRIVATE
utils)
# Unit tests
add_subdirectory(tests)

View File

@ -1,70 +0,0 @@
#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

@ -60,7 +60,6 @@ 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;
}

View File

@ -1,109 +0,0 @@
#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

View File

@ -1,136 +0,0 @@
#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

View File

View File

@ -1,58 +0,0 @@
#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

33
model/Rocket.cpp Normal file
View File

@ -0,0 +1,33 @@
// qtrocket headers
#include "Rocket.h"
#include "QtRocket.h"
Rocket::Rocket()
{
}
void Rocket::launch()
{
mm.startMotor(0.0);
}
void Rocket::setMotorModel(const model::MotorModel& motor)
{
mm = motor;
}
bool Rocket::terminateCondition(const std::pair<double, Vector6>& 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,10 +1,9 @@
#ifndef ROCKETMODEL_H
#define ROCKETMODEL_H
#ifndef ROCKET_H
#define ROCKET_H
/// \cond
// C headers
// C++ headers
#include <vector>
#include <memory>
#include <string>
#include <utility> // std::move
@ -13,34 +12,22 @@
/// \endcond
// qtrocket headers
#include "model/Part.h"
#include "sim/Propagator.h"
#include "model/ThrustCurve.h"
#include "model/MotorModel.h"
#include "model/Propagatable.h"
// Not yet
//#include "model/Stage.h"
namespace model
{
#include "sim/Propagator.h"
#include "utils/math/MathTypes.h"
/**
* @brief The Rocket class holds all rocket components
*
*/
class RocketModel : public Propagatable
class Rocket
{
public:
/**
* @brief Rocket class constructor
*/
RocketModel();
/**
* @brief Rocket class destructor
*
*/
virtual ~RocketModel() {}
Rocket();
/**
* @brief launch Propagates the Rocket object until termination,
@ -48,22 +35,33 @@ public:
*/
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
* @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(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;
double getMass(double simTime) const { return mass + mm.getMass(simTime); }
Matrix3 getInertiaTensor(double t) override;
/**
* @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
@ -72,25 +70,24 @@ public:
*/
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; }
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, Vector6>& cond);
/**
* @brief setName sets the rocket name
@ -98,19 +95,16 @@ public:
*/
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
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
model::Part topPart;
};
} // namespace model
#endif // ROCKETMODEL_H
#endif // ROCKET_H

View File

@ -1,79 +0,0 @@
// 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

View File

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

View File

@ -1,16 +0,0 @@
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)

View File

@ -1,70 +0,0 @@
#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);
}

View File

View File

@ -1,40 +0,0 @@
#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,10 +13,6 @@ 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

View File

@ -1,6 +1,4 @@
add_library(sim
Aero.cpp
Aero.h
AtmosphericModel.h
ConstantAtmosphere.h
ConstantGravityModel.h

View File

@ -15,10 +15,6 @@ 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

@ -4,12 +4,13 @@
/// \cond
// C headers
// C++ headers
#include <utility>
#include <vector>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "utils/math/MathTypes.h"
namespace sim
{

View File

@ -17,6 +17,7 @@
#include "sim/ConstantAtmosphere.h"
#include "sim/USStandardAtmosphere.h"
#include "sim/GeoidModel.h"
namespace sim
{

View File

@ -2,6 +2,7 @@
/// \cond
// C headers
// C++ headers
#include <cmath>
#include <chrono>
#include <iostream>
#include <sstream>
@ -13,36 +14,106 @@
// qtrocket headers
#include "Propagator.h"
#include "QtRocket.h"
#include "model/Rocket.h"
#include "sim/RK4Solver.h"
#include "utils/Logger.h"
namespace sim
{
Propagator::Propagator(std::shared_ptr<model::Propagatable> r)
namespace sim {
Propagator::Propagator(std::shared_ptr<Rocket> r)
: linearIntegrator(),
object(r),
saveStates(true),
timeStep(0.01)
orientationIntegrator(),
rocket(r),
currentBodyState(),
worldFrameState()
{
// 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;
// dvx/dt
dVelocity = object->getForces(currentTime) / object->getMass(currentTime);
return std::make_pair(dPosition, dVelocity);
};
// 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
linearIntegrator.reset(new RK4Solver<Vector3>(linearODEs));
linearIntegrator->setTimeStep(timeStep);
// The state vector has components of the form:
saveStates = true;
// Linear velocity and acceleration
std::function<std::pair<Vector3, Vector3>(Vector3&, Vector3&)> linearODE = [this](Vector3& state, Vector3& rate) -> std::pair<Vector3, Vector3>
{
Vector3 dPosition;
Vector3 dVelocity;
// dx/dt
dPosition[0] = rate[0];
// dy/dt
dPosition[1] = rate[1];
// dz/dt
dPosition[2] = rate[2];
// dvx/dt
dVelocity[0] = getForceX() / getMass();
// dvy/dt
dVelocity[1] = getForceY() / getMass();
// dvz/dt
dVelocity[2] = getForceZ() / getMass();
return std::make_pair(dPosition, dVelocity);
};
linearIntegrator.reset(new RK4Solver<Vector6>(linearODE));
linearIntegrator->setTimeStep(timeStep);
// This is pure quaternion
// This formula is taken from https://www.vectornav.com/resources/inertial-navigation-primer/math-fundamentals/math-attitudetran
//
// Convention for the quaternions is (vector, scalar). So q4 is scalar term
//
// q1Dot = 1/2 * [(q4*omega1) - (q3*omega2) + (q2*omega3)]
// q2Dot = 1/2 * [(q3*omega1) + (q4*omega2) - (q1*omega3)]
// q3Dot = 1/2 * [(-q2*omega1) + (q1*omega2) + (q4*omega3)]
// q4Dot = -1/2 *[(q1*omega1) + (q2*omega2) + (q3*omega3)]
//
// omega1 = yawRate
// omega2 = pitchRate
// omega3 = rollRate
//
// orientationIntegrator.reset(new RK4Solver(
// /* dyawRate/dt */ [this](const std::vector<double>& s, double) -> double
// { return getTorqueP() / getIyaw(); },
// /* dpitchRate/dt */ [this](const std::vector<double>& s, double) -> double
// { return getTorqueQ() / getIpitch(); },
// /* drollRate/dt */ [this](const std::vector<double>& s, double) -> double
// { return getTorqueR() / getIroll(); },
// /* q1Dot */ [](const std::vector<double>& s, double) -> double
// {
// double retVal = s[6]*s[0] - s[5]*s[1] + s[4]*s[2];
// return 0.5 * retVal;
// },
// /* q2Dot */ [](const std::vector<double>& s, double) -> double
// {
// double retVal = s[5]*s[0] + s[6]*s[1] - s[3]*s[2];
// return 0.5 * retVal;
// },
// /* q3Dot */ [](const std::vector<double>& s, double) -> double
// {
// double retVal = -s[4]*s[0] + s[3]*s[1] + s[6]*s[2];
// return 0.5 * retVal;
// },
// /* q4Dot */ [](const std::vector<double>& s, double) -> double
// {
// double retVal = s[3]*s[0] + s[4]*s[1] + s[5]*s[2];
// return -0.5 * retVal;
// }));
// orientationIntegrator->setTimeStep(timeStep);
saveStates = true;
}
Propagator::~Propagator()
@ -51,40 +122,91 @@ Propagator::~Propagator()
void Propagator::runUntilTerminate()
{
std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point endTime;
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)
{
currentPosition = object->getCurrentState().position;
currentVelocity = object->getCurrentState().velocity;
while(true)
{
std::tie(nextPosition, nextVelocity) = linearIntegrator->step(currentPosition, currentVelocity);
// Reset the body frame positions to zero since the origin of the body frame is the CM
currentBodyState[0] = 0.0;
currentBodyState[1] = 0.0;
currentBodyState[2] = 0.0;
StateData nextState;
nextState.position = nextPosition;
nextState.velocity = nextVelocity;
object->setCurrentState(nextState);
// tempRes gets overwritten
tempRes = linearIntegrator->step(currentBodyState);
if(saveStates)
{
object->appendState(currentTime, nextState);
}
if(object->terminateCondition(currentTime))
break;
std::swap(currentBodyState, tempRes);
currentTime += timeStep;
}
endTime = std::chrono::steady_clock::now();
if(saveStates)
{
states.push_back(std::make_pair(currentTime, currentBodyState));
}
if(rocket->terminateCondition(std::make_pair(currentTime, currentBodyState)))
break;
currentTime += timeStep;
}
endTime = std::chrono::steady_clock::now();
std::stringstream duration;
duration << "runUntilTerminate time (microseconds): ";
duration << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
utils::Logger::getInstance()->debug(duration.str());
}
double Propagator::getMass()
{
return rocket->getMass(currentTime);
}
double Propagator::getForceX()
{
QtRocket* qtrocket = QtRocket::getInstance();
return (currentBodyState[3] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentBodyState[2])/ 2.0 * 0.008107 * rocket->getDragCoefficient() * currentBodyState[3]* currentBodyState[3];
}
double Propagator::getForceY()
{
QtRocket* qtrocket = QtRocket::getInstance();
return (currentBodyState[4] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentBodyState[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentBodyState[4]* currentBodyState[4];
}
double Propagator::getForceZ()
{
QtRocket* qtrocket = QtRocket::getInstance();
double gravity = (qtrocket->getEnvironment()->getGravityModel()->getAccel(currentBodyState[0], currentBodyState[1], currentBodyState[2]))[2];
double airDrag = (currentBodyState[5] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentBodyState[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentBodyState[5]* currentBodyState[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; }
Vector3 Propagator::getCurrentGravity()
{
auto gravityModel = QtRocket::getInstance()->getEnvironment()->getGravityModel();
auto gravityAccel = gravityModel->getAccel(currentBodyState[0],
currentBodyState[1],
currentBodyState[2]);
Vector3 gravityVector{gravityAccel[0],
gravityAccel[1],
gravityAccel[2]};
Quaternion q{currentOrientation[3],
currentOrientation[4],
currentOrientation[5],
currentOrientation[6]};
Vector3 res = q * gravityVector;
return Vector3{0.0, 0.0, 0.0};
std::stringstream duration;
duration << "runUntilTerminate time (microseconds): ";
duration << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
utils::Logger::getInstance()->debug(duration.str());
}

View File

@ -5,22 +5,20 @@
// 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
@ -29,17 +27,43 @@ namespace sim
class Propagator
{
public:
Propagator(std::shared_ptr<model::Propagatable> o);
Propagator(std::shared_ptr<Rocket> r);
~Propagator();
void setInitialState(const StateData& initialState)
void setInitialState(const std::vector<double>& initialState,
const std::vector<double>& initialVelocity,
const std::vector<double>& initialOrientation,
const std::vector<double>& initalOriRate)
{
object->setInitialState(initialState);
for(std::size_t i = 0; i < initialState.size(); ++i)
{
currentBodyPosition[i] = initialState[i];
}
for(std::size_t i = 0; i < initialVelocity.size(); ++i)
{
currentBodyVelocity[i] = initialVelocity[i];
}
/*
for(std::size_t i = 0; i < initialOrientation.size(); ++i)
{
currentOrientation[i] = initialOrientation[i];
}
for(std::size_t i = 0; i < initialOriRate.size(); ++i)
{
currentOrientationRate[i] = initialOriRate[i];
}
*/
}
const StateData& getCurrentState() const
const Vector6& getCurrentState() const
{
return object->getCurrentState();
std::vector<double> retVal{currentBodyPosition.begin(), currentBodyPosition.end()};
for(auto& i : currentBodyVelocity)
{
retVal.push_back(i);
}
return retVal;
}
void runUntilTerminate();
@ -49,21 +73,56 @@ public:
saveStates = s;
}
const std::vector<std::pair<double, Vector6>>& 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();
double getIpitch() { return 1.0; }
double getIyaw() { return 1.0; }
double getIroll() { return 1.0; }
std::unique_ptr<sim::RK4Solver<Vector3>> linearIntegrator;
// std::unique_ptr<sim::RK4Solver<Quaternion>> orientationIntegrator;
std::shared_ptr<model::Propagatable> object;
std::shared_ptr<Rocket> rocket;
StateData worldFrameState;
StateData bodyFrameState
Vector3 currentBodyPosition{0.0, 0.0, 0.0};
Vector3 currentBodyVelocity{0.0, 0.0, 0.0};
Vector3 nextBodyPosition{0.0, 0.0, 0.0};
Vector3 nextBodyVelocity{0.0, 0.0, 0.0};
std::vector<double> currentWorldState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
Vector3 currentGravity{0.0, 0.0, 0.0};
Vector3 currentWindSpeed{0.0, 0.0, 0.0};
// orientation vectors in the form (yawDot, pitchDot, rollDot, q1, q2, q3, q4)
Quaternion currentOrientation{0.0, 0.0, 0.0, 0.0};
Quaternion currentOrientationRate{0.0, 0.0, 0.0, 0.0};
Quaternion nextOrientation{0.0, 0.0, 0.0, 0.0};
Quaternion nextOrientationRate{0.0, 0.0, 0.0, 0.0};
bool saveStates{true};
double currentTime{0.0};
double timeStep{0.01};
std::vector<std::pair<double, Vector6>> states;
Vector3 getCurrentGravity();
};
} // namespace sim

View File

@ -4,8 +4,10 @@
/// \cond
// C headers
// C++ headers
#include <cmath>
#include <functional>
#include <limits>
#include <vector>
// 3rd party headers

View File

@ -22,63 +22,24 @@ public:
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
std::vector<double> getPosStdVector()
{
return std::vector<double>{position[0], position[1], position[2]};
}
std::vector<double> getVelStdVector() const
std::vector<double> getVelStdVector()
{
return std::vector<double>{velocity[0], velocity[1], velocity[2]};
}
/// TODO: Put these behind an interface
//Vector3 getPosition() const
//{
// return position;
//}
//Vector3 getVelocity() const
//{
// return velocity;
//}
// private:
// Intended to be used as world state data
// These are 4-vectors so quaternion multiplication works out. The last term (scalar) is always
// zero. I could just use quaternions here, but I want to make it clear that these aren't
// rotations, they're vectors
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)
@ -90,6 +51,9 @@ public:
/// roll - phi
Vector3 eulerAngles{0.0, 0.0, 0.0};
// This is an array because the integrator expects it
double data[6];
};
#endif // STATEDATA_H

View File

@ -18,9 +18,9 @@ namespace sim
{
// Populate static data
utils::Bin initTemps()
utils::BinMap initTemps()
{
utils::Bin map;
utils::BinMap 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));
@ -33,9 +33,10 @@ utils::Bin initTemps()
}
utils::Bin initLapseRates()
/// TODO: These are inverted. They should be of the opposite sign
utils::BinMap initLapseRates()
{
utils::Bin map;
utils::BinMap 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));
@ -47,9 +48,9 @@ utils::Bin initLapseRates()
return map;
}
utils::Bin initDensities()
utils::BinMap initDensities()
{
utils::Bin map;
utils::BinMap 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));
@ -61,9 +62,9 @@ utils::Bin initDensities()
return map;
}
utils::Bin initPressures()
utils::BinMap initPressures()
{
utils::Bin map;
utils::BinMap 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));
@ -75,10 +76,12 @@ utils::Bin initPressures()
return map;
}
utils::Bin USStandardAtmosphere::temperatureLapseRate(initLapseRates());
utils::Bin USStandardAtmosphere::standardTemperature(initTemps());
utils::Bin USStandardAtmosphere::standardDensity(initDensities());
utils::Bin USStandardAtmosphere::standardPressure(initPressures());
utils::BinMap USStandardAtmosphere::temperatureLapseRate(initLapseRates());
utils::BinMap USStandardAtmosphere::standardTemperature(initTemps());
utils::BinMap USStandardAtmosphere::standardDensity(initDensities());
utils::BinMap USStandardAtmosphere::standardPressure(initPressures());
USStandardAtmosphere::USStandardAtmosphere()
{
@ -117,6 +120,7 @@ double USStandardAtmosphere::getTemperature(double altitude)
double baseAltitude = standardTemperature.getBinBase(altitude);
return baseTemp - (altitude - baseAltitude) * temperatureLapseRate[altitude];
return 0.0;
}
double USStandardAtmosphere::getPressure(double altitude)
{
@ -124,13 +128,13 @@ double USStandardAtmosphere::getPressure(double altitude)
{
return standardPressure[altitude] * std::exp(
(-Constants::g0 * Constants::airMolarMass * (altitude - standardPressure.getBinBase(altitude)))
/ (Constants::Rstar * standardTemperature[altitude]));
/ (Constants::Rstar * standardPressure[altitude]));
}
else
{
double base = (standardTemperature[altitude] - temperatureLapseRate[altitude] *
(altitude - standardPressure.getBinBase(altitude))) / standardTemperature[altitude];
double base = (standardPressure[altitude] - temperatureLapseRate[altitude] *
(altitude - standardPressure.getBinBase(altitude))) / standardPressure[altitude];
double exponent = (Constants::g0 * Constants::airMolarMass) /
(Constants::Rstar * temperatureLapseRate[altitude]);
@ -139,17 +143,4 @@ double USStandardAtmosphere::getPressure(double altitude)
}
}
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/Bin.h"
#include "utils/BinMap.h"
namespace sim
{
@ -28,15 +28,11 @@ public:
double getPressure(double altitude) override;
double getTemperature(double altitude) override;
double getSpeedOfSound(double altitude) override;
double getDynamicViscosity(double altitude) override;
private:
static utils::Bin temperatureLapseRate;
static utils::Bin standardTemperature;
static utils::Bin standardDensity;
static utils::Bin standardPressure;
static utils::BinMap temperatureLapseRate;
static utils::BinMap standardTemperature;
static utils::BinMap standardDensity;
static utils::BinMap standardPressure;
};

View File

@ -1,3 +1,4 @@
enable_testing()
add_executable(sim_tests
USStandardAtmosphereTests.cpp
@ -11,5 +12,3 @@ target_link_libraries(sim_tests
include(GoogleTest)
gtest_discover_tests(sim_tests)
add_test(NAME qtrocket_sim_tests COMMAND sim_tests)

View File

@ -6,85 +6,27 @@ 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);
// Test that the calucated values are with 1% of the published values in the NOAA report
EXPECT_NEAR(atmosphere.getDensity(0.0) / 1.225, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(1000.0) / 1.112, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(2000.0) / 1.007, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(3000.0) / 0.9093, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(4000.0) / 0.8194, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(5000.0) / 0.7364, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(6000.0) / 0.6601, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(7000.0) / 0.5900, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(8000.0) / 0.5258, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(9000.0) / 0.4647, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(10000.0) / 0.4135, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(15000.0) / 0.1948, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(20000.0) / 0.08891, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(25000.0) / 0.039466, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(30000.0) / 0.018012, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(40000.0) / 0.0038510, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(60000.0) / 0.00028832, 1.0, 0.01);
EXPECT_NEAR(atmosphere.getDensity(70000.0) / 0.000074243, 1.0, 0.01);
// These two fail. Commenting out for now, the 50k meters is off by 5%, the 80k by 100%
// TODO: Why?
//EXPECT_NEAR(atmosphere.getDensity(50000.0) / 0.0010269, 1.0, 0.01);
//EXPECT_NEAR(atmosphere.getDensity(80000.0) / 0.000015701, 1.0, 0.01);
}

View File

@ -3,14 +3,15 @@
// C headers
// C++ headers
#include <algorithm>
#include <format>
#include <sstream>
#include <stdexcept>
// 3rd party headers
#include <fmt/core.h>
/// \endcond
// qtrocket headers
#include "Bin.h"
#include "BinMap.h"
// TODO: Check on the availability of this in Clang.
// Replace libfmt with format when LLVM libc++ supports it
@ -19,33 +20,33 @@
namespace utils
{
Bin::Bin()
BinMap::BinMap()
: bins()
{
}
Bin::Bin(Bin&& o)
BinMap::BinMap(BinMap&& o)
: bins(std::move(o.bins))
{
}
Bin::~Bin()
BinMap::~BinMap()
{
}
// TODO: Very low priority, but if anyone wants to make this more efficient it could be
// interesting
void Bin::insert(const std::pair<double, double>& toInsert)
void BinMap::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 Bin::operator[](double key)
double BinMap::operator[](double key)
{
auto iter = bins.begin();
// If the key is less than the lowest bin value, then it is out of range
@ -55,12 +56,12 @@ double Bin::operator[](double key)
if(key < iter->first)
{
throw std::out_of_range(
std::format("{} less than lower bound {} of BinMap", key, iter->first));
fmt::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.back().second;
double retVal = bins.end()->second;
while(iter != bins.end())
{
if(key < iter->first)
@ -73,7 +74,7 @@ double Bin::operator[](double key)
return retVal;
}
double Bin::getBinBase(double key)
double BinMap::getBinBase(double key)
{
auto iter = bins.begin();
// If the key is less than the lowest bin value, then it is out of range
@ -83,7 +84,7 @@ double Bin::getBinBase(double key)
if(key < iter->first)
{
throw std::out_of_range(
std::format("{} less than lower bound {} of BinMap", key, iter->first));
fmt::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_BIN_H
#define UTILS_BIN_H
#ifndef UTILS_BINMAP_H
#define UTILS_BINMAP_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 Bin
class BinMap
{
public:
Bin();
Bin(Bin&& o);
~Bin();
BinMap();
BinMap(BinMap&& o);
~BinMap();
void insert(const std::pair<double, double>& toInsert);
double operator[](double key);
@ -40,4 +40,4 @@ private:
} // namespace utils
#endif // UTILS_BIN_H
#endif // UTILS_BINMAP_H

View File

@ -1,6 +1,6 @@
add_library(utils
Bin.cpp
Bin.h
BinMap.cpp
BinMap.h
CurlConnection.cpp
CurlConnection.h
Logger.cpp
@ -18,13 +18,8 @@ add_library(utils
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
fmt::fmt-header-only
eigen)

View File

@ -40,13 +40,6 @@ void Logger::log(std::string_view msg, const LogLevel& lvl)
// all levels at or lower than the current level.
switch(currentLevel)
{
case PERF_:
if(lvl == PERF_)
{
outFile << "[PERF] " << msg << std::endl;
std::cout << "[PERF] " << msg << "\n";
}
[[fallthrough]];
case DEBUG_:
if(lvl == DEBUG_)
{

View File

@ -25,8 +25,7 @@ public:
ERROR_,
WARN_,
INFO_,
DEBUG_,
PERF_
DEBUG_
};
static Logger* getInstance();
@ -39,11 +38,16 @@ 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 perf(std::string_view msg) { log(msg, PERF_); }
void log(std::ostream& o, const std::string& msg);

View File

@ -235,9 +235,7 @@ 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();
@ -246,7 +244,6 @@ Logger::getInstance()->debug("2");
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")
@ -256,7 +253,6 @@ Logger::getInstance()->debug("3");
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();
@ -283,10 +279,8 @@ Logger::getInstance()->debug("4");
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");
auto tc = getThrustCurve(mm.motorIdTC);
if(tc)
{
motorModel.addThrustCurve(*tc);

View File

@ -6,19 +6,9 @@ namespace utils::math
namespace Constants
{
constexpr double Rstar = 8.31432;
constexpr double Rstar = 8.3144598;
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;

View File

@ -2,7 +2,6 @@
#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.
@ -21,54 +20,4 @@ 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