我正在制作一個包含 400 多個節點的圖表并嘗試繪制它們。節點是城市的代表,所以我把它們的經度和緯度設定為 X 和 Y。問題是這些城市來自一個縣,所以它們的經度和緯度彼此非常接近,所以即使我做了 X 和Y 大 10 倍,它們仍然彼此靠近。唯一的事情是將“解析度”提高到 100 倍,但隨后它們將不可見,因為值會上升到 5000px
我的問題是:我可以縮放面板以顯示所有內容,即使它有 5000 像素大?或者也許有一種方法可以縮放經度和緯度,這樣它們的間距會更大,但仍然類似于城市的現實生活布局?謝謝你
uj5u.com熱心網友回復:
給定一組點,為 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 的標準化點值,然后乘以相應的視口大小值(寬度和高度)。
var normalizedX = (point.X - minMaxX.X) / (minMaxX.Y - minMaxX.X);
var normalizedY = (point.Y - minMaxY.X) / (minMaxY.Y - minMaxY.X);
var posX = (int)(normalizedX * viewportWidth);
var posY = (int)(normalizedY * viewportHeight);
The above does not take into account the aspect ratio of the original points' rectangle, so your results will likely be squished. This can be solved using letter boxing or pillar boxing, depending on the width/height of the points rectangle compared to the viewport rectangle.
uj5u.com熱心網友回復:
I think this is what you want:

and the code that goes with it.
The arbitrary city coordinates shown are
74.2344f, 25.3134f
41.4388f, -12.158f
58.8734f, 32.3634f
22.8486f, 7.678f
83.8304f, 12.3733f
which get mapped into pixels based on the size of the panel in the Project() method.
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;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/422379.html
標籤:
下一篇:懸停在X上時X或工具提示的句柄
