Untitled

 avatar
unknown
plain_text
5 months ago
9.0 kB
4
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