mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-01 08:02:10 +01:00
fix(editor): the gizmo keeps the diverging path of a switch on the surface of its main path
The diverging path p3-p4 takes its heights, grades at the ends and cant from the main path p1-p2 (the cone of its cant) after every gizmo change: grade and cant rings, moving an end and editing a control vector. The tracks joined to it follow its ends and grades. The grade ring measures along the main path and the gizmo stands in its middle; the start vector of the diverging path slides along the main one and turns with it.
This commit is contained in:
@@ -674,6 +674,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
|||||||
void track_gizmo_settle();
|
void track_gizmo_settle();
|
||||||
void track_gizmo_stretch(TTrack &Track, double const Length);
|
void track_gizmo_stretch(TTrack &Track, double const Length);
|
||||||
void track_gizmo_control(TTrack &Track, glm::dvec3 Control);
|
void track_gizmo_control(TTrack &Track, glm::dvec3 Control);
|
||||||
|
void track_gizmo_point(TTrack &Track, glm::dvec3 const &Position);
|
||||||
void track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_operation const Operation);
|
void track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_operation const Operation);
|
||||||
void track_gizmo_turn(TTrack &Track, int const Axis, double const Angle);
|
void track_gizmo_turn(TTrack &Track, int const Axis, double const Angle);
|
||||||
void track_gizmo_length(TTrack &Track, double Length);
|
void track_gizmo_length(TTrack &Track, double Length);
|
||||||
|
|||||||
@@ -357,7 +357,9 @@ void editor_mode::selftest_step()
|
|||||||
auto const lateral{(point.x - base.x) * -direction.y + (point.z - base.z) * direction.x};
|
auto const lateral{(point.x - base.x) * -direction.y + (point.z - base.z) * direction.x};
|
||||||
auto const &path{track->m_paths[0]};
|
auto const &path{track->m_paths[0]};
|
||||||
auto const roll{glm::radians(path.rolls[0] + (path.rolls[1] - path.rolls[0]) * along)};
|
auto const roll{glm::radians(path.rolls[0] + (path.rolls[1] - path.rolls[0]) * along)};
|
||||||
auto const cone{base.y - lateral * std::tan(roll)};
|
auto const tangent{main.first(along)};
|
||||||
|
auto const beyond{(point.x - base.x) * direction.x + (point.z - base.z) * direction.y};
|
||||||
|
auto const cone{base.y + beyond * tangent.y / glm::length(geometry::plan_of(tangent)) - lateral * std::tan(roll)};
|
||||||
text += format(" [t %.3f off %.3f dy %.4f]", t, lateral, point.y - cone);
|
text += format(" [t %.3f off %.3f dy %.4f]", t, lateral, point.y - cone);
|
||||||
}
|
}
|
||||||
WriteLog("SELFTEST conecheck " + name + ":" + text);
|
WriteLog("SELFTEST conecheck " + name + ":" + text);
|
||||||
@@ -1214,10 +1216,7 @@ void editor_mode::selftest_step()
|
|||||||
words >> offset.x >> offset.y >> offset.z;
|
words >> offset.x >> offset.y >> offset.z;
|
||||||
if (m_track_point.valid())
|
if (m_track_point.valid())
|
||||||
{
|
{
|
||||||
auto const position{editor_track::point_position(*track, m_track_point) + offset};
|
track_gizmo_point(*track, editor_track::point_position(*track, m_track_point) + offset);
|
||||||
editor_track::move_point(*track, m_track_point, position);
|
|
||||||
for (auto const &connection : m_track_drag_points)
|
|
||||||
editor_track::move_point(*connection.first, connection.second, position);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -383,16 +383,18 @@ glm::mat4 gizmo_along(glm::dvec3 const &Position, glm::dvec3 const &Axis)
|
|||||||
|
|
||||||
void track_middle(TTrack const &Track, glm::dvec3 &Point, glm::dvec3 &Tangent, double &Chainage)
|
void track_middle(TTrack const &Track, glm::dvec3 &Point, glm::dvec3 &Tangent, double &Chainage)
|
||||||
{
|
{
|
||||||
|
auto const count{Track.eType == tt_Switch ? std::min<std::size_t>(1, Track.m_paths.size()) : Track.m_paths.size()};
|
||||||
double total{0.0};
|
double total{0.0};
|
||||||
for (auto const &path : Track.m_paths)
|
for (std::size_t i = 0; i < count; ++i)
|
||||||
total += bezier{path}.plan_length();
|
total += bezier{Track.m_paths[i]}.plan_length();
|
||||||
Chainage = total * 0.5;
|
Chainage = total * 0.5;
|
||||||
double along{0.0};
|
double along{0.0};
|
||||||
for (auto const &path : Track.m_paths)
|
for (std::size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
auto const &path{Track.m_paths[i]};
|
||||||
bezier const curve{path};
|
bezier const curve{path};
|
||||||
auto const length{curve.plan_length()};
|
auto const length{curve.plan_length()};
|
||||||
if (along + length >= Chainage || &path == &Track.m_paths.back())
|
if (along + length >= Chainage || i + 1 == count)
|
||||||
{
|
{
|
||||||
auto const t{curve.parameter(Chainage - along)};
|
auto const t{curve.parameter(Chainage - along)};
|
||||||
Point = curve.point(t);
|
Point = curve.point(t);
|
||||||
@@ -417,6 +419,13 @@ double roll_into(TTrack const &Track, editor_track::point_ref const &Point)
|
|||||||
return Point.kind == editor_track::point_kind::start ? path.rolls[0] : -path.rolls[1];
|
return Point.kind == editor_track::point_kind::start ? path.rolls[0] : -path.rolls[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor_track::point_ref switch_main(TTrack const &Track, editor_track::point_ref Point)
|
||||||
|
{
|
||||||
|
if (Track.eType == tt_Switch && Point.valid() && Point.path > 0)
|
||||||
|
Point.path = 0;
|
||||||
|
return Point;
|
||||||
|
}
|
||||||
|
|
||||||
editor_track::point_ref stretch_remap(editor_track::point_ref Point, int const Path, std::size_t const Pieces)
|
editor_track::point_ref stretch_remap(editor_track::point_ref Point, int const Path, std::size_t const Pieces)
|
||||||
{
|
{
|
||||||
if (false == Point.valid() || Point.path < Path)
|
if (false == Point.valid() || Point.path < Path)
|
||||||
@@ -686,9 +695,29 @@ void editor_mode::track_gizmo_control(TTrack &Track, glm::dvec3 Control)
|
|||||||
Control = glm::length(Control) > 1e-9 ? glm::normalize(Control) * 0.5 : drag.axis * 0.5;
|
Control = glm::length(Control) > 1e-9 ? glm::normalize(Control) * 0.5 : drag.axis * 0.5;
|
||||||
editor_track::move_point(Track, drag.point, editor_track::point_position(Track, editor_track::end_of(drag.point)) + Control);
|
editor_track::move_point(Track, drag.point, editor_track::point_position(Track, editor_track::end_of(drag.point)) + Control);
|
||||||
editor_track::align_controls(Track, drag.point, drag.partners);
|
editor_track::align_controls(Track, drag.point, drag.partners);
|
||||||
|
if (Track.eType == tt_Switch)
|
||||||
|
{
|
||||||
|
editor_track::conform_switch(Track);
|
||||||
|
editor_track::follow(Track, m_track_joints);
|
||||||
|
editor_track::follow_grade(Track, m_track_joints);
|
||||||
|
}
|
||||||
m_track_dirty = true;
|
m_track_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void editor_mode::track_gizmo_point(TTrack &Track, glm::dvec3 const &Position)
|
||||||
|
{
|
||||||
|
editor_track::move_point(Track, m_track_point, Position);
|
||||||
|
if (Track.eType == tt_Switch)
|
||||||
|
{
|
||||||
|
editor_track::conform_switch(Track);
|
||||||
|
editor_track::follow(Track, m_track_joints);
|
||||||
|
editor_track::follow_grade(Track, m_track_joints);
|
||||||
|
}
|
||||||
|
auto const moved{editor_track::point_position(Track, m_track_point)};
|
||||||
|
for (auto const &connection : m_track_drag_points)
|
||||||
|
editor_track::move_point(*connection.first, connection.second, moved);
|
||||||
|
}
|
||||||
|
|
||||||
void editor_mode::track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_operation const Operation)
|
void editor_mode::track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_operation const Operation)
|
||||||
{
|
{
|
||||||
bool const controlmode{Pointmode && false == editor_track::is_end(m_track_point.kind)};
|
bool const controlmode{Pointmode && false == editor_track::is_end(m_track_point.kind)};
|
||||||
@@ -729,14 +758,15 @@ void editor_mode::track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_o
|
|||||||
{
|
{
|
||||||
std::string reason;
|
std::string reason;
|
||||||
auto const &path{partner.first->m_paths[partner.second.path]};
|
auto const &path{partner.first->m_paths[partner.second.path]};
|
||||||
if (partner.first->eType != tt_Normal || false == editor_track::can_edit_geometry(*partner.first, reason))
|
bool const own{partner.first == &Track};
|
||||||
|
if (own ? m_track_point.path != 0 : partner.first->eType != tt_Normal || false == editor_track::can_edit_geometry(*partner.first, reason))
|
||||||
{
|
{
|
||||||
bool const start{partner.second.kind == editor_track::point_kind::start};
|
bool const start{partner.second.kind == editor_track::point_kind::start};
|
||||||
auto const theirs{path.points[start ? segment_data::point::control1 : segment_data::point::control2]};
|
auto const theirs{path.points[start ? segment_data::point::control1 : segment_data::point::control2]};
|
||||||
auto const chord{path.points[start ? segment_data::point::end : segment_data::point::start] - path.points[start ? segment_data::point::start : segment_data::point::end]};
|
auto const chord{path.points[start ? segment_data::point::end : segment_data::point::start] - path.points[start ? segment_data::point::start : segment_data::point::end]};
|
||||||
auto const along{theirs != glm::dvec3{} ? theirs : chord};
|
auto const along{theirs != glm::dvec3{} ? theirs : chord};
|
||||||
if (glm::length(along) > 1e-9)
|
if (glm::length(along) > 1e-9)
|
||||||
drag.fixed = -glm::normalize(along);
|
drag.fixed = (own && partner.second.kind == editor_track::end_of(m_track_point).kind ? 1.0 : -1.0) * glm::normalize(along);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (false == m_track_drag_connected && partner.first != &Track)
|
if (false == m_track_drag_connected && partner.first != &Track)
|
||||||
@@ -746,6 +776,18 @@ void editor_mode::track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_o
|
|||||||
m_track_drag.emplace_back(partner.first);
|
m_track_drag.emplace_back(partner.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (false == whole && Track.eType == tt_Switch && m_track_drag_connected)
|
||||||
|
{
|
||||||
|
auto const edited{editor_track::point_position(Track, editor_track::end_of(m_track_point))};
|
||||||
|
for (auto const &joint : editor_track::joints(Track))
|
||||||
|
{
|
||||||
|
if (controlmode && glm::distance(editor_track::point_position(Track, joint.own), edited) < geometry::same_point)
|
||||||
|
continue;
|
||||||
|
m_track_joints.push_back(joint);
|
||||||
|
if (std::find(m_track_drag.begin(), m_track_drag.end(), joint.other) == m_track_drag.end())
|
||||||
|
m_track_drag.emplace_back(joint.other);
|
||||||
|
}
|
||||||
|
}
|
||||||
std::vector<std::pair<TTrack *, editor_track::state>> states;
|
std::vector<std::pair<TTrack *, editor_track::state>> states;
|
||||||
for (auto *dragged : m_track_drag)
|
for (auto *dragged : m_track_drag)
|
||||||
states.emplace_back(dragged, editor_track::capture(*dragged));
|
states.emplace_back(dragged, editor_track::capture(*dragged));
|
||||||
@@ -778,8 +820,13 @@ void editor_mode::track_gizmo_begin(TTrack &Track, bool const Pointmode, gizmo_o
|
|||||||
drag.lengths.push_back(bezier{path}.plan_length());
|
drag.lengths.push_back(bezier{path}.plan_length());
|
||||||
along += drag.lengths.back();
|
along += drag.lengths.back();
|
||||||
}
|
}
|
||||||
auto const end{editor_track::end_of(drag.point)};
|
auto const end{switch_main(Track, editor_track::end_of(drag.point))};
|
||||||
if (end.valid() && end.path < static_cast<int>(drag.chainages.size()))
|
if (Track.eType == tt_Switch && false == Track.m_paths.empty())
|
||||||
|
{
|
||||||
|
drag.pivot_chainage = editor_track::switch_station(Track, drag.pivot);
|
||||||
|
drag.roll0 = end.valid() && end.kind == editor_track::point_kind::end ? Track.m_paths[0].rolls[1] : Track.m_paths[0].rolls[0];
|
||||||
|
}
|
||||||
|
else if (end.valid() && end.path < static_cast<int>(drag.chainages.size()))
|
||||||
{
|
{
|
||||||
drag.pivot_chainage = drag.chainages[end.path] + (end.kind == editor_track::point_kind::end ? drag.lengths[end.path] : 0.0);
|
drag.pivot_chainage = drag.chainages[end.path] + (end.kind == editor_track::point_kind::end ? drag.lengths[end.path] : 0.0);
|
||||||
drag.roll0 = end.kind == editor_track::point_kind::start ? Track.m_paths[end.path].rolls[0] : Track.m_paths[end.path].rolls[1];
|
drag.roll0 = end.kind == editor_track::point_kind::start ? Track.m_paths[end.path].rolls[0] : Track.m_paths[end.path].rolls[1];
|
||||||
@@ -836,7 +883,8 @@ void editor_mode::track_gizmo_turn(TTrack &Track, int const Axis, double const A
|
|||||||
track_gizmo_control(Track, {control.x, control.y + step * run * (along >= 0.0 ? 1.0 : -1.0), control.z});
|
track_gizmo_control(Track, {control.x, control.y + step * run * (along >= 0.0 ? 1.0 : -1.0), control.z});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (std::size_t i = 0; i < Track.m_paths.size() && i < drag.chainages.size(); ++i)
|
auto const count{Track.eType == tt_Switch ? std::min<std::size_t>(1, Track.m_paths.size()) : Track.m_paths.size()};
|
||||||
|
for (std::size_t i = 0; i < count && i < drag.chainages.size(); ++i)
|
||||||
{
|
{
|
||||||
auto &path{Track.m_paths[i]};
|
auto &path{Track.m_paths[i]};
|
||||||
auto const from{drag.chainages[i] - drag.pivot_chainage};
|
auto const from{drag.chainages[i] - drag.pivot_chainage};
|
||||||
@@ -848,12 +896,14 @@ void editor_mode::track_gizmo_turn(TTrack &Track, int const Axis, double const A
|
|||||||
control1.y += step * glm::length(plan_of(control1));
|
control1.y += step * glm::length(plan_of(control1));
|
||||||
control2.y -= step * glm::length(plan_of(control2));
|
control2.y -= step * glm::length(plan_of(control2));
|
||||||
}
|
}
|
||||||
|
editor_track::conform_switch(Track);
|
||||||
editor_track::follow(Track, m_track_joints);
|
editor_track::follow(Track, m_track_joints);
|
||||||
editor_track::follow_grade(Track, m_track_joints);
|
editor_track::follow_grade(Track, m_track_joints);
|
||||||
m_track_dirty = true;
|
m_track_dirty = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto const end{editor_track::end_of(drag.point)};
|
auto const end{editor_track::end_of(drag.point)};
|
||||||
|
auto const canted{switch_main(Track, end)};
|
||||||
auto target{glm::degrees(drag.point.kind == editor_track::point_kind::control2 ? -Angle : Angle)};
|
auto target{glm::degrees(drag.point.kind == editor_track::point_kind::control2 ? -Angle : Angle)};
|
||||||
if (snap)
|
if (snap)
|
||||||
target = glm::degrees(std::asin(std::clamp(std::round(1500.0 * std::sin(glm::radians(drag.roll0 + target)) / 5.0) * 5.0 / 1500.0, -1.0, 1.0))) - drag.roll0;
|
target = glm::degrees(std::asin(std::clamp(std::round(1500.0 * std::sin(glm::radians(drag.roll0 + target)) / 5.0) * 5.0 / 1500.0, -1.0, 1.0))) - drag.roll0;
|
||||||
@@ -864,11 +914,17 @@ void editor_mode::track_gizmo_turn(TTrack &Track, int const Axis, double const A
|
|||||||
for (int i = 0; i < static_cast<int>(Track.m_paths.size()); ++i)
|
for (int i = 0; i < static_cast<int>(Track.m_paths.size()); ++i)
|
||||||
{
|
{
|
||||||
auto &path{Track.m_paths[i]};
|
auto &path{Track.m_paths[i]};
|
||||||
if (false == end.valid() || (i == end.path && end.kind == editor_track::point_kind::start))
|
if (false == canted.valid() || (i == canted.path && canted.kind == editor_track::point_kind::start))
|
||||||
path.rolls[0] += step;
|
path.rolls[0] += step;
|
||||||
if (false == end.valid() || (i == end.path && end.kind == editor_track::point_kind::end))
|
if (false == canted.valid() || (i == canted.path && canted.kind == editor_track::point_kind::end))
|
||||||
path.rolls[1] += step;
|
path.rolls[1] += step;
|
||||||
}
|
}
|
||||||
|
if (Track.eType == tt_Switch)
|
||||||
|
{
|
||||||
|
editor_track::conform_switch(Track);
|
||||||
|
editor_track::follow(Track, m_track_joints);
|
||||||
|
editor_track::follow_grade(Track, m_track_joints);
|
||||||
|
}
|
||||||
for (auto const &joint : m_track_joints)
|
for (auto const &joint : m_track_joints)
|
||||||
{
|
{
|
||||||
if (joint.own.path >= static_cast<int>(Track.m_paths.size()) || joint.theirs.path >= static_cast<int>(joint.other->m_paths.size()))
|
if (joint.own.path >= static_cast<int>(Track.m_paths.size()) || joint.theirs.path >= static_cast<int>(joint.other->m_paths.size()))
|
||||||
@@ -882,6 +938,8 @@ void editor_mode::track_gizmo_turn(TTrack &Track, int const Axis, double const A
|
|||||||
}
|
}
|
||||||
for (auto const &partner : drag.partners)
|
for (auto const &partner : drag.partners)
|
||||||
{
|
{
|
||||||
|
if (partner.first == &Track)
|
||||||
|
continue;
|
||||||
auto const roll{static_cast<float>(roll_into(Track, end))};
|
auto const roll{static_cast<float>(roll_into(Track, end))};
|
||||||
auto &theirs{partner.first->m_paths[partner.second.path]};
|
auto &theirs{partner.first->m_paths[partner.second.path]};
|
||||||
if (partner.second.kind == editor_track::point_kind::start)
|
if (partner.second.kind == editor_track::point_kind::start)
|
||||||
@@ -994,10 +1052,8 @@ void editor_mode::render_track_gizmo()
|
|||||||
}
|
}
|
||||||
else if (pointmode)
|
else if (pointmode)
|
||||||
{
|
{
|
||||||
glm::dvec3 const position = frame.camera + glm::dvec3(m_track_gizmo[3]);
|
track_gizmo_point(*track, frame.camera + glm::dvec3(m_track_gizmo[3]));
|
||||||
editor_track::move_point(*track, m_track_point, position);
|
auto const position{editor_track::point_position(*track, m_track_point)};
|
||||||
for (auto const &connection : m_track_drag_points)
|
|
||||||
editor_track::move_point(*connection.first, connection.second, position);
|
|
||||||
m_track_dirty = true;
|
m_track_dirty = true;
|
||||||
if (editor_track::is_end(m_track_point.kind) && m_track_drag_points.empty())
|
if (editor_track::is_end(m_track_point.kind) && m_track_drag_points.empty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -678,6 +678,129 @@ void editor_track::follow_grade(TTrack const &Track, std::vector<joint> const &J
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
struct surface_foot
|
||||||
|
{
|
||||||
|
double t{0.0};
|
||||||
|
double along{0.0};
|
||||||
|
double lateral{0.0};
|
||||||
|
glm::dvec3 base{0.0};
|
||||||
|
glm::dvec2 direction{0.0, 1.0};
|
||||||
|
double grade{0.0};
|
||||||
|
};
|
||||||
|
|
||||||
|
surface_foot foot_on(segment_data const &Path, glm::dvec3 const &Position)
|
||||||
|
{
|
||||||
|
bezier const curve{Path};
|
||||||
|
auto const distance = [&](double const T) { return glm::distance(plan_of(curve.point(T)), plan_of(Position)); };
|
||||||
|
int constexpr samples{200};
|
||||||
|
double best{std::numeric_limits<double>::max()};
|
||||||
|
int nearest{0};
|
||||||
|
for (int i = 0; i <= samples; ++i)
|
||||||
|
if (auto const d{distance(static_cast<double>(i) / samples)}; d < best)
|
||||||
|
{
|
||||||
|
best = d;
|
||||||
|
nearest = i;
|
||||||
|
}
|
||||||
|
auto low{std::max(0, nearest - 1) / static_cast<double>(samples)};
|
||||||
|
auto high{std::min(samples, nearest + 1) / static_cast<double>(samples)};
|
||||||
|
for (int i = 0; i < 40; ++i)
|
||||||
|
{
|
||||||
|
auto const a{low + (high - low) / 3.0};
|
||||||
|
auto const b{high - (high - low) / 3.0};
|
||||||
|
if (distance(a) < distance(b))
|
||||||
|
high = b;
|
||||||
|
else
|
||||||
|
low = a;
|
||||||
|
}
|
||||||
|
surface_foot foot;
|
||||||
|
foot.t = std::clamp((low + high) * 0.5, 0.0, 1.0);
|
||||||
|
foot.base = curve.point(foot.t);
|
||||||
|
auto const tangent{curve.first(foot.t)};
|
||||||
|
auto const plan{plan_of(tangent)};
|
||||||
|
auto const run{glm::length(plan)};
|
||||||
|
if (run > 1e-9)
|
||||||
|
{
|
||||||
|
foot.direction = plan / run;
|
||||||
|
foot.grade = tangent.y / run;
|
||||||
|
}
|
||||||
|
auto const offset{plan_of(Position) - plan_of(foot.base)};
|
||||||
|
foot.along = glm::dot(offset, foot.direction);
|
||||||
|
foot.lateral = glm::dot(offset, glm::dvec2{-foot.direction.y, foot.direction.x});
|
||||||
|
return foot;
|
||||||
|
}
|
||||||
|
|
||||||
|
double foot_roll(segment_data const &Path, surface_foot const &Foot)
|
||||||
|
{
|
||||||
|
return Path.rolls[0] + (Path.rolls[1] - Path.rolls[0]) * Foot.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
double surface_height(segment_data const &Path, surface_foot const &Foot)
|
||||||
|
{
|
||||||
|
return Foot.base.y + Foot.along * Foot.grade - Foot.lateral * std::tan(glm::radians(foot_roll(Path, Foot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void editor_track::conform_switch(TTrack &Track)
|
||||||
|
{
|
||||||
|
if (Track.eType != tt_Switch || Track.m_paths.size() != 2)
|
||||||
|
return;
|
||||||
|
auto const &main{Track.m_paths[0]};
|
||||||
|
auto &path{Track.m_paths[1]};
|
||||||
|
auto &start{path.points[segment_data::point::start]};
|
||||||
|
auto &end{path.points[segment_data::point::end]};
|
||||||
|
auto &control1{path.points[segment_data::point::control1]};
|
||||||
|
auto &control2{path.points[segment_data::point::control2]};
|
||||||
|
if (control1 == glm::dvec3{} && control2 == glm::dvec3{})
|
||||||
|
{
|
||||||
|
control1 = (end - start) / 3.0;
|
||||||
|
control2 = (start - end) / 3.0;
|
||||||
|
}
|
||||||
|
auto const height = [&](glm::dvec3 const &Point) { return surface_height(main, foot_on(main, Point)); };
|
||||||
|
auto const slope = [&](glm::dvec3 const &Point, glm::dvec3 const &Control) {
|
||||||
|
auto const plan{plan_of(Control)};
|
||||||
|
auto const run{glm::length(plan)};
|
||||||
|
if (run < 1e-9)
|
||||||
|
return 0.0;
|
||||||
|
double constexpr step{0.05};
|
||||||
|
glm::dvec3 const offset{plan.x / run * step, 0.0, plan.y / run * step};
|
||||||
|
return (4.0 * height(Point + offset) - 3.0 * height(Point) - height(Point + 2.0 * offset)) / (2.0 * step) * run;
|
||||||
|
};
|
||||||
|
start.y = height(start);
|
||||||
|
end.y = height(end);
|
||||||
|
control1.y = slope(start, control1);
|
||||||
|
control2.y = slope(end, control2);
|
||||||
|
bezier const curve{path};
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
auto const foot{foot_on(main, i == 0 ? start : end)};
|
||||||
|
auto const along{glm::dot(plan_of(curve.first(i)), foot.direction) >= 0.0 ? 1.0 : -1.0};
|
||||||
|
path.rolls[i] = static_cast<float>(foot_roll(main, foot) * along);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double editor_track::switch_station(TTrack const &Track, glm::dvec3 const &Position)
|
||||||
|
{
|
||||||
|
if (Track.m_paths.empty())
|
||||||
|
return 0.0;
|
||||||
|
auto const &main{Track.m_paths[0]};
|
||||||
|
auto const foot{foot_on(main, Position)};
|
||||||
|
bezier const curve{main};
|
||||||
|
int constexpr steps{64};
|
||||||
|
double length{0.0};
|
||||||
|
auto previous{plan_of(curve.point(0.0))};
|
||||||
|
for (int i = 1; i <= steps; ++i)
|
||||||
|
{
|
||||||
|
auto const next{plan_of(curve.point(foot.t * i / steps))};
|
||||||
|
length += glm::distance(previous, next);
|
||||||
|
previous = next;
|
||||||
|
}
|
||||||
|
return length + foot.along;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> editor_track::hold_controls(TTrack &Track)
|
std::vector<int> editor_track::hold_controls(TTrack &Track)
|
||||||
{
|
{
|
||||||
std::vector<int> result;
|
std::vector<int> result;
|
||||||
@@ -757,7 +880,8 @@ void editor_track::align_controls(TTrack const &Track, point_ref const &Control,
|
|||||||
bool const start{partner.second.kind == point_kind::start};
|
bool const start{partner.second.kind == point_kind::start};
|
||||||
auto &control{path.points[start ? segment_data::point::control1 : segment_data::point::control2]};
|
auto &control{path.points[start ? segment_data::point::control1 : segment_data::point::control2]};
|
||||||
auto const length{control != glm::dvec3{} ? glm::length(control) : glm::distance(path.points[segment_data::point::start], path.points[segment_data::point::end]) / 3.0};
|
auto const length{control != glm::dvec3{} ? glm::length(control) : glm::distance(path.points[segment_data::point::start], path.points[segment_data::point::end]) / 3.0};
|
||||||
control = -direction * length;
|
auto const same{partner.first == &Track && partner.second.kind == end_of(Control).kind};
|
||||||
|
control = (same ? direction : -direction) * length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ class editor_track
|
|||||||
// moves the joined ends to where the ends of the track are now, turning them as the track turned there
|
// moves the joined ends to where the ends of the track are now, turning them as the track turned there
|
||||||
static void follow(TTrack const &Track, std::vector<joint> const &Joints);
|
static void follow(TTrack const &Track, std::vector<joint> const &Joints);
|
||||||
static void follow_grade(TTrack const &Track, std::vector<joint> const &Joints);
|
static void follow_grade(TTrack const &Track, std::vector<joint> const &Joints);
|
||||||
|
static void conform_switch(TTrack &Track);
|
||||||
|
static double switch_station(TTrack const &Track, glm::dvec3 const &Position);
|
||||||
static std::vector<int> hold_controls(TTrack &Track);
|
static std::vector<int> hold_controls(TTrack &Track);
|
||||||
static void settle_controls(TTrack &Track, std::vector<int> const &Paths);
|
static void settle_controls(TTrack &Track, std::vector<int> const &Paths);
|
||||||
static std::vector<std::pair<TTrack *, point_ref>> partners(TTrack &Track, point_ref const &End);
|
static std::vector<std::pair<TTrack *, point_ref>> partners(TTrack &Track, point_ref const &End);
|
||||||
|
|||||||
Reference in New Issue
Block a user