17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-19 21:44:58 +02:00

feat(editor): track gizmo turns, lengthens and edits the control vectors, joined tracks keep the tangent

W turns the track (about its middle or the selected end) and a selection of tracks, the joined tracks follow.
E lengthens the track at its free end: a straight stays straight, an arc keeps its radius, cant and grade.
The gizmo on a control point moves, turns or lengthens the vector; the control point of the track joined
there turns with it, at a switch the vector only slides along the switch. Straight neighbours dragged along
keep their tangents and become straight again when nothing bent them.
This commit is contained in:
maj00r
2026-10-11 12:59:55 +02:00
parent 2beae15390
commit 89678ead3e
8 changed files with 782 additions and 99 deletions

View File

@@ -1281,6 +1281,79 @@ void editor_mode::render_track_set_ui()
ImGui::Separator();
}
bool editor_mode::track_set_begin(bool const Rotate)
{
std::string reason;
if (false == tracks_editable(m_track_set, reason))
{
ui()->set_status(reason, true);
return false;
}
m_track_set_using = true;
m_track_gizmo_drag = {};
m_track_gizmo_drag.operation = Rotate ? gizmo_operation::rotate : gizmo_operation::translate;
m_track_drag = m_track_set;
m_track_set_joints.clear();
for (auto *track : m_track_set)
{
auto joints{editor_track::joints(*track)};
joints.erase(std::remove_if(joints.begin(), joints.end(), [&](editor_track::joint const &Joint) { return in_track_set(Joint.other); }), joints.end());
for (auto const &joint : joints)
if (std::find(m_track_drag.begin(), m_track_drag.end(), joint.other) == m_track_drag.end())
m_track_drag.push_back(joint.other);
m_track_set_joints.emplace_back(track, std::move(joints));
}
std::vector<std::pair<TTrack *, editor_track::state>> states;
for (auto *track : m_track_drag)
states.emplace_back(track, editor_track::capture(*track));
push_track_snapshot(std::move(states));
track_gizmo_hold();
return true;
}
void editor_mode::track_set_turn(double const Angle)
{
auto &drag{m_track_gizmo_drag};
auto const step{std::remainder(Angle - drag.angle, 2.0 * glm::pi<double>())};
if (std::abs(step) < 1e-9)
return;
drag.angle += step;
for (auto &entry : m_track_set_joints)
editor_track::rotate_y(*entry.first, m_track_set_pivot, step);
for (auto &entry : m_track_set_joints)
editor_track::follow(*entry.first, entry.second);
m_track_dirty = true;
}
void editor_mode::track_set_move(glm::dvec3 const &Offset)
{
for (auto &entry : m_track_set_joints)
{
editor_track::translate(*entry.first, Offset);
editor_track::follow(*entry.first, entry.second);
}
m_track_dirty = true;
}
void editor_mode::track_set_end()
{
track_gizmo_settle();
m_track_dirty = true;
commit_track_drag(true);
m_track_set_using = false;
m_track_drag.clear();
m_track_set_joints.clear();
straight_refresh();
}
glm::dvec3 editor_mode::track_set_centre() const
{
glm::dvec3 centre{0.0};
for (auto const *track : m_track_set)
centre += editor_track::pivot(*track);
return m_track_set.empty() ? centre : centre / static_cast<double>(m_track_set.size());
}
void editor_mode::render_track_set_gizmo()
{
track_set_prune();
@@ -1292,61 +1365,24 @@ void editor_mode::render_track_set_gizmo()
gizmo_frame const frame;
if (false == m_track_set_using)
{
glm::dvec3 centre{0.0};
for (auto const *track : m_track_set)
centre += editor_track::pivot(*track);
m_track_set_pivot = centre / static_cast<double>(m_track_set.size());
m_track_set_pivot = track_set_centre();
m_track_set_gizmo = glm::translate(glm::mat4(1.0f), glm::vec3(m_track_set_pivot - frame.camera));
}
auto const rotate{m_track_set_using ? m_track_gizmo_drag.operation == gizmo_operation::rotate : m_gizmo_op == gizmo_operation::rotate};
glm::mat4 delta(1.0f);
frame.manipulate(ImGuizmo::TRANSLATE, m_track_set_gizmo, m_gizmo_snap, &delta);
frame.manipulate(rotate ? ImGuizmo::ROTATE_Y : ImGuizmo::TRANSLATE, m_track_set_gizmo, rotate ? 5.0f : m_gizmo_snap, &delta);
if (ImGuizmo::IsUsing())
{
if (false == m_track_set_using)
{
std::string reason;
if (false == tracks_editable(m_track_set, reason))
{
ui()->set_status(reason, true);
return;
}
m_track_set_using = true;
m_track_drag = m_track_set;
m_track_set_joints.clear();
for (auto *track : m_track_set)
{
auto joints{editor_track::joints(*track)};
joints.erase(std::remove_if(joints.begin(), joints.end(), [&](editor_track::joint const &Joint) { return in_track_set(Joint.other); }), joints.end());
for (auto const &joint : joints)
if (std::find(m_track_drag.begin(), m_track_drag.end(), joint.other) == m_track_drag.end())
m_track_drag.push_back(joint.other);
m_track_set_joints.emplace_back(track, std::move(joints));
}
std::vector<std::pair<TTrack *, editor_track::state>> states;
for (auto *track : m_track_drag)
states.emplace_back(track, editor_track::capture(*track));
push_track_snapshot(std::move(states));
}
glm::dvec3 const offset{delta[3]};
if (glm::length(offset) > 1e-9)
{
for (auto &entry : m_track_set_joints)
{
editor_track::translate(*entry.first, offset);
editor_track::follow(*entry.first, entry.second);
}
m_track_dirty = true;
}
if (false == m_track_set_using && false == track_set_begin(rotate))
return;
if (rotate)
track_set_turn(std::atan2(static_cast<double>(m_track_set_gizmo[2][0]), static_cast<double>(m_track_set_gizmo[0][0])));
else if (glm::dvec3 const offset{delta[3]}; glm::length(offset) > 1e-9)
track_set_move(offset);
commit_track_drag(false);
}
else if (m_track_set_using)
{
commit_track_drag(true);
m_track_set_using = false;
m_track_drag.clear();
m_track_set_joints.clear();
straight_refresh();
}
track_set_end();
}
void editor_mode::render_lineside_ui()