将正方形放置在笛卡尔平面上,并根据序列号

时间:2015-07-22 00:34:48

标签: math sequence discrete-mathematics cartesian

一群男人和我自己都在试图解决这个问题,但是找不到一个干净有效的数学方法来解决这个问题。这是:

给定一个标准的笛卡尔平面和一系列图像(所有方形和相同的尺寸,我们只说1个单位)我们如何以它们围绕原点旋转的方式组织它们( 0,0)飞机的左上角。但更具体地说,如果给出数字25(例如序列中的第25个方格),它的X,Y坐标是什么?

enter image description here

希望这张原始图像有助于解释序列。放置在网格上的第一个正方形将是红色,然后是蓝色,黄色,紫色,绿色,黑色,棕色,然后如点所示。

我们希望是否有相对"这个简单的数学公式,但也许这是一厢情愿的想法。

3 个答案:

答案 0 :(得分:1)

我之前的回答(现在降级到修订历史)是一个递归的解决方案。以下是我称之为" cyclic"溶液

我们的想法是围绕一个正方形进行多次旋转。在任何给定的指数:

  • 我们正在围绕一个较小的广场进行革命
  • 我们在这个广场的一边
  • 我们部分地在这个广场的一边

通过跟踪正方形,侧面和侧面的距离,我们可以索引每个点。

我们通过绘制4条相等的线来绕过一个正方形。 (称他们为#34;段"。)我们在第一段的中间开始每一次革命。

例如:

革命1是一个大小为0的正方形,长度为1的段:

            O    OO
 O    OO    OO   OO

革命2是一个大小为4的正方形,长度为3的段:

            O     OOOO  OOOO 
 OO    OO   OOO   OOO   OOOO
 OOO   OOO  OOOO  OOOO  OOOO
   O  OOOO  OOOO  OOOO  OOOO

革命3是一个大小为16的正方形,长度为5的段:

                 O       OOOOOO  OOOOOO
 OOOO    OOOO    OOOOO   OOOOO   OOOOOO
 OOOO    OOOO    OOOOO   OOOOO   OOOOOO
 OOOOO   OOOOO   OOOOOO  OOOOOO  OOOOOO
 OOOOO   OOOOO   OOOOOO  OOOOOO  OOOOOO
     O  OOOOOO   OOOOOO  OOOOOO  OOOOOO

下面是Python中的一个实现。

import math

def makeSquare(main_index, offset_size):
    step_index = int(math.sqrt(main_index))/2   # How many revolutions have we made?
    last_square = int(math.pow(step_index*2,2)) # Whats the largest square less than main_index?
    segment_length = (2 * step_index) + 1       # How long is the side of the square we've made so far? The segment length is 1 more than that.

    main_index = main_index + step_index + 1    # Skip ahead so we start in the middle of the right side instead of the top. We do some modulo stuff below to wrap around.

    segment_index = (main_index - last_square) / segment_length # Which segment are we on?
    dot_index = main_index - segment_index*segment_length - last_square # How far along the segment are we?

    draw_functions = [
        lambda i, size:  [size,     size - i], # Draw the right side of a square
        lambda i, size:  [size - i, 0       ], # Draw the bottom of a square
        lambda i, size:  [0,        i       ], # Draw the left side of a square
        lambda i, size:  [i,        size    ], # Draw the top of a square
    ]    

    x, y = draw_functions[segment_index % 4](dot_index % (4 * segment_length), segment_length)
    return [ x + offset_size - step_index - 1, y + offset_size - step_index - 1]

# Print the points to the console in sequence
import time, os
step = 4
points = [makeSquare(i, step) for i in range(int(math.pow(step*2,2)))]
board = [[" " for x in range(step*2)] for x in range(step*2)] 
for p in range(len(points)):
    print
    print p, "------------------"
    board[step*2-1 - points[p][1]][points[p][0]] = "O" # Do some coordinate wrangling so we have normal X and Y
    print (os.linesep).join([''.join(row) for row in board])
    time.sleep(.1)

答案 1 :(得分:1)

(编辑:我添加了第二个函数,可以直接获得笛卡尔坐标版本。)

在我头部爆炸之前,我已经走了这么远。它是闭合形式,它给出了百万分之一平方的坐标,而不需要将它们一个接一个地放在一个循环中。写下来不会给出一个很好的公式,但你可以写成一个8件的分段定义公式。答案以1为基础的网格坐标给出。第一个坐标指示您在y轴的右侧或左侧有多少个方格,第二个坐标显示向上或向下的距离。从这些数字可以比较容易地例如得到左上角的笛卡尔坐标。我用Python实现了它:

CSV.foreach(File.path("month.csv")) do |row|
 dateper=row[0].split(',')[0] 
 p DateTime.strptime(dateper,"%m/%d/%y %I:%M:%S %p %z").strftime("%s")
end

要从(i,j)网格坐标获得左上角的(x,y)笛卡尔坐标,可以使用以下函数,该函数具有可选的宽度参数以允许非单位正方形:

from math import sqrt, ceil

def coordinates(m):
    n = ceil(sqrt(m)/2) #shell number
    i = m - 4*(n-1)**2 #index in shell
    if i <= n:
        return (n,-i)
    elif i <= 2*n-1:
        return (2*n - i, -n)
    elif i <= 3*n - 1:
        return (2*n - 1 - i, -n)
    elif i <= 4*n - 2:
        return (-n, -4*n + 1  + i)
    elif i <= 5*n - 2:
        return (-n, -4*n + 2 + i)
    elif i <= 6*n - 3:
        return (-6*n + 2 + i, n)
    elif i <= 7*n - 3:
        return (-6*n + 3 + i,n)
    else:
        return (n, 8*n -3 - i)

可以直接获取左上角的笛卡尔坐标,而无需先通过网格坐标。由此产生的公式涉及较少的案例(因为我不需要从1直接跳到-1,反之亦然)虽然我在答案中保留了两个公式,因为在很多方面,网格视角更自然:

def cartesianFromGrid(i,j,w = 1):
    x = w * (i if i < 0 else i - 1)
    y = w * (j if j > 0 else j + 1)
    return (x,y)

1-16的输出:

def  cartCoordinates(m):
    n = ceil(sqrt(m)/2) #shell number
    i = m - 4*(n-1)**2 #index in shell
    if i <= n:
        return (n-1,-i+1)
    elif i <= 3*n - 1:
        return (2*n - 1 - i, -n + 1)
    elif i <= (5*n - 2):
        return (-n, -4*n + 2 + i)
    elif i <= 7*n - 3:
        return (-6*n + 2 + i, n)
    else:
        return (n-1, 8 * n - 3 - i)

万一你想知道:

>>> for n in range(1,17):
    print(n, ': grid coords =', coordinates(n),
          'Cartesian =',cartesianFromGrid(*coordinates(n)))


1 : grid coords = (1, -1) Cartesian = (0, 0)
2 : grid coords = (-1, -1) Cartesian = (-1, 0)
3 : grid coords = (-1, 1) Cartesian = (-1, 1)
4 : grid coords = (1, 1) Cartesian = (0, 1)
5 : grid coords = (2, -1) Cartesian = (1, 0)
6 : grid coords = (2, -2) Cartesian = (1, -1)
7 : grid coords = (1, -2) Cartesian = (0, -1)
8 : grid coords = (-1, -2) Cartesian = (-1, -1)
9 : grid coords = (-2, -2) Cartesian = (-2, -1)
10 : grid coords = (-2, -1) Cartesian = (-2, 0)
11 : grid coords = (-2, 1) Cartesian = (-2, 1)
12 : grid coords = (-2, 2) Cartesian = (-2, 2)
13 : grid coords = (-1, 2) Cartesian = (-1, 2)
14 : grid coords = (1, 2) Cartesian = (0, 2)
15 : grid coords = (2, 2) Cartesian = (1, 2)
16 : grid coords = (2, 1) Cartesian = (1, 1)

这最后一个答案是有道理的,因为百万分之一的正方形是1000x1000正方形网格的顶点。

我使用上面的方法在tkinter画布小部件上放置彩色方块:

enter image description here

答案 2 :(得分:0)

假设您正在使用基于1的索引,您可以使用以下算法来查找答案(不确定是否存在封闭的表单解决方案)。

这背后的想法是找到你所在的层(你的x或y距离0有多远)。然后找到你所在的象限。然后找出你所在的那一侧,然后找出坐标。

get_coords(n)
    layer = 1
    while (n > 3 * layer * layer + (layer+1)*(layer+1))
        ++layer
    layer_ind = n - 3 * (layer - 1) * (layer - 1) - layer * layer
    if (layer_ind < 2 * layer + 1) # in bottom right
        if (layer_ind <= layer + 1)
            return (layer, - layer_ind + 1)
        else
            return (2 * layer + 1 - layer_ind, -layer)
    else if ((layer_ind - 2 * layer - 1)/(2 * layer - 1) < 1) # bottom left
        layer_ind = layer_ind - 2 * layer - 1
        if (layer_ind <= layer)
            return (-layer_ind+1, -layer+1)
        else
            return (-layer+1, -2*layer + 1 + layer_ind)
    else if ((layer_ind - 2 * layer - 1)/(2 * layer - 1) < 2) # top left
        layer_ind = layer_ind - 4 * layer
        if (layer_ind <= layer)
            return (-layer+1, layer_ind)
        else
            return (layer_ind - 2 * layer, layer)
    else # top right
        layer_ind = layer_ind - 6 * layer + 1
        if (layer_ind <= layer)
            return (layer_ind-1, layer)
        else
            return (layer-1, 2 * layer - layer_ind)