#include "selfdrive/ui/qt/onroad/driver_monitoring.h" #include #include #include "selfdrive/ui/qt/onroad/buttons.h" #include "selfdrive/ui/qt/util.h" // Default 3D coordinates for face keypoints static constexpr vec3 DEFAULT_FACE_KPTS_3D[] = { {-5.98, -51.20, 8.00}, {-17.64, -49.14, 8.00}, {-23.81, -46.40, 8.00}, {-29.98, -40.91, 8.00}, {-32.04, -37.49, 8.00}, {-34.10, -32.00, 8.00}, {-36.16, -21.03, 8.00}, {-36.16, 6.40, 8.00}, {-35.47, 10.51, 8.00}, {-32.73, 19.43, 8.00}, {-29.30, 26.29, 8.00}, {-24.50, 33.83, 8.00}, {-19.01, 41.37, 8.00}, {-14.21, 46.17, 8.00}, {-12.16, 47.54, 8.00}, {-4.61, 49.60, 8.00}, {4.99, 49.60, 8.00}, {12.53, 47.54, 8.00}, {14.59, 46.17, 8.00}, {19.39, 41.37, 8.00}, {24.87, 33.83, 8.00}, {29.67, 26.29, 8.00}, {33.10, 19.43, 8.00}, {35.84, 10.51, 8.00}, {36.53, 6.40, 8.00}, {36.53, -21.03, 8.00}, {34.47, -32.00, 8.00}, {32.42, -37.49, 8.00}, {30.36, -40.91, 8.00}, {24.19, -46.40, 8.00}, {18.02, -49.14, 8.00}, {6.36, -51.20, 8.00}, {-5.98, -51.20, 8.00}, }; // Colors used for drawing based on monitoring state static const QColor DMON_ENGAGED_COLOR = QColor::fromRgbF(0.1, 0.945, 0.26); static const QColor DMON_DISENGAGED_COLOR = QColor::fromRgbF(0.545, 0.545, 0.545); DriverMonitorRenderer::DriverMonitorRenderer() : face_kpts_draw(std::size(DEFAULT_FACE_KPTS_3D)) { dm_img = loadPixmap("../assets/img_driver_face.png", {img_size + 5, img_size + 5}); } void DriverMonitorRenderer::updateState(const UIState &s) { auto &sm = *(s.sm); is_visible = sm["selfdriveState"].getSelfdriveState().getAlertSize() == cereal::SelfdriveState::AlertSize::NONE && sm.rcv_frame("driverStateV2") > s.scene.started_frame; if (!is_visible) return; auto dm_state = sm["driverMonitoringState"].getDriverMonitoringState(); is_active = dm_state.getIsActiveMode(); is_rhd = dm_state.getIsRHD(); dm_fade_state = std::clamp(dm_fade_state + 0.2f * (0.5f - is_active), 0.0f, 1.0f); const auto &driverstate = sm["driverStateV2"].getDriverStateV2(); const auto driver_orient = is_rhd ? driverstate.getRightDriverData().getFaceOrientation() : driverstate.getLeftDriverData().getFaceOrientation(); for (int i = 0; i < 3; ++i) { float v_this = (i == 0 ? (driver_orient[i] < 0 ? 0.7 : 0.9) : 0.4) * driver_orient[i]; driver_pose_diff[i] = std::abs(driver_pose_vals[i] - v_this); driver_pose_vals[i] = 0.8f * v_this + (1 - 0.8) * driver_pose_vals[i]; driver_pose_sins[i] = std::sin(driver_pose_vals[i] * (1.0f - dm_fade_state)); driver_pose_coss[i] = std::cos(driver_pose_vals[i] * (1.0f - dm_fade_state)); } auto [sin_y, sin_x, sin_z] = driver_pose_sins; auto [cos_y, cos_x, cos_z] = driver_pose_coss; // Rotation matrix for transforming face keypoints based on driver's head orientation const mat3 r_xyz = {{ cos_x * cos_z, cos_x * sin_z, -sin_x, -sin_y * sin_x * cos_z - cos_y * sin_z, -sin_y * sin_x * sin_z + cos_y * cos_z, -sin_y * cos_x, cos_y * sin_x * cos_z - sin_y * sin_z, cos_y * sin_x * sin_z + sin_y * cos_z, cos_y * cos_x, }}; // Transform vertices for (int i = 0; i < face_kpts_draw.size(); ++i) { vec3 kpt = matvecmul3(r_xyz, DEFAULT_FACE_KPTS_3D[i]); face_kpts_draw[i] = {{kpt.v[0], kpt.v[1], kpt.v[2] * (1.0f - dm_fade_state) + 8 * dm_fade_state}}; } } void DriverMonitorRenderer::draw(QPainter &painter, const QRect &surface_rect) { if (!is_visible) return; painter.save(); int offset = UI_BORDER_SIZE + btn_size / 2; float x = is_rhd ? surface_rect.width() - offset : offset; float y = surface_rect.height() - offset; float opacity = is_active ? 0.65f : 0.2f; drawIcon(painter, QPoint(x, y), dm_img, QColor(0, 0, 0, 70), opacity); QPointF keypoints[std::size(DEFAULT_FACE_KPTS_3D)]; for (int i = 0; i < std::size(keypoints); ++i) { const auto &v = face_kpts_draw[i].v; float kp = (v[2] - 8) / 120.0f + 1.0f; keypoints[i] = QPointF(v[0] * kp + x, v[1] * kp + y); } painter.setPen(QPen(QColor::fromRgbF(1.0, 1.0, 1.0, opacity), 5.2, Qt::SolidLine, Qt::RoundCap)); painter.drawPolyline(keypoints, std::size(keypoints)); // tracking arcs const int arc_l = 133; const float arc_t_default = 6.7f; const float arc_t_extend = 12.0f; QColor arc_color = uiState()->engaged() ? DMON_ENGAGED_COLOR : DMON_DISENGAGED_COLOR; arc_color.setAlphaF(0.4 * (1.0f - dm_fade_state)); float delta_x = -driver_pose_sins[1] * arc_l / 2.0f; float delta_y = -driver_pose_sins[0] * arc_l / 2.0f; // Draw horizontal tracking arc painter.setPen(QPen(arc_color, arc_t_default + arc_t_extend * std::min(1.0, driver_pose_diff[1] * 5.0), Qt::SolidLine, Qt::RoundCap)); painter.drawArc(QRectF(std::min(x + delta_x, x), y - arc_l / 2, std::abs(delta_x), arc_l), (driver_pose_sins[1] > 0 ? 90 : -90) * 16, 180 * 16); // Draw vertical tracking arc painter.setPen(QPen(arc_color, arc_t_default + arc_t_extend * std::min(1.0, driver_pose_diff[0] * 5.0), Qt::SolidLine, Qt::RoundCap)); painter.drawArc(QRectF(x - arc_l / 2, std::min(y + delta_y, y), arc_l, std::abs(delta_y)), (driver_pose_sins[0] > 0 ? 0 : 180) * 16, 180 * 16); painter.restore(); }