Untitled
unknown
plain_text
a year ago
9.0 kB
5
Indexable
@Composable
fun ARSceneContent(sourceLatLng: LatLng,destinationLatLng: LatLng?) {
Box(modifier = Modifier.fillMaxSize()) {
val engine = rememberEngine()
val modelLoader = rememberModelLoader(engine)
val materialLoader = rememberMaterialLoader(engine)
val cameraNode = rememberARCameraNode(engine)
val childNodes = rememberNodes()
val view = rememberView(engine)
val collisionSystem = rememberCollisionSystem(view)
var planeRenderer by remember { mutableStateOf(true) }
var trackingFailureReason by remember {
mutableStateOf<TrackingFailureReason?>(null)
}
var frame by remember { mutableStateOf<Frame?>(null) }
var destinationAnchor: Anchor? = null
var previousDestination: LatLng? = null
ARScene(
modifier = Modifier.fillMaxSize(),
childNodes = childNodes,
engine = engine,
view = view,
modelLoader = modelLoader,
collisionSystem = collisionSystem,
sessionConfiguration = { session, config ->
config.depthMode =
when (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {
true -> Config.DepthMode.AUTOMATIC
else -> Config.DepthMode.DISABLED
}
config.instantPlacementMode = Config.InstantPlacementMode.LOCAL_Y_UP
config.lightEstimationMode =
Config.LightEstimationMode.ENVIRONMENTAL_HDR
config.geospatialMode = Config.GeospatialMode.ENABLED
},
cameraNode = cameraNode,
planeRenderer = planeRenderer,
onTrackingFailureChanged = {
trackingFailureReason = it
},
onSessionUpdated = { session, updatedFrame ->
frame = updatedFrame
// if(session.isGeospatialModeSupported(Config.GeospatialMode.ENABLED)){
//// Log.d("tg", "ARSceneContent:enabled ")
// }
// if (childNodes.isEmpty()) {
// updatedFrame.getUpdatedPlanes().firstOrNull { it.type == Plane.Type.HORIZONTAL_UPWARD_FACING }
// ?.let { it.createAnchorOrNull(it.centerPose) }?.let { anchor ->
// childNodes += createAnchorNode(
// engine = engine,
// modelLoader = modelLoader,
// materialLoader = materialLoader,
// anchor = anchor
// )
// }
// }
val earth = session.earth
if (earth?.earthState == Earth.EarthState.ENABLED) {
// Check if destination anchor needs to be recreated
if (destinationAnchor == null || previousDestination != destinationLatLng) {
previousDestination = destinationLatLng
// Detach old anchor if it exists
destinationAnchor?.detach()
destinationAnchor =
createDestinationAnchor(earth, destinationLatLng!!)?.also { anchor ->
childNodes += createAnchorNode(
engine = engine,
modelLoader = modelLoader,
materialLoader = materialLoader,
anchor = anchor
)
}
}
}
else{
Log.d("tag", "null: "+earth)
}
},
onGestureListener = rememberOnGestureListener(
onSingleTapConfirmed = { motionEvent, node ->
if (node == null) {
val hitResults = frame?.hitTest(motionEvent.x, motionEvent.y)
hitResults?.firstOrNull {
it.isValid(
depthPoint = false,
point = false
)
}?.createAnchorOrNull()
?.let { anchor ->
planeRenderer = false
childNodes += createAnchorNode(
engine = engine,
modelLoader = modelLoader,
materialLoader = materialLoader,
anchor = anchor
)
}
}
})
)
}
}
fun createDestinationAnchor(earth: Earth?, destinationLatLng: LatLng): Anchor? {
if (earth?.earthState != Earth.EarthState.ENABLED) {
Log.e("Anchor", "Earth is not enabled")
return null
}
val latitude = destinationLatLng.latitude
val longitude = destinationLatLng.longitude
val altitude = earth.cameraGeospatialPose.altitude - 1.5
return earth.createAnchor(
longitude,
altitude,
latitude,
0.0f, 0.0f, 0.0f, 1.0f
).also {
Log.d("Anchor", "Created anchor at Lat=$latitude, Lng=$longitude, Alt=$altitude")
}
}
fun createAnchorNode(
engine: Engine,
modelLoader: ModelLoader,
materialLoader: MaterialLoader,
anchor: Anchor
): AnchorNode {
val anchorNode = AnchorNode(engine = engine, anchor = anchor)
val modelNode = ModelNode(
modelInstance = modelLoader.createModelInstance(kModelFile),
// Scale to fit in a 0.5 meters cube
scaleToUnits = 0.5f
).apply {
// Model Node needs to be editable for independent rotation from the anchor rotation
isEditable = true
editableScaleRange = 0.2f..0.75f
}
val boundingBoxNode = CubeNode(
engine,
size = modelNode.extents,
center = modelNode.center,
materialInstance = materialLoader.createColorInstance(Color.White.copy(alpha = 0.5f))
).apply {
isVisible = false
}
modelNode.addChildNode(boundingBoxNode)
anchorNode.addChildNode(modelNode)
listOf(modelNode, anchorNode).forEach {
it.onEditingChanged = { editingTransforms ->
boundingBoxNode.isVisible = editingTransforms.isNotEmpty()
}
}
return anchorNode
}
fun generatePathPoints(start: LatLng, end: LatLng, spacing: Double): List<LatLng> {
val pathPoints = mutableListOf<LatLng>()
val distance = calculateDistance(start, end)
val steps = (distance / spacing).toInt()
Log.d("", "distance: "+distance)
for (i in 0..steps) {
val fraction = i.toDouble() / steps
val lat = start.latitude + fraction * (end.latitude - start.latitude)
val lng = start.longitude + fraction * (end.longitude - start.longitude)
pathPoints.add(LatLng(lat, lng))
}
Log.d("", "pathPoints: "+pathPoints)
return pathPoints
}
fun calculateBearing(start: LatLng, end: LatLng): Float {
val startLat = Math.toRadians(start.latitude)
val startLng = Math.toRadians(start.longitude)
val endLat = Math.toRadians(end.latitude)
val endLng = Math.toRadians(end.longitude)
val dLng = endLng - startLng
val x = Math.sin(dLng) * Math.cos(endLat)
val y = Math.cos(startLat) * Math.sin(endLat) - Math.sin(startLat) * Math.cos(endLat) * Math.cos(dLng)
return ((Math.toDegrees(Math.atan2(x, y)) + 360) % 360).toFloat()
}
// Calculate distance between two LatLng points
private fun calculateDistance(start: LatLng, end: LatLng): Double {
val results = FloatArray(1)
Location.distanceBetween(
start.latitude,
start.longitude,
end.latitude,
end.longitude,
results
)
return results[0].toDouble()
}
Editor is loading...
Leave a Comment