之前在阅读一个使用rust语言编写的contour tracing算法模块的源代码的时候,其中有一个向量的左旋以及右旋的操作。这个操作的具体的含义是和在算法中的轮廓边缘像素的读取方向有关:因为访问方向是一个二维平面的概念,但是在代码中我们只能够使用一个一维的数组的来存储这个二维的信息。所以在这段rust代码之中,作者很巧妙的使用了向量的左旋以及右旋操作来实现一维数组中对二维平面上的方位的访问操作。

// https://github.com/STPR/contour_tracing

/*
    contours: an array of contours
    ol: outlines level
    hl: holes level
    rn: reachable neighbor - for the outlines: 0: none, 1: front left,  2: front, 3: front right
                           - for the holes:    0: none, 1: front right, 2: front, 3: front left
    o: orientation, e.g. to the east:
             N
       ┏━━━━━━━━━━━┓
       ┃ 7   0   1 ┃
     W ┃ 6   o > 2 ┃ E   o = [2, 3, 4, 5, 6, 7, 0, 1]
       ┃ 5   4   3 ┃
       ┗━━━━━━━━━━━┛
             S
*/

// Rotate 90 degrees, clockwise for the outlines (rot = 2) or
// counterclockwise for the holes (rot = -2)
o.rotate_left(rot.rem_euclid(8) as usize);

// Rotate 90 degrees, counterclockwise for the outlines (rot = 2) or
// clockwise for the holes (rot = -2)
o.rotate_right(rot.rem_euclid(8) as usize);

C++ STLstd::rotate()函数

实现上面的rotate_left以及rotate_right rust函数,在c++语言中存在着一个std::rotate函数可以实现相同的功能:

// std::rotate(iterator start, iterator middle, iterator end);
// Input:
vector<int> v{ 10, 20, 30, 40, 50 };

// rotating vector from 2nd element
rotate(v.begin(), v.begin() + 2, v.end());

// Output:
// 30 40 50 10 20

rotate()算法会从左边选择序列的元素。如下图所示,可以将序列中的元素想象成手镯上的珠子。rotate()操作会导致一个新元素成为开始迭代器所指向的第一个元素。在旋转之后,最后一个元素会在新的第一个元素之前。

VB.NET中的rotate函数

依照着C++中的对向量的rotate操作的函数实现原理,在VB.NET代码中实现了下面两个分别用于Left和Right方向旋转向量的通用函数:

Public Sub RotateLeft(Of T)(ByRef ArrayToRotate As T(), ByVal iPlacesToRotate As Integer)
    Dim kdd = ArrayToRotate.Take(iPlacesToRotate).ToArray
    Dim ddk = ArrayToRotate.Skip(iPlacesToRotate).ToArray

    Array.ConstrainedCopy(kdd, Scan0, ArrayToRotate, ArrayToRotate.Length - kdd.Length, kdd.Length)
    Array.ConstrainedCopy(ddk, Scan0, ArrayToRotate, Scan0, ddk.Length)
End Sub

Public Sub RotateRight(Of T)(ByRef ArrayToRotate As T(), ByVal iPlacesToRotate As Integer)
    ArrayToRotate = ArrayToRotate.Reverse.ToArray

    Dim ddk = ArrayToRotate.Take(iPlacesToRotate).Reverse.ToArray
    Dim kdd = ArrayToRotate.Skip(iPlacesToRotate).Reverse.ToArray

    Array.ConstrainedCopy(ddk, Scan0, ArrayToRotate, Scan0, iPlacesToRotate)
    Array.ConstrainedCopy(kdd, Scan0, ArrayToRotate, iPlacesToRotate, ArrayToRotate.Length - iPlacesToRotate)
End Sub

R#脚本语言中的rotate函数

将上面在VB.NET框架底层代码中所实现的向量左旋以及右旋的代码同时也开放给了R#脚本环境中,使用起来的实际效果是和rust代码中差不多的:

const x = [1,2,3,4,5,6,7,8,9];

print("Old vector: ");
print(x);
print("New vector after left rotation 3 times: ");
# 4 5 6 7 8 9 1 2 3
print(x |> rotate_left(3));

cat("\n\n\n");

print("Old vector: ");
print(x);
print("New vector after right rotation 4 times: ");
# 6 7 8 9 1 2 3 4 5
print(x |> rotate_right(4));

Latest posts by xie guigang (see all)

Attachments

No responses yet

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注