簡體   English   中英

如何在 C# 中縮放面板

[英]How to scale panel in C#

我正在制作一個包含 400 多個節點的圖表並嘗試繪制它們。 節點是城市的代表,所以我把它們的經度和緯度設置為 X 和 Y。問題是這些城市來自一個縣,所以它們的經度和緯度彼此非常接近,所以即使我做了 X 和Y 大 10 倍,它們仍然彼此靠近。 唯一的事情是將“分辨率”提高到 100 倍,但隨后它們將不可見,因為值會上升到 5000px

我的問題是:我可以縮放面板以顯示所有內容,即使它有 5000 像素大? 或者也許有一種方法可以縮放經度和緯度,這樣它們的間距會更大,但仍然類似於城市的現實生活布局? 謝謝你

給定一組點,為 X 取最小值和最大值,為 Y 取最小值和最大值

var minMaxX = new PointF(
    points.Min(point => point.X), 
    points.Max(point => point.X)
);
var minMaxY = new PointF(
    points.Min(point => point.Y), 
    points.Max(point => point.Y)
);

接下來,您需要計算 X 和 Y 的標量值,其中寬度和高度是視口的大小。

scalarX = (minMaxX.Y - minMaxX.X) * width;
scalarY = (minMaxY.Y - minMaxY.X) * height;

然后循環遍歷每個點並將 point.x 乘以標量 x 和 point.y 乘以標量 y。

var posX = (int)(point.X * scalarX);
var posY = (int)(point.Y * scalarY);

以上沒有考慮原始點矩形的縱橫比,因此您的結果可能會被擠壓。 這可以使用信箱或柱箱解決,具體取決於點矩形與視口矩形相比的寬度/高度。

我認為這就是你想要的:

scr1

以及隨之而來的代碼。

顯示的任意城市坐標是

74.2344f, 25.3134f
41.4388f, -12.158f
58.8734f, 32.3634f
22.8486f, 7.678f 
83.8304f, 12.3733f

根據Project()方法中面板的大小將其映射為像素。

public readonly struct City
{
    public City(float longitude, float latitude, float size) : this()
    {
        Longitude=longitude;
        Latitude=latitude;
        Size=size;
    }

    public float Longitude { get; }
    public float Latitude { get; }
    public float Size { get; }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Cities = new List<City>();
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        pictureBox1.Paint += (s, ev) =>
        {
            ev.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            using (var fill = new SolidBrush(Color.Black))
            {
                // Draw cities as dots of various sizes.
                var cities = Cities.ToArray();
                var points = Project(cities, pictureBox1, out var scale);
                for (int i = 0; i < points.Length; i++)
                {
                    float r = Math.Max(1, scale * cities[i].Size);
                    ev.Graphics.FillEllipse(fill, points[i].X-r, points[i].Y-r, 2*r, 2*r);

                    ev.Graphics.DrawString($"City {i+1}", SystemFonts.CaptionFont, Brushes.Blue, points[i].X-2*r, points[i].Y+2*r);
                }

                // Draw a bounding box to check math is correct.
                using (var pen = new Pen(Color.LightGray,0))
                {
                    pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                    var bounds = GetBounds(cities);
                    var box = Project(
                        new City[] {
                        new City(bounds.Left, bounds.Top,0),
                        new City(bounds.Right, bounds.Top,0),
                        new City(bounds.Right, bounds.Bottom,0),
                        new City(bounds.Left, bounds.Bottom,0) }, pictureBox1, out scale);
                    ev.Graphics.DrawPolygon(pen, box);
                }
            }
        };

        pictureBox1.Resize += (s, ev) =>
        {
            pictureBox1.Invalidate();
        };

        Cities.Add(new City(74.2344f, 25.3134f, 0.2f));
        Cities.Add(new City(41.4388f, -12.158f, 0.25f));
        Cities.Add(new City(58.8734f, 32.3634f, 0.12f));
        Cities.Add(new City(22.8486f, 7.678f, 0.25f));
        Cities.Add(new City(83.8304f, 12.3733f, 0.07f));
    }

    public List<City> Cities { get; }

    public RectangleF GetBounds(City[] map)
    {
        RectangleF bounds = new RectangleF(map[0].Longitude, map[0].Latitude, 0, 0);
        for (int i = 1; i < map.Length; i++)
        {
            bounds.X = Math.Min(bounds.X, map[i].Longitude);
            bounds.Width = Math.Max(bounds.Width, map[i].Longitude-bounds.X);
            bounds.Y = Math.Min(bounds.Y, map[i].Latitude);
            bounds.Height = Math.Max(bounds.Height, map[i].Latitude-bounds.Y);
        }
        return bounds;
    }

    public PointF[] Project(City[] map, Control target, out float scale)
    {
        // Find the bounds of the map
        var bounds = GetBounds(map);

        // Find the scaling between pixels and map distances
        int margin = 32;
        int wt = target.ClientSize.Width, ht = target.ClientSize.Height;
        scale = Math.Min(
            (wt-2*margin)/bounds.Width,
            (ht-2*margin)/bounds.Height);

        // Minimum 1 pixel per unit (to avoid negative scales etc)
        scale = Math.Max(1, scale);

        // Convert map to pixels starting from the center
        // of the target control.
        PointF[] pixels = new PointF[map.Length];
        for (int i = 0; i < pixels.Length; i++)
        {
            pixels[i] = new PointF(
                wt/2 + scale * (map[i].Longitude - bounds.X - bounds.Width/2),
                ht/2 - scale * (map[i].Latitude - bounds.Y - bounds.Height/2));
        }

        return pixels;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM