diff --git a/application/editormodenmt.cpp b/application/editormodenmt.cpp index 02992d4b..7760a619 100644 --- a/application/editormodenmt.cpp +++ b/application/editormodenmt.cpp @@ -2073,10 +2073,22 @@ bool editor_mode::nmt_fit_line(TTrack &Track) // are cut off and set to the bridge, the formation is laid up to it, the ground under it stays as the model has it double constexpr kBridged{1.0}; // m double constexpr kAbutment{100.0}; // per mille + // spans a few metres apart are one bridge on its piers; what is shorter than that is a culvert under the embankment + double constexpr kPier{5.0}; // m + double constexpr kCulvert{3.0}; // m std::vector heights(count); for (std::size_t i = 0; i < count; ++i) heights[i] = profile::elevation(fitted_line, sampled[i]); - auto const bridges{profile::bridged(sampled, heights, model, kBridged, kAbutment)}; + std::vector bridges; + for (auto const &stretch : profile::bridged(sampled, heights, model, kBridged, kAbutment)) + if (false == bridges.empty() && stretch.from - bridges.back().to < kPier) + { + bridges.back().to = stretch.to; + bridges.back().depth = std::min(bridges.back().depth, stretch.depth); + } + else + bridges.push_back(stretch); + bridges.erase(std::remove_if(bridges.begin(), bridges.end(), [&](profile::departure const &Bridge) { return Bridge.to - Bridge.from < kCulvert; }), bridges.end()); profile_apply(false, bridges); auto const applied{profile.error.empty()}; // where the line parts from the model: under it a gap, a bridge or a viaduct, over it a wall or a structure above the track diff --git a/application/editormodeprofile.cpp b/application/editormodeprofile.cpp index d14dcf70..0d0add80 100644 --- a/application/editormodeprofile.cpp +++ b/application/editormodeprofile.cpp @@ -1476,7 +1476,18 @@ void editor_mode::profile_apply(bool const Terrain, std::vector> states; std::vector created; auto cuts{profile::breaks(line)}; - for (auto const &bridge : Bridges) + // a bridge ends at a joint or a break of the line by its abutment rather than leave a sliver of a path there + double constexpr kBridgeSnap{1.0}; // m + auto joints{cuts}; + for (auto const &span : state.route.spans) + joints.insert(joints.end(), {span.from, span.to}); + auto bridges{Bridges}; + for (auto &bridge : bridges) + for (auto *end : {&bridge.from, &bridge.to}) + if (auto const nearest{std::min_element(joints.begin(), joints.end(), [&](double const A, double const B) { return std::abs(A - *end) < std::abs(B - *end); })}; + nearest != joints.end() && std::abs(*nearest - *end) <= kBridgeSnap) + *end = *nearest; + for (auto const &bridge : bridges) cuts.insert(cuts.end(), {bridge.from, bridge.to}); std::sort(cuts.begin(), cuts.end()); auto const gaps{editor_track::apply_profile( @@ -1486,7 +1497,7 @@ void editor_mode::profile_apply(bool const Terrain, std::vectoreEnvironment != e_bridge && span.track->eEnvironment != e_tunnel - && std::any_of(Bridges.begin(), Bridges.end(), [&](profile::departure const &Bridge) { return span.from >= Bridge.from - kBridgeEnd && span.to <= Bridge.to + kBridgeEnd; })) + && std::any_of(bridges.begin(), bridges.end(), [&](profile::departure const &Bridge) { return span.from >= Bridge.from - kBridgeEnd && span.to <= Bridge.to + kBridgeEnd; })) { span.track->eEnvironment = e_bridge; ++bridged;