GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
result_file_exporter.cpp
[詳解]
1
3
4// Copyright(c) 2023-2025 Design Engineering Laboratory, Saitama University
5// Released under the MIT license
6// https://opensource.org/licenses/mit-license.php
7
9
10#include <format>
11#include <map>
12
13#include <algorithm>
14#include <filesystem>
15
16#include <magic_enum.hpp>
17
18#include "average_calculator.h"
19#include "cmdio_util.h"
20#include "math_util.h"
21#include "map_file_exporter.h"
22#include "stopwatch.h"
23
24
25namespace designlab
26{
27
28namespace sf = ::std::filesystem; // 長すぎるので,filesystemの名前空間を短縮する.
29
30
31const std::string ResultFileConst::kDirectoryPath =
32sf::current_path().string() + "\\" + "result";
33
34const std::string ResultFileConst::kLegDirectoryName = "leg_pos";
35
36const std::string ResultFileConst::kNodeListName = "node_list";
37
38const std::string ResultFileConst::kMapStateName = "map_state";
39
40const std::string ResultFileConst::kDetailFileName = "simulation_result_detail";
41
42const std::string ResultFileConst::kSuccessfulCount = "simulation_successful_count";
43
44
46 const std::shared_ptr<const IHexapodJointCalculator>& calculator_ptr) :
47 calculator_ptr_(calculator_ptr)
48{
49}
50
51
53{
54 using enum OutputDetail;
55
56 // 結果出力先フォルダがなければ作成する.
57 if (!sf::exists(ResultFileConst::kDirectoryPath))
58 {
60 "結果出力先フォルダ {} が存在しないので作成します.",
62
63 sf::create_directory(ResultFileConst::kDirectoryPath);
64 }
65}
66
68{
69 // 結果をセットする.
70 result_list_.push_back(result);
71}
72
74{
75 using enum OutputDetail;
76
77 // 結果出力先フォルダがなければ終了する.
78 if (!sf::exists(ResultFileConst::kDirectoryPath))
79 {
80 CmdIOUtil::Output("出力先フォルダがないので終了します.", kError);
81 return;
82 }
83
84 // 出力先フォルダを作成する.
85 std::string output_folder_path = MakeOutputDirectory();
86
87 // NodeListを出力する.
88 ExportEachNodeList(output_folder_path);
89
90 // MapStateを出力する.
91 ExportEachMapState(output_folder_path);
92
93 // シミュレーション詳細を出力する.
94 ExportEachSimulationDetail(output_folder_path);
95
96 // シミュレーション全体の結果を出力する.
97 ExportSuccessfulCount(output_folder_path);
98
99 // 脚の位置を出力する.
100 ExportEachLegPos(output_folder_path);
101
102 // 脚の位置を出力する.
103 ExportAllLegPos(output_folder_path);
104
105 // 成功したシミュレーションのみを出力する.
106 ExportEachLegPosAllSuccessfulSimulation(output_folder_path);
107
108 // 成功したシミュレーションのみを出力する.
109 ExportAllLegPosAllSuccessfulSimulation(output_folder_path);
110
111 CmdIOUtil::Output("結果の出力が完了しました.", kInfo);
112}
113
114
115std::string ResultFileExporter::MakeOutputDirectory() const
116{
117 using enum OutputDetail;
118
119 CmdIOUtil::Output("フォルダ名を入力してください.", kInfo);
120 const auto input_result = CmdIOUtil::InputDirName();
121
122 Stopwatch stopwatch;
123 const std::string folder_name = std::format("{}\\{}_{}",
125 input_result, stopwatch.GetNowTimeString());
126
127 // 指定されたフォルダを作成する.
128 if (!sf::exists(folder_name))
129 {
130 sf::create_directory(folder_name);
131 CmdIOUtil::Output(std::format("フォルダ {} を作成しました.", folder_name), kInfo);
132 }
133
134 return folder_name;
135}
136
137void ResultFileExporter::ExportEachNodeList(const std::string& path) const
138{
139 using enum OutputDetail;
140
141 CmdIOUtil::Output("NodeListを出力します.", kInfo);
142
143 for (size_t i = 0; i < result_list_.size(); ++i)
144 {
145 // 出力先ファイルを作成する.
146 std::string output_file_name = std::format("{}\\{}{}.csv", path, ResultFileConst::kNodeListName, i + 1);
147
148 std::ofstream ofs(output_file_name);
149
150 // ファイルが作成できなかった場合は,なにも出力しない.
151 if (!ofs)
152 {
153 CmdIOUtil::Output(std::format("ファイル {} を作成できませんでした.", output_file_name), kError);
154 return;
155 }
156
157 for (const auto& j : result_list_[i].graph_search_result_recorder)
158 {
159 ofs << j.result_node << "\n"; // ノードを出力する.
160 }
161
162 ofs.close(); // ファイルを閉じる.
163
164 CmdIOUtil::Output("出力ファイル : " + output_file_name, kInfo);
165 }
166
167 CmdIOUtil::Output("NodeListの出力が完了しました.", kInfo);
168}
169
170void ResultFileExporter::ExportEachMapState(const std::string& path) const
171{
172 using enum designlab::OutputDetail;
173
174 CmdIOUtil::Output("MapStateを出力します.", kInfo);
175
176 for (size_t i = 0; i < result_list_.size(); ++i)
177 {
178 // 出力先ファイルを作成する.
179 std::string output_file_name = std::format("{}\\{}{}.csv", path, ResultFileConst::kMapStateName, i + 1);
180
181 MapFileExporter map_file_exporter;
182
183 if (map_file_exporter.ExportMap(output_file_name, result_list_[i].map_state))
184 {
185 CmdIOUtil::Output("出力ファイル : " + output_file_name, kInfo);
186 }
187 else
188 {
189 CmdIOUtil::Output("出力ファイル : " + output_file_name, kInfo);
190 }
191 }
192
193 CmdIOUtil::Output("MapStateの出力が完了しました.", kInfo);
194}
195
196void ResultFileExporter::ExportEachSimulationDetail(const std::string& path) const
197{
198 using enum designlab::OutputDetail;
199
200 CmdIOUtil::Output("シミュレーション詳細を出力します.", kInfo);
201
202 for (size_t i = 0; i < result_list_.size(); ++i)
203 {
204 // 出力先ファイルを作成する.
205 std::string output_file_name = std::format("{}\\{}{}.csv", path, ResultFileConst::kDetailFileName, i + 1);
206
207 std::ofstream ofs(output_file_name);
208
209 // ファイルが作成できなかった場合は,なにも出力しない.
210 if (!ofs)
211 {
212 CmdIOUtil::Output(std::format("ファイル {} を作成できませんでした.", output_file_name), kError);
213 return;
214 }
215
216 const SimulationResultRecord recorder = result_list_[i];
217
218 // 結果を出力する.
219 ofs << recorder.ToCsvString() << std::endl;
220
221
222 // 時間の統計を出力する.
223
224 double max_time = recorder.graph_search_result_recorder[1].computation_time;
225
226 double min_time = max_time;
227
228 AverageCalculator<double> average_calculator;
229
230 // 最初のノードは除く(計算時間0で固定のため)
231 if (recorder.graph_search_result_recorder.size() > 1)
232 {
233 for (size_t j = 1; j < recorder.graph_search_result_recorder.size(); ++j)
234 {
235 const double time = recorder.graph_search_result_recorder[j].computation_time;
236
237 if (time > max_time) { max_time = time; }
238
239 if (time < min_time) { min_time = time; }
240
241 average_calculator.AddData(time);
242 }
243 }
244
245 ofs << "最大探索時間," << math_util::FloatingPointNumToString(max_time) <<
246 ",[milli_sec]" << std::endl;
247
248 ofs << "最小探索時間," << math_util::FloatingPointNumToString(min_time) <<
249 ",[milli_sec]" << std::endl;
250
251 ofs << "総合探索時間," <<
252 math_util::FloatingPointNumToString(average_calculator.GetSum().value_or(-1.f)) <<
253 ",[milli_sec]" << std::endl;
254
255 ofs << "平均探索時間," <<
256 math_util::FloatingPointNumToString(average_calculator.GetAverage().value_or(-1.f)) <<
257 ",[milli_sec]" << std::endl;
258
259 ofs << "分散," <<
260 math_util::FloatingPointNumToString(average_calculator.GetVariance().value_or(-1.f)) <<
261 ",[milli_sec^2]" << std::endl;
262
263 ofs << "標準偏差," << math_util::FloatingPointNumToString(
264 average_calculator.GetStandardDeviation().value_or(-1.f)) <<
265 ",[milli_sec]" << std::endl;
266
267
268 const double time_1sigma_plus = average_calculator.GetAverage().value_or(-1.f) +
269 average_calculator.GetStandardDeviation().value_or(-1.f);
270
271 const double time_1sigma_minus = (std::max)(
272 average_calculator.GetAverage().value_or(-1.f) -
273 average_calculator.GetStandardDeviation().value_or(-1.f), 0.0);
274
275 ofs << "全データの約68%は" <<
276 math_util::FloatingPointNumToString(time_1sigma_plus) << " [milli_sec]以下で" <<
277 math_util::FloatingPointNumToString(time_1sigma_minus) << " [milli_sec]以上です." <<
278 std::endl << std::endl;
279
280
281 // 移動距離の統計を出力する.
282 if (recorder.graph_search_result_recorder.size() > 1)
283 {
284 float x_move_sum = 0.0f;
285 float y_move_sum = 0.0f;
286 float z_move_sum = 0.0f;
287
288 for (size_t j = 0; j != recorder.graph_search_result_recorder.size() - 1; ++j)
289 {
290 RobotStateNode current_node = recorder.graph_search_result_recorder[j].result_node;
291 RobotStateNode next_node = recorder.graph_search_result_recorder[j + 1].result_node;
292 Vector3 com_dif = next_node.center_of_mass_global_coord - current_node.center_of_mass_global_coord;
293
294 x_move_sum += com_dif.x;
295 y_move_sum += com_dif.y;
296 z_move_sum += com_dif.z;
297 }
298
299 const double x_move_average = x_move_sum /
300 static_cast<double>(recorder.graph_search_result_recorder.size() - 1);
301
302 const double y_move_average = y_move_sum /
303 static_cast<double>(recorder.graph_search_result_recorder.size() - 1);
304
305 const double z_move_average = z_move_sum /
306 static_cast<double>(recorder.graph_search_result_recorder.size() - 1);
307
308 ofs << "X方向総移動距離," << math_util::FloatingPointNumToString(x_move_sum) <<
309 ",[mm]" << std::endl;
310
311 ofs << "Y方向総移動距離," << math_util::FloatingPointNumToString(y_move_sum) <<
312 ",[mm]" << std::endl;
313
314 ofs << "Z方向総移動距離," << math_util::FloatingPointNumToString(z_move_sum) <<
315 ",[mm]" << std::endl;
316
317 ofs << "X方向平均移動距離," << math_util::FloatingPointNumToString(x_move_average) <<
318 ",[mm/動作]" << std::endl;
319
320 ofs << "Y方向平均移動距離," << math_util::FloatingPointNumToString(y_move_average) <<
321 ",[mm/動作]" << std::endl;
322
323 ofs << "Z方向平均移動距離," << math_util::FloatingPointNumToString(z_move_average) <<
324 ",[mm/動作]" << std::endl;
325 }
326
327 ofs.close();
328
329 CmdIOUtil::Output("出力ファイル : " + output_file_name, kInfo);
330 }
331
332 CmdIOUtil::Output("シミュレーション詳細の出力が完了しました.", kInfo);
333}
334
335void ResultFileExporter::ExportSuccessfulCount(const std::string& path) const
336{
337 using enum designlab::OutputDetail;
339
340 CmdIOUtil::Output(std::format("シミュレーション全体の結果を出力します.シミュレーション数 : {}", result_list_.size()), kInfo);
341
342 // 出力先ファイルを作成する.
343 std::string output_file_name = std::format("{}\\{}.csv", path, ResultFileConst::kSuccessfulCount);
344
345 std::ofstream ofs(output_file_name);
346
347 // ファイルが作成できなかった場合は,なにも出力しない.
348 if (!ofs)
349 {
350 CmdIOUtil::Output(std::format("ファイルを作成できませんでした."), kError);
351 return;
352 }
353
354 ofs << "シミュレーション数, " << result_list_.size() << "\n";
355
356 // 成功したシミュレーション数を数える.
357 std::map<enums::SimulationResult, int> result_count;
358
359 for (const auto& i : result_list_)
360 {
361 result_count[i.simulation_result]++;
362 }
363
364 // シミュレーション結果を出力する.
365 ofs << std::format("成功したシミュレーション数, {} \n", result_count[kSuccess]);
366
367 ofs << std::format("失敗したシミュレーション数, {} \n", result_count[kFailureByGraphSearch] + result_count[kFailureByLoopMotion] + result_count[kFailureByNodeLimitExceeded]);
368
369 ofs << std::format("グラフ探索に失敗, {} \n", result_count[kFailureByGraphSearch]);
370
371 ofs << std::format("デッドロックに陥った, {} \n", result_count[kFailureByLoopMotion]);
372
373 ofs << std::format("ノード数制限を超えた, {} \n", result_count[kFailureByNodeLimitExceeded]);
374}
375
376void ResultFileExporter::ExportEachLegPos(const std::string& path) const
377{
378 // ディレクトリを作成する.
379 std::string leg_pos_dir_path = path + "\\" + ResultFileConst::kLegDirectoryName;
380
381 if (!sf::exists(leg_pos_dir_path))
382 {
383 sf::create_directory(leg_pos_dir_path);
384 }
385
386 // ファイルを作成する.
387 for (size_t i = 0; i < result_list_.size(); ++i)
388 {
389 for (int j = 0; j < HexapodConst::kLegNum; j++)
390 {
391 std::string output_file_name = std::format("{}\\simulation{}_leg{}.csv", leg_pos_dir_path, i + 1, j + 1);
392
393 std::ofstream ofs(output_file_name);
394
395 // ファイルが作成できなかった場合は,なにも出力しない.
396 if (!ofs)
397 {
398 CmdIOUtil::Output(std::format("ファイル {} を作成できませんでした.", output_file_name), OutputDetail::kError);
399 return;
400 }
401
402 ofs << GetHeader() << "\n";
403
404 std::optional<Vector3> past_pos;
405
406 for (const auto& recorder : result_list_[i].graph_search_result_recorder)
407 {
408 const Vector3 current_pos = recorder.result_node.leg_pos[j];
409
410 // 変化がない場合はスキップする.
411 if (past_pos.has_value() && current_pos == past_pos) { continue; }
412
413 // 高さが変化している and 平行に移動している場合は中継点も出力する.
414 if (past_pos.has_value() &&
415 current_pos.z != past_pos.value().z &&
416 current_pos.ProjectedXY() != past_pos.value().ProjectedXY())
417 {
418 if (current_pos.z < past_pos.value().z)
419 {
420 const Vector3 relay_point = Vector3(current_pos.x, current_pos.y, past_pos.value().z);
421 const auto joint_state = calculator_ptr_->CalculateJointState(j, relay_point);
422
423 // 接地時.
424 ofs << current_pos.GetLength() << "," << past_pos.value().z << ",true,g," << std::boolalpha << calculator_ptr_->IsValidJointState(j, relay_point, joint_state) << "\n";
425 }
426 else
427 {
428 const Vector3 relay_point = Vector3(past_pos.value().x, past_pos.value().y, current_pos.z);
429 const auto joint_state = calculator_ptr_->CalculateJointState(j, relay_point);
430
431 // 遊脚時.
432 ofs << past_pos.value().GetLength() << "," << current_pos.z << ",true,l," << std::boolalpha << calculator_ptr_->IsValidJointState(j, relay_point, joint_state) << "\n";
433 }
434 }
435
436 const auto joint_state = calculator_ptr_->CalculateJointState(j, current_pos);
437
438 ofs << current_pos.ProjectedXY().GetLength() << "," <<
439 current_pos.z << ",false," << GetLegChangeStatus(past_pos, current_pos) << "," <<
440 std::boolalpha << calculator_ptr_->IsValidJointState(j, current_pos, joint_state) << "\n";
441
442 past_pos = current_pos;
443 }
444 }
445 }
446}
447
448void ResultFileExporter::ExportAllLegPos(const std::string& path) const
449{
450 // ディレクトリを作成する.
451 std::string leg_pos_dir_path = path + "\\" + ResultFileConst::kLegDirectoryName;
452
453 if (!sf::exists(leg_pos_dir_path))
454 {
455 sf::create_directory(leg_pos_dir_path);
456 }
457
458 for (size_t i = 0; i < result_list_.size(); ++i)
459 {
460 std::string output_file_name = std::format("{}\\simulation{}_all_leg.csv", leg_pos_dir_path, i + 1);
461
462 std::ofstream ofs(output_file_name);
463
464 // ファイルが作成できなかった場合は,なにも出力しない.
465 if (!ofs)
466 {
467 CmdIOUtil::Output(std::format("ファイル {} を作成できませんでした.", output_file_name), OutputDetail::kError);
468 return;
469 }
470
471 ofs << GetHeader() << "\n";
472
473 for (int j = 0; j < HexapodConst::kLegNum; j++)
474 {
475 std::optional<Vector3> past_pos;
476
477 for (const auto& recorder : result_list_[i].graph_search_result_recorder)
478 {
479 const Vector3 current_pos = recorder.result_node.leg_pos[j];
480
481 // 変化がない場合はスキップする.
482 if (past_pos.has_value() && current_pos == past_pos) { continue; }
483
484 // 高さが変化している and 平行に移動している場合は中継点も出力する.
485 if (past_pos.has_value() &&
486 current_pos.z != past_pos.value().z &&
487 current_pos.ProjectedXY() != past_pos.value().ProjectedXY())
488 {
489 if (current_pos.z < past_pos.value().z)
490 {
491 const Vector3 relay_point = Vector3(current_pos.x, current_pos.y, past_pos.value().z);
492 const auto joint_state = calculator_ptr_->CalculateJointState(j, relay_point);
493
494 // 接地時
495 ofs << current_pos.GetLength() << "," << past_pos.value().z << ",true,g," <<
496 std::boolalpha << calculator_ptr_->IsValidJointState(j, relay_point, joint_state) <<
497 "," << j << "\n";
498 }
499 else
500 {
501 const Vector3 relay_point = Vector3(past_pos.value().x, past_pos.value().y, current_pos.z);
502 const auto joint_state = calculator_ptr_->CalculateJointState(j, relay_point);
503
504 // 遊脚時
505 ofs << past_pos.value().GetLength() << "," << current_pos.z << ",true,l," <<
506 std::boolalpha << calculator_ptr_->IsValidJointState(j, relay_point, joint_state) <<
507 "," << j << "\n";
508 }
509 }
510
511 const auto joint_state = calculator_ptr_->CalculateJointState(j, current_pos);
512
513 ofs << current_pos.ProjectedXY().GetLength() << "," << current_pos.z << ",false," <<
514 GetLegChangeStatus(past_pos, current_pos) << "," <<
515 std::boolalpha << calculator_ptr_->IsValidJointState(j, current_pos, joint_state) <<
516 "," << j << "\n";
517
518 past_pos = current_pos;
519 }
520 }
521 }
522}
523
524void ResultFileExporter::ExportEachLegPosAllSuccessfulSimulation(const std::string& path) const
525{
526 // ディレクトリを作成する.
527 std::string leg_pos_dir_path = path + "\\" + ResultFileConst::kLegDirectoryName;
528
529 if (!sf::exists(leg_pos_dir_path))
530 {
531 sf::create_directory(leg_pos_dir_path);
532 }
533
534 // ファイルを作成する.
535
536 for (int j = 0; j < HexapodConst::kLegNum; ++j)
537 {
538 std::string output_file_name = std::format("{}\\all_simulation_leg{}.csv", leg_pos_dir_path, j + 1);
539
540 std::ofstream ofs(output_file_name);
541
542 // ファイルが作成できなかった場合は,なにも出力しない.
543 if (!ofs)
544 {
545 CmdIOUtil::Output(std::format("ファイル {} を作成できませんでした.", output_file_name), OutputDetail::kError);
546 return;
547 }
548
549 ofs << GetHeader() << "\n";
550
551 for (int k = 0; k < result_list_.size(); ++k)
552 {
553 if (result_list_[k].simulation_result != enums::SimulationResult::kSuccess) { continue; }
554
555 std::optional<Vector3> past_pos;
556
557 for (const auto& recorder : result_list_[k].graph_search_result_recorder)
558 {
559 const Vector3 current_pos = recorder.result_node.leg_pos[j];
560
561 // 変化がない場合はスキップする.
562 if (past_pos.has_value() && current_pos == past_pos) { continue; }
563
564 // 高さが変化している and 平行に移動している場合は中継点も出力する.
565 if (past_pos.has_value() &&
566 current_pos.z != past_pos.value().z &&
567 current_pos.ProjectedXY() != past_pos.value().ProjectedXY())
568 {
569 if (current_pos.z < past_pos.value().z)
570 {
571 const Vector3 relay_point = { current_pos.x, current_pos.y, past_pos.value().z };
572
573 const auto joint_state = calculator_ptr_->CalculateJointState(j, relay_point);
574
575 // 接地時
576 ofs << current_pos.GetLength() << "," << past_pos.value().z << ",true,g," << std::boolalpha << calculator_ptr_->IsValidJointState(j, relay_point, joint_state) << "\n";
577 }
578 else
579 {
580 const Vector3 relay_point = Vector3(past_pos.value().x, past_pos.value().y, current_pos.z);
581 const auto joint_state = calculator_ptr_->CalculateJointState(j, relay_point);
582
583 // 遊脚時
584 ofs << past_pos.value().GetLength() << "," << current_pos.z << ",true,l," << std::boolalpha << calculator_ptr_->IsValidJointState(j, relay_point, joint_state) << "\n";
585 }
586 }
587
588 const auto joint_state = calculator_ptr_->CalculateJointState(j, current_pos);
589
590 ofs << current_pos.ProjectedXY().GetLength() << "," <<
591 current_pos.z << ",false," << GetLegChangeStatus(past_pos, current_pos) << "," <<
592 std::boolalpha << calculator_ptr_->IsValidJointState(j, current_pos, joint_state) << "\n";
593
594 past_pos = current_pos;
595 }
596 }
597
598 ofs.close();
599 }
600}
601
602void ResultFileExporter::ExportAllLegPosAllSuccessfulSimulation(
603 const std::string& path) const
604{
605 using enum designlab::OutputDetail;
607
608 // ディレクトリを作成する.
609 std::string leg_pos_dir_path = path + "\\" + ResultFileConst::kLegDirectoryName;
610
611 if (!sf::exists(leg_pos_dir_path))
612 {
613 sf::create_directory(leg_pos_dir_path);
614 }
615
616 std::string output_file_name =
617 std::format("{}\\all_simulation_all_leg.csv", leg_pos_dir_path);
618
619 std::ofstream ofs(output_file_name);
620
621 // ファイルが作成できなかった場合は,なにも出力しない.
622 if (!ofs)
623 {
625 "ファイル {} を作成できませんでした.", output_file_name);
626 return;
627 }
628
629 ofs << GetHeader() << "\n";
630
631 for (int j = 0; j < HexapodConst::kLegNum; ++j)
632 {
633 for (int k = 0; k < result_list_.size(); ++k)
634 {
635 if (result_list_[k].simulation_result != kSuccess) { continue; }
636
637 for (int l = 0; l < HexapodConst::kLegNum; ++l)
638 {
639 std::optional<Vector3> past_pos;
640
641 for (const auto& recorder : result_list_[k].graph_search_result_recorder)
642 {
643 const Vector3 current_pos = recorder.result_node.leg_pos[l];
644
645 // 変化がない場合はスキップする.
646 if (past_pos.has_value() && current_pos == past_pos) { continue; }
647
648 // 高さが変化している and 平行に移動している場合は中継点も出力する.
649 if (past_pos.has_value() &&
650 current_pos.z != past_pos.value().z &&
651 current_pos.ProjectedXY() != past_pos.value().ProjectedXY())
652 {
653 if (current_pos.z < past_pos.value().z)
654 {
655 const Vector3 relay_point = Vector3(current_pos.x, current_pos.y, past_pos.value().z);
656 const auto joint_state = calculator_ptr_->CalculateJointState(l, relay_point);
657
658 // 接地時
659 ofs << current_pos.GetLength() << "," << past_pos.value().z << ",true,g," << std::boolalpha << calculator_ptr_->IsValidJointState(l, relay_point, joint_state) << "," << l << "\n";
660 }
661 else
662 {
663 const Vector3 relay_point = Vector3(past_pos.value().x, past_pos.value().y, current_pos.z);
664 const auto joint_state = calculator_ptr_->CalculateJointState(l, relay_point);
665
666 // 遊脚時
667 ofs << past_pos.value().GetLength() << "," << current_pos.z << ",true,l," << std::boolalpha << calculator_ptr_->IsValidJointState(l, relay_point, joint_state) << "," << l << "\n";
668 }
669 }
670
671 const auto joint_state = calculator_ptr_->CalculateJointState(l, current_pos);
672
673 ofs << current_pos.ProjectedXY().GetLength() << "," << current_pos.z << ",false," << GetLegChangeStatus(past_pos, current_pos) << "," << std::boolalpha << calculator_ptr_->IsValidJointState(l, current_pos, joint_state) << "," << l << "\n";
674
675 past_pos = current_pos;
676 }
677 }
678 }
679
680 ofs.close();
681 }
682}
683
684std::string ResultFileExporter::GetHeader() const
685{
686 return "x,z,relay,string,error,index";
687}
688
689std::string ResultFileExporter::GetLegChangeStatus(const std::optional<Vector3>& past, const Vector3& current) const
690{
691 if (!past.has_value()) { return "f"; }
692
693 if (math_util::IsEqual(past.value().z, current.z)) { return "b"; }
694
695 if (past.value().z > current.z) { return "g"; }
696
697 if (past.value().z < current.z) { return "l"; }
698
699 return "o";
700}
701
702} // namespace designlab
static std::string InputDirName(const std::string &str="Enter a directory name. (Japanese is not recommended).")
ディレクトリ名を入力させる関数. 出力される文字列は,必ず OutputDetail::kSystem で出力される. ディレクトリ名には次の文字は使えない. \ / : * ?...
static void Output(const std::string &str, OutputDetail detail)
コマンドラインに文字を出力する関数. SetOutputLimit() で設定した出力の許可範囲内であれば出力される. 必ず SetOutputLimit() を呼び出してから使うこと.
static void FormatOutput(OutputDetail detail, const std::format_string< Args... > str, Args &&... args)
コマンドラインに文字を出力する関数. SetOutputLimit() で設定した出力の許可範囲内であれば出力される. 必ず SetOutputLimit() を呼び出してから使うこと.
Definition cmdio_util.h:117
static constexpr int kLegNum
static const std::string kLegDirectoryName
出力先ディレクトリ(フォルダ)名.
static const std::string kNodeListName
ノードリストのファイル名 (プログラムの読み込み用)
static const std::string kDetailFileName
ファイル名 ( 人間が見る用 )
static const std::string kSuccessfulCount
シミュレーションの成功回数をまとめたファイルの名前.
static const std::string kDirectoryPath
出力先ディレクトリ(フォルダ)名.
static const std::string kMapStateName
マップ状態のファイル名 (プログラムの読み込み用)
void PushSimulationResult(const SimulationResultRecord &simulation_result)
シミュレーション結果を追加する.
ResultFileExporter(const std::shared_ptr< const IHexapodJointCalculator > &calculator_ptr)
void Export() const
結果をファイルに出力する.
void CreateRootDirectory()
resultフォルダがなければ作成する.また,フォルダ名を指定する.
時間計測用のクラス.
Definition stopwatch.h:31
std::string GetNowTimeString() const
現在の日時をYYYY/MM/DD HH:MM形式の文字列で取得する.
Definition stopwatch.cpp:96
SimulationResult
シミュレーション全体の結果を表す列挙型.
@ kSuccess
目標座標,姿勢を満たし,シミュレーションに成功した.
std::string FloatingPointNumToString(const T num, const int digit=kDigit, const int width=kWidth)
小数を文字列に変換する関数. C++ では C のフォーマットのように %3.3f とかで小数を文字列に変換できないため自作する.
Definition math_util.h:161
constexpr bool IsEqual(const T num1, const T num2) noexcept
C++において,小数同士の計算は誤差が出てしまう. 誤差込みで値が等しいか調べる.
Definition math_util.h:45
OutputDetail
コマンドラインに文字を出力する際に,その詳細を指定するための列挙体.
@ kInfo
優先度低めの情報.
@ kError
エラーメッセージ.
シミュレーションの結果を格納する構造体.