将 2d 边界转移到其 1d 网格上

Posted

技术标签:

【中文标题】将 2d 边界转移到其 1d 网格上【英文标题】:Transferring 2d boundaries onto its 1d grid 【发布时间】:2021-10-09 00:23:05 【问题描述】:

我有一个定义为 mxn 128x128 的矩阵。我已经将我的 2d x,y 位置转换到这个 1D 矩阵网格上。我的二维坐标接受使用数字 0->127 的位置,即x=0,y=0-->x=127,y=127 范围内的任何组合。我正在实现采用这些节点的相邻位置的算法。特别是距离 i 的 8 个周围位置(假设 i=1)。所以考虑 node=0,0,我的邻居是通过将这些向量添加到所述节点来生成的:

two_d_nodes=
        0,i*1,0,-i*1,-i*1,0,i*1,0,
        i*1,i*1,i*1,-i*1,-i*1,-i*1,-i*1,i*1
    

虽然我排除了边界外的邻居,但就 2d 而言。所以在上面的 node=0,0 中,只生成了邻居 0,1,1,11,0。设置边界基本上只是实现某种形式:

if x>=0 and y>=0 and x<=127 and y<=127 then... 

node=0,0 的 1d 转换是 node=0 并且我的向量加法转换为 1d 是:

one_d_nodes=128,-128,-1,1,129,-127,-129,127

然而,与 2d 边界表达式的关系在这里并不成立。或者至少我不知道如何翻译它。作为回应,我尝试生成网格的所有松散案例:

0,127,16256,16383 --the 4 corner positions  
node%128==0 --right-side boundary  
node%128==1 --left-side boundary  
node>1 and node<128 --top-side boundary  
node>127*128 and node<128*128 --bottom-side boundary    

然后尝试实现特殊情况....我只是忽略了生成特定的越界邻居。这很混乱,甚至由于某种原因没有工作。无论如何,我觉得我错过了一种更清洁的方法。

所以我的问题是:我如何将我的 2d 边界转换为我的 1d 网格,以便仅在边界内生成邻居?


以下是关于以下答案的:

function newmatrix(node) --node=x=0,y=0
    local matrix=
    add(matrix,(node.y<<8)+node.x) --matrix= 0,...
--lets say [1 2 3] is a width=3; height=1 matrix, 
--then the above line maps my 2d coord to a matrix of width=256, height=128 
    matrix.height, matrix.width = #node,#node[1] --1,1
    return matrix
 end

function indexmatrix(matrix, r,c)
    if r > 1 and r <= matrix.height and c > 1 and c <= matrix.width then
        return matrix[matrix.width * r + c]
    else
        return false
    end
end

function getneighbors(matrix, r, c)
    local two_d_nodes=
        0,1,0,-1,-1,0,1,0,
        1,1,1,-1,-1,-1,-1,1
    
    local neighbors = 
    for index, node in ipairs(two_d_nodes) do
        table.insert(neighbors, indexmatrix(matrix, r + node[1], c + node[2]))
    end
    return neighbors
end
--Usage:
m=x=0,y=0
matrix=newmatrix(m) --0
--here's where I'm stuck, cause idk what r and c are
--normally I'd grab my neighbors next....
neighbors=getneighbors(matrix)
--then I have indexmatrix for...?
--my understanding is that I am using indexmatrix to
--check if the nieghbors are within the bounds or not, is that right?
--can you illustrate how it would work for my code here, it should
--toss out anything with x less then 0 and y less than 0. Same as in OP's ex 
indexmatrix(matrix) ---not sure what to do here

关于以下评论部分的尝试 2:

function indexmatrix(matrix, x ,y)
    if x > 1 and x <= matrix['height'] and y > 1 and y <= matrix['width'] then
        return matrix[matrix['width'] * x + y]
    else
        return false
    end
end
function getneighbors(matrix, pos_x, pos_y)
    local two_d_nodes=
        0,1,0,-1,-1,0,1,0,
        1,1,1,-1,-1,-1,-1,1
    
    local neighbors = 
    for _, node in ipairs(two_d_nodes) do
        add(neighbors, indexmatrix(matrix, pos_x + node[1], pos_y + node[2]))
    end
    return neighbors
end

matrix= --128 columns/width, 128 rows/height 
for k=1,128 do
add(matrix,) ----add() is same as table.insert()
    for i=1,128 do
        matrix[k][i]=i
    end
end

id_matrix= -- 1...16k
for j=1,128*128 do
    id_matrix[1][j]=j
end
id_matrix.height, id_matrix.width = 128,128 
    
position=x=0,y=0
neighbors = getNeighbors(matrix, position.x, position.y)

尝试 3:给定代码的工作简化版本。根本不是我想要的。

function indexmatrix(x,y)
    if x>=0 and y>=0 and x<127 and y<127 then
        return 128 * x + y
    else
        return false
    end
end
function getneighbors(posx,posy)
    local two_d_nodes=
        0,1,0,-1,-1,0,1,0,
        1,1,1,-1,-1,-1,-1,1
    
    local neighbors = 
    for _, node in pairs(two_d_nodes) do
        add(neighbors, indexmatrix(posx+node[1], posy + node[2]))
    end
    return neighbors
end

pos=x=0,y=10
neighbors = getneighbors(pos.x,pos.y)

【问题讨论】:

澄清一下,您有一个函数(如mat:index(0,0))可以将给定坐标转换为一维位置?如果是这样,您应该能够验证给定元素的two_d_nodes 并返回有效元素。一种简单的方法是让访问矩阵的方法检查参数是否“在界限内”,如果不是则返回 nil。 如何检查 1d 是否“在界限内”?就是这个问题。 这通常是不可能的,不是吗?来自 0..16383 的所有 1d 索引都是“界内”,因为它们对应于 128x128 矩阵上的界内位置。您无法从一维索引本身判断它是否超出范围。您不仅需要知道指数,还需要知道让您到达那里的运动。当您只有一维索引时,为时已晚。考虑极端情况,例如 i=64i=127 @Weeble 正确,多个 2D 位置可以映射到同一个 1D 索引,而不会限制 2D 表示的范围。如果您检查将 2D 映射到 1D 的函数并意识到它是一个多变量 eqn (y = m*x + z),这很直观。为了使其可解,需要一个方程组,但 x 和 z 是相互独立的。唯一可用的关系是0 &lt;= x &lt;= 1280 &lt;= z &lt;= 128,它们不能在一维上下文中使用。 @kite 我已将此解释添加到我的答案中。 我想知道,鉴于“pico-8”标签,是否有未说明的要求代码尽可能简洁(因为 pico 8 同时具有令牌限制和压缩大小限制),以及一个未说明的假设,即使用一维坐标会导致代码更短?我认为这值得提前说明,因为 a) 这并不明显,b) 可能有办法解决这些问题。 【参考方案1】:

编辑:将 2D 坐标映射到 1D 的方程 y = mx + z 是两个变量的函数。多变量方程不可能有一个解,除非给出的方程组根据另一个变量得到xz。因为xz 是相互独立的,所以对这个问题的简短回答是:

相反,必须使用xz 上的约束来确保一维坐标的完整性。

下面是一个如何处理一维数组的示例,就好像它是一个二维矩阵一样。

假设我们有一个将二维表映射到一维矩阵的构造函数

local function newMatrix(m) -- m is 128x128 Matrix
    local Matrix = 
    --logic to map m to 1D array
    -- ...
   return Matrix -- Matrix is m 1x16384 Array
end

数字索引是保留的,但我们可以添加非数字键来存储有关矩阵的信息。让我们将行数和列数存储为heightwidth。我们可以在构造函数中做到这一点

local function newMatrix(m)
    local Matrix = 
    --logic to map to 1D array
    -- ...
    -- Store row and column info in the matrix
    Matrix.height, Matrix.width = #m, #m[1] -- Not the best way
    return Matrix
end

虽然矩阵现在是一个 1x16384 数组,但我们可以创建一个函数,让我们能够与 1D 数组交互,就像它仍然是一个 2D 矩阵一样。此函数将获取矩阵中某个位置的值,但如果索引超出范围,我们将返回 false/nil

需要明确的是,将矩阵的二维坐标映射到一维坐标的公式,可以在here找到:

1D position = 2D.x * Matrix-Width + 2D.y

下面是这个函数的样子:

local function indexMatrix(Matrix, r,c)
    if r >= 1 and r <= Matrix.height and c >= 1 and c <= Matrix.width then
        return Matrix[Matrix.width * r + c] -- the above formula
    else
        return false -- out of bounds
    end
end

我们现在可以用任何边界索引我们的矩阵,而不必担心返回不正确的元素。

最后,我们可以创建一个函数来获取给定二维位置的邻居。在这个函数中,我们将向量添加到给定的 2D 位置以获得周围位置,然后使用 indexMatrix 函数对矩阵进行索引。因为indexMatrix 检查二维位置是否在原始矩阵的范围内(在它被转换之前),所以我们只得到存在的邻居。

local function getNeighbors(Matrix, r, c) -- r,c = row, column (2D position)
    local two_d_nodes=
        0,1,0,-1,-1,0,1,0,
        1,1,1,-1,-1,-1,-1,1
    
    local neighbors = 
    for index, node in ipairs(two_d_nodes) do
        -- Add each vector to the given position and get the node from the Matrix
        table.insert(neighbors, indexMatrix(Matrix, r + node[1], c + node[2]))
    end
    return neighbors
end

您可以跳过从 indexMatrix 返回 false 的元素,也可以在事后删除它们。或者其他任何你觉得更好听的东西(这段代码不是很棒,它只是作为一个例子)。将其包裹在for i ... do 循环中,您可以出去任意距离。

我希望我没有做太多假设,这很有帮助。只要知道它不是万无一失的(例如,# 运算符在第一个 nil 处停止计数)

编辑:用法

Matrix = 
    1,2,3...128, -- row 1
    1,2,3...128,
    ...
    1,2,3...128, -- row 128


Array = newMatrix(Matrix) -- Convert to 1D Array (1,2,3,...,16384)
--Array.width = 128, Array.height = 128
position = x=0, y=0
neighbors = getNeighbors(Array, position.x, position.y)
-- neighbors is: 0,1, false, false, 1,0, 1,1, false, false, false

【讨论】:

我不明白 r 和 c 是什么。它检查无论它们是什么,是否在矩阵的范围内。然后是这一行“return matrix[matrix.width * r + c]”,这也让我感到困惑。我正在从矩阵中返回一个具有极高价值的键,但这不是在矩阵范围之外,也就是 nil ...?我在这里遗漏了一些东西。我在 OP 中添加了代码,概述了您提供的功能的示例。你能带我看看剩下的部分吗? @kite 我在最后添加了示例用法并清理了答案以增加清晰度。 您使用 Array.width 和 Array.height 定义 Array,但您不使用 Array 做任何事情。我不明白,你的意思是在你的函数中调用一维矩阵而不是二维矩阵......?您向我发送链接,通过定义一定大小的网格将 2d 位置转换为 1d ......但这不是这段代码所说的。此代码将整个 2d 矩阵定义为整个 1d 矩阵。我不明白。我在 OP 中重新发布了我的第二次代码尝试,请告诉我出了什么问题,我删除了你的第一个函数,因为它只是令人困惑。 好的。你没有回答问题。我在上面提供了您的代码的第三个版本....这个正在工作,输出您的代码显然在为您做什么?我无法让您的代码按照上述方式工作。尽管这没有任何意义。为什么要定义二维矩阵,为什么要定义一维矩阵。为什么要引用一维矩阵的键来输出与键相同的值!?!为什么? OP 询问是否可以在 1d 中保留 2d 边界条件。为了检查边界条件而从 1d 转换回 2d 是我想要避免的。 注意 pico-8 标签。 Pico 8 不提供完整的 Lua 标准库,并重命名了它提供的一些函数。这可能是这里很多混乱和沮丧的根源。例如,add 函数不是 table.insert。可以在此处找到差异列表:gist.github.com/josefnpat/bfe4aaa5bbb44f572cd0

以上是关于将 2d 边界转移到其 1d 网格上的主要内容,如果未能解决你的问题,请参考以下文章

平滑2D曲线

诗人小G(1D1D动态规划)

决策单调性

专题三 · 1018

当管理面板中的“设置”已更改以准备转移到实时站点时,如何恢复 wordpress?

使用 CUDA 进行矩阵乘法:2D 块与 1D 块