这个问题有几个部分。1)如何将世界坐标缩放到屏幕坐标。2)如何加载形状数据,3)如何将数据绘制到屏幕上。
数据转换信息来自 Buro Tshaggelar 的文章(http://www.ibrtses.com/delphi/dmcs.html)。他讨论了如何进行数据转换。
Tpaintbox 或 Timage 左上角的 x, y 坐标为 0, 0 。它们必须是整数值。您可以通过相对于偏移值进行缩放从世界坐标转换为屏幕坐标或从屏幕坐标转换为世界坐标。
您可以将形状绘制到 Tpaintbox 或 TImage Canvas。如果绘制到 Tpaintbox,则结果不是持久的。
我建议您使用一组 Tpoint 来绘制您的形状,而不是绘制单独的线条来创建您的形状。以下适用于 XE2 VCL。
第1部分
当 World 坐标为十进制值时,坐标由坐标为 xLowvalue、xHighValue 和 yLowVaue 和 yHighValue 的框包围,屏幕窗口可以定义为 tlx..brx、tly..bry,其中坐标为整数值。
以下函数在世界坐标和屏幕坐标之间进行转换。Andreas 的转换也有效。我喜欢它们,它们同时转换坐标对更有效。我更喜欢下面的转换来描述这个过程。
从世界坐标转换为屏幕坐标:
函数 mapW2SxLin(xf:double):integer; 开始结果:= round(tlx + (xf - xlow) * (brx - tlx) / (xhigh - xlow)); 结尾;
函数 mapW2SyLin(yf:double):integer; 开始结果:= round(bry - (yf - ylow) * (bry - tly) / (yhigh - ylow)); 结尾;
从屏幕坐标转换为世界坐标:
函数 mapS2WxLin(xs:integer):double; 开始结果:= xlow +(xs - tlx) * (xhigh - xlow )/ (brx - tlx); 结尾;
函数 mapS2WyLin(ys:integer):double; 开始结果:= yhigh - (ys - tly) * (yhigh - ylow) / (bry - tly); 结尾;
在 ikathygreat 提供的示例中,所需的转换似乎是从笛卡尔坐标到屏幕坐标数据(提供的值似乎是纬度和经度位置对,以十进制纬度和经度值表示)。
第 2 部分
不是加载数据文件,而是在此处对数据进行硬编码。Goodle 用于从文件中填充 tpoint 数组, 用于加载 xy 动态数组的示例。有一些代码可以让您从文本文件中加载数据。请注意,当您加载数据时,您必须提供代码来更改 SetLength 中数组 (6) 的大小(当前编码为 Setlength(xy, 6); )并将数组的大小设置为 6。如何要做到这一点应该是另一个问题。该值将根据形状中的顶点数而变化。
第 3 部分
使用 Tpoint 数组绘制形状。所要求但未使用请求者方法的内容。绘制单独的线对于绘制形状的代码来说有点尴尬。我相信下面的示例是一个更简单的解决方案并且可以完成工作。
使用以下方法设置您的绘制框,其边界反映世界坐标的最大限制:
xLow := -88; // 提供的最东经度 xHigh:= -100; // 提供的最西经度 yLow:= 37; // 提供的最高纬度 yHigh:= 32; // 提供的最低纬度
我建议将全局变量定义为:
var xLow,xHigh,yLow,yHigh:double; tlx,brx,tly,bry:整数;
xy:TPoint 数组;
要使用数组绘制形状,您需要定义一个类型
类型 TMyPolygon = TPoint 数组;// 一个动态数组
并在您的 OnCreate 表单事件处理程序上分配这些值:
brx:=Paintbox1.Left; tlx:=Paintbox1.Left + paintbox1.Width ; bry:= Paintbox1.Top; tly :=Paintbox1.Top + paintbox1.Height;
将图像、油漆盒和按钮添加到窗体。然后在 Button 和 Form OnCreate 处理程序中使用以下代码。还要添加转换函数和全局变量 (xLow,xHigh,yLow,yHigh:double; tlx,brx,tly,bry:integer; xy: array of Point;) 并记得添加 Tpoint 类型:( type TMyPolygon = array of T点;)
implementation
{$R *.dfm}
function mapW2SxLin(xf:double):integer;
begin
result:=round(tlx+(xf-xlow)*(brx-tlx)/(xhigh-xlow));
end;
function mapW2SyLin(yf:double):integer;
begin
result:=round(bry-(yf-ylow)*(bry-tly)/(yhigh-ylow));
end;
function mapS2WxLin(xs:integer):double;
begin
result:=xlow+(xs-tlx)*(xhigh-xlow)/(brx-tlx);
end;
function mapS2WyLin(ys:integer):double;
begin
result:=yhigh-(ys-tly)*(yhigh-ylow)/(bry-tly);
end;
procedure TPlotShapeFm.Button1Click(Sender: TObject);
var
// xy: array of TPoint; //probably want to define this globally
x,y,x1,y1,x2,y2,x3,y3:integer;
ax,ay,ax2,ay2:integer;
begin
{ Your values
-88.988857, 36.265838
-89.094923, 36.371904
-89.094923, 36.371904
-95.000423, 36.371904
-95.000423, 36.371904
-95.000423, 32.828604
-95.000423, 32.828604
-99.134273, 32.828604
-88.988857, 36.265838 //repeat the first value to close the shape
}
//convert from World to screen coordinates
// these values are hard coded for this example
// there are many ways to load these from a text file
x:= mapW2SxLin(-88.988857);
y:= mapW2SyLin( 36.265838 );
ax:= mapW2SxLin(-89.094923);
ay:= mapW2SyLin(36.371904);
x1:= mapW2SxLin(-95.000423);
y1:= mapW2SyLin(36.371904);
x2:= mapW2SxLin(-95.000423);
y2:= mapW2SyLin(32.828604);
ax2:= mapW2SxLin(-99.134273);
ay2:= mapW2SyLin(32.828604);
x3:= mapW2SxLin(-88.988857); //return to the starting coordinates to finish off the shape
y3:= mapW2SyLin(36.265838 );
// populate the dynamic array
Setlength(xy, 6);
xy[0] := point(x,y);
xy[1] := point(ax,ay);
xy[2] := point(x1,y1);
xy[3] := point(x2,y2);
xy[4] := point(ax2,ay2);
xy[5] := point(x3,y3);
Paintbox1.Canvas.Brush.Color := Random($FFFFFF);
//plot the shape
//canvas.Polygon(xy); //generic or plot on the form itself
// or
Image1.canvas.polygon(xy); //to plot on a Timage
Paintbox1.canvas. polygon(xy); //to plot on a Tpaintbox
end;
procedure TPlotShapeFm.FormCreate(Sender: TObject);
begin
//You can set up you paint box using:
{ xLow := 0;
xHigh:=-180;
yLow:= 50;
yHigh:= 30; //to display part of North America or
xLow := 180;
xHigh:=-180;
yLow:= 90;
yHigh:= 00; //to display the entire World, North of the equator.
}
// but to display the info provided as a large image
xLow := -88;
xHigh:=-100;
yLow:= 37;
yHigh:= 32;
// scale the paintbox to World coordinates
brx:= Paintbox1.Left;
tlx:= Paintbox1.Left + paintbox1.Width;
bry:= Paintbox1.Top;
tly := Paintbox1.Top + paintbox1.Height;
end;
做对了,结果是这样的:
当我查看提供的数据和生成的形状时,我注意到数据可能没有按照请求者希望使用数组正确绘制形状的顺序列出(注意交叉)。可以通过从初始点开始按顺时针或逆时针顺序列出点,然后在初始点结束来固定交叉点。必须通过在初始点完成绘图来闭合形状。