mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-03 01:30:16 +01:00
feat(editor): a switch laid with no track there, and no switch laid by a click: a press on the ground with a switch armed lays the switch there, its start where it was pressed, the direction of its main track taken from the drag once it's 4 m long and held, the drag sideways then giving the side of the diverging track, back by the start the direction free again; pressed by a free end within 5 m it goes on from that end in its direction and grade, joined to it. Its ends are left free to lay on from, styled after the track it goes on from or as the lay tool lays its tracks (editor_track::create_switch with a path_style). A press let go within 10 pixels places no switch, a slip at a crossing included, which was laid at once on the press: it's laid once dragged, its straights shown meanwhile. The hints and the panel tell of both. Selftest switchfree: Rz 60E1-300-1:9 on the ground with its four ends free, from the free end of a straight joined and walked through; a click on a straight laid none, a drag laid z1
This commit is contained in:
@@ -49,6 +49,8 @@ std::vector<segment_data> editor_mode::switch_preview() const
|
||||
auto const &tool{m_switch};
|
||||
if (false == tool.placing || tool.armed < 0 || tool.armed >= static_cast<int>(tool.templates.size()))
|
||||
return {};
|
||||
if (tool.free)
|
||||
return free_switch_paths();
|
||||
if (tool.curved)
|
||||
{
|
||||
int forward;
|
||||
@@ -56,6 +58,20 @@ std::vector<segment_data> editor_mode::switch_preview() const
|
||||
curved_switch_pose(forward, side);
|
||||
return curved_switch_paths(tool.templates[tool.armed], tool.frame, curved_switch_start(forward), forward, side);
|
||||
}
|
||||
if (tool.templates[tool.armed].double_slip)
|
||||
{
|
||||
// a slip at the crossing where it was pressed: its two straights, laid there once dragged
|
||||
slip_plan plan;
|
||||
if (false == plan_double_slip(tool.line, tool.point, tool.templates[tool.armed], plan) || plan.replaces != nullptr)
|
||||
return {};
|
||||
auto const straight = [](glm::dvec3 const &From, glm::dvec3 const &To) {
|
||||
segment_data path;
|
||||
path.points[segment_data::point::start] = From;
|
||||
path.points[segment_data::point::end] = To;
|
||||
return path;
|
||||
};
|
||||
return {straight(plan.points[0], plan.points[1]), straight(plan.points[2], plan.points[3])};
|
||||
}
|
||||
if (switch_link plan; plan_switch_link(plan))
|
||||
{
|
||||
plan.paths.insert(plan.paths.end(), plan.link.pieces.begin(), plan.link.pieces.end());
|
||||
@@ -80,6 +96,7 @@ bool editor_mode::start_switch_placement()
|
||||
return false;
|
||||
glm::dvec3 const ground{cursor_level(selected->m_paths.front().points[segment_data::point::start].y)};
|
||||
tool.curved = false;
|
||||
tool.free = false;
|
||||
tool.status.clear();
|
||||
if (current_straight().tracks.empty())
|
||||
{
|
||||
@@ -141,7 +158,12 @@ bool editor_mode::start_switch_placement()
|
||||
return false;
|
||||
if (tool.templates[tool.armed].double_slip)
|
||||
{
|
||||
insert_double_slip(line, cursor, tool.templates[tool.armed]);
|
||||
// at the crossing where it was pressed, laid only once dragged, as a switch is
|
||||
tool.along = along;
|
||||
tool.point = cursor;
|
||||
tool.mouse = cursor;
|
||||
tool.line = line;
|
||||
tool.placing = true;
|
||||
return true;
|
||||
}
|
||||
tool.along = along;
|
||||
@@ -155,6 +177,12 @@ bool editor_mode::start_switch_placement()
|
||||
void editor_mode::finish_switch_placement()
|
||||
{
|
||||
auto &tool{m_switch};
|
||||
if (tool.free)
|
||||
{
|
||||
tool.placing = false;
|
||||
insert_free_switch();
|
||||
return;
|
||||
}
|
||||
if (tool.connection >= 0)
|
||||
{
|
||||
if (false == tool.curved)
|
||||
@@ -170,6 +198,11 @@ void editor_mode::finish_switch_placement()
|
||||
tool.placing = false;
|
||||
if (tool.armed < 0 || tool.armed >= static_cast<int>(tool.templates.size()))
|
||||
return;
|
||||
if (tool.templates[tool.armed].double_slip && false == tool.curved)
|
||||
{
|
||||
insert_double_slip(tool.line, tool.point, tool.templates[tool.armed]);
|
||||
return;
|
||||
}
|
||||
if (linked)
|
||||
{
|
||||
insert_linked_switch(plan);
|
||||
@@ -207,6 +240,98 @@ void editor_mode::insert_switch(editor_track::straight const &Line, double const
|
||||
}
|
||||
|
||||
|
||||
bool editor_mode::free_switch_offered() const
|
||||
{
|
||||
auto const &tool{m_switch};
|
||||
return m_track_tab == track_tab::turnout && tool.connection < 0 && tool.armed >= 0 && tool.armed < static_cast<int>(tool.templates.size()) && false == tool.templates[tool.armed].double_slip;
|
||||
}
|
||||
|
||||
editor_track::snap_target editor_mode::free_switch_end(glm::dvec3 const &Ground) const
|
||||
{
|
||||
return editor_track::find_free_end(nullptr, kRailCategory, Ground, kLaySnapRadius, {});
|
||||
}
|
||||
|
||||
void editor_mode::start_free_switch(glm::dvec3 const &Ground)
|
||||
{
|
||||
auto &tool{m_switch};
|
||||
if (false == free_switch_offered())
|
||||
return;
|
||||
tool.status.clear();
|
||||
tool.curved = false;
|
||||
tool.line = {};
|
||||
tool.free = true;
|
||||
tool.free_end = free_switch_end(Ground);
|
||||
tool.free_heading.reset();
|
||||
if (tool.free_end.track != nullptr)
|
||||
{
|
||||
// going on from the free end in its direction
|
||||
auto const outward{plan_of(-tool.free_end.direction)};
|
||||
if (glm::length(outward) > 1e-9)
|
||||
tool.free_heading = glm::normalize(outward);
|
||||
tool.point = tool.free_end.position;
|
||||
}
|
||||
else
|
||||
tool.point = lay_bed(Ground);
|
||||
tool.mouse = tool.point;
|
||||
tool.placing = true;
|
||||
}
|
||||
|
||||
void editor_mode::free_switch_pose(glm::dvec3 &Start, glm::dvec2 &Heading, int &Side, double &Grade) const
|
||||
{
|
||||
auto const &tool{m_switch};
|
||||
Start = tool.point;
|
||||
glm::dvec2 const offset{plan_of(tool.mouse - tool.point)};
|
||||
// till the drag is long enough to take the direction from, it follows the cursor, the diverging track to the left
|
||||
Heading = tool.free_heading.value_or(glm::length(offset) > 1e-6 ? glm::normalize(offset) : glm::dvec2{0.0, 1.0});
|
||||
Side = cross(Heading, offset) >= 0.0 ? 1 : -1;
|
||||
Grade = 0.0;
|
||||
if (tool.free_end.track != nullptr)
|
||||
{
|
||||
// the grade of the track it goes on from
|
||||
auto const &into{tool.free_end.direction};
|
||||
auto const run{glm::length(plan_of(into))};
|
||||
Grade = run > 1e-9 ? -into.y / run : 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<segment_data> editor_mode::free_switch_paths() const
|
||||
{
|
||||
auto const &tool{m_switch};
|
||||
if (tool.armed < 0 || tool.armed >= static_cast<int>(tool.templates.size()))
|
||||
return {};
|
||||
glm::dvec3 start;
|
||||
glm::dvec2 heading;
|
||||
int side;
|
||||
double grade;
|
||||
free_switch_pose(start, heading, side, grade);
|
||||
return editor_track::place_switch(tool.templates[tool.armed], start, heading, side, grade);
|
||||
}
|
||||
|
||||
void editor_mode::insert_free_switch()
|
||||
{
|
||||
auto &tool{m_switch};
|
||||
tool.free = false;
|
||||
// a click with no drag on the ground gives no direction; from a free end it's the end's
|
||||
if (tool.free_end.track == nullptr && false == tool.free_heading.has_value())
|
||||
{
|
||||
tool.status = refused(STR_C("Drag along the main track of the switch, then sideways to the side of the diverging one"));
|
||||
return;
|
||||
}
|
||||
auto const paths{free_switch_paths()};
|
||||
if (paths.size() < 2)
|
||||
return;
|
||||
auto const made{create_switch_set(tool.templates[tool.armed], paths, tool.free_end.track, switch_name_for_new())};
|
||||
if (made.empty())
|
||||
return;
|
||||
push_track_snapshot({}, made, {});
|
||||
straight_refresh();
|
||||
switch_placed(made);
|
||||
auto const text{tool.free_end.track != nullptr ? format(STR_C("Switch %s laid on from %s, its other ends free: lay on from them"), made.front()->name().c_str(), tool.free_end.track->name().c_str())
|
||||
: format(STR_C("Switch %s laid with no track, its ends free: lay on from them"), made.front()->name().c_str())};
|
||||
tool.status = text + (tool.status.empty() ? std::string{} : "\n" + tool.status);
|
||||
ui()->set_status(tool.status, false);
|
||||
}
|
||||
|
||||
void editor_mode::switch_placed(std::vector<TTrack *> const &Created)
|
||||
{
|
||||
auto const found{std::find_if(Created.begin(), Created.end(), [](TTrack const *Track) { return Track != nullptr && Track->eType == tt_Switch; })};
|
||||
@@ -424,15 +549,24 @@ bool editor_mode::place_switch_on_straight(editor_track::straight const &Line, e
|
||||
|
||||
std::vector<TTrack *> editor_mode::create_switch_set(editor_track::switch_template const &Shape, std::vector<segment_data> const &Paths, TTrack const &Style, std::string const &Name)
|
||||
{
|
||||
return create_switch_set(Shape, Paths, &Style, Name);
|
||||
}
|
||||
|
||||
std::vector<TTrack *> editor_mode::create_switch_set(editor_track::switch_template const &Shape, std::vector<segment_data> const &Paths, TTrack const *Style, std::string const &Name)
|
||||
{
|
||||
// with no track to copy, styled as the lay tool lays its tracks
|
||||
auto const switch_of = [&](editor_track::switch_template const &Template, std::vector<segment_data> const &Each, std::string const &Named) {
|
||||
return Style != nullptr ? editor_track::create_switch(Template, Each, *Style, Named) : editor_track::create_switch(Template, Each, m_lay.style, Named);
|
||||
};
|
||||
if (Shape.twofold() && Paths.size() >= 5)
|
||||
{
|
||||
auto firstshape{Shape};
|
||||
firstshape.length = glm::distance(Paths[0].points[segment_data::point::start], Paths[0].points[segment_data::point::end]);
|
||||
auto secondshape{Shape};
|
||||
secondshape.length = Shape.length - Shape.stagger;
|
||||
auto *one{editor_track::create_switch(firstshape, Paths, Style, Name)};
|
||||
auto *two{one != nullptr ? editor_track::create_switch(secondshape, {Paths[2], Paths[3]}, Style, Name + "b") : nullptr};
|
||||
auto *link{two != nullptr ? editor_track::create_path(Style, Paths[4]) : nullptr};
|
||||
auto *one{switch_of(firstshape, Paths, Name)};
|
||||
auto *two{one != nullptr ? switch_of(secondshape, {Paths[2], Paths[3]}, Name + "b") : nullptr};
|
||||
auto *link{two == nullptr ? nullptr : Style != nullptr ? editor_track::create_path(*Style, Paths[4]) : editor_track::create_path(m_lay.style, Paths[4])};
|
||||
if (link == nullptr)
|
||||
{
|
||||
m_switch.status = refused(STR_C("The switch couldn't be created from this template"));
|
||||
@@ -443,7 +577,7 @@ std::vector<TTrack *> editor_mode::create_switch_set(editor_track::switch_templa
|
||||
m_switch.status = format(STR_C("Double switch %s with its second switch %s inserted"), one->name().c_str(), two->name().c_str());
|
||||
return {one, two, link};
|
||||
}
|
||||
auto *track{editor_track::create_switch(Shape, Paths, Style, Name)};
|
||||
auto *track{switch_of(Shape, Paths, Name)};
|
||||
if (track == nullptr)
|
||||
{
|
||||
m_switch.status = refused(STR_C("The switch couldn't be created from this template"));
|
||||
|
||||
Reference in New Issue
Block a user