Ejemplo n.º 1
0
    public void MapEarth()
    {
        profilePanel.SetActive(false);

        // Clear old variables
        Destroy(mappedEarth);

        foreach (GameObject l in landmarkList)
        {
            Destroy(l);
        }
        landmarkList.Clear();

        foreach (GameObject t in labelList)
        {
            Destroy(t);
        }
        labelList.Clear();

        #region EARTH_MAPPING
        // Initialise the earth object and the horizon
        // The horizon (range) is 5km x 5km as suggested for a 1.7m human
        referenceOrigin = placementPose.position;
        referenceEarth  = Instantiate(earthToReference, referenceOrigin, Quaternion.identity);
        mappedEarth     = Instantiate(earthHorizonPrefab, referenceOrigin, Quaternion.identity);

        Transform pinGroup = referenceEarth.transform.Find("Group_Pins");
        Transform refTop   = referenceEarth.transform.Find("Ref_Top");

        // Scale and reposition the Earth
        referenceEarth.transform.localScale = Vector3.one * CORE.EARTH_PREFAB_SCALE_TO_REAL;

        // Rotate the Earth so that the current position is facing up so that we can do the following calculations
        // Use the pre-calculated value
        referenceEarth.transform.rotation = CORE.ROTATE_TO_TOP;

        // Rotate the Earth so that the current north direction is aligned geographically
        // First, find the current device facing direction (projection on z axis)
        Vector3 facingDirection      = Vector3.ProjectOnPlane(Camera.main.transform.forward, Vector3.up).normalized;
        Vector3 prefabNorthDirection = Vector3.ProjectOnPlane(refTop.position - referenceEarth.transform.position, Vector3.up).normalized;

        // Then, compute the degree required to rotate the earth to the facing direction
        Quaternion rotateToFacingDirection = Quaternion.FromToRotation(prefabNorthDirection, facingDirection);

        // Lastly, compute the degree required to rotate the earth to the geographical north
        Quaternion rotateToGeographicalNorth = Quaternion.Euler(0, -Input.compass.trueHeading, 0);

        // 1. Use ROTATION
        // Compute the degree required to rotate the north direction to match the facing direction
        //float degree;
        //Vector3 axis;
        //rotateToFacingDirection.ToAngleAxis(out degree, out axis);
        //mappedEarth.transform.RotateAround(transform.position, Vector3.up, degree);

        // Then rotate the Earth again according to the heading direction from the GPS so that the north direction is matched both virtually and physically
        //mappedEarth.transform.Rotate(Vector3.up, -Input.compass.trueHeading, Space.World);

        // OR 2. Use QUATERNION
        // Those steps need to be combined backwards to get the correct result
        referenceEarth.transform.rotation = rotateToGeographicalNorth * rotateToFacingDirection * CORE.ROTATE_TO_TOP;

        // Fix the floating point imprecision issue due to the large scale
        Vector3 impreciseRefPosition = pinGroup.GetChild(0).gameObject.transform.position;
        float   preciseScaleFactor   = CORE.EARTH_CRUST_RADIUS / impreciseRefPosition.y;

        foreach (Transform pin in pinGroup)
        {
            pin.position *= preciseScaleFactor;
        }

        // Shift the mapped earth down so that the y value of current position is the same as the selected surface for mapping
        referenceEarth.transform.position -= new Vector3(0, CORE.EARTH_CRUST_RADIUS, 0);
        #endregion

        mappedEarth.transform.Find("Mapping_Border").rotation = referenceEarth.transform.rotation;

        #region PIN_ASSIGNMENT
        Vector3 preciseRefPosition = pinGroup.GetChild(0).gameObject.transform.position;
        foreach (Transform pin in pinGroup)
        {
            // Display landmarks excluding the current position
            if (pin.position != preciseRefPosition)
            {
                CORE.LocationInfo currentPinLocation = CORE.LOCATION_DATABASE[int.Parse(pin.gameObject.name)];
                float             geoDistance        = CORE.DistanceBetweenLatLong(currentPinLocation.coord, CORE.USER_LATLONG);
                float             distanceScale      = (pin.position - referenceOrigin).magnitude / 1000;

                #region CITY_LANDMARK_IMAGE
                // Instantiate the landmark prefab
                GameObject landmark = Instantiate(landmarkPrefab, pin.position, Quaternion.identity, canvasWorld.transform);

                // Set the landmark image
                Transform landmarkImage = landmark.transform.Find("UI_Landmark_Image");
                landmarkImage.name = pin.name;

                // Rescale the landmark
                landmark.transform.localScale *= distanceScale;

                // Change the sprite based on the geographical distance
                if (geoDistance > 5)
                {
                    landmarkImage.GetComponent <Image>().sprite = spriteFarPin;
                }
                else
                {
                    landmarkImage.GetComponent <Image>().sprite = spriteNearPin;
                }

                // Fill the color
                landmarkImage.GetComponent <Image>().color = new Color32(0, 255, 0, 255);

                landmarkList.Add(landmark);
                #endregion

                #region CITY_INFO_LABEL
                // Place hovering labels
                GameObject label = Instantiate(labelPrefab, pin.position, Quaternion.identity, canvasWorld.transform);
                label.transform.Find("Label_LandmarkName").GetComponent <Text>().text = currentPinLocation.name + ", " + currentPinLocation.country;

                // Display the indicator based on the geographical distance
                if (geoDistance > 5)
                {
                    label.transform.Find("Label_LandmarkDistance").GetComponent <Text>().text = "▽ ";
                }
                else
                {
                    label.transform.Find("Label_LandmarkDistance").GetComponent <Text>().text = "▲ ";
                }

                // Display the geographical distance
                label.transform.Find("Label_LandmarkDistance").GetComponent <Text>().text += (geoDistance.ToString() + "km");

                // Rescale the label
                label.transform.localScale = Vector3.one * UILabelScale * distanceScale;
                labelList.Add(label);
                #endregion
            }
            else
            {
                pin.gameObject.SetActive(false);
            }
        }

        profilePanel.transform.SetAsLastSibling();
        #endregion

        legendPanel.SetActive(true);

        // Destroy it since it is no longer needed
        Destroy(referenceEarth);
    }