Beispiel #1
0
        /// <summary>
        /// Creates a node and either splits the objects recursively into sub-nodes, or stores them at the node depending on the heuristics.
        /// Tree is built top->down
        /// </summary>
        /// <param name="objList">Geometries to index</param>
        /// <param name="depth">Current depth of tree</param>
        /// <param name="heurdata">Heuristics data</param>
        public QuadTree(List <BoxObjects> objList, uint depth, Heuristic heurdata)
        {
            _depth = depth;

            _box = objList[0].Box;
            for (var i = 0; i < objList.Count; i++)
            {
                _box = _box.Join(objList[i].Box);
            }

            // test our build heuristic - if passes, make children
            if (depth < heurdata.Maxdepth && objList.Count > heurdata.Mintricnt &&
                (objList.Count > heurdata.Tartricnt || ErrorMetric(_box) > heurdata.Minerror))
            {
                var objBuckets = new List <BoxObjects> [2]; // buckets of geometries
                objBuckets[0] = new List <BoxObjects>();
                objBuckets[1] = new List <BoxObjects>();

                var    useXAxis   = _box.Width > _box.Height; // longest axis
                double geoAverage = 0;                        // geometric average - midpoint of ALL the objects

                // go through all bbox and calculate the average of the midpoints
                double fraction = 1.0f / objList.Count;
                for (var i = 0; i < objList.Count; i++)
                {
                    var centroid = useXAxis ? objList[i].Box.Centroid.X : objList[i].Box.Centroid.Y;
                    geoAverage += centroid * fraction;
                }

                // bucket bbox based on their midpoint's side of the geo average in the longest axis
                for (var i = 0; i < objList.Count; i++)
                {
                    var centroid = useXAxis ? objList[i].Box.Centroid.X : objList[i].Box.Centroid.Y;
                    objBuckets[geoAverage > centroid ? 1 : 0].Add(objList[i]);
                }

                //If objects couldn't be split, just store them at the leaf
                //TODO: Try splitting on another axis
                if (objBuckets[0].Count == 0 || objBuckets[1].Count == 0)
                {
                    _child0 = null;
                    _child1 = null;
                    // copy object list
                    _objList = objList;
                }
                else
                {
                    // create new children using the buckets
                    _child0 = new QuadTree(objBuckets[0], depth + 1, heurdata);
                    _child1 = new QuadTree(objBuckets[1], depth + 1, heurdata);
                }
            }
            else
            {
                // otherwise the build heuristic failed, this is
                // set the first child to null (identifies a leaf)
                _child0 = null;
                _child1 = null;
                // copy object list
                _objList = objList;
            }
        }
Beispiel #2
0
        public void Draw(SKCanvas canvas, IReadOnlyViewport viewport, IWidget widget,
                         float layerOpacity)
        {
            var scaleBar = (ScaleBarWidget)widget;

            if (!scaleBar.CanProject())
            {
                return;
            }

            // If this is the first time, we call this renderer, ...
            if (_paintScaleBar == null)
            {
                // ... than create the paints
                _paintScaleBar        = CreateScaleBarPaint(SKPaintStyle.Fill);
                _paintScaleBarStroke  = CreateScaleBarPaint(SKPaintStyle.Stroke);
                _paintScaleText       = CreateTextPaint(SKPaintStyle.Fill);
                _paintScaleTextStroke = CreateTextPaint(SKPaintStyle.Stroke);
            }

            // Update paints with new values
            _paintScaleBar.Color             = scaleBar.TextColor.ToSkia(layerOpacity);
            _paintScaleBar.StrokeWidth       = scaleBar.StrokeWidth * scaleBar.Scale;
            _paintScaleBarStroke !.Color     = scaleBar.Halo.ToSkia(layerOpacity);
            _paintScaleBarStroke.StrokeWidth = scaleBar.StrokeWidthHalo * scaleBar.Scale;
            _paintScaleText !.Color          = scaleBar.TextColor.ToSkia(layerOpacity);
            _paintScaleText.StrokeWidth      = scaleBar.StrokeWidth * scaleBar.Scale;
            _paintScaleText.Typeface         = SKTypeface.FromFamilyName(scaleBar.Font?.FontFamily,
                                                                         SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright);
            _paintScaleText.TextSize          = (float)(scaleBar.Font?.Size ?? 10) * scaleBar.Scale;
            _paintScaleTextStroke !.Color     = scaleBar.Halo.ToSkia(layerOpacity);
            _paintScaleTextStroke.StrokeWidth = scaleBar.StrokeWidthHalo / 2 * scaleBar.Scale;
            _paintScaleTextStroke.Typeface    = SKTypeface.FromFamilyName(scaleBar.Font?.FontFamily,
                                                                          SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright);
            _paintScaleTextStroke.TextSize = (float)(scaleBar.Font?.Size ?? 10) * scaleBar.Scale;

            float  scaleBarLength1;
            string?scaleBarText1;
            float  scaleBarLength2;
            string?scaleBarText2;

            (scaleBarLength1, scaleBarText1, scaleBarLength2, scaleBarText2) = scaleBar.GetScaleBarLengthAndText(viewport);

            // Calc height of scale bar
            var textSize = SKRect.Empty;

            // Do this, because height of text changes sometimes (e.g. from 2 m to 1 m)
            _paintScaleTextStroke.MeasureText("9999 m", ref textSize);

            var scaleBarHeight = textSize.Height + (scaleBar.TickLength + scaleBar.StrokeWidthHalo * 0.5f + scaleBar.TextMargin) * scaleBar.Scale;

            if (scaleBar.ScaleBarMode == ScaleBarMode.Both && scaleBar.SecondaryUnitConverter != null)
            {
                scaleBarHeight *= 2;
            }
            else
            {
                scaleBarHeight += scaleBar.StrokeWidthHalo * 0.5f * scaleBar.Scale;
            }

            scaleBar.Height = scaleBarHeight;

            // Draw lines

            // Get lines for scale bar
            var points = scaleBar.GetScaleBarLinePositions(viewport, scaleBarLength1, scaleBarLength2, scaleBar.StrokeWidthHalo);

            // Draw outline of scale bar
            for (var i = 0; i < points.Count; i += 2)
            {
                canvas.DrawLine((float)points[i].X, (float)points[i].Y, (float)points[i + 1].X, (float)points[i + 1].Y, _paintScaleBarStroke);
            }

            // Draw scale bar
            for (var i = 0; i < points.Count; i += 2)
            {
                canvas.DrawLine((float)points[i].X, (float)points[i].Y, (float)points[i + 1].X, (float)points[i + 1].Y, _paintScaleBar);
            }

            if (!points.Any())
            {
                throw new NotImplementedException($"A {nameof(ScaleBarWidget)} can not be drawn without line positions");
            }

            var envelop = new MRect(points.Select(p => p.MRect));

            envelop = envelop.Grow(scaleBar.StrokeWidthHalo * 0.5f * scaleBar.Scale);

            // Draw text

            // Calc text height
            var textSize1 = SKRect.Empty;
            var textSize2 = SKRect.Empty;

            scaleBarText1 ??= string.Empty;
            _paintScaleTextStroke.MeasureText(scaleBarText1, ref textSize1);

            if (scaleBar.ScaleBarMode == ScaleBarMode.Both && scaleBar.SecondaryUnitConverter != null)
            {
                // If there is SecondaryUnitConverter we need to calculate the size before passing it into GetScaleBarTextPositions
                scaleBarText2 ??= string.Empty;
                _paintScaleTextStroke.MeasureText(scaleBarText2, ref textSize2);
            }

            var(posX1, posY1, posX2, posY2) = scaleBar.GetScaleBarTextPositions(viewport, textSize.ToMRect(), textSize1.ToMRect(), textSize2.ToMRect(), scaleBar.StrokeWidthHalo);

            // Now draw text
            canvas.DrawText(scaleBarText1, posX1, posY1 - textSize1.Top, _paintScaleTextStroke);
            canvas.DrawText(scaleBarText1, posX1, posY1 - textSize1.Top, _paintScaleText);

            envelop = envelop?.Join(new MRect(posX1, posY1, posX1 + textSize1.Width, posY1 + textSize1.Height));

            if (scaleBar.ScaleBarMode == ScaleBarMode.Both && scaleBar.SecondaryUnitConverter != null)
            {
                // Now draw second text
                canvas.DrawText(scaleBarText2, posX2, posY2 - textSize2.Top, _paintScaleTextStroke);
                canvas.DrawText(scaleBarText2, posX2, posY2 - textSize2.Top, _paintScaleText);

                envelop = envelop?.Join(new MRect(posX2, posY2, posX2 + textSize2.Width, posY2 + textSize2.Height));
            }

            scaleBar.Envelope = envelop;

            if (scaleBar.ShowEnvelop && envelop != null)
            {
                // Draw a rect around the scale bar for testing
                var tempPaint = _paintScaleTextStroke;
                canvas.DrawRect(new SKRect((float)envelop.MinX, (float)envelop.MinY, (float)envelop.MaxX, (float)envelop.MaxY), tempPaint);
            }
        }