/// <summary> /// Triggers rendering. /// </summary> public void TriggerRendering(bool force) { if (this.SurfaceWidth == 0) { // nothing to render yet! return; } // create the view that would be use for rendering. View2D view = _cacheRenderer.Create((int)(this.SurfaceWidth * _extra), (int)(this.SurfaceHeight * _extra), this.Map, (float)this.Map.Projection.ToZoomFactor(this.MapZoom), this.MapCenter, _invertX, _invertY, this.MapTilt); // ... and compare to the previous rendered view. if (!force && _previouslyRenderedView != null && view.Equals(_previouslyRenderedView)) { return; } _previouslyRenderedView = view; // end existing rendering thread. if (_renderingThread != null && _renderingThread.IsAlive) { if (_cacheRenderer.IsRunning) { this.Map.ViewChangedCancel(); _cacheRenderer.CancelAndWait(); } } // start new rendering thread. _renderingThread = new Thread(new ThreadStart(Render)); _renderingThread.Start(); }
/// <summary> /// Notifies change /// </summary> internal void TriggerRendering() { if (_rect.Width == 0) { return; } if (Monitor.TryEnter(_cacheRenderer, 1000)) { // entered the exclusive lock area. try { // create the view that would be use for rendering. float size = System.Math.Max(_rect.Width, _rect.Height); View2D view = _cacheRenderer.Create((int)(size * _extra), (int)(size * _extra), this.Map, (float)this.Map.Projection.ToZoomFactor(this.MapZoom), this.MapCenter, _invertX, _invertY, this.MapTilt); // ... and compare to the previous rendered view. if (_previouslyRenderedView != null && view.Equals(_previouslyRenderedView)) { _listener.NotifyRenderSuccess(view, this.MapZoom, 0); return; } _previouslyRenderedView = view; // end existing rendering thread. if (_renderingThread != null && _renderingThread.IsAlive) { if (_cacheRenderer.IsRunning) { _cacheRenderer.CancelAndWait(); } } // start new rendering thread. _renderingThread = new Thread(new ThreadStart(Render)); _renderingThread.Start(); } finally { Monitor.Exit(_cacheRenderer); } } }
/// <summary> /// Notifies change /// </summary> /// <param name="touch">If set to <c>true</c> change was trigger by touch.</param> internal void Change(bool touch) { if (_rect.Width == 0) { return; } lock (_cacheRenderer) { // create the view that would be use for rendering. View2D view = _cacheRenderer.Create((int)(_rect.Width * _extra), (int)(_rect.Height * _extra), this.Map, (float)this.Map.Projection.ToZoomFactor(this.MapZoom), this.MapCenter, _invertX, _invertY, this.MapTilt); // ... and compare to the previous rendered view. if (_previousRenderedZoom != null && view.Equals(_previousRenderedZoom)) { return; } _previousRenderedZoom = view; // end existing rendering thread. if (_renderingThread != null && _renderingThread.IsAlive) { if (_cacheRenderer.IsRunning) { _cacheRenderer.CancelAndWait(); } _renderingThread.Abort(); } // start new rendering thread. _renderingThread = new Thread(new ThreadStart(Render)); _renderingThread.Start(); // raise touched event. if (touch) { this.RaiseMapTouched(); } } }
/// <summary> /// Triggers rendering. /// </summary> public void TriggerRendering(bool force) { try { if (this.SurfaceWidth == 0) { // nothing to render yet! return; } // create the view that would be use for rendering. View2D view = _cacheRenderer.Create((int)(this.SurfaceWidth * _extra), (int)(this.SurfaceHeight * _extra), this.Map, (float)this.Map.Projection.ToZoomFactor(this.MapZoom), this.MapCenter, _invertX, _invertY, this.MapTilt); // ... and compare to the previous rendered view. if (!force && _previouslyRenderedView != null && view.Equals(_previouslyRenderedView)) { return; } _previouslyRenderedView = view; // end existing rendering thread. if (_renderingThread != null && _renderingThread.IsAlive) { if (_cacheRenderer.IsRunning) { this.Map.ViewChangedCancel(); _cacheRenderer.CancelAndWait(); } } // start new rendering thread. _renderingThread = new Thread(new ThreadStart(Render)); _renderingThread.Start(); } catch (Exception ex) { OsmSharp.Logging.Log.TraceEvent("MapViewSurface", TraceEventType.Critical, string.Format("An unhandled exception occured:{0}", ex.ToString())); } }
/// <summary> /// Renders the current complete scene. /// </summary> private void Render() { try { if (_renderingSuspended) { // no rendering when rendering is suspended. return; } if (_cacheRenderer.IsRunning) { // cancel previous render. _cacheRenderer.CancelAndWait(); } // make sure only on thread at the same time is using the renderer. lock (_cacheRenderer) { this.Map.ViewChangedCancel(); // build the layers list. var layers = new List <Layer>(); for (int layerIdx = 0; layerIdx < this.Map.LayerCount; layerIdx++) { // get the layer. if (this.Map[layerIdx].IsVisible) { layers.Add(this.Map[layerIdx]); } } // add the internal layers. layers.Add(_makerLayer); if (this.SurfaceHeight == 0) { // the surface has no height yet. Impossible to render like this. return; } // get old image if available. NativeImage image = null; if (_offScreenBuffer != null) { // get the native image from the off-screen buffer. image = _offScreenBuffer.NativeImage as NativeImage; } // resize image if needed. float sizeX = this.SurfaceWidth; float sizeY = this.SurfaceHeight; //if(this.MapAllowTilt) //{ // when rotation is allowed make sure a square is rendered. // sizeX = System.Math.Max(this.SurfaceWidth, this.SurfaceHeight); // sizeY = System.Math.Max(this.SurfaceWidth, this.SurfaceHeight); //} // float size = System.Math.Max(this.SurfaceHeight, this.SurfaceWidth); if (image == null || image.Image.Width != (int)(sizeX * _extra) || image.Image.Height != (int)(sizeY * _extra)) { // create a bitmap and render there. if (image != null) { // make sure to dispose the old image. image.Dispose(); } image = new NativeImage(global::Android.Graphics.Bitmap.CreateBitmap((int)(sizeX * _extra), (int)(sizeY * _extra), global::Android.Graphics.Bitmap.Config.Argb8888)); } // create and reset the canvas. using (var canvas = new global::Android.Graphics.Canvas(image.Image)) { canvas.DrawColor(new global::Android.Graphics.Color( SimpleColor.FromKnownColor(KnownColor.White).Value)); // create the view. double[] sceneCenter = this.Map.Projection.ToPixel(this.MapCenter.Latitude, this.MapCenter.Longitude); float mapZoom = this.MapZoom; float sceneZoomFactor = (float)this.Map.Projection.ToZoomFactor(this.MapZoom); // create the view for this control. float scaledNormalWidth = image.Image.Width / _bufferFactor; float scaledNormalHeight = image.Image.Height / _bufferFactor; var view = View2D.CreateFrom((float)sceneCenter[0], (float)sceneCenter[1], scaledNormalWidth * _extra, scaledNormalHeight * _extra, sceneZoomFactor, _invertX, _invertY, this.MapTilt); long before = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", TraceEventType.Information, "Rendering Start"); // notify the map that the view has changed. if (_previouslyChangedView == null || !_previouslyChangedView.Equals(view)) { // report change once! var normalView = View2D.CreateFrom((float)sceneCenter[0], (float)sceneCenter[1], scaledNormalWidth, scaledNormalHeight, sceneZoomFactor, _invertX, _invertY, this.MapTilt); this.Map.ViewChanged((float)this.Map.Projection.ToZoomFactor(this.MapZoom), this.MapCenter, normalView, view); _previouslyChangedView = view; long afterViewChanged = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", TraceEventType.Information, "View change took: {0}ms @ zoom level {1}", (new TimeSpan(afterViewChanged - before).TotalMilliseconds), this.MapZoom); } // does the rendering. bool complete = _cacheRenderer.Render(canvas, layers, view, (float)this.Map.Projection.ToZoomFactor(this.MapZoom)); long afterRendering = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", TraceEventType.Information, "Rendering took: {0}ms @ zoom level {1} and {2}", (new TimeSpan(afterRendering - before).TotalMilliseconds), this.MapZoom, this.MapCenter); if (complete) { // there was no cancellation, the rendering completely finished. // add the result to the scene cache. // add the newly rendered image again. if (_offScreenBuffer == null) { // create the offscreen buffer first. _offScreenBuffer = new ImageTilted2D(view.Rectangle, image, float.MinValue, float.MaxValue); } else { // augment the previous buffer. _offScreenBuffer.Bounds = view.Rectangle; _offScreenBuffer.NativeImage = image; } var temp = _onScreenBuffer; _onScreenBuffer = _offScreenBuffer; _offScreenBuffer = temp; } long after = DateTime.Now.Ticks; if (complete) { // report a successful render to listener. _listener.NotifyRenderSuccess(view, mapZoom, (int)new TimeSpan(after - before).TotalMilliseconds); } } } // notify the the current surface of the new rendering. this.PostInvalidate(); } catch (Exception ex) { // exceptions can be thrown when the mapview is disposed while rendering. // don't worry too much about these, the mapview is garbage anyway. OsmSharp.Logging.Log.TraceEvent("MapViewSurface", TraceEventType.Critical, string.Format("An unhandled exception occured:{0}", ex.ToString())); } }
/// <summary> /// Render the current complete scene. /// </summary> void Render() { try { RectangleF rect = _rect; lock (this.Map) { //lock (_cacheRenderer) { // make sure only on thread at the same time is using the renderer. // create the view. View2D view = _cacheRenderer.Create((int)(rect.Width * _extra), (int)(rect.Height * _extra), this.Map, (float)this.Map.Projection.ToZoomFactor(this.MapZoom), this.MapCenter, _invertX, _invertY, this.MapTilt); if (view.Equals(_previousRenderedZoom)) { return; } if (rect.Width == 0) // only render if a proper size is known. { return; } OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", System.Diagnostics.TraceEventType.Information, "Before lock."); long before = DateTime.Now.Ticks; // OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", System.Diagnostics.TraceEventType.Information, // "Rendering Start"); // build the layers list. var layers = new List <ILayer> (); for (int layerIdx = 0; layerIdx < this.Map.LayerCount; layerIdx++) { layers.Add(this.Map [layerIdx]); } // add the internal layer. // TODO: create marker layer. int imageWidth = (int)(rect.Width * _extra * _scaleFactor); int imageHeight = (int)(rect.Height * _extra * _scaleFactor); // create a new bitmap context. CGColorSpace space = CGColorSpace.CreateDeviceRGB(); int bytesPerPixel = 4; int bytesPerRow = bytesPerPixel * imageWidth; int bitsPerComponent = 8; if (_bytescache == null) { _bytescache = new byte[bytesPerRow * imageHeight]; } CGBitmapContext gctx = new CGBitmapContext(null, imageWidth, imageHeight, bitsPerComponent, bytesPerRow, space, // kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast CGBitmapFlags.PremultipliedFirst | CGBitmapFlags.ByteOrder32Big); // notify the map that the view has changed. this.Map.ViewChanged((float)this.Map.Projection.ToZoomFactor(this.MapZoom), this.MapCenter, view); long afterViewChanged = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", System.Diagnostics.TraceEventType.Information, "View change took: {0}ms @ zoom level {1}", (new TimeSpan(afterViewChanged - before).TotalMilliseconds), this.MapZoom); // does the rendering. bool complete = _cacheRenderer.Render(new CGContextWrapper(gctx, new RectangleF(0, 0, (int)(rect.Width * _extra), (int)(rect.Height * _extra))), layers, view); long afterRendering = DateTime.Now.Ticks; OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", System.Diagnostics.TraceEventType.Information, "Rendering took: {0}ms @ zoom level {1}", (new TimeSpan(afterRendering - afterViewChanged).TotalMilliseconds), this.MapZoom); if (complete) // there was no cancellation, the rendering completely finished. // add the result to the scene cache. { lock (_cachedScene) { // add the newly rendered image again. _cachedScene.Clear(); _cachedScene.AddImage(0, float.MinValue, float.MaxValue, view.Rectangle, new byte[0], gctx.ToImage()); } this.InvokeOnMainThread(InvalidateMap); // store the previous view. _previousRenderedZoom = view; } long after = DateTime.Now.Ticks; // if (!complete) { // OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", System.Diagnostics.TraceEventType.Information,"Rendering CANCELLED!", // new TimeSpan (after - before).TotalMilliseconds); // } else { OsmSharp.Logging.Log.TraceEvent("OsmSharp.Android.UI.MapView", System.Diagnostics.TraceEventType.Information, "Rendering in {0}ms", new TimeSpan(after - before).TotalMilliseconds); // } //} } } catch (Exception ex) { _cacheRenderer.Reset(); } }