Esempio n. 1
0
        /// <summary>
        /// Obtains a new image from this cache.
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public override INativeImage Obtain(byte[] data)
        {
            OsmSharp.Logging.Log.TraceEvent("NativeImageCache",
                                            Logging.TraceEventType.Information, "Bitmap obtain: {0} {1}", _unusedImages.Count, _usedImages.Count);

            lock (_usedImages)
            {     // synchronize access to this cache.
                if (_unusedImages.Count > 0)
                { // there are unused images, first recover one from there.
                    // get unused image and remove.
                    var unusedImage = _unusedImages.First();
                    _unusedImages.Remove(unusedImage);

                    var newNativeImage = global::Android.Graphics.BitmapFactory.DecodeByteArray(data, 0, data.Length, new global::Android.Graphics.BitmapFactory.Options()
                    {
                        InBitmap     = (unusedImage as NativeImage).Image,
                        InSampleSize = 1
                    });

                    // DecodeByteArray could return null: if we assign null to
                    // NativeImage.Image, NativeImage.GetHashCode crashes on a
                    // NullPointerException. So in this case, just roll back
                    // and return null. User code should handle this.
                    if (newNativeImage == null)
                    {
                        // Rollback
                        _unusedImages.Add(unusedImage);
                        return(null);
                    }

                    // change native image and add to used images.
                    (unusedImage as NativeImage).Image = newNativeImage;
                    _usedImages.Add(unusedImage);
                    return(unusedImage);
                }
                else if (_unusedImages.Count + _usedImages.Count < _cacheSize)
                { // there is still space to add a used iamge.
                    var newNativeImage = global::Android.Graphics.BitmapFactory.DecodeByteArray(data, 0, data.Length, new global::Android.Graphics.BitmapFactory.Options()
                    {
                        InSampleSize = 1,
                        InMutable    = true
                    });

                    var usedImage = new NativeImage(newNativeImage);
                    _usedImages.Add(usedImage);
                    return(usedImage);
                }
                else
                { // there are no unused images left and there is no more room.
                    throw new Exception("Cannot get a new image from cache, no image left.");
                }
            }
        }
Esempio n. 2
0
        /// <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.
                        _cacheRenderer.Density = this.MapScaleFactor;
                        bool complete = _cacheRenderer.Render(canvas, _map.Projection, 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()));
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Obtains a new image from this cache.
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public override INativeImage Obtain(byte[] data)
        {
            OsmSharp.Logging.Log.TraceEvent("NativeImageCache",
                Logging.TraceEventType.Information, "Bitmap obtain: {0} {1}", _unusedImages.Count, _usedImages.Count);

            lock (_usedImages)
            { // synchronize access to this cache.
                if (_unusedImages.Count > 0)
                { // there are unused images, first recover one from there.
                    // get unused image and remove.
                    var unusedImage = _unusedImages.First();
                    _unusedImages.Remove(unusedImage);

                    var newNativeImage = global::Android.Graphics.BitmapFactory.DecodeByteArray(data, 0, data.Length, new global::Android.Graphics.BitmapFactory.Options()
                    {
                        InBitmap = (unusedImage as NativeImage).Image,
                        InSampleSize = 1
                    });

                    // DecodeByteArray could return null: if we assign null to
                    // NativeImage.Image, NativeImage.GetHashCode crashes on a
                    // NullPointerException. So in this case, just roll back
                    // and return null. User code should handle this.
                    if (newNativeImage == null)
                    {
                        // Rollback
                        _unusedImages.Add(unusedImage);
                        return null;
                    }

                    // change native image and add to used images.
                    (unusedImage as NativeImage).Image = newNativeImage;
                    _usedImages.Add(unusedImage);
                    return unusedImage;
                }
                else if (_unusedImages.Count + _usedImages.Count < _cacheSize)
                { // there is still space to add a used iamge.
                    var newNativeImage = global::Android.Graphics.BitmapFactory.DecodeByteArray(data, 0, data.Length, new global::Android.Graphics.BitmapFactory.Options()
                    {
                        InSampleSize = 1,
                        InMutable = true
                    });

                    var usedImage = new NativeImage(newNativeImage);
                    _usedImages.Add(usedImage);
                    return usedImage;
                }
                else
                { // there are no unused images left and there is no more room.
                    throw new Exception("Cannot get a new image from cache, no image left.");
                }
            }
        }