43 #include <ilqgames/gui/control_sliders.h> 44 #include <ilqgames/gui/top_down_renderer.h> 45 #include <ilqgames/utils/operating_point.h> 46 #include <ilqgames/utils/solver_log.h> 47 #include <ilqgames/utils/types.h> 49 #include <imgui/imgui.h> 58 static constexpr
float kPixelsToZoomConversion = 1.0 / 20.0;
59 static constexpr
float kMinZoom = 2.0;
62 void TopDownRenderer::Render() {
64 const auto& logs = sliders_->LogForEachProblem();
67 if (sliders_->MaxLogIndex() == 1)
return;
70 std::vector<size_t> num_agents(problems_.size());
72 problems_.begin(), problems_.end(), num_agents.begin(),
73 [](
const std::shared_ptr<const TopDownRenderableProblem>& problem) {
74 return problem->Dynamics()->NumPlayers();
78 ImGui::Begin(
"Top-Down View");
82 const ImVec2 mouse_position = ImGui::GetMousePos();
83 if (ImGui::BeginChild(
"User Guide")) {
84 ImGui::TextUnformatted(
"Press \"c\" key to enable navigation.");
85 ImGui::TextUnformatted(
"Press \"z\" key to change zoom.");
87 const Point2 mouse_point = WindowCoordinatesToPosition(mouse_position);
88 ImGui::Text(
"Mouse is at: (%3.1f, %3.1f)", mouse_point.x(),
94 constexpr
bool kCatchRepeats =
false;
95 if (ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_C], kCatchRepeats) ||
96 ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Z], kCatchRepeats))
97 last_mouse_position_ = mouse_position;
98 else if (ImGui::IsKeyReleased(ImGui::GetIO().KeyMap[ImGuiKey_C])) {
101 PixelsToLength(mouse_position.x - last_mouse_position_.x);
103 PixelsToLength(mouse_position.y - last_mouse_position_.y);
104 }
else if (ImGui::IsKeyReleased(ImGui::GetIO().KeyMap[ImGuiKey_Z])) {
106 const float mouse_delta_y = mouse_position.y - last_mouse_position_.y;
107 pixel_to_meter_ratio_ =
108 std::max(kMinZoom, pixel_to_meter_ratio_ -
109 kPixelsToZoomConversion * mouse_delta_y);
113 ImDrawList* draw_list = ImGui::GetWindowDrawList();
114 const ImU32 trajectory_color = ImColor(ImVec4(1.0, 1.0, 1.0, 0.5));
115 const float trajectory_thickness = std::min(1.0f, LengthToPixels(0.5));
118 for (
size_t problem_idx = 0; problem_idx < problems_.size(); problem_idx++) {
119 const auto& problem = problems_[problem_idx];
120 const auto& log = logs[problem_idx];
123 std::vector<ImVec2> points(time::kNumTimeSteps);
124 for (
size_t ii = 0; ii < num_agents[problem_idx]; ii++) {
125 for (
size_t kk = 0; kk < time::kNumTimeSteps; kk++) {
126 const VectorXf x = log->State(sliders_->SolverIterate(problem_idx), kk);
128 PositionToWindowCoordinates(problem->Xs(x)[ii], problem->Ys(x)[ii]);
131 constexpr
bool kPolylineIsClosed =
false;
132 draw_list->AddPolyline(points.data(), time::kNumTimeSteps,
133 trajectory_color, kPolylineIsClosed,
134 trajectory_thickness);
139 constexpr
float kMinGreen = 0.15;
140 constexpr
float kMaxGreen = 1.0 - kMinGreen;
141 const float color_scaling = (1.0 - 2.0 * kMinGreen) *
142 static_cast<float>(problem_idx + 1) /
143 static_cast<float>(problems_.size());
145 const ImU32 agent_color =
146 ImColor(ImVec4(0.15, kMinGreen + color_scaling,
147 kMinGreen + kMaxGreen - color_scaling, 1.0));
148 const float agent_radius = std::max(5.0f, LengthToPixels(2.5));
149 const float agent_base = std::max(6.0f, LengthToPixels(2.5));
150 const float agent_height = std::max(10.0f, LengthToPixels(3.0));
154 const VectorXf current_x =
155 log->InterpolateState(sliders_->SolverIterate(problem_idx),
156 sliders_->InterpolationTime(problem_idx));
157 const std::vector<float> current_pxs = problem->Xs(current_x);
158 const std::vector<float> current_pys = problem->Ys(current_x);
159 const std::vector<float> current_thetas = problem->Thetas(current_x);
160 for (
size_t ii = 0; ii < num_agents[problem_idx]; ii++) {
162 PositionToWindowCoordinates(current_pxs[ii], current_pys[ii]);
164 if (ii >= current_thetas.size()) {
165 VLOG(2) <<
"More players than coordinates to visualize.";
168 const float heading = HeadingToWindowCoordinates(current_thetas[ii]);
169 const float cheading = std::cos(heading);
170 const float sheading = std::sin(heading);
174 const ImVec2 top(p.x + agent_height * cheading,
175 p.y + agent_height * sheading);
176 const ImVec2 bl(p.x - 0.5 * agent_base * sheading,
177 p.y + 0.5 * agent_base * cheading);
178 const ImVec2 br(p.x + 0.5 * agent_base * sheading,
179 p.y - 0.5 * agent_base * cheading);
181 draw_list->AddTriangleFilled(bl, br, top, agent_color);
182 draw_list->AddCircle(p, agent_radius, agent_color);
190 inline float TopDownRenderer::CurrentZoomLevel()
const {
191 float conversion = pixel_to_meter_ratio_;
194 if (ImGui::IsKeyDown(ImGui::GetIO().KeyMap[ImGuiKey_Z])) {
195 const float mouse_delta_y = ImGui::GetMousePos().y - last_mouse_position_.y;
196 conversion = std::max(kMinZoom,
197 conversion - kPixelsToZoomConversion * mouse_delta_y);
203 inline ImVec2 TopDownRenderer::PositionToWindowCoordinates(
float x,
205 ImVec2 coords = WindowCenter();
208 if (ImGui::IsKeyDown(ImGui::GetIO().KeyMap[ImGuiKey_C])) {
209 const ImVec2 mouse_position = ImGui::GetMousePos();
210 x += PixelsToLength(mouse_position.x - last_mouse_position_.x);
211 y -= PixelsToLength(mouse_position.y - last_mouse_position_.y);
214 coords.x += LengthToPixels(x + center_delta_.x);
215 coords.y -= LengthToPixels(y + center_delta_.y);
219 inline Point2 TopDownRenderer::WindowCoordinatesToPosition(
220 const ImVec2& coords)
const {
221 const ImVec2 center = WindowCenter();
224 const float x = PixelsToLength(coords.x - center.x) - center_delta_.x;
225 const float y = PixelsToLength(center.y - coords.y) - center_delta_.y;
229 inline ImVec2 TopDownRenderer::WindowCenter()
const {
230 const ImVec2 window_pos = ImGui::GetWindowPos();
231 const float window_width = ImGui::GetWindowWidth();
232 const float window_height = ImGui::GetWindowHeight();
234 const float center_x = window_pos.x + 0.5 * window_width;
235 const float center_y = window_pos.y + 0.5 * window_height;
236 return ImVec2(center_x, center_y);