载入中...
搜索中...
未找到
CrowdAvoidance.cpp
浏览该文件的文档.
2
3#include <limits>
4
5namespace eve::crowd {
6
8 if (!std::isfinite(settings.horizon) || settings.horizon <= 0.f || settings.horizon > 10.f ||
9 !std::isfinite(settings.margin) || settings.margin < 0.f || settings.maxNeighbors < 1 ||
10 settings.maxNeighbors > 128)
12 Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid predictive avoidance settings", "avoidance"));
13 impl_->avoidance = settings;
15}
16
17AvoidanceSettings Crowd::getAvoidanceSettings() const { return impl_->avoidance; }
18
19void Crowd::Impl::selectAvoidanceVelocity(size_t i, float dt, float& vx, float& vy) {
20 if (maxSpeeds[i] <= 0.f) return;
21 using Neighbor = AvoidanceNeighbor;
22 auto& neighbors = avoidanceNeighbors;
23 neighbors.clear();
24 neighbors.reserve(size_t(avoidance.maxNeighbors) + 1);
25 const double query = double(radii[i]) + avoidanceMaxRadius + avoidance.margin +
26 double(avoidance.horizon) * (double(maxSpeeds[i]) + avoidanceMaxSpeed);
27 int encountered = 0;
28 const auto nearer = [&](const Neighbor& a, const Neighbor& b) {
29 if (a.distance2 != b.distance2) return a.distance2 < b.distance2;
30 if (stableIds[a.slot] != stableIds[b.slot]) return stableIds[a.slot] < stableIds[b.slot];
31 return a.slot < b.slot;
32 };
33 forEachNeighbor(xs[i], ys[i], float(std::min(query, double(std::numeric_limits<float>::max()))), [&](int slot) {
34 const size_t j = size_t(slot);
35 if (i == j || !canInteract(i, j)) return;
36 ++encountered;
37 const double dx = double(xs[j]) - xs[i], dy = double(ys[j]) - ys[i];
38 Neighbor neighbor{j, dx * dx + dy * dy};
39 const auto position = std::lower_bound(neighbors.begin(), neighbors.end(), neighbor, nearer);
40 if (position != neighbors.end() || neighbors.size() < size_t(avoidance.maxNeighbors)) {
41 neighbors.insert(position, neighbor);
42 if (neighbors.size() > size_t(avoidance.maxNeighbors)) neighbors.pop_back();
43 }
44 });
45 if (encountered > avoidance.maxNeighbors) ++avoidanceTruncations;
46 if (neighbors.empty()) return;
47
48 const float speed = maxSpeeds[i];
49 const float preferredX = preferredVxs[i], preferredY = preferredVys[i];
50 const float preferredLength = std::hypot(preferredX, preferredY);
51 const float baseAngle = preferredLength > 1e-5f ? std::atan2(preferredY, preferredX) : headings[i];
52 const float acceleration = maxAccels[i] * dt;
53 const auto reachable = [&](float& x, float& y) {
54 const float changeX = x - vxs[i], changeY = y - vys[i];
55 const float change = std::hypot(changeX, changeY);
56 if (change > acceleration && change > 0.f) {
57 x = vxs[i] + changeX * acceleration / change;
58 y = vys[i] + changeY * acceleration / change;
59 }
60 const float length = std::hypot(x, y);
61 if (length > speed) {
62 x *= speed / length;
63 y *= speed / length;
64 }
65 };
66 const auto score = [&](float x, float y) {
67 double cost =
68 std::hypot(x - preferredX, y - preferredY) / speed + 0.15 * std::hypot(x - vxs[i], y - vys[i]) / speed;
69 // A small, persistent right-hand preference breaks mirror symmetry.
70 if (preferredLength > 1e-5f)
71 cost += 0.05 * std::max(0.f, preferredX * y - preferredY * x) / (preferredLength * speed);
72 for (const auto& neighbor : neighbors) {
74 const size_t j = neighbor.slot;
75 const double px = double(xs[j]) - xs[i], py = double(ys[j]) - ys[i];
76 const double dx = double(x) - vxs[j], dy = double(y) - vys[j];
77 const double radius = double(radii[i]) + radii[j] + avoidance.margin;
78 const double c = neighbor.distance2 - radius * radius;
79 const double a = dx * dx + dy * dy, b = px * dx + py * dy;
80 double collision = double(avoidance.horizon) + 1.0;
81 if (c < 0.0) {
82 // Prefer opening an existing contact, rather than freezing all candidates.
83 collision = 0.0;
84 cost += 2.0 * std::max(0.0, b) / (std::max(radius, 1e-6) * speed);
85 } else if (a > 1e-10 && b > 0.0) {
86 const double discriminant = b * b - a * c;
87 if (discriminant >= 0.0) collision = (b - std::sqrt(discriminant)) / a;
88 }
89 if (collision >= 0.0 && collision < avoidance.horizon) {
90 const double urgency = 1.0 - collision / avoidance.horizon;
91 // Priority adjusts yielding preference; it never removes collision cost.
92 const double priority =
93 std::clamp(double(avoidancePriorities[j]) - avoidancePriorities[i], -100.0, 100.0);
94 cost += (20.0 + 0.1 * priority) * urgency * urgency;
95 }
96 }
97 if (field.valid()) {
98 float px = xs[i] + x * dt, py = ys[i] + y * dt;
99 float projectedX = px, projectedY = py;
100 field.resolvePenetration(projectedX, projectedY, radii[i]);
101 if (std::hypot(projectedX - px, projectedY - py) > 1e-4f) cost += 100.0;
102 if (clampToField && (px - radii[i] < field.getOriginX() || py - radii[i] < field.getOriginY() ||
103 px + radii[i] > field.getOriginX() + float(field.getWidth()) * field.getCellSize() ||
104 py + radii[i] > field.getOriginY() + float(field.getHeight()) * field.getCellSize()))
105 cost += 100.0;
106 }
107 return cost;
108 };
109 double best = score(vx, vy);
110 const auto consider = [&](float x, float y) {
111 reachable(x, y);
112 const double value = score(x, y);
113 if (value < best - 1e-9) {
114 best = value;
115 vx = x;
116 vy = y;
117 }
118 };
119 consider(0.f, 0.f);
120 consider(vxs[i], vys[i]);
121 const float samplingSpeed = std::max(preferredLength, speed * 0.25f);
122 constexpr float angles[] = {0.f, -0.2617994f, 0.2617994f, -0.5235988f, 0.5235988f,
123 -0.7853982f, 0.7853982f, -1.0471976f, 1.0471976f, -1.5707963f,
124 1.5707963f, -2.3561945f, 2.3561945f, 3.1415927f};
125 for (float fraction : {1.f, 0.5f, 0.25f})
126 for (float angle : angles)
127 consider(std::cos(baseAngle + angle) * samplingSpeed * fraction,
128 std::sin(baseAngle + angle) * samplingSpeed * fraction);
129}
130
131} // namespace eve::crowd
double value
double score
Definition Agent.cpp:50
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
int priority
float length
Definition CaveMesh.cpp:94
float py
eve::resource::CostSpec cost
std::int32_t c
std::vector< Colorf > px
std::array< float, 3 > position
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float radius
float dy
float dx
std::map< Cell, int > best
TerrainThermalSettings settings
float vy
float vx
float angle
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
float getOriginX() const
Returns the origin x.
Definition CrowdField.h:53
int getWidth() const
网格尺寸访问器。
Definition CrowdField.h:47
float getOriginY() const
Returns the origin y.
Definition CrowdField.h:55
bool resolvePenetration(float &wx, float &wy, float radius) const
圆 vs 阻挡格碰撞消解:把圆心从覆盖到的阻挡格中推出来。
int getHeight() const
Returns the height.
Definition CrowdField.h:49
float getCellSize() const
Returns the cell size.
Definition CrowdField.h:51
bool valid() const
是否配置了有效网格。
Definition CrowdField.h:44
Result< void > configureAvoidance(AvoidanceSettings settings)
Configure predictive velocity sampling; invalid input leaves settings unchanged.
AvoidanceSettings getAvoidanceSettings() const
Return an owning settings snapshot. @thread Simulation thread only.
Optional bounded velocity sampling for RTS local avoidance.
Definition Crowd.h:48
float horizon
Positive prediction seconds, at most ten.
Definition Crowd.h:50
float margin
Non-negative extra pair clearance in world units.
Definition Crowd.h:51
int maxNeighbors
Nearest interacting neighbors considered, in [1,128].
Definition Crowd.h:52
std::vector< float > xs
SOA agent storage, indexed by compact slot id. @cost Linear in agent count; mutation keeps all owned ...
std::vector< float > preferredVys
std::vector< float > headings
std::vector< float > maxSpeeds
std::vector< AvoidanceNeighbor > avoidanceNeighbors
Per-step avoidance neighbor scratch space. @cost Linear in checked neighbors and bounded by avoidance...
std::int64_t avoidanceChecks
std::vector< float > vys
std::vector< float > ys
std::vector< float > preferredVxs
std::vector< float > maxAccels
AvoidanceSettings avoidance
std::vector< float > vxs
std::vector< int32_t > avoidancePriorities
void selectAvoidanceVelocity(size_t index, float dt, float &vx, float &vy)
void forEachNeighbor(float qx, float qy, float radius, Fn &&fn) const
std::vector< float > radii
std::vector< std::string > stableIds
bool canInteract(size_t a, size_t b) const