GaitGeneration by Graph Search
全て クラス 名前空間 ファイル 関数 変数 型定義 列挙型 列挙値 マクロ定義 ページ Concepts
map_creator_for_simulation.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 <algorithm>
11#include <random>
12
13#include "cassert_define.h"
14#include "math_util.h"
15
16
17namespace designlab
18{
19
21 messenger_(messenger)
22{
23 // map_min_x が map_max_x より小さいことを確認する.
24 assert(messenger_.map_min_x < messenger_.map_max_x);
25
26 // map_min_y が map_max_y より小さいことを確認する.
27 assert(messenger_.map_min_y < messenger_.map_max_y);
28}
29
31{
32 std::vector<Vector3> map_data;
33
34 switch (messenger_.mode)
35 {
37 {
38 CreateFlatMap(&map_data);
39 break;
40 }
42 {
43 CreateVerticalStripeMap(&map_data);
44 break;
45 }
47 {
48 CreateHorizontalStripeMap(&map_data);
49 break;
50 }
52 {
53 CreateDiagonalStripeMap(&map_data);
54 break;
55 }
57 {
58 CreateMeshMap(&map_data);
59 break;
60 }
62 {
63 CreateLatticePointMap(&map_data);
64 break;
65 }
67 {
68 CreateCircleMap(&map_data);
69 break;
70 }
72 {
73 CreateDonutMap(&map_data);
74 break;
75 }
76 default:
77 {
78 // 異常な値が入力されたら,平面のマップを生成する.
79 CreateFlatMap(&map_data);
80 break;
81 }
82 }
83
84 // オプション指定に基づき,Z座標を変更する.
85
86 if (messenger_.option & static_cast<unsigned int>(enums::SimulationMapOption::kPerforated))
87 {
88 // 穴あき地形にする.
89 ChangeMapToPerforated(&map_data);
90 }
91
92 if (messenger_.option & static_cast<unsigned int>(enums::SimulationMapOption::kStep))
93 {
94 // 階段状にする.
95 ChangeMapToStep(&map_data);
96 }
97
98 if (messenger_.option & static_cast<unsigned int>(enums::SimulationMapOption::kSlope))
99 {
100 // 坂道にする.
101 ChangeMapToSlope(&map_data);
102 }
103
104 if (messenger_.option & static_cast<unsigned int>(enums::SimulationMapOption::kTilt))
105 {
106 // 坂道にする.
107 ChangeMapToTilt(&map_data);
108 }
109
110 if (messenger_.option & static_cast<unsigned int>(enums::SimulationMapOption::kRough))
111 {
112 // デコボコにする.
113 ChangeMapToRough(&map_data);
114 }
115
116 if (messenger_.option & static_cast<unsigned int>(enums::SimulationMapOption::kRadiation))
117 {
118 // 放射状に穴をあける.
119 ChangeMapToRadial(&map_data);
120 }
121
122 return MapState(map_data);
123}
124
125void MapCreatorForSimulation::UpdateMap([[maybe_unused]] MapState* current_map)
126{
127 // マップを更新する必要がないので,何もしない.
128}
129
130
131void MapCreatorForSimulation::CreateFlatMap(std::vector<Vector3>* map) const
132{
133 assert(map != nullptr); // map が nullptr でないことを確認する.
134 assert(map->empty()); // map が空であることを確認する.
135
136 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
137 const float x_max = (messenger_.map_max_x - messenger_.map_min_x) / MapState::kMapPointDistance;
138 const float y_max = (messenger_.map_max_y - messenger_.map_min_y) / MapState::kMapPointDistance;
139
140 for (int x = 0; x < x_max; x++)
141 {
142 for (int y = 0; y < y_max; y++)
143 {
144 // ロボットの正面方向.
145 const float x_pos = messenger_.map_min_x + x * MapState::kMapPointDistance;
146
147 // ロボットの側面方向.
148 const float y_pos = messenger_.map_min_y + y * MapState::kMapPointDistance;
149
150 map->push_back({ x_pos, y_pos, messenger_.base_z }); // 脚設置可能点を追加する.
151 }
152 }
153}
154
155void MapCreatorForSimulation::CreateVerticalStripeMap(std::vector<Vector3>* map) const
156{
157 assert(map != nullptr); // map が nullptr でないことを確認する.
158 assert(map->empty()); // map が空であることを確認する.
159
160 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
161 const float x_max = (messenger_.map_max_x - messenger_.map_min_x) / MapState::kMapPointDistance;
162 const float y_max = (messenger_.map_max_y - messenger_.map_min_y) / MapState::kMapPointDistance;
163
164 for (int x = 0; x < x_max; x++)
165 {
166 for (int y = 0; y < y_max; y++)
167 {
168 // 縦じまをつくるために,一定間隔ごとに追加する.最初の待機場所の座標ならば無条件に追加する.
169 const float x_rough = (messenger_.map_start_rough_x - messenger_.map_min_x) /
171
172 if (y % (messenger_.stripe_interval * 2) < messenger_.stripe_interval || x < x_rough)
173 {
174 // ロボットの正面方向.
175 const float x_pos = messenger_.map_min_x + x * MapState::kMapPointDistance;
176
177 // ロボットの側面方向.
178 const float y_pos = messenger_.map_min_y + y * MapState::kMapPointDistance;
179
180 map->push_back({ x_pos, y_pos, messenger_.base_z }); // 脚設置可能点を追加する.
181 }
182 }
183 }
184}
185
186void MapCreatorForSimulation::CreateHorizontalStripeMap(std::vector<Vector3>* map) const
187{
188 assert(map != nullptr); // map が nullptr でないことを確認する.
189 assert(map->empty()); // map が空であることを確認する.
190
191 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
192 const float x_max = (messenger_.map_max_x - messenger_.map_min_x) / MapState::kMapPointDistance;
193 const float y_max = (messenger_.map_max_y - messenger_.map_min_y) / MapState::kMapPointDistance;
194
195 for (int x = 0; x < x_max; x++)
196 {
197 for (int y = 0; y < y_max; y++)
198 {
199 // 縦じまをつくるために,一定間隔ごとに追加する.最初の待機場所の座標ならば無条件に追加する.
200 const float x_rough = (messenger_.map_start_rough_x - messenger_.map_min_x) /
202
203 if (x % (messenger_.stripe_interval * 2) < messenger_.stripe_interval || x < x_rough)
204 {
205 // ロボットの正面方向.
206 const float x_pos = messenger_.map_min_x + x * MapState::kMapPointDistance;
207
208 // ロボットの側面方向.
209 const float y_pos = messenger_.map_min_y + y * MapState::kMapPointDistance;
210
211 map->push_back({ x_pos, y_pos, messenger_.base_z }); // 脚設置可能点を追加する.
212 }
213 }
214 }
215}
216
217void MapCreatorForSimulation::CreateDiagonalStripeMap(std::vector<Vector3>* map) const
218{
219 assert(map != nullptr); // map が nullptr でないことを確認する.
220 assert(map->empty()); // map が空であることを確認する.
221
222 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
223 const float x_max = (messenger_.map_max_x - messenger_.map_min_x) / MapState::kMapPointDistance;
224 const float y_max = (messenger_.map_max_y - messenger_.map_min_y) / MapState::kMapPointDistance;
225
226 for (int x = 0; x < x_max; x++)
227 {
228 for (int y = 0; y < y_max; y++)
229 {
230 // 斜めじまをつくるために,一定間隔ごとに追加する.最初の待機場所の座標ならば無条件に追加する.
231 const bool x_in_stripe = x % (messenger_.stripe_interval * 2) <
232 messenger_.stripe_interval;
233
234 const bool y_in_stripe = y % (messenger_.stripe_interval * 2) <
235 messenger_.stripe_interval;
236
237 const bool do_create_map = x_in_stripe == y_in_stripe;
238
239 const float x_rough = (messenger_.map_start_rough_x - messenger_.map_min_x) /
241
242 if (do_create_map || x < x_rough)
243 {
244 // ロボットの正面方向.
245 const float x_pos = messenger_.map_min_x + x * MapState::kMapPointDistance;
246
247 // ロボットの側面方向.
248 const float y_pos = messenger_.map_min_y + y * MapState::kMapPointDistance;
249
250 map->push_back({ x_pos, y_pos, messenger_.base_z }); // 脚設置可能点を追加する.
251 }
252 }
253 }
254}
255
256void MapCreatorForSimulation::CreateMeshMap(std::vector<Vector3>* map) const
257{
258 assert(map != nullptr); // map が nullptr でないことを確認する.
259 assert(map->empty()); // map が空であることを確認する.
260
261 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
262 const float x_max = (messenger_.map_max_x - messenger_.map_min_x) / MapState::kMapPointDistance;
263 const float y_max = (messenger_.map_max_y - messenger_.map_min_y) / MapState::kMapPointDistance;
264
265 for (int x = 0; x < x_max; x++)
266 {
267 for (int y = 0; y < y_max; y++)
268 {
269 // 網目模様をつくるために,一定間隔ごとに追加する.
270 // 最初の待機場所の座標ならば無条件に追加する.
271 bool do_create_map;
272
273 if ((x % (messenger_.stripe_interval * 2) < messenger_.stripe_interval))
274 {
275 if ((y % (messenger_.stripe_interval * 2) < messenger_.stripe_interval))
276 {
277 do_create_map = true;
278 }
279 else
280 {
281 do_create_map = false;
282 }
283 }
284 else
285 {
286 do_create_map = true;
287 }
288
289 const float x_rough = (messenger_.map_start_rough_x - messenger_.map_min_x) /
291
292 if (do_create_map || x < x_rough)
293 {
294 // ロボットの正面方向.
295 const float x_pos = messenger_.map_min_x + x * MapState::kMapPointDistance;
296
297 // ロボットの側面方向.
298 const float y_pos = messenger_.map_min_y + y * MapState::kMapPointDistance;
299
300 map->push_back({ x_pos, y_pos, messenger_.base_z }); // 脚設置可能点を追加する.
301 }
302 }
303 }
304}
305
306void MapCreatorForSimulation::CreateLatticePointMap(std::vector<Vector3>* map) const
307{
308 assert(map != nullptr); // map が nullptr でないことを確認する.
309 assert(map->empty()); // map が空であることを確認する.
310
311 // マップの x と y の存在範囲全体に脚設置可能点を敷き詰める.
312
313 const float x_max = (messenger_.map_max_x - messenger_.map_min_x) / MapState::kMapPointDistance;
314 const float y_max = (messenger_.map_max_y - messenger_.map_min_y) / MapState::kMapPointDistance;
315
316 for (int x = 0; x < x_max; x++)
317 {
318 for (int y = 0; y < y_max; y++)
319 {
320 // 網目模様をつくるために,一定間隔ごとに追加する.
321 // 最初の待機場所の座標ならば無条件に追加する.
322 bool do_create_map = false;
323
324 if ((x % (messenger_.stripe_interval * 2) < messenger_.stripe_interval))
325 {
326 if ((y % (messenger_.stripe_interval * 2) >= messenger_.stripe_interval))
327 {
328 do_create_map = false;
329 }
330 else
331 {
332 do_create_map = true;
333 }
334 }
335 else
336 {
337 do_create_map = false;
338 }
339
340 float x_rough = (messenger_.map_start_rough_x - messenger_.map_min_x) /
342
343 if (do_create_map || x < x_rough)
344 {
345 // ロボットの正面方向.
346 const float x_pos = messenger_.map_min_x + x * MapState::kMapPointDistance;
347
348 // ロボットの側面方向.
349 const float y_pos = messenger_.map_min_y + y * MapState::kMapPointDistance;
350
351 // 脚設置可能点を追加する.
352 map->push_back({ x_pos, y_pos, messenger_.base_z });
353 }
354 }
355 }
356}
357
358void MapCreatorForSimulation::CreateCircleMap(std::vector<Vector3>* map) const
359{
360 assert(map != nullptr); // map が nullptr でないことを確認する.
361
362 // 円が存在する範囲に脚設置可能点を敷き詰める.
363 // その後,円の外側の脚設置可能点を削除する.
364
365 const float x_min = messenger_.circle_center.x - messenger_.circle_radius;
366 const float x_max = messenger_.circle_center.x + messenger_.circle_radius;
367 const float y_min = messenger_.circle_center.y - messenger_.circle_radius;
368 const float y_max = messenger_.circle_center.y + messenger_.circle_radius;
369
370 for (int x = 0; x < (x_max - x_min) / MapState::kMapPointDistance; ++x)
371 {
372 for (int y = 0; y < (y_max - y_min) / MapState::kMapPointDistance; ++y)
373 {
374 // ロボットの正面方向.
375 const float x_pos = x_min + x * MapState::kMapPointDistance;
376
377 // ロボットの側面方向.
378 const float y_pos = y_min + y * MapState::kMapPointDistance;
379
380 // 脚設置可能点を追加する.
381 const float distance = Vector2(x_pos, y_pos).GetDistanceFrom(messenger_.circle_center.ProjectedXY());
382
383 if (distance <= messenger_.circle_radius)
384 {
385 map->push_back({ x_pos, y_pos, messenger_.base_z });
386 }
387 }
388 }
389}
390
391void MapCreatorForSimulation::CreateDonutMap(std::vector<Vector3>* map) const
392{
393 assert(map != nullptr); // map が nullptr でないことを確認する.
394
395 // ドーナツが存在する範囲に脚設置可能点を敷き詰める.
396 // その後,ドーナツの外側の脚設置可能点を削除する.
397
398 const float x_min = messenger_.circle_center.x - messenger_.circle_radius;
399 const float x_max = messenger_.circle_center.x + messenger_.circle_radius;
400 const float y_min = messenger_.circle_center.y - messenger_.circle_radius;
401 const float y_max = messenger_.circle_center.y + messenger_.circle_radius;
402
403 for (int x = 0; x < (x_max - x_min) / MapState::kMapPointDistance; ++x)
404 {
405 for (int y = 0; y < (y_max - y_min) / MapState::kMapPointDistance; ++y)
406 {
407 // ロボットの正面方向.
408 const float x_pos = x_min + x * MapState::kMapPointDistance;
409
410 // ロボットの側面方向.
411 const float y_pos = y_min + y * MapState::kMapPointDistance;
412
413 // 脚設置可能点を追加する.
414 const float distance = Vector2(x_pos, y_pos).GetDistanceFrom(messenger_.circle_center.ProjectedXY());
415
416 if (messenger_.donut_radius <= distance && distance <= messenger_.circle_radius)
417 {
418 map->push_back({ x_pos, y_pos, messenger_.base_z });
419 }
420 }
421 }
422}
423
424void MapCreatorForSimulation::ChangeMapToPerforated(std::vector<Vector3>* map) const
425{
426 assert(map != nullptr); // map が nullptr でないことを確認する.
427
428 // 厳密にホール率に合わせるために,まずはマップを stripe_interval に合わせて区切って,
429 // 全部で何マスあるか調べる.
430 const int cell_num_x = static_cast<int>(
431 (messenger_.map_max_x - messenger_.map_start_rough_x) / MapState::kMapPointDistance) /
432 messenger_.stripe_interval;
433
434 const int cell_num_y = static_cast<int>(
435 (messenger_.map_max_y - messenger_.map_min_y) / MapState::kMapPointDistance) /
436 messenger_.stripe_interval;
437
438 const int cell_sum = cell_num_x * cell_num_y;
439
440 // マスの数だけ要素を持つ vector を用意する.値は全て false で初期化する.
441 std::vector<bool> do_perforated(cell_sum, false);
442
443 // ホール率に合わせて,値を true に変更する.
444 const int hole_num = cell_sum * messenger_.hole_rate / 100;
445
446 for (int i = 0; i < hole_num; i++)
447 {
448 do_perforated.at(i) = true;
449 }
450
451 // ランダムなホールにするために要素の順番をシャッフルする.
452 std::shuffle(std::begin(do_perforated), std::end(do_perforated),
453 std::default_random_engine());
454
455 // マップに穴をあける.
456 for (auto itr = (*map).begin(); itr != (*map).end();)
457 {
458 // 待機場所の外に対してのみ作業をする.
459 if ((*itr).x < messenger_.map_start_rough_x)
460 {
461 itr++;
462 continue;
463 }
464
465 // マスで区切るとどこに位置するかを調べる.
466 const int cell_pos_x = static_cast<int>(
467 ((*itr).x - messenger_.map_start_rough_x) / MapState::kMapPointDistance) /
468 messenger_.stripe_interval;
469
470 const int cell_pos_y = static_cast<int>(
471 ((*itr).y - messenger_.map_min_y) / MapState::kMapPointDistance) /
472 messenger_.stripe_interval;
473
474 const int cell_index = cell_pos_x * cell_num_y + cell_pos_y;
475
476 // cell_pos の値がおかしくないかチェックする.
477 if (0 <= cell_index && cell_index < do_perforated.size())
478 {
479 // 穴あけをする場所ならば.
480 if (do_perforated[cell_index])
481 {
482 // 脚設置可能点を消してイテレータを更新する.
483 itr = (*map).erase(itr);
484 }
485 else
486 {
487 // 消さないならば次へ移動する.
488 itr++;
489 }
490 }
491 else
492 {
493 // 消さずに次へ移動する.
494 itr++;
495 }
496 }
497}
498
499void MapCreatorForSimulation::ChangeMapToStep(std::vector<Vector3>* map) const
500{
501 assert(map != nullptr); // map が nullptr でないことを確認する.
502
503 for (auto& i : *map)
504 {
505 // 待機場所の外に対してのみ作業をする.
506 if (i.x > messenger_.map_start_rough_x)
507 {
508 // 階段の何段目かを計算する.待機場所のすぐ上が1段目なので1を足している.
509 const int step_count = 1 + static_cast<int>((i.x - messenger_.map_start_rough_x) /
510 messenger_.step_length);
511
512 // 階段状にZ座標を変更する.
513 i.z += messenger_.step_height * step_count;
514 }
515 }
516}
517
518void MapCreatorForSimulation::ChangeMapToSlope(std::vector<Vector3>* map) const
519{
520 assert(map != nullptr); // map が nullptr でないことを確認する.
521
522 for (auto& i : *map)
523 {
524 // 待機場所の外に対してのみ作業をする.
525 if (i.x > messenger_.map_start_rough_x)
526 {
527 // 階段状にZ座標を変更する.
528 i.z += (i.x - messenger_.map_start_rough_x) *
530 }
531 }
532}
533
534void MapCreatorForSimulation::ChangeMapToTilt(std::vector<Vector3>* map) const
535{
536 assert(map != nullptr); // map が nullptr でないことを確認する.
537
538 for (auto& i : *map)
539 {
540 // 待機場所の外に対してのみ作業をする
541 if (i.x > messenger_.map_start_rough_x)
542 {
543 // 階段状にZ座標を変更する.
544 i.z += i.y * tan(math_util::ConvertDegToRad(messenger_.tilt_angle));
545 }
546 }
547}
548
549void MapCreatorForSimulation::ChangeMapToRough(std::vector<Vector3>* map) const
550{
551 assert(map != nullptr); // map が nullptr でないことを確認する.
552
553 // まずはマップを STRIPE_INTERVAL にあわせて区切って,全部で何マスあるか調べる.
554 const int cell_num_x = static_cast<int>(
555 (messenger_.map_start_rough_x - messenger_.map_min_x) /
557
558 const int cell_num_y = static_cast<int>(
559 (messenger_.map_max_y - messenger_.map_min_y) /
561
562 const int cell_sum = cell_num_x * cell_num_y;
563
564 // マスの数だけ要素を持つ vector を用意する.
565 std::vector<float> change_z_length;
566
567 for (int i = 0; i < cell_sum; i++)
568 {
569 // ランダムなZ座標を入れる.
570 change_z_length.push_back(math_util::GenerateRandomNumber(
571 messenger_.rough_min_height,
572 messenger_.rough_max_height));
573 }
574
575 for (auto& i : *map)
576 {
577 if (i.x <= messenger_.map_start_rough_x)
578 {
579 continue;
580 }
581
582 // マスで区切るとどこに位置するかを調べる.
583 const int cell_pos_x = static_cast<int>((i.x - messenger_.map_start_rough_x) /
585 messenger_.stripe_interval;
586
587 const int cell_pos_y = static_cast<int>((i.y - messenger_.map_min_y) /
589 messenger_.stripe_interval;
590
591 const int cell_index = cell_pos_x * cell_num_y + cell_pos_y;
592
593 // cell_index の値がおかしくないかチェックする.
594 if (0 <= cell_index && cell_index < change_z_length.size())
595 {
596 i.z += change_z_length[cell_index];
597 }
598 }
599}
600
601void MapCreatorForSimulation::ChangeMapToRadial(std::vector<Vector3>* map) const
602{
603 assert(map != nullptr); // map が nullptr でないことを確認する.
604
605 const float divided_angle = std::numbers::pi_v<float> / messenger_.radial_division;
606
607 for (auto itr = (*map).begin(); itr != (*map).end();)
608 {
609 // 放射状の穴あけの中心からの角度を計算する.
610 const float angle = atan2((*itr).y - messenger_.radial_center.y, (*itr).x - messenger_.radial_center.x) +
611 std::numbers::pi_v<float> +math_util::ConvertDegToRad(messenger_.radial_angle_offset);
612
613 if (static_cast<int>(angle / divided_angle) % 2 == 1)
614 {
615 const int i = static_cast<int>(angle / divided_angle); // 何番目の角度かを計算する.
616 const float angle_dif = angle - i * divided_angle; // 何番目の角度からの差を計算する.
617
618 // 角度の差がホール率より小さい場合は消す.
619 if (angle_dif < divided_angle * messenger_.radial_hole_rate / 100)
620 {
621 // 脚設置可能点を消してイテレータを更新する.
622 itr = (*map).erase(itr);
623 }
624 else
625 {
626 // 消さないならば次へ移動する.
627 itr++;
628 }
629 }
630 else
631 {
632 // 消さないならば次へ移動する.
633 itr++;
634 }
635 }
636}
637
638} // namespace designlab
MapCreatorForSimulation(const SimulationMapParameter &param)
コンストラクタで作成するマップ情報を与える
MapState InitMap() override
マップの初期化を行う.
void UpdateMap(MapState *current_map) override
マップの更新を行う.
マップを表すクラス.
Definition map_state.h:32
static constexpr float kMapPointDistance
z軸から(上から)みたとき,格子点状に分けられた脚接地可能点の間隔 [mm].
Definition map_state.h:92
@ kHorizontalStripe
横じまの面を生成する.
@ kVerticalStripe
縦じまの面を生成する.
@ kLatticePoint
格子点の面を生成する.網目状の逆.
@ kFlat
普通の平らな面を生成する.
@ kMesh
格子状の面を生成する.網目状の地形ともいっていい.
@ kDiagonalStripe
斜めじまの面を生成する.
@ kCircle
円形の面を生成する.
@ kDonut
ドーナツ状の面を生成する.
@ kTilt
縦軸を中心軸として回転させた地形に変化させる.
@ kRough
凸凹の地形に変化させる.
@ kRadiation
放射状の地形に変化させる.
@ kPerforated
穴の空いたマップに変化させる.
@ kStep
階段状の地形に変化させる.
@ kSlope
スロープ状の地形に変化させる.
T GenerateRandomNumber(T min, T max)
指定した範囲内の乱数を生成する.
Definition math_util.h:102
constexpr T ConvertDegToRad(const T deg) noexcept
角度を [deg] から [rad] に変換する関数.
Definition math_util.h:126
マップ生成時のモードとオプションを指定する構造体.
int radial_hole_rate
放射状の地形のホール率[%].
int radial_division
放射状の地形の分割数.
float map_max_y
マップのY座標の最大値.
int stripe_interval
各種模様や穴を作成する際,これで指定したマス分の1辺を持つ正方形状にあなをあける.
float map_min_x
マップのX座標の最小値.
float map_start_rough_x
不整地が始まるX座標.
float circle_radius
円 / ドーナツの半径.
float radial_angle_offset
放射状の地形の角度オフセット[deg].
float map_min_y
マップのY座標の最小値.
float donut_radius
ドーナツの内側の半径.
unsigned int option
マップ生成のオプションを指定するbit.
Vector2 radial_center
放射状の地形の中心座標.
float step_height
段差高さ[mm].負の値にすると下りの階段になる.
float rough_min_height
デコボコな地形の最小高さ[mm]
float map_max_x
マップのX座標の最大値.
float slope_angle
斜面の傾斜角[deg]
float rough_max_height
デコボコな地形の最大高さ[mm]
float tilt_angle
地形を傾ける角度[deg]
float base_z
マップの基準となるZ座標.
Vector3 circle_center
円 / ドーナツの中心座標.
int hole_rate
不整地上の足場を除外する割合。ホール率[%]
float x
ロボットの正面方向に正.
constexpr Vector2 ProjectedXY() const noexcept
XY平面に射影したベクトルを返す.
float y
ロボットの左向きに正.