mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-29 10:27:32 +01:00
feat(editor): a join of ends side by side shifts the track with reverse curves over the whole gap
The reverse curves of a join start and end at the joined ends, with the largest radius that fits, so a shift of the track spacing (4 -> 4.75 m over 400 m) is one S instead of two curves with straights around them. A straight or a single arc with a kink at its ends, though still under the joints check, comes after the smooth curves among the variants; a practically exact one stays first. An element under 1 mm, like the straight left between the reverse curves by the radius fit, no longer drops out of the pieces and leaves a gap: the neighbouring piece takes it over.
This commit is contained in:
@@ -969,10 +969,12 @@ std::optional<join_result> straight_join(join_frame const &Frame)
|
|||||||
{
|
{
|
||||||
auto const &a{Frame.request.start};
|
auto const &a{Frame.request.start};
|
||||||
auto const &b{Frame.request.end};
|
auto const &b{Frame.request.end};
|
||||||
if (std::abs(geometry::signed_angle(Frame.start_direction, Frame.chord)) > Frame.tolerance || std::abs(geometry::signed_angle(Frame.chord, Frame.end_direction)) > Frame.tolerance)
|
auto const kink{std::max(std::abs(geometry::signed_angle(Frame.start_direction, Frame.chord)), std::abs(geometry::signed_angle(Frame.chord, Frame.end_direction)))};
|
||||||
|
if (kink > Frame.tolerance)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
join_result straight;
|
join_result straight;
|
||||||
straight.kind = join_kind::straight;
|
straight.kind = join_kind::straight;
|
||||||
|
straight.kink = kink;
|
||||||
segment_data path;
|
segment_data path;
|
||||||
path.points[segment_data::point::start] = a.position;
|
path.points[segment_data::point::start] = a.position;
|
||||||
path.points[segment_data::point::end] = b.position;
|
path.points[segment_data::point::end] = b.position;
|
||||||
@@ -992,10 +994,12 @@ std::optional<join_result> arc_join(join_frame const &Frame)
|
|||||||
auto const angle{2.0 * std::atan2(std::abs(lateral), glm::dot(Frame.start_direction, Frame.chord))};
|
auto const angle{2.0 * std::atan2(std::abs(lateral), glm::dot(Frame.start_direction, Frame.chord))};
|
||||||
int const side{lateral > 0.0 ? 1 : -1};
|
int const side{lateral > 0.0 ? 1 : -1};
|
||||||
auto const radius{Frame.distance * Frame.distance / (2.0 * std::abs(lateral))};
|
auto const radius{Frame.distance * Frame.distance / (2.0 * std::abs(lateral))};
|
||||||
if (angle >= kPi - 1e-3 || std::abs(geometry::signed_angle(turned(Frame.start_direction, side * angle), Frame.end_direction)) > Frame.tolerance)
|
auto const kink{std::abs(geometry::signed_angle(turned(Frame.start_direction, side * angle), Frame.end_direction))};
|
||||||
|
if (angle >= kPi - 1e-3 || kink > Frame.tolerance)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
join_result arc;
|
join_result arc;
|
||||||
arc.kind = join_kind::arc;
|
arc.kind = join_kind::arc;
|
||||||
|
arc.kink = kink;
|
||||||
arc.pieces = geometry::arc_pieces(a.position, Frame.start_direction, Frame.rise / (radius * angle), radius, angle, side);
|
arc.pieces = geometry::arc_pieces(a.position, Frame.start_direction, Frame.rise / (radius * angle), radius, angle, side);
|
||||||
arc.pieces.back().points[segment_data::point::end] = b.position;
|
arc.pieces.back().points[segment_data::point::end] = b.position;
|
||||||
spread_rolls(arc.pieces, a.roll, b.roll);
|
spread_rolls(arc.pieces, a.roll, b.roll);
|
||||||
@@ -1024,7 +1028,7 @@ design join_design(join_frame const &Frame, join_kind const Kind)
|
|||||||
shape.vertices = {corner};
|
shape.vertices = {corner};
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
corner.offset = Frame.distance / 3.0;
|
corner.offset = Frame.distance / 4.0;
|
||||||
shape.vertices = {corner, corner};
|
shape.vertices = {corner, corner};
|
||||||
}
|
}
|
||||||
return shape;
|
return shape;
|
||||||
@@ -1103,9 +1107,11 @@ join_result join(join_request const &Request)
|
|||||||
auto const enddirection{glm::normalize(b.direction)};
|
auto const enddirection{glm::normalize(b.direction)};
|
||||||
join_frame const frame{Request, startdirection, enddirection, chord, distance, glm::radians(Request.kink), std::abs(geometry::signed_angle(startdirection, enddirection)), b.position.y - a.position.y};
|
join_frame const frame{Request, startdirection, enddirection, chord, distance, glm::radians(Request.kink), std::abs(geometry::signed_angle(startdirection, enddirection)), b.position.y - a.position.y};
|
||||||
std::vector<join_result> candidates;
|
std::vector<join_result> candidates;
|
||||||
|
std::vector<join_result> kinked;
|
||||||
for (auto const &candidate : {straight_join(frame), arc_join(frame), curve_join(frame)})
|
for (auto const &candidate : {straight_join(frame), arc_join(frame), curve_join(frame)})
|
||||||
if (candidate.has_value())
|
if (candidate.has_value())
|
||||||
candidates.push_back(*candidate);
|
(candidate->kink > 0.1 * frame.tolerance ? kinked : candidates).push_back(*candidate);
|
||||||
|
candidates.insert(candidates.end(), kinked.begin(), kinked.end());
|
||||||
if (candidates.empty())
|
if (candidates.empty())
|
||||||
candidates.push_back(bezier_join(frame));
|
candidates.push_back(bezier_join(frame));
|
||||||
auto const count{static_cast<int>(candidates.size())};
|
auto const count{static_cast<int>(candidates.size())};
|
||||||
@@ -1253,12 +1259,36 @@ std::vector<segment_data> pieces(result const &Result, design const &Design, std
|
|||||||
auto const chainage_from = [&](span const &Span) { return Span.generic ? Span.start : Result.elements[Span.element].chainage + Span.from; };
|
auto const chainage_from = [&](span const &Span) { return Span.generic ? Span.start : Result.elements[Span.element].chainage + Span.from; };
|
||||||
auto const chainage_to = [&](span const &Span) { return Span.generic ? Span.end : Result.elements[Span.element].chainage + Span.to; };
|
auto const chainage_to = [&](span const &Span) { return Span.generic ? Span.end : Result.elements[Span.element].chainage + Span.to; };
|
||||||
std::vector<span> spans;
|
std::vector<span> spans;
|
||||||
|
std::optional<double> lead;
|
||||||
for (std::size_t i = 0; i < Result.elements.size(); ++i)
|
for (std::size_t i = 0; i < Result.elements.size(); ++i)
|
||||||
{
|
{
|
||||||
auto const &e{Result.elements[i]};
|
auto const &e{Result.elements[i]};
|
||||||
auto const count{element_pieces(e, Design.shape, Design.transition_pieces, Design.arc_piece_angle)};
|
auto const count{element_pieces(e, Design.shape, Design.transition_pieces, Design.arc_piece_angle)};
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
if (e.length <= 0.0)
|
||||||
|
continue;
|
||||||
|
if (spans.empty())
|
||||||
|
{
|
||||||
|
lead = lead.value_or(e.chainage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto &previous{spans.back()};
|
||||||
|
previous.start = chainage_from(previous);
|
||||||
|
previous.end = e.chainage + e.length;
|
||||||
|
previous.generic = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (std::size_t j = 0; j < count; ++j)
|
for (std::size_t j = 0; j < count; ++j)
|
||||||
spans.push_back({i, e.length * j / count, e.length * (j + 1) / count});
|
spans.push_back({i, e.length * j / count, e.length * (j + 1) / count});
|
||||||
|
if (lead.has_value())
|
||||||
|
{
|
||||||
|
auto &first{spans[spans.size() - count]};
|
||||||
|
first.end = chainage_to(first);
|
||||||
|
first.start = *lead;
|
||||||
|
first.generic = true;
|
||||||
|
lead.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
double const shortest{1.0};
|
double const shortest{1.0};
|
||||||
for (std::size_t i = 0; i < spans.size() && spans.size() > 1;)
|
for (std::size_t i = 0; i < spans.size() && spans.size() > 1;)
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ struct join_result
|
|||||||
double cant{0.0};
|
double cant{0.0};
|
||||||
double transition{0.0};
|
double transition{0.0};
|
||||||
double speed{0.0};
|
double speed{0.0};
|
||||||
|
double kink{0.0};
|
||||||
int variants{0};
|
int variants{0};
|
||||||
std::vector<std::string> warnings;
|
std::vector<std::string> warnings;
|
||||||
std::vector<std::string> radius_warnings;
|
std::vector<std::string> radius_warnings;
|
||||||
|
|||||||
Reference in New Issue
Block a user