/// <summary> /// for substitute tiles - /// makes a subset of features out of existing features, adds it to cache (under this tile name), /// so the next time this tile is called a cache-resident subset is ready for use /// </summary> public void CreateFeaturesSubset() { Features tileFeatures = TileCache.getFeatures(this, m_baseName); if (!m_tileFeatures.HasLoaded) { #if DEBUG LibSys.StatusBar.Trace("IP: Tile::CreateFeaturesSubset() - " + m_baseName + " - not loaded yet " + m_tileFeatures); #endif return; } if (tileFeatures.HasLoaded) { #if DEBUG LibSys.StatusBar.Trace("IP: Tile::CreateFeaturesSubset() - " + m_baseName + " - found in cache " + tileFeatures); #endif } else { GeoCoord bottomRight = m_bottomRight.Clone(); bottomRight.Normalize(); GeoCoord topLeft = m_topLeft.Clone(); topLeft.Normalize(); double rightLng = bottomRight.Lng; double leftLng = topLeft.Lng; if (rightLng <= -180.0d) { rightLng += 360.0d; } double bottomLat = bottomRight.Lat; double topLat = topLeft.Lat; //LibSys.StatusBar.Trace("IP: Tile::CreateFeaturesSubset() - " + m_baseName + " - copying features related to lng:" + leftLng + "<" + rightLng + " lat:" + bottomLat + "<" + topLat + " from " + m_tileFeatures.BaseName); // we are not cloning the lo assuming that lo's belonging to a tile are not reappearing // in any other tile. That also means that we need to cut selection rectangles correctly. foreach (LiveObject lo in m_tileFeatures.List) { if (lo.Location.Lat <= topLat && lo.Location.Lat >= bottomLat && lo.Location.Lng >= leftLng && lo.Location.Lng <= rightLng) { try { //LibSys.StatusBar.WriteLine(" --- " + lo); tileFeatures.Add(lo); } catch (Exception e) { } } } tileFeatures.HasLoaded = true; tileFeatures.IsEmpty = false; } m_tileFeatures = tileFeatures; //LibSys.StatusBar.Trace("OK: Tile::CreateFeaturesSubset() - " + m_baseName + " result: " + m_tileFeatures); //TileCache.ListFeaturesCache(); }
public static event DownloadProgressHandler ProgressCallback; // needed for WebDownload, stays empty here public static void setMappingCacheLocation(string path) { Project.setMappingCacheLocation(path); m_mapsPath = Project.GetMapsTempPath(); TileCache.Clear(); // release all files TerraserverCache.setMappingCacheLocation(); }
public void Dispose() { //LibSys.StatusBar.Trace("TileTerra:Dispose() baseName=" + m_baseName); if (m_tileBackdrop != null) { TileCache.BackdropMarkUnused(m_baseName); m_tileBackdrop = null; } }
public void backdropArrived(Backdrop backdrop) { // the backdrop may arrive when this tile has been phased out due to TileSet.ReTile() // this tile then hangs around as a means to pass backdrop to TileSet, which is supposed // to find appropriate location for the backdrop. #if DEBUG LibSys.StatusBar.Trace("Tile::backdropArrived() - backdrop=" + backdrop); #endif m_tileBackdrop = backdrop; if (m_tileBackdrop.IsEmpty) { // more likely, need to use substitute is discovered here. if (MayUseSubstitute && !UseSubstitute) { // get substitute backdrop: m_useSubstitute = true; #if DEBUG LibSys.StatusBar.Trace("Tile::backdropArrived() - requesting substitute " + m_substituteName); #endif m_tileBackdrop = TileCache.getBackdrop(this, m_substituteName); // may be Empty, never null if (m_tileBackdrop.IsEmpty) { #if DEBUG LibSys.StatusBar.Trace("Tile::backdropArrived() - got empty substitute " + m_substituteName); #endif m_isEmpty = true; } else if (m_tileBackdrop.HasImage) { #if DEBUG LibSys.StatusBar.Trace("Tile::backdropArrived() - got good substitute " + m_tileBackdrop); #endif CalculateSubstituteRectangle(); // may instead set IsEmpty } else { #if DEBUG LibSys.StatusBar.Trace("Tile::backdropArrived() - will wait for substitute "); #endif return; // waiting for substitute backdrop image to arrive } } else { m_isEmpty = true; } } else if (UseSubstitute && m_tileBackdrop.HasImage) { CalculateSubstituteRectangle(); // may instead set IsEmpty } m_tileSet.tileBackdropArrived(this); }
public void featuresArrived(Features features) { // the Features may arrive when this tile has been phased out due to TileSet.ReTile() // this tile then hangs around as a means to pass Features to TileSet, which is supposed // to find appropriate location for the Features. #if DEBUG LibSys.StatusBar.Trace("featuresArrived() - features=" + features); #endif m_tileFeatures = features; if (m_tileFeatures.IsEmpty) { // more likely, need to use substitute is discovered here. if (MayUseSubstitute) { // get substitute features: #if DEBUG LibSys.StatusBar.Trace("Tile::featuresArrived() - requesting substitute " + m_substituteName); #endif m_tileFeatures = TileCache.getFeatures(this, m_substituteName); // may be Empty, never null if (m_tileFeatures.IsEmpty) { #if DEBUG LibSys.StatusBar.Trace("Tile::featuresArrived() - got empty substitute " + m_substituteName); #endif } else { #if DEBUG LibSys.StatusBar.Trace("Tile::featuresArrived() - copying relevant features"); #endif CreateFeaturesSubset(); ProvokeFeaturesPutOnMap(); // provoke PutOnMap on the next Tile_Paint() } } } else { ProvokeFeaturesPutOnMap(); // provoke PutOnMap on the next Tile_Paint() } m_tileSet.tileFeaturesArrived(this); }
private void ReTile() { //LibSys.StatusBar.Trace("IP: ReTile() drawableReady=" + Project.drawableReady); if (!Project.drawableReady) // when starting, we get several resize events with different sizes, as // layout settles. We want to ignore these and retile after the first paint. { return; } // what is the picture area in degrees? // use CameraManager.m_coverageXDegrees, m_coverageYDegrees for span in degrees // what is appropriate tile resolution? double cameraHeightKm = (m_cameraManager.Location.Elev) / 1000.0d; // km string tileScale; // each tile scale has it's threshold, after which the next tile scale is used. // the idea is to use the tile while it maps closely to 1:1 in pixels, and when // the mapping requires magnification (i.e. x tile 1200x1200 --> 1300x1300 on the picture), // then use the next level if (cameraHeightKm > 5000.0d) { m_tileResolutionDegreesH = 360.0d; // degrees per tile m_tileResolutionDegreesV = 180.0d; // degrees per tile tileScale = "w"; } else if (cameraHeightKm > 2000.0d) { m_tileResolutionDegreesH = 40.0d; // degrees per tile m_tileResolutionDegreesV = 50.0d; // degrees per tile tileScale = "y"; } //else if(cameraHeightKm > 900.0d) else if (cameraHeightKm > 370.0d) { m_tileResolutionDegreesH = 10.0d; // degrees per tile m_tileResolutionDegreesV = 10.0d; // degrees per tile tileScale = "x"; } /* * else if(cameraHeightKm > 370.0d) * { * m_tileResolutionDegreesH = 4.0d; // degrees per tile * m_tileResolutionDegreesV = 4.0d; // degrees per tile * tileScale = "z"; * } */ else if (cameraHeightKm > 100.0d) { m_tileResolutionDegreesH = 1.0d; // degrees per tile m_tileResolutionDegreesV = 1.0d; // degrees per tile tileScale = ""; } else { m_tileResolutionDegreesH = 0.5d; // degrees per tile m_tileResolutionDegreesV = 0.5d; // degrees per tile tileScale = "a"; } // how many tiles v*h do we need to cover the picture area? GeoCoord topLeftTileCorner = getTopLeftTileCorner(m_cameraManager.CoverageTopLeft, tileScale, m_tileResolutionDegreesH, m_tileResolutionDegreesV); GeoCoord bottomRightTileCorner = getBottomRightTileCorner(m_cameraManager.CoverageBottomRight, tileScale, m_tileResolutionDegreesH, m_tileResolutionDegreesV); #if DEBUG LibSys.StatusBar.Trace("TileSet:ReTile() topLeftTileCorner=" + topLeftTileCorner + " bottomRightTileCorner=" + bottomRightTileCorner); #endif m_hCount = (int)((bottomRightTileCorner.Lng - topLeftTileCorner.Lng) / m_tileResolutionDegreesH); m_vCount = (int)((topLeftTileCorner.Lat - bottomRightTileCorner.Lat) / m_tileResolutionDegreesV); // world tile is replicated, if 180 meridian is in the picture: bool doWorldOffset = false; switch (tileScale) { case "w": if (m_cameraManager.CoverageBottomRight.Lng > 180.0d) { m_hCount++; doWorldOffset = true; } else if (m_cameraManager.CoverageTopLeft.Lng < -180.0d) { topLeftTileCorner.Lng -= 360.0d; // left tile starts there m_hCount++; doWorldOffset = true; } break; } #if DEBUG LibSys.StatusBar.Trace("TileSet:ReTile() m_vCount=" + m_vCount + " m_hCount=" + m_hCount + " doWorldOffset=" + doWorldOffset); #endif // calculate meters per pixel for selected tile scale: m_xMetersPerPixel = m_cameraManager.MetersPerPixelX(); m_yMetersPerPixel = m_cameraManager.MetersPerPixelY(); #if DEBUG LibSys.StatusBar.Trace("TileSet:ReTile() m_xMetersPerPixel=" + m_xMetersPerPixel + " m_yMetersPerPixel=" + m_yMetersPerPixel); LibSys.StatusBar.Trace("TileSet:ReTile() ----------------- before " + TileCache.ToString()); #endif double topLeftLat = topLeftTileCorner.Lat; cleanTiles(); lock (tilesLock) { m_tiles = new Tile[m_vCount, m_hCount]; for (int vv = 0; vv < m_vCount; vv++) { double topLeftLng = topLeftTileCorner.Lng; for (int hh = 0; hh < m_hCount; hh++) { GeoCoord topLeft = new GeoCoord(topLeftLng, topLeftLat, 0.0d); GeoCoord bottomRight = new GeoCoord(topLeftLng + m_tileResolutionDegreesH, topLeftLat - m_tileResolutionDegreesV, 0.0d); m_tiles[vv, hh] = new Tile(this, tileScale, topLeft, bottomRight); m_tiles[vv, hh].init(); switch (tileScale) { case "w": // world tiles use doWorldOffset around 180 meridian: if (doWorldOffset && hh > 0) { int offsetX = m_tiles[vv, hh].getFrameRectangle().Width; m_tiles[vv, hh].Offset = new Point(offsetX, 0); } break; default: m_tiles[vv, hh].Offset = new Point(0, 0); break; } #if DEBUG LibSys.StatusBar.Trace(" hh=" + hh + " ---- offset=" + m_tiles[vv, hh].getOffset()); #endif topLeftLng += m_tileResolutionDegreesH; } topLeftLat -= m_tileResolutionDegreesV; } } // lock #if DEBUG LibSys.StatusBar.Trace("TileSet:ReTile() ----------------- after " + TileCache.ToString()); #endif TileCache.purge(); double safeHeight = ((double)Project.CAMERA_HEIGHT_SAFE) * 1000.0d; if (m_cameraManager.Elev < safeHeight && (!Project.allowUnreasonableZoom && IsAllSubstitutes || IsEmpty)) { // we get here if all tiles are already in cache, and all are empty. LibSys.StatusBar.Trace("TileSet:ReTile() - all tiles empty - repositioning"); m_cameraManager.Elev = safeHeight; } }
private bool m_triedReload = false; // limits reload attempts public void Tile_Paint(object sender, PaintEventArgs e) { //LibSys.StatusBar.Trace("Tile_Paint(): " + m_baseName + " painting to " + e.ClipRectangle); try { Rectangle destRect = getFrameRectangle(); int www = 0; int hhh = 0; //LibSys.StatusBar.Trace("Tile_Paint(): tileImage=" + m_tileBackdrop); if (m_tileBackdrop != null && !m_tileBackdrop.IsEmpty && m_tileBackdrop.HasImage) { //int compensate = 2; //destRect.Inflate(compensate, compensate); //destRect.Offset(-compensate / 2, -compensate / 2); if (UseSubstitute) { int offX = m_substituteRectangle.X; int offY = m_substituteRectangle.Y; www = m_substituteRectangle.Width; hhh = m_substituteRectangle.Height; e.Graphics.DrawImage(m_tileBackdrop.Image, destRect, offX, offY, www, hhh, System.Drawing.GraphicsUnit.Pixel); } else { www = m_tileBackdrop.Width; hhh = m_tileBackdrop.Height; //LibSys.StatusBar.Trace("Tile_Paint(): tileImage w=" + www + " h=" + hhh); // destRect = e.ClipRectangle; e.Graphics.DrawImage(m_tileBackdrop.Image, destRect, 0, 0, www, hhh, System.Drawing.GraphicsUnit.Pixel); } if (Project.drawGrid) { DrawGrid(e.Graphics, destRect, www, hhh, null); } } else { if (m_tileBackdrop != null && m_tileBackdrop.ImageCorrupted) { DrawGrid(e.Graphics, destRect, www, hhh, "BAD JPG"); if (!m_triedReload) { m_triedReload = true; TileCache.resetBackdrop(this, m_baseName); // try reloading } } else { DrawGrid(e.Graphics, destRect, www, hhh, "NOT LOADED"); } } } catch (Exception eee) { LibSys.StatusBar.Error("Tile:Tile_Paint(): " + m_baseName + " " + eee); } }
public void init() { GeoCoord topLeft = m_topLeft.Clone(); topLeft.Normalize(); GeoCoord bottomRight = m_bottomRight.Clone(); bottomRight.Normalize(); int iLat = (int)Math.Ceiling(topLeft.Lat); int iLng = (int)Math.Floor(topLeft.Lng); m_siLng = iLng; m_siLat = iLat; if (m_tileScale.Equals("z")) { // HACK: // compensate for the shift in z-level tiles // (their names point to the center, not the top left corner: iLat -= 2; iLng += 2; } string latDir = iLat < 0 ? "s" : "n"; string lngDir = iLng < 0 ? "w" : "e"; iLat = Math.Abs(iLat); iLng = Math.Abs(iLng); switch (m_tileScale) { case "w": m_level = 0; m_baseName = "world_good"; break; case "y": m_level = 1; if (iLat == 60 && latDir.Equals("s")) { m_tileBackdrop = null; return; } else { string sLng = ("" + iLng).PadLeft(3, '0'); string sLat = "" + iLat; m_baseName = m_tileScale + sLng + lngDir + sLat + latDir; } break; case "x": m_level = 2; m_baseName = m_tileScale + iLng + lngDir + iLat + latDir; break; case "z": m_level = 3; m_baseName = m_tileScale + iLng + lngDir + iLat + latDir; break; default: m_level = 4; iLat = (int)Math.Floor(bottomRight.Lat); iLng = (int)Math.Ceiling(bottomRight.Lng); if (iLng == -180) { // edge correction needed around Lng=180 iLng = 180; } latDir = iLat < 0 ? "s" : "n"; lngDir = iLng <= 0 ? "w" : "e"; m_siLng = iLng; m_siLat = iLat; iLat = Math.Abs(iLat); iLng = Math.Abs(iLng); m_baseName = m_tileScale + iLng + lngDir + iLat + latDir; break; case "a": m_level = 5; iLat = (int)Math.Floor(bottomRight.Lat); iLng = (int)Math.Ceiling(bottomRight.Lng); if (iLng == -180) { // edge correction needed around Lng=180 iLng = 180; } latDir = iLat < 0 ? "s" : "n"; lngDir = iLng <= 0 ? "w" : "e"; m_siLng = iLng; m_siLat = iLat; iLat = Math.Abs(iLat); iLng = Math.Abs(iLng); // figure out quadrant and correct the tile scale letter: double ty = topLeft.Lat - Math.Floor(topLeft.Lat); double tx = topLeft.Lng - Math.Floor(topLeft.Lng); if (ty > 0.01d && tx > 0.01d) { m_tileScale = "d"; m_aShiftX = 1; m_aShiftY = 1; } else if (tx > 0.01d) { m_tileScale = "b"; m_aShiftX = 1; } else if (ty > 0.01d) { m_tileScale = "c"; m_aShiftY = 1; } m_baseName = m_tileScale + iLng + lngDir + iLat + latDir; break; } if (MayUseSubstitute) { // calculate substitute backdrop parameters, just in case real backdrop will be missing: int substLat = (int)Math.Floor(bottomRight.Lat); if (substLat >= 0) { substLat = substLat / 10 + 1; } else if (substLat < 0 && substLat >= -10) { substLat = 0; latDir = "n"; } else { substLat = (int)Math.Ceiling(bottomRight.Lat + 0.0001d); substLat = substLat / 10; } substLat = substLat * 10; int substLng = (int)Math.Ceiling(bottomRight.Lng); if (substLng > 0) { substLng = (int)Math.Floor(topLeft.Lng); substLng = substLng / 10; } else if (substLng == 0) { // edge correction needed around Lng=0 substLng = 1; } else if (substLng == -180) { // edge correction needed around Lng=180 substLng = 17; } else { substLng = substLng / 10 - 1; } substLng = substLng * 10; m_substLng = substLng; m_substLat = substLat; substLat = Math.Abs(substLat); substLng = Math.Abs(substLng); m_substituteName = "x" + substLng + lngDir + substLat + latDir; #if DEBUG LibSys.StatusBar.Trace("Tile::init() m_substituteName=" + m_substituteName); LibSys.StatusBar.Trace("siLng=" + m_siLng + " m_substLng=" + m_substLng + " siLat=" + m_siLat + " m_substLat=" + m_substLat); #endif } //LibSys.StatusBar.Trace("Tile:init() baseName=" + m_baseName); m_tileBackdrop = TileCache.getBackdrop(this, m_baseName); // may be Empty, never null if (m_tileBackdrop.IsEmpty) { // unlikely, but we may know immediately that we need to use substitute, if feasible: if (MayUseSubstitute) { // get substitute backdrop: m_useSubstitute = true; //LibSys.StatusBar.Trace("Tile::init() - requesting backdrop substitute " + m_substituteName); m_tileBackdrop = TileCache.getBackdrop(this, m_substituteName); // may be Empty, never null if (m_tileBackdrop.IsEmpty) { m_isEmpty = true; } else if (m_tileBackdrop.HasImage) { CalculateSubstituteRectangle(); // may instead set IsEmpty } // else wait for arrival... } else { m_isEmpty = true; } } m_tileFeatures = TileCache.getFeatures(this, m_baseName); // may be Empty, never null if (m_tileFeatures.IsEmpty) { // unlikely, but we may know immediately that we need to use substitute, if feasible: if (MayUseSubstitute) { // get substitute features: #if DEBUG LibSys.StatusBar.Trace("Tile::init() - requesting features substitute " + m_substituteName); #endif m_tileFeatures = TileCache.getFeatures(this, m_substituteName); // may be Empty, never null if (m_tileFeatures.HasLoaded) { CreateFeaturesSubset(); ProvokeFeaturesPutOnMap(); // provoke PutOnMap on the next Tile_Paint() } else { #if DEBUG LibSys.StatusBar.Trace("Tile::init() - " + m_baseName + " - features hasn't loaded - nothing to copy..."); #endif } // wait for arrival... } } else { ProvokeFeaturesPutOnMap(); // provoke PutOnMap on the next Tile_Paint() } }