Dragging a lever based on orientation & viewing angle

Looks like I’m getting pretty close:
[video]https://youtu.be/ops__oWtFf0[/video]

Here’s the code I used in the video
(USERotatingDevice is a subclass of USEDeviceActivator, which handles all the mouse input and event delegates for the component):


/* Called whenever a mouse drag operation occurs */
void USERotatingDevice::OnDeviceDragged_Callback(UActorComponent *Device, FVector2D DeltaMouse, float DeltaTime)
{
    // Only allow changes to occur on the device being interacted with
    if (Device != this)
        return;

    // Only allow changes to occur if this component is attached to a base component
    TArray<USceneComponent*> Parents;
    GetParentComponents(Parents);
    if (Parents.Num() < 1)
        return;

    // Find the base component
    USceneComponent *Base = nullptr;
    for (auto Parent : Parents) {
        if (Parent->GetName().Contains(TEXT("Base"))) {
            Base = Parent;
            break;
        }
    }

    // Exit if no valid base component could be found
    if (!IsValid(Base))
        return;

    // Exit if no activation nodes have been defined
    auto NodeCount = ActivationNodes.Num();
    if (NodeCount < 1)
        return;

    // Get the handle and pivot socket locations
    auto GrabSocketLocation = FVector::ZeroVector;
    auto PivotSocketLocation = FVector::ZeroVector;
    if (ActivationMesh->HasAnySockets()) {
        if (MeshSocketName != NAME_None) {
            GrabSocketLocation = ActivationMesh->GetSocketLocation(MeshSocketName);
        }
        PivotSocketLocation = ActivationMesh->GetSocketLocation(TEXT("PivotPoint"));
    }

    // Get the mouse location & directional vector (in world coordinates)
    auto PC = CastChecked<AMyPlayerController>(UGameplayStatics::GetPlayerController(GetWorld(), 0));
    auto MouseWorldLocation = FVector::ZeroVector;
    auto MouseWorldDirection = FVector::ZeroVector;
    PC->DeprojectMousePositionToWorld(MouseWorldLocation, MouseWorldDirection);

    // Get the device's normalized directional vectors
    auto BaseUpVector = Base->GetUpVector();
    auto BaseRightVector = Base->GetRightVector();
    auto BaseForwardVector = Base->GetForwardVector();

    // Get the camera's normlized directional vectors
    auto Character = CastChecked<ASEDeviceTestCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
    auto CharacterCamera = Character->GetFirstPersonCameraComponent();
    auto CameraUpVector = CharacterCamera->GetUpVector();
    auto CameraRightVector = CharacterCamera->GetRightVector();
    auto CameraForwardVector = CharacterCamera->GetForwardVector();

    // Get the direction vectors between Pivot & Handle, and Pivot & Mouse
    auto HandleUpVector = -(PivotSocketLocation - GrabSocketLocation); // Not sure why, but without the negation this is actually a "down" vector
    auto PivotToMouseVector = PivotSocketLocation - MouseWorldLocation;
    HandleUpVector.Normalize();
    PivotToMouseVector.Normalize();

    auto LeverActivationVector = BaseForwardVector;
    auto dotPUp = FVector::DotProduct(LeverActivationVector.SafeNormal(), CameraUpVector);
    auto dotPRight = FVector::DotProduct(LeverActivationVector.SafeNormal(), CameraRightVector);
    auto dotPForward = FVector::DotProduct(LeverActivationVector.SafeNormal(), CameraForwardVector);

    auto StrDotPUp = FString(TEXT("[UP]: ")).Append(FString::SanitizeFloat(dotPUp));
    auto StrDotPRight = FString(TEXT("[RIGHT]: ")).Append(FString::SanitizeFloat(dotPRight));
    auto StrDotPForward = FString(TEXT("[FORWARD]: ")).Append(FString::SanitizeFloat(dotPForward));

    FlushPersistentDebugLines(GetWorld());
    DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, PivotSocketLocation + (BaseForwardVector * 40.f), 6.f, FColor::Red, false, 3.f, 0, 1.5f);
    DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, PivotSocketLocation + (BaseRightVector * 40.f), 6.f, FColor::Green, false, 3.f, 0, 1.5f);
    DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, PivotSocketLocation + (BaseUpVector * 40.f), 6.f, FColor::Blue, false, 3.f, 0, 1.5f);
    DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, GrabSocketLocation + (HandleUpVector * 40.f), 6.f, FColor::Yellow, false, 3.f, 1, 2.f);

    auto color = FColor::White;
    auto message = FString(TEXT("N/A"));

    // in front
    if (dotPForward > 0.5f && FMath::Abs(dotPRight) < 0.5f &&  FMath::Abs(dotPUp) < 0.5f)
    {
        color = FColor::Blue;
        message = TEXT("Floor: FRONT");
    }
    // behind
    if (dotPForward < 0.5f && FMath::Abs(dotPRight) < 0.5f &&  FMath::Abs(dotPUp) < 0.5f)
    {
        color = FColor::Cyan;
        message = TEXT("Floor: BEHIND");
    }
    // from right side
    if (dotPRight > 0.5f && FMath::Abs(dotPForward) < 0.5f &&  FMath::Abs(dotPUp) < 0.5f)
    {
        color = FColor::Emerald;
        message = TEXT("Floor: RIGHT");
    }
    // from left side
    if (dotPRight < 0.5f && FMath::Abs(dotPForward) < 0.5f &&  FMath::Abs(dotPUp) < 0.5f)
    {
        color = FColor::Green;
        message = TEXT("Floor: LEFT");
    }
    // on wall
    if (FMath::Abs(dotPUp) > 0.5f)
    {
        color = FColor::Magenta;
        message = TEXT("Wall");
    }

    FlushDebugStrings(GetWorld());
    DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 40.f), message, nullptr, color);
    DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 32.f), StrDotPUp, nullptr, dotPUp < 0.f ? FColor::Red : FColor::Green);
    DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 24.f), StrDotPRight, nullptr, dotPRight < 0.f ? FColor::Red : FColor::Green);
    DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 16.f), StrDotPForward, nullptr, dotPForward < 0.f ? FColor::Red : FColor::Green);
}

Any suggestions?