Skip to content

Commit e9cbcc9

Browse files
feat: add GPS->AR for RVCA Geospatial
1 parent b8f5484 commit e9cbcc9

6 files changed

Lines changed: 124 additions & 18 deletions

File tree

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

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,17 +1541,61 @@ void VROARSessionARCore::checkVPSAvailability(double latitude, double longitude,
15411541
});
15421542
}
15431543

1544+
// Create a local ARCore anchor at the GPS-computed world position using
1545+
// acquireNewAnchor. No VPS required — placed by GPS + compass + VIO.
1546+
// AR placement math is delegated to RVCCAGeospatialProvider::computeArPosition()
1547+
// (proprietary algorithm inside libreactvisioncca — not exposed in open-source virocore).
1548+
static std::shared_ptr<VROGeospatialAnchor> createLocalGPSAnchor(
1549+
arcore::Session *session,
1550+
const VROGeospatialPose &devicePose,
1551+
double anchorLat, double anchorLng, double anchorAlt,
1552+
VROGeospatialAnchorType type, VROQuaternion quaternion,
1553+
std::shared_ptr<VROARSessionARCore> arSession,
1554+
ReactVisionCCA::RVCCAGeospatialProvider *provider,
1555+
std::string &outError) {
1556+
if (devicePose.latitude == 0.0 && devicePose.longitude == 0.0) {
1557+
outError = "GPS position not available yet. Ensure location permissions are granted.";
1558+
return nullptr;
1559+
}
1560+
auto pos = provider->computeArPosition(
1561+
devicePose.latitude, devicePose.longitude, devicePose.altitude, devicePose.heading,
1562+
anchorLat, anchorLng, anchorAlt);
1563+
float arX = pos[0], arY = pos[1], arZ = pos[2];
1564+
1565+
arcore::Pose *pose = session->createPose(arX, arY, arZ,
1566+
quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
1567+
arcore::Anchor *nativeAnchor = session->acquireNewAnchor(pose);
1568+
delete pose;
1569+
1570+
if (!nativeAnchor) {
1571+
outError = "Failed to create local anchor at GPS position.";
1572+
return nullptr;
1573+
}
1574+
std::shared_ptr<arcore::Anchor> anchorShared(nativeAnchor);
1575+
std::string key = VROStringUtil::toString64(anchorShared->getId());
1576+
1577+
auto geoAnchor = std::make_shared<VROGeospatialAnchor>(type, anchorLat, anchorLng, anchorAlt, quaternion);
1578+
geoAnchor->setId(key);
1579+
geoAnchor->setResolveState(VROGeospatialAnchorResolveState::Success);
1580+
1581+
auto vAnchor = std::make_shared<VROARAnchorARCore>(key, anchorShared, geoAnchor, arSession);
1582+
arSession->addAnchor(vAnchor);
1583+
return geoAnchor;
1584+
}
1585+
15441586
void VROARSessionARCore::createGeospatialAnchor(double latitude, double longitude, double altitude,
15451587
VROQuaternion quaternion,
15461588
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,
15471589
std::function<void(std::string error)> onFailure) {
15481590
#if RVCCA_AVAILABLE
15491591
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1550-
// ReactVision has no VPS — cannot map GPS coordinates to AR world space.
1551-
// Use rvCreateGeospatialAnchor to store GPS metadata, and resolveCloudAnchor
1552-
// to place anchors in AR via visual feature matching.
1553-
if (onFailure) onFailure("createGeospatialAnchor requires ARCore VPS (provider='arcore'). "
1554-
"ReactVision provider does not support GPS→AR placement.");
1592+
std::string error;
1593+
auto anchor = createLocalGPSAnchor(_session, _lastKnownGPSPose,
1594+
latitude, longitude, altitude,
1595+
VROGeospatialAnchorType::WGS84, quaternion,
1596+
shared_from_this(), _geospatialProviderRV.get(), error);
1597+
if (anchor) { if (onSuccess) onSuccess(anchor); }
1598+
else { if (onFailure) onFailure(error); }
15551599
return;
15561600
}
15571601
#endif
@@ -1595,8 +1639,15 @@ void VROARSessionARCore::createTerrainAnchor(double latitude, double longitude,
15951639
std::function<void(std::string error)> onFailure) {
15961640
#if RVCCA_AVAILABLE
15971641
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1598-
if (onFailure) onFailure("createTerrainAnchor requires ARCore VPS (provider='arcore'). "
1599-
"ReactVision provider does not support GPS→AR placement.");
1642+
// Terrain alt = device altitude + offset above terrain (approximation)
1643+
double absoluteAlt = _lastKnownGPSPose.altitude + altitudeAboveTerrain;
1644+
std::string error;
1645+
auto anchor = createLocalGPSAnchor(_session, _lastKnownGPSPose,
1646+
latitude, longitude, absoluteAlt,
1647+
VROGeospatialAnchorType::Terrain, quaternion,
1648+
shared_from_this(), _geospatialProviderRV.get(), error);
1649+
if (anchor) { if (onSuccess) onSuccess(anchor); }
1650+
else { if (onFailure) onFailure(error); }
16001651
return;
16011652
}
16021653
#endif
@@ -1650,8 +1701,15 @@ void VROARSessionARCore::createRooftopAnchor(double latitude, double longitude,
16501701
std::function<void(std::string error)> onFailure) {
16511702
#if RVCCA_AVAILABLE
16521703
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1653-
if (onFailure) onFailure("createRooftopAnchor requires ARCore VPS (provider='arcore'). "
1654-
"ReactVision provider does not support GPS→AR placement.");
1704+
// Rooftop alt = device altitude + offset above rooftop (approximation)
1705+
double absoluteAlt = _lastKnownGPSPose.altitude + altitudeAboveRooftop;
1706+
std::string error;
1707+
auto anchor = createLocalGPSAnchor(_session, _lastKnownGPSPose,
1708+
latitude, longitude, absoluteAlt,
1709+
VROGeospatialAnchorType::Rooftop, quaternion,
1710+
shared_from_this(), _geospatialProviderRV.get(), error);
1711+
if (anchor) { if (onSuccess) onSuccess(anchor); }
1712+
else { if (onFailure) onFailure(error); }
16551713
return;
16561714
}
16571715
#endif
784 Bytes
Binary file not shown.
Binary file not shown.
936 Bytes
Binary file not shown.
1.61 KB
Binary file not shown.

ios/ViroKit/VROARSessioniOS.cpp

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,17 +1674,51 @@ void VROARSessioniOS::checkVPSAvailability(double latitude, double longitude,
16741674
}
16751675
}
16761676

1677+
// Create a native ARKit local anchor at the GPS-computed world position.
1678+
// AR placement math is delegated to RVCCAGeospatialProvider::computeArPosition()
1679+
// (proprietary algorithm inside libreactvisioncca — not exposed in open-source virocore).
1680+
static std::shared_ptr<VROGeospatialAnchor> createLocalGPSAnchor(
1681+
ARSession *session,
1682+
const VROGeospatialPose &devicePose,
1683+
double anchorLat, double anchorLng, double anchorAlt,
1684+
VROGeospatialAnchorType type, VROQuaternion quaternion,
1685+
ReactVisionCCA::RVCCAGeospatialProvider *provider,
1686+
std::string &outError) {
1687+
if (devicePose.latitude == 0.0 && devicePose.longitude == 0.0) {
1688+
outError = "GPS position not available yet. Ensure location permissions are granted.";
1689+
return nullptr;
1690+
}
1691+
auto pos = provider->computeArPosition(
1692+
devicePose.latitude, devicePose.longitude, devicePose.altitude, devicePose.heading,
1693+
anchorLat, anchorLng, anchorAlt);
1694+
float arX = pos[0], arY = pos[1], arZ = pos[2];
1695+
1696+
simd_quatf q = simd_quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
1697+
simd_float4x4 transform = simd_matrix4x4(q);
1698+
transform.columns[3] = simd_make_float4(arX, arY, arZ, 1.0f);
1699+
1700+
ARAnchor *arAnchor = [[ARAnchor alloc] initWithTransform:transform];
1701+
[session addAnchor:arAnchor];
1702+
1703+
auto geo = std::make_shared<VROGeospatialAnchor>(type, anchorLat, anchorLng, anchorAlt, quaternion);
1704+
geo->setId(std::string([arAnchor.identifier.UUIDString UTF8String]));
1705+
geo->setResolveState(VROGeospatialAnchorResolveState::Success);
1706+
return geo;
1707+
}
1708+
16771709
void VROARSessioniOS::createGeospatialAnchor(double latitude, double longitude, double altitude,
16781710
VROQuaternion quaternion,
16791711
std::function<void(std::shared_ptr<VROGeospatialAnchor>)> onSuccess,
16801712
std::function<void(std::string error)> onFailure) {
16811713
#if RVCCA_AVAILABLE
16821714
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1683-
// ReactVision has no VPS — cannot map GPS coordinates to AR world space.
1684-
// Use rvCreateGeospatialAnchor to store GPS metadata, and resolveCloudAnchor
1685-
// to place anchors in AR via visual feature matching.
1686-
if (onFailure) onFailure("createGeospatialAnchor requires ARCore VPS (provider='arcore'). "
1687-
"ReactVision provider does not support GPS→AR placement.");
1715+
std::string error;
1716+
auto anchor = createLocalGPSAnchor(_session, _lastKnownGPSPose,
1717+
latitude, longitude, altitude,
1718+
VROGeospatialAnchorType::WGS84, quaternion,
1719+
_geospatialProviderRV.get(), error);
1720+
if (anchor) { if (onSuccess) onSuccess(anchor); }
1721+
else { if (onFailure) onFailure(error); }
16881722
return;
16891723
}
16901724
#endif
@@ -1718,8 +1752,15 @@ void VROARSessioniOS::createTerrainAnchor(double latitude, double longitude, dou
17181752
std::function<void(std::string error)> onFailure) {
17191753
#if RVCCA_AVAILABLE
17201754
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1721-
if (onFailure) onFailure("createTerrainAnchor requires ARCore VPS (provider='arcore'). "
1722-
"ReactVision provider does not support GPS→AR placement.");
1755+
// altitudeAboveTerrain: approximate absolute alt = device altitude + offset
1756+
double absoluteAlt = _lastKnownGPSPose.altitude + altitudeAboveTerrain;
1757+
std::string error;
1758+
auto anchor = createLocalGPSAnchor(_session, _lastKnownGPSPose,
1759+
latitude, longitude, absoluteAlt,
1760+
VROGeospatialAnchorType::Terrain, quaternion,
1761+
_geospatialProviderRV.get(), error);
1762+
if (anchor) { if (onSuccess) onSuccess(anchor); }
1763+
else { if (onFailure) onFailure(error); }
17231764
return;
17241765
}
17251766
#endif
@@ -1752,8 +1793,15 @@ void VROARSessioniOS::createRooftopAnchor(double latitude, double longitude, dou
17521793
std::function<void(std::string error)> onFailure) {
17531794
#if RVCCA_AVAILABLE
17541795
if (getGeospatialAnchorProvider() == VROGeospatialAnchorProvider::ReactVision) {
1755-
if (onFailure) onFailure("createRooftopAnchor requires ARCore VPS (provider='arcore'). "
1756-
"ReactVision provider does not support GPS→AR placement.");
1796+
// altitudeAboveRooftop: approximate absolute alt = device altitude + offset
1797+
double absoluteAlt = _lastKnownGPSPose.altitude + altitudeAboveRooftop;
1798+
std::string error;
1799+
auto anchor = createLocalGPSAnchor(_session, _lastKnownGPSPose,
1800+
latitude, longitude, absoluteAlt,
1801+
VROGeospatialAnchorType::Rooftop, quaternion,
1802+
_geospatialProviderRV.get(), error);
1803+
if (anchor) { if (onSuccess) onSuccess(anchor); }
1804+
else { if (onFailure) onFailure(error); }
17571805
return;
17581806
}
17591807
#endif

0 commit comments

Comments
 (0)