35 #include <vtkPiecewiseFunction.h>
38 #include <QMouseEvent>
49 QWidget(parent), mBorder(4), mStart(0), mStop(0), mPos(0), mCloseToGlyph(false), mTolerance_p(5)
51 mForward = vtkPiecewiseFunctionPtr::New();
52 mBackward = vtkPiecewiseFunctionPtr::New();
62 this->setFocusPolicy(Qt::StrongFocus);
63 this->setMouseTracking(
true);
86 double TimelineWidget::findCompactedTime(
double timeInterval,
double totalUsedTime,
double totalTime)
const
95 double compactingFactor0 = 0.2;
96 double compactingFactor1 = totalUsedTime/totalTime * 0.2;
99 double w = timeInterval/totalTime;
100 double c = w*compactingFactor1 + (1-w)*compactingFactor0;
102 double compactedTime = std::min(timeInterval * c, 0.2*totalUsedTime);
104 return compactedTime;
115 void TimelineWidget::createCompactingTransforms()
119 std::vector<TimelineEvent> temp = mEvents;
123 for (
unsigned i = 0; i < temp.size(); ++i)
125 temp[i].mDescription =
"merged";
126 temp[i].mStartTime = std::max(temp[i].mStartTime - fat, mStart);
127 temp[i].mEndTime = std::min(temp[i].mEndTime + fat, mStop);
131 for (
unsigned i = 0; i < temp.size(); ++i)
135 for (
unsigned j = i + 1; j < temp.size();)
137 if (temp[i].isOverlap(temp[j]))
139 temp[i].mStartTime = std::min(temp[i].mStartTime, temp[j].mStartTime);
140 temp[i].mEndTime = std::max(temp[i].mEndTime, temp[j].mEndTime);
141 temp.erase(temp.begin() + j);
151 std::sort(temp.begin(), temp.end());
153 double totalUsedTime = 0;
154 for (
unsigned i = 0; i < temp.size(); ++i)
155 totalUsedTime += temp[i].mEndTime - temp[i].mStartTime;
160 mForward = vtkPiecewiseFunctionPtr::New();
163 mForward->AddPoint(mStart, y);
164 double x_last = mStart;
165 for (
unsigned i = 0; i < temp.size(); ++i)
168 y = y + this->findCompactedTime(temp[i].mStartTime - x_last, totalUsedTime, mStop-mStart);
169 mForward->AddPoint(temp[i].mStartTime, y);
171 y = y + temp[i].mEndTime - temp[i].mStartTime;
172 mForward->AddPoint(temp[i].mEndTime, y);
174 x_last = temp[i].mEndTime;
178 y = y + this->findCompactedTime(mStop - x_last, totalUsedTime, mStop-mStart);
179 mForward->AddPoint(mStop, y);
183 mForward->GetRange(range);
184 double y_min = mForward->GetValue(range[0]);
185 double y_max = mForward->GetValue(range[1]);
186 for (
int i = 0; i < mForward->GetSize(); ++i)
189 mForward->GetNodeValue(i, val);
190 val[1] = (val[1] - y_min) / (y_max - y_min);
191 mForward->SetNodeValue(i, val);
195 mBackward = vtkPiecewiseFunctionPtr::New();
196 for (
int i = 0; i < mForward->GetSize(); ++i)
199 mForward->GetNodeValue(i, val);
200 mBackward->AddPoint(val[1], val[0]);
203 mNoncompactedIntervals = temp;
213 this->createCompactingTransforms();
219 for (
unsigned i = 0; i < mEvents.size(); ++i)
221 if (mEvents[i].isSingular())
225 if (!std::count(mContinousEvents.begin(), mContinousEvents.end(), mEvents[i].mGroup))
226 mContinousEvents.push_back(mEvents[i].mGroup);
240 int TimelineWidget::mapTime2PlotX(
double time)
const
242 double normalized = mForward->GetValue(time);
244 int retval = normalized * mPlotArea.width() + mPlotArea.left();
250 double TimelineWidget::mapPlotX2Time(
int plotX)
const
252 double normalized = double(plotX - mPlotArea.left()) / mPlotArea.width();
253 double retval = mBackward->GetValue(normalized);
262 QWidget::paintEvent(event);
264 QPainter painter(
this);
266 painter.setRenderHint(QPainter::Antialiasing);
267 painter.setPen(Qt::NoPen);
269 QColor gray0(240, 240, 240);
270 QColor gray01(220, 220, 220);
271 QColor gray1(200, 200, 200);
272 QColor gray2(170, 170, 170);
273 QColor gray3(150, 150, 150);
274 QColor gray4(100, 100, 100);
275 QColor highlight(110, 214, 255);
278 QBrush brush(Qt::SolidPattern);
279 brush.setColor(gray2);
280 painter.setBrush(brush);
282 painter.drawRoundedRect(this->mFullArea, 4, 4);
284 brush.setColor(gray1);
285 painter.setBrush(brush);
286 painter.drawRoundedRect(this->mPlotArea, 4, 4);
291 for (
unsigned i = 0; i < mNoncompactedIntervals.size(); ++i)
293 int start_p = this->mapTime2PlotX(mNoncompactedIntervals[i].mStartTime);
294 int stop_p = this->mapTime2PlotX(mNoncompactedIntervals[i].mEndTime);
295 QColor color = gray01;
296 painter.fillRect(QRect(start_p, mPlotArea.top(), stop_p - start_p, mPlotArea.height()), color);
300 for (
unsigned i = 0; i < mEvents.size(); ++i)
302 if (!mContinousEvents.contains(mEvents[i].mGroup))
304 int start_p = this->mapTime2PlotX(mEvents[i].mStartTime);
305 int stop_p = this->mapTime2PlotX(mEvents[i].mEndTime);
306 int level = std::distance(mContinousEvents.begin(),
307 std::find(mContinousEvents.begin(), mContinousEvents.end(), mEvents[i].mGroup));
308 int level_max = mContinousEvents.size();
309 int thisHeight = (mPlotArea.height()) / level_max - margin * (level_max - 1) / level_max;
310 int thisTop = mPlotArea.top() + level * thisHeight + level * margin;
313 QColor color = mEvents[i].mColor;
315 painter.fillRect(QRect(start_p, thisTop, stop_p - start_p, thisHeight), color);
319 for (
unsigned i = 0; i < mEvents.size(); ++i)
321 if (mContinousEvents.contains(mEvents[i].mGroup))
324 int start_p = this->mapTime2PlotX(mEvents[i].mStartTime);
328 QRect rect(start_p - glyphWidth / 2, mPlotArea.top(), glyphWidth, mPlotArea.height());
330 brush.setColor(QColor(50, 50, 50));
331 painter.setBrush(brush);
332 painter.drawRoundedRect(rect, 2, 2);
335 if (rect.width() > 2 && rect.height() > 2)
337 rect.adjust(1, 1, -1, -1);
338 painter.fillRect(rect, gray2);
342 int offset_p = this->mapTime2PlotX(mPos);
345 int h = mPlotArea.height();
346 glyph.push_back(QPointF(-z, 0));
347 glyph.push_back(QPointF(z, 0));
348 glyph.push_back(QPointF(z, 0.7 * h));
349 glyph.push_back(QPointF(0, h));
350 glyph.push_back(QPointF(-z, 0.7 * h));
351 glyph.translate(offset_p, 0);
352 if (this->hasFocus() || mCloseToGlyph)
353 painter.setPen(highlight);
355 painter.setPen(gray4);
358 QRadialGradient radialGrad(QPointF(offset_p, h / 3), 2 * h / 3);
359 radialGrad.setColorAt(0, gray0);
361 radialGrad.setColorAt(1, gray2);
363 brush = QBrush(radialGrad);
365 painter.setBrush(brush);
366 painter.drawPolygon(glyph);
371 QWidget::resizeEvent(evt);
374 this->mFullArea = QRect(0, 0, width(), height());
375 this->mPlotArea = QRect(mBorder, mBorder, width() - mBorder * 2, height() - mBorder * 2);
378 void TimelineWidget::setPositionFromScreenPos(
int x,
int y)
380 mPos = this->mapPlotX2Time(x);
387 QWidget::mousePressEvent(event);
389 if (event->button() == Qt::LeftButton)
391 this->setPositionFromScreenPos(event->x(),
event->y());
396 QWidget::mouseReleaseEvent(event);
401 if (event->type() == QEvent::ToolTip)
403 QHelpEvent *helpEvent =
static_cast<QHelpEvent *
>(
event);
404 if (!this->showHelp(helpEvent->pos()))
411 return QWidget::event(event);
414 bool TimelineWidget::showHelp(QPoint pos)
416 double mouseTimePos = this->mapPlotX2Time(pos.x());
417 double tol_ms = this->mapPlotX2Time(pos.x()+mTolerance_p) - mouseTimePos;
421 for (
unsigned i = 0; i < mEvents.size(); ++i)
423 if (mEvents[i].isInside(mouseTimePos, tol_ms))
425 text << mEvents[i].mDescription;
432 QToolTip::hideText();
439 QToolTip::showText(this->mapToGlobal(pos), text.join(
"\n"),
this);
446 QWidget::mouseMoveEvent(event);
448 if (event->buttons() == Qt::LeftButton)
450 this->setPositionFromScreenPos(event->x(),
event->y());
453 bool newCloseToGlyph = fabs((
double)(this->mapTime2PlotX(mPos) - event->x())) < 5;
454 if (mCloseToGlyph != newCloseToGlyph)
459 mCloseToGlyph = newCloseToGlyph;
464 return QSize(100, 30);
469 return QSize(100, 20);
bool similar(const DoubleBoundingBox3D &a, const DoubleBoundingBox3D &b, double tol)