17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 03:59:19 +02:00

feat(editor): no sub-metre straights, switches snap, K splits path

This commit is contained in:
maj00r
2026-10-03 00:49:35 +02:00
parent 8a50d352fb
commit bf24c3983a
6 changed files with 200 additions and 11 deletions

View File

@@ -1500,6 +1500,77 @@ TTrack *editor_track::create_path(TTrack const &Style, segment_data const &Path)
return track;
}
double editor_track::nearest_parameter(TTrack const &Track, glm::dvec3 const &Point)
{
if (Track.m_paths.empty())
return 0.5;
auto const &path{Track.m_paths.front()};
auto const p0{path.points[segment_data::point::start]};
auto const p3{path.points[segment_data::point::end]};
auto const p1{p0 + path.points[segment_data::point::control1]};
auto const p2{p3 + path.points[segment_data::point::control2]};
auto const at = [&](double const T) {
auto const u{1.0 - T};
return u * u * u * p0 + 3.0 * u * u * T * p1 + 3.0 * u * T * T * p2 + T * T * T * p3;
};
auto const distance = [&](double const T) { auto const q{at(T)}; return glm::distance(glm::dvec2{q.x, q.z}, glm::dvec2{Point.x, Point.z}); };
double best{0.5};
for (int i = 0; i <= 200; ++i)
if (distance(i / 200.0) < distance(best))
best = i / 200.0;
double step{1.0 / 200.0};
for (int i = 0; i < 30; ++i)
{
step *= 0.5;
if (best - step > 0.0 && distance(best - step) < distance(best))
best -= step;
else if (best + step < 1.0 && distance(best + step) < distance(best))
best += step;
}
return best;
}
TTrack *editor_track::split_path(TTrack &Track, double const T)
{
if (Track.eType != tt_Normal || Track.m_paths.empty() || T <= 0.001 || T >= 0.999)
return nullptr;
auto const path{Track.m_paths.front()};
auto const p0{path.points[segment_data::point::start]};
auto const p3{path.points[segment_data::point::end]};
segment_data first{path};
segment_data second{path};
auto const roll{static_cast<float>(path.rolls[0] + (path.rolls[1] - path.rolls[0]) * T)};
if (path.points[segment_data::point::control1] == glm::dvec3{} && path.points[segment_data::point::control2] == glm::dvec3{})
{
auto const middle{glm::mix(p0, p3, T)};
first.points[segment_data::point::end] = middle;
second.points[segment_data::point::start] = middle;
}
else
{
auto const p1{p0 + path.points[segment_data::point::control1]};
auto const p2{p3 + path.points[segment_data::point::control2]};
auto const p01{glm::mix(p0, p1, T)};
auto const p12{glm::mix(p1, p2, T)};
auto const p23{glm::mix(p2, p3, T)};
auto const p012{glm::mix(p01, p12, T)};
auto const p123{glm::mix(p12, p23, T)};
auto const middle{glm::mix(p012, p123, T)};
first.points[segment_data::point::control1] = p01 - p0;
first.points[segment_data::point::control2] = p012 - middle;
first.points[segment_data::point::end] = middle;
second.points[segment_data::point::start] = middle;
second.points[segment_data::point::control1] = p123 - middle;
second.points[segment_data::point::control2] = p23 - p3;
}
first.rolls[1] = roll;
second.rolls[0] = roll;
auto *created{create_path(Track, second)};
Track.m_paths.front() = first;
commit({&Track, created});
return created;
}
TTrack *editor_track::load_path(std::string const &Text, TTrack const &Template)
{
cParser parser(Text, cParser::buffer_TEXT);