/// <summary> /// Inverse (Go from lat/lon to specified projection) /// </summary> /// <param name="uv"></param> /// <returns></returns> public UV Inverse(UV uv) { return pj_inv(uv, projPJ); }
/// <summary> /// Forward (Go from specified projection to lat/lon) /// </summary> /// <param name="uv"></param> /// <returns></returns> public UV Forward(UV uv) { return pj_fwd(uv, projPJ); }
static extern UV pj_inv(UV uv, IntPtr projPJ);
static extern UV pj_fwd(UV uv, IntPtr projPJ);
//NOTE this is a mix from Mashi's Reproject and WW for terrain public void CreateMesh(byte opacity, float verticalExaggeration) { this.vertEx = verticalExaggeration; int opacityColor = System.Drawing.Color.FromArgb(opacity, 0, 0, 0).ToArgb(); meshPointCount = 32; //64; //96 // How many vertices for each direction in mesh (total: n^2) //vertices = new CustomVertex.PositionColoredTextured[meshPointCount * meshPointCount]; // Build mesh with one extra row and col around the terrain for normal computation and struts vertices = new CustomVertex.PositionNormalTextured[(meshPointCount + 2) * (meshPointCount + 2)]; int upperBound = meshPointCount - 1; float scaleFactor = (float)1 / upperBound; //using(Projection proj = new Projection(m_projectionParameters)) //{ double uStep = (UR.U - UL.U) / upperBound; double vStep = (UL.V - LL.V) / upperBound; UV curUnprojected = new UV(UL.U - uStep, UL.V + vStep); // figure out latrange (for terrain detail) UV geoUL = _proj.Inverse(m_ul); UV geoLR = _proj.Inverse(m_lr); double latRange = (geoUL.U - geoLR.U) * 180 / Math.PI; North = geoUL.V * 180 / Math.PI; South = geoLR.V * 180 / Math.PI; West = geoUL.U * 180 / Math.PI; East = geoLR.U * 180 / Math.PI; float meshBaseRadius = (float)_layerRadius; /* float[,] heightData = null; if (_terrainAccessor != null && _veForm.IsTerrainOn == true) { //does the +1 to help against tears between elevated tiles? - made it worse //TODO not sure how to fix the tear between tiles caused by elevation? // Get elevation data with one extra row and col all around the terrain double degreePerSample = Math.Abs(latRange / (meshPointCount - 1)); TerrainTile tile = _terrainAccessor.GetElevationArray(North + degreePerSample, South - degreePerSample, West - degreePerSample, East + degreePerSample, meshPointCount + 2); heightData = tile.ElevationData; tile.Dispose(); tile = null; // Calculate mesh base radius (bottom vertices) float minimumElevation = float.MaxValue; float maximumElevation = float.MinValue; // Find minimum elevation to account for possible bathymetry foreach(float _height in heightData) { if(_height < minimumElevation) minimumElevation = _height; if(_height > maximumElevation) maximumElevation = _height; } minimumElevation *= verticalExaggeration; maximumElevation *= verticalExaggeration; if(minimumElevation > maximumElevation) { // Compensate for negative vertical exaggeration float tmp = minimumElevation; minimumElevation = maximumElevation; maximumElevation = tmp; } float overlap = 500 * verticalExaggeration; // 500m high tiles // Radius of mesh bottom grid meshBaseRadius = (float) _layerRadius + minimumElevation - overlap; } */ UV geo; Vector3 pos; double height = 0; for (int i = 0; i < meshPointCount + 2; i++) { for (int j = 0; j < meshPointCount + 2; j++) { geo = _proj.Inverse(curUnprojected); // Radians -> Degrees geo.U *= 180 / Math.PI; geo.V *= 180 / Math.PI; if (_terrainAccessor != null) { if (_veForm.IsTerrainOn == true) { //height = heightData[i, j] * verticalExaggeration; //original : need to fetch altitude on a per vertex basis (in VE space) to have matching tile borders (note PM) height = verticalExaggeration * _terrainAccessor.GetElevationAt(geo.V, geo.U, Math.Abs(upperBound / latRange)); } else { height = 0; } } pos = MathEngine.SphericalToCartesian( geo.V, geo.U, _layerRadius + height); int idx = i * (meshPointCount + 2) + j; vertices[idx].X = pos.X; vertices[idx].Y = pos.Y; vertices[idx].Z = pos.Z; //double sinLat = Math.Sin(geo.V); //vertices[idx].Z = (float) (pos.Z * sinLat); vertices[idx].Tu = (j - 1) * scaleFactor; vertices[idx].Tv = (i - 1) * scaleFactor; //vertices[idx].Color = opacityColor; curUnprojected.U += uStep; } curUnprojected.U = UL.U - uStep; curUnprojected.V -= vStep; } //} int slices = meshPointCount + 1; indices = new short[2 * slices * slices * 3]; for (int i = 0; i < slices; i++) { for (int j = 0; j < slices; j++) { indices[(2 * 3 * i * slices) + 6 * j] = (short)(i * (meshPointCount + 2) + j); indices[(2 * 3 * i * slices) + 6 * j + 1] = (short)((i + 1) * (meshPointCount + 2) + j); indices[(2 * 3 * i * slices) + 6 * j + 2] = (short)(i * (meshPointCount + 2) + j + 1); indices[(2 * 3 * i * slices) + 6 * j + 3] = (short)(i * (meshPointCount + 2) + j + 1); indices[(2 * 3 * i * slices) + 6 * j + 4] = (short)((i + 1) * (meshPointCount + 2) + j); indices[(2 * 3 * i * slices) + 6 * j + 5] = (short)((i + 1) * (meshPointCount + 2) + j + 1); } } // Compute normals and fold struts calculate_normals(); fold_struts(false, meshBaseRadius); }
/// <summary> /// Update layer (called from worker thread) /// </summary> public override void Update(DrawArgs drawArgs) { try { if (this.isOn == false) { return; } //NOTE for some reason Initialize is not getting called from the Plugin Menu Load/Unload //it does get called when the plugin loads from Startup //not sure what is going on, so i'll just call it manually if (this.isInitialized == false) { this.Initialize(drawArgs); return; } //get lat, lon double lat = drawArgs.WorldCamera.Latitude.Degrees; double lon = drawArgs.WorldCamera.Longitude.Degrees; double tilt = drawArgs.WorldCamera.Tilt.Degrees; //determine zoom level double alt = drawArgs.WorldCamera.Altitude; //could go off distance, but this changes when view angle changes //Angle fov = drawArgs.WorldCamera.Fov; //stays at 45 degress //Angle viewRange = drawArgs.WorldCamera.ViewRange; //off of distance, same as TVR but changes when view angle changes Angle tvr = drawArgs.WorldCamera.TrueViewRange; //off of altitude //smallest altitude = 100m //tvr = .00179663198575926 //start altitude = 12756273m //tvr = 180 //WW _levelZeroTileSizeDegrees //180 90 45 22.5 11.25 5.625 2.8125 1.40625 .703125 .3515625 .17578125 .087890625 0.0439453125 0.02197265625 0.010986328125 0.0054931640625 int zoomLevel = GetZoomLevelByTrueViewRange(tvr.Degrees); //dont start VE tiles until a certain zoom level if (zoomLevel < veForm.StartZoomLevel) { this.RemoveAllTiles(); this.ForceRefresh(); return; } //WW tiles //double tileDegrees = GetLevelDegrees(zoomLevel); //int row = MathEngine.GetRowFromLatitude(lat, tileDegrees); //int col = MathEngine.GetColFromLongitude(lon, tileDegrees); //VE tiles double metersY; double yMeters; int yMetersPerPixel; int row; /* //WRONG - doesn't stay centered away from equator //int yMeters = LatitudeToYAtZoom(lat, zoomLevel); //1024 double sinLat = Math.Sin(DegToRad(lat)); metersY = earthRadius / 2 * Math.Log((1 + sinLat) / (1 - sinLat)); //0 yMeters = earthHalfCirc - metersY; //20037508.342789244 yMetersPerPixel = (int) Math.Round(yMeters / MetersPerPixel(zoomLevel)); row = yMetersPerPixel / pixelsPerTile; */ //CORRECT //int xMeters = LongitudeToXAtZoom(lon, zoomLevel); //1024 double metersX = earthRadius * DegToRad(lon); //0 double xMeters = earthHalfCirc + metersX; //20037508.342789244 int xMetersPerPixel = (int)Math.Round(xMeters / MetersPerPixel(zoomLevel)); int col = xMetersPerPixel / pixelsPerTile; //reproject - overrides row above //this correctly keeps me on the current tile that is being viewed UV uvCurrent = new UV(DegToRad(lon), DegToRad(lat)); uvCurrent = proj.Forward(uvCurrent); metersY = uvCurrent.V; yMeters = earthHalfCirc - metersY; yMetersPerPixel = (int)Math.Round(yMeters / MetersPerPixel(zoomLevel)); row = yMetersPerPixel / pixelsPerTile; //update mesh if VertEx changes if (prevVe != World.Settings.VerticalExaggeration) { lock (veTiles.SyncRoot) { VeTile veTile; for (int i = 0; i < veTiles.Count; i++) { veTile = (VeTile)veTiles[i]; if (veTile.VertEx != World.Settings.VerticalExaggeration) { veTile.CreateMesh(this.Opacity, World.Settings.VerticalExaggeration); } } } } prevVe = World.Settings.VerticalExaggeration; //if within previous bounds and same zoom level, then exit if (row == prevRow && col == prevCol && zoomLevel == prevLvl && tilt == preTilt) { return; } //System.Diagnostics.Debug.WriteLine("CHANGE"); lock (veTiles.SyncRoot) { VeTile veTile; for (int i = 0; i < veTiles.Count; i++) { veTile = (VeTile)veTiles[i]; veTile.IsNeeded = false; } } //metadata ArrayList alMetadata = null; if (veForm.IsDebug == true) { alMetadata = new ArrayList(); alMetadata.Add("yMeters " + yMeters.ToString()); alMetadata.Add("metersY " + metersY.ToString()); alMetadata.Add("yMeters2 " + yMeters.ToString()); alMetadata.Add("vLat " + uvCurrent.V.ToString()); //alMetadata.Add("xMeters " + xMeters.ToString()); //alMetadata.Add("metersX " + metersX.ToString()); //alMetadata.Add("uLon " + uvCurrent.U.ToString()); } //add current tiles first AddVeTile(drawArgs, row, col, zoomLevel, alMetadata); //then add other tiles outwards in surrounding circles AddNeighborTiles(drawArgs, row, col, zoomLevel, null, 1); AddNeighborTiles(drawArgs, row, col, zoomLevel, null, 2); AddNeighborTiles(drawArgs, row, col, zoomLevel, null, 3); // Extend tile grid if camera tilt above some values if(tilt > 45) AddNeighborTiles(drawArgs, row, col, zoomLevel, null, 4); if(tilt > 60) AddNeighborTiles(drawArgs, row, col, zoomLevel, null, 5); //if(prevLvl > zoomLevel) //zooming out //{ //} lock (veTiles.SyncRoot) { VeTile veTile; for (int i = 0; i < veTiles.Count; i++) { veTile = (VeTile)veTiles[i]; if (veTile.IsNeeded == false) { veTile.Dispose(); veTiles.RemoveAt(i); i--; } } } prevRow = row; prevCol = col; prevLvl = zoomLevel; preTilt = tilt; } catch (Exception ex) { Utility.Log.Write(ex); } }