Skip to content

Commit 78e6933

Browse files
committed
Refactor distribute points tool
The core functionality to distribute points evenly along a path was partly contained in the MapEditorController class (which was marked as a TODO). Move the functionality to the (renamed) DistributePointsDialog class. Add three dots to the submenu item's name to indicate that selecting it will open another window. Remove the 'Settings' since changing them in the dialog was not made persistent.
1 parent 9361905 commit 78e6933

File tree

3 files changed

+128
-202
lines changed

3 files changed

+128
-202
lines changed

src/gui/map/map_editor.cpp

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ void MapEditorController::createActions()
10771077
simplify_path_act = newAction("simplify", tr("Simplify path"), this, SLOT(simplifyPathClicked()), "tool-simplify-path.png", QString{}, "toolbars.html#simplify_path");
10781078
clip_area_act = newToolAction("cliparea", tr("Clip area"), this, SLOT(clipAreaClicked()), "tool-clip.png", QString{}, "toolbars.html#clip_area");
10791079
erase_area_act = newToolAction("erasearea", tr("Erase area"), this, SLOT(eraseAreaClicked()), "tool-erase.png", QString{}, "toolbars.html#erase_area");
1080-
distribute_points_act = newAction("distributepoints", tr("Distribute points along path"), this, SLOT(distributePointsClicked()), "tool-distribute-points.png", QString{}, "toolbars.html#distribute_points"); // TODO: write documentation
1080+
distribute_points_act = newAction("distributepoints", tr("Distribute points along path..."), this, SLOT(distributePointsClicked()), "tool-distribute-points.png", QString{}, "toolbars.html#distribute_points"); // TODO: write documentation
10811081

10821082
paint_feature = std::make_unique<PaintOnTemplateFeature>(*this);
10831083

@@ -3475,38 +3475,11 @@ void MapEditorController::eraseAreaClicked()
34753475
void MapEditorController::distributePointsClicked()
34763476
{
34773477
Q_ASSERT(activeSymbol()->getType() == Symbol::Point);
3478-
PointSymbol* point = activeSymbol()->asPoint();
3478+
const auto point = activeSymbol()->asPoint();
34793479

3480-
DistributePointsTool::Settings settings;
3481-
if (!DistributePointsTool::showSettingsDialog(window, point, settings))
3482-
return;
3483-
3484-
// Create points along paths
3485-
std::vector<PointObject*> created_objects;
3486-
for (const auto* object : map->selectedObjects())
3487-
{
3488-
if (object->getType() == Object::Path)
3489-
DistributePointsTool::execute(object->asPath(), point, settings, created_objects);
3490-
}
3491-
if (created_objects.empty())
3492-
return;
3493-
3494-
// Add points to map
3495-
for (auto* o : created_objects)
3496-
map->addObject(o);
3497-
3498-
// Create undo step and select new objects
3499-
map->clearObjectSelection(false);
3500-
MapPart* part = map->getCurrentPart();
3501-
auto* delete_step = new DeleteObjectsUndoStep(map);
3502-
for (std::size_t i = 0; i < created_objects.size(); ++i)
3503-
{
3504-
Object* object = created_objects[i];
3505-
delete_step->addObject(part->findObjectIndex(object));
3506-
map->addObjectToSelection(object, i == created_objects.size() - 1);
3507-
}
3508-
map->push(delete_step);
3509-
map->setObjectsDirty();
3480+
DistributePointsDialog dialog(window, map, point);
3481+
dialog.setWindowModality(Qt::WindowModal);
3482+
dialog.exec();
35103483
}
35113484

35123485
void MapEditorController::addFloatingDockWidget(QDockWidget* dock_widget)
Lines changed: 101 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright 2013 Thomas Schöps
3-
* Copyright 2014, 2015 Kai Pastor
3+
* Copyright 2014-2015, 2017-2019 Kai Pastor
4+
* Copyright 2024 Matthias Kühlewein
45
*
56
* This file is part of OpenOrienteering.
67
*
@@ -21,8 +22,9 @@
2122

2223
#include "distribute_points_tool.h"
2324

25+
#include <vector>
26+
2427
#include <Qt>
25-
#include <QtMath>
2628
#include <QCheckBox>
2729
#include <QDialogButtonBox>
2830
#include <QDoubleSpinBox>
@@ -32,35 +34,109 @@
3234
#include <QSpinBox>
3335
#include <QWidget>
3436

37+
#include "core/map.h"
3538
#include "core/map_coord.h"
3639
#include "core/path_coord.h"
3740
#include "core/symbols/point_symbol.h"
3841
#include "core/objects/object.h"
3942
#include "gui/util_gui.h"
43+
#include "undo/object_undo.h"
4044

4145

4246
namespace OpenOrienteering {
4347

44-
bool DistributePointsTool::showSettingsDialog(
45-
QWidget* parent,
46-
const PointSymbol* point,
47-
DistributePointsTool::Settings& settings )
48+
DistributePointsDialog::DistributePointsDialog(QWidget* parent, Map* map, const PointSymbol* point)
49+
: QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
50+
, map { map }
51+
, point { point }
52+
{
53+
setWindowTitle(tr("Distribute points evenly along path"));
54+
55+
auto layout = new QFormLayout();
56+
57+
num_points_edit = Util::SpinBox::create(1, 9999);
58+
num_points_edit->setValue(3);
59+
layout->addRow(tr("Number of points per path:"), num_points_edit);
60+
61+
points_at_ends_check = new QCheckBox(tr("Also place objects at line end points"));
62+
points_at_ends_check->setChecked(true);
63+
layout->addRow(points_at_ends_check);
64+
65+
layout->addItem(Util::SpacerItem::create(this));
66+
67+
auto rotation_headline = Util::Headline::create(tr("Rotation settings"));
68+
layout->addRow(rotation_headline);
69+
70+
rotate_symbols_check = new QCheckBox(tr("Align points with direction of line"));
71+
rotate_symbols_check->setChecked(true);
72+
layout->addRow(rotate_symbols_check);
73+
74+
additional_rotation_edit = Util::SpinBox::create<Util::RotationalDegrees>();
75+
additional_rotation_edit->setDecimals(1);
76+
additional_rotation_edit->setSingleStep(5.0);
77+
additional_rotation_edit->setValue(qRadiansToDegrees(0.0));
78+
layout->addRow(tr("Additional rotation angle (counter-clockwise):"), additional_rotation_edit);
79+
80+
if (!point->isRotatable())
81+
{
82+
rotation_headline->setEnabled(false);
83+
rotate_symbols_check->setEnabled(false);
84+
additional_rotation_edit->setEnabled(false);
85+
layout->labelForField(additional_rotation_edit)->setEnabled(false);
86+
}
87+
88+
layout->addItem(Util::SpacerItem::create(this));
89+
auto button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
90+
layout->addRow(button_box);
91+
92+
setLayout(layout);
93+
94+
connect(button_box, &QDialogButtonBox::accepted, this, &DistributePointsDialog::okClicked);
95+
connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
96+
}
97+
98+
DistributePointsDialog::~DistributePointsDialog() = default;
99+
100+
// slot
101+
void DistributePointsDialog::okClicked()
48102
{
49-
DistributePointsSettingsDialog dialog(parent, point, settings);
50-
dialog.setWindowModality(Qt::WindowModal);
51-
if (dialog.exec() == QDialog::Rejected)
52-
return false;
103+
// Create points along paths
104+
created_objects.reserve(map->selectedObjects().size() * num_points_edit->value());
105+
for (const auto* object : map->selectedObjects())
106+
{
107+
if (object->getType() == Object::Path)
108+
distributePoints(object->asPath());
109+
}
110+
if (created_objects.empty())
111+
return;
112+
113+
// Add points to map
114+
for (auto* o : created_objects)
115+
map->addObject(o);
116+
117+
// Create undo step and select new objects
118+
map->clearObjectSelection(false);
119+
MapPart* part = map->getCurrentPart();
120+
auto* delete_step = new DeleteObjectsUndoStep(map);
121+
for (std::size_t i = 0; i < created_objects.size(); ++i)
122+
{
123+
Object* object = created_objects[i];
124+
delete_step->addObject(part->findObjectIndex(object));
125+
map->addObjectToSelection(object, i == created_objects.size() - 1);
126+
}
127+
map->push(delete_step);
128+
map->setObjectsDirty();
53129

54-
dialog.getValues(settings);
55-
return true;
130+
accept();
56131
}
57132

58-
void DistributePointsTool::execute(
59-
const PathObject* path,
60-
PointSymbol* point,
61-
const DistributePointsTool::Settings& settings,
62-
std::vector<PointObject*>& out_objects )
133+
void DistributePointsDialog::distributePoints(const PathObject* path)
63134
{
135+
const auto num_points_per_line = num_points_edit->value();
136+
const auto points_at_ends = points_at_ends_check->isChecked();
137+
const auto rotate_symbols = rotate_symbols_check->isChecked();
138+
const auto additional_rotation = qDegreesToRadians(additional_rotation_edit->value());
139+
64140
path->update();
65141

66142
// This places the points only on the first part.
@@ -70,25 +146,25 @@ void DistributePointsTool::execute(
70146
int total, start, end;
71147
if (part.isClosed())
72148
{
73-
total = settings.num_points_per_line;
149+
total = num_points_per_line;
74150
start = 0;
75151
end = total - 1;
76152
}
77-
else if (!settings.points_at_ends)
153+
else if (!points_at_ends)
78154
{
79-
total = settings.num_points_per_line + 1;
155+
total = num_points_per_line + 1;
80156
start = 1;
81157
end = total - 1;
82158
}
83-
else if (settings.num_points_per_line == 1)
159+
else if (num_points_per_line == 1)
84160
{
85161
total = 1;
86162
start = 1;
87163
end = 1;
88164
}
89165
else
90166
{
91-
total = settings.num_points_per_line - 1;
167+
total = num_points_per_line - 1;
92168
start = 0;
93169
end = total;
94170
}
@@ -106,77 +182,17 @@ void DistributePointsTool::execute(
106182
object->setPosition(split.pos);
107183
if (point->isRotatable())
108184
{
109-
double rotation = settings.additional_rotation;
110-
if (settings.rotate_symbols)
185+
double rotation = additional_rotation;
186+
if (rotate_symbols)
111187
{
112188
auto right = split.tangentVector().perpRight();
113189
rotation -= right.angle();
114190
}
115191
object->setRotation(rotation);
116192
}
117-
out_objects.push_back(object);
193+
created_objects.push_back(object);
118194
}
119195
}
120196

121197

122-
DistributePointsSettingsDialog::DistributePointsSettingsDialog(
123-
QWidget* parent,
124-
const PointSymbol* point,
125-
const DistributePointsTool::Settings& settings )
126-
: QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
127-
{
128-
setWindowTitle(tr("Distribute points evenly along path"));
129-
130-
auto layout = new QFormLayout();
131-
132-
num_points_edit = Util::SpinBox::create(1, 9999);
133-
num_points_edit->setValue(settings.num_points_per_line);
134-
layout->addRow(tr("Number of points per path:"), num_points_edit);
135-
136-
points_at_ends_check = new QCheckBox(tr("Also place objects at line end points"));
137-
points_at_ends_check->setChecked(settings.points_at_ends);
138-
layout->addRow(points_at_ends_check);
139-
140-
layout->addItem(Util::SpacerItem::create(this));
141-
142-
auto rotation_headline = Util::Headline::create(tr("Rotation settings"));
143-
layout->addRow(rotation_headline);
144-
145-
rotate_symbols_check = new QCheckBox(tr("Align points with direction of line"));
146-
rotate_symbols_check->setChecked(settings.rotate_symbols);
147-
layout->addRow(rotate_symbols_check);
148-
149-
additional_rotation_edit = Util::SpinBox::create<Util::RotationalDegrees>();
150-
additional_rotation_edit->setDecimals(1);
151-
additional_rotation_edit->setSingleStep(5.0);
152-
additional_rotation_edit->setValue(qRadiansToDegrees(settings.additional_rotation));
153-
layout->addRow(tr("Additional rotation angle (counter-clockwise):"), additional_rotation_edit);
154-
155-
if (!point->isRotatable())
156-
{
157-
rotation_headline->setEnabled(false);
158-
rotate_symbols_check->setEnabled(false);
159-
additional_rotation_edit->setEnabled(false);
160-
layout->labelForField(additional_rotation_edit)->setEnabled(false);
161-
}
162-
163-
layout->addItem(Util::SpacerItem::create(this));
164-
auto button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal);
165-
layout->addRow(button_box);
166-
167-
setLayout(layout);
168-
169-
connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
170-
connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
171-
}
172-
173-
void DistributePointsSettingsDialog::getValues(DistributePointsTool::Settings& settings)
174-
{
175-
settings.num_points_per_line = num_points_edit->value();
176-
settings.points_at_ends = points_at_ends_check->isChecked();
177-
settings.rotate_symbols = rotate_symbols_check->isChecked();
178-
settings.additional_rotation = qDegreesToRadians(additional_rotation_edit->value());
179-
}
180-
181-
182198
} // namespace OpenOrienteering

0 commit comments

Comments
 (0)