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 circles
if (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)));
}
else
transmissionCircles[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 speed
if (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