mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-29 22:07:28 +01:00
fix(editor): the track shown while it's laid over the ground no longer holds up the frames: its grade line is fitted on a thread of its own, the line fitted a moment ago stretched over the track meanwhile, and the click takes the line fitted for the same ground instead of fitting it again; the terrain follows the tracks once the laying ends, not after each click of a chain
Fitting the grade line took 3 ms for 250 m of track, 30 ms for 1 km, 65 ms for 2 km and 200 ms for 4 km, and the preview of the lay tool and of the drag from a free end fitted it every frame, twice for the drag; on the terrain model the preview of some 800 m took 10 to 17 ms a frame, the cursor standing or not. Now the frame waits under 1.5 ms for 4 km. The formations of the tracks led into the terrain went through every chunk under them 0.3 s after each click, some 50 ms, while the cursor went on to the next point; they wait for the laying to end. The tracks laid and the terrain are the same as before. Selftests: perf logs the longest frame and those over 33 ms, fittime the time of the fit by length, terrainhash a hash of the chunks in memory.
This commit is contained in:
@@ -39,6 +39,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "editor/editorSpeed.hpp"
|
||||
#include "editor/editorRoad.hpp"
|
||||
#include "editor/editorProfile.hpp"
|
||||
#include "editor/editorGroundFollow.hpp"
|
||||
#include "editor/editorInfra.hpp"
|
||||
#include "editor/editorGauge.hpp"
|
||||
#include "editor/editorClips.hpp"
|
||||
@@ -1512,6 +1513,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
bool start_extend(editor_track::snap_target const &End);
|
||||
void finish_extend();
|
||||
std::vector<segment_data> extend_pieces() const;
|
||||
// the same for the track shown while it's dragged: its grade line fitted on the thread of the fitter, the frame not waiting for it
|
||||
std::vector<segment_data> extend_preview() const;
|
||||
// the free end of the path as the start of a new track; false if it isn't free or has no direction
|
||||
static bool free_end(TTrack &Track, int const Path, bool const Atend, extend_tool &Tool);
|
||||
// the free end new pieces are added at: the selected point if it's one, else the end, else the start
|
||||
@@ -1732,6 +1735,10 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
static std::pair<double, double> trackbed(TTrack const *Style);
|
||||
std::vector<double> bed_heights(std::vector<glm::dvec3> const &Points, std::vector<glm::dvec2> const &Directions, TTrack const *Style) const;
|
||||
void follow_ground(std::vector<segment_data> &Pieces, double const Height0, double const Grade0, double const Height1, double const Grade1, TTrack const *Style) const;
|
||||
ground_follow::grading laying_grading(TTrack const *Style) const;
|
||||
// the grade lines of the tracks shown while they're laid are fitted on a thread of their own, not to hold up the frames
|
||||
mutable ground_follow::fitter m_fitter;
|
||||
mutable bool m_follow_preview{false};
|
||||
glm::dvec3 lay_bed(glm::dvec3 const &Point);
|
||||
std::optional<glm::dvec3> m_cursor_override;
|
||||
bool sweep_grabs(glm::dvec3 const &Point);
|
||||
|
||||
@@ -101,7 +101,9 @@ void editor_mode::update_build_tools()
|
||||
if (plan_distance(lay.mouse, points.back()) > 1.0)
|
||||
points.push_back(lay.mouse);
|
||||
}
|
||||
m_follow_preview = true;
|
||||
lay.preview = lay_pieces(points, end, lay.preview_length, lay.preview_error);
|
||||
m_follow_preview = false;
|
||||
}
|
||||
|
||||
bool editor_mode::free_end(TTrack &Track, int const Path, bool const Atend, extend_tool &Tool)
|
||||
@@ -490,6 +492,14 @@ std::vector<segment_data> editor_mode::extend_pieces() const
|
||||
return pieces;
|
||||
}
|
||||
|
||||
std::vector<segment_data> editor_mode::extend_preview() const
|
||||
{
|
||||
m_follow_preview = true;
|
||||
auto pieces{extend_pieces()};
|
||||
m_follow_preview = false;
|
||||
return pieces;
|
||||
}
|
||||
|
||||
TTrack const *editor_mode::speed_track(TTrack const *From, TTrack const *To) const
|
||||
{
|
||||
if (m_lay.own_speed && m_lay.style.velocity > 0.0)
|
||||
|
||||
@@ -691,6 +691,10 @@ void editor_mode::nmt_follow_tracks()
|
||||
return;
|
||||
if (state.stage != nmt_state::automatic::idle || state.fitting || ImGui::GetTime() - state.changed_time < 0.3 || ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right))
|
||||
return;
|
||||
// laying on, from the end of the track laid or dragged from a free end, the terrain waits for the laying to end: shaping it
|
||||
// goes through every chunk under the tracks, a stall each click
|
||||
if ((m_lay.active && false == m_lay.points.empty()) || m_extend.active)
|
||||
return;
|
||||
if (false == m_streamer.active())
|
||||
{
|
||||
state.changed.clear();
|
||||
|
||||
@@ -151,7 +151,11 @@ editor_mode::selftest_result editor_mode::selftest_dispatch(std::string const &c
|
||||
// screenshot
|
||||
// save
|
||||
// log <text>
|
||||
// perf <label> the frames drawn since the last perf and the time per frame logged, with the timings and counts of the renderer
|
||||
// perf <label> the frames drawn since the last perf and the time per frame logged, the longest frame and those over 33 ms,
|
||||
// with the timings and counts of the renderer
|
||||
// fittime <metres>... the grade line of a straight over rolling ground of each length fitted, as at a click, and the time the
|
||||
// frame waits for it while the track is laid, the line fitted on the thread of the fitter
|
||||
// terrainhash a hash of the heights of the terrain chunks in memory, to compare the ground two builds made
|
||||
// rebuildall the geometry of every path in the sections made already laid anew, the time it took logged,
|
||||
// and the 3d sleepers of all the tracks laid anew, timed apart
|
||||
// sleepercheck the 3d sleepers of all the tracks checked for beams over each other and rails without enough under them
|
||||
@@ -177,6 +181,16 @@ void editor_mode::selftest_step()
|
||||
set_norms_free(true);
|
||||
}
|
||||
++editor_selftest::frames();
|
||||
// how long each frame took, for the longest one perf tells
|
||||
{
|
||||
static auto last{std::chrono::steady_clock::now()};
|
||||
auto const now{std::chrono::steady_clock::now()};
|
||||
auto const frame{std::chrono::duration<double, std::milli>(now - last).count()};
|
||||
last = now;
|
||||
editor_selftest::frame_longest() = std::max(editor_selftest::frame_longest(), frame);
|
||||
if (frame > 33.0)
|
||||
++editor_selftest::frames_slow();
|
||||
}
|
||||
if (test.wait > 0)
|
||||
{
|
||||
--test.wait;
|
||||
|
||||
@@ -24,6 +24,19 @@ inline std::size_t &frames()
|
||||
return count;
|
||||
}
|
||||
|
||||
// the longest frame since the last perf, and the frames longer than 33 ms
|
||||
inline double &frame_longest()
|
||||
{
|
||||
static double value{0.0};
|
||||
return value;
|
||||
}
|
||||
|
||||
inline std::size_t &frames_slow()
|
||||
{
|
||||
static std::size_t count{0};
|
||||
return count;
|
||||
}
|
||||
|
||||
inline std::string one_line(std::string Text)
|
||||
{
|
||||
std::replace(Text.begin(), Text.end(), '\n', ';');
|
||||
|
||||
@@ -129,6 +129,35 @@ editor_mode::selftest_result editor_mode::selftest_join(std::string const &comma
|
||||
WriteLog(format("SELFTEST %s end: %.3f m from the target", command.c_str(), geometry::plan_distance(previous, b)));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "fittime")
|
||||
{
|
||||
// the grade line of a straight laid over rolling ground fitted, as at a click, and as while the track follows the
|
||||
// cursor: the frame then waits only for the ground to be sampled
|
||||
for (double length{0.0}; words >> length;)
|
||||
{
|
||||
auto const ground = [](double const X) { return 130.0 + 4.0 * std::sin(X / 180.0) + 1.5 * std::sin(X / 37.0) + 0.2 * std::sin(X / 6.0); };
|
||||
auto const bed = [&](std::vector<glm::dvec3> const &Points, std::vector<glm::dvec2> const &) {
|
||||
std::vector<double> heights;
|
||||
for (auto const &point : Points)
|
||||
heights.push_back(ground(point.x));
|
||||
return heights;
|
||||
};
|
||||
auto const pieces{geometry::straight_piece({0.0, ground(0.0), 0.0}, {1.0, 0.0}, 0.0, length)};
|
||||
ground_follow::ends const ends{ground(0.0), std::numeric_limits<double>::quiet_NaN(), ground(length), std::numeric_limits<double>::quiet_NaN()};
|
||||
auto const grading{laying_grading(nullptr)};
|
||||
auto fitted{pieces};
|
||||
auto const start{std::chrono::steady_clock::now()};
|
||||
ground_follow::follow(fitted, ends, bed, grading);
|
||||
auto const fit{std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - start).count()};
|
||||
ground_follow::fitter fitter;
|
||||
auto shown{pieces};
|
||||
auto const asked{std::chrono::steady_clock::now()};
|
||||
ground_follow::follow_meanwhile(shown, ends, bed, grading, fitter);
|
||||
auto const meanwhile{std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - asked).count()};
|
||||
WriteLog(format("SELFTEST fittime %.0f m: fitted in %.1f ms, %zu pieces; while laid %.2f ms", length, fit, fitted.size(), meanwhile));
|
||||
}
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "layheights")
|
||||
{
|
||||
std::string which;
|
||||
|
||||
@@ -113,9 +113,11 @@ editor_mode::selftest_result editor_mode::selftest_scene(std::string const &comm
|
||||
auto const now{std::chrono::steady_clock::now()};
|
||||
auto const frames{editor_selftest::frames() - lastframe};
|
||||
auto const elapsed{std::chrono::duration<double, std::milli>(now - last).count()};
|
||||
WriteLog(format("SELFTEST perf %s: %zu frames, %.3f ms per frame | %s | %s", label.c_str(), frames, frames > 0 ? elapsed / frames : 0.0, editor_selftest::one_line(GfxRenderer->info_times()).c_str(), editor_selftest::one_line(GfxRenderer->info_stats()).c_str()));
|
||||
WriteLog(format("SELFTEST perf %s: %zu frames, %.3f ms per frame, the longest %.1f ms, %zu over 33 ms | %s | %s", label.c_str(), frames, frames > 0 ? elapsed / frames : 0.0, editor_selftest::frame_longest(), editor_selftest::frames_slow(), editor_selftest::one_line(GfxRenderer->info_times()).c_str(), editor_selftest::one_line(GfxRenderer->info_stats()).c_str()));
|
||||
last = now;
|
||||
lastframe = editor_selftest::frames();
|
||||
editor_selftest::frame_longest() = 0.0;
|
||||
editor_selftest::frames_slow() = 0;
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "rebuildall")
|
||||
|
||||
@@ -42,6 +42,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
@@ -470,6 +471,23 @@ editor_mode::selftest_result editor_mode::selftest_terrain(std::string const &co
|
||||
WriteLog("SELFTEST terrainadd: " + m_terrain_status);
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "terrainhash")
|
||||
{
|
||||
// the heights of the chunks in memory hashed, to compare the ground two builds made
|
||||
std::vector<editor_terrain *> chunks;
|
||||
m_streamer.collect(chunks);
|
||||
std::sort(chunks.begin(), chunks.end(), [](editor_terrain const *A, editor_terrain const *B) { return A->key() < B->key(); });
|
||||
std::uint64_t hash{1469598103934665603ull};
|
||||
for (auto const *chunk : chunks)
|
||||
for (auto const height : chunk->heights())
|
||||
{
|
||||
std::uint32_t bits;
|
||||
std::memcpy(&bits, &height, sizeof(bits));
|
||||
hash = (hash ^ bits) * 1099511628211ull;
|
||||
}
|
||||
WriteLog(format("SELFTEST terrainhash: %zu chunks, %016llx", chunks.size(), static_cast<unsigned long long>(hash)));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "terrainprobe")
|
||||
{
|
||||
double x{0.0};
|
||||
|
||||
@@ -1832,7 +1832,7 @@ std::string editor_mode::track_readout() const
|
||||
{
|
||||
double length{0.0};
|
||||
double radius{0.0};
|
||||
auto const pieces{extend_pieces()};
|
||||
auto const pieces{extend_preview()};
|
||||
for (auto const &piece : pieces)
|
||||
{
|
||||
length += bezier{piece}.plan_length();
|
||||
@@ -2238,7 +2238,7 @@ void editor_mode::draw_build_overlay() const
|
||||
ImVec2 screen;
|
||||
if (projection.project(target.position, screen))
|
||||
drawlist->AddCircle(screen, 14.0f, IM_COL32(255, 60, 255, 255), 20, 3.0f);
|
||||
for (auto const &piece : extend_pieces())
|
||||
for (auto const &piece : extend_preview())
|
||||
drawpath(piece, overlay_color::marked);
|
||||
}
|
||||
else if (plan_crossover(plan))
|
||||
@@ -2249,7 +2249,7 @@ void editor_mode::draw_build_overlay() const
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto const &piece : extend_pieces())
|
||||
for (auto const &piece : extend_preview())
|
||||
drawpath(piece, overlay_color::marked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,16 @@ void editor_mode::follow_ground(std::vector<segment_data> &Pieces, double const
|
||||
ground_follow::follow(Pieces, {Height0, Grade0, Height1, Grade1}, [](std::vector<glm::dvec3> const &Points, std::vector<glm::dvec2> const &) { return std::vector<double>(Points.size(), std::numeric_limits<double>::quiet_NaN()); });
|
||||
return;
|
||||
}
|
||||
auto const grading{laying_grading(Style)};
|
||||
auto const bed = [&](std::vector<glm::dvec3> const &Points, std::vector<glm::dvec2> const &Directions) { return bed_heights(Points, Directions, Style); };
|
||||
if (m_follow_preview)
|
||||
ground_follow::follow_meanwhile(Pieces, {Height0, Grade0, Height1, Grade1}, bed, grading, m_fitter);
|
||||
else
|
||||
ground_follow::follow(Pieces, {Height0, Grade0, Height1, Grade1}, bed, grading, &m_fitter);
|
||||
}
|
||||
|
||||
ground_follow::grading editor_mode::laying_grading(TTrack const *Style) const
|
||||
{
|
||||
// the line goes over the ground as the tracks go onto the terrain: the vertical curves of the norms, the grades as steep as the
|
||||
// ground has them, a rise or a hollow longer than a structure followed closely, the bumps and what parts from it gone past
|
||||
ground_follow::grading grading;
|
||||
@@ -148,7 +158,7 @@ void editor_mode::follow_ground(std::vector<segment_data> &Pieces, double const
|
||||
grading.fit.follow_steepest = 100.0;
|
||||
grading.fit.follow_tolerance = 0.05;
|
||||
grading.reach = kModel;
|
||||
ground_follow::follow(Pieces, {Height0, Grade0, Height1, Grade1}, [&](std::vector<glm::dvec3> const &Points, std::vector<glm::dvec2> const &Directions) { return bed_heights(Points, Directions, Style); }, grading);
|
||||
return grading;
|
||||
}
|
||||
|
||||
glm::dvec3 editor_mode::lay_bed(glm::dvec3 const &Point)
|
||||
|
||||
Reference in New Issue
Block a user