175 lines
5.2 KiB
C++
175 lines
5.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Insights/ViewModels/GraphSeries.h"
|
|
|
|
// TraceInsights
|
|
#include "Insights/ViewModels/GraphTrackEvent.h"
|
|
#include "Insights/ViewModels/TimingTrackViewport.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "GraphTrack"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// FGraphSeries
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
INSIGHTS_IMPLEMENT_RTTI(FGraphSeries)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FGraphSeries::FGraphSeries()
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FGraphSeries::~FGraphSeries()
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const FGraphSeriesEvent* FGraphSeries::GetEvent(const float X, const float Y, const FTimingTrackViewport& Viewport, bool bCheckLine, bool bCheckBox) const
|
|
{
|
|
const float LocalBaselineY = static_cast<float>(GetBaselineY());
|
|
|
|
for (const FGraphSeriesEvent& Event : Events)
|
|
{
|
|
const float EventX1 = Viewport.TimeToSlateUnitsRounded(Event.Time);
|
|
const float EventX2 = Viewport.TimeToSlateUnitsRounded(Event.Time + Event.Duration);
|
|
|
|
const float EventY = GetRoundedYForValue(Event.Value);
|
|
|
|
// Check bounding box of the visual point.
|
|
constexpr float PointTolerance = 5.0f;
|
|
if (X >= EventX1 - PointTolerance && X <= EventX1 + PointTolerance &&
|
|
Y >= EventY - PointTolerance && Y <= EventY + PointTolerance)
|
|
{
|
|
return &Event;
|
|
}
|
|
|
|
if (bCheckLine)
|
|
{
|
|
// Check bounding box of the horizontal line.
|
|
constexpr float LineTolerance = 2.0f;
|
|
if (X >= EventX1 - LineTolerance && X <= EventX2 + LineTolerance &&
|
|
Y >= EventY - LineTolerance && Y <= EventY + LineTolerance)
|
|
{
|
|
return &Event;
|
|
}
|
|
}
|
|
|
|
if (bCheckBox)
|
|
{
|
|
// Check bounding box of the visual box.
|
|
constexpr float BoxTolerance = 1.0f;
|
|
if (X >= EventX1 - BoxTolerance && X <= EventX2 + BoxTolerance)
|
|
{
|
|
if (EventY < LocalBaselineY)
|
|
{
|
|
if (Y >= EventY - BoxTolerance && Y <= LocalBaselineY + BoxTolerance)
|
|
{
|
|
return &Event;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Y >= LocalBaselineY - BoxTolerance && Y <= EventY + BoxTolerance)
|
|
{
|
|
return &Event;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FString FGraphSeries::FormatValue(double Value) const
|
|
{
|
|
return FString::Printf(TEXT("%g"), Value);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool FGraphSeries::UpdateAutoZoomEx(const float InTopY, const float InBottomY, const double InMinEventValue, const double InMaxEventValue, const bool bIsAutoZoomAnimated)
|
|
{
|
|
bool bViewportChanged = false;
|
|
bIsAutoZoomDirty = false;
|
|
|
|
const double LowValue = GetValueForY(InBottomY);
|
|
const double HighValue = GetValueForY(InTopY);
|
|
|
|
double MinValue = InMinEventValue;
|
|
double MaxValue = InMaxEventValue;
|
|
|
|
// If MinValue == MaxValue, we keep the previous baseline and scale, but only if the min/max value is already visible.
|
|
if (MinValue == MaxValue && (MinValue < LowValue || MaxValue > HighValue))
|
|
{
|
|
MinValue = FMath::Min(MinValue, LowValue);
|
|
MaxValue = FMath::Max(MaxValue, HighValue);
|
|
}
|
|
|
|
if (MinValue < MaxValue)
|
|
{
|
|
if (bIsAutoZoomAnimated)
|
|
{
|
|
// Interpolate the min-max interval (animating the vertical position and scale of the graph series).
|
|
constexpr double InterpolationSpeed = 0.5;
|
|
const double NewMinValue = InterpolationSpeed * MinValue + (1.0 - InterpolationSpeed) * LowValue;
|
|
const double NewMaxValue = InterpolationSpeed * MaxValue + (1.0 - InterpolationSpeed) * HighValue;
|
|
|
|
// Check if we reach the target min-max interval.
|
|
const double ErrorTolerance = 0.5 / GetScaleY(); // delta value for dy ~= 0.5 pixels
|
|
if (!FMath::IsNearlyEqual(NewMinValue, MinValue, ErrorTolerance) ||
|
|
!FMath::IsNearlyEqual(NewMaxValue, MaxValue, ErrorTolerance))
|
|
{
|
|
MinValue = NewMinValue;
|
|
MaxValue = NewMaxValue;
|
|
|
|
// Request a new update so we can further interpolate the min-max interval.
|
|
bIsAutoZoomDirty = true;
|
|
}
|
|
}
|
|
|
|
double NewBaselineY;
|
|
double NewScaleY;
|
|
ComputeBaselineAndScale(MinValue, MaxValue, InTopY, InBottomY, NewBaselineY, NewScaleY);
|
|
|
|
if (NewBaselineY != GetBaselineY() || NewScaleY != GetScaleY())
|
|
{
|
|
bViewportChanged = true;
|
|
}
|
|
|
|
SetBaselineY(NewBaselineY);
|
|
SetScaleY(NewScaleY);
|
|
}
|
|
else
|
|
{
|
|
// If MinValue == MaxValue, we keep the previous baseline and scale.
|
|
}
|
|
|
|
return bViewportChanged;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void FGraphSeries::UpdateAutoZoom(const float InTopY, const float InBottomY, const double InMinEventValue, const double InMaxEventValue, const bool bIsAutoZoomAnimated)
|
|
{
|
|
if (IsAutoZoomEnabled())
|
|
{
|
|
UpdateAutoZoomEx(InTopY, InBottomY, InMinEventValue, InMaxEventValue, bIsAutoZoomAnimated);
|
|
|
|
if (bIsAutoZoomDirty)
|
|
{
|
|
SetDirtyFlag();
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#undef LOCTEXT_NAMESPACE
|