/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "stdafx.h" #include "application/editormode.h" #include "editor/editorSettings.hpp" #include "editor/editorGeometry.hpp" #include "application/application.h" #include "application/editoruilayer.h" #include "application/editorprojection.h" #include "simulation/simulation.h" #include "simulation/simulationtime.h" #include "scene/scenelayers.h" #include "utilities/Globals.h" #include "utilities/Logs.h" #include "world/Track.h" #include "world/TrackRails.h" #include "world/MemCell.h" #include "world/Event.h" #include "vehicle/DynObj.h" #include "model/AnimModel.h" #include "model/Model3d.h" #include "rendering/renderer.h" #include "world/Sweep.h" #include "input/keyboardinput.h" #include "launcher/textures_scanner.h" #include #include #include #include "editor/editorFormat.hpp" #include "editor/editorAlignmentStore.hpp" #include "editor/editorSwitchStore.hpp" #include "scene/sceneterrain.h" #include "editor/editorSpeed.hpp" #include #include #include #include #include #include #include "application/editormodeselftest.h" editor_mode::selftest_result editor_mode::selftest_sweep(std::string const &command, std::istringstream &words) { if (command == "sweep") { auto values{selftest_values(words)}; auto &tool{m_sweep}; auto const get = [&](char const *Key, std::string const &Default) { auto const found{values.find(Key)}; return found != values.end() ? found->second : Default; }; tool.edited = nullptr; tool.curve_for = nullptr; std::snprintf(tool.model, sizeof(tool.model), "%s", get("model", "").c_str()); tool.parameters.clear(); std::stringstream parameters(get("params", "")); std::string parameter; while (std::getline(parameters, parameter, ',')) { tool.parameters.emplace_back(); std::snprintf(tool.parameters.back().data(), tool.parameters.back().size(), "%s", parameter.c_str()); } tool.parameters_for = tool.model; auto &settings{tool.settings}; settings.lateral = std::stod(get("lateral", "0")); settings.height = std::stod(get("height", "0")); auto const side{get("side", "origin")}; settings.side_anchor = side == "near" ? 1 : side == "far" ? 2 : side == "centre" ? 3 : 0; auto const top{get("top", "origin")}; settings.height_anchor = top == "bottom" ? 1 : top == "top" ? 2 : top == "edge" ? 3 : 0; settings.bend = get("mode", "bend") != "repeat"; settings.step = std::stod(get("step", "0")); settings.widen = get("widen", "0") == "1"; settings.platform = get("platform", "0") == "1"; settings.face = get("face", "1") == "1"; settings.tilt = get("tilt", "0") == "1"; settings.from = std::stod(get("from", "0")); settings.to = std::stod(get("to", "-1")); auto const length{get("length", "all")}; tool.length_mode = length == "original" ? 0 : length == "all" ? 2 : 1; if (tool.length_mode == 1) tool.length = std::stod(length); if (values.count("edge")) EditorSettings.platform_edge(std::stod(values["edge"])); tool.measured.clear(); tool.open = true; sweep_curve(); sweep_measure(); if (values.count("widen")) settings.widen = get("widen", "0") == "1"; if (values.count("platform")) settings.platform = get("platform", "0") == "1"; if (get("create", "1") == "1") { sweep_create(); WriteLog("SELFTEST sweep: " + tool.status); } return selftest_result::handled; } if (command == "drag") { glm::dvec3 from{0.0}; glm::dvec3 to{0.0}; words >> from.x >> from.z >> to.x >> to.z; m_sweep.open = true; if (false == sweep_press_at(from, false)) { WriteLog("SELFTEST drag: the press wasn't taken"); return selftest_result::handled; } sweep_drag_at(to); sweep_release(); WriteLog("SELFTEST drag: " + m_sweep.status); return selftest_result::handled; } if (command == "spread") { std::string name; words >> name >> m_spread.stop >> m_spread.reach; if (auto *track{simulation::Paths.find(name)}) { std::string names; for (auto const *other : track_spread_from(*track)) names += ' ' + other->name(); WriteLog("SELFTEST spread " + name + ":" + names + " | prev " + (track->trPrev ? track->trPrev->name() : std::string{"-"}) + " next " + (track->trNext ? track->trNext->name() : std::string{"-"})); } return selftest_result::handled; } if (command == "turntable") { glm::dvec3 centre{0.0}; double yaw{0.0}; words >> centre.x >> centre.y >> centre.z >> yaw; turntable_place(centre, yaw); for (double angle; words >> angle;) { m_turntable.heading = m_turntable.table_yaw + angle; m_turntable.exit_length = 10.0; track_intent intent; intent.what = track_intent::kind::turntable_exit; turntable_press(intent); } WriteLog("SELFTEST turntable: " + (m_turntable.error.empty() ? m_turntable.status : m_turntable.error)); return selftest_result::handled; } if (command == "bend" || command == "bendset") { auto values{selftest_values(words)}; auto const vector = [](std::string Text) { std::replace(Text.begin(), Text.end(), ',', ' '); std::istringstream numbers(Text); glm::dvec3 result{0.0}; numbers >> result.x >> result.y >> result.z; return result; }; auto const index = [](std::string const &Text, std::vector const &Names) { return static_cast(std::find(Names.begin(), Names.end(), Text) - Names.begin()); }; auto &tool{m_bend}; auto const along{values.count("along") ? index(values["along"], {"start", "origin", "middle", "end", "point"}) : tool.along_anchor}; auto const side{values.count("side") ? index(values["side"], {"origin", "near", "far", "middle", "point"}) : tool.side_anchor}; auto const height{values.count("height") ? index(values["height"], {"origin", "bottom", "top", "edge", "point"}) : tool.height_anchor}; auto const point{values.count("point") ? vector(values["point"]) : tool.point}; if (command == "bend") { tool.edited = nullptr; tool.along_anchor = along; tool.side_anchor = side; tool.height_anchor = height; tool.point = point; tool.axis = values.count("axis") ? index(values["axis"], {"auto", "z", "x"}) : 0; tool.turned = values["turned"] == "1"; bend_source source; if (false == bend_source_of_selection(source)) { std::string reason; auto const editable{m_node != nullptr && scene::Layers.editable(m_node, &reason)}; WriteLog(format("SELFTEST bend: nothing to bend (node %p template %d editable %d %s, instance %d)", static_cast(m_node), m_node != nullptr && m_node->from_template() ? 1 : 0, editable ? 1 : 0, reason.c_str(), static_cast(m_instance))); return selftest_result::handled; } tool.tracks_for = nullptr; bend_find_tracks(glm::dvec3(source.transform[3]), source.model != nullptr ? static_cast(source.model) : reinterpret_cast(static_cast(source.instance))); tool.track = values.count("track") ? std::stoi(values["track"]) : 0; if (values.count("pick")) bend_pick(vector(values["pick"])); if (tool.tracks.empty()) { WriteLog("SELFTEST bend: no track nearby"); return selftest_result::handled; } sweep_node::state state; std::vector tracks; bend_definition(source, *tool.tracks[tool.track].first, state, tracks); WriteLog(format("SELFTEST bend: track %s, %zu paths, anchor before %.3f %.3f %.3f, lateral %.3f height %.3f from %.3f to %.3f, axis %s flip %d; %s", tool.tracks[tool.track].first->name().c_str(), tracks.size(), tool.marker.x, tool.marker.y, tool.marker.z, state.lateral, state.height, state.from, state.to, state.along_x ? "x" : "z", state.flip ? 1 : 0, tool.status.c_str())); if (values["go"] == "1") { bend_selection(); WriteLog("SELFTEST bend: " + tool.status); } } else if (auto *sweep{tool.edited}) { auto state{sweep->definition()}; tool.along_anchor = along; if (side != tool.side_anchor || height != tool.height_anchor || point != tool.point) { tool.side_anchor = side; tool.height_anchor = height; tool.point = point; bend_reanchor(state, side, height, point); } if (values.count("lateral")) state.lateral = std::stod(values["lateral"]); if (values.count("up")) state.height = std::stod(values["up"]); if (values.count("widen")) state.widen = values["widen"] == "1"; if (values.count("pick")) { bend_pick(vector(values["pick"])); state = sweep->definition(); } if (values.count("length")) { bend_stretch(*sweep, bend_fixed(*sweep, state.point), std::stod(values["length"]), state.point, state); } bend_edit(state); WriteLog("SELFTEST bendset done"); } return selftest_result::handled; } if (command == "bendprobe") { auto *sweep{m_bend.edited}; if (sweep == nullptr) { WriteLog("SELFTEST bendprobe: nothing bent"); return selftest_result::handled; } glm::dvec3 low; glm::dvec3 high; glm::dvec3 shift; sweep->bounds(low, high, shift); auto const &state{sweep->definition()}; auto const marker{bend_marker(*sweep)}; glm::dvec3 boxlow{std::numeric_limits::max()}; glm::dvec3 boxhigh{-std::numeric_limits::max()}; std::size_t vertices{0}; for (auto const &shape : sweep->create_shapes()) for (auto const &vertex : shape.data().vertices) { boxlow = glm::min(boxlow, vertex.position); boxhigh = glm::max(boxhigh, vertex.position); ++vertices; } WriteLog(format("SELFTEST bendprobe %s: stations %.3f - %.3f, along the reference line %.3f m, model %.3f m, lateral %.3f height %.3f anchors %d/%d point %.3f %.3f %.3f, marker %.3f %.3f %.3f, box %.2f %.2f %.2f - %.2f %.2f %.2f, %zu vertices, removed %d", sweep->name().c_str(), sweep->start(), sweep->end(), sweep->distance_at(sweep->end()) - sweep->distance_at(sweep->start()), high.x - low.x, state.lateral, state.height, state.side_anchor, state.height_anchor, state.point.x, state.point.y, state.point.z, marker.x, marker.y, marker.z, boxlow.x, boxlow.y, boxlow.z, boxhigh.x, boxhigh.y, boxhigh.z, vertices, sweep->m_editorremoved ? 1 : 0)); return selftest_result::handled; } if (command == "lineside") { std::string tab; words >> tab; show_track_tab(tab == "parallel" ? track_tab::parallel : track_tab::lineside); (tab == "vehicle" ? m_vehicle.tab().expand : tab == "hekto" ? m_hekto.tab().expand : tab == "fouling" ? m_fouling.tab().expand : m_parallel.tab().expand) = true; return selftest_result::handled; } if (command == "bendpanel") { ui()->expand_bend(); return selftest_result::handled; } if (command == "ttincludes") { std::string name; words >> name; auto const *track{simulation::Paths.find(name)}; WriteLog(format("SELFTEST ttincludes %s: track %s, includes %d", name.c_str(), track == nullptr ? "none" : track->m_editorremoved ? "removed" : "present", track != nullptr ? static_cast(turntable_includes(*track).size()) : -1)); return selftest_result::handled; } if (command == "checkspans") { WriteLog("SELFTEST spans: " + scene::Layers.check_sources()); return selftest_result::handled; } return selftest_result::unhandled; }