void Host::refreshDisplay() const
{cCanvas *canvas = getParentModule()->getCanvas();const int numCircles = 20;const double circleLineWidth = 10;// 第一次使用时候创建:如果没有传输波形图,则创建一个圆环内部填色,创建20个圆环,用边框填色if (!transmissionRing) {auto color = cFigure::GOOD_DARK_COLORS[getId() % cFigure::NUM_GOOD_DARK_COLORS];transmissionRing = new cRingFigure(("Host" + std::to_string(getIndex()) + "Ring").c_str());transmissionRing->setOutlined(false);transmissionRing->setFillColor(color);transmissionRing->setFillOpacity(0.25);transmissionRing->setFilled(true);transmissionRing->setVisible(false);transmissionRing->setZIndex(-1);canvas->addFigure(transmissionRing);for (int i = 0; i < numCircles; ++i) {auto circle = new cOvalFigure(("Host" + std::to_string(getIndex()) + "Circle" + std::to_string(i)).c_str());circle->setFilled(false);circle->setLineColor(color);circle->setLineOpacity(0.75);circle->setLineWidth(circleLineWidth);circle->setZoomLineWidth(true);circle->setVisible(false);circle->setZIndex(-0.5);transmissionCircles.push_back(circle);canvas->addFigure(circle);}}// 如果是最后一个包出现了,则把所有的圆形和圆环挂接到最后一个数据包上if (lastPacket) {// update transmission ring and circlesif (transmissionRing->getAssociatedObject() != lastPacket) {transmissionRing->setAssociatedObject(lastPacket);for (auto c : transmissionCircles)c->setAssociatedObject(lastPacket);}simtime_t now = simTime();simtime_t frontTravelTime = now - lastPacket->getSendingTime();simtime_t backTravelTime = now - (lastPacket->getSendingTime() + lastPacket->getDuration());// 使用光速,将波形的传播时间,对应到以米为单位的距离上// distance = speed * time,// 外圈不能超过最大传输距离,最大传播距离取最小值。double frontRadius = std::min(ringMaxRadius, frontTravelTime.dbl() * propagationSpeed);// 后圈,后面的传输时间直接对应距离double backRadius = backTravelTime.dbl() * propagationSpeed;// 各个圈的距离是按照:最大传输距离 / 圈数,用边框显示颜色double circleRadiusIncrement = circlesMaxRadius / numCircles;// 更新传输环几何结构和可见性/不透明度double opacity = 1.0;// 如果超过了最大传输距离,就不要显示了if (backRadius > ringMaxRadius) {transmissionRing->setVisible(false);transmissionRing->setAssociatedObject(nullptr);}else {// 设置圆形大小的矩形框transmissionRing->setVisible(true);transmissionRing->setBounds(cFigure::Rectangle(x - frontRadius, y - frontRadius, 2*frontRadius, 2*frontRadius));// 设置内环大小transmissionRing->setInnerRadius(std::max(0.0, std::min(ringMaxRadius, backRadius)));if (backRadius > 0)opacity = std::max(0.0, 1.0 - backRadius / circlesMaxRadius);}// 圆环部分的不透明度是慢慢减小的,也就是慢慢变淡消失transmissionRing->setLineOpacity(opacity);transmissionRing->setFillOpacity(opacity/5);// 设置一个个圆圈的 几何形状与不透明度// 首先按照前波走的距离,对间距取模,作为基础半径double radius0 = std::fmod(frontTravelTime.dbl() * propagationSpeed, circleRadiusIncrement);// 对每个圆圈单独计算for (int i = 0; i < (int)transmissionCircles.size(); ++i) {// 半径按照基础半径 + 圈数 * 增量double circleRadius = std::min(ringMaxRadius, radius0 + i * circleRadiusIncrement);// 如果圆圈位于前波与后波的范围内,时候显示;否则不显示;而且透明度也是慢慢递减的,展示衰减效果if (circleRadius < frontRadius - circleRadiusIncrement/2 && circleRadius > backRadius + circleLineWidth/2) {transmissionCircles[i]->setVisible(true);transmissionCircles[i]->setBounds(cFigure::Rectangle(x - circleRadius, y - circleRadius, 2*circleRadius, 2*circleRadius));transmissionCircles[i]->setLineOpacity(std::max(0.0, 0.2 - 0.2 * (circleRadius / circlesMaxRadius)));}elsetransmissionCircles[i]->setVisible(false);}// 计算动画速度,在传输不同的阶段,动画速度是不一样的,空闲时候是1,边界时候慢,中间时候稍微快些,在INI中定义double animSpeed = idleAnimationSpeed;if ((frontRadius >= 0 && frontRadius < circlesMaxRadius) || (backRadius >= 0 && backRadius < circlesMaxRadius))animSpeed = transmissionEdgeAnimationSpeed;if (frontRadius > circlesMaxRadius && backRadius < 0)animSpeed = midtransmissionAnimationSpeed;canvas->setAnimationSpeed(animSpeed, this);}else {// hide transmission rings, update animation speedif (transmissionRing->getAssociatedObject() != nullptr) {transmissionRing->setVisible(false);transmissionRing->setAssociatedObject(nullptr);for (auto c : transmissionCircles) {c->setVisible(false);c->setAssociatedObject(nullptr);}canvas->setAnimationSpeed(idleAnimationSpeed, this);}}// update host appearance (color and text)getDisplayString().setTagArg("t", 2, "#808000");if (state == IDLE) {getDisplayString().setTagArg("i", 1, "");getDisplayString().setTagArg("t", 0, "");}else if (state == TRANSMIT) {getDisplayString().setTagArg("i", 1, "yellow");getDisplayString().setTagArg("t", 0, "TRANSMIT");}
} // end display