Algorithm 是否有一个简单的;“以矩形表示的点”;环绕图的算法?
我正试图建立一个矩形网格,可以在边缘环绕。任何玩电子游戏的人都可能熟悉这个概念:在世界地图上朝一个方向走足够远,你就会回到你开始的地方。但是,这会给设置视口带来一些困难,因为边可以滚动到负坐标区域 取负坐标并确定其实际值非常容易:Algorithm 是否有一个简单的;“以矩形表示的点”;环绕图的算法?,algorithm,delphi,math,geometry,coordinates,Algorithm,Delphi,Math,Geometry,Coordinates,我正试图建立一个矩形网格,可以在边缘环绕。任何玩电子游戏的人都可能熟悉这个概念:在世界地图上朝一个方向走足够远,你就会回到你开始的地方。但是,这会给设置视口带来一些困难,因为边可以滚动到负坐标区域 取负坐标并确定其实际值非常容易: function GetRealCoords(value: TPoint): TPoint; begin result := ModPoints(AddPoints(value, MAP_SIZE), MAP_SIZE); end; 其中,AddPoints和
function GetRealCoords(value: TPoint): TPoint;
begin
result := ModPoints(AddPoints(value, MAP_SIZE), MAP_SIZE);
end;
其中,AddPoints和ModPoints只需将+
和mod
运算符分别应用于两个输入的每个坐标,以产生输出值
问题是要逆转这一操作。给定一个点,其中两个坐标都是正的,一个树的顶部和左侧值可以是正的或负的(底部或右侧可以超出地图的边缘),并且地图大小在全局范围内声明,是否有任何方法可以确定该点是否位于观察矩形覆盖的区域内,而不必运行相同的计算多达四次?我相信是这样
我能想到的最糟糕的情况(grid=[0,1)x[0,1])是:
顶部=-0.25,左侧=-0.25,底部=0.25,右侧=0.25
这看起来像(包装时):
现在,您必须测试四个角,以查看该点是否位于它们内部。
但是,我相信通过在空间[1,2)x[1,2]中执行测试,可以避免
问题,因为它再次变成一个矩形
______
| |
| |
| _|_
|____| |
|___|
Width=Mod(Right-Left+MAP_SIZE,MAP_SIZE)
Height=Mod(Bottom-Top+MAP_SIZE,MAP_SIZE)
function PointInRect(aPoint:TPoint;aRect:TRect):boolean;
begin
Result:=(aPoint.X >= aRect.Left ) and
(aPoint.X < aRect.Right ) and
(aPoint.Y >= aRect.Top ) and
(aPoint.Y < aRect.Bottom);
end;
通过计算矩形的宽度和高度来简化问题
______
| |
| |
| _|_
|____| |
|___|
Width=Mod(Right-Left+MAP_SIZE,MAP_SIZE)
Height=Mod(Bottom-Top+MAP_SIZE,MAP_SIZE)
function PointInRect(aPoint:TPoint;aRect:TRect):boolean;
begin
Result:=(aPoint.X >= aRect.Left ) and
(aPoint.X < aRect.Right ) and
(aPoint.Y >= aRect.Top ) and
(aPoint.Y < aRect.Bottom);
end;
现在,计算左上角的包裹位置
LeftNew=Mod(Left+MAP_SIZE,MAP_SIZE)
TopNew=Mod(Top+MAP_SIZE,MAP_SIZE)
计算新的底部和右侧:
RightNew=LeftNew+Width
BottomNew=TopNew+Height
现在,对于您希望测试的每个点,添加MAP_大小,并测试它是否位于新矩形内
TestNew=AddPoints(Test,MAP_SIZE)
If (TestNew.X>=LeftNew && TestNew.X<=RightNew && TestNew.Y>=TopNew && TestNew.T<=BottomNew)
{
We have a point inside!
}
TestNew=AddPoints(测试,映射大小)
如果(TestNew.X>=LeftNew&&TestNew.X=TopNew&&TestNew.T,使用此选项可以测试点是否在矩形内
______
| |
| |
| _|_
|____| |
|___|
Width=Mod(Right-Left+MAP_SIZE,MAP_SIZE)
Height=Mod(Bottom-Top+MAP_SIZE,MAP_SIZE)
function PointInRect(aPoint:TPoint;aRect:TRect):boolean;
begin
Result:=(aPoint.X >= aRect.Left ) and
(aPoint.X < aRect.Right ) and
(aPoint.Y >= aRect.Top ) and
(aPoint.Y < aRect.Bottom);
end;
函数PointInRect(aPoint:TPoint;aRect:TRect):布尔;
开始
结果:=(aPoint.X>=aRect.Left)和
(aPoint.X=aRect.Top)和
(A点Y<正确的底部);
结束;
但如果我正确理解你的描述,你会想要这样的东西:
function NormalisePoint(aPoint:TPoint;aRect:TRect):TPoint;
var Width,Height:integer;
begin
Width := aRect.Right-aRect.Left;
Height := aRect.Bottom-aRect.Top;
if (Width=0) then
aPoint.X := aRect.Left
else
begin
while (aPoint.X< aRect.Left ) do inc(aPoint.X,Width );
while (aPoint.X>=aRect.Right ) do dec(aPoint.X,Width );
end;
if (Height=0) then
aPoint.Y := aRect.Top
else
begin
while (aPoint.Y< aRect.Top ) do inc(aPoint.Y,Height);
while (aPoint.Y>=aRect.Bottom) do dec(aPoint.Y,Height);
end;
Result := aPoint;
end;
函数NormalisePoint(aPoint:TPoint;aRect:TRect):TPoint;
变量宽度、高度:整数;
开始
宽度:=aRect.Right-aRect.Left;
高度:=aRect.Bottom-aRect.Top;
如果(宽度=0),则
aPoint.X:=左对齐
其他的
开始
而(aPoint.X=aRect.Right)do dec(aPoint.X,Width);
结束;
如果(高度=0),则
aPoint.Y:=aRect.Top
其他的
开始
while(aPoint.Y=aRect.Bottom)do dec(aPoint.Y,Height);
结束;
结果:=aPoint;
结束;
在进行二维操作之前,先考虑一维。你想知道一个数字是否在一个可能环绕的范围内,例如时钟上7到2的范围内是3。一旦这样,你就可以对X和Y坐标进行测试
我对更简单问题的解决方案:
//assumes start and end are both in [0, divisor). (Because .net and most other languages do modulus WRONG.)
double ClockDistance(double start, double end, double clockSize) {
return (end - start + clockSize) % clockSize;
}
//assumes inclusive bounds
bool ClockBetween(int n, double start, double end, double clockSize) {
return ClockDistance(start, n, clockSize)
<= ClockDistance(start, end, clockSize);
}
//假设开始和结束都在[0,除数中)。(因为.net和大多数其他语言都不正确。)
双时钟距离(双起点、双终点、双时钟尺寸){
返回(结束-开始+时钟大小)%clockSize;
}
//假设包含边界
布尔时钟间隔(整数n,双起点,双终点,双时钟大小){
返回时钟距离(开始,n,时钟大小)
哎哟!我很想在一般原则上否决这一点,只是因为我的“双倍增加”声明。这使它更难阅读。:(我不同意这种情况下的可读性论点,但我知道“with”Delphi开发人员的信条。我将以详细的方式重写它。作为补充,Delphi RTL已经有了一个函数来检查rect是否位于某个点:。