Quero obter as coordenadas de vários pontos que juntos formam um octógono. Para um círculo, isso é feito facilmente da seguinte forma:
import numpy as np
n = 100
x = np.cos(np.linspace(0, 2 * np.pi, n))
y = np.sin(np.linspace(0, 2 * np.pi, n))
coordinates = list(zip(x, y))
Ao mudar, n
posso aumentar/diminuir a "angularidade". Agora, quero fazer o mesmo para um octógono. Sei que um octógono tem 8 lados e o ângulo entre cada lado é de 45 graus. Vamos supor que o perímetro do octógono seja 30,72 m. Cada lado tem, portanto, um comprimento de 3,79 m.
perimeter = 30.72
n_sides = 8
angle = 45
Como posso obter n
coordenadas que representam este octógono?
Editar:
Com a ajuda das respostas de @lastchance e @mozway, sou capaz de gerar um octógono. Meu objetivo é obter n
coordenadas uniformemente espaçadas do perímetro deste octógono. Se n = 8
essas coordenadas correspondem aos cantos do octógono, mas estou interessado em casos em quen > 8
Vamos usar um pouco de matemática.
Cada triângulo no polígono é isósceles. Assumindo
r
o raio do círculo que o contém ea
cada lado do polígono, temos:Assim, as coordenadas são:
Observe o
endpoint=False
emlinspace
.Como um gráfico:
Saída:
Se você quiser um ponto extra para "fechar" o polígono (o último ponto sendo o mesmo que o primeiro ponto):
Agora, vamos usar
shapely
para verificar se o cálculo está correto:Interpolação de
n
pontos no octógono/polígonoAgora que temos um polígono, podemos interpolar
n
pontos ao longo de seu perímetro.Vamos gerar um polígono "fechado" (ou seja, n_sides+1 ponto em que o último é igual ao primeiro), criar um
LineString
einterpolate
n
valores ao longo dele:Saída:
Bem, se você definir n=8 e usar seu código para um círculo, você receberá coordenadas para um octógono. Você então precisa escalar esse octógono para encontrar seu perímetro. Eu adicionei uma função de distância para ajudar a calcular o tamanho das bordas do octógono original. Também há um arredondamento para 4 casas decimais para torná-lo mais legível, mas você pode escolher remover isso. Eu acredito que isso funcionará para uma forma de qualquer tamanho e qualquer perímetro desejado.
Outro uso para números complexos. Seu gráfico é um diagrama de Argand, com coordenadas x e y, as partes real e imaginária de uma variável complexa em forma polar.
Parte 1: Octógono Simples
Vai contra a corrente para meus octógonos terem 9 vértices, então eu usei
endpoint=False
nanumpy.linspace
chamada. Para fechar o polígono, eu simplesmente junto o último e o primeiro ponto com umaplot
chamada separada.Se você não quiser octógonos, altere para qualquer valor que
numsides
desejar.Parte 2: Pontos Adicionais
Não está muito claro o que "uniformemente espaçado" significa: pode significar igualmente distribuído por distância perimétrica, ou pode significar ângulos polares iguais. Como é mais fácil, presumi o primeiro.
Quando você quiser
n
pontos do original,numsides
você pode simplesmente mapear números e interpolar:Assim, seu índice de interpolação (de ponto flutuante) vem da multiplicação do índice de ponto por
numsides/n
. A interpolação é feita extraindo partes inteiras e fracionárias. Um pouco de cuidado deve ser exercido no último segmento se o ponto final (como aqui) não repetir o primeiro.Funciona seja
n
um múltiplo denumsides
(por exemplon=24
) ou não (por exemplon=13
). No entanto, parece mais natural quando é um múltiplo de número inteiro (nesse caso, a interpolação pode ser feita com um loop aninhado simples).Se você quiser que os pontos sejam espaçados uniformemente ao longo do perímetro, você pode calcular o comprimento do
perimeter = n * side
para umn
polígono de lados, distribuir ospts
pontos ao longo desse comprimento total (totalpos = perimeter * i / pts
, ondei = 0 ... pts-1
), e então caminhar sobre as bordas, calculando o índice do lado atual comoindex = floor(totalpos / side)
, e a posição dentro do lado dado comosidepos = totalpos - index * side
. Então pegue o lado em questão, e use essa posição interna ao longo dele para obter um ponto.Este código JavaScript faz isso de forma interativa, a única parte complicada é que eu queria ter a borda mais inferior horizontal, é por isso que os "tradicionais" x-cos, y-sin são trocados e também deslocados pela metade (desta forma o comprimento do lado é apenas a diferença das coordenadas x). Não posso escrever isso em Python no momento.
Uma solução "antiga" sem usar bibliotecas externas (exceto para calcular cos e seno!):