Bestimmen Sie die Abmessungen eines gedrehten Rechtecks

14

Mit diesem Stapel-Snippet wird ein weißes Rechteck mit einem Alias auf schwarzem Hintergrund gezeichnet. Dabei werden die Abmessungen, die Position, der Winkel und die Rastermaße angegeben:

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

Die Textdarstellung hat XXüberall dort, wo sich ein schwarzes Pixel im Bild befindet, und ..überall dort, wo sich ein weißes Pixel befindet. (Es sieht zerquetscht aus, wenn sie Xund sind ..)

Schreiben Sie ein Programm, das die Textdarstellung eines vom Snippet erzeugten Rechtecks ​​verwendet und die ungefähre Breite und Höhe des Rechtecks innerhalb von ± 7% der tatsächlichen Breite und Höhe ausgibt .

Ihr Programm sollte für alle möglichen Rechtecke, die vom Snippet gezeichnet werden können, mit den folgenden Einschränkungen funktionieren:

  • Die Rechteckbreite und -höhe beträgt mindestens 24.
  • Die Gitterbreite und -höhe beträgt mindestens 26.
  • Das Rechteck berührt und verlässt niemals die Gittergrenzen.

Das Eingaberechteck kann also eine beliebige Drehung, Position und Bemaßung haben, und das Gitter kann eine beliebige Bemaßung haben, solange die drei oben genannten Bedingungen erfüllt sind. Beachten Sie, dass die Snippet-Parameter mit Ausnahme der Rastermaße Gleitkommazahlen sein können.

Einzelheiten

  • Nehmen Sie das Rohtextrechteck als Eingabe oder den Dateinamen einer Datei, die das Rohtextrechteck enthält (über stdin oder Befehlszeile). Sie können davon ausgehen, dass das Textrechteck einen nachgestellten Zeilenumbruch hat.
  • Sie können davon ausgehen, dass das Textrechteck aus zwei unterschiedlichen druckbaren ASCII- Zeichen besteht, die nicht Xund .falls gewünscht sind. (Zeilenumbrüche müssen Zeilenumbrüche bleiben.)
  • Geben Sie die gemessene Breite und Höhe als Ganzzahlen oder Gleitkommazahlen in beliebiger Reihenfolge als stdout aus (da nicht festgestellt werden kann, welcher Parameter tatsächlich zu welchem ​​Parameter gehört). Jedes Format , dass eindeutig die beiden Dimensionen zeigt ist in Ordnung, zum Beispiel D1 D2, D1,D2, D1\nD2, (D1, D2)etc.
  • Anstelle eines Programms können Sie eine Funktion schreiben, die das Textrechteck als Zeichenfolge oder als Dateinamen verwendet und das Ergebnis normal ausgibt oder als Zeichenfolge oder Liste / Tupel mit zwei Elementen zurückgibt.
  • Denken Sie daran, dass XXoder ..ein Pixel des Rechtecks ​​ist, nicht zwei.

Beispiele

Ex. 1

Parameter: grid w:60 grid h:34 w:40 h:24 x:0 y:0 θ:12(Snippet-Standardeinstellungen)

Eingang

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

Beispielausgaben

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

Ex. 2

Parameter: grid w:55 grid h:40 w:24.5 h:24 x:-10.1 y:2 θ:38.5

Eingang

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

Beispielausgaben

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

Wertung

Der kürzeste Code in Bytes gewinnt. Tiebreaker ist der am höchsten gewählte Beitrag.

Calvins Hobbys
quelle
Sollte eine Lösung nicht die zu akzeptierenden Präzisionsanforderungen erfüllen? Der von Ihnen akzeptierte Wert ist für bestimmte Eingabewerte weit entfernt.
Reto Koradi

Antworten:

6

Matlab, 226 Bytes

Die Idee ist einfach: Zuerst versuche ich herauszufinden, um wie viel das Rechteck gedreht wurde, und dann drehe ich das Bild entsprechend, sodass das Rechteck aufrecht steht. Dann 'summiere' ich einfach alle Pixel in den Zeilenspalten und zähle, wie viele der Summen über dem Durchschnitt liegen (einfaches Schwellenwertverfahren), um die Breite und Höhe zu bestimmen. Diese einfache Methode funktioniert überraschend zuverlässig.

Wie kann ich den Winkel erkennen?

Ich versuche einfach jeden Schritt (jeweils ein Grad) und summiere entlang der Spalten und erhalte einen Summenvektor. Wenn das Rechteck aufrecht ist, sollte ich idealerweise nur zwei plötzliche Änderungen in diesem Summenvektor erhalten. Wenn sich das Quadrat auf der Spitze befindet, sind die Änderungen sehr allmählich. Ich verwende also nur die erste Ableitung und versuche, die Anzahl der "Sprünge" zu minimieren. Hier sehen Sie eine grafische Darstellung des Kriteriums, das wir zu minimieren versuchen. Beachten Sie, dass Sie die vier Minima sehen können, die den vier möglichen aufrechten Ausrichtungen entsprechen.

Minimierungskriterium

Weitere Überlegungen: Ich bin mir nicht sicher, wie viel Golf gespielt werden kann, da die exhausive Winkelsuche viele Zeichen erfordert, und ich bezweifle, dass Sie dies mit integrierten Optimierungsmethoden so gut erreichen können, da es, wie Sie sehen, viele lokale Minima gibt das suchen wir nicht. Sie können ganz einfach die Genauigkeit (für große Bilder) verbessern , indem eine kleinere Schrittweite für die Winkel wählen und nur 90 suchen ° statt 360 ° , so dass Sie ersetzen könnte 0:360mit 0:.1:90oder somehting so. Für mich bestand die Herausforderung jedoch eher darin, einen robusten Algorithmus zu finden, als Golf zu spielen, und ich bin mir sicher, dass die Einträge in den Golfsprachen meine Einsendung weit hinter sich lassen werden =)

PS: Jemand sollte wirklich eine Golfsprache von Matlab / Octave ableiten.

Ausgänge

Beispiel 1:

 25    39

Beispiel 2:

 25    24

Code

Golf gespielt:

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

CJam, 68 65 64 Bytes

Dies kann ein wenig mehr golfen werden ..

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

Wie es funktioniert

Die Logik ist ziemlich einfach, wenn Sie darüber nachdenken.

Alles, was wir von den Eingabekombinationen benötigen, X.sind 3 Koordinaten von zwei benachbarten Seiten. So bekommen wir sie:

First

Bei jeder Ausrichtung des Rechtecks ​​ist die erste .in der gesamten Eingabe eine der Ecken. Beispielsweise..

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

Hier ist die erste .in der 2 nd Linie, 8 th Spalte.

Aber das ist es nicht, wir müssen einige Anpassungen vornehmen und die Breite des .Laufs auf dieser Linie zu den Koordinaten hinzufügen , um die Koordinate des rechten Endes zu erhalten.

Second

Wenn wir das obige Rechteck transponieren (in Zeilenumbrüchen gedreht), nimmt die linke untere Ecke den Platz des obigen Schritts ein. Aber hier kompensieren wir die .Lauflänge nicht, da wir uns sowieso gewünscht hätten, die untere linke Koordinate der Kante zu erhalten (die in transponierter Form immer noch die erste sein wird, auf die wir stoßen .).

Rest two

Zum Ausruhen zweier Koordinaten drehen wir einfach das Rechteck horizontal und führen die obigen beiden Schritte aus. Eine der Ecken hier wird von den ersten beiden gemeinsam sein.

Nachdem wir alle 4 erhalten haben, berechnen wir einfach die Entfernungen.

Dies ist nicht die genaueste Methode, funktioniert jedoch innerhalb der Fehlergrenze und für alle möglichen Ausrichtungen des Rechtecks.

Code-Erweiterung (etwas veraltet)

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

Probieren Sie es hier online aus

Optimierer
quelle
Versuchen Sie es mit einer Rastergröße von 50 x 50, einer Rechteckgröße von 45 x 45 und einem Winkel -2. Der Fehler liegt bei 28%. Ich habe einen ähnlichen Ansatz ausprobiert (es war meine ursprüngliche Idee, bevor ich mich mit Ihrer befasst habe), und es stellte sich heraus, dass es schwieriger als erwartet war, genau genug zu sein, insbesondere wenn die Seiten in der Nähe von horizontal / vertikal sind. Funktioniert gut, wenn sie näher an der Diagonale liegen. Ich denke, dies erfordert entweder mehr Logik (z. B. auch die Suche nach Extremen in diagonaler Richtung) oder einen völlig anderen Ansatz.
Reto Koradi
@RetoKoradi Oh. Das liegt nur daran, dass für alle negativen Winkel die .Breitenanpassung an der zweiten statt an der ersten Koordinate erforderlich ist . Wird reparieren. Sollte kurz sein.
Optimierer
1
@RetoKoradi sollte jetzt behoben sein.
Optimierer
Probieren Sie das 40x24 Rechteck mit Winkel 0.
Reto Koradi
@RetoKoradi Gute Punkte. Vorerst nicht akzeptiert.
Calvins Hobbys
5

Python 3, 347 337 Bytes

Dies fiel schwerer aus als ich erwartet hatte. In Arbeit...

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

Definiert eine Funktion, fdie den String als Argument verwendet und das Ergebnis an STDOUT ausgibt.

Pyth, 87 84 82 81 75 72 71 Bytes

(MÖGLICHERWEISE UNGÜLTIG, UNTERSUCHUNG, WENN ICH NACH HAUSE KOMME)

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

Weg noch zu lang. Grundsätzlich ein Port des Vorgängers. Pyths .aeuklidische Distanz lieben . Übernimmt die Eingabe über STDIN und gibt die Ausgabe über STDOUT aus. Erwartet, dass das Nicht-Rechteck-Zeichen in Kleinbuchstaben geschrieben wird x(also alles mit einem ASCII-Wert von 98 oder mehr).

Algorithmus

Beide verwenden den gleichen Algorithmus. Ich beginne im Grunde genommen mit einem Array, das den Massenmittelpunkt des Rechteckbereichs enthält. Ich füge dann drei Punkte zum Array aller Punkte im Rechteck hinzu und wähle immer den Punkt mit der maximalen Summe der Abstände zu den bereits im Array vorhandenen Punkten. Das Ergebnis sind immer drei Punkte in verschiedenen Ecken des Rechtecks. Ich berechne dann einfach alle drei Abstände zwischen diesen drei Punkten und nehme die zwei kürzesten.

PurkkaKoodari
quelle
Die Pyth-Lösung funktioniert überhaupt nicht. Die beiden Beispiele aus dem OP geben die Ergebnisse [33.0, 59.0]statt [40, 24]und [39.0, 54.0]statt [24.0, 24.5].
Jakube
@ Jakube Weird. Ich werde nachforschen, sobald ich nach Hause komme. Leider bin ich bis zum 9. Juni auf Klassenreise nach Lappland.
PurkkaKoodari
Ich würde leider keine Reise nach Lappland
anrufen ;-)
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

Dies wurde vom Algorithmus von @ Pietu1998 inspiriert. Es geht darum, eine Ecke als den Punkt zu bestimmen, der am weitesten vom Zentrum entfernt ist, unterscheidet sich jedoch von dort:

  • Ich bestimme die zweite Ecke als den Punkt mit dem größten Kreuzprodukt mit dem Vektor von der Mitte zur ersten Ecke. Dies gibt den Punkt mit dem größten Abstand von der Linie von der Mitte zur ersten Ecke.
  • Es ist nicht erforderlich, nach einer dritten Ecke zu suchen, da dies nur das Spiegelbild der zweiten Ecke relativ zur Mitte ist.

Der Code folgt also dieser Sequenz:

  • Die erste Schleife verläuft über den Linien in der Eingabe und erstellt eine Liste rmit Rechteckpunkten.
  • Die zweite Schleife berechnet den Durchschnitt aller Rechteckpunkte und gibt die Mitte des Rechtecks ​​an.
  • Die dritte Schleife findet den Punkt, der am weitesten vom Zentrum entfernt ist. Dies ist die erste Kurve. Gleichzeitig wird der Mittelpunkt von den Punkten in der Liste abgezogen, sodass die Punktkoordinaten für die verbleibende Berechnung relativ zum Mittelpunkt sind.
  • Die vierte Schleife findet den Punkt mit dem größten Kreuzprodukt mit dem Vektor zur ersten Ecke. Dies ist die zweite Ecke.
  • Druckt den Abstand zwischen der ersten Ecke und der zweiten Ecke sowie den Abstand zwischen der ersten Ecke und dem Spiegelbild der zweiten Ecke aus.
  • 1.0wird zu den Entfernungen hinzugefügt, da die ursprünglichen Entfernungsberechnungen Pixelindizes verwenden. Wenn Sie beispielsweise 5 Pixel haben, betrug die Differenz zwischen dem Index des letzten und des ersten Pixels nur 4, was im Endergebnis ausgeglichen werden muss.

Präzision ist ziemlich gut. Für die beiden Beispiele:

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

Python 2, 272 Bytes

Posten Sie dies als separate Antwort, da es sich um einen völlig anderen Algorithmus handelt als meinen vorherigen:

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

Dieser Ansatz identifiziert überhaupt keine Ecken. Es basiert auf der Beobachtung, dass die Größe (Breite und Höhe) des Begrenzungsrahmens und der Bereich des gedrehten Rechtecks ​​ausreichen, um die Breite und Höhe des Rechtecks ​​zu bestimmen.

Wenn Sie auf einer Skizze betrachten, ist es ziemlich einfach , die Breite (zu berechnen wb) und Höhe ( hb) des Begrenzungsrahmens mit w/ hdie Größe des Rechtecks und pder Drehwinkel:

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

wbund hbkann direkt aus dem Bild extrahiert werden. Wir können die Gesamtfläche ades Rechtecks auch schnell extrahieren, indem wir die Anzahl der ..Pixel zählen. Da es sich um ein Rechteck handelt, erhalten wir die zusätzliche Gleichung:

a = w * h

So haben wir drei Gleichungen mit drei Unbekannten ( w, hund p), die die Unbekannten bestimmen genug ist. Das einzige Problem ist, dass die Gleichungen trigonometrische Funktionen enthalten, und zumindest mit meiner Geduld und meinen mathematischen Fähigkeiten kann das System nicht einfach analytisch gelöst werden.

Was ich implementiert habe, ist eine Brute-Force-Suche nach dem Winkel p. Sobald pgegeben ist, werden die ersten beiden obigen Gleichungen zu einem System von zwei linearen Gleichungen, die für wund aufgelöst werden können 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))

Mit diesen Werten können wir dann w * hmit dem gemessenen Bereich des Rechtecks ​​vergleichen. Die beiden Werte wären idealerweise irgendwann gleich. Dies wird in der Gleitkomma-Mathematik natürlich nicht passieren.

Der Wert von w * hnimmt mit zunehmendem Winkel ab. Wir beginnen also bei Winkel 0.0 und erhöhen den Winkel dann in kleinen Schritten, bis das erste Mal w * hkleiner als der gemessene Bereich ist.

Der Code besteht nur aus zwei Hauptschritten:

  1. Extrahieren Sie die Größe des Begrenzungsrahmens und des Rechteckbereichs aus der Eingabe.
  2. Bewerberwinkel durchlaufen, bis das Abbruchkriterium erreicht ist.

Die Genauigkeit der Ausgabe ist gut für Rechtecke, bei denen Breite und Höhe erheblich voneinander abweichen. Bei Rechtecken, die fast quadratisch und fast um 45 Grad gedreht sind, wird es etwas zweifelhaft, und die 7% -Fehlerhürde für Testbeispiel 2 wird kaum überwunden.

Die Bitmap für Beispiel 2 sieht tatsächlich etwas seltsam aus. Die linke Ecke sieht verdächtig langweilig aus. Wenn ich an der linken Ecke ein Pixel mehr hinzufüge, sieht beides (für mich) besser aus und liefert eine viel bessere Präzision für diesen Algorithmus.

Reto Koradi
quelle