mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-14 01:57:58 +01:00
feat(editor): in the mode of the straights the line from the end of the diverging track of a switch begins with a straight right at P4, the curvature jumping as at the start of the switch, a bend clicked getting its own curve where it was clicked; only a curve traced from P4 goes on with the curve of the switch. Dragged from a free end the shape follows the mode of laying: a straight in the one of the straights, from P4 right from its end, an arc and a straight in the one of a curve (Tab), from P4 the curve of the switch going on; the four shapes to pick under More settings and with Shift+wheel are gone, which only muddled the two ways of laying. Shift+wheel picks the way of joining over another free end. The hints, the readout by the cursor and the table of the keys say so. Selftests of P4: a straight of 100 m and of 15 m laid right from P4, bends of 8 degrees either way after a straight, dragged straight; traced and joined from P4 the curve of the switch goes on
This commit is contained in:
@@ -5530,9 +5530,9 @@ void editor_mode::render_shortcuts_window()
|
||||
{"K", "Split the selected track at the cursor, a break of the grade at the height of the ground"},
|
||||
{"L, LMB, LMB...", "Lay track: each click a bend of the straights, eased with a large curve; Enter lays them and goes on from the end"},
|
||||
{"Tab while laying", "The points clicked next go along the middle of a curve seen on the photo, the last two on the straight after it; Tab again: back to the bends"},
|
||||
{"Drag from a free end", "Lead a track out of it; onto another free end: join the two"},
|
||||
{"Drag from a free end", "Lead a track out of it: a straight, an arc and a straight where a curve is traced (Tab); onto another free end: join the two"},
|
||||
{"Ctrl+wheel", "Dragging from a free end: radius"},
|
||||
{"Shift+wheel", "Dragging from a free end: arc then straight, straight then arc, arc, straight; over another free end: another way to join"},
|
||||
{"Shift+wheel", "Dragging over another free end: another way to join"},
|
||||
{"0-9 while laying", "Type the length of the next straight, Enter puts the point"},
|
||||
{"Alt held while laying", "The direction in steps of 15 degrees, or 1:9, 1:6.6... to a straight track; the first click with Alt goes onto the axis of the track"},
|
||||
{"N", "Parallel track: LMB on a track, then the side and the spacing"},
|
||||
|
||||
@@ -1546,6 +1546,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
lay_line_plan *Plan = nullptr) const;
|
||||
// Adjoining: the curve next to a free end on a curve goes on from its curvature, where it turns its way; else from a straight there
|
||||
bool lay_line(std::vector<glm::dvec3> const &Points, std::vector<lay_mode> const &Modes, editor_track::snap_target const &End, lay_line_plan &Plan, std::string &Error, bool const Adjoining = true) const;
|
||||
// whether the points next to the start of the line, or to its end, AtEnd, a free end joined there, are clicked along a curve
|
||||
static bool traced_from(std::vector<glm::dvec3> const &Points, std::vector<lay_mode> const &Modes, bool const AtEnd);
|
||||
// the curves of a stretch traced, the ones fitted lately kept for the same points
|
||||
// none while the stretch the cursor moves along is still being fitted; Meanwhile: the fit done last of the same points but the one
|
||||
// at the cursor until then
|
||||
@@ -1673,7 +1675,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
void extend_add(int const Side);
|
||||
void render_extend_ui();
|
||||
using track_layout = editor_track::layout;
|
||||
track_layout m_track_layout{track_layout::arc_straight};
|
||||
// the shape dragged from a free end, as the mode of laying has it: a straight in the one of the straights, an arc and a straight in
|
||||
// the one of a curve
|
||||
track_layout m_track_layout{track_layout::straight};
|
||||
double m_join_radius{0.0};
|
||||
int m_join_variant{0};
|
||||
TTrack const *m_join_track{nullptr};
|
||||
@@ -1696,7 +1700,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
wheel_state m_wheel;
|
||||
int wheel_step(double const Offset, bool const Gesture);
|
||||
std::string track_shaping(bool const Joined) const;
|
||||
void render_layout_combo();
|
||||
double design_speed(TTrack const *From, TTrack const *To) const;
|
||||
// the track whose speed the design takes, none where it's the one set for the laying
|
||||
TTrack const *speed_track(TTrack const *From, TTrack const *To) const;
|
||||
|
||||
@@ -49,11 +49,19 @@ using namespace track_mode;
|
||||
namespace
|
||||
{
|
||||
|
||||
// the curve of the track of a free end the line goes on from or into: the one of a plain track always, the one of the diverging track
|
||||
// of a switch where a curve is traced from it, Traced; the bends of straights begin there with a straight, the curvature jumping as at
|
||||
// the start of the switch
|
||||
bool goes_on_curved(editor_track::snap_target const &End, bool const Traced)
|
||||
{
|
||||
return End.track != nullptr && (End.track->eType == tt_Normal || (End.track->eType == tt_Switch && Traced));
|
||||
}
|
||||
|
||||
// the curve of the track of a free end the line laid goes on from at its start, or into at its end: its radius, the side it turns to
|
||||
// as the line runs and its cant leaning into the turn; nothing on a straight
|
||||
void adjoining_curve(editor_track::snap_target const &End, bool const Atend, double const Gauge, alignment::design &Design)
|
||||
void adjoining_curve(editor_track::snap_target const &End, bool const Atend, bool const Traced, double const Gauge, alignment::design &Design)
|
||||
{
|
||||
if (End.track == nullptr || (End.track->eType != tt_Normal && End.track->eType != tt_Switch))
|
||||
if (false == goes_on_curved(End, Traced))
|
||||
return;
|
||||
auto const bend{editor_track::bend_at(*End.track, End.position)};
|
||||
if (false == bend.has_value() || std::abs(bend->curvature) < 1e-4)
|
||||
@@ -460,9 +468,10 @@ void editor_mode::point_drag_finish()
|
||||
std::optional<alignment::lay_result> editor_mode::eased_layout(TTrack const *From, glm::dvec3 const &Point, glm::dvec2 const &Direction, glm::dvec3 const &Target, double const Radius) const
|
||||
{
|
||||
m_eased_last.reset();
|
||||
// from the end of a curved track, the diverging track of a switch too, the line goes on from its curvature: a curve from it, a
|
||||
// straight after a transition out of it, never with a jump of the curvature at the end
|
||||
if (From == nullptr || (From->eType != tt_Normal && From->eType != tt_Switch))
|
||||
// from the end of a curved track the line goes on from its curvature: a curve from it, a straight after a transition out of it, never
|
||||
// with a jump of the curvature at the end; at the diverging track of a switch a curve from it, a straight right from its end, as the
|
||||
// switch goes on with a straight
|
||||
if (From == nullptr || (From->eType != tt_Normal && (From->eType != tt_Switch || m_track_layout == track_layout::straight)))
|
||||
return std::nullopt;
|
||||
auto const end{editor_track::bend_at(*From, Point)};
|
||||
if (false == end.has_value())
|
||||
@@ -784,66 +793,6 @@ void editor_mode::render_extend_ui()
|
||||
extend_add(-1);
|
||||
}
|
||||
|
||||
// the shapes laid from a free end as four tiles, each with a sketch: the end of the track, what's laid from it, the cursor
|
||||
void editor_mode::render_layout_combo()
|
||||
{
|
||||
char const *const names[]{"Arc, then straight", "Straight, then arc", "Arc through the cursor", "Straight"};
|
||||
auto const current{static_cast<int>(m_track_layout)};
|
||||
ImGui::TextDisabled("%s", STR_C("Shape from a free end"));
|
||||
auto const font{ImGui::GetFontSize()};
|
||||
auto const gap{std::round(font * 0.3f)};
|
||||
auto const width{std::floor((ImGui::GetContentRegionAvail().x - 3.0f * gap) * 0.25f)};
|
||||
auto const height{std::round(font * 2.4f)};
|
||||
auto *list{ImGui::GetWindowDrawList()};
|
||||
auto const accent{family_colour(0)};
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
ImGui::SameLine(0.0f, gap);
|
||||
ImGui::PushID(i);
|
||||
auto const top{ImGui::GetCursorScreenPos()};
|
||||
if (ImGui::InvisibleButton("##shape", ImVec2(width, height)))
|
||||
m_track_layout = static_cast<track_layout>(i);
|
||||
auto const hovered{ImGui::IsItemHovered()};
|
||||
if (hovered)
|
||||
ImGui::SetTooltip("%s\n%s", STR_C(names[i]), STR_C("While laying from a free end: Shift+wheel"));
|
||||
ImGui::PopID();
|
||||
auto const chosen{i == current};
|
||||
ImVec2 const bottom{top.x + width, top.y + height};
|
||||
auto const rounding{std::round(font * 0.35f)};
|
||||
list->AddRectFilled(top, bottom, chosen ? (accent & ~IM_COL32_A_MASK) | IM_COL32(0, 0, 0, 46) : ImGui::GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), rounding);
|
||||
list->AddRect(top, bottom, chosen ? accent : ImGui::GetColorU32(ImGuiCol_Border), rounding, 0, chosen ? 2.0f : 1.0f);
|
||||
auto const pad{std::round(font * 0.45f)};
|
||||
auto const at = [&](float const X, float const Y) { return ImVec2(top.x + pad + X * (width - 2.0f * pad), top.y + pad + Y * (height - 2.0f * pad)); };
|
||||
auto const laid{chosen ? accent : ImGui::GetColorU32(ImGuiCol_Text, 0.7f)};
|
||||
list->AddLine(at(0.0f, 0.85f), at(0.18f, 0.85f), ImGui::GetColorU32(ImGuiCol_TextDisabled), 3.0f);
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
list->AddBezierQuadratic(at(0.18f, 0.85f), at(0.4f, 0.85f), at(0.61f, 0.6f), laid, 2.0f);
|
||||
list->AddLine(at(0.61f, 0.6f), at(1.0f, 0.1f), laid, 2.0f);
|
||||
break;
|
||||
case 1:
|
||||
list->AddLine(at(0.18f, 0.85f), at(0.45f, 0.85f), laid, 2.0f);
|
||||
list->AddBezierQuadratic(at(0.45f, 0.85f), at(0.85f, 0.85f), at(1.0f, 0.1f), laid, 2.0f);
|
||||
break;
|
||||
case 2: list->AddBezierQuadratic(at(0.18f, 0.85f), at(0.7f, 0.85f), at(1.0f, 0.1f), laid, 2.0f); break;
|
||||
default:
|
||||
list->AddLine(at(0.18f, 0.85f), at(1.0f, 0.85f), laid, 2.0f);
|
||||
for (float y{0.15f}; y < 0.8f; y += 0.2f)
|
||||
list->AddLine(at(1.0f, y), at(1.0f, y + 0.1f), IM_COL32(255, 210, 60, 160), 1.0f);
|
||||
break;
|
||||
}
|
||||
list->AddCircleFilled(at(0.18f, 0.85f), 2.5f, IM_COL32(230, 80, 230, 255));
|
||||
auto const cursor{at(1.0f, 0.1f)};
|
||||
list->AddLine(ImVec2(cursor.x - 4.0f, cursor.y), ImVec2(cursor.x + 4.0f, cursor.y), IM_COL32(255, 210, 60, 255), 1.5f);
|
||||
list->AddLine(ImVec2(cursor.x, cursor.y - 4.0f), ImVec2(cursor.x, cursor.y + 4.0f), IM_COL32(255, 210, 60, 255), 1.5f);
|
||||
}
|
||||
ImGui::TextUnformatted(STR_C(names[current]));
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("%s", STR_C("(Shift+wheel)"));
|
||||
}
|
||||
|
||||
int editor_mode::wheel_step(double const Offset, bool const Gesture)
|
||||
{
|
||||
auto const &io{ImGui::GetIO()};
|
||||
@@ -944,8 +893,6 @@ bool editor_mode::track_wheel(double const Offset)
|
||||
}
|
||||
if (joined)
|
||||
m_join_variant += step;
|
||||
else
|
||||
m_track_layout = static_cast<track_layout>((static_cast<int>(m_track_layout) + 4 - step) % 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1002,10 +949,11 @@ std::vector<segment_data> editor_mode::lay_pieces(std::vector<glm::dvec3> const
|
||||
};
|
||||
std::vector<segment_data> pieces;
|
||||
// the curvature of the track laid has to go on from the one of the track it joins, a jump gets a transition curve between them; at
|
||||
// the end of the diverging track of a switch as well, the curve of the switch going on
|
||||
// the end of the diverging track of a switch where a curve is traced from it, the curve of the switch going on, the bends of
|
||||
// straights beginning there with a straight
|
||||
auto const grade{(Points.back().y - Points.front().y) / std::max(1.0, plan_distance(Points.front(), Points.back()))};
|
||||
auto const eased = [&](editor_track::snap_target const &Joint, double const Chainage, double const Sign) {
|
||||
if (Joint.track == nullptr || (Joint.track->eType != tt_Normal && Joint.track->eType != tt_Switch))
|
||||
if (false == goes_on_curved(Joint, traced_from(Points, Modes, Sign < 0.0)))
|
||||
return editor_track::easing{};
|
||||
auto result{editor_track::ease_out_of(*Joint.track, Joint.position, grade * Sign, design.speed, design.norms)};
|
||||
auto const own{Sign * curvature_at(shape, Chainage)};
|
||||
@@ -1095,6 +1043,14 @@ std::vector<segment_data> editor_mode::lay_pieces(std::vector<glm::dvec3> const
|
||||
return pieces;
|
||||
}
|
||||
|
||||
bool editor_mode::traced_from(std::vector<glm::dvec3> const &Points, std::vector<lay_mode> const &Modes, bool const AtEnd)
|
||||
{
|
||||
if (Points.size() < 3)
|
||||
return false;
|
||||
auto const index{AtEnd ? Points.size() - 2 : std::size_t{1}};
|
||||
return index < Modes.size() && Modes[index] == lay_mode::curve;
|
||||
}
|
||||
|
||||
bool editor_mode::lay_line(std::vector<glm::dvec3> const &Points, std::vector<lay_mode> const &Modes, editor_track::snap_target const &End, lay_line_plan &Plan, std::string &Error, bool const Adjoining) const
|
||||
{
|
||||
auto const &tool{m_lay};
|
||||
@@ -1107,13 +1063,13 @@ bool editor_mode::lay_line(std::vector<glm::dvec3> const &Points, std::vector<la
|
||||
auto const joined{End.track != nullptr && glm::length(plan_of(End.direction)) > 1e-6};
|
||||
// from a free end on a curve, or to one, the curve laid next to it turning its way goes on from its curvature: it begins right at the
|
||||
// end, not on a straight, its transition going from that curvature. Where no such curve fits, the line is laid from a straight there,
|
||||
// which lay_pieces eases out of the curve
|
||||
// which lay_pieces eases out of the curve. At a switch only a curve traced from it, the bends of straights from a straight there
|
||||
if (Adjoining)
|
||||
{
|
||||
if (tool.start.track != nullptr && glm::length(plan_of(tool.start.direction)) > 1e-6)
|
||||
adjoining_curve(tool.start, false, design.norms.gauge, design);
|
||||
adjoining_curve(tool.start, false, traced_from(Points, Modes, false), design.norms.gauge, design);
|
||||
if (joined)
|
||||
adjoining_curve(End, true, design.norms.gauge, design);
|
||||
adjoining_curve(End, true, traced_from(Points, Modes, true), design.norms.gauge, design);
|
||||
}
|
||||
auto const curved{design.start_curved || design.end_curved};
|
||||
auto const from_straight = [&]() { return curved && lay_line(Points, Modes, End, Plan, Error, false); };
|
||||
@@ -1505,6 +1461,7 @@ void editor_mode::lay_switch_mode()
|
||||
{
|
||||
auto &tool{m_lay};
|
||||
tool.mode = tool.mode == lay_mode::straights ? lay_mode::curve : lay_mode::straights;
|
||||
m_track_layout = tool.mode == lay_mode::curve ? track_layout::arc_straight : track_layout::straight;
|
||||
if (tool.mode == lay_mode::curve)
|
||||
first_step_done(first_step::trace);
|
||||
tool.status = tool.mode == lay_mode::curve ? STR("Curve: click points along the middle of the track, the last two on the straight after the curve. Tab: back to the straights")
|
||||
@@ -2010,7 +1967,6 @@ void editor_mode::render_lay_ui()
|
||||
value_chips("radii", tool.radius, {190.0, 300.0, 500.0, 800.0, 1200.0, 2000.0}, "%.0f");
|
||||
tool.radius = std::max(10.0, tool.radius);
|
||||
ImGui::PopItemWidth();
|
||||
render_layout_combo();
|
||||
ImGui::Spacing();
|
||||
ImGui::PushItemWidth(120.0f);
|
||||
ImGui::DragScalar(STR_C("Longest path (m)"), ImGuiDataType_Double, &tool.piece_length, 1.0f, nullptr, nullptr, "%.0f");
|
||||
|
||||
@@ -1690,8 +1690,10 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
|
||||
else
|
||||
{
|
||||
hints = {{"LMB", curve ? "a point along the middle of the curve, the last two on the straight after it" : "a bend of the straights, eased with a large curve"}, {"LMB on a free end", "join and lay"}, {"Tab", tab}};
|
||||
if (m_lay.mouse_snap.track != nullptr)
|
||||
if (m_lay.mouse_snap.track != nullptr && m_lay.start.track != nullptr)
|
||||
hints.insert(hints.end(), {{"Ctrl+wheel", "radius"}, {"Shift+wheel", "another shape"}});
|
||||
else if (m_lay.mouse_snap.track != nullptr && curve)
|
||||
hints.push_back({"Ctrl+wheel", "radius"});
|
||||
hints.insert(hints.end(), {{"Alt", "the direction in steps of 15 degrees, or 1:9, 1:6.6... to a straight track"}, {"Enter", "stop laying"},
|
||||
{"Backspace", m_lay.chain.empty() ? "take back the point" : "take back the last piece"}, {"Esc", "stop laying"}});
|
||||
}
|
||||
@@ -1703,7 +1705,14 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
|
||||
hints = {{m_straights.tool == 2 ? "LMB" : "Shift+click", format(STR_C("point %zu of 4: %s"), step + 1, STR_C(steps[step]))}, {"Esc", "cancel"}};
|
||||
}
|
||||
else if (m_extend.active)
|
||||
hints = {{"Drag", "lays the shape to the cursor, to a free end: joins it"}, {"Ctrl+wheel", "radius"}, {"Shift+wheel", "another shape"}, {"Release", "build"}, {"Esc", "cancel"}};
|
||||
{
|
||||
hints = {{"Drag", "lays the shape to the cursor, to a free end: joins it"}};
|
||||
if (editor_track::snap_target target; extend_snap(target))
|
||||
hints.insert(hints.end(), {{"Ctrl+wheel", "radius"}, {"Shift+wheel", "another shape"}});
|
||||
else if (m_track_layout != track_layout::straight)
|
||||
hints.push_back({"Ctrl+wheel", "radius"});
|
||||
hints.insert(hints.end(), {{"Release", "build"}, {"Esc", "cancel"}});
|
||||
}
|
||||
else if (m_switch.placing)
|
||||
hints = m_switch.connection >= 0 && false == m_switch.curved ?
|
||||
std::vector<key_hint>{{"Drag onto the other track", "the connection there"}, {"Shift+wheel", "another kind"}, {"Ctrl+wheel", "R of the aligning curve"}, {"Alt+wheel", "where a double crossover meets"}, {"Esc", "cancel"}} :
|
||||
@@ -2092,7 +2101,9 @@ std::string editor_mode::track_shaping(bool const Joined) const
|
||||
auto text{std::string{STR_C(names[static_cast<int>(m_track_layout)])}};
|
||||
if (m_track_layout == track_layout::arc_straight || m_track_layout == track_layout::straight_arc)
|
||||
text += format(" R %.0f m", m_lay.radius);
|
||||
return text + "\n" + STR("Ctrl+wheel: radius, Shift+wheel: arc / straight") + STR(", Ctrl+Shift+wheel: speed");
|
||||
// the shape follows the mode of laying, Tab switching it where the laying goes on
|
||||
return text + "\n" + (m_track_layout == track_layout::straight ? STR("Tab while laying: an arc, then a straight") : STR("Ctrl+wheel: radius, Tab while laying: a straight")) +
|
||||
STR(", Ctrl+Shift+wheel: speed");
|
||||
}
|
||||
auto const &join{m_join_last};
|
||||
char const *const kinds[]{"", "straight", "arc", "curve", "reverse curve", "free curve"};
|
||||
|
||||
@@ -621,7 +621,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
intent.track = lay.mouse_snap.track;
|
||||
intent.position = lay.mouse_snap.position;
|
||||
auto const diverging{lay.mouse_snap.track->eType == tt_Switch && lay.mouse_snap.point == editor_track::point_ref{1, editor_track::point_kind::end}};
|
||||
if (lay.points.empty() && diverging)
|
||||
if (lay.points.empty() && diverging && m_track_layout != track_layout::straight)
|
||||
return make(kind::lay_end, "Click: start from this free end, drag: the curve of the switch goes on");
|
||||
return make(kind::lay_end, lay.points.empty() ? "Click: start from this free end, drag: lead a track out of it" : "Click: join this end and lay");
|
||||
}
|
||||
@@ -732,7 +732,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
intent.snap.track = selected;
|
||||
intent.snap.point = hit;
|
||||
intent.snap.position = intent.position;
|
||||
auto const diverging{selected->eType == tt_Switch && hit == editor_track::point_ref{1, editor_track::point_kind::end}};
|
||||
auto const diverging{selected->eType == tt_Switch && hit == editor_track::point_ref{1, editor_track::point_kind::end} && m_track_layout != track_layout::straight};
|
||||
return make(kind::extend_end, diverging ? "Drag: the curve of the switch goes on; Ctrl+drag: move the end" : "Drag: a new track out of this end, as in laying; Ctrl+drag: move the end");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12285,3 +12285,15 @@ msgstr "Wstrzymaj"
|
||||
|
||||
msgid "Terrain model: %d of %d squares in the cache, %d failed"
|
||||
msgstr "Model terenu: %d z %d kwadratów w pamięci podręcznej, nieudanych %d"
|
||||
|
||||
msgid "Tab while laying: an arc, then a straight"
|
||||
msgstr "Tab przy kładzeniu: łuk, potem prosta"
|
||||
|
||||
msgid "Ctrl+wheel: radius, Tab while laying: a straight"
|
||||
msgstr "Ctrl+kółko: promień, Tab przy kładzeniu: prosta"
|
||||
|
||||
msgid "Lead a track out of it: a straight, an arc and a straight where a curve is traced (Tab); onto another free end: join the two"
|
||||
msgstr "Wyprowadza z niego tor: prostą, a w trybie łuku (Tab) łuk i prostą; na inny wolny koniec: łączy oba"
|
||||
|
||||
msgid "Dragging over another free end: another way to join"
|
||||
msgstr "Przeciąganie nad innym wolnym końcem: inny sposób połączenia"
|
||||
|
||||
Reference in New Issue
Block a user