23.5 C
New York
Tuesday, August 19, 2025

unity – Aligning OpenStreetMap knowledge with Cesium 3D tiles


I’ve my OpenStreetMap knowledge exported utilizing QGIS as a gltf file, and I am making an attempt to align it with Cesium 3d tiles for my excessive decision mannequin.

The issue is that each have totally different coordinate programs:

After I import the gltf and drop it in my scene, each the fashions are misaligned. I attempted to align them collectively utilizing this C# script ChatGPT helped me write, however did not succeed:

utilizing UnityEngine;
utilizing System;
utilizing CesiumForUnity;

[ExecuteAlways]
public class PlaceModelCartographic : MonoBehaviour
{
    [Header("Known EPSG:25832 (UTM Zone 32N) coordinates of reference point")]
    public double easting = 680813.8264980253;
    public double northing = 5779850.461563687;
    public double heightEllipsoid = 165.098;   // ellipsoidal meters

    [Header("Manual alignment offsets")]
    public Vector3 localOffsetMeters = Vector3.zero; // small nudge in native house
    public float heightOffset = 0.0f;               // regulate vertical misalignment
    public float uniformScale = 1.0f;               // repair scale mismatch

    [Range(0.01f, 10f)]
    public float scaleFactor = 1.0f;

    non-public CesiumForUnity.CesiumGlobeAnchor anchor;

    void OnValidate()
    {
        UpdatePlacement();
    }

    void UpdatePlacement()
    {
        // Guarantee anchor exists
        if (anchor == null)
        {
            anchor = GetComponent();
            if (anchor == null)
                anchor = gameObject.AddComponent();
        }

        double latDeg, lonDeg;
        Epsg25832Utility.UtmToLatLonDegrees(easting, northing, out latDeg, out lonDeg);

        anchor.latitude = latDeg;
        anchor.longitude = lonDeg;
        anchor.top = heightEllipsoid + heightOffset;

        // Reset little one transforms
        foreach (Remodel little one in remodel)
        {
            little one.localPosition = Vector3.zero;
            little one.localRotation = Quaternion.id;
            little one.localScale = Vector3.one * scaleFactor;
        }
    }
}
/// 
/// EPSG:25832 UTM → WGS84 lat/lon (levels).
/// 
static class Epsg25832Utility
{
    const double a = 6378137.0;                 // GRS80
    const double f = 1.0 / 298.257222101;
    const double k0 = 0.9996;
    const double FE = 500000.0;
    const int ZONE = 32;
    static readonly double LON0 = (ZONE * 6 - 183) * Mathf.Deg2Rad; // 9°E

    public static void UtmToLatLonDegrees(double E, double N, out double latDeg, out double lonDeg)
    {
        double latRad, lonRad;
        UtmToLatLonRadians(E, N, out latRad, out lonRad);
        latDeg = latRad * Mathf.Rad2Deg;
        lonDeg = lonRad * Mathf.Rad2Deg;
    }

    static void UtmToLatLonRadians(double E, double N, out double lat, out double lon)
    {
        double b = a * (1 - f);
        double e2 = (a * a - b * b) / (a * a);
        double ep2 = (a * a - b * b) / (b * b);

        double x = (E - FE) / k0;
        double y = N / k0;

        double e1 = (1 - Mathf.Sqrt(1 - (float)e2)) / (1 + Mathf.Sqrt(1 - (float)e2));
        double M = y;
        double mu = M / (a * (1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * Mathf.Pow((float)e2, 3) / 256));

        double J1 = (3 * e1 / 2 - 27 * Mathf.Pow((float)e1, 3) / 32);
        double J2 = (21 * e1 * e1 / 16 - 55 * Mathf.Pow((float)e1, 4) / 32);
        double J3 = (151 * Mathf.Pow((float)e1, 3) / 96);
        double J4 = (1097 * Mathf.Pow((float)e1, 4) / 512);

        double fp = mu + J1 * Mathf.Sin(2f * (float)mu) + J2 * Mathf.Sin(4f * (float)mu)
                      + J3 * Mathf.Sin(6f * (float)mu) + J4 * Mathf.Sin(8f * (float)mu);

        double sinfp = Mathf.Sin((float)fp);
        double cosfp = Mathf.Cos((float)fp);
        double tanfp = Mathf.Tan((float)fp);

        double C1 = ep2 * cosfp * cosfp;
        double T1 = tanfp * tanfp;
        double N1 = a / Math.Sqrt(1 - e2 * sinfp * sinfp);
        double R1 = N1 * (1 - e2) / (1 - e2 * sinfp * sinfp);
        double D = x / N1;

        lat = fp - (N1 * tanfp / R1) * (
              (D * D) / 2
            - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * ep2) * Mathf.Pow((float)D, 4) / 24
            + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * ep2 - 3 * C1 * C1) * Mathf.Pow((float)D, 6) / 720
        );

        lon = LON0 + (
              D
            - (1 + 2 * T1 + C1) * Mathf.Pow((float)D, 3) / 6
            + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * ep2 + 24 * T1 * T1) * Mathf.Pow((float)D, 5) / 120
        ) / cosfp;
    }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles