react-native-cesium 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -26
- package/android/CMakeLists.txt +1 -2
- package/android/src/main/cpp/CesiumBridgeAndroid.cpp +264 -130
- package/android/src/main/cpp/CesiumBridgeAndroid.h +70 -27
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/CesiumBridgeJNI.kt +68 -44
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/HybridCesiumView.kt +160 -187
- package/cpp/engine/CameraIntegrator.cpp +374 -0
- package/cpp/engine/CameraIntegrator.hpp +146 -0
- package/cpp/engine/CesiumEngine.cpp +3 -1
- package/cpp/engine/EngineTunables.hpp +80 -21
- package/cpp/engine/GlobeCamera.cpp +17 -6
- package/cpp/engine/GlobeCamera.hpp +11 -8
- package/cpp/engine/test/CameraIntegratorTest.cpp +205 -0
- package/cpp/engine/test/build_and_run.sh +27 -0
- package/example/README.md +1 -1
- package/ios/CesiumBridge.h +53 -28
- package/ios/CesiumBridge.mm +172 -86
- package/ios/HybridCesiumView.swift +213 -145
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts +77 -13
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.cpp +90 -9
- package/nitrogen/generated/android/c++/JHybridCesiumViewSpec.hpp +19 -3
- package/nitrogen/generated/android/c++/views/JHybridCesiumViewStateUpdater.cpp +20 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativecesium/HybridCesiumViewSpec.kt +57 -3
- package/nitrogen/generated/ios/ReactNativeCesium-Swift-Cxx-Bridge.hpp +9 -9
- package/nitrogen/generated/ios/c++/HybridCesiumViewSpecSwift.hpp +82 -9
- package/nitrogen/generated/ios/c++/views/HybridCesiumViewComponent.mm +25 -0
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec.swift +14 -3
- package/nitrogen/generated/ios/swift/HybridCesiumViewSpec_cxx.swift +210 -16
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.cpp +19 -3
- package/nitrogen/generated/shared/c++/HybridCesiumViewSpec.hpp +20 -4
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.cpp +55 -0
- package/nitrogen/generated/shared/c++/views/HybridCesiumViewComponent.hpp +5 -0
- package/nitrogen/generated/shared/json/CesiumViewConfig.json +5 -0
- package/package.json +2 -2
- package/src/specs/cesium-view.nitro.ts +93 -14
- package/cpp/engine/CameraSmoother.cpp +0 -71
- package/cpp/engine/CameraSmoother.hpp +0 -25
- package/cpp/engine/CameraTargetState.cpp +0 -140
- package/cpp/engine/CameraTargetState.hpp +0 -103
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "GlobeCamera.hpp"
|
|
4
|
-
|
|
5
|
-
namespace reactnativecesium {
|
|
6
|
-
|
|
7
|
-
// Stateless helper. Given a current camera state and a target camera state,
|
|
8
|
-
// returns the next camera state for a frame of duration `dt` seconds.
|
|
9
|
-
//
|
|
10
|
-
// Per-DoF smoothing rules:
|
|
11
|
-
// - lat / lon: snapped directly to target. The target itself is already a
|
|
12
|
-
// linearly-interpolated position produced by CameraTargetState::snapshot(),
|
|
13
|
-
// so snapping here gives constant-velocity motion between position fixes.
|
|
14
|
-
// - altitude / heading / pitch / roll / viewCorrection: exponential decay
|
|
15
|
-
// `1 - exp(-k * dt)` per DoF with k taken from EngineTunables.
|
|
16
|
-
// - When the delta drops below the matching epsilon, the value is snapped
|
|
17
|
-
// to the target so we eventually reach exact equality.
|
|
18
|
-
class CameraSmoother {
|
|
19
|
-
public:
|
|
20
|
-
static CameraParams step(const CameraParams& current,
|
|
21
|
-
const CameraParams& target,
|
|
22
|
-
double dt);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
} // namespace reactnativecesium
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
#include "CameraTargetState.hpp"
|
|
2
|
-
|
|
3
|
-
#include <algorithm>
|
|
4
|
-
#include <cmath>
|
|
5
|
-
|
|
6
|
-
namespace reactnativecesium {
|
|
7
|
-
|
|
8
|
-
namespace {
|
|
9
|
-
|
|
10
|
-
inline double angleDeltaAbsDeg(double a, double b) {
|
|
11
|
-
return std::abs(std::fmod(b - a + 540.0, 360.0) - 180.0);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
inline double quatDotAbs(const glm::dquat& a, const glm::dquat& b) {
|
|
15
|
-
return std::abs(glm::dot(glm::normalize(a), glm::normalize(b)));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Shortest signed angular delta for longitude, wrapped to [-180, 180].
|
|
19
|
-
inline double lonDeltaDeg(double from, double to) {
|
|
20
|
-
return std::fmod(to - from + 540.0, 360.0) - 180.0;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
} // namespace
|
|
24
|
-
|
|
25
|
-
// ── Public writers ────────────────────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
void CameraTargetState::setAll(const CameraParams& target) {
|
|
28
|
-
{
|
|
29
|
-
std::lock_guard<std::mutex> g(mutex_);
|
|
30
|
-
target_ = target;
|
|
31
|
-
// Deliberately do NOT touch interpolation state: setAll is engine-init only
|
|
32
|
-
// and the first frame must snap to the requested position immediately.
|
|
33
|
-
}
|
|
34
|
-
dirty_.store(true, std::memory_order_release);
|
|
35
|
-
forceRender_.store(true, std::memory_order_release);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
void CameraTargetState::setHpr(double lat, double lon, double alt,
|
|
39
|
-
double heading, double pitch, double roll) {
|
|
40
|
-
{
|
|
41
|
-
std::lock_guard<std::mutex> g(mutex_);
|
|
42
|
-
|
|
43
|
-
const bool posChanged =
|
|
44
|
-
std::abs(lat - target_.latitude) > tunables::kEpsLatLon ||
|
|
45
|
-
std::abs(lon - target_.longitude) > tunables::kEpsLatLon;
|
|
46
|
-
|
|
47
|
-
if (posChanged) {
|
|
48
|
-
const auto now = std::chrono::steady_clock::now();
|
|
49
|
-
|
|
50
|
-
if (!hasInterpolation_) {
|
|
51
|
-
// First runtime lat/lon update: seed posFrom = destination so that
|
|
52
|
-
// lerp(dest, dest, t) = dest for all t — clean snap, no startup glide.
|
|
53
|
-
posFromLat_ = lat;
|
|
54
|
-
posFromLon_ = lon;
|
|
55
|
-
ewmaIntervalSec_ = tunables::kSmoothPositionTauMax / tunables::kSmoothPositionAlpha;
|
|
56
|
-
posUpdateTime_ = now;
|
|
57
|
-
hasInterpolation_ = true;
|
|
58
|
-
} else {
|
|
59
|
-
// Subsequent update: record where we're moving FROM (the previous
|
|
60
|
-
// target), update the EWMA interval, and reset the clock.
|
|
61
|
-
posFromLat_ = target_.latitude;
|
|
62
|
-
posFromLon_ = target_.longitude;
|
|
63
|
-
|
|
64
|
-
const double dt = std::chrono::duration<double>(now - posUpdateTime_).count();
|
|
65
|
-
if (dt > 0.0) {
|
|
66
|
-
ewmaIntervalSec_ = ewmaIntervalSec_ +
|
|
67
|
-
tunables::kEwmaIntervalAlpha * (dt - ewmaIntervalSec_);
|
|
68
|
-
}
|
|
69
|
-
posUpdateTime_ = now;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
target_.latitude = lat;
|
|
74
|
-
target_.longitude = lon;
|
|
75
|
-
target_.altitude = alt;
|
|
76
|
-
target_.heading = heading;
|
|
77
|
-
target_.pitch = pitch;
|
|
78
|
-
target_.roll = roll;
|
|
79
|
-
}
|
|
80
|
-
dirty_.store(true, std::memory_order_release);
|
|
81
|
-
forceRender_.store(true, std::memory_order_release);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
void CameraTargetState::setViewCorrection(const glm::dquat& q) {
|
|
85
|
-
{
|
|
86
|
-
std::lock_guard<std::mutex> g(mutex_);
|
|
87
|
-
target_.viewCorrection = q;
|
|
88
|
-
// Position cadence intentionally NOT updated — viewCorrection changes
|
|
89
|
-
// carry no lat/lon information and must not affect the interpolation window.
|
|
90
|
-
}
|
|
91
|
-
dirty_.store(true, std::memory_order_release);
|
|
92
|
-
forceRender_.store(true, std::memory_order_release);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ── Snapshot (render-thread read) ─────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
CameraParams CameraTargetState::snapshot() const {
|
|
98
|
-
const auto now = std::chrono::steady_clock::now();
|
|
99
|
-
std::lock_guard<std::mutex> g(mutex_);
|
|
100
|
-
|
|
101
|
-
CameraParams result = target_;
|
|
102
|
-
|
|
103
|
-
if (hasInterpolation_ && ewmaIntervalSec_ > 0.0) {
|
|
104
|
-
const double dLat = target_.latitude - posFromLat_;
|
|
105
|
-
const double dLon = lonDeltaDeg(posFromLon_, target_.longitude);
|
|
106
|
-
|
|
107
|
-
// Snap-through guard: genuine teleports (setCamera(NewYork → Tokyo)) bypass
|
|
108
|
-
// the interpolation so they remain instant rather than gliding across the planet.
|
|
109
|
-
const bool snapThrough =
|
|
110
|
-
std::abs(dLat) > tunables::kPosSnapThroughDeg ||
|
|
111
|
-
std::abs(dLon) > tunables::kPosSnapThroughDeg;
|
|
112
|
-
|
|
113
|
-
if (!snapThrough) {
|
|
114
|
-
const double elapsed =
|
|
115
|
-
std::chrono::duration<double>(now - posUpdateTime_).count();
|
|
116
|
-
const double t = std::min(elapsed / ewmaIntervalSec_, 1.0);
|
|
117
|
-
|
|
118
|
-
result.latitude = posFromLat_ + t * dLat;
|
|
119
|
-
result.longitude = posFromLon_ + t * dLon;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return result;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// ── Epsilon check (shared) ────────────────────────────────────────────────────
|
|
127
|
-
|
|
128
|
-
bool CameraTargetState::deltaExceedsEpsilon(
|
|
129
|
-
const CameraParams& a, const CameraParams& b) {
|
|
130
|
-
return std::abs(a.latitude - b.latitude) > tunables::kEpsLatLon
|
|
131
|
-
|| std::abs(a.longitude - b.longitude) > tunables::kEpsLatLon
|
|
132
|
-
|| std::abs(a.altitude - b.altitude) > tunables::kEpsAltitudeMeters
|
|
133
|
-
|| angleDeltaAbsDeg(a.heading, b.heading) > tunables::kEpsAngleDeg
|
|
134
|
-
|| angleDeltaAbsDeg(a.pitch, b.pitch) > tunables::kEpsAngleDeg
|
|
135
|
-
|| angleDeltaAbsDeg(a.roll, b.roll) > tunables::kEpsAngleDeg
|
|
136
|
-
|| (1.0 - quatDotAbs(a.viewCorrection, b.viewCorrection))
|
|
137
|
-
> tunables::kEpsQuatDot;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
} // namespace reactnativecesium
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "EngineTunables.hpp"
|
|
4
|
-
#include "GlobeCamera.hpp"
|
|
5
|
-
|
|
6
|
-
#include <atomic>
|
|
7
|
-
#include <chrono>
|
|
8
|
-
#include <mutex>
|
|
9
|
-
|
|
10
|
-
namespace reactnativecesium {
|
|
11
|
-
|
|
12
|
-
// Thread-safe holder for the *demand* camera (what the JS side last asked for).
|
|
13
|
-
//
|
|
14
|
-
// Writers: the React Native JS / worklet thread, via setCamera / setCameraQuaternion.
|
|
15
|
-
// Readers: the dedicated render thread (per frame), via shouldRenderNextFrame /
|
|
16
|
-
// renderFrame.
|
|
17
|
-
//
|
|
18
|
-
// We use a small mutex around `target_` because the writes are uncontended and
|
|
19
|
-
// the read side only happens once per frame; the cost is negligible compared to
|
|
20
|
-
// the cost of *not* synchronising a 56-byte struct that contains a glm::dquat.
|
|
21
|
-
//
|
|
22
|
-
// `dirty_` and `forceRender_` are independent atomic flags so the read side can
|
|
23
|
-
// poll without taking the lock when the camera has not moved.
|
|
24
|
-
//
|
|
25
|
-
// Lat/lon interpolation
|
|
26
|
-
// ─────────────────────
|
|
27
|
-
// When setHpr is called with a new lat/lon, `posFrom` (old target) and
|
|
28
|
-
// `posUpdateTime` are recorded inside the mutex. snapshot() then linearly
|
|
29
|
-
// interpolates posFrom → target over `ewmaIntervalSec` (EWMA of inter-arrival
|
|
30
|
-
// times). This produces constant-velocity motion between position fixes —
|
|
31
|
-
// realistic for any vehicle/GPS source — without any changes to the public API.
|
|
32
|
-
//
|
|
33
|
-
// Special cases handled in snapshot():
|
|
34
|
-
// - t >= 1 : camera has reached the target, returns target_ directly.
|
|
35
|
-
// - Snap-through guard: deltas > kPosSnapThroughDeg bypass interpolation so
|
|
36
|
-
// deliberate teleports (setCamera(NewYork → Tokyo)) remain instant.
|
|
37
|
-
// - First setHpr for a given lat/lon: posFrom is set to the *destination*
|
|
38
|
-
// so lerp(dest, dest, t) = dest — no startup glide.
|
|
39
|
-
// - setAll (initialisation only): does not touch interpolation state; always
|
|
40
|
-
// snaps directly.
|
|
41
|
-
class CameraTargetState {
|
|
42
|
-
public:
|
|
43
|
-
CameraTargetState() = default;
|
|
44
|
-
|
|
45
|
-
// Replace the entire target. Used only for engine initialisation; does NOT
|
|
46
|
-
// update position-interpolation state so the first rendered frame snaps.
|
|
47
|
-
void setAll(const CameraParams& target);
|
|
48
|
-
|
|
49
|
-
// Update lat/lon/alt + heading/pitch/roll, leaving viewCorrection unchanged.
|
|
50
|
-
// When lat/lon actually changes, updates the linear-interpolation bookkeeping.
|
|
51
|
-
void setHpr(double lat, double lon, double alt,
|
|
52
|
-
double heading, double pitch, double roll);
|
|
53
|
-
|
|
54
|
-
void setViewCorrection(const glm::dquat& q);
|
|
55
|
-
|
|
56
|
-
// Snapshot the demand target for this render frame. Lat/lon are linearly
|
|
57
|
-
// interpolated between the previous target (posFrom) and the current target
|
|
58
|
-
// over the EWMA inter-arrival interval. All other DoFs are returned as-is
|
|
59
|
-
// (the smoother handles their exponential curves).
|
|
60
|
-
CameraParams snapshot() const;
|
|
61
|
-
|
|
62
|
-
// Lightweight, lock-free check used by the render thread to decide whether
|
|
63
|
-
// it should bother taking a full snapshot at all.
|
|
64
|
-
bool isDirty() const noexcept {
|
|
65
|
-
return dirty_.load(std::memory_order_acquire);
|
|
66
|
-
}
|
|
67
|
-
void clearDirty() noexcept {
|
|
68
|
-
dirty_.store(false, std::memory_order_release);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
bool consumeForceRender() noexcept {
|
|
72
|
-
return forceRender_.exchange(false, std::memory_order_acq_rel);
|
|
73
|
-
}
|
|
74
|
-
void requestForceRender() noexcept {
|
|
75
|
-
forceRender_.store(true, std::memory_order_release);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Compares snapshot to "current" (the engine's current camera) and returns
|
|
79
|
-
// true if any DoF differs by more than the matching epsilon. Used to decide
|
|
80
|
-
// whether to render this frame.
|
|
81
|
-
static bool deltaExceedsEpsilon(const CameraParams& a, const CameraParams& b);
|
|
82
|
-
|
|
83
|
-
private:
|
|
84
|
-
mutable std::mutex mutex_;
|
|
85
|
-
CameraParams target_;
|
|
86
|
-
std::atomic<bool> dirty_{false};
|
|
87
|
-
std::atomic<bool> forceRender_{true};
|
|
88
|
-
|
|
89
|
-
// ── Lat/lon linear interpolation state (all protected by mutex_) ──────────
|
|
90
|
-
// posFromLat_/posFromLon_: the target position when the last update arrived
|
|
91
|
-
// (i.e. where we are smoothly moving FROM).
|
|
92
|
-
// posUpdateTime_: wall-clock time of the last lat/lon change.
|
|
93
|
-
// ewmaIntervalSec_: EWMA of inter-arrival times of lat/lon changes.
|
|
94
|
-
// hasInterpolation_: true once we have valid posFrom + posUpdateTime
|
|
95
|
-
// data (false until the second distinct lat/lon value).
|
|
96
|
-
double posFromLat_{0.0};
|
|
97
|
-
double posFromLon_{0.0};
|
|
98
|
-
std::chrono::steady_clock::time_point posUpdateTime_{};
|
|
99
|
-
double ewmaIntervalSec_{0.0};
|
|
100
|
-
bool hasInterpolation_{false};
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
} // namespace reactnativecesium
|