Skip to content

Commit 8b1b6d6

Browse files
feat: simplify geospatial api to avoid confusions
1 parent e9cbcc9 commit 8b1b6d6

7 files changed

Lines changed: 406 additions & 36 deletions

File tree

ViroRenderer/VROARSession.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,25 @@ class VROARSession {
446446
}
447447
}
448448

449+
virtual void resolveGeospatialAnchor(const std::string& platformUuid, VROQuaternion quaternion,
450+
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,
451+
std::function<void(std::string error)> onFailure) {
452+
if (onFailure) {
453+
onFailure("Resolve geospatial anchor not supported");
454+
}
455+
}
456+
457+
// Host a geospatial anchor to the ReactVision backend at the given GPS position.
458+
// Returns the platform UUID via onSuccess(platformUuid) string callback.
459+
virtual void hostGeospatialAnchor(double latitude, double longitude, double altitude,
460+
const std::string& altitudeMode,
461+
std::function<void(std::string platformUuid)> onSuccess,
462+
std::function<void(std::string error)> onFailure) {
463+
if (onFailure) {
464+
onFailure("Host geospatial anchor not supported");
465+
}
466+
}
467+
449468
/*
450469
Create a terrain anchor at the specified location.
451470
Terrain anchors are positioned relative to the terrain surface.

android/sharedCode/src/main/cpp/arcore/ARSceneController_JNI.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,84 @@ VRO_METHOD(void, nativeCreateGeospatialAnchor)(VRO_ARGS
259259
}
260260
}
261261

262+
VRO_METHOD(void, nativeHostGeospatialAnchor)(VRO_ARGS
263+
VRO_REF(VROARSceneController) arSceneControllerPtr,
264+
jstring key,
265+
jdouble latitude, jdouble longitude, jdouble altitude,
266+
jstring altitudeMode) {
267+
std::shared_ptr<VROARScene> arScene = std::dynamic_pointer_cast<VROARScene>(VRO_REF_GET(VROARSceneController, arSceneControllerPtr)->getScene());
268+
std::shared_ptr<VROARSession> arSession = arScene->getARSession();
269+
if (arSession) {
270+
std::string keyStr = VRO_STRING_STL(key);
271+
std::string modeStr = VRO_STRING_STL(altitudeMode);
272+
VRO_WEAK weakObj = VRO_NEW_WEAK_GLOBAL_REF(obj);
273+
arSession->hostGeospatialAnchor(latitude, longitude, altitude, modeStr,
274+
[weakObj, keyStr](std::string platformUuid) {
275+
VRO_ENV env = VROPlatformGetJNIEnv();
276+
VRO_OBJECT localObj = VRO_NEW_LOCAL_REF(weakObj);
277+
if (VRO_IS_OBJECT_NULL(localObj)) { VRO_DELETE_WEAK_GLOBAL_REF(weakObj); return; }
278+
VRO_STRING jKey = VRO_NEW_STRING(keyStr.c_str());
279+
VRO_STRING jUuid = VRO_NEW_STRING(platformUuid.c_str());
280+
VROPlatformCallHostFunction(localObj, "onHostGeospatialAnchorSuccess", "(Ljava/lang/String;Ljava/lang/String;)V", jKey, jUuid);
281+
VRO_DELETE_LOCAL_REF(localObj);
282+
VRO_DELETE_WEAK_GLOBAL_REF(weakObj);
283+
},
284+
[weakObj, keyStr](std::string error) {
285+
VRO_ENV env = VROPlatformGetJNIEnv();
286+
VRO_OBJECT localObj = VRO_NEW_LOCAL_REF(weakObj);
287+
if (VRO_IS_OBJECT_NULL(localObj)) { VRO_DELETE_WEAK_GLOBAL_REF(weakObj); return; }
288+
VRO_STRING jKey = VRO_NEW_STRING(keyStr.c_str());
289+
VRO_STRING jError = VRO_NEW_STRING(error.c_str());
290+
VROPlatformCallHostFunction(localObj, "onHostGeospatialAnchorFailure", "(Ljava/lang/String;Ljava/lang/String;)V", jKey, jError);
291+
VRO_DELETE_LOCAL_REF(localObj);
292+
VRO_DELETE_WEAK_GLOBAL_REF(weakObj);
293+
});
294+
}
295+
}
296+
297+
VRO_METHOD(void, nativeResolveGeospatialAnchor)(VRO_ARGS
298+
VRO_REF(VROARSceneController) arSceneControllerPtr,
299+
jstring key,
300+
jstring platformUuid,
301+
jfloat qx, jfloat qy, jfloat qz, jfloat qw) {
302+
std::shared_ptr<VROARScene> arScene = std::dynamic_pointer_cast<VROARScene>(VRO_REF_GET(VROARSceneController, arSceneControllerPtr)->getScene());
303+
std::shared_ptr<VROARSession> arSession = arScene->getARSession();
304+
305+
if (arSession) {
306+
std::string keyStr = VRO_STRING_STL(key);
307+
std::string uuidStr = VRO_STRING_STL(platformUuid);
308+
VROQuaternion quat(qx, qy, qz, qw);
309+
VRO_WEAK weakObj = VRO_NEW_WEAK_GLOBAL_REF(obj);
310+
311+
arSession->resolveGeospatialAnchor(uuidStr, quat,
312+
[weakObj, keyStr](std::shared_ptr<VROGeospatialAnchor> anchor) {
313+
VRO_ENV env = VROPlatformGetJNIEnv();
314+
VRO_OBJECT localObj = VRO_NEW_LOCAL_REF(weakObj);
315+
if (VRO_IS_OBJECT_NULL(localObj)) { VRO_DELETE_WEAK_GLOBAL_REF(weakObj); return; }
316+
VRO_STRING jKey = VRO_NEW_STRING(keyStr.c_str());
317+
VRO_STRING jAnchorId = VRO_NEW_STRING(anchor->getId().c_str());
318+
VROVector3f pos = anchor->getTransform().extractTranslation();
319+
VROPlatformCallHostFunction(localObj, "onGeospatialAnchorSuccess", "(Ljava/lang/String;Ljava/lang/String;IDDDDFFF)V",
320+
jKey, jAnchorId, (int)anchor->getGeospatialType(),
321+
anchor->getLatitude(), anchor->getLongitude(), anchor->getAltitude(), anchor->getHeading(),
322+
pos.x, pos.y, pos.z);
323+
VRO_DELETE_LOCAL_REF(localObj);
324+
VRO_DELETE_WEAK_GLOBAL_REF(weakObj);
325+
},
326+
[weakObj, keyStr](std::string error) {
327+
VRO_ENV env = VROPlatformGetJNIEnv();
328+
VRO_OBJECT localObj = VRO_NEW_LOCAL_REF(weakObj);
329+
if (VRO_IS_OBJECT_NULL(localObj)) { VRO_DELETE_WEAK_GLOBAL_REF(weakObj); return; }
330+
VRO_STRING jKey = VRO_NEW_STRING(keyStr.c_str());
331+
VRO_STRING jError = VRO_NEW_STRING(error.c_str());
332+
VROPlatformCallHostFunction(localObj, "onGeospatialAnchorFailure", "(Ljava/lang/String;Ljava/lang/String;)V",
333+
jKey, jError);
334+
VRO_DELETE_LOCAL_REF(localObj);
335+
VRO_DELETE_WEAK_GLOBAL_REF(weakObj);
336+
});
337+
}
338+
}
339+
262340
VRO_METHOD(void, nativeCreateTerrainAnchor)(VRO_ARGS
263341
VRO_REF(VROARSceneController) arSceneControllerPtr,
264342
jstring key,

android/sharedCode/src/main/cpp/arcore/VROARSessionARCore.cpp

Lines changed: 115 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,33 @@
5454
#include <VROImageAndroid.h>
5555
#include <algorithm>
5656
#include <cmath>
57+
#include <cstdio>
58+
#include <fcntl.h>
59+
#include <unistd.h>
5760

5861
static bool kDebugTracking = false;
5962

63+
// Generate a random UUID v4 string (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx).
64+
static std::string generateUUID() {
65+
uint8_t b[16];
66+
int fd = open("/dev/urandom", O_RDONLY);
67+
if (fd >= 0) {
68+
read(fd, b, sizeof(b));
69+
close(fd);
70+
} else {
71+
// Fallback: zero-filled (shouldn't happen on Android).
72+
memset(b, 0, sizeof(b));
73+
}
74+
b[6] = (b[6] & 0x0f) | 0x40; // version 4
75+
b[8] = (b[8] & 0x3f) | 0x80; // variant bits
76+
char buf[37];
77+
snprintf(buf, sizeof(buf),
78+
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
79+
b[0],b[1],b[2],b[3], b[4],b[5], b[6],b[7],
80+
b[8],b[9], b[10],b[11],b[12],b[13],b[14],b[15]);
81+
return std::string(buf);
82+
}
83+
6084
// Minimum plane size filter to prevent small artifacts from being detected
6185
// Planes smaller than this threshold will be ignored
6286
static const float kMinPlaneExtent = 0.10f; // 10cm minimum size in any dimension
@@ -1410,8 +1434,7 @@ void VROARSessionARCore::setGeospatialAnchorProvider(VROGeospatialAnchorProvider
14101434

14111435
if (provider == VROGeospatialAnchorProvider::ReactVision) {
14121436
// ReactVision has no ARCore dependency — no VPS, no ARCore session config.
1413-
// GPS→AR placement (createGeospatialAnchor) is not supported for this provider.
1414-
// Use rvCreateGeospatialAnchor / rvFindNearbyGeospatialAnchors for RVCA metadata.
1437+
// GPS→AR placement uses createLocalGPSAnchor; backend persistence via createAnchor.
14151438
// _geospatialProviderRV is initialized in setReactVisionConfig().
14161439
if (!_geospatialProviderRV) {
14171440
pwarn("VROARSessionARCore: ReactVision geospatial not ready — "
@@ -1552,7 +1575,8 @@ static std::shared_ptr<VROGeospatialAnchor> createLocalGPSAnchor(
15521575
VROGeospatialAnchorType type, VROQuaternion quaternion,
15531576
std::shared_ptr<VROARSessionARCore> arSession,
15541577
ReactVisionCCA::RVCCAGeospatialProvider *provider,
1555-
std::string &outError) {
1578+
std::string &outError,
1579+
const std::string &knownId = "") {
15561580
if (devicePose.latitude == 0.0 && devicePose.longitude == 0.0) {
15571581
outError = "GPS position not available yet. Ensure location permissions are granted.";
15581582
return nullptr;
@@ -1573,12 +1597,19 @@ static std::shared_ptr<VROGeospatialAnchor> createLocalGPSAnchor(
15731597
}
15741598
std::shared_ptr<arcore::Anchor> anchorShared(nativeAnchor);
15751599
std::string key = VROStringUtil::toString64(anchorShared->getId());
1600+
std::string uuid = knownId.empty() ? generateUUID() : knownId;
15761601

15771602
auto geoAnchor = std::make_shared<VROGeospatialAnchor>(type, anchorLat, anchorLng, anchorAlt, quaternion);
1578-
geoAnchor->setId(key);
1603+
geoAnchor->setId(uuid);
15791604
geoAnchor->setResolveState(VROGeospatialAnchorResolveState::Success);
15801605

1581-
auto vAnchor = std::make_shared<VROARAnchorARCore>(key, anchorShared, geoAnchor, arSession);
1606+
// Set the AR-space transform immediately so the onSuccess callback gets the correct position.
1607+
// (processUpdatedAnchors will keep it in sync each frame via updateFromGeospatialTransform.)
1608+
float mtx[16];
1609+
nativeAnchor->getTransform(mtx);
1610+
geoAnchor->setTransform(VROMatrix4f(mtx));
1611+
1612+
auto vAnchor = std::make_shared<VROARAnchorARCore>(uuid, anchorShared, geoAnchor, arSession);
15821613
arSession->addAnchor(vAnchor);
15831614
return geoAnchor;
15841615
}
@@ -1593,7 +1624,8 @@ void VROARSessionARCore::createGeospatialAnchor(double latitude, double longitud
15931624
auto anchor = createLocalGPSAnchor(_session, _lastKnownGPSPose,
15941625
latitude, longitude, altitude,
15951626
VROGeospatialAnchorType::WGS84, quaternion,
1596-
shared_from_this(), _geospatialProviderRV.get(), error);
1627+
shared_from_this(), _geospatialProviderRV.get(),
1628+
error);
15971629
if (anchor) { if (onSuccess) onSuccess(anchor); }
15981630
else { if (onFailure) onFailure(error); }
15991631
return;
@@ -1633,6 +1665,74 @@ void VROARSessionARCore::createGeospatialAnchor(double latitude, double longitud
16331665
}
16341666
}
16351667

1668+
void VROARSessionARCore::resolveGeospatialAnchor(const std::string& platformUuid,
1669+
VROQuaternion quaternion,
1670+
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,
1671+
std::function<void(std::string error)> onFailure) {
1672+
#if RVCCA_AVAILABLE
1673+
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1674+
if (!_geospatialProviderRV) {
1675+
if (onFailure) onFailure("ReactVision geospatial provider not initialized");
1676+
return;
1677+
}
1678+
if (_lastKnownGPSPose.latitude == 0.0 && _lastKnownGPSPose.longitude == 0.0) {
1679+
if (onFailure) onFailure("GPS position not available yet. Ensure location permissions are granted.");
1680+
return;
1681+
}
1682+
VROGeospatialPose devicePose = _lastKnownGPSPose;
1683+
std::weak_ptr<VROARSessionARCore> weakSelf = shared_from_this();
1684+
_geospatialProviderRV->getAnchor(platformUuid,
1685+
[weakSelf, devicePose, platformUuid, quaternion, onSuccess, onFailure]
1686+
(ReactVisionCCA::ApiResult<ReactVisionCCA::GeospatialAnchorRecord> r) {
1687+
VROPlatformDispatchAsyncRenderer([weakSelf, r, devicePose, platformUuid, quaternion, onSuccess, onFailure] {
1688+
auto self = weakSelf.lock();
1689+
if (!self) return;
1690+
if (!r.success) {
1691+
if (onFailure) onFailure(r.error.message);
1692+
return;
1693+
}
1694+
std::string error;
1695+
auto anchor = createLocalGPSAnchor(self->_session, devicePose,
1696+
r.data.lat, r.data.lng, r.data.alt,
1697+
VROGeospatialAnchorType::WGS84, quaternion,
1698+
self, self->_geospatialProviderRV.get(),
1699+
error, platformUuid);
1700+
if (anchor) { if (onSuccess) onSuccess(anchor); }
1701+
else { if (onFailure) onFailure(error); }
1702+
});
1703+
});
1704+
return;
1705+
}
1706+
#endif
1707+
if (onFailure) onFailure("resolveGeospatialAnchor requires ReactVision geospatial provider");
1708+
}
1709+
1710+
void VROARSessionARCore::hostGeospatialAnchor(double latitude, double longitude, double altitude,
1711+
const std::string& altitudeMode,
1712+
std::function<void(std::string)> onSuccess,
1713+
std::function<void(std::string)> onFailure) {
1714+
#if RVCCA_AVAILABLE
1715+
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1716+
if (!_geospatialProviderRV) {
1717+
if (onFailure) onFailure("ReactVision geospatial provider not initialized");
1718+
return;
1719+
}
1720+
ReactVisionCCA::GeospatialCreateRequest req;
1721+
req.lat = latitude;
1722+
req.lng = longitude;
1723+
req.alt = altitude;
1724+
req.altitudeMode = altitudeMode.empty() ? "street_level" : altitudeMode;
1725+
_geospatialProviderRV->createAnchor(req,
1726+
[onSuccess, onFailure](ReactVisionCCA::ApiResult<ReactVisionCCA::GeospatialAnchorRecord> r) {
1727+
if (r.success) { if (onSuccess) onSuccess(r.data.id); }
1728+
else { if (onFailure) onFailure(r.error.message); }
1729+
});
1730+
return;
1731+
}
1732+
#endif
1733+
if (onFailure) onFailure("hostGeospatialAnchor requires ReactVision geospatial provider");
1734+
}
1735+
16361736
void VROARSessionARCore::createTerrainAnchor(double latitude, double longitude, double altitudeAboveTerrain,
16371737
VROQuaternion quaternion,
16381738
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,
@@ -1719,7 +1819,7 @@ void VROARSessionARCore::createRooftopAnchor(double latitude, double longitude,
17191819
}
17201820

17211821
std::weak_ptr<VROARSessionARCore> weakSession = shared_from_this();
1722-
1822+
17231823
_session->createRooftopAnchor(latitude, longitude, altitudeAboveRooftop, quaternion.X, quaternion.Y, quaternion.Z, quaternion.W,
17241824
[weakSession, latitude, longitude, altitudeAboveRooftop, quaternion, onSuccess](arcore::Anchor *nativeAnchor) {
17251825
VROPlatformDispatchAsyncRenderer([weakSession, latitude, longitude, altitudeAboveRooftop, quaternion, onSuccess, nativeAnchor] {
@@ -1760,17 +1860,17 @@ void VROARSessionARCore::createRooftopAnchor(double latitude, double longitude,
17601860
void VROARSessionARCore::removeGeospatialAnchor(std::shared_ptr<VROGeospatialAnchor> anchor) {
17611861
if (!anchor) return;
17621862

1763-
#if RVCCA_AVAILABLE
1764-
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision
1765-
&& _geospatialProviderRV) {
1766-
_geospatialProviderRV->deleteAnchor(anchor->getId(),
1767-
[](bool, ReactVisionCCA::ApiError) { /* fire-and-forget */ });
1768-
}
1769-
#endif
1863+
// Note: do NOT call _geospatialProviderRV->deleteAnchor() here.
1864+
// removeGeospatialAnchor only removes the anchor from the local AR session.
1865+
// Use rvDeleteGeospatialAnchor() to explicitly delete from the backend.
17701866

1867+
// Search by ID because the caller may pass a dummy anchor (from nativeRemoveGeospatialAnchor)
1868+
// that shares only the ID with the stored trackable, not the same pointer.
17711869
std::shared_ptr<VROARAnchorARCore> foundAnchor = nullptr;
1870+
const std::string &targetId = anchor->getId();
17721871
for (std::shared_ptr<VROARAnchorARCore> vAnchor : _anchors) {
1773-
if (vAnchor->getTrackable() == anchor) {
1872+
auto trackable = vAnchor->getTrackable();
1873+
if (trackable && trackable->getId() == targetId) {
17741874
foundAnchor = vAnchor;
17751875
break;
17761876
}

android/sharedCode/src/main/cpp/arcore/VROARSessionARCore.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ class VROARSessionARCore : public VROARSession,
170170
VROQuaternion quaternion,
171171
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,
172172
std::function<void(std::string error)> onFailure) override;
173+
void resolveGeospatialAnchor(const std::string& platformUuid, VROQuaternion quaternion,
174+
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,
175+
std::function<void(std::string error)> onFailure) override;
176+
void hostGeospatialAnchor(double latitude, double longitude, double altitude,
177+
const std::string& altitudeMode,
178+
std::function<void(std::string platformUuid)> onSuccess,
179+
std::function<void(std::string error)> onFailure) override;
173180
void createTerrainAnchor(double latitude, double longitude, double altitudeAboveTerrain,
174181
VROQuaternion quaternion,
175182
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,

0 commit comments

Comments
 (0)