Initial Thrustcurve.org integration. Can get metadata and perform searches
This commit is contained in:
parent
3f6342994d
commit
311870e957
@ -21,6 +21,8 @@ AnalysisWindow::AnalysisWindow(QWidget *parent) :
|
||||
}
|
||||
*/
|
||||
auto& plot = ui->plotWidget;
|
||||
plot->setInteraction(QCP::iRangeDrag, true);
|
||||
plot->setInteraction(QCP::iRangeZoom, true);
|
||||
// generate some data:
|
||||
QVector<double> tData(res.size()), zData(res.size());
|
||||
for (int i = 0; i < tData.size(); ++i)
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "ui_MainWindow.h"
|
||||
#include "gui/AboutWindow.h"
|
||||
#include "gui/AnalysisWindow.h"
|
||||
#include "gui/ThrustCurveMotorSelector.h"
|
||||
|
||||
#include "sim/RK4Solver.h"
|
||||
#include "model/Rocket.h"
|
||||
@ -141,3 +142,12 @@ void MainWindow::on_loadRSE_button_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_getTCMotorData_clicked()
|
||||
{
|
||||
ThrustCurveMotorSelector window;
|
||||
window.setModal(false);
|
||||
window.exec();
|
||||
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@ private slots:
|
||||
|
||||
void on_loadRSE_button_clicked();
|
||||
|
||||
void on_getTCMotorData_clicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
QtRocket* qtRocket;
|
||||
|
@ -188,7 +188,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>90</x>
|
||||
<y>220</y>
|
||||
<y>250</y>
|
||||
<width>421</width>
|
||||
<height>80</height>
|
||||
</rect>
|
||||
@ -213,6 +213,19 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="getTCMotorData">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>240</x>
|
||||
<y>360</y>
|
||||
<width>201</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Get Thrustcurve Motor Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QCustomPlot" name="plotWindow" native="true"/>
|
||||
|
65
gui/ThrustCurveMotorSelector.cpp
Normal file
65
gui/ThrustCurveMotorSelector.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include "ThrustCurveMotorSelector.h"
|
||||
#include "ui_ThrustCurveMotorSelector.h"
|
||||
|
||||
ThrustCurveMotorSelector::ThrustCurveMotorSelector(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ThrustCurveMotorSelector),
|
||||
tcApi(new utils::ThrustCurveAPI)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->setWindowModality(Qt::NonModal);
|
||||
this->hide();
|
||||
this->show();
|
||||
}
|
||||
|
||||
ThrustCurveMotorSelector::~ThrustCurveMotorSelector()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ThrustCurveMotorSelector::on_getMetadata_clicked()
|
||||
{
|
||||
// When the user clicks "Get Metadata", we want to pull in Metadata from thrustcurve.org
|
||||
// and populate the Manufacturer, Diameter, and Impulse Class combo boxes
|
||||
|
||||
utils::ThrustcurveMetadata metadata = tcApi->getMetadata();
|
||||
|
||||
for(const auto& i : metadata.diameters)
|
||||
{
|
||||
ui->diameter->addItem(QString::number(i));
|
||||
}
|
||||
|
||||
for(const auto& i : metadata.manufacturers)
|
||||
{
|
||||
ui->manufacturer->addItem(QString::fromStdString(i.first));
|
||||
}
|
||||
for(const auto& i : metadata.impulseClasses)
|
||||
{
|
||||
ui->impulseClass->addItem(QString::fromStdString(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ThrustCurveMotorSelector::on_searchButton_clicked()
|
||||
{
|
||||
|
||||
//double diameter = ui->diameter->
|
||||
|
||||
std::string diameter = ui->diameter->currentText().toStdString();
|
||||
std::string manufacturer = ui->manufacturer->currentText().toStdString();
|
||||
std::string impulseClass = ui->impulseClass->currentText().toStdString();
|
||||
|
||||
utils::SearchCriteria c;
|
||||
c.addCriteria("diameter", diameter);
|
||||
c.addCriteria("manufacturer", manufacturer);
|
||||
c.addCriteria("impulseClass", impulseClass);
|
||||
|
||||
std::vector<MotorModel> motors = tcApi->searchMotors(c);
|
||||
|
||||
for(const auto& i : motors)
|
||||
{
|
||||
ui->motorSelection->addItem(QString::fromStdString(i.commonName));
|
||||
}
|
||||
|
||||
}
|
||||
|
33
gui/ThrustCurveMotorSelector.h
Normal file
33
gui/ThrustCurveMotorSelector.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef THRUSTCURVEMOTORSELECTOR_H
|
||||
#define THRUSTCURVEMOTORSELECTOR_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "utils/ThrustCurveAPI.h"
|
||||
|
||||
namespace Ui {
|
||||
class ThrustCurveMotorSelector;
|
||||
}
|
||||
|
||||
class ThrustCurveMotorSelector : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ThrustCurveMotorSelector(QWidget *parent = nullptr);
|
||||
~ThrustCurveMotorSelector();
|
||||
|
||||
private slots:
|
||||
void on_getMetadata_clicked();
|
||||
|
||||
void on_searchButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::ThrustCurveMotorSelector *ui;
|
||||
|
||||
std::unique_ptr<utils::ThrustCurveAPI> tcApi;
|
||||
};
|
||||
|
||||
#endif // THRUSTCURVEMOTORSELECTOR_H
|
127
gui/ThrustCurveMotorSelector.ui
Normal file
127
gui/ThrustCurveMotorSelector.ui
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ThrustCurveMotorSelector</class>
|
||||
<widget class="QDialog" name="ThrustCurveMotorSelector">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>622</width>
|
||||
<height>878</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="formLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>170</x>
|
||||
<y>90</y>
|
||||
<width>160</width>
|
||||
<height>101</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Manufacturer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Diameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Impulse Class</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="manufacturer"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="diameter"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="impulseClass"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="getMetadata">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>40</y>
|
||||
<width>91</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Get Metadata</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCustomPlot" name="plot" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>320</y>
|
||||
<width>601</width>
|
||||
<height>551</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="searchButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>210</x>
|
||||
<y>210</y>
|
||||
<width>80</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="formLayoutWidget_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>170</x>
|
||||
<y>260</y>
|
||||
<width>160</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="pushButton_2">
|
||||
<property name="text">
|
||||
<string>Download</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="motorSelection"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QCustomPlot</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/qcustomplot.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -29,6 +29,8 @@ public:
|
||||
OOP // Out of Production
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum class CERTORG
|
||||
{
|
||||
AMRS,
|
||||
@ -116,7 +118,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO: make these private. Public just for testing
|
||||
//private:
|
||||
// Needed for boost serialize
|
||||
@ -132,7 +133,7 @@ public:
|
||||
// int dataFiles
|
||||
std::vector<int> delays; // -1 delay means no ejection charge
|
||||
std::string designation{""};
|
||||
int diameter{0};
|
||||
double diameter{0};
|
||||
std::string impulseClass; // 'A', 'B', '1/2A', 'M', etc
|
||||
std::string infoUrl{""};
|
||||
double length{0.0};
|
||||
|
@ -12,6 +12,7 @@ SOURCES += \
|
||||
QtRocket.cpp \
|
||||
gui/AboutWindow.cpp \
|
||||
gui/AnalysisWindow.cpp \
|
||||
gui/ThrustCurveMotorSelector.cpp \
|
||||
gui/qcustomplot.cpp \
|
||||
main.cpp \
|
||||
gui/RocketTreeView.cpp \
|
||||
@ -43,6 +44,7 @@ HEADERS += \
|
||||
gui/AnalysisWindow.h \
|
||||
gui/RocketTreeView.h \
|
||||
gui/MainWindow.h \
|
||||
gui/ThrustCurveMotorSelector.h \
|
||||
gui/qcustomplot.h \
|
||||
model/MotorCase.h \
|
||||
model/MotorModel.h \
|
||||
@ -76,7 +78,8 @@ HEADERS += \
|
||||
FORMS += \
|
||||
gui/AboutWindow.ui \
|
||||
gui/AnalysisWindow.ui \
|
||||
gui/MainWindow.ui
|
||||
gui/MainWindow.ui \
|
||||
gui/ThrustCurveMotorSelector.ui
|
||||
|
||||
TRANSLATIONS += \
|
||||
qtrocket_en_US.ts
|
||||
@ -90,8 +93,8 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
|
||||
unix: CONFIG += link_pkgconfig
|
||||
unix: PKGCONFIG += libcurl
|
||||
|
||||
unix: PKGCONFIG += fmt
|
||||
unix: PKGCONFIG += jsoncpp
|
||||
|
||||
RESOURCES += \
|
||||
qtrocket.qrc
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include "ThrustCurveAPI.h"
|
||||
|
||||
#include <json/json.h>
|
||||
#include "utils/Logger.h"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
@ -29,4 +32,168 @@ MotorModel ThrustCurveAPI::getMotorData(const std::string& motorId)
|
||||
return mm;
|
||||
}
|
||||
|
||||
ThrustcurveMetadata ThrustCurveAPI::getMetadata()
|
||||
{
|
||||
|
||||
std::string endpoint = hostname;
|
||||
endpoint += "metadata.json";
|
||||
std::string result = curlConnection.get(endpoint, extraHeaders);
|
||||
ThrustcurveMetadata ret;
|
||||
|
||||
if(!result.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
Json::Reader reader;
|
||||
Json::Value jsonResult;
|
||||
reader.parse(result, jsonResult);
|
||||
|
||||
for(Json::ValueConstIterator iter = jsonResult["certOrgs"].begin();
|
||||
iter != jsonResult["certOrgs"].end();
|
||||
++iter)
|
||||
{
|
||||
std::string org = (*iter)["abbrev"].asString();
|
||||
|
||||
if(org == "AMRS")
|
||||
ret.certOrgs.emplace_back(MotorModel::CERTORG::AMRS);
|
||||
else if(org == "CAR")
|
||||
ret.certOrgs.emplace_back(MotorModel::CERTORG::CAR);
|
||||
else if(org == "NAR")
|
||||
ret.certOrgs.emplace_back(MotorModel::CERTORG::NAR);
|
||||
else if(org == "TRA")
|
||||
ret.certOrgs.emplace_back(MotorModel::CERTORG::TRA);
|
||||
else if(org == "UNC")
|
||||
ret.certOrgs.emplace_back(MotorModel::CERTORG::UNC);
|
||||
else
|
||||
ret.certOrgs.emplace_back(MotorModel::CERTORG::UNK);
|
||||
}
|
||||
for(Json::ValueConstIterator iter = jsonResult["diameters"].begin();
|
||||
iter != jsonResult["diameters"].end();
|
||||
++iter)
|
||||
{
|
||||
ret.diameters.push_back((*iter).asDouble());
|
||||
}
|
||||
for(Json::ValueConstIterator iter = jsonResult["impulseClasses"].begin();
|
||||
iter != jsonResult["impulseClasses"].end();
|
||||
++iter)
|
||||
{
|
||||
ret.impulseClasses.emplace_back((*iter).asString());
|
||||
}
|
||||
for(Json::ValueConstIterator iter = jsonResult["manufacturers"].begin();
|
||||
iter != jsonResult["manufacturers"].end();
|
||||
++iter)
|
||||
{
|
||||
ret.manufacturers[(*iter)["abbrev"].asString()] = (*iter)["name"].asString();
|
||||
}
|
||||
for(Json::ValueConstIterator iter = jsonResult["types"].begin();
|
||||
iter != jsonResult["types"].end();
|
||||
++iter)
|
||||
{
|
||||
std::string type = (*iter)["types"].asString();
|
||||
if(type == "SU")
|
||||
ret.types.emplace_back(MotorModel::MOTORTYPE::SU);
|
||||
else if(type == "reload")
|
||||
ret.types.emplace_back(MotorModel::MOTORTYPE::RELOAD);
|
||||
else
|
||||
ret.types.emplace_back(MotorModel::MOTORTYPE::HYBRID);
|
||||
}
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
|
||||
std::string err("Unable to parse JSON from Thrustcurve metadata request. Error: ");
|
||||
err += e.what();
|
||||
|
||||
Logger::getInstance()->error(err);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
std::vector<MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria& c)
|
||||
{
|
||||
std::vector<MotorModel> retVal;
|
||||
std::string endpoint = hostname;
|
||||
endpoint += "search.json?";
|
||||
for(const auto& i : c.criteria)
|
||||
{
|
||||
endpoint += i.first;
|
||||
endpoint += "=";
|
||||
endpoint += i.second;
|
||||
endpoint += "&";
|
||||
}
|
||||
endpoint = endpoint.substr(0, endpoint.length() - 1);
|
||||
|
||||
|
||||
Logger::getInstance()->debug("endpoint: " + endpoint);
|
||||
std::string result = curlConnection.get(endpoint, extraHeaders);
|
||||
if(!result.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
Json::Reader reader;
|
||||
Json::Value jsonResult;
|
||||
reader.parse(result, jsonResult);
|
||||
|
||||
for(Json::ValueConstIterator iter = jsonResult["results"].begin();
|
||||
iter != jsonResult["results"].end();
|
||||
++iter)
|
||||
{
|
||||
MotorModel mm;
|
||||
mm.commonName = (*iter)["commonName"].asString();
|
||||
|
||||
std::string availability = (*iter)["availability"].asString();
|
||||
if(availability == "regular")
|
||||
mm.availability = MotorModel::MotorAvailability(MotorModel::AVAILABILITY::REGULAR);
|
||||
else
|
||||
mm.availability = MotorModel::MotorAvailability(MotorModel::AVAILABILITY::OOP);
|
||||
|
||||
mm.avgThrust = (*iter)["avgThrustN"].asDouble();
|
||||
mm.burnTime = (*iter)["burnTimeS"].asDouble();
|
||||
// TODO fill in certOrg
|
||||
// TODO fill in delays
|
||||
mm.designation = (*iter)["designation"].asString();
|
||||
mm.diameter = (*iter)["diameter"].asDouble();
|
||||
mm.impulseClass = (*iter)["impulseClass"].asString();
|
||||
mm.length = (*iter)["length"].asDouble();
|
||||
mm.manufacturer = (*iter)["manufacturer"].asString();
|
||||
mm.maxThrust = (*iter)["maxThrustN"].asDouble();
|
||||
mm.motorIdTC = (*iter)["motorId"].asString();
|
||||
mm.propType = (*iter)["propInfo"].asString();
|
||||
mm.propWeight = (*iter)["propWeightG"].asDouble();
|
||||
mm.sparky = (*iter)["sparky"].asBool();
|
||||
mm.totalImpulse = (*iter)["totImpulseNs"].asDouble();
|
||||
mm.totalWeight = (*iter)["totalWeightG"].asDouble();
|
||||
|
||||
std::string type = (*iter)["type"].asString();
|
||||
if(type == "SU")
|
||||
mm.type = MotorModel::MotorType(MotorModel::MOTORTYPE::SU);
|
||||
else if(type == "reload")
|
||||
mm.type = MotorModel::MotorType(MotorModel::MOTORTYPE::RELOAD);
|
||||
else
|
||||
mm.type = MotorModel::MotorType(MotorModel::MOTORTYPE::HYBRID);
|
||||
|
||||
retVal.push_back(mm);
|
||||
}
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
|
||||
std::string err("Unable to parse JSON from Thrustcurve metadata request. Error: ");
|
||||
err += e.what();
|
||||
|
||||
Logger::getInstance()->error(err);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void SearchCriteria::addCriteria(const std::string& name,
|
||||
const std::string& value)
|
||||
{
|
||||
criteria[name] = value;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
@ -3,14 +3,53 @@
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "CurlConnection.h"
|
||||
#include "model/MotorModel.h"
|
||||
#include "model/Thrustcurve.h"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
class ThrustcurveMetadata
|
||||
{
|
||||
public:
|
||||
ThrustcurveMetadata() = default;
|
||||
~ThrustcurveMetadata() = default;
|
||||
|
||||
ThrustcurveMetadata(const ThrustcurveMetadata&) = default;
|
||||
ThrustcurveMetadata(ThrustcurveMetadata&&) = default;
|
||||
|
||||
ThrustcurveMetadata& operator=(const ThrustcurveMetadata&) = default;
|
||||
ThrustcurveMetadata& operator=(ThrustcurveMetadata&&) = default;
|
||||
|
||||
//private:
|
||||
std::vector<MotorModel::CertOrg> certOrgs;
|
||||
std::vector<double> diameters;
|
||||
std::vector<std::string> impulseClasses;
|
||||
std::map<std::string, std::string> manufacturers;
|
||||
std::vector<MotorModel::MotorType> types;
|
||||
|
||||
};
|
||||
|
||||
class SearchCriteria
|
||||
{
|
||||
public:
|
||||
SearchCriteria() = default;
|
||||
~SearchCriteria() = default;
|
||||
SearchCriteria(const SearchCriteria&) = default;
|
||||
SearchCriteria(SearchCriteria&&) = default;
|
||||
|
||||
SearchCriteria& operator=(const SearchCriteria&) = default;
|
||||
SearchCriteria& operator=(SearchCriteria&&) = default;
|
||||
|
||||
void addCriteria(const std::string& name,
|
||||
const std::string& vaue);
|
||||
|
||||
std::map<std::string, std::string> criteria;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This API for Thrustcurve.org - It will provide an interface for querying thrustcurve.org
|
||||
* for motor data
|
||||
@ -30,12 +69,23 @@ public:
|
||||
MotorModel getMotorData(const std::string& motorId);
|
||||
|
||||
|
||||
/**
|
||||
* @brief getMetaData
|
||||
*/
|
||||
|
||||
ThrustcurveMetadata getMetadata();
|
||||
|
||||
std::vector<MotorModel> searchMotors(const SearchCriteria& c);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
const std::string hostname;
|
||||
CurlConnection curlConnection;
|
||||
|
||||
// no extra headers, but CurlConnection library wants them
|
||||
const std::vector<std::string> extraHeaders{};
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
Loading…
x
Reference in New Issue
Block a user