Определить размеры повернутого прямоугольника


14

Этот фрагмент стека рисует наложенный белый прямоугольник на черном фоне с заданными параметрами для его размеров, положения, угла и размеров сетки:

<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>
( Версия JSFiddle )

Текстовое представление имеет XXвезде, где есть черный пиксель на изображении, и ..везде, где есть белый пиксель. (Это выглядит сжато, если они Xи ..)

Напишите программу, которая принимает текстовое представление прямоугольника, созданного фрагментом кода, и выводит приблизительную ширину и высоту прямоугольника с точностью до ± 7% от фактической ширины и высоты .

Ваша программа должна эффективно работать со всеми возможными прямоугольниками, которые могут быть нарисованы фрагментом, с ограничениями, которые:

  • Ширина и высота прямоугольника не менее 24.
  • Ширина и высота сетки не менее 26.
  • Прямоугольник никогда не касается и не выходит за границы сетки.

Таким образом, входной прямоугольник может иметь любое вращение, положение и размеры, а сетка может иметь любые размеры при условии соблюдения трех указанных выше ограничений. Обратите внимание, что за исключением размеров сетки, параметры Snippet могут быть плавающими.

Детали

  • Возьмите прямоугольник необработанного текста в качестве ввода или имя файла, содержащего прямоугольник необработанного текста (через stdin или командную строку). Вы можете предположить, что у текстового прямоугольника есть завершающий символ новой строки.
  • Вы можете предположить, что текстовый прямоугольник состоит из любых двух различных печатаемых символов ASCII, кроме Xи .при желании. (Новые строки должны оставаться новыми.)
  • Выведите измеренную ширину и высоту в виде целых чисел или значений с плавающей точкой в ​​стандартный вывод в любом порядке (поскольку невозможно определить, какой из них на самом деле соответствовал какому параметру). Любой формат , который четко показывает два измерения в порядке, например D1 D2, D1,D2, D1\nD2, (D1, D2)и т.д.
  • Вместо программы вы можете написать функцию, которая принимает текстовый прямоугольник в виде строки или имя файла и печатает результат в обычном режиме или возвращает его в виде строки или списка / кортежа с двумя элементами.
  • Помните, что XXили ..это один «пиксель» прямоугольника, а не два.

Примеры

Ex. 1

Параметры: grid w:60 grid h:34 w:40 h:24 x:0 y:0 θ:12(по умолчанию сниппет)

вход

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

Пример выходов

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

Ex. 2

Параметры: grid w:55 grid h:40 w:24.5 h:24 x:-10.1 y:2 θ:38.5

вход

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

Пример выходов

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

счет

Самый короткий код в байтах побеждает. Tiebreaker является самым высоко оцененным постом.


Разве решение не должно соответствовать требованиям точности, которые должны быть приняты? Тот, который вы приняли, далек для определенных входных значений.
Рето Коради

Ответы:


6

Matlab, 226 байт

Идея проста: сначала я пытаюсь выяснить, насколько прямоугольник был повернут, а затем поверните изображение соответствующим образом, чтобы прямоугольник был в вертикальном положении. Затем я просто «суммирую» все пиксели в столбцах строк и пытаюсь подсчитать, сколько сумм выше среднего (простое пороговое значение) для определения ширины и высоты. Этот простой метод работает на удивление надежно.

Как я могу определить угол?

Я просто пробую каждый шаг (по одному градусу), суммирую по столбцам и получаю вектор сумм. Когда прямоугольник выпрямлен, в идеале я должен получить только два внезапных изменения этого вектора сумм. Если квадрат на кончике, изменения очень постепенные. Поэтому я просто использую первую производную и пытаюсь минимизировать количество «прыжков». Здесь вы можете увидеть график критерия, который мы пытаемся минимизировать. Обратите внимание, что вы можете увидеть четыре минимума, которые соответствуют четырем возможным вертикальным ориентациям.

критерий минимизации

Дальнейшие размышления: я не уверен, сколько это может быть в гольфе, поскольку исчерпывающий поиск углов занимает много символов, и я сомневаюсь, что вы могли бы добиться этого так хорошо с помощью встроенных методов оптимизации, потому что, как вы можете видеть, есть много локальных минимумов что мы не ищем. Вы можете легко улучшить точность (для больших изображений), выбирая меньший размер шага для угла и поиск только 90 ° вместо 360 ° , чтобы вы могли заменить 0:360с 0:.1:90или somehting подобными. Но в любом случае, для меня проблема заключалась в поиске надежного алгоритма, а не в игре в гольф, и я уверен, что записи языков игры в гольф оставят мое представление далеко позади =)

PS: Кто-то должен действительно вывести язык игры в гольф от Matlab / Octave.

Выходы

Пример 1:

 25    39

Пример 2:

 25    24

Код

Golfed:

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))])

7

CJam, 68 65 64 байта

Это может быть в гольф немного больше ..

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

Как это устроено

Логика довольно проста, если подумать.

Все, что нам нужно из входных X.комбинаций, это 3 координаты двух соседних сторон. Вот как мы их получаем:

First

В любой ориентации прямоугольника первый .из входных данных будет одним из углов. Например..

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

Здесь первый .находится во 2- й строке 8- го столбца.

Но это не так, мы должны сделать некоторую корректировку и добавить ширину линии .на этой линии к координатам, чтобы получить координату правого конца.

Second

Если мы транспонируем вышеуказанный прямоугольник (повернутый на новых строках), то нижний левый угол занимает место вышеуказанного шага. Но здесь мы не компенсируем .длину пробега, так как мы хотели бы получить нижнюю левую координату края в любом случае (которая в транспонированной форме все равно будет первой, с которой столкнулись .)

Rest two

Для остальных двух координат мы просто переворачиваем прямоугольник по горизонтали и выполняем два вышеуказанных шага. Один из углов здесь будет общим с первых двух.

После получения всех 4, мы просто делаем простую математику, чтобы получить расстояния.

Сейчас это не самый точный метод, но он хорошо работает в пределах погрешности и хорошо подходит для всех возможных ориентаций прямоугольника.

Расширение кода (немного устаревшее)

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

Попробуйте онлайн здесь


Попробуйте размер сетки 50x50, размер прямоугольника 45x45 и угол -2. Ошибка составляет около 28%. Я попробовал подобный подход (это была моя первоначальная идея, прежде чем увидеть вашу), и получить его достаточно точно оказалось сложнее, чем ожидалось, особенно если стороны близки к горизонтали / вертикали. Прекрасно работает, если они ближе к диагонали. Я думаю, что это требует либо большей логики (например, поиска экстремумов в диагональном направлении), либо совершенно другого подхода.
Рето Коради

@RetoKoradi Ох. Это потому, что все отрицательные углы нуждаются в .регулировке ширины по второй координате, а не по первой. Починю. Должно быть короткое исправление.
Оптимизатор

1
@RetoKoradi должен быть исправлен сейчас.
Оптимизатор

Попробуйте прямоугольник 40х24 с углом 0.
Рето Коради

@RetoKoradi Хорошие очки. Пока не принято.
Увлечения Кэлвина

5

Python 3, 347 337 байт

Это оказалось сложнее, чем я ожидал. Работа в процессе...

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])

Определяет функцию f принимающую строку в качестве аргумента и печатающую результат в STDOUT.

Pyth, 87 84 82 81 75 72 71 байт

(ВОЗМОЖНО НЕДОПУСТИМО, РАССЛЕДОВАТЬ, КОГДА Я ПОЛУЧУ ДОМ

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

Путь еще слишком длинный. В основном порт предыдущего. Любящее .aевклидово расстояние Пита . Принимает ввод через STDIN и выдает вывод через STDOUT. Предполагается, что непрямоугольный символ будет строчным x(ну, все, что имеет значение ASCII 98 или более).

Алгоритм

Оба из них используют один и тот же алгоритм. Я в основном начинаю с массива, содержащего центр масс области прямоугольника. Затем я добавляю три точки в массив всех точек в прямоугольнике, всегда выбирая ту, которая имеет максимальную сумму расстояний до точек, уже находящихся в массиве. В результате всегда три точки в разных углах прямоугольника. Затем я просто вычисляю все три расстояния между этими тремя точками и беру две самые короткие.


Решение Pyth не работает вообще. Два примера из OP дают результаты [33.0, 59.0]вместо [40, 24]и [39.0, 54.0]вместо [24.0, 24.5].
Якуб

@Jakube Странно. Я расследую, как только вернусь домой. К сожалению, я нахожусь в учебной поездке в Лапландию до 9 июня.
PurkkaKoodari

Я бы не назвал поездку в Лапландию к сожалению ;-)
Якуб

0

Python 2, 342 байта

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

Это черпало вдохновение из алгоритма @ Pietu1998. Требуется определить один угол как точку, самую дальнюю от центра, но отличается от нее:

  • Я определяю второй угол как точку с наибольшим перекрестным произведением с вектором от центра к первому углу. Это дает точку с наибольшим расстоянием от линии от центра до первого угла.
  • Нет необходимости искать третий угол, так как это просто зеркальное отображение второго угла относительно центра.

Таким образом, код следует этой последовательности:

  • Первый цикл проходит по строкам на входе и строит список rточек прямоугольника.
  • Второй цикл вычисляет среднее значение всех точек прямоугольника, давая центр прямоугольника.
  • Третий цикл находит точку, самую дальнюю от центра. Это первый поворот. В то же время он вычитает центр из точек в списке, так что координаты точек относительно центра для оставшегося расчета.
  • Четвертый цикл находит точку с наибольшим перекрестным произведением с вектором в первом углу. Это второй угол.
  • Распечатывает расстояние между первым углом и вторым углом, а также расстояние между первым углом и зеркальным отображением второго угла.
  • 1.0добавляется к расстоянию, потому что исходные расчеты расстояния используют индексы пикселей. Например, если у вас есть 5 пикселей, разница между индексом последнего и первого пикселя составила всего 4, что требует компенсации в конечном результате.

Точность довольно хорошая. Для двух примеров:

$ cat rect1.txt | python Golf.py 
24.5372045919 39.8329756779
$ cat rect2.txt | python Golf.py 
23.803508502 24.5095563412

0

Python 2, 272 байта

Публикуем это как отдельный ответ, так как это совершенно другой алгоритм, чем мой предыдущий:

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

Этот подход не определяет углы вообще. Он основан на наблюдении, что размер (ширина и высота) ограничительной рамки и площадь повернутого прямоугольника достаточны для определения ширины и высоты прямоугольника.

Если вы посмотрите на эскиз, довольно легко вычислить ширину ( wb) и высоту ( hb) ограничительной рамки с w/ hразмером прямоугольника и pуглом поворота:

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

wbи hbможет быть извлечен непосредственно из изображения. Мы также можем быстро извлечь общую площадь aпрямоугольника, посчитав количество ..пикселей. Поскольку мы имеем дело с прямоугольником, это дает нам дополнительное уравнение:

a = w * h

Таким образом, у нас есть 3 уравнения с 3 неизвестными ( w, hиp ), чего достаточно для определения неизвестных. Единственный облом в том, что уравнения содержат тригонометрические функции, и, по крайней мере, с моим терпением и математическими навыками, система не может быть легко решена аналитически.

То, что я реализовал, - это грубый поиск угла p. Как только pдано, первые два уравнения выше становятся системой двух линейных уравнений, которые могут быть решены для wи 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))

С этими значениями мы можем сравнить w * hс измеренной площадью прямоугольника. Два значения в идеале должны быть равны в какой-то момент. Это, конечно, не произойдет в математике с плавающей точкой.

Значение w * hуменьшается с увеличением угла. Итак, мы начинаем с угла 0.0, а затем увеличиваем угол небольшими шагами до тех пор, пока первый раз не w * hстанет меньше измеренной площади.

Код имеет только два основных шага:

  1. Извлечь размер ограничивающего прямоугольника и прямоугольника из ввода.
  2. Зацикливайтесь на возможных углах, пока не будет достигнут критерий завершения.

Точность вывода хороша для прямоугольников, где ширина и высота существенно различаются. Это несколько ненадежно с прямоугольниками, которые почти квадратные и повернуты близко к 45 градусам, просто преодолевая 7% -ое препятствие ошибки для тестового примера 2.

Растровое изображение для примера 2 на самом деле выглядит немного странно. Левый угол выглядит подозрительно скучно. Если я добавлю еще один пиксель в левом углу, он будет выглядеть лучше (для меня) и даст гораздо лучшую точность для этого алгоритма.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.