Skip to content

Commit 9bbd0b3

Browse files
committed
Make arrow mass configurable relative to draw force or energy
Closes #269
1 parent 9938608 commit 9bbd0b3

23 files changed

Lines changed: 310 additions & 42 deletions

File tree

gui/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ add_executable(
150150
source/pre/views/LineView.hpp
151151
source/pre/views/MassesView.cpp
152152
source/pre/views/MassesView.hpp
153+
source/pre/views/ArrowMassView.cpp
154+
source/pre/views/ArrowMassView.hpp
153155
source/pre/views/MaterialView.cpp
154156
source/pre/views/MaterialView.hpp
155157
source/pre/views/primitive/ColorView.cpp

gui/source/post/OutputWidget.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ DynamicOutputWidget::DynamicOutputWidget(const BowResult& data)
192192

193193
numbers->addColumn();
194194
numbers->addGroup("Performance");
195+
numbers->addValue("Arrow mass", data.dynamics->arrow_mass, Quantities::mass);
195196
numbers->addValue("Final arrow velocity", departure.arrow_vel, Quantities::velocity);
196197
numbers->addValue("Final arrow energy", departure.kinetic_energy_arrow, Quantities::energy);
197198
numbers->addValue("Degree of efficiency", departure.energy_efficiency, Quantities::ratio);

gui/source/pre/Main.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
#include "MainWindow.hpp"
22
#include "KeyEventFilter.hpp"
33
#include "config.hpp"
4+
#include "solver/BowModel.hpp"
45
#include <iostream>
56

67
#include <QApplication>
78
#include <QCommandLineParser>
89

9-
int main(int argc, char* argv[]) {
10+
Q_DECLARE_METATYPE(LayerAlignment)
11+
Q_DECLARE_METATYPE(ArrowMass)
12+
13+
int main(int argc, char* argv[]) {
1014
QApplication::setOrganizationName(Config::ORGANIZATION_NAME);
1115
QApplication::setOrganizationDomain(Config::ORGANIZATION_DOMAIN);
1216
QApplication::setApplicationName(Config::APPLICATION_NAME_GUI);
1317
QApplication::setApplicationDisplayName(Config::APPLICATION_DISPLAY_NAME_GUI);
1418
QApplication::setApplicationVersion(Config::APPLICATION_VERSION);
1519
QLocale::setDefault(QLocale::C);
1620

21+
qRegisterMetaType<LayerAlignment>("LayerAlignment");
22+
qRegisterMetaType<ArrowMass>("ArrowMass");
23+
1724
QApplication application(argc, argv);
1825
application.installEventFilter(new KeyEventFilter());
1926

gui/source/pre/models/MassesModel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#include "solver/BowModel.hpp"
33

44
MassesModel::MassesModel(Masses& masses) {
5-
ARROW = addDouble(masses.arrow);
5+
ARROW = addArrowMass(masses.arrow);
66
STRING_CENTER = addDouble(masses.string_center);
77
STRING_TIP = addDouble(masses.string_tip);
88
LIMB_TIP = addDouble(masses.limb_tip);

gui/source/pre/models/PropertyListModel.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ QPersistentModelIndex PropertyListModel::addDouble(double& value) {
2626
return addProperty(new DoubleProperty(this, value));
2727
}
2828

29+
QPersistentModelIndex PropertyListModel::addArrowMass(ArrowMass& value) {
30+
return addProperty(new ArrowMassProperty(this, value));
31+
}
32+
33+
2934
int PropertyListModel::rowCount(const QModelIndex& parent) const {
3035
return properties.count();
3136
}

gui/source/pre/models/PropertyListModel.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include "solver/BowModel.hpp"
23
#include <QVariant>
34
#include <QColor>
45
#include <QAbstractListModel>
@@ -170,6 +171,39 @@ class EnumProperty: public AbstractProperty {
170171
EnumType& value;
171172
};
172173

174+
class ArrowMassProperty: public AbstractProperty {
175+
public:
176+
ArrowMassProperty(QObject* parent, ArrowMass& value):
177+
value(value)
178+
{
179+
setParent(parent); // TODO: Do this by calling super-constructor?
180+
}
181+
182+
virtual QVariant data(int role) const override {
183+
if(role == Qt::DisplayRole || role == Qt::EditRole ) {
184+
return QVariant::fromValue(value);
185+
}
186+
187+
return QVariant();
188+
}
189+
190+
virtual bool setData(const QVariant &value, int role) override {
191+
if(role != Qt::EditRole) {
192+
return false;
193+
}
194+
195+
if(!value.canConvert<ArrowMass>()) {
196+
return false;
197+
}
198+
199+
this->value = value.value<ArrowMass>();
200+
return true;
201+
}
202+
203+
private:
204+
ArrowMass& value;
205+
};
206+
173207
class PropertyListModel: public QAbstractListModel {
174208
Q_OBJECT
175209

@@ -180,6 +214,7 @@ class PropertyListModel: public QAbstractListModel {
180214
QPersistentModelIndex addColor(std::string& value);
181215
QPersistentModelIndex addInteger(int& value);
182216
QPersistentModelIndex addDouble(double& value);
217+
QPersistentModelIndex addArrowMass(ArrowMass& value);
183218

184219
template<typename EnumType>
185220
QPersistentModelIndex addEnum(EnumType& value) {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include "ArrowMassView.hpp"
2+
#include "solver/BowModel.hpp"
3+
#include "pre/widgets/DoubleSpinBox.hpp"
4+
#include "pre/models/units/UnitSystem.hpp"
5+
#include <QAbstractItemModel>
6+
#include <QVBoxLayout>
7+
#include <QStackedLayout>
8+
#include <QLabel>
9+
#include <QComboBox>
10+
#include <cmath>
11+
12+
ArrowMassView::ArrowMassView(QAbstractItemModel* model, QPersistentModelIndex index) {
13+
/*
14+
setToolTip(tooltip);
15+
16+
// Set value from model and keep model up to date on changes
17+
setValue(model->data(index, Qt::DisplayRole).toDouble());
18+
QObject::connect(this, &QDoubleSpinBox::valueChanged, this, [=](double value){ model->setData(index, value); });
19+
*/
20+
21+
auto selectionBox = new QComboBox();
22+
selectionBox->setToolTip("Select how the arrow mass is to be defined");
23+
selectionBox->addItems({"Mass", "Mass per Force", "Mass per Energy"});
24+
25+
auto massEdit = new DoubleSpinBox(Quantities::mass, DoubleRange::nonNegative(1e-3));
26+
massEdit->setToolTip("Arrow mass (absolute value)");
27+
massEdit->setValue(1e-3);
28+
29+
auto massPerForceEdit = new DoubleSpinBox(Quantities::mass_per_force, DoubleRange::nonNegative(1e-6));
30+
massPerForceEdit->setToolTip("Arrow mass relative to the final draw force of the bow");
31+
massPerForceEdit->setValue(1e-6);
32+
33+
auto massPerEnergyEdit = new DoubleSpinBox(Quantities::mass_per_energy, DoubleRange::nonNegative(1e-4));
34+
massPerEnergyEdit->setToolTip("Arrow mass relative to the input energy of the bow");
35+
massPerEnergyEdit->setValue(1e-4);
36+
37+
auto stack = new QStackedLayout();
38+
stack->addWidget(massEdit);
39+
stack->addWidget(massPerForceEdit);
40+
stack->addWidget(massPerEnergyEdit);
41+
42+
auto vbox = new QVBoxLayout();
43+
vbox->setContentsMargins(0, 0, 0, 0);
44+
vbox->addWidget(selectionBox);
45+
vbox->addLayout(stack);
46+
setLayout(vbox);
47+
48+
// Update view according to the data in the model
49+
auto updateView = [=]() {
50+
// Set selection according to the type of mass definition
51+
ArrowMass mass = model->data(index, Qt::DisplayRole).value<ArrowMass>();
52+
selectionBox->setCurrentIndex(mass.index());
53+
54+
// Assign value to the correct editor according to the type of mass definition
55+
if(auto value = std::get_if<Mass>(&mass)) {
56+
massEdit->setValue(value->value);
57+
}
58+
else if(auto value = std::get_if<MassPerForce>(&mass)) {
59+
massPerForceEdit->setValue(value->value);
60+
}
61+
else if(auto value = std::get_if<MassPerEnergy>(&mass)) {
62+
massPerEnergyEdit->setValue(value->value);
63+
}
64+
else {
65+
throw std::invalid_argument("Unknown variant");
66+
}
67+
};
68+
69+
// Update model according to data in the view
70+
auto updateModel = [=]() {
71+
switch(selectionBox->currentIndex()) {
72+
case 0:
73+
model->setData(index, QVariant::fromValue<ArrowMass>(Mass{ .value = massEdit->value() }));
74+
break;
75+
76+
case 1:
77+
model->setData(index, QVariant::fromValue<ArrowMass>(MassPerForce{ .value = massPerForceEdit->value() }));
78+
break;
79+
80+
case 2:
81+
model->setData(index, QVariant::fromValue<ArrowMass>(MassPerEnergy{ .value = massPerEnergyEdit->value() }));
82+
break;
83+
84+
default:
85+
throw std::invalid_argument("Unknown variant");
86+
}
87+
};
88+
89+
// Activate the correct editor according to the selected mass definition
90+
QObject::connect(selectionBox, &QComboBox::currentIndexChanged, stack, &QStackedLayout::setCurrentIndex);
91+
92+
// Initialize view from model once
93+
updateView();
94+
95+
// Keep model up to date on changes
96+
QObject::connect(selectionBox, &QComboBox::currentIndexChanged, this, updateModel);
97+
QObject::connect(massEdit, &DoubleSpinBox::valueChanged, this, updateModel);
98+
QObject::connect(massPerForceEdit, &DoubleSpinBox::valueChanged, this, updateModel);
99+
QObject::connect(massPerEnergyEdit, &DoubleSpinBox::valueChanged, this, updateModel);
100+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
#include <QWidget>
3+
4+
class QAbstractItemModel;
5+
6+
class ArrowMassView: public QWidget {
7+
public:
8+
ArrowMassView(QAbstractItemModel* model, QPersistentModelIndex index);
9+
};

gui/source/pre/views/MassesView.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "MassesView.hpp"
2+
#include "ArrowMassView.hpp"
23
#include "pre/models/MassesModel.hpp"
34
#include "primitive/DoubleView.hpp"
45
#include "pre/utils/DoubleRange.hpp"
@@ -7,7 +8,7 @@
78
MassesView::MassesView(MassesModel* model) {
89
addProperty(
910
"Arrow",
10-
new DoubleView(model, model->ARROW, Quantities::mass, DoubleRange::positive(1e-3), "Mass of the arrow")
11+
new ArrowMassView(model, model->ARROW)
1112
);
1213

1314
addProperty(

gui/source/pre/views/primitive/DoubleView.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ DoubleView::DoubleView(QAbstractItemModel* model, QPersistentModelIndex index, c
99

1010
// Set value from model and keep model up to date on changes
1111
setValue(model->data(index, Qt::DisplayRole).toDouble());
12-
QObject::connect(this, &QDoubleSpinBox::valueChanged, this, [=](double value){ model->setData(index, value); });
12+
QObject::connect(this, &DoubleSpinBox::valueChanged, this, [=](double value){ model->setData(index, value); });
1313
}

0 commit comments

Comments
 (0)