void SimFieldView::drawTeamSpace(QPainter& p) {
    FieldView::drawTeamSpace(p);

    // Simulator drag-to-shoot
    std::shared_ptr<LogFrame> frame = currentFrame();
    if (_dragMode == DRAG_SHOOT && frame) {
        p.setPen(QPen(Qt::white, 0.1f));
        Geometry2d::Point ball = frame->ball().pos();
        p.drawLine(ball.toQPointF(), _dragTo.toQPointF());

        if (ball != _dragTo) {
            p.setPen(QPen(Qt::gray, 0.1f));

            _shot = (ball - _dragTo) * ShootScale;
            float speed = _shot.mag();
            Geometry2d::Point shotExtension = ball + _shot / speed * 8;

            p.drawLine(ball.toQPointF(), shotExtension.toQPointF());

            p.setPen(Qt::black);
            drawText(p, _dragTo.toQPointF(),
                     QString("%1 m/s").arg(speed, 0, 'f', 1));
        }
    }
}
Ejemplo n.º 2
0
void FieldView::drawTeamSpace(QPainter& p) {
    // Get the latest LogFrame
    const LogFrame* frame = _history->at(0).get();

    if (showTeamNames) {
        // Draw Team Names
        QFont savedFont = p.font();
        QFont fontstyle = p.font();
        fontstyle.setPointSize(20);
        p.setFont(fontstyle);
        p.setPen(bluePen);
        drawText(p, QPointF(0, 4.75), QString(frame->team_name_blue().c_str()),
                 true);  // Blue
        p.setPen(yellowPen);
        drawText(p, QPointF(0, 1.75),
                 QString(frame->team_name_yellow().c_str()),
                 true);  // Yellow
        p.setFont(savedFont);
    }

    // Block off half the field
    if (!frame->use_our_half()) {
        const float FX = Field_Dimensions::Current_Dimensions.FloorWidth() / 2;
        const float FY1 = -Field_Dimensions::Current_Dimensions.Border();
        const float FY2 = Field_Dimensions::Current_Dimensions.Length() / 2;
        p.fillRect(QRectF(QPointF(-FX, FY1), QPointF(FX, FY2)),
                   QColor(0, 0, 0, 128));
    }
    if (!frame->use_opponent_half()) {
        const float FX = Field_Dimensions::Current_Dimensions.FloorWidth() / 2;
        const float FY1 = Field_Dimensions::Current_Dimensions.Length() / 2;
        const float FY2 = Field_Dimensions::Current_Dimensions.Length() +
                          Field_Dimensions::Current_Dimensions.Border();
        p.fillRect(QRectF(QPointF(-FX, FY1), QPointF(FX, FY2)),
                   QColor(0, 0, 0, 128));
    }

    if (showCoords) {
        drawCoords(p);
    }

    // History
    p.setBrush(Qt::NoBrush);
    QPainterPath ballTrail;
    for (unsigned int i = 0; i < 200 && i < _history->size(); ++i) {
        const LogFrame* oldFrame = _history->at(i).get();
        if (oldFrame && oldFrame->has_ball()) {
            QPointF pos = qpointf(oldFrame->ball().pos());

            if (i == 0)
                ballTrail.moveTo(pos);
            else
                ballTrail.lineTo(pos);
        }
    }
    QPen ballTrailPen(ballColor, 0.03);
    ballTrailPen.setCapStyle(Qt::RoundCap);
    p.setPen(ballTrailPen);
    p.drawPath(ballTrail);

    // Debug lines
    for (const DebugPath& path : frame->debug_paths()) {
        if (path.layer() < 0 || layerVisible(path.layer())) {
            tempPen.setColor(qcolor(path.color()));
            p.setPen(tempPen);
            std::vector<QPointF> pts;
            for (int i = 0; i < path.points_size(); ++i) {
                pts.push_back(qpointf(path.points(i)));
            }
            p.drawPolyline(pts.data(), pts.size());
        }
    }

    for (const DebugRobotPath& path : frame->debug_robot_paths()) {
        if (path.layer() < 0 || layerVisible(path.layer())) {
            for (int i = 0; i < path.points_size() - 1; ++i) {
                const DebugRobotPath::DebugRobotPathPoint& from =
                    path.points(i);
                const DebugRobotPath::DebugRobotPathPoint& to =
                    path.points(i + 1);

                Geometry2d::Point avgVel =
                    (Geometry2d::Point(path.points(i).vel()) +
                     Geometry2d::Point(path.points(i + 1).vel())) /
                    2;
                float pcntMaxSpd =
                    avgVel.mag() / MotionConstraints::defaultMaxSpeed();
                QColor mixedColor(std::min((int)(255 * pcntMaxSpd), 255), 0,
                                  std::min((int)(255 * (1 - pcntMaxSpd)), 255));
                QPen pen(mixedColor);
                pen.setCapStyle(Qt::RoundCap);
                pen.setWidthF(0.03);
                p.setPen(pen);

                const Geometry2d::Point fromPos = Geometry2d::Point(from.pos());
                const Geometry2d::Point toPos = Geometry2d::Point(to.pos());
                p.drawLine(fromPos.toQPointF(), toPos.toQPointF());
            }
        }
    }

    // Debug circles
    for (const DebugCircle& c : frame->debug_circles()) {
        if (c.layer() < 0 || layerVisible(c.layer())) {
            tempPen.setColor(c.color());
            p.setPen(tempPen);
            p.drawEllipse(qpointf(c.center()), c.radius(), c.radius());
        }
    }

    // Debug arcs
    for (const DebugArc& a : frame->debug_arcs()) {
        if (a.layer() < 0 || layerVisible(a.layer())) {
            tempPen.setColor(a.color());
            p.setPen(tempPen);

            auto c = a.center();
            auto t1 = a.start();
            auto t2 = a.end();
            auto R = a.radius();

            QRectF rect;
            rect.setX(-R + c.x());
            rect.setY(-R + c.y());
            rect.setWidth(R * 2);
            rect.setHeight(R * 2);

            t1 *= -(180 / M_PI) * 16;
            t2 *= -(180 / M_PI) * 16;

            p.drawArc(rect, t1, t2 - t1);
        }
    }

    // Debug text
    for (const DebugText& text : frame->debug_texts()) {
        if (text.layer() < 0 || layerVisible(text.layer())) {
            tempPen.setColor(text.color());
            p.setPen(tempPen);
            drawText(p, qpointf(text.pos()),
                     QString::fromStdString(text.text()), text.center());
        }
    }

    // Debug polygons
    p.setPen(Qt::NoPen);
    for (const DebugPath& path : frame->debug_polygons()) {
        if (path.layer() < 0 || layerVisible(path.layer())) {
            if (path.points_size() < 3) {
                fprintf(stderr, "Ignoring DebugPolygon with %d points\n",
                        path.points_size());
                continue;
            }

            QColor color = qcolor(path.color());
            color.setAlpha(64);
            p.setBrush(color);
            std::vector<QPointF> pts;
            for (int i = 0; i < path.points_size(); ++i) {
                pts.push_back(qpointf(path.points(i)));
            }
            p.drawConvexPolygon(pts.data(), pts.size());
        }
    }
    p.setBrush(Qt::NoBrush);

    // maps robots to their comet trails, so we can draw a path of where each
    // robot has been over the past X frames the pair used as a key is of the
    // form (team, robot_id).  Blue team = 1, yellow = 2. we only draw trails
    // for robots that exist in the current frame
    map<pair<int, int>, QPainterPath> cometTrails;

    /// populate @cometTrails with the past locations of each robot
    int pastLocationCount = 40;  // number of past locations to show
    for (int i = 0; i < pastLocationCount + 1 && i < _history->size(); i++) {
        const LogFrame* oldFrame = _history->at(i).get();
        if (oldFrame) {
            for (const LogFrame::Robot& r : oldFrame->self()) {
                pair<int, int> key(1, r.shell());
                if (cometTrails.find(key) != cometTrails.end() || i == 0) {
                    QPointF pt = qpointf(r.pos());
                    if (i == 0)
                        cometTrails[key].moveTo(pt);
                    else
                        cometTrails[key].lineTo(pt);
                }
            }

            for (const LogFrame::Robot& r : oldFrame->self()) {
                pair<int, int> key(2, r.shell());
                if (cometTrails.find(key) != cometTrails.end() || i == 0) {
                    QPointF pt = qpointf(r.pos());
                    if (i == 0)
                        cometTrails[key].moveTo(pt);
                    else
                        cometTrails[key].lineTo(pt);
                }
            }
        }
    }

    // draw robot comet trails
    const float cometTrailPenSize = 0.07;
    for (auto& kv : cometTrails) {
        QColor color = kv.first.first == 1 ? Qt::blue : Qt::yellow;
        QPen pen(color, cometTrailPenSize);
        pen.setCapStyle(Qt::RoundCap);
        p.setPen(pen);
        p.drawPath(kv.second);
    }

    // Text positioning vectors
    QPointF rtX = qpointf(Geometry2d::Point(0, 1).rotated(-_rotate * 90));
    QPointF rtY = qpointf(Geometry2d::Point(-1, 0).rotated(-_rotate * 90));

    // Opponent robots
    for (const LogFrame::Robot& r : frame->opp()) {
        drawRobot(p, !frame->blue_team(), r.shell(), qpointf(r.pos()),
                  r.angle(), r.ball_sense_status() == HasBall);
    }

    // Our robots
    int manualID = frame->manual_id();
    for (const LogFrame::Robot& r : frame->self()) {
        QPointF center = qpointf(r.pos());

        bool faulty = false;
        if (r.has_ball_sense_status() && (r.ball_sense_status() == Dazzled ||
                                          r.ball_sense_status() == Failed)) {
            faulty = true;
        }
        if (r.has_kicker_works() && !r.kicker_works()) {
            // 			faulty = true;
        }
        for (int i = 0; i < r.motor_status().size(); ++i) {
            if (r.motor_status(i) != Good) {
                faulty = true;
            }
        }
        if (r.has_battery_voltage() && r.battery_voltage() <= 14.3f) {
            faulty = true;
        }

        drawRobot(p, frame->blue_team(), r.shell(), center, r.angle(),
                  r.ball_sense_status() == HasBall, faulty);

        // Highlight the manually controlled robot
        if (manualID == r.shell()) {
            p.setPen(greenPen);
            const float r = Robot_Radius + .05;
            p.drawEllipse(center, r, r);
        }

        // Robot text
        QPointF textPos = center - rtX * 0.2 - rtY * (Robot_Radius + 0.1);
        for (const DebugText& text : r.text()) {
            if (text.layer() < 0 || layerVisible(text.layer())) {
                tempPen.setColor(text.color());
                p.setPen(tempPen);
                drawText(p, textPos, QString::fromStdString(text.text()),
                         false);
                textPos -= rtY * 0.1;
            }
        }
    }

    // Current ball position and velocity
    if (frame->has_ball()) {
        QPointF pos = qpointf(frame->ball().pos());
        QPointF vel = qpointf(frame->ball().vel());

        p.setPen(ballPen);
        p.setBrush(ballColor);
        p.drawEllipse(QRectF(-Ball_Radius + pos.x(), -Ball_Radius + pos.y(),
                             Ball_Diameter, Ball_Diameter));

        if (!vel.isNull()) {
            p.drawLine(pos, QPointF(pos.x() + vel.x(), pos.y() + vel.y()));
        }
    }
}