| 1123 | } |
| 1124 | |
| 1125 | bool GetActorBoundsSync( |
| 1126 | const FString& ActorKey, |
| 1127 | bool bComponentsOnly, |
| 1128 | double OutMin[3], |
| 1129 | double OutMax[3], |
| 1130 | FString& OutResolvedName, |
| 1131 | FString& OutError) |
| 1132 | { |
| 1133 | OutError.Empty(); |
| 1134 | if (!GEditor) |
| 1135 | { |
| 1136 | OutError = TEXT("GEditor null"); |
| 1137 | return false; |
| 1138 | } |
| 1139 | UWorld* World = GEditor->GetEditorWorldContext().World(); |
| 1140 | if (!World) |
| 1141 | { |
| 1142 | OutError = TEXT("editor world unavailable"); |
| 1143 | return false; |
| 1144 | } |
| 1145 | AActor* A = FindByActorIdOrName(World, ActorKey); |
| 1146 | if (!A) |
| 1147 | { |
| 1148 | OutError = FString::Printf(TEXT("no actor matching '%s'"), *ActorKey); |
| 1149 | return false; |
| 1150 | } |
| 1151 | OutResolvedName = A->GetName(); |
| 1152 | |
| 1153 | const FBox Box = A->GetComponentsBoundingBox(bComponentsOnly); |
| 1154 | // UE cm -> MJ metres, +Y -> -Y flip baked into MjUtils. |
| 1155 | double MjMin[3], MjMax[3]; |
| 1156 | MjUtils::UEToMjPosition(Box.Min, MjMin); |
| 1157 | MjUtils::UEToMjPosition(Box.Max, MjMax); |
| 1158 | // The Y-flip swaps min/max on that axis; normalise. |
| 1159 | for (int i = 0; i < 3; ++i) |
| 1160 | { |
| 1161 | OutMin[i] = FMath::Min(MjMin[i], MjMax[i]); |
| 1162 | OutMax[i] = FMath::Max(MjMin[i], MjMax[i]); |
| 1163 | } |
| 1164 | return true; |
| 1165 | } |
| 1166 | |
| 1167 | bool SnapshotSceneSync( |
| 1168 | TArray<TSharedPtr<FJsonValue>>& OutActors, |