Skip to content

Commit ce3597f

Browse files
authored
QtFRED Relative Coordinates Dialog (#7031)
* qtfred relative coords dialog * clang
1 parent d42789d commit ce3597f

File tree

9 files changed

+542
-2
lines changed

9 files changed

+542
-2
lines changed

qtfred/source_groups.cmake

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ add_file_folder("Source/Mission/Dialogs"
7373
src/mission/dialogs/ObjectOrientEditorDialogModel.cpp
7474
src/mission/dialogs/ObjectOrientEditorDialogModel.h
7575
src/mission/dialogs/ReinforcementsEditorDialogModel.cpp
76-
src/mission/dialogs/ReinforcementsEditorDialogModel.h
76+
src/mission/dialogs/ReinforcementsEditorDialogModel.h
77+
src/mission/dialogs/RelativeCoordinatesDialogModel.cpp
78+
src/mission/dialogs/RelativeCoordinatesDialogModel.h
7779
src/mission/dialogs/SelectionDialogModel.cpp
7880
src/mission/dialogs/SelectionDialogModel.h
7981
src/mission/dialogs/ShieldSystemDialogModel.cpp
@@ -174,6 +176,8 @@ add_file_folder("Source/UI/Dialogs"
174176
src/ui/dialogs/ObjectOrientEditorDialog.h
175177
src/ui/dialogs/ReinforcementsEditorDialog.cpp
176178
src/ui/dialogs/ReinforcementsEditorDialog.h
179+
src/ui/dialogs/RelativeCoordinatesDialog.cpp
180+
src/ui/dialogs/RelativeCoordinatesDialog.h
177181
src/ui/dialogs/SelectionDialog.cpp
178182
src/ui/dialogs/SelectionDialog.h
179183
src/ui/dialogs/ShieldSystemDialog.h
@@ -288,6 +292,7 @@ add_file_folder("UI"
288292
ui/MusicPlayerDialog.ui
289293
ui/ObjectOrientationDialog.ui
290294
ui/ReinforcementsDialog.ui
295+
ui/RelativeCoordinatesDialog.ui
291296
ui/SelectionDialog.ui
292297
ui/ShieldSystemDialog.ui
293298
ui/SoundEnvironmentDialog.ui
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#include "RelativeCoordinatesDialogModel.h"
2+
3+
#include "math/vecmat.h"
4+
#include <mission/object.h>
5+
6+
7+
namespace fso::fred::dialogs {
8+
9+
RelativeCoordinatesDialogModel::RelativeCoordinatesDialogModel(QObject* parent, EditorViewport* viewport)
10+
: AbstractDialogModel(parent, viewport)
11+
{
12+
_objects.clear();
13+
14+
for (auto ptr = GET_FIRST(&obj_used_list); ptr != END_OF_LIST(&obj_used_list); ptr = GET_NEXT(ptr)) {
15+
bool added = false;
16+
17+
int objnum = OBJ_INDEX(ptr);
18+
19+
if (ptr->type == OBJ_START || ptr->type == OBJ_SHIP) {
20+
_objects.emplace_back(Ships[ptr->instance].ship_name, objnum);
21+
22+
added = true;
23+
} else if (ptr->type == OBJ_WAYPOINT) {
24+
SCP_string text;
25+
int waypoint_num;
26+
27+
auto wp_list = find_waypoint_list_with_instance(ptr->instance, &waypoint_num);
28+
Assert(wp_list != nullptr);
29+
text = wp_list->get_name();
30+
text += ":";
31+
text += std::to_string(waypoint_num + 1);
32+
_objects.emplace_back(text, objnum);
33+
34+
added = true;
35+
}
36+
37+
bool marked = (ptr->flags[Object::Object_Flags::Marked]);
38+
39+
if (added && marked && _originIndex == -1) {
40+
_originIndex = objnum; // TODO: select first marked object as origin.. not sure QtFRED has cur_object_index available yet
41+
} else if (added && marked && _satelliteIndex == -1 && objnum != _originIndex) {
42+
_satelliteIndex = objnum;
43+
}
44+
}
45+
46+
computeCoordinates();
47+
}
48+
49+
bool RelativeCoordinatesDialogModel::apply()
50+
{
51+
// Read only dialog
52+
return true;
53+
}
54+
55+
void RelativeCoordinatesDialogModel::reject()
56+
{
57+
// Read only dialog
58+
}
59+
60+
float RelativeCoordinatesDialogModel::getDistance() const
61+
{
62+
return _distance;
63+
}
64+
float RelativeCoordinatesDialogModel::getPitch() const
65+
{
66+
return _orientation_p;
67+
}
68+
float RelativeCoordinatesDialogModel::getBank() const
69+
{
70+
return _orientation_b;
71+
}
72+
float RelativeCoordinatesDialogModel::getHeading() const
73+
{
74+
return _orientation_h;
75+
}
76+
77+
int RelativeCoordinatesDialogModel::getOrigin() const
78+
{
79+
return _originIndex;
80+
}
81+
82+
void RelativeCoordinatesDialogModel::setOrigin(int index)
83+
{
84+
if (_originIndex == index)
85+
return;
86+
_originIndex = index;
87+
computeCoordinates();
88+
}
89+
90+
int RelativeCoordinatesDialogModel::getSatellite() const
91+
{
92+
return _satelliteIndex;
93+
}
94+
95+
void RelativeCoordinatesDialogModel::setSatellite(int index)
96+
{
97+
if (_satelliteIndex == index)
98+
return;
99+
_satelliteIndex = index;
100+
computeCoordinates();
101+
}
102+
103+
SCP_vector<std::pair<SCP_string, int>> RelativeCoordinatesDialogModel::getObjectsList() const
104+
{
105+
return _objects;
106+
}
107+
108+
void RelativeCoordinatesDialogModel::computeCoordinates()
109+
{
110+
if (_originIndex < 0 || _satelliteIndex < 0 || (_originIndex == _satelliteIndex)) {
111+
_distance = 0.0f;
112+
_orientation_p = 0.0f;
113+
_orientation_b = 0.0f;
114+
_orientation_h = 0.0f;
115+
116+
return;
117+
}
118+
119+
auto origin_pos = Objects[_originIndex].pos;
120+
auto satellite_pos = Objects[_satelliteIndex].pos;
121+
122+
// distance
123+
_distance = vm_vec_dist(&origin_pos, &satellite_pos);
124+
125+
// transform the coordinate frame
126+
vec3d delta_vec, local_vec;
127+
vm_vec_sub(&delta_vec, &satellite_pos, &origin_pos);
128+
if (Objects[_originIndex].type != OBJ_WAYPOINT)
129+
vm_vec_rotate(&local_vec, &delta_vec, &Objects[_originIndex].orient);
130+
131+
// find the orientation
132+
matrix m;
133+
vm_vector_2_matrix(&m, &local_vec);
134+
135+
// find the angles
136+
angles ang;
137+
vm_extract_angles_matrix(&ang, &m);
138+
_orientation_p = to_degrees(ang.p);
139+
_orientation_b = to_degrees(ang.b);
140+
_orientation_h = to_degrees(ang.h);
141+
}
142+
143+
float RelativeCoordinatesDialogModel::to_degrees(float rad)
144+
{
145+
float deg = fl_degrees(rad);
146+
return normalize_degrees(deg);
147+
}
148+
149+
float RelativeCoordinatesDialogModel::normalize_degrees(float deg)
150+
{
151+
while (deg < -180.0f)
152+
deg += 180.0f;
153+
while (deg > 180.0f)
154+
deg -= 180.0f;
155+
// check for negative zero...
156+
if (deg == -0.0f)
157+
return 0.0f;
158+
return deg;
159+
}
160+
161+
} // namespace fso::fred::dialogs
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#pragma once
2+
3+
#include "mission/dialogs/AbstractDialogModel.h"
4+
5+
namespace fso::fred::dialogs {
6+
7+
class RelativeCoordinatesDialogModel : public AbstractDialogModel {
8+
Q_OBJECT
9+
public:
10+
RelativeCoordinatesDialogModel(QObject* parent, EditorViewport* viewport);
11+
12+
bool apply() override;
13+
void reject() override;
14+
15+
float getDistance() const;
16+
float getPitch() const;
17+
float getBank() const;
18+
float getHeading() const;
19+
20+
int getOrigin() const;
21+
void setOrigin(int index);
22+
int getSatellite() const;
23+
void setSatellite(int index);
24+
25+
SCP_vector<std::pair<SCP_string, int>> getObjectsList() const;
26+
27+
private:
28+
void computeCoordinates();
29+
static float to_degrees(float rad);
30+
static float normalize_degrees(float deg);
31+
32+
int _originIndex = -1;
33+
int _satelliteIndex = -1;
34+
35+
float _distance = 0.0f;
36+
float _orientation_p = 0.0f;
37+
float _orientation_b = 0.0f;
38+
float _orientation_h = 0.0f;
39+
40+
SCP_vector<std::pair<SCP_string, int>> _objects; // (name, obj index)
41+
42+
};
43+
44+
} // namespace fred::dialogs

qtfred/src/ui/FredView.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <ui/dialogs/LoadoutDialog.h>
3939
#include <ui/dialogs/VariableDialog.h>
4040
#include <ui/dialogs/MusicPlayerDialog.h>
41+
#include <ui/dialogs/RelativeCoordinatesDialog.h>
4142
#include <iff_defs/iff_defs.h>
4243

4344
#include "mission/Editor.h"
@@ -1235,6 +1236,12 @@ void FredView::on_actionMusic_Player_triggered(bool)
12351236
dialog->show();
12361237
}
12371238

1239+
void FredView::on_actionCalculate_Relative_Coordinates_triggered(bool) {
1240+
auto dialog = new dialogs::RelativeCoordinatesDialog(this, _viewport);
1241+
dialog->setAttribute(Qt::WA_DeleteOnClose);
1242+
dialog->show();
1243+
}
1244+
12381245
void FredView::on_actionFiction_Viewer_triggered(bool) {
12391246
auto dialog = new dialogs::FictionViewerDialog(this, _viewport);
12401247
dialog->setAttribute(Qt::WA_DeleteOnClose);

qtfred/src/ui/FredView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ class FredView: public QMainWindow, public IDialogProvider {
153153
void on_actionFiction_Viewer_triggered(bool);
154154
void on_actionMission_Goals_triggered(bool);
155155
void on_actionMusic_Player_triggered(bool);
156+
void on_actionCalculate_Relative_Coordinates_triggered(bool);
156157
signals:
157158
/**
158159
* @brief Special version of FredApplication::onIdle which is limited to the lifetime of this object
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#include "ui/dialogs/RelativeCoordinatesDialog.h"
2+
#include "ui_RelativeCoordinatesDialog.h"
3+
#include "ui/util/SignalBlockers.h"
4+
5+
#include <QCloseEvent>
6+
7+
namespace fso::fred::dialogs {
8+
9+
RelativeCoordinatesDialog::RelativeCoordinatesDialog(FredView* parent, EditorViewport* viewport)
10+
: QDialog(parent), _viewport(viewport), ui(new Ui::RelativeCoordinatesDialog()),
11+
_model(new RelativeCoordinatesDialogModel(this, viewport))
12+
{
13+
ui->setupUi(this);
14+
15+
initializeUi();
16+
}
17+
18+
RelativeCoordinatesDialog::~RelativeCoordinatesDialog() = default;
19+
20+
void RelativeCoordinatesDialog::initializeUi()
21+
{
22+
util::SignalBlockers blockers(this);
23+
24+
ui->originListWidget->clear();
25+
ui->satelliteListWidget->clear();
26+
27+
const auto objects = _model->getObjectsList();
28+
29+
auto addWithData = [](QListWidget* list, const std::string& name, int objnum) {
30+
auto* item = new QListWidgetItem(QString::fromStdString(name));
31+
item->setData(Qt::UserRole, objnum);
32+
list->addItem(item);
33+
};
34+
35+
for (const auto& [name, objnum] : objects) {
36+
addWithData(ui->originListWidget, name, objnum);
37+
addWithData(ui->satelliteListWidget, name, objnum);
38+
}
39+
40+
updateUi();
41+
}
42+
43+
void RelativeCoordinatesDialog::updateUi()
44+
{
45+
util::SignalBlockers blockers(this);
46+
47+
// Restore selections based on model's obj indices
48+
auto selectByObjnum = [](QListWidget* list, int wantObj) {
49+
if (wantObj < 0)
50+
return;
51+
for (int r = 0; r < list->count(); ++r) {
52+
if (list->item(r)->data(Qt::UserRole).toInt() == wantObj) {
53+
list->setCurrentRow(r);
54+
break;
55+
}
56+
}
57+
};
58+
selectByObjnum(ui->originListWidget, _model->getOrigin());
59+
selectByObjnum(ui->satelliteListWidget, _model->getSatellite());
60+
61+
ui->distanceDoubleSpinBox->setValue(static_cast<double>(_model->getDistance()));
62+
ui->pitchDoubleSpinBox->setValue(static_cast<double>(_model->getPitch()));
63+
ui->bankDoubleSpinBox->setValue(static_cast<double>(_model->getBank()));
64+
ui->headingDoubleSpinBox->setValue(static_cast<double>(_model->getHeading()));
65+
}
66+
67+
void RelativeCoordinatesDialog::on_originListWidget_currentRowChanged(int row)
68+
{
69+
auto* item = ui->originListWidget->item(row);
70+
if (!item)
71+
return;
72+
const int objnum = item->data(Qt::UserRole).toInt();
73+
_model->setOrigin(objnum);
74+
updateUi();
75+
}
76+
77+
void RelativeCoordinatesDialog::on_satelliteListWidget_currentRowChanged(int row)
78+
{
79+
auto* item = ui->satelliteListWidget->item(row);
80+
if (!item)
81+
return;
82+
const int objnum = item->data(Qt::UserRole).toInt();
83+
_model->setSatellite(objnum);
84+
updateUi();
85+
}
86+
87+
} // namespace fred::dialogs
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#include <QDialog>
4+
5+
#include "mission/dialogs/RelativeCoordinatesDialogModel.h"
6+
#include <ui/FredView.h>
7+
8+
namespace fso::fred::dialogs {
9+
10+
namespace Ui {
11+
class RelativeCoordinatesDialog;
12+
}
13+
14+
class RelativeCoordinatesDialog final : public QDialog {
15+
Q_OBJECT
16+
public:
17+
explicit RelativeCoordinatesDialog(FredView* parent, EditorViewport* viewport);
18+
~RelativeCoordinatesDialog() override;
19+
20+
private slots:
21+
void on_originListWidget_currentRowChanged(int row);
22+
void on_satelliteListWidget_currentRowChanged(int row);
23+
24+
private: // NOLINT(readability-redundant-access-specifiers)
25+
void initializeUi();
26+
void updateUi();
27+
28+
// Boilerplate
29+
EditorViewport* _viewport = nullptr;
30+
std::unique_ptr<Ui::RelativeCoordinatesDialog> ui;
31+
std::unique_ptr<RelativeCoordinatesDialogModel> _model;
32+
};
33+
34+
} // namespace fred::dialogs

0 commit comments

Comments
 (0)