/// <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); }
static extern UV pj_inv(UV uv, IntPtr 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_fwd(UV uv, IntPtr projPJ);
/// <summary> /// This can be used by mesh calculation to calculate projected meshes for tiles /// </summary> internal virtual void GetProjectionCorners(IGeoSpatialDownloadTile tile, out UV ul, out UV ur, out UV ll, out UV lr) { // For normal quad tiles this is equal to the geographic coordinates ul = new UV(tile.West, tile.North); ur = new UV(tile.East, tile.North); ll = new UV(tile.West, tile.South); lr = new UV(tile.East, tile.South); }
/// <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; //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); //VE tiles double metersY; double yMeters; int yMetersPerPixel; int row; 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; //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); lock (veTiles.SyncRoot) { VeTile veTile; for (int i = 0; i < veTiles.Count; i++) { veTile = (VeTile)veTiles[i]; if (veTile.IsNeeded == false && veTile.DownloadInProgress == false) { veTile.Dispose(); veTiles.RemoveAt(i); i--; } } } prevRow = row; prevCol = col; prevLvl = zoomLevel; preTilt = tilt; } catch (Exception ex) { Utility.Log.Write(ex); } }
//NOTE this is a mix from Mashi's Reproject and WW for terrain internal void CreateMesh(byte opacity, float verticalExaggeration) { this.vertEx = verticalExaggeration; 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; UV geo; Point3d 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) { height = verticalExaggeration * _terrainAccessor.GetElevationAt(geo.V, geo.U, Math.Abs(upperBound / latRange)); } pos = MathEngine.SphericalToCartesian( geo.V, geo.U, _layerRadius + height); int idx = i * (meshPointCount + 2) + j; vertices[idx].X = (float)pos.X; vertices[idx].Y = (float)pos.Y; vertices[idx].Z = (float)pos.Z; vertices[idx].Tu = (j - 1) * scaleFactor; vertices[idx].Tv = (i - 1) * scaleFactor; 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> /// Builds a mesh using a projection (with terrain if requested) /// </summary> protected virtual void CreateProjectedMesh(Projection proj, bool bTerrain) { int baseIndex; UV geo; double sinLat, cosLat, sinLon, cosLon, height, latRange = North - South; double layerRadius = (double)quadTileSet.LayerRadius; double scaleFactor = 1.0 / (double)vertexCount; int thisVertexCount = vertexCount / 2 + (vertexCount % 2); int thisVertexCountPlus1 = thisVertexCount + 1; const double Degrees2Radians = Math.PI / 180.0; int totalVertexCount = thisVertexCountPlus1 * thisVertexCountPlus1; northWestVertices = new CustomVertex.PositionNormalTextured[totalVertexCount]; southWestVertices = new CustomVertex.PositionNormalTextured[totalVertexCount]; northEastVertices = new CustomVertex.PositionNormalTextured[totalVertexCount]; southEastVertices = new CustomVertex.PositionNormalTextured[totalVertexCount]; double uStep = (UR.U - UL.U) * scaleFactor; double vStep = (UL.V - LL.V) * scaleFactor; // figure out latrange (for terrain detail) if (bTerrain) { UV geoUL = proj.Inverse(UL); UV geoLR = proj.Inverse(LR); latRange = (geoUL.V - geoLR.V) * 180 / Math.PI; } baseIndex = 0; UV curUnprojected = new UV(UL.U, UL.V); for (int i = 0; i < thisVertexCountPlus1; i++) { for (int j = 0; j < thisVertexCountPlus1; j++) { geo = proj.Inverse(curUnprojected); sinLat = Math.Sin(geo.V); sinLon = Math.Sin(geo.U); cosLat = Math.Cos(geo.V); cosLon = Math.Cos(geo.U); height = layerRadius; if (bTerrain) { // Radians -> Degrees geo.U /= Degrees2Radians; geo.V /= Degrees2Radians; height += verticalExaggeration * quadTileSet.World.TerrainAccessor.GetElevationAt(geo.V, geo.U, Math.Abs(vertexCount / latRange)); } northWestVertices[baseIndex].X = (float)(height * cosLat * cosLon - localOrigin.X); northWestVertices[baseIndex].Y = (float)(height * cosLat * sinLon - localOrigin.Y); northWestVertices[baseIndex].Z = (float)(height * sinLat - localOrigin.Z); northWestVertices[baseIndex].Tu = (float)(j * scaleFactor); northWestVertices[baseIndex].Tv = (float)(i * scaleFactor); northWestVertices[baseIndex].Normal = new Vector3(northWestVertices[baseIndex].X + (float)localOrigin.X, northWestVertices[baseIndex].Y + (float)localOrigin.Y, northWestVertices[baseIndex].Z + (float)localOrigin.Z); northWestVertices[baseIndex].Normal.Normalize(); baseIndex += 1; curUnprojected.U += uStep; } curUnprojected.U = UL.U; curUnprojected.V -= vStep; } baseIndex = 0; curUnprojected = new UV(UL.U, UL.V - (UL.V - LL.V) / 2.0); for (int i = 0; i < thisVertexCountPlus1; i++) { for (int j = 0; j < thisVertexCountPlus1; j++) { geo = proj.Inverse(curUnprojected); sinLat = Math.Sin(geo.V); sinLon = Math.Sin(geo.U); cosLat = Math.Cos(geo.V); cosLon = Math.Cos(geo.U); height = layerRadius; if (bTerrain) { // Radians -> Degrees geo.U /= Degrees2Radians; geo.V /= Degrees2Radians; height += verticalExaggeration * quadTileSet.World.TerrainAccessor.GetElevationAt(geo.V, geo.U, Math.Abs(vertexCount / latRange)); } southWestVertices[baseIndex].X = (float)(height * cosLat * cosLon - localOrigin.X); southWestVertices[baseIndex].Y = (float)(height * cosLat * sinLon - localOrigin.Y); southWestVertices[baseIndex].Z = (float)(height * sinLat - localOrigin.Z); southWestVertices[baseIndex].Tu = (float)(j * scaleFactor); southWestVertices[baseIndex].Tv = (float)((i + thisVertexCount) * scaleFactor); southWestVertices[baseIndex].Normal = new Vector3(southWestVertices[baseIndex].X + (float)localOrigin.X, southWestVertices[baseIndex].Y + (float)localOrigin.Y, southWestVertices[baseIndex].Z + (float)localOrigin.Z); southWestVertices[baseIndex].Normal.Normalize(); baseIndex += 1; curUnprojected.U += uStep; } curUnprojected.U = UL.U; curUnprojected.V -= vStep; } baseIndex = 0; curUnprojected = new UV(UL.U + (UR.U - UL.U) / 2.0, UL.V); for (int i = 0; i < thisVertexCountPlus1; i++) { for (int j = 0; j < thisVertexCountPlus1; j++) { geo = proj.Inverse(curUnprojected); sinLat = Math.Sin(geo.V); sinLon = Math.Sin(geo.U); cosLat = Math.Cos(geo.V); cosLon = Math.Cos(geo.U); height = layerRadius; if (bTerrain) { // Radians -> Degrees geo.U /= Degrees2Radians; geo.V /= Degrees2Radians; height += verticalExaggeration * quadTileSet.World.TerrainAccessor.GetElevationAt(geo.V, geo.U, Math.Abs(vertexCount / latRange)); } northEastVertices[baseIndex].X = (float)(height * cosLat * cosLon - localOrigin.X); northEastVertices[baseIndex].Y = (float)(height * cosLat * sinLon - localOrigin.Y); northEastVertices[baseIndex].Z = (float)(height * sinLat - localOrigin.Z); northEastVertices[baseIndex].Tu = (float)((j + thisVertexCount) * scaleFactor); northEastVertices[baseIndex].Tv = (float)(i * scaleFactor); northEastVertices[baseIndex].Normal = new Vector3(northEastVertices[baseIndex].X + (float)localOrigin.X, northEastVertices[baseIndex].Y + (float)localOrigin.Y, northEastVertices[baseIndex].Z + (float)localOrigin.Z); northEastVertices[baseIndex].Normal.Normalize(); baseIndex += 1; curUnprojected.U += uStep; } curUnprojected.U = UL.U + (UR.U - UL.U) / 2.0; curUnprojected.V -= vStep; } baseIndex = 0; curUnprojected = new UV(UL.U + (UR.U - UL.U) / 2.0, UL.V - (UL.V - LL.V) / 2.0); for (int i = 0; i < thisVertexCountPlus1; i++) { for (int j = 0; j < thisVertexCountPlus1; j++) { geo = proj.Inverse(curUnprojected); sinLat = Math.Sin(geo.V); sinLon = Math.Sin(geo.U); cosLat = Math.Cos(geo.V); cosLon = Math.Cos(geo.U); height = layerRadius; if (bTerrain) { // Radians -> Degrees geo.U /= Degrees2Radians; geo.V /= Degrees2Radians; height += verticalExaggeration * quadTileSet.World.TerrainAccessor.GetElevationAt(geo.V, geo.U, Math.Abs(vertexCount / latRange)); } southEastVertices[baseIndex].X = (float)(height * cosLat * cosLon - localOrigin.X); southEastVertices[baseIndex].Y = (float)(height * cosLat * sinLon - localOrigin.Y); southEastVertices[baseIndex].Z = (float)(height * sinLat - localOrigin.Z); southEastVertices[baseIndex].Tu = (float)((j + thisVertexCount) * scaleFactor); southEastVertices[baseIndex].Tv = (float)((i + thisVertexCount) * scaleFactor); southEastVertices[baseIndex].Normal = new Vector3(southEastVertices[baseIndex].X + (float)localOrigin.X, southEastVertices[baseIndex].Y + (float)localOrigin.Y, southEastVertices[baseIndex].Z + (float)localOrigin.Z); southEastVertices[baseIndex].Normal.Normalize(); baseIndex += 1; curUnprojected.U += uStep; } curUnprojected.U = UL.U + (UR.U - UL.U) / 2.0; curUnprojected.V -= vStep; } vertexIndexes = new short[2 * thisVertexCount * thisVertexCount * 3]; for (int i = 0; i < thisVertexCount; i++) { baseIndex = (2 * 3 * i * thisVertexCount); for (int j = 0; j < thisVertexCount; j++) { vertexIndexes[baseIndex] = (short)(i * thisVertexCountPlus1 + j); vertexIndexes[baseIndex + 1] = (short)((i + 1) * thisVertexCountPlus1 + j); vertexIndexes[baseIndex + 2] = (short)(i * thisVertexCountPlus1 + j + 1); vertexIndexes[baseIndex + 3] = (short)(i * thisVertexCountPlus1 + j + 1); vertexIndexes[baseIndex + 4] = (short)((i + 1) * thisVertexCountPlus1 + j); vertexIndexes[baseIndex + 5] = (short)((i + 1) * thisVertexCountPlus1 + j + 1); baseIndex += 6; } } // JBTODO: Should we normalize here for elevated mesh? }