/// <summary>
        /// Finds a good position to set the anchor.
        /// 1. If we have an anchor stored in the player prefs/ anchor store, use that
        /// 2. If we don't have spatial mapping, just use where the object happens to be
        /// 3. if we do have spatial mapping, anchor at a vertex dense portion of spatial mapping
        /// </summary>
        private void FindAnchorPosition()
        {
            // 1. recover a stored anchor if we can
            if (PlayerPrefs.HasKey(SavedAnchorKey) && AttachToCachedAnchor(PlayerPrefs.GetString(SavedAnchorKey)))
            {
                exportingAnchorName = PlayerPrefs.GetString(SavedAnchorKey);
                Debug.Log("found " + exportingAnchorName + " again");
                ExportAnchor();
            }
            // 2. just use the current object position if we don't have access to spatial mapping
            else if (spatialMapping == null)
            {
                if (UseSpatialMapping)
                {
                    Debug.Log("No spatial mapping...");
                }

                ExportAnchorAtPosition(objectToAnchor.transform.position);
            }
            // 3. seek a vertex dense portion of spatial mapping
            else
            {
                ReadOnlyCollection <SpatialMappingSource.SurfaceObject> surfaces = spatialMapping.GetSurfaceObjects();
                if (surfaces == null || surfaces.Count == 0)
                {
                    // If we aren't getting surfaces we may need to start the observer.
                    if (spatialMapping.IsObserverRunning() == false)
                    {
                        spatialMapping.StartObserver();
                        StartedObserver = true;
                    }

                    // And try again after the observer has a chance to get an update.
                    Invoke("FindAnchorPosition", spatialMapping.GetComponent <SpatialMappingObserver>().TimeBetweenUpdates);
                }
                else
                {
                    float startTime = Time.realtimeSinceStartup;
                    // If we have surfaces, we need to iterate through them to find a dense area
                    // of geometry, which should provide a good spot for an anchor.
                    Mesh       bestMesh   = null;
                    MeshFilter bestFilter = null;
                    int        mostVerts  = 0;

                    for (int index = 0; index < surfaces.Count; index++)
                    {
                        // If the current surface doesn't have a filter or a mesh, skip to the next one
                        // This happens as a surface is being processed.  We need to track both the mesh
                        // and the filter because the mesh has the verts in local space and the filter has the transform to
                        // world space.
                        MeshFilter currentFilter = surfaces[index].Filter;
                        if (currentFilter == null)
                        {
                            continue;
                        }

                        Mesh currentMesh = currentFilter.sharedMesh;
                        if (currentMesh == null)
                        {
                            continue;
                        }

                        // If we have a collider we can use the extents to estimate the volume.
                        MeshCollider currentCollider = surfaces[index].Collider;
                        float        volume          = currentCollider == null ? 1.0f : currentCollider.bounds.extents.magnitude;

                        // get th verts divided by the volume if any
                        int meshVerts = (int)(currentMesh.vertexCount / volume);

                        // and if this is most verts/volume we've seen, record this mesh as the current best.
                        mostVerts = Mathf.Max(meshVerts, mostVerts);
                        if (mostVerts == meshVerts)
                        {
                            bestMesh   = currentMesh;
                            bestFilter = currentFilter;
                        }
                    }

                    // If we have a good area to use, then use it.
                    if (bestMesh != null && mostVerts > 100)
                    {
                        // Get the average of the vertices
                        Vector3[] verts   = bestMesh.vertices;
                        Vector3   avgVert = verts.Average();

                        // transform the average into world space.
                        Vector3 center = bestFilter.transform.TransformPoint(avgVert);

                        Debug.LogFormat("found a good mesh mostVerts = {0} processed {1} meshes in {2} ms", mostVerts, surfaces.Count, 1000 * (Time.realtimeSinceStartup - startTime));
                        // then export the anchor where we've calculated.
                        ExportAnchorAtPosition(center);
                    }
                    else
                    {
                        // If we didn't find a good mesh, try again a little later.
                        Debug.LogFormat("Failed to find a good mesh mostVerts = {0} processed {1} meshes in {2} ms", mostVerts, surfaces.Count, 1000 * (Time.realtimeSinceStartup - startTime));
                        Invoke("FindAnchorPosition", spatialMapping.GetComponent <SpatialMappingObserver>().TimeBetweenUpdates);
                    }
                }
            }
        }