17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-03 22:22:04 +01:00

fix(editor): the band of the curvature edits each arc of a compound curve: its arcs, elements of an even curvature, were taken for nothing to drag, and any change went to the first radius; now the plateau of an arc changes its own radius, a ramp between two arcs the transition between them, the ends of a plateau the transitions either side of it, by a drag or the wheel, the tooltip and the value shown while dragging naming the arc. The tutorial shows the correcting of a compound curve in a clip recorded in the editor in place of the drawing: the plan of the curve opened, the plateau of R2 dragged from 138 to 174 m, the line applied to the scenery

This commit is contained in:
maj00r
2026-10-25 12:01:12 +01:00
parent cb766dabb4
commit 91900a0ead
5 changed files with 93 additions and 108 deletions

View File

@@ -1694,7 +1694,46 @@ bool editor_mode::render_route_band()
auto const mouse{ImGui::GetIO().MousePos};
auto const count{static_cast<int>(result.elements.size())};
// the element under the mouse and what of it a drag changes: near the ends of a plateau its transitions, also the ones of no length yet
// what of its vertex each element is: an arc, the arcs of a compound curve counted from the first one, which are elements of an even
// curvature as an arc is, or a transition, in from the straight, out to it, or between two arcs, which goes on from the arc before it
struct role
{
int part{0};
int arc{0};
};
std::vector<role> roles(static_cast<std::size_t>(count));
std::vector<int> arcs(design.vertices.size(), 0);
{
int vertex{-1};
int arc{-1};
double last{0.0};
for (int i = 0; i < count; ++i)
{
auto const &element{result.elements[i]};
if (element.vertex != vertex)
{
vertex = element.vertex;
arc = -1;
last = 0.0;
}
if (element.vertex < 0 || element.vertex >= static_cast<int>(design.vertices.size()) || element.kind == alignment::element_kind::straight)
continue;
auto const [from, to]{ends(element)};
if (element.kind == alignment::element_kind::arc || (std::abs(from - to) <= 1e-6 * std::abs(from) && std::abs(from) > 1e-9))
{
// the next arc where the curvature isn't the one of the arc before, an arc cut in parts staying one
if (arc < 0 || std::abs(std::abs(from) - last) > 1e-6 * std::abs(from))
++arc;
last = std::abs(from);
roles[i] = {1, arc};
arcs[element.vertex] = std::max(arcs[element.vertex], arc + 1);
}
else
roles[i] = std::abs(from) <= 1e-9 ? role{2, 0} : std::abs(to) <= 1e-9 ? role{3, 0} : role{4, arc + 1};
}
}
// the element under the mouse and what of it a drag changes: near the ends of a plateau the transitions either side of it, also the
// ones of no length yet
int under{-1};
int part{0};
if (hovered && false == dragging)
@@ -1702,27 +1741,38 @@ bool editor_mode::render_route_band()
for (int i = 0; i < count; ++i)
{
auto const &element{result.elements[i]};
int arc{0};
if (mouse.x < x_of(element.chainage) || mouse.x >= x_of(element.chainage + element.length))
continue;
under = i;
auto const from{x_of(element.chainage)};
auto const to{x_of(element.chainage + element.length)};
auto const edge{std::min(std::round(font * 0.5f), (to - from) * 0.25f)};
switch (element.kind)
part = roles[i].part;
arc = roles[i].arc;
if (part == 1)
{
case alignment::element_kind::arc: part = mouse.x < from + edge ? 2 : mouse.x >= to - edge ? 3 : 1; break;
case alignment::element_kind::transition_in: part = 2; break;
case alignment::element_kind::transition_out: part = 3; break;
default: break;
auto const from{x_of(element.chainage)};
auto const to{x_of(element.chainage + element.length)};
auto const edge{std::min(std::round(font * 0.5f), (to - from) * 0.25f)};
if (mouse.x < from + edge)
part = arc == 0 ? 2 : 4;
else if (mouse.x >= to - edge)
{
part = arc + 1 >= arcs[element.vertex] ? 3 : 4;
arc += 1;
}
}
if (element.vertex < 0 || element.vertex >= static_cast<int>(design.vertices.size()))
part = 0;
break;
}
}
auto const value_of = [&](int const Vertex, int const Part) -> double & {
auto const value_of = [&](int const Vertex, int const Part, int const Arc) -> double & {
auto &vertex{design.vertices[Vertex]};
return Part == 1 ? vertex.radius : Part == 2 ? vertex.transition_in : vertex.transition_out;
auto const later{Arc >= 1 && Arc <= static_cast<int>(vertex.arcs.size())};
switch (Part)
{
case 1: return later ? vertex.arcs[Arc - 1].radius : vertex.radius;
case 2: return vertex.transition_in;
case 3: return vertex.transition_out;
default: return later ? vertex.arcs[Arc - 1].transition : vertex.transition_in;
}
};
auto const rounded_radius = [](double const Radius) {
auto const step{Radius < 1000.0 ? 1.0 : 10.0};
@@ -1733,14 +1783,15 @@ bool editor_mode::render_route_band()
{
band.vertex = result.elements[under].vertex;
band.part = part;
band.value = value_of(band.vertex, part);
band.arc = arc;
band.value = value_of(band.vertex, part, arc);
band.press = mouse;
band.metres = metres;
band.curvature = curvature;
}
if (band.vertex >= 0 && band.vertex < static_cast<int>(design.vertices.size()) && active)
{
auto &value{value_of(band.vertex, band.part)};
auto &value{value_of(band.vertex, band.part, band.arc)};
double wanted{value};
if (band.part == 1)
{
@@ -1759,6 +1810,7 @@ bool editor_mode::render_route_band()
}
if (wanted != value)
{
// the transition in grows to the left, from where it starts; the others to the right
value = wanted;
changed = true;
}
@@ -1773,7 +1825,7 @@ bool editor_mode::render_route_band()
ImGui::SetMouseCursor(part == 1 ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW);
if (auto const wheel{ImGui::GetIO().MouseWheel}; wheel != 0.0f)
{
auto &value{value_of(result.elements[under].vertex, part)};
auto &value{value_of(result.elements[under].vertex, part, arc)};
value = part == 1 ? rounded_radius(value * (wheel > 0.0f ? 0.95 : 1.0 / 0.95)) : std::max(0.0, std::round(value / 5.0) * 5.0 + (wheel > 0.0f ? 5.0 : -5.0));
changed = true;
}
@@ -1862,8 +1914,8 @@ bool editor_mode::render_route_band()
}
if (dragging && band.vertex >= 0 && band.vertex < static_cast<int>(design.vertices.size()))
{
auto const &vertex{design.vertices[band.vertex]};
auto const text{band.part == 1 ? format("R %.0f m", vertex.radius) : format("%.0f m", band.part == 2 ? vertex.transition_in : vertex.transition_out)};
auto const value{value_of(band.vertex, band.part, band.arc)};
auto const text{band.part == 1 ? format("R %.0f m", value) : format("%.0f m", value)};
auto const size{ImGui::CalcTextSize(text.c_str())};
ImVec2 const at{std::clamp(mouse.x + pad, top.x, bottom.x - size.x - pad), std::clamp(mouse.y - size.y - pad, top.y, bottom.y - size.y)};
list->AddRectFilled(ImVec2(at.x - 3.0f, at.y - 1.0f), ImVec2(at.x + size.x + 3.0f, at.y + size.y + 1.0f), IM_COL32(0, 0, 0, 170), 3.0f);
@@ -1875,12 +1927,18 @@ bool editor_mode::render_route_band()
if (part != 0 && false == dragging && ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
{
auto const &vertex{design.vertices[result.elements[under].vertex]};
auto const index{result.elements[under].vertex};
auto const &vertex{design.vertices[index]};
auto const value{value_of(index, part, arc)};
ImGui::BeginTooltip();
if (part == 1)
ImGui::Text(STR_C("Curve %d: R %.0f m, cant %.0f mm"), result.elements[under].vertex + 1, vertex.radius, vertex.cant);
if (part == 1 && arcs[index] > 1)
ImGui::Text(STR_C("Curve %d, arc R%d: %.0f m"), index + 1, arc + 1, value);
else if (part == 1)
ImGui::Text(STR_C("Curve %d: R %.0f m, cant %.0f mm"), index + 1, value, vertex.cant);
else if (part == 4)
ImGui::Text(STR_C("Curve %d, transition between R%d and R%d: %.0f m"), index + 1, arc, arc + 1, value);
else
ImGui::Text(part == 2 ? STR_C("Transition into curve %d: %.0f m") : STR_C("Transition out of curve %d: %.0f m"), result.elements[under].vertex + 1, part == 2 ? vertex.transition_in : vertex.transition_out);
ImGui::Text(part == 2 ? STR_C("Transition into curve %d: %.0f m") : STR_C("Transition out of curve %d: %.0f m"), index + 1, value);
gesture_rows({{"Drag", part == 1 ? "up or down: the radius" : "sideways: the length"}, {"Wheel", part == 1 ? "the radius by 5%" : "the length by 5 m"}});
ImGui::EndTooltip();
}