Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/application/ScenarioCanvasWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ QString formatEnvironmentHazardTooltip(const safecrowd::domain::EnvironmentHazar
.arg(std::max(start, hazard.endSeconds), 0, 'f', 1));
}
text.append(QString("\nSeverity: %1").arg(severityLabel(hazard.severity)));
text.append(QString("\nInfluence radius: %1m")
.arg(safecrowd::domain::environmentHazardRadiusMeters(hazard.severity), 0, 'f', 1));
text.append(QStringLiteral("\nDetection varies by agent sensitivity"));
return text;
}

Expand Down
13 changes: 12 additions & 1 deletion src/application/SimulationCanvasWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ QString formatEnvironmentHazardTooltip(const safecrowd::domain::EnvironmentHazar
.arg(std::max(start, hazard.endSeconds), 0, 'f', 1));
}
text.append(QString("\nSeverity: %1").arg(severityLabel(hazard.severity)));
text.append(QString("\nInfluence radius: %1m")
.arg(safecrowd::domain::environmentHazardRadiusMeters(hazard.severity), 0, 'f', 1));
text.append(QStringLiteral("\nDetection varies by agent sensitivity"));
return text;
}

Expand Down Expand Up @@ -1132,8 +1135,16 @@ void SimulationCanvasWidget::drawEnvironmentHazardOverlay(QPainter& painter, con
markerFill = QColor(100, 116, 139, 115);
}
QRadialGradient gradient(center, radius);
auto falloffColor = [&](double ratio, QColor color) {
const auto influence = safecrowd::domain::environmentHazardInfluenceAt(
hazard,
radiusMeters * std::clamp(ratio, 0.0, 1.0));
color.setAlpha(std::clamp(static_cast<int>(std::lround(static_cast<double>(color.alpha()) * influence)), 0, 255));
return color;
};
gradient.setColorAt(0.0, core);
gradient.setColorAt(0.48, mid);
gradient.setColorAt(0.35, falloffColor(0.35, core));
gradient.setColorAt(0.65, falloffColor(0.65, mid));
gradient.setColorAt(1.0, edge);
painter.setPen(Qt::NoPen);
painter.setBrush(gradient);
Expand Down
22 changes: 16 additions & 6 deletions src/domain/ScenarioAuthoring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,17 @@ double environmentHazardRadiusMeters(ScenarioElementSeverity severity) {
}
}

double environmentHazardInfluenceAt(const EnvironmentHazardDraft& hazard, double distanceMeters) {
const auto radius = environmentHazardRadiusMeters(hazard.severity);
if (radius <= 1e-9) {
return 0.0;
}

const auto t = std::clamp(std::max(0.0, distanceMeters) / radius, 0.0, 1.0);
const auto smooth = t * t * (3.0 - (2.0 * t));
return 1.0 - smooth;
}

double environmentHazardRoutePenaltyMeters(ScenarioElementSeverity severity) {
switch (severity) {
case ScenarioElementSeverity::Low:
Expand Down Expand Up @@ -323,13 +334,12 @@ double environmentHazardSmokeVisibilityMetersAt(const EnvironmentHazardDraft& ha
break;
}

const auto distance = std::max(0.0, distanceMeters);
if (distance >= radius) {
const auto influence = environmentHazardInfluenceAt(hazard, distanceMeters);
if (influence <= 1e-9) {
return 3.0;
}

const auto t = std::clamp(distance / radius, 0.0, 1.0);
return sourceVisibility + ((3.0 - sourceVisibility) * t);
return 3.0 - ((3.0 - sourceVisibility) * influence);
}

double environmentHazardSmokeSpeedMetersPerSecond(double smokeFreeSpeedMetersPerSecond, double visibilityMeters) {
Expand Down Expand Up @@ -367,8 +377,8 @@ double environmentHazardSpeedFactorAt(
}

const auto centerFactor = environmentHazardSpeedFactor(hazard.kind, hazard.severity);
const auto proximity = 1.0 - std::clamp(std::max(0.0, distanceMeters) / radius, 0.0, 1.0);
return 1.0 - ((1.0 - centerFactor) * proximity);
const auto influence = environmentHazardInfluenceAt(hazard, distanceMeters);
return 1.0 - ((1.0 - centerFactor) * influence);
}

EnvironmentHazardRuntimeProfile environmentHazardRuntimeProfile(const EnvironmentHazardDraft& hazard) {
Expand Down
1 change: 1 addition & 0 deletions src/domain/ScenarioAuthoring.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ std::vector<std::string> computeScenarioDiffKeys(const ScenarioDraft& baseline,
const ScenarioDraft& variant);

double environmentHazardRadiusMeters(ScenarioElementSeverity severity);
double environmentHazardInfluenceAt(const EnvironmentHazardDraft& hazard, double distanceMeters);
double environmentHazardRoutePenaltyMeters(ScenarioElementSeverity severity);
double environmentHazardSeverityWeight(ScenarioElementSeverity severity);
double environmentHazardSpeedFactor(EnvironmentHazardKind kind, ScenarioElementSeverity severity);
Expand Down
26 changes: 24 additions & 2 deletions src/domain/ScenarioSimulationMotionSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,15 @@ class ScenarioSimulationMotionSystem final : public engine::EngineSystem {
? &resources.get<ScenarioAgentSpatialIndexResource>()
: nullptr;

routeGuidance_.apply(query, entities, layoutCache, clock.elapsedSeconds, step.derivedSeed, sharedSpatialIndex);
routeGuidance_.apply(
query,
entities,
layoutCache,
clock.elapsedSeconds,
step.derivedSeed,
reactions,
activeHazards,
sharedSpatialIndex);
advanceRoutesForCurrentZones(query, activeEntities_, layoutCache);
replanBlockedExitRoutes(query, activeEntities_, layoutCache, clock.elapsedSeconds, layoutRevision, reactions);
advanceRoutesForWaypointProgress(query, 0.0, activeEntities_, layoutCache);
Expand Down Expand Up @@ -1208,7 +1216,19 @@ class ScenarioSimulationMotionSystem final : public engine::EngineSystem {
return;
}

for (const auto entity : entities) {
if (entities.empty()) {
hazardReplanCursor_ = 0;
return;
}

constexpr std::size_t kHazardReplanEntityBudgetPerFrame = 50;
if (hazardReplanCursor_ >= entities.size()) {
hazardReplanCursor_ = 0;
}
const auto startCursor = hazardReplanCursor_;
const auto visitCount = std::min<std::size_t>(entities.size(), kHazardReplanEntityBudgetPerFrame);
for (std::size_t offset = 0; offset < visitCount; ++offset) {
const auto entity = entities[(startCursor + offset) % entities.size()];
const auto* hazardState = activeHazardState(reactions, entity.index);
if (hazardState == nullptr) {
continue;
Expand Down Expand Up @@ -1246,6 +1266,7 @@ class ScenarioSimulationMotionSystem final : public engine::EngineSystem {
routeGuidance_.replaceRouteWithPlan(route, plan, position.value);
route.nextExitReplanSeconds = elapsedSeconds + kExitReplanCooldownSeconds;
}
hazardReplanCursor_ = (startCursor + visitCount) % entities.size();
}

bool closureReadyForBlockedConnection(
Expand Down Expand Up @@ -1708,6 +1729,7 @@ class ScenarioSimulationMotionSystem final : public engine::EngineSystem {
std::optional<ScenarioLayoutCacheResource> layoutCache_{};
ScenarioRouteGuidanceController routeGuidance_{};
std::vector<engine::Entity> activeEntities_{};
mutable std::size_t hazardReplanCursor_{0};
};


Expand Down
Loading
Loading