116 const FVector2D& Start,
117 const FVector2D& End,
118 const FConnectionParams& Params
122 const FVector2D& P0 = Start;
123 const FVector2D& P1 = End;
126 const FVector2D P0Tangent = Params.StartDirection == EGPD_Output ? SplineTangent : -SplineTangent;
127 const FVector2D P1Tangent = Params.EndDirection == EGPD_Input ? SplineTangent : -SplineTangent;
129 if (Settings->bTreatSplinesLikePins)
132 const float QueryDistanceTriggerThresholdSquared = FMath::Square(Settings->SplineHoverTolerance + Params.WireThickness * 0.5f);
135 const float QueryDistanceToBoundingBoxSquared = QueryDistanceTriggerThresholdSquared;
137 bool bCloseToSpline =
false;
141 constexpr float MaximumTangentContribution = 4.0f / 27.0f;
142 FBox2D Bounds(ForceInit);
144 Bounds += FVector2D(P0);
145 Bounds += FVector2D(P0 + MaximumTangentContribution * P0Tangent);
146 Bounds += FVector2D(P1);
147 Bounds += FVector2D(P1 - MaximumTangentContribution * P1Tangent);
149 bCloseToSpline = Bounds.ComputeSquaredDistanceToPoint(LocalMousePosition) < QueryDistanceToBoundingBoxSquared;
155 FVector2D ClosestPoint(ForceInit);
156 float ClosestDistanceSquared = FLT_MAX;
158 constexpr int32 NumStepsToTest = 16;
159 constexpr float StepInterval = 1.0f /
static_cast<float>(NumStepsToTest);
160 FVector2D Point1 = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, 0.0f);
161 for (
float TestAlpha = 0.0f; TestAlpha < 1.0f; TestAlpha += StepInterval)
163 const FVector2D Point2 = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, TestAlpha + StepInterval);
165 const FVector2D ClosestPointToSegment = FMath::ClosestPointOnSegment2D(LocalMousePosition, Point1, Point2);
166 const float DistanceSquared = (LocalMousePosition - ClosestPointToSegment).SizeSquared();
168 if (DistanceSquared < ClosestDistanceSquared)
170 ClosestDistanceSquared = DistanceSquared;
171 ClosestPoint = ClosestPointToSegment;
178 if (ClosestDistanceSquared < QueryDistanceTriggerThresholdSquared)
180 if (ClosestDistanceSquared < SplineOverlapResult.GetDistanceSquared())
182 const float SquaredDistToPin1 = Params.AssociatedPin1 !=
nullptr ? (P0 - ClosestPoint).SizeSquared() : FLT_MAX;
184 float SquaredDistToPin2 = FLT_MAX;
185 UEdGraphPin* InputPin = Params.AssociatedPin2;
187 if (InputPin !=
nullptr)
190 UDialogueGraphNode_Edge* GraphNode_Edge = CastChecked<UDialogueGraphNode_Edge>(Params.AssociatedPin2->GetOwningNode());
192 SquaredDistToPin2 = (P1 - ClosestPoint).SizeSquared();
196 SplineOverlapResult = FGraphSplineOverlapResult(Params.AssociatedPin1, Params.AssociatedPin1, ClosestDistanceSquared,
197 SquaredDistToPin1, SquaredDistToPin1);
204 FSlateDrawElement::MakeDrawSpaceSpline(
209 Params.WireThickness,
210 ESlateDrawEffect::None,
214 if (Params.bDrawBubbles || (MidpointImage !=
nullptr))
217 FInterpCurve<float> SplineReparamTable;
218 const float SplineLength = MakeSplineReparamTable(P0, P0Tangent, P1, P1Tangent, SplineReparamTable);
221 if (Params.bDrawBubbles)
223 const float BubbleSpacing = 64.f * ZoomFactor;
224 const float BubbleSpeed = 192.f * ZoomFactor;
225 const FVector2D BubbleSize = BubbleImage->ImageSize * ZoomFactor * 0.1f * Params.WireThickness;
227 const float Time = FPlatformTime::Seconds() - GStartTime;
228 const float BubbleOffset = FMath::Fmod(Time * BubbleSpeed, BubbleSpacing);
229 const int32 NumBubbles = FMath::CeilToInt(SplineLength / BubbleSpacing);
230 for (int32 i = 0; i < NumBubbles; ++i)
232 const float Distance = (
static_cast<float>(i) * BubbleSpacing) + BubbleOffset;
233 if (Distance < SplineLength)
235 const float Alpha = SplineReparamTable.Eval(Distance, 0.f);
236 FVector2D BubblePos = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, Alpha);
237 BubblePos -= (BubbleSize * 0.5f);
239 FSlateDrawElement::MakeBox(
242 FPaintGeometry(BubblePos, BubbleSize, ZoomFactor),
244 ESlateDrawEffect::None,
252 if (MidpointImage !=
nullptr)
255 const float MidpointAlpha = SplineReparamTable.Eval(SplineLength * 0.5f, 0.f);
256 const FVector2D Midpoint = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha);
259 const FVector2D MidpointPlusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha + KINDA_SMALL_NUMBER);
260 const FVector2D MidpointMinusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha - KINDA_SMALL_NUMBER);
261 const FVector2D SlopeUnnormalized = MidpointPlusE - MidpointMinusE;
264 const FVector2D MidpointDrawPos = Midpoint - MidpointRadius;
265 const float AngleInRadians = SlopeUnnormalized.IsNearlyZero() ? 0.0f : FMath::Atan2(SlopeUnnormalized.Y, SlopeUnnormalized.X);
267 FSlateDrawElement::MakeRotatedBox(
270 FPaintGeometry(MidpointDrawPos, MidpointImage->ImageSize * ZoomFactor, ZoomFactor),
272 ESlateDrawEffect::None,
274 TOptional<FVector2D>(),
275 FSlateDrawElement::RelativeToElement,
330 const FVector2D& StartAnchorPoint,
331 const FVector2D& EndAnchorPoint,
332 const FConnectionParams& Params
335 constexpr float LineSeparationAmount = 4.5f;
337 const FVector2D DeltaPos = EndAnchorPoint - StartAnchorPoint;
338 const FVector2D UnitDelta = DeltaPos.GetSafeNormal();
339 const FVector2D Normal = FVector2D(DeltaPos.Y, -DeltaPos.X).GetSafeNormal();
342 const FVector2D DirectionBias = Normal * LineSeparationAmount;
343 const FVector2D LengthBias = ArrowRadius.X * UnitDelta;
344 const FVector2D StartPoint = StartAnchorPoint + DirectionBias + LengthBias;
345 const FVector2D EndPoint = EndAnchorPoint + DirectionBias - LengthBias;
353 const FVector2D ArrowDrawPos = EndPoint - ArrowRadius;
354 const float AngleInRadians = FMath::Atan2(DeltaPos.Y, DeltaPos.X);
356 FSlateDrawElement::MakeRotatedBox(
359 FPaintGeometry(ArrowDrawPos, ArrowImage->ImageSize * ZoomFactor, ZoomFactor),
361 ESlateDrawEffect::None,
363 TOptional<FVector2D>(),
364 FSlateDrawElement::RelativeToElement,