我正在尝试构建一个可以在边缘环绕的矩形网格。任何玩电子游戏的人都可能熟悉这个概念:在世界地图上向一个方向走得足够远,你最终会回到你开始的地方。但是,这会导致设置视口时出现一些困难,因为边缘可以滚动到负坐标区域。
采用负坐标并确定其实际值很容易:
function GetRealCoords(value: TPoint): TPoint;
begin
result := ModPoints(AddPoints(value, MAP_SIZE), MAP_SIZE);
end;
其中AddPoints和ModPoints分别将+
和mod
运算符分别应用于两个输入的每个坐标以生成输出值。
问题在于扭转此操作。给定一个点,其中两个坐标都是正的,TRect,其中Top和Left值可以是正的或负的(并且Bottom或Right可能超出了map的边缘),并且在全局范围内声明了MAP_SIZE,有没有办法确定该点是否属于观察矩形覆盖的区域,而不必在四个不同时间运行相同的计算?
答案 0 :(得分:4)
我相信。
我能想到的最糟糕的情况(grid = [0,1)x [0,1))是这样的: Top = -0.25,Left = -0.25,Bottom = 0.25,Right = 0.25
这看起来像(包裹时):
______
|_| |_|
| |
|_ _|
|_|__|_|
现在,您必须测试四个角以查看该点是否位于其中。 但是,我相信通过在空间[1,2] x [1,2]中执行测试,你可以避免 问题,因为它又变成了一个矩形。
______
| |
| |
| _|_
|____| |
|___|
通过计算矩形的宽度和高度来简化问题。
Width=Mod(Right-Left+MAP_SIZE,MAP_SIZE)
Height=Mod(Bottom-Top+MAP_SIZE,MAP_SIZE)
现在,计算左上角的包裹位置
LeftNew=Mod(Left+MAP_SIZE,MAP_SIZE)
TopNew=Mod(Top+MAP_SIZE,MAP_SIZE)
计算新的底部和右边:
RightNew=LeftNew+Width
BottomNew=TopNew+Height
现在,对于您要测试的每个点,添加MAP_SIZE,并测试它是否在新的rect中!
TestNew=AddPoints(Test,MAP_SIZE)
If (TestNew.X>=LeftNew && TestNew.X<=RightNew && TestNew.Y>=TopNew && TestNew.T<=BottomNew)
{
We have a point inside!
}
我没有对此进行详尽的测试,但我认为这是正确的。
答案 1 :(得分:3)
通过这个,您可以测试您的点是否在矩形内。
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;
但如果我理解你的描述,你需要这样的东西:
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;
答案 2 :(得分:0)
在二维之前进行一维考虑。你想弄清楚一个数字是否在一个可能环绕的范围内,例如。时钟在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);
}
其中概括为:
//assumes rects oriented so bottom < top, not the other way around like in UI
bool RectContains(double x, double y, double left, double bottom, double right, double top, double worldWidth, double wordlHeight) {
return ClockBetween(x, left, right, worldWidth)
&& ClockBetween(y, bottom, top, worldHeight);
}