mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-30 23:40:29 +01:00
fix(editor): a curve with a switch in it read as one curve through the main track of the switch, the switch placed into a curve on the part around the click; the diverging path of a switch placed into a canted curve lies on the conical surface of the cant along its whole length, not only at its ends; platforms by a switch keep the cant of the track for their height, the gauge of the other path only sets them back
This commit is contained in:
@@ -926,6 +926,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
|||||||
bool switch_reach(glm::dvec3 const &Ground, glm::dvec3 &Point);
|
bool switch_reach(glm::dvec3 const &Ground, glm::dvec3 &Point);
|
||||||
glm::dvec3 cursor_ground() const;
|
glm::dvec3 cursor_ground() const;
|
||||||
glm::dvec3 cursor_level(double const Height) const;
|
glm::dvec3 cursor_level(double const Height) const;
|
||||||
|
std::optional<glm::dvec3> m_cursor_override;
|
||||||
bool sweep_grabs(glm::dvec3 const &Point);
|
bool sweep_grabs(glm::dvec3 const &Point);
|
||||||
// menu of the path a click of the right mouse button lands on
|
// menu of the path a click of the right mouse button lands on
|
||||||
struct track_context
|
struct track_context
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "application/editormode.h"
|
#include "application/editormode.h"
|
||||||
#include "editor/editorSettings.hpp"
|
#include "editor/editorSettings.hpp"
|
||||||
|
#include "editor/editorGeometry.hpp"
|
||||||
#include "application/application.h"
|
#include "application/application.h"
|
||||||
#include "application/editoruilayer.h"
|
#include "application/editoruilayer.h"
|
||||||
#include "application/editorprojection.h"
|
#include "application/editorprojection.h"
|
||||||
@@ -273,6 +274,67 @@ void editor_mode::selftest_step()
|
|||||||
text += format(" [%.1f %.2f..%.2f]", index * 0.1, column.first, column.second);
|
text += format(" [%.1f %.2f..%.2f]", index * 0.1, column.first, column.second);
|
||||||
WriteLog(format("SELFTEST profile %s at %.0f m:", name.c_str(), station) + text);
|
WriteLog(format("SELFTEST profile %s at %.0f m:", name.c_str(), station) + text);
|
||||||
}
|
}
|
||||||
|
else if (command == "curvedswitch")
|
||||||
|
{
|
||||||
|
std::string name, label;
|
||||||
|
glm::dvec3 at{0.0}, toward{0.0};
|
||||||
|
words >> name >> at.x >> at.z >> toward.x >> toward.z >> label;
|
||||||
|
m_node = simulation::Paths.find(name);
|
||||||
|
ui()->set_node(m_node);
|
||||||
|
show_track_tab(track_tab::turnout);
|
||||||
|
arm_switch();
|
||||||
|
auto &tool{m_switch};
|
||||||
|
for (int i = 0; i < static_cast<int>(tool.templates.size()); ++i)
|
||||||
|
if (false == label.empty() && tool.templates[i].label.find(label) != std::string::npos)
|
||||||
|
{
|
||||||
|
tool.armed = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_cursor_override = at;
|
||||||
|
auto const started{start_switch_placement()};
|
||||||
|
m_cursor_override.reset();
|
||||||
|
if (false == started)
|
||||||
|
{
|
||||||
|
WriteLog("SELFTEST curvedswitch: not started, " + tool.status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tool.mouse = glm::dvec3{toward.x, tool.point.y, toward.z};
|
||||||
|
finish_switch_placement();
|
||||||
|
WriteLog("SELFTEST curvedswitch " + (tool.armed >= 0 ? tool.templates[tool.armed].label : std::string{}) + ": " + tool.status);
|
||||||
|
}
|
||||||
|
else if (command == "conecheck")
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
words >> name;
|
||||||
|
auto *track{simulation::Paths.find(name)};
|
||||||
|
if (track == nullptr || track->m_paths.size() < 2)
|
||||||
|
{
|
||||||
|
WriteLog("SELFTEST conecheck: no switch " + name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
geometry::bezier const main{track->m_paths[0]};
|
||||||
|
geometry::bezier const other{track->m_paths[1]};
|
||||||
|
std::string text;
|
||||||
|
for (double t = 0.125; t < 1.01; t += 0.125)
|
||||||
|
{
|
||||||
|
auto const point{other.point(t)};
|
||||||
|
double best{std::numeric_limits<double>::max()}, along{0.0};
|
||||||
|
for (int k = 0; k <= 2000; ++k)
|
||||||
|
if (auto const distance{geometry::plan_distance(main.point(k / 2000.0), point)}; distance < best)
|
||||||
|
{
|
||||||
|
best = distance;
|
||||||
|
along = k / 2000.0;
|
||||||
|
}
|
||||||
|
auto const base{main.point(along)};
|
||||||
|
auto const direction{glm::normalize(geometry::plan_of(main.first(along)))};
|
||||||
|
auto const lateral{(point.x - base.x) * -direction.y + (point.z - base.z) * direction.x};
|
||||||
|
auto const &path{track->m_paths[0]};
|
||||||
|
auto const roll{glm::radians(path.rolls[0] + (path.rolls[1] - path.rolls[0]) * along)};
|
||||||
|
auto const cone{base.y - lateral * std::tan(roll)};
|
||||||
|
text += format(" [t %.3f off %.3f dy %.4f]", t, lateral, point.y - cone);
|
||||||
|
}
|
||||||
|
WriteLog("SELFTEST conecheck " + name + ":" + text);
|
||||||
|
}
|
||||||
else if (command == "fouling")
|
else if (command == "fouling")
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> values;
|
std::map<std::string, std::string> values;
|
||||||
|
|||||||
@@ -3815,6 +3815,8 @@ glm::dvec3 editor_mode::cursor_ground() const
|
|||||||
|
|
||||||
glm::dvec3 editor_mode::cursor_level(double const Height) const
|
glm::dvec3 editor_mode::cursor_level(double const Height) const
|
||||||
{
|
{
|
||||||
|
if (m_cursor_override.has_value())
|
||||||
|
return glm::dvec3{m_cursor_override->x, Height, m_cursor_override->z};
|
||||||
glm::dvec3 const ground{cursor_ground()};
|
glm::dvec3 const ground{cursor_ground()};
|
||||||
screen_projection const projection;
|
screen_projection const projection;
|
||||||
glm::dvec3 level;
|
glm::dvec3 level;
|
||||||
@@ -4565,11 +4567,17 @@ bool editor_mode::start_switch_placement()
|
|||||||
tool.status = STR_C("The selected track is neither a recognized straight nor a curve");
|
tool.status = STR_C("The selected track is neither a recognized straight nor a curve");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (false == editor_track::find_chain(curve.from, curve.to, chain, error))
|
if (false == editor_track::find_chain(curve.from, curve.to, chain, error, true))
|
||||||
{
|
{
|
||||||
tool.status = error.empty() ? std::string{STR_C("The curve can't be followed")} : error;
|
tool.status = error.empty() ? std::string{STR_C("The curve can't be followed")} : error;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
for (auto const &part : editor_track::chain_parts(chain))
|
||||||
|
if (std::find(part.tracks.begin(), part.tracks.end(), track) != part.tracks.end())
|
||||||
|
{
|
||||||
|
chain = part;
|
||||||
|
break;
|
||||||
|
}
|
||||||
tool.frame = sample_chain(chain);
|
tool.frame = sample_chain(chain);
|
||||||
tool.frame_tracks = chain.tracks;
|
tool.frame_tracks = chain.tracks;
|
||||||
if (tool.frame.size() < 2)
|
if (tool.frame.size() < 2)
|
||||||
@@ -5825,6 +5833,20 @@ std::vector<segment_data> editor_mode::curved_switch_paths(editor_track::switch_
|
|||||||
auto const p0{map(start, startdirection, localstart)};
|
auto const p0{map(start, startdirection, localstart)};
|
||||||
auto const p3{map(end, enddirection, localend)};
|
auto const p3{map(end, enddirection, localend)};
|
||||||
auto path{hermite(p0, startdirection, p3, enddirection)};
|
auto path{hermite(p0, startdirection, p3, enddirection)};
|
||||||
|
{
|
||||||
|
auto const cone = [&](double const T) {
|
||||||
|
auto const point{bezier{path}.point(T)};
|
||||||
|
auto const sample{sample_at(Frame, nearest_station(Frame, point))};
|
||||||
|
auto const lateral{glm::dot(plan_of(point) - plan_of(sample.position), glm::dvec2{-sample.tangent.y, sample.tangent.x})};
|
||||||
|
return sample.position.y - lateral * std::tan(glm::radians(static_cast<double>(sample.roll)));
|
||||||
|
};
|
||||||
|
auto const h1{cone(1.0 / 3.0)};
|
||||||
|
auto const h2{cone(2.0 / 3.0)};
|
||||||
|
auto const y1{3.0 * h1 - 1.5 * h2 - 5.0 / 6.0 * p0.y + p3.y / 3.0};
|
||||||
|
auto const y2{3.0 * h2 - 1.5 * h1 + p0.y / 3.0 - 5.0 / 6.0 * p3.y};
|
||||||
|
path.points[segment_data::point::control1].y = y1 - p0.y;
|
||||||
|
path.points[segment_data::point::control2].y = y2 - p3.y;
|
||||||
|
}
|
||||||
auto const rollstart{sample_at(Frame, Station + Direction * start.z).roll * Direction};
|
auto const rollstart{sample_at(Frame, Station + Direction * start.z).roll * Direction};
|
||||||
auto const rollend{sample_at(Frame, Station + Direction * end.z).roll * Direction};
|
auto const rollend{sample_at(Frame, Station + Direction * end.z).roll * Direction};
|
||||||
path.rolls = {static_cast<float>(rollstart), static_cast<float>(rollend)};
|
path.rolls = {static_cast<float>(rollstart), static_cast<float>(rollend)};
|
||||||
|
|||||||
@@ -1368,12 +1368,32 @@ bool editor_track::find_curve(TTrack &Track, straight_tolerance const &Tolerance
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::deque<std::pair<TTrack *, bool>> run{{&Track, true}};
|
std::deque<std::pair<TTrack *, bool>> run{{&Track, true}};
|
||||||
|
auto const known = [&](TTrack const *Other) { return std::any_of(run.begin(), run.end(), [&](auto const &Member) { return Member.first == Other; }); };
|
||||||
for (auto const throughend : {true, false})
|
for (auto const throughend : {true, false})
|
||||||
{
|
{
|
||||||
TTrack *previous{&Track};
|
TTrack *previous{&Track};
|
||||||
TTrack *current{throughend ? Track.trNext : Track.trPrev};
|
TTrack *current{throughend ? Track.trNext : Track.trPrev};
|
||||||
while (curved(current) && std::none_of(run.begin(), run.end(), [&](auto const &Member) { return Member.first == current; }))
|
while (current != nullptr && false == known(current))
|
||||||
{
|
{
|
||||||
|
if (current->eType == tt_Switch && has_switch_paths(*current) && is_supported(*current) && false == current->m_editorremoved)
|
||||||
|
{
|
||||||
|
auto const &extension{*current->SwitchExtension};
|
||||||
|
bool const atstart{extension.pPrevs[0] == previous};
|
||||||
|
if (atstart == (extension.pNexts[0] == previous))
|
||||||
|
break;
|
||||||
|
auto *beyond{atstart ? extension.pNexts[0] : extension.pPrevs[0]};
|
||||||
|
if (false == curved(beyond) || known(beyond))
|
||||||
|
break;
|
||||||
|
if (throughend)
|
||||||
|
run.emplace_back(current, atstart);
|
||||||
|
else
|
||||||
|
run.emplace_front(current, false == atstart);
|
||||||
|
previous = current;
|
||||||
|
current = beyond;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (false == curved(current))
|
||||||
|
break;
|
||||||
auto const entersatstart{current->trPrev == previous};
|
auto const entersatstart{current->trPrev == previous};
|
||||||
if (throughend)
|
if (throughend)
|
||||||
run.emplace_back(current, entersatstart);
|
run.emplace_back(current, entersatstart);
|
||||||
@@ -1433,7 +1453,7 @@ bool editor_track::analyse_curve(std::vector<std::pair<TTrack *, bool>> const &R
|
|||||||
for (std::size_t i = 0; i < run.size(); ++i)
|
for (std::size_t i = 0; i < run.size(); ++i)
|
||||||
{
|
{
|
||||||
auto const &path{run[i].first->m_paths.front()};
|
auto const &path{run[i].first->m_paths.front()};
|
||||||
auto const length{run[i].first->Length()};
|
auto const length{run[i].first->eType == tt_Switch ? bezier{path}.plan_length() : run[i].first->Length()};
|
||||||
auto const internal{signed_angle(incoming(i), outgoing(i))};
|
auto const internal{signed_angle(incoming(i), outgoing(i))};
|
||||||
turns.push_back(internal + kinks[i] * 0.5 + kinks[i + 1] * 0.5);
|
turns.push_back(internal + kinks[i] * 0.5 + kinks[i + 1] * 0.5);
|
||||||
lengths.push_back(length);
|
lengths.push_back(length);
|
||||||
|
|||||||
@@ -657,10 +657,7 @@ void sweep_node::beside_switches(std::vector<sample> &Samples)
|
|||||||
continue;
|
continue;
|
||||||
auto const needed{offset + total(*nearest)};
|
auto const needed{offset + total(*nearest)};
|
||||||
if (needed > total(here))
|
if (needed > total(here))
|
||||||
{
|
here.widening[side] = needed - std::max(0.0, here.cant[side]) * edgeheight / 1.5;
|
||||||
here.widening[side] = needed;
|
|
||||||
here.cant[side] = 0.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user