Cesium for Unreal 2.13.2
Loading...
Searching...
No Matches
CesiumGlobeAnchorComponent.h
Go to the documentation of this file.
1// Copyright 2020-2024 CesiumGS, Inc. and Contributors
2
3#pragma once
4
5#include "CesiumGeospatial/GlobeAnchor.h"
6#include "Components/ActorComponent.h"
7#include "Delegates/IDelegateInstance.h"
8#include "CesiumGlobeAnchorComponent.generated.h"
9
11
12/**
13 * This component can be added to a movable actor to anchor it to the globe
14 * and maintain precise placement. When the owning actor is transformed through
15 * normal Unreal Engine mechanisms, the internal geospatial coordinates will be
16 * automatically updated. The actor position can also be set in terms of
17 * Earth-Centered, Earth-Fixed coordinates (ECEF) or Longitude, Latitude, and
18 * Height relative to the ellipsoid.
19 */
20UCLASS(ClassGroup = Cesium, Meta = (BlueprintSpawnableComponent))
21class CESIUMRUNTIME_API UCesiumGlobeAnchorComponent : public UActorComponent {
22 GENERATED_BODY()
23
24#pragma region Properties
25private:
26 /**
27 * The designated georeference actor controlling how the owning actor's
28 * coordinate system relates to the coordinate system in this Unreal Engine
29 * level.
30 *
31 * If this is null, the Component will find and use the first Georeference
32 * Actor in the level, or create one if necessary. To get the active/effective
33 * Georeference from Blueprints or C++, use ResolvedGeoreference instead.
34 *
35 * If setting this property changes the CesiumGeoreference, the globe position
36 * will be maintained and the Actor's transform will be updated according to
37 * the new CesiumGeoreference.
38 */
39 UPROPERTY(
40 EditAnywhere,
41 BlueprintReadWrite,
42 BlueprintGetter = GetGeoreference,
43 BlueprintSetter = SetGeoreference,
44 Category = "Cesium",
45 Meta = (AllowPrivateAccess))
46 TSoftObjectPtr<ACesiumGeoreference> Georeference = nullptr;
47
48 /**
49 * The resolved georeference used by this component. This is not serialized
50 * because it may point to a Georeference in the PersistentLevel while this
51 * component is in a sub-level. If the Georeference property is specified,
52 * however then this property will have the same value.
53 *
54 * This property will be null before ResolveGeoreference is called, which
55 * happens automatically when the component is registered.
56 */
57 UPROPERTY(
58 Transient,
59 VisibleAnywhere,
60 BlueprintReadOnly,
61 BlueprintGetter = GetResolvedGeoreference,
62 Category = "Cesium",
63 Meta = (AllowPrivateAccess))
64 ACesiumGeoreference* ResolvedGeoreference = nullptr;
65
66 /**
67 * Whether to adjust the Actor's orientation based on globe curvature as the
68 * Actor moves.
69 *
70 * The Earth is not flat, so as we move across its surface, the direction of
71 * "up" changes. If we ignore this fact and leave an object's orientation
72 * unchanged as it moves over the globe surface, the object will become
73 * increasingly tilted and eventually be completely upside-down when we arrive
74 * at the opposite side of the globe.
75 *
76 * When this setting is enabled, this Component will automatically apply a
77 * rotation to the Actor to account for globe curvature any time the Actor's
78 * position on the globe changes.
79 *
80 * This property should usually be enabled, but it may be useful to disable it
81 * when your application already accounts for globe curvature itself when it
82 * updates an Actor's position and orientation, because in that case the Actor
83 * would be over-rotated.
84 */
85 UPROPERTY(
86 EditAnywhere,
87 BlueprintReadWrite,
88 BlueprintGetter = GetAdjustOrientationForGlobeWhenMoving,
89 BlueprintSetter = SetAdjustOrientationForGlobeWhenMoving,
90 Category = "Cesium",
91 Meta = (AllowPrivateAccess))
92 bool AdjustOrientationForGlobeWhenMoving = true;
93
94 /**
95 * Using the teleport flag will move objects to the updated transform
96 * immediately and without affecting their velocity. This is useful when
97 * working with physics actors that maintain an internal velocity which we do
98 * not want to change when updating location.
99 */
100 UPROPERTY(
101 EditAnywhere,
102 BlueprintReadWrite,
103 BlueprintGetter = GetTeleportWhenUpdatingTransform,
104 BlueprintSetter = SetTeleportWhenUpdatingTransform,
105 Category = "Cesium",
106 Meta = (AllowPrivateAccess))
107 bool TeleportWhenUpdatingTransform = true;
108
109 /**
110 * The 4x4 transformation matrix from the Actors's local coordinate system to
111 * the Earth-Centered, Earth-Fixed (ECEF) coordinate system.
112 *
113 * The ECEF coordinate system is a right-handed system located at the center
114 * of the Earth. The +X axis points to the intersection of the Equator and
115 * Prime Meridian (zero degrees longitude). The +Y axis points to the
116 * intersection of the Equator and +90 degrees longitude. The +Z axis points
117 * up through the North Pole.
118 *
119 * If `AdjustOrientationForGlobeWhenMoving` is enabled and this property is
120 * set, the Actor's orientation will also be adjusted to account for globe
121 * curvature.
122 */
123 UPROPERTY(
124 BlueprintReadWrite,
125 BlueprintGetter = GetActorToEarthCenteredEarthFixedMatrix,
126 BlueprintSetter = SetActorToEarthCenteredEarthFixedMatrix,
127 Category = "Cesium",
128 Meta = (AllowPrivateAccess))
129 FMatrix ActorToEarthCenteredEarthFixedMatrix;
130
131#pragma endregion
132
133#pragma region Property Accessors
134public:
135 /**
136 * Gets the designated georeference actor controlling how the owning actor's
137 * coordinate system relates to the coordinate system in this Unreal Engine
138 * level.
139 *
140 * If this is null, the Component will find and use the first Georeference
141 * Actor in the level, or create one if necessary. To get the active/effective
142 * Georeference from Blueprints or C++, use ResolvedGeoreference instead.
143 */
144 UFUNCTION(BlueprintGetter)
145 TSoftObjectPtr<ACesiumGeoreference> GetGeoreference() const;
146
147 /**
148 * Sets the designated georeference actor controlling how the owning actor's
149 * coordinate system relates to the coordinate system in this Unreal Engine
150 * level.
151 *
152 * If this is null, the Component will find and use the first Georeference
153 * Actor in the level, or create one if necessary. To get the active/effective
154 * Georeference from Blueprints or C++, use ResolvedGeoreference instead.
155 */
156 UFUNCTION(BlueprintSetter)
157 void SetGeoreference(TSoftObjectPtr<ACesiumGeoreference> NewGeoreference);
158
159 /**
160 * Gets the resolved georeference used by this component. This is not
161 * serialized because it may point to a Georeference in the PersistentLevel
162 * while this component is in a sub-level. If the Georeference property is
163 * manually specified, however, then this property will have the same value.
164 *
165 * This property will be null before ResolveGeoreference is called, which
166 * happens automatically when the component is registered.
167 */
168 UFUNCTION(BlueprintGetter)
169 ACesiumGeoreference* GetResolvedGeoreference() const;
170
171 /**
172 * Resolves the Cesium Georeference to use with this Component. Returns
173 * the value of the Georeference property if it is set. Otherwise, finds a
174 * Georeference in the World and returns it, creating it if necessary. The
175 * resolved Georeference is cached so subsequent calls to this function will
176 * return the same instance, unless ForceReresolve is true.
177 */
178 UFUNCTION(BlueprintCallable, Category = "Cesium")
179 ACesiumGeoreference* ResolveGeoreference(bool bForceReresolve = false);
180
181 /**
182 * Obtains the {@link UCesiumEllipsoid} set on the georeference used by this
183 * component.
184 */
185 UFUNCTION(BlueprintGetter, Category = "Cesium")
187
188 /**
189 * Gets the 4x4 transformation matrix from the Actors's local coordinate
190 * system to the Earth-Centered, Earth-Fixed (ECEF) coordinate system.
191 *
192 * The ECEF coordinate system is a right-handed system located at the center
193 * of the Earth. The +X axis points to the intersection of the Equator and
194 * Prime Meridian (zero degrees longitude). The +Y axis points to the
195 * intersection of the Equator and +90 degrees longitude. The +Z axis points
196 * up through the North Pole.
197 */
198 UFUNCTION(BlueprintGetter, Category = "Cesium")
199 FMatrix GetActorToEarthCenteredEarthFixedMatrix() const;
200
201 /**
202 * Sets the 4x4 transformation matrix from the Actors's local coordinate
203 * system to the Earth-Centered, Earth-Fixed (ECEF) coordinate system.
204 *
205 * The ECEF coordinate system is a right-handed system located at the center
206 * of the Earth. The +X axis points to the intersection of the Equator and
207 * Prime Meridian (zero degrees longitude). The +Y axis points to the
208 * intersection of the Equator and +90 degrees longitude. The +Z axis points
209 * up through the North Pole.
210 *
211 * If `AdjustOrientationForGlobeWhenMoving` is enabled, the Actor's
212 * orientation will also be adjusted to account for globe curvature.
213 */
214 UFUNCTION(BlueprintSetter, Category = "Cesium")
215 void SetActorToEarthCenteredEarthFixedMatrix(const FMatrix& Value);
216
217 /**
218 * Gets a flag indicating whether to move objects to the updated transform
219 * immediately and without affecting their velocity. This is useful when
220 * working with physics actors that maintain an internal velocity which we do
221 * not want to change when updating location.
222 */
223 UFUNCTION(BlueprintGetter, Category = "Cesium")
224 bool GetTeleportWhenUpdatingTransform() const;
225
226 /**
227 * Sets a flag indicating whether to move objects to the updated transform
228 * immediately and without affecting their velocity. This is useful when
229 * working with physics actors that maintain an internal velocity which we do
230 * not want to change when updating location.
231 */
232 UFUNCTION(BlueprintSetter, Category = "Cesium")
233 void SetTeleportWhenUpdatingTransform(bool Value);
234
235 /**
236 * Gets a flag indicating whether to adjust the Actor's orientation based on
237 * globe curvature as the Actor moves.
238 *
239 * The Earth is not flat, so as we move across its surface, the direction of
240 * "up" changes. If we ignore this fact and leave an object's orientation
241 * unchanged as it moves over the globe surface, the object will become
242 * increasingly tilted and eventually be completely upside-down when we arrive
243 * at the opposite side of the globe.
244 *
245 * When this setting is enabled, this Component will automatically apply a
246 * rotation to the Actor to account for globe curvature any time the Actor's
247 * position on the globe changes.
248 *
249 * This property should usually be enabled, but it may be useful to disable it
250 * when your application already accounts for globe curvature itself when it
251 * updates an Actor's position and orientation, because in that case the Actor
252 * would be over-rotated.
253 */
254 UFUNCTION(BlueprintGetter, Category = "Cesium")
255 bool GetAdjustOrientationForGlobeWhenMoving() const;
256
257 /**
258 * Sets a flag indicating whether to adjust the Actor's orientation based on
259 * globe curvature as the Actor moves.
260 *
261 * The Earth is not flat, so as we move across its surface, the direction of
262 * "up" changes. If we ignore this fact and leave an object's orientation
263 * unchanged as it moves over the globe surface, the object will become
264 * increasingly tilted and eventually be completely upside-down when we arrive
265 * at the opposite side of the globe.
266 *
267 * When this setting is enabled, this Component will automatically apply a
268 * rotation to the Actor to account for globe curvature any time the Actor's
269 * position on the globe changes.
270 *
271 * This property should usually be enabled, but it may be useful to disable it
272 * when your application already accounts for globe curvature itself when it
273 * updates an Actor's position and orientation, because in that case the Actor
274 * would be over-rotated.
275 */
276 UFUNCTION(BlueprintSetter, Category = "Cesium")
277 void SetAdjustOrientationForGlobeWhenMoving(bool Value);
278
279#pragma endregion
280
281#pragma region Public Methods
282
283public:
284 /**
285 * Gets the longitude in degrees (X), latitude in degrees (Y),
286 * and height in meters above the ellipsoid (Z) of the actor.
287 *
288 * Do not confuse the ellipsoid height with a geoid height or height above
289 * mean sea level, which can be tens of meters higher or lower depending on
290 * where in the world the object is located.
291 */
292 UFUNCTION(
293 BlueprintPure,
294 Category = "Cesium",
295 Meta = (ReturnDisplayName = "LongitudeLatitudeHeight"))
296 FVector GetLongitudeLatitudeHeight() const;
297
298 /**
299 * Gets the longitude in degrees.
300 */
301 UFUNCTION(
302 BlueprintPure,
303 Category = "Cesium",
304 Meta = (ReturnDisplayName = "Longitude"))
305 double GetLongitude() const { return this->GetLongitudeLatitudeHeight().X; }
306
307 /**
308 * Gets the latitude in degrees.
309 */
310 UFUNCTION(
311 BlueprintPure,
312 Category = "Cesium",
313 Meta = (ReturnDisplayName = "Latitude"))
314 double GetLatitude() const { return this->GetLongitudeLatitudeHeight().Y; }
315
316 /**
317 * Gets the height in meters above the ellipsoid.
318 *
319 * Do not confuse the ellipsoid height with a geoid height or height above
320 * mean sea level, which can be tens of meters higher or lower depending on
321 * where in the world the object is located.
322 */
323 UFUNCTION(
324 BlueprintPure,
325 Category = "Cesium",
326 Meta = (ReturnDisplayName = "Height"))
327 double GetHeight() const { return this->GetLongitudeLatitudeHeight().Z; }
328
329 /**
330 * Moves the Actor to which this component is attached to a given longitude in
331 * degrees (X), latitude in degrees (Y), and height in meters (Z).
332 *
333 * The Height (Z) is measured in meters above the ellipsoid. Do not
334 * confused an ellipsoidal height with a geoid height or height above mean sea
335 * level, which can be tens of meters higher or lower depending on where in
336 * the world the object is located.
337 *
338 * If `AdjustOrientationForGlobeWhenMoving` is enabled, the Actor's
339 * orientation will also be adjusted to account for globe curvature.
340 */
341 UFUNCTION(BlueprintCallable, Category = "Cesium")
342 void MoveToLongitudeLatitudeHeight(const FVector& LongitudeLatitudeHeight);
343
344 /**
345 * Gets the Earth-Centered, Earth-Fixed (ECEF) coordinates of the Actor in
346 * meters.
347 */
348 UFUNCTION(
349 BlueprintPure,
350 Category = "Cesium",
351 meta = (ReturnDisplayName = "EarthCenteredEarthFixedPosition"))
352 FVector GetEarthCenteredEarthFixedPosition() const;
353
354 /**
355 * Moves the Actor to which this component is attached to a given globe
356 * position in Earth-Centered, Earth-Fixed coordinates in meters.
357 *
358 * If AdjustOrientationForGlobeWhenMoving is enabled, this method will
359 * also update the orientation based on the globe curvature.
360 *
361 * @param EarthCenteredEarthFixedPosition The new position.
362 */
363 UFUNCTION(BlueprintCallable, Category = "Cesium")
364 void MoveToEarthCenteredEarthFixedPosition(
365 const FVector& EarthCenteredEarthFixedPosition);
366
367 /**
368 * Gets the rotation of the Actor relative to a local coordinate system
369 * centered on this object where the +X points in the local East direction,
370 * the +Y axis points in the local South direction, and the +Z axis points in
371 * the local Up direction.
372 */
373 UFUNCTION(
374 BlueprintPure,
375 Category = "Cesium",
376 meta = (ReturnDisplayName = "EastSouthUpRotation"))
377 FQuat GetEastSouthUpRotation() const;
378
379 /**
380 * Sets the rotation of the Actor relative to a local coordinate system
381 * centered on this object where the +X points in the local East direction,
382 * the +Y axis points in the local South direction, and the +Z axis points in
383 * the local Up direction.
384 *
385 * When the rotation is set via this method, it is internally converted to
386 * and stored in the ActorToEarthCenteredEarthFixedMatrix property. As a
387 * result, getting this property will not necessarily return the exact value
388 * that was set.
389 */
390 UFUNCTION(BlueprintCallable, Category = "Cesium")
391 void SetEastSouthUpRotation(const FQuat& EastSouthUpRotation);
392
393 /**
394 * Gets the rotation of the Actor relative to the Earth-Centered, Earth-Fixed
395 * (ECEF) coordinate system.
396 *
397 * The ECEF coordinate system is a right-handed system located at the center
398 * of the Earth. The +X axis points from there to the intersection of the
399 * Equator and Prime Meridian (zero degrees longitude). The +Y axis points to
400 * the intersection of the Equator and +90 degrees longitude. The +Z axis
401 * points up through the North Pole.
402 */
403 UFUNCTION(
404 BlueprintPure,
405 Category = "Cesium",
406 meta = (ReturnDisplayName = "EarthCenteredEarthFixedRotation"))
407 FQuat GetEarthCenteredEarthFixedRotation() const;
408
409 /**
410 * Sets the rotation of the Actor relative to the Earth-Centered, Earth-Fixed
411 * (ECEF) coordinate system.
412 *
413 * The ECEF coordinate system is a right-handed system located at the center
414 * of the Earth. The +X axis points from there to the intersection of the
415 * Equator and Prime Meridian (zero degrees longitude). The +Y axis points to
416 * the intersection of the Equator and +90 degrees longitude. The +Z axis
417 * points up through the North Pole.
418 */
419 UFUNCTION(BlueprintCallable, Category = "Cesium")
420 void SetEarthCenteredEarthFixedRotation(
421 const FQuat& EarthCenteredEarthFixedRotation);
422
423 /**
424 * Rotates the Actor so that its local +Z axis is aligned with the ellipsoid
425 * surface normal at its current location.
426 */
427 UFUNCTION(BlueprintCallable, Category = "Cesium")
428 void SnapLocalUpToEllipsoidNormal();
429
430 /**
431 * Rotates the Actor so that its +X axis points in the local East direction,
432 * its +Y axis points in the local South direction, and its +Z axis points in
433 * the local Up direction.
434 */
435 UFUNCTION(BlueprintCallable, Category = "Cesium")
436 void SnapToEastSouthUp();
437
438 /**
439 * Synchronizes the properties of this globe anchor.
440 *
441 * It is usually not necessary to call this method because it is called
442 * automatically when needed.
443 *
444 * This method performs the following actions:
445 *
446 * - If the ActorToEarthCenteredEarthFixedMatrix has not yet been
447 * determined, it is computed from the Actor's current root transform.
448 * - If the Actor's root transform has changed since the last time this
449 * component was registered, this method updates the
450 * ActorToEarthCenteredEarthFixedMatrix from the current transform.
451 * - If the origin of the CesiumGeoreference has changed, the Actor's root
452 * transform is updated based on the ActorToEarthCenteredEarthFixedMatrix and
453 * the new georeference origin.
454 */
455 UFUNCTION(BlueprintCallable, Category = "Cesium")
456 void Sync();
457
458#pragma endregion
459
460#pragma region Obsolete
461public:
462 /**
463 * @brief DEPRECATED
464 * @deprecated The resolved georeference can no longer be explicitly
465 * invalidated. To change the georeference, call SetGeoreference or
466 * ReregisterComponent.
467 */
468 UE_DEPRECATED(
469 "Cesium For Unreal v2.0",
470 "The resolved georeference can no longer be explicitly invalidated. To change the georeference, call SetGeoreference or ReregisterComponent.")
471 UFUNCTION(
472 BlueprintCallable,
473 Category = "Cesium",
474 Meta =
475 (DeprecatedFunction,
476 DeprecationMessage =
477 "The resolved georeference can no longer be explicitly invalidated. To change the georeference, call SetGeoreference or ReregisterComponent."))
478 void InvalidateResolvedGeoreference();
479#pragma endregion
480
481#pragma region Unreal Lifecycle
482protected:
483 /**
484 * Handles reading, writing, and reference collecting using FArchive.
485 * This implementation handles all FProperty serialization, but can be
486 * overridden for native variables.
487 *
488 * This class overrides this method to ensure internal variables are
489 * immediately synchronized with newly-loaded values.
490 */
491 virtual void Serialize(FArchive& Ar) override;
492
493 /**
494 * Called when a component is created (not loaded). This can happen in the
495 * editor or during gameplay.
496 *
497 * This method is invoked after this component is pasted and just prior to
498 * registration. We mark the globe transform invalid here because we can't
499 * assume the globe transform is still valid when the component is pasted into
500 * another Actor, or even if the Actor was changed since the Component was
501 * copied.
502 */
503 virtual void OnComponentCreated() override;
504
505#if WITH_EDITOR
506 virtual void
507 PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
508#endif
509
510 /**
511 * Called when a component is registered. This can be viewed as "enabling"
512 * this Component on the Actor to which it is attached.
513 *
514 * In the Editor, this is called in a many different situations, such as on
515 * changes to properties.
516 */
517 virtual void OnRegister() override;
518
519 /**
520 * Called when a component is unregistered. This can be viewed as
521 * "disabling" this Component on the Actor to which it is attached.
522 *
523 * In the Editor, this is called in a many different situations, such as on
524 * changes to properties.
525 */
526 virtual void OnUnregister() override;
527#pragma endregion
528
529#pragma region Implementation Details
530private:
531 CesiumGeospatial::GlobeAnchor _createNativeGlobeAnchor() const;
532
533 USceneComponent* _getRootComponent(bool warnIfNull) const;
534
535 FTransform _getCurrentRelativeTransform() const;
536
537 void _setCurrentRelativeTransform(const FTransform& relativeTransform);
538
540 _createOrUpdateNativeGlobeAnchorFromRelativeTransform(
541 const FTransform& newRelativeTransform);
542
544 _createOrUpdateNativeGlobeAnchorFromECEF(const FMatrix& newActorToECEFMatrix);
545
546 void _updateFromNativeGlobeAnchor(
547 const CesiumGeospatial::GlobeAnchor& nativeAnchor);
548
549 void _setNewActorToECEFFromRelativeTransform();
550
551#if WITH_EDITORONLY_DATA
552 // This is used only to preserve the transformation saved by old versions of
553 // Cesium for Unreal. See the Serialize method.
554 UPROPERTY(Meta = (DeprecatedProperty))
555 double _actorToECEF_Array_DEPRECATED[16];
556#endif
557
558 /**
559 * True if the globe transform is a valid and correct representation of the
560 * position and orientation of this Actor. False if the globe transform has
561 * not yet been computed and so the Actor transform is the only valid
562 * representation of the Actor's position and orientation.
563 */
564 UPROPERTY()
565 bool _actorToECEFIsValid = false;
566
567 /**
568 * Whether an update of the actor transform is currently in progress,
569 * and further calls that are received by _onActorTransformChanged
570 * should be ignored
571 */
572 bool _updatingActorTransform = false;
573
574 bool _lastRelativeTransformIsValid = false;
575 FTransform _lastRelativeTransform{};
576
577 /**
578 * Called when the root transform of the Actor to which this Component is
579 * attached has changed. So:
580 * * The globe (ECEF) position and orientation are computed from the new
581 * transform.
582 * * When `AdjustOrientationForGlobeWhenMoving` is enabled, the orientation
583 * will also be adjusted for globe curvature.
584 */
585 void _onActorTransformChanged(
586 USceneComponent* InRootComponent,
587 EUpdateTransformFlags UpdateTransformFlags,
588 ETeleportType Teleport);
589
590 /**
591 * Called when the Component switches to a new Georeference Actor or the
592 * existing Georeference is given a new origin Longitude, Latitude, or
593 * Height. The Actor's position and orientation are recomputed from the
594 * Component's globe (ECEF) position and orientation.
595 */
596 UFUNCTION(CallInEditor)
597 void _onGeoreferenceChanged();
598
599 friend class FCesiumGlobeAnchorCustomization;
600#pragma endregion
601};
Controls how global geospatial coordinates are mapped to coordinates in the Unreal Engine level.
UCesiumEllipsoid * GetEllipsoid() const
Returns a pointer to the UCesiumEllipsoid currently being used by this georeference.
This component can be added to a movable actor to anchor it to the globe and maintain precise placeme...
virtual void OnUnregister() override
Called when a component is unregistered.
virtual void OnComponentCreated() override
Called when a component is created (not loaded).
virtual void Serialize(FArchive &Ar) override
Handles reading, writing, and reference collecting using FArchive.
virtual void OnRegister() override
Called when a component is registered.