ralpha-assets/Plugins/CesiumForUnreal/Source/CesiumEditor/Private/CesiumGlobeAnchorCustomizat...

324 lines
12 KiB
C++

// Copyright 2020-2024 CesiumGS, Inc. and Contributors
#include "CesiumGlobeAnchorCustomization.h"
#include "CesiumCustomization.h"
#include "CesiumDegreesMinutesSecondsEditor.h"
#include "CesiumGeoreference.h"
#include "CesiumGlobeAnchorComponent.h"
#include "DetailCategoryBuilder.h"
#include "DetailLayoutBuilder.h"
#include "DetailWidgetRow.h"
#include "IDetailGroup.h"
#include "Widgets/SToolTip.h"
#include "Widgets/Text/STextBlock.h"
#define LOCTEXT_NAMESPACE "CesiumGlobeAnchorCustomization"
FName FCesiumGlobeAnchorCustomization::RegisteredLayoutName;
void FCesiumGlobeAnchorCustomization::Register(
FPropertyEditorModule& PropertyEditorModule) {
RegisteredLayoutName = UCesiumGlobeAnchorComponent::StaticClass()->GetFName();
PropertyEditorModule.RegisterCustomClassLayout(
RegisteredLayoutName,
FOnGetDetailCustomizationInstance::CreateStatic(
&FCesiumGlobeAnchorCustomization::MakeInstance));
}
void FCesiumGlobeAnchorCustomization::Unregister(
FPropertyEditorModule& PropertyEditorModule) {
PropertyEditorModule.UnregisterCustomClassLayout(RegisteredLayoutName);
}
TSharedRef<IDetailCustomization>
FCesiumGlobeAnchorCustomization::MakeInstance() {
return MakeShareable(new FCesiumGlobeAnchorCustomization);
}
void FCesiumGlobeAnchorCustomization::CustomizeDetails(
IDetailLayoutBuilder& DetailBuilder) {
DetailBuilder.GetObjectsBeingCustomized(this->SelectedObjects);
const bool bIsMultiSelect = this->SelectedObjects.Num() > 1;
IDetailCategoryBuilder& CesiumCategory = DetailBuilder.EditCategory("Cesium");
TSharedPtr<CesiumButtonGroup> pButtons =
CesiumCustomization::CreateButtonGroup();
pButtons->AddButtonForUFunction(
UCesiumGlobeAnchorComponent::StaticClass()->FindFunctionByName(
GET_FUNCTION_NAME_CHECKED(
UCesiumGlobeAnchorComponent,
SnapLocalUpToEllipsoidNormal)));
pButtons->AddButtonForUFunction(
UCesiumGlobeAnchorComponent::StaticClass()->FindFunctionByName(
GET_FUNCTION_NAME_CHECKED(
UCesiumGlobeAnchorComponent,
SnapToEastSouthUp)));
pButtons->Finish(DetailBuilder, CesiumCategory);
CesiumCategory.AddProperty(
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorComponent, Georeference));
CesiumCategory.AddProperty(GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorComponent,
ResolvedGeoreference));
CesiumCategory.AddProperty(GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorComponent,
AdjustOrientationForGlobeWhenMoving));
CesiumCategory.AddProperty(GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorComponent,
TeleportWhenUpdatingTransform));
if (!bIsMultiSelect) {
this->UpdateDerivedProperties();
this->CreatePositionLongitudeLatitudeHeight(DetailBuilder, CesiumCategory);
this->CreatePositionEarthCenteredEarthFixed(DetailBuilder, CesiumCategory);
this->CreateRotationEastSouthUp(DetailBuilder, CesiumCategory);
} else {
FDetailWidgetRow& Row =
CesiumCategory
.AddCustomRow(
LOCTEXT("MultipleSelectionFilter", "Multiple Selection"))
.FilterString(LOCTEXT(
"MultipleSelectionFilters",
"Latitude Longitude Height ECEF ESU"));
Row.WholeRowContent()[SNew(SBox).Padding(FMargin(
0.f,
4.f))[SNew(STextBlock)
.Text(LOCTEXT(
"MultiSelectInfo",
"Multiple actors selected. Geodetic position (Latitude, Longitude, Height; ECEF) and "
"ESU rotation cannot be edited in multi-select. Select a single actor to edit these values."))
.AutoWrapText(true)]];
}
}
void FCesiumGlobeAnchorCustomization::CreatePositionEarthCenteredEarthFixed(
IDetailLayoutBuilder& DetailBuilder,
IDetailCategoryBuilder& Category) {
IDetailGroup& Group = CesiumCustomization::CreateGroup(
Category,
"PositionEarthCenteredEarthFixed",
FText::FromString("Position (Earth-Centered, Earth-Fixed)"),
false,
true);
TArrayView<UObject*> View = this->DerivedPointers;
TSharedPtr<IPropertyHandle> XProperty = DetailBuilder.AddObjectPropertyData(
View,
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, X));
TSharedPtr<IPropertyHandle> YProperty = DetailBuilder.AddObjectPropertyData(
View,
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, Y));
TSharedPtr<IPropertyHandle> ZProperty = DetailBuilder.AddObjectPropertyData(
View,
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, Z));
Group.AddPropertyRow(XProperty.ToSharedRef());
Group.AddPropertyRow(YProperty.ToSharedRef());
Group.AddPropertyRow(ZProperty.ToSharedRef());
}
void FCesiumGlobeAnchorCustomization::CreatePositionLongitudeLatitudeHeight(
IDetailLayoutBuilder& DetailBuilder,
IDetailCategoryBuilder& Category) {
IDetailGroup& Group = CesiumCustomization::CreateGroup(
Category,
"PositionLatitudeLongitudeHeight",
FText::FromString("Position (Latitude, Longitude, Height)"),
false,
true);
TArrayView<UObject*> View = this->DerivedPointers;
TSharedPtr<IPropertyHandle> LatitudeProperty =
DetailBuilder.AddObjectPropertyData(
View,
GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Latitude));
TSharedPtr<IPropertyHandle> LongitudeProperty =
DetailBuilder.AddObjectPropertyData(
View,
GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Longitude));
TSharedPtr<IPropertyHandle> HeightProperty =
DetailBuilder.AddObjectPropertyData(
View,
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, Height));
IDetailPropertyRow& LatitudeRow =
Group.AddPropertyRow(LatitudeProperty.ToSharedRef());
LatitudeEditor =
MakeShared<CesiumDegreesMinutesSecondsEditor>(LatitudeProperty, false);
LatitudeEditor->PopulateRow(LatitudeRow);
IDetailPropertyRow& LongitudeRow =
Group.AddPropertyRow(LongitudeProperty.ToSharedRef());
LongitudeEditor =
MakeShared<CesiumDegreesMinutesSecondsEditor>(LongitudeProperty, true);
LongitudeEditor->PopulateRow(LongitudeRow);
Group.AddPropertyRow(HeightProperty.ToSharedRef());
}
void FCesiumGlobeAnchorCustomization::CreateRotationEastSouthUp(
IDetailLayoutBuilder& DetailBuilder,
IDetailCategoryBuilder& Category) {
IDetailGroup& Group = CesiumCustomization::CreateGroup(
Category,
"RotationEastSouthUp",
FText::FromString("Rotation (East-South-Up)"),
false,
true);
this->UpdateDerivedProperties();
TArrayView<UObject*> EastSouthUpPointerView = this->DerivedPointers;
TSharedPtr<IPropertyHandle> RollProperty =
DetailBuilder.AddObjectPropertyData(EastSouthUpPointerView, "Roll");
TSharedPtr<IPropertyHandle> PitchProperty =
DetailBuilder.AddObjectPropertyData(EastSouthUpPointerView, "Pitch");
TSharedPtr<IPropertyHandle> YawProperty =
DetailBuilder.AddObjectPropertyData(EastSouthUpPointerView, "Yaw");
Group.AddPropertyRow(RollProperty.ToSharedRef());
Group.AddPropertyRow(PitchProperty.ToSharedRef());
Group.AddPropertyRow(YawProperty.ToSharedRef());
}
void FCesiumGlobeAnchorCustomization::UpdateDerivedProperties() {
this->DerivedObjects.SetNum(this->SelectedObjects.Num());
this->DerivedPointers.SetNum(DerivedObjects.Num());
for (int i = 0; i < this->SelectedObjects.Num(); ++i) {
if (!IsValid(this->DerivedObjects[i].Get())) {
this->DerivedObjects[i] =
NewObject<UCesiumGlobeAnchorDerivedProperties>();
}
UCesiumGlobeAnchorComponent* GlobeAnchor =
Cast<UCesiumGlobeAnchorComponent>(this->SelectedObjects[i]);
this->DerivedObjects[i]->Initialize(GlobeAnchor);
this->DerivedPointers[i] = this->DerivedObjects[i].Get();
}
}
void UCesiumGlobeAnchorDerivedProperties::PostEditChangeProperty(
FPropertyChangedEvent& PropertyChangedEvent) {
Super::PostEditChangeProperty(PropertyChangedEvent);
if (!PropertyChangedEvent.Property) {
return;
}
FName propertyName = PropertyChangedEvent.Property->GetFName();
if (propertyName ==
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, X) ||
propertyName ==
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, Y) ||
propertyName ==
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, Z)) {
this->GlobeAnchor->Modify();
this->GlobeAnchor->MoveToEarthCenteredEarthFixedPosition(
FVector(this->X, this->Y, this->Z));
} else if (true) {
if (propertyName == GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Longitude) ||
propertyName == GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Latitude) ||
propertyName == GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Height)) {
this->GlobeAnchor->Modify();
this->GlobeAnchor->MoveToLongitudeLatitudeHeight(
FVector(this->Longitude, this->Latitude, this->Height));
} else if (
propertyName == GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Pitch) ||
propertyName ==
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, Yaw) ||
propertyName == GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Roll)) {
this->GlobeAnchor->Modify();
this->GlobeAnchor->SetEastSouthUpRotation(
FRotator(this->Pitch, this->Yaw, this->Roll).Quaternion());
}
}
}
bool UCesiumGlobeAnchorDerivedProperties::CanEditChange(
const FProperty* InProperty) const {
const FName Name = InProperty->GetFName();
// Valid georeference, nothing to disable
if (IsValid(this->GlobeAnchor->ResolveGeoreference())) {
return true;
}
return Name != GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Longitude) &&
Name != GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Latitude) &&
Name != GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Height) &&
Name != GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Pitch) &&
Name != GET_MEMBER_NAME_CHECKED(
UCesiumGlobeAnchorDerivedProperties,
Yaw) &&
Name !=
GET_MEMBER_NAME_CHECKED(UCesiumGlobeAnchorDerivedProperties, Roll);
}
void UCesiumGlobeAnchorDerivedProperties::Initialize(
UCesiumGlobeAnchorComponent* GlobeAnchorComponent) {
this->GlobeAnchor = GlobeAnchorComponent;
this->Tick(0.0f);
}
void UCesiumGlobeAnchorDerivedProperties::Tick(float DeltaTime) {
if (this->GlobeAnchor) {
FVector position = this->GlobeAnchor->GetEarthCenteredEarthFixedPosition();
this->X = position.X;
this->Y = position.Y;
this->Z = position.Z;
// We can't transform the GlobeAnchor's ECEF coordinates back to
// cartographic & rotation without a valid georeference to know what
// ellipsoid to use.
if (IsValid(this->GlobeAnchor->ResolveGeoreference())) {
FVector llh = this->GlobeAnchor->GetLongitudeLatitudeHeight();
this->Longitude = llh.X;
this->Latitude = llh.Y;
this->Height = llh.Z;
FQuat rotation = this->GlobeAnchor->GetEastSouthUpRotation();
FRotator rotator = rotation.Rotator();
this->Roll = rotator.Roll;
this->Pitch = rotator.Pitch;
this->Yaw = rotator.Yaw;
}
}
}
TStatId UCesiumGlobeAnchorDerivedProperties::GetStatId() const {
RETURN_QUICK_DECLARE_CYCLE_STAT(
UCesiumGlobeAnchorRotationEastSouthUp,
STATGROUP_Tickables);
}
#undef LOCTEXT_NAMESPACE