예제 #1
0
        public override void Draw(BoundingBox boundingBox, sbyte zoomLevel, ICanvas canvas, Point topLeftPoint)
        {
            lock (this)
            {
                if (this.latLong == null || this.bitmap == null)
                {
                    return;
                }

                long   mapSize = MercatorProjection.GetMapSize(zoomLevel, this.displayModel.TileSize);
                double pixelX  = MercatorProjection.LongitudeToPixelX(this.latLong.Longitude, mapSize);
                double pixelY  = MercatorProjection.LatitudeToPixelY(this.latLong.Latitude, mapSize);

                int halfBitmapWidth  = this.bitmap.Width / 2;
                int halfBitmapHeight = this.bitmap.Height / 2;

                int left   = (int)(pixelX - topLeftPoint.X - halfBitmapWidth + this.horizontalOffset);
                int top    = (int)(pixelY - topLeftPoint.Y - halfBitmapHeight + this.verticalOffset);
                int right  = left + this.bitmap.Width;
                int bottom = top + this.bitmap.Height;

                Rectangle bitmapRectangle = new Rectangle(left, top, right, bottom);
                Rectangle canvasRectangle = new Rectangle(0, 0, canvas.Width, canvas.Height);
                if (!canvasRectangle.Intersects(bitmapRectangle))
                {
                    return;
                }

                canvas.DrawBitmap(this.bitmap, left, top);
            }
        }
예제 #2
0
 public virtual bool Contains(Point center, Point point)
 {
     lock (this)
     {
         Rectangle r = new Rectangle(center.X - (float)bitmap.Width / 2 + this.horizontalOffset, center.Y - (float)bitmap.Height / 2 + this.verticalOffset, center.X + (float)bitmap.Width / 2 + this.horizontalOffset, center.Y + (float)bitmap.Height / 2 + this.verticalOffset);
         return(r.Contains(point));
     }
 }
예제 #3
0
        /// <summary>
        /// Fills the area outside the specificed rectangle with color.
        /// This method is used to blank out areas that fall outside the map area. </summary>
        /// <param name="color"> the fill color for the outside area </param>
        /// <param name="insideArea"> the inside area on which not to draw </param>
        internal virtual void FillOutsideAreas(int color, Rectangle insideArea)
        {
            if (canvas == null)
            {
                return;
            }

            this.canvas.SetClipDifference((int)insideArea.Left, (int)insideArea.Top, (int)insideArea.Width, (int)insideArea.Height);
            this.canvas.FillColor(color);
            this.canvas.ResetClip();
        }
예제 #4
0
        public override void Draw(BoundingBox boundingBox, sbyte zoomLevel, ICanvas canvas, Point topLeftPoint)
        {
            lock (this)
            {
                if (this.latLong == null || (this.paintStroke == null && this.paintFill == null))
                {
                    return;
                }

                double latitude      = this.latLong.Latitude;
                double longitude     = this.latLong.Longitude;
                long   mapSize       = MercatorProjection.GetMapSize(zoomLevel, displayModel.TileSize);
                int    pixelX        = (int)(MercatorProjection.LongitudeToPixelX(longitude, mapSize) - topLeftPoint.X);
                int    pixelY        = (int)(MercatorProjection.LatitudeToPixelY(latitude, mapSize) - topLeftPoint.Y);
                int    radiusInPixel = GetRadiusInPixels(latitude, zoomLevel);

                Rectangle canvasRectangle = new Rectangle(0, 0, canvas.Width, canvas.Height);
                if (!canvasRectangle.IntersectsCircle(pixelX, pixelY, radiusInPixel))
                {
                    return;
                }

                if (this.paintStroke != null)
                {
                    if (this.keepAligned)
                    {
                        this.paintStroke.SetBitmapShaderShift = topLeftPoint;
                    }
                    canvas.DrawCircle(pixelX, pixelY, radiusInPixel, this.paintStroke);
                }
                if (this.paintFill != null)
                {
                    if (this.keepAligned)
                    {
                        this.paintFill.SetBitmapShaderShift = topLeftPoint;
                    }
                    canvas.DrawCircle(pixelX, pixelY, radiusInPixel, this.paintFill);
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Called when a job needs to be executed.
        /// </summary>
        /// <param name="rendererJob">
        ///            the job that should be executed. </param>
        public virtual ITileBitmap ExecuteJob(RendererJob rendererJob)
        {
            RenderTheme renderTheme;

            try
            {
                // Wait until RenderTheme is ready
                renderTheme = rendererJob.renderThemeFuture.Result;
            }
            catch (Exception e)
            {
                LOGGER.Fatal("Error to retrieve render theme from future", e);
                return(null);
            }

            RenderContext renderContext = null;

            try
            {
                renderContext = new RenderContext(renderTheme, rendererJob, new CanvasRasterer(graphicFactory));

                if (RenderBitmap(renderContext))
                {
                    ITileBitmap bitmap = null;

                    if (this.mapDatabase != null)
                    {
                        MapReadResult mapReadResult = this.mapDatabase.ReadMapData(rendererJob.tile);
                        ProcessReadMapData(renderContext, mapReadResult);
                    }

                    if (!rendererJob.labelsOnly)
                    {
                        bitmap           = this.graphicFactory.CreateTileBitmap(renderContext.rendererJob.tile.TileSize, renderContext.rendererJob.hasAlpha);
                        bitmap.Timestamp = rendererJob.mapDataStore.GetDataTimestamp(renderContext.rendererJob.tile);
                        renderContext.canvasRasterer.CanvasBitmap = bitmap;
                        if (!rendererJob.hasAlpha && rendererJob.displayModel.BackgroundColor != renderContext.renderTheme.MapBackground)
                        {
                            renderContext.canvasRasterer.Fill(renderContext.renderTheme.MapBackground);
                        }
                        renderContext.canvasRasterer.DrawWays(renderContext);
                    }

                    if (renderLabels)
                    {
                        ISet <MapElementContainer> labelsToDraw = ProcessLabels(renderContext);
                        // now draw the ways and the labels
                        renderContext.canvasRasterer.DrawMapElements(labelsToDraw, renderContext.rendererJob.tile);
                    }
                    else
                    {
                        // store elements for this tile in the label cache
                        this.labelStore.StoreMapItems(renderContext.rendererJob.tile, renderContext.labels);
                    }

                    if (!rendererJob.labelsOnly && renderContext.renderTheme.HasMapBackgroundOutside())
                    {
                        // blank out all areas outside of map
                        Rectangle insideArea = this.mapDatabase.BoundingBox.GetPositionRelativeToTile(renderContext.rendererJob.tile);
                        if (!rendererJob.hasAlpha)
                        {
                            renderContext.canvasRasterer.FillOutsideAreas(renderContext.renderTheme.MapBackgroundOutside, insideArea);
                        }
                        else
                        {
                            renderContext.canvasRasterer.FillOutsideAreas(Color.TRANSPARENT, insideArea);
                        }
                    }
                    return(bitmap);
                }
                // outside of map area with background defined:
                return(CreateBackgroundBitmap(renderContext));
            }
            finally
            {
                if (renderContext != null)
                {
                    renderContext.Destroy();
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Finds the segments of a line along which a name can be drawn and then adds WayTextContainers
        /// to the list of drawable items.
        /// </summary>
        /// <param name="tile"> the tile on which the text will be drawn. </param>
        /// <param name="text"> the text to draw </param>
        /// <param name="priority"> priority of the text </param>
        /// <param name="dy"> if 0, then a line  parallel to the coordinates will be calculated first </param>
        /// <param name="fill"> fill paint for text </param>
        /// <param name="stroke"> stroke paint for text </param>
        /// <param name="coordinates"> the list of way coordinates </param>
        /// <param name="currentLabels"> the list of labels to which a new WayTextContainer will be added </param>
        internal static void RenderText(Tile tile, string text, Display display, int priority, float dy, IPaint fill, IPaint stroke, Point[][] coordinates, ICollection <MapElementContainer> currentLabels)
        {
            // Calculate the way name length plus some margin of safety
            int wayNameWidth = (stroke == null) ? fill.GetTextWidth(text) + WAYNAME_SAFETY_MARGIN * 2 : stroke.GetTextWidth(text) + WAYNAME_SAFETY_MARGIN * 2;

            // Compute the tile boundary on which we render the name.
            // We make the tile smaller because otherwise we sometimes write the text beyond the tile boundary
            // (e.g. a road that runs parallel just below a tile boundary)
            double    textHeight   = (stroke == null) ? fill.GetTextHeight(text) : stroke.GetTextHeight(text);
            Rectangle tileBoundary = tile.BoundaryAbsolute.Envelope(-textHeight);

            int skipPixels = 0;

            Point[] c;
            if (dy == 0f)
            {
                c = coordinates[0];
            }
            else
            {
                c = RendererUtils.ParallelPath(coordinates[0], dy);
            }

            // iterate through the segments to find those long enough to draw the way name on them
            for (int i = 1; i < c.Length; ++i)
            {
                LineSegment currentSegment = new LineSegment(c[i - 1], c[i]);
                double      currentLength  = currentSegment.Length();

                skipPixels -= (int)currentLength;

                if (skipPixels > 0)
                {
                    // we should still be skipping pixels, so skip this segment. Note that
                    // this does not guarantee that we skip any certain minimum of pixels,
                    // it is more a rule of thumb.
                    continue;
                }

                if (currentLength < wayNameWidth)
                {
                    // no point trying to clip, the segment is too short anyway
                    continue;
                }

                // clip the current segment to the tile, so that we never overlap tile boundaries
                // with the way name
                LineSegment drawableSegment = currentSegment.ClipToRectangle(tileBoundary);

                if (drawableSegment == null)
                {
                    // this happens if the segment does not intersect the tile
                    continue;
                }

                double segmentLengthInPixel = drawableSegment.Length();
                if (segmentLengthInPixel < wayNameWidth)
                {
                    // not enough space to draw name on this segment
                    continue;
                }

                // now calculate the actually used part of the segment to ensure the bbox of the waytext container
                // is as small as possible. The offset at the beginning/end is to ensure that we are a bit off the center
                // of an intersection (otherwise we have more collisions at the intersection)
                LineSegment actuallyUsedSegment = drawableSegment.SubSegment(WAYNAME_SAFETY_MARGIN, wayNameWidth - WAYNAME_SAFETY_MARGIN);
                // check to prevent inverted way names
                if (actuallyUsedSegment.Start.X <= actuallyUsedSegment.End.X)
                {
                    currentLabels.Add(new WayTextContainer(actuallyUsedSegment.Start, actuallyUsedSegment.End, display, priority, text, fill, stroke, textHeight));
                }
                else
                {
                    currentLabels.Add(new WayTextContainer(actuallyUsedSegment.End, actuallyUsedSegment.Start, display, priority, text, fill, stroke, textHeight));
                }

                skipPixels = wayNameWidth;
            }
        }