Determinar as dimensões de um retângulo girado

14

Este snippet de pilha desenha um retângulo branco com alias em um fundo preto, com parâmetros para suas dimensões, posição, ângulo e dimensões da grade:

<style>html *{font-family:Consolas,monospace}input{width:24pt;text-align:right;padding:1px}canvas{border:1px solid gray}</style><p>grid w:<input id='gw' type='text' value='60'> grid h:<input id='gh' type='text' value='34'> w:<input id='w' type='text' value='40'> h:<input id='h' type='text' value='24'> x:<input id='x' type='text' value='0'> y:<input id='y' type='text' value='0'> &theta;:<input id='t' type='text' value='12'>&deg; <button type='button' onclick='go()'>Go</button></p>Image<br><canvas id='c'>Canvas not supported</canvas><br>Text<br><textarea id='o' rows='36' cols='128'></textarea><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script>function toCart(t,a,n,r){return{x:t-n/2,y:r/2-a}}function vtx(t,a,n){return{x:n.x+t*Math.cos(a),y:n.y+t*Math.sin(a)}}function sub(t,a){return{x:t.x-a.x,y:t.y-a.y}}function dot(t,a){return t.x*a.x+t.y*a.y}function inRect(t,a,n,r){var e=sub(a,t),o=sub(a,n),l=sub(a,r),i=dot(e,o),v=dot(e,l);return i>0&&i<dot(o,o)&&v>0&&v<dot(l,l)}function go(){var t=parseInt($("#gw").val()),a=parseInt($("#gh").val()),n=parseFloat($("#w").val()),r=parseFloat($("#h").val()),e={x:parseFloat($("#x").val()),y:parseFloat($("#y").val())},o=Math.PI*parseFloat($("#t").val())/180,l=Math.sqrt(n*n+r*r)/2,i=Math.atan2(r,n),v=vtx(l,o+i,e),h=vtx(l,o+Math.PI-i,e),u=vtx(l,o-i,e),x=$("#c");x.width(t).height(a).prop({width:t,height:a}),x=x[0].getContext("2d");for(var s="",c=0;a>c;c++){for(var f=0;t>f;f++)inRect(toCart(f+.5,c+.5,t,a),v,h,u)?(s+="..",x.fillStyle="white",x.fillRect(f,c,1,1)):(s+="XX",x.fillStyle="black",x.fillRect(f,c,1,1));a-1>c&&(s+="\n")}$("#o").val(s)}$(go)</script>
( Versão JSFiddle )

A representação do texto tem XXonde houver um pixel preto na imagem e ..onde houver um pixel branco. (Parece esmagado se eles são Xe ..)

Escreva um programa que utilize a representação de texto de um retângulo produzido pelo Snippet e produza a largura e a altura aproximadas do retângulo, ambas dentro de ± 7% da largura e altura reais .

Seu programa deve trabalhar para efetivamente todos os retângulos possíveis que podem ser desenhados pelo snippet, com as restrições que:

  • A largura e a altura do retângulo são 24 no mínimo.
  • A largura e a altura da grade são 26 no mínimo.
  • O retângulo nunca toca nem sai dos limites da grade.

Portanto, o retângulo de entrada pode ter qualquer rotação, posição e dimensões, e a grade pode ter quaisquer dimensões, desde que as três restrições acima sejam atendidas. Observe que, exceto para as dimensões da grade, os parâmetros do snippet podem ser flutuantes.

Detalhes

  • Tome o retângulo de texto bruto como entrada ou o nome do arquivo de um arquivo que contém o retângulo de texto bruto (via stdin ou linha de comando). Você pode assumir que o retângulo de texto tem uma nova linha à direita.
  • Você pode assumir o retângulo de texto é feita a partir de quaisquer dois distintos ASCII imprimíveis caracteres que não sejam Xe .se desejado. (As novas linhas devem permanecer novas.)
  • Emita a largura e a altura medidas como números inteiros ou flutuantes para stdout em qualquer ordem (já que não há como determinar qual delas realmente foi com qual parâmetro). Qualquer formato que mostra claramente as duas dimensões é fino, por exemplo D1 D2, D1,D2, D1\nD2, (D1, D2), etc.
  • Em vez de um programa, você pode escrever uma função que leva o retângulo de texto como uma string ou o nome do arquivo e imprime o resultado normalmente ou o retorna como uma string ou lista / tupla com dois elementos.
  • Lembre-se disso XXou ..é um 'pixel' do retângulo, não dois.

Exemplos

Ex. 1

Parâmetros: grid w:60 grid h:34 w:40 h:24 x:0 y:0 θ:12(padrões do snippet)

Entrada

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....XXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............XXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX........................XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..................................XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............................................XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....................................................XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..............................................................XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX..........................................................................XXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX................................................................................XXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX................................................................................XXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX..................................................................................XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX..........................................................................XXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX..............................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX....................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX............................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX..................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX........................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXX............XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXX....XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Saídas de exemplo

  • 40 24
  • 24 40
  • [40.0, 24.0]
  • 42.8, 25.68 (+ 7%)
  • 37.2, 22.32 (-7%)

Ex. 2

Parâmetros: grid w:55 grid h:40 w:24.5 h:24 x:-10.1 y:2 θ:38.5

Entrada

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX......XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX............XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..............XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXX..................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXX......................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX............................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXX..............................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX..................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX......................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXX............................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXX................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXX..................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX......................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX............................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX..............................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX................................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX..............................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX..............................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXX............................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXX......................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXX....................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXX................................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXX............................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX......................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX..................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX................................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXX..........................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX......................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX..................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXX................XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXX......XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX..XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Saídas de exemplo

  • 24.0 24.5
  • 25.68 26.215 (+ 7%)
  • 22.32 22.785 (-7%)

Pontuação

O código mais curto em bytes vence. O desempate é o posto mais votado.

Passatempos de Calvin
fonte
Uma solução não deve atender aos requisitos de precisão para ser aceita? O que você aceitou está distante para determinados valores de entrada.
Reto Koradi

Respostas:

6

Matlab, 226 bytes

A idéia é simples: primeiro tento descobrir quanto o retângulo foi girado e depois giro a imagem de forma que o retângulo fique na vertical. Então, apenas 'somar' todos os pixels nas colunas da linha de maneira sutil e tentar contar quantas somas estão acima da média (limiar simples) para determinar a largura e a altura. Este método simples funciona de maneira surpreendentemente confiável.

Como posso detectar o ângulo?

Eu apenas tento cada passo (um grau cada) e soma ao longo das colunas e obtém um vetor de somas. Quando o retângulo está na vertical, idealmente, eu deveria obter apenas duas mudanças repentinas nesse vetor de somas. Se o quadrado estiver na ponta, as alterações serão muito graduais. Então, eu apenas uso a primeira derivada e tento minimizar o número de 'saltos'. Aqui você pode ver um gráfico do critério que estamos tentando minimizar. Observe que você pode ver os quatro mínimos que correspondem às quatro orientações possíveis na vertical.

critério de minimização

Pensamentos adicionais: não tenho certeza do quanto isso poderia ser praticado, pois a pesquisa exaustiva de ângulos ocupa muitos caracteres e duvido que você possa conseguir isso tão bem com métodos de otimização integrados, porque, como você pode ver, existem muitos mínimos locais que não estamos procurando. Você pode facilmente melhorar a precisão (para grandes fotos), escolhendo um tamanho menor passo para o ângulo e só procurar 90 ° em vez de 360 ° para que você poderia substituir 0:360com 0:.1:90ou somehting assim. De qualquer forma, para mim, o desafio foi mais encontrar um algoritmo robusto do que jogar golfe, e tenho certeza de que as entradas das linguagens de golfe deixarão minha apresentação muito para trás =)

PS: Alguém realmente deve derivar uma linguagem de golfe do Matlab / Octave.

Saídas

Exemplo 1:

 25    39

Exemplo 2:

 25    24

Código

Golfe:

s=input('');r=sum(s=='n');S=reshape(s',nnz(s)/r,r)';S=S(:,1:2:end-2)=='.';m=Inf;a=0;for d=0:360;v=sum(1-~diff(sum(imrotate(S,d))));if v<m;m=v;a=d;end;end;S=imrotate(S,a);x=sum(S);y=sum(S');disp([sum(x>mean(x)),sum(y>mean(y))])

Ungolfed:

s=input('');
r=sum(s=='n');              
S=reshape(s',nnz(s)/r,r)'; 
S=S(:,1:2:end-2)=='.';    
m=Inf;a=0;
for d=0:360;                 
    v=sum(1-~diff(sum(imrotate(S,d))));
    if v<m;
        m=v;a=d;
    end;
end;
S=imrotate(S,a);
x=sum(S);y=sum(S');
disp([sum(x>mean(x)),sum(y>mean(y))])
flawr
fonte
7

CJam, 68 65 64 bytes

Isso pode ser jogado um pouco mais ..

qN/2f%{{:QN*'.#Qz,)mdQ2$>2<".X"f#_~>@@0=?Qz}2*;@@-@@-mhSQWf%}2*;

Como funciona

A lógica é bastante simples, se você pensar sobre isso.

Tudo o que precisamos das X.combinações de entrada são 3 coordenadas de dois lados adjacentes. Aqui está como os obtemos:

First

Em qualquer orientação do retângulo, o primeiro de .toda a entrada será um dos cantos. Por exemplo..

XXXXXXXXXXXXXX
XXXXXXX...XXXX
XXXX.......XXX
X............X
XX.........XXX
XXXX...XXXXXXX
XXXXXXXXXXXXXX

Aqui, a primeira .é na 2 ª linha, 8 th coluna.

Mas não é isso, temos que fazer alguns ajustes e adicionar a largura da .corrida nessa linha às coordenadas para obter a coordenada da extremidade certa.

Second

Se transpormos o retângulo acima (girado em novas linhas), o canto inferior esquerdo ocupará o lugar da etapa acima. Mas aqui, não compensamos o .comprimento da execução, pois gostaríamos de obter a coordenada inferior esquerda da aresta de qualquer maneira (que na forma transposta ainda será a primeira encontrada .)

Rest two

Para as duas coordenadas restantes, simplesmente giramos horizontalmente o retângulo e executamos os dois passos acima. Um dos cantos aqui será comum dos dois primeiros.

Depois de obter todos os 4, simplesmente fazemos algumas contas simples para obter as distâncias.

Agora, esse não é o método mais preciso, mas funciona bem dentro da margem de erro e para todas as orientações possíveis do retângulo.

Expansão do código (pouco desatualizado)

qN/2f%{{:QN*'.#Q0=,)md}:A~1$Q='.e=+QzA@@-@@-mhSQWf%}2*;
qN/2f%                               e# Read the input, split on newlines and squish it
      {   ...   }2*                  e# Run the code block two times, one for each side  
{:QN*'.#Q0=,)md}:A~                  e# Store the code block in variable A and execute it
 :QN*                                e# Store the rows in Q variable and join by newlines
     '.#                             e# Get the location of the first '.'
        Q0=,)                        e# Get length + 1 of the first row
             md                      e# Take in X and Y and leave out X/Y and X%Y on stack
1$Q=                                 e# Get the row in which the first '.' appeared
    '.e=+                            e# Get number of '.' in that row and add it to X%Y
         QzA                         e# Transpose the rows and apply function A to get
                                     e# the second coordinate
            @@-@@-                   e# Subtract resp. x and y coordinates of the two corners
                  mh                 e# Calculate (diff_x**2 + diff_y**2)**0.5 to get 1 side
                    SQWF%            e# Put a space on stack and put the horizontally flipped
                                     e# version of the rows/rectangle all ready for next two
                                     e# coordinates and thus, the second side

Experimente online aqui

Optimizer
fonte
Experimente um tamanho de grade de 50 x 50, tamanho de retângulo de 45 x 45 e ângulo -2. O erro é de cerca de 28%. Tentei uma abordagem semelhante (foi minha ideia inicial, antes de ver a sua), e obtê-la com precisão o suficiente acaba sendo mais complicada do que o esperado, principalmente se os lados estiverem próximos da horizontal / vertical. Funciona muito bem se estiverem mais próximos da diagonal. Eu acho que isso requer mais lógica (por exemplo, também procurando por extremos na direção diagonal) ou uma abordagem totalmente diferente.
Reto Koradi
@RetoKoradi Oh. Isso ocorre porque todos os ângulos negativos precisam do .ajuste de largura na segunda coordenada, em vez de na primeira. Fixará. Deve ser uma solução curta.
Optimizer
1
@RetoKoradi deve ser corrigido agora.
Optimizer
Experimente o rectângulo 40x24 com ângulo 0.
Reto Koradi
@RetoKoradi Bons pontos. Inaceitável por enquanto.
Calvin's Hobbies
5

Python 3, 347 337 bytes

Isso ficou mais difícil do que eu esperava. Trabalho em progresso...

def f(s):
 l=s.split('\n');r=range;v=sorted;w=len(l[0]);h=len(l);p=[[x,y]for x in r(w)for y in r(h)if'X'>l[y][x]];x,y=[sum(k)/w/h for k in zip(*p)];g=[[x/2,y]];d=lambda a:((a[0]/2-a[2]/2)**2+(a[1]-a[3])**2)**.5
 for i in r(3):g+=v(p,key=lambda c:~-(c in g)*sum(d(j+c)for j in g))[:1]
 print(v(map(d,[g[1]+g[2],g[2]+g[3],g[1]+g[3]]))[:2])

Define uma função que ftoma a string como argumento e imprime o resultado em STDOUT.

Pitão, 87 84 82 81 75 72 71 bytes

(POSSÍVELMENTE INVÁLIDO, INVESTIGANDO QUANDO EU CHEGO EM CASA)

Km%2d.zJf<@@KeThTG*UhKUKPSm.adfqlT2ytu+G]ho*t}NGsm.a,kNGJ3]mccsklhKlKCJ

Way Ainda muito longo. Basicamente, um porto do anterior. Distância .aeuclidiana de Pyth . Recebe entrada via STDIN e fornece saída via STDOUT. Espera que o caractere não retângulo seja minúsculo x(bem, qualquer coisa com valor ASCII 98 ou mais).

Algoritmo

Ambos usam o mesmo algoritmo. Basicamente, começo com uma matriz que contém o centro de massa da área do retângulo. Em seguida, adiciono três pontos à matriz de todos os pontos do retângulo, sempre escolhendo aquele com a soma máxima de distâncias aos pontos já presentes na matriz. O resultado é sempre três pontos nos diferentes cantos do retângulo. Calculo então todas as três distâncias entre esses três pontos e tomo os dois mais curtos.

PurkkaKoodari
fonte
A solução Pyth não funciona. Os dois exemplos do OP fornecem os resultados em [33.0, 59.0]vez de [40, 24]e em [39.0, 54.0]vez de [24.0, 24.5].
Jakube 31/05
@Jakube Weird. Vou investigar quando chegar em casa. Infelizmente, estou em uma viagem de classe à Lapônia até 9 de junho.
PurkkaKoodari
Eu não chamaria uma viagem à Lapónia infelizmente ;-)
Jakube
0

Python 2, 342 bytes

import sys
r=[]
h=.0
for l in sys.stdin:w=len(l);r+=[[x*.5,h]for x in range(0,w,2)if l[x:x+2]=='..'];h+=1
x,y=.0,.0
for p in r:x+=p[0];y+=p[1]
n=len(r)
x/=n
y/=n
m=.0
for p in r:
 p[0]-=x;p[1]-=y;d=p[0]**2+p[1]**2
 if d>m:m=d;u,v=p
m=.0
for p in r:
 d=p[0]*v-p[1]*u
 if d>m:m=d;s,t=p
print ((u-s)**2+(v-t)**2)**.5+1,((u+s)**2+(v+t)**2)**.5+1

Isso inspirou-se no algoritmo de @ Pietu1998. É preciso a idéia de determinar um canto como o ponto mais distante do centro, mas difere a partir daí:

  • Eu determino o segundo canto como o ponto com o maior produto cruzado com o vetor do centro ao primeiro canto. Isso indica o ponto com a maior distância da linha do centro até o primeiro canto.
  • Não é necessário procurar um terceiro canto, pois é apenas a imagem espelhada do segundo canto em relação ao centro.

Portanto, o código segue esta sequência:

  • O primeiro loop é sobre as linhas da entrada e cria uma lista rde pontos de retângulo.
  • O segundo loop calcula a média de todos os pontos do retângulo, fornecendo o centro do retângulo.
  • O terceiro loop encontra o ponto mais distante do centro. Esta é a primeira esquina. Ao mesmo tempo, subtrai o centro dos pontos da lista, para que as coordenadas do ponto sejam relativas ao centro para o cálculo restante.
  • O quarto loop encontra o ponto com o maior produto cruzado com o vetor no primeiro canto. Esta é a segunda esquina.
  • Imprime a distância entre o primeiro canto e o segundo canto e a distância entre o primeiro canto e a imagem espelhada do segundo canto.
  • 1.0é adicionado às distâncias porque os cálculos de distância originais usam índices de pixels. Por exemplo, se você tiver 5 pixels, a diferença entre o índice do último e do primeiro pixel será de apenas 4, o que precisa de compensação no resultado final.

Precisão é muito boa. Para os dois exemplos:

$ cat rect1.txt | python Golf.py 
24.5372045919 39.8329756779
$ cat rect2.txt | python Golf.py 
23.803508502 24.5095563412
Reto Koradi
fonte
0

Python 2, 272 bytes

Postando isso como uma resposta separada, pois é um algoritmo completamente diferente do meu anterior:

import sys,math
y,a,r=0,0,0
l,t=[1<<99]*2
for s in sys.stdin:
 c=s.count('..')
 if c:a+=c;x=s.find('.')/2;l=min(l,x);r=max(r,x+c);t=min(t,y);b=y+1
 y+=1
r-=l
b-=t
p=.0
w,h=r,b
while w*h>a:c=math.cos(p);s=math.sin(p);d=c*c-s*s;w=(r*c-b*s)/d;h=(b*c-r*s)/d;p+=.001
print w,h

Essa abordagem não identifica os cantos. É baseado na observação de que o tamanho (largura e altura) da caixa delimitadora e a área do retângulo girado são suficientes para determinar a largura e a altura do retângulo.

Se você observar um esboço, é bastante fácil calcular a largura ( wb) e a altura ( hb) da caixa delimitadora com w/ ho tamanho do retângulo e po ângulo de rotação:

wb = w * cos(p) + h * sin(p)
hb = w * sin(p) + h * cos(p)

wbe hbpode ser extraído diretamente da imagem. Também podemos extrair rapidamente a área total ado retângulo contando o número de ..pixels. Como estamos lidando com um retângulo, isso nos dá a equação adicional:

a = w * h

Portanto, temos 3 equações com 3 incógnitas ( w, he p), o que é suficiente para determinar as incógnitas. A única chatice é que as equações contêm funções trigonométricas e, pelo menos com minha paciência e habilidades matemáticas, o sistema não pode ser facilmente resolvido analiticamente.

O que implementei é uma busca de força bruta pelo ângulo p. Uma vez pdada, as duas primeiras equações acima se tornam um sistema de duas equações lineares, que podem ser resolvidas we h:

w = (wb * cos(p) - hb * sin(p)) / (cos(p) * cos(p) - sin(p) * sin(p))
h = (hb * cos(p) - wb * sin(p)) / (cos(p) * cos(p) - sin(p) * sin(p))

Com esses valores, podemos comparar w * hcom a área medida do retângulo. Os dois valores seriam idealmente iguais em algum momento. É claro que isso não vai acontecer na matemática de ponto flutuante.

O valor de w * hdiminui à medida que o ângulo aumenta. Então começamos no ângulo 0.0 e, em seguida, incrementamos o ângulo em pequenos passos até que a primeira vez w * hseja menor que a área medida.

O código possui apenas duas etapas principais:

  1. Extraia o tamanho da caixa delimitadora e da área retangular da entrada.
  2. Faça um loop sobre os ângulos candidatos até que o critério de término seja atingido.

A precisão da saída é boa para retângulos em que a largura e a altura são significativamente diferentes. Fica um pouco duvidoso com retângulos quase quadrados e girados perto de 45 graus, apenas eliminando o obstáculo de 7% no exemplo de teste 2.

O bitmap do exemplo 2, na verdade, parece um pouco estranho. O canto esquerdo parece desconfiado. Se eu adicionar mais um pixel no canto esquerdo, ambos parecerão melhores (para mim) e fornecerão uma precisão muito melhor para esse algoritmo.

Reto Koradi
fonte