Pusat-pusat segitiga

13

Lingkaran dan bujur sangkar memiliki satu titik pusat yang pasti. Namun, gagasan tentang pusat segitiga telah lama dibahas. Empat pusat yang berbeda diketahui oleh orang Yunani Kuno:

  • Incenter : Persimpangan dari garis-bagi sudut segitiga
  • Centroid : Perpotongan garis-garis dari setiap sudut segitiga ke tengah sisi yang berlawanan
  • Circumcenter : Perpotongan garis-garis tegak lurus sisi
  • Orthocenter : Persimpangan ketinggian segitiga

Euler kemudian membuktikan bahwa centroid, circumcenter dan orthocenter adalah collinear dalam segitiga apa pun. Garis di mana ketiga titik ini berada dalam segitiga disebut Garis Euler . Ini didefinisikan untuk setiap segitiga kecuali segitiga sama sisi, di mana semua titik bertepatan.

Tantangan Anda adalah membuat program atau fungsi terpendek yang, ketika diberi dua input, menghasilkan pusat tertentu atau Garis Euler pada segitiga. Yang pertama menentukan koordinat masing-masing simpul dari sebuah segitiga. Yang kedua adalah bilangan bulat dari 1 hingga 5, menentukan apa yang akan dihasilkan.

1 - Incenter
2 - Centroid
3 - Circumcenter
4 - Orthocenter
5 - Equation of Euler Line
    (if the Euler Line is vertical, output the `x` value of the line
      (e.g. output `5` if the equation of the line is `x = 5`))

Anda dapat mengasumsikan bahwa simpul yang diberikan tidak akan pernah menjadi linear, dan bahwa mereka akan selalu menjadi koordinat bilangan bulat (ini juga mengecualikan kemungkinan memiliki segitiga sama sisi sebagai input, sesuai komentar @Kap ).

Array input harus berupa array bertingkat yang valid dalam bahasa Anda, dan input harus dalam format apa pun yang masuk akal. Nilai float apa pun harus ditampilkan ke setidaknya 3 tempat desimal, tetapi tidak kurang. Titik keluaran harus berupa array yang valid dalam bahasa Anda, cocok dengan format input.


Kasus uji:

Input: [(-2, 0), (1, 0), (0, 1)] 1
Output: (-0.089, 0.451)

Input: [(-2, 0), (1, 0), (0, 1)] 2
Output: (-0.333, 0.333)

Input: [(-2, 0), (1, 0), (0, 1)] 3
Output: (-0.5, -0.5)

Input: [(-2, 0), (1, 0), (0, 1)] 4
Output: (0, 2)

Input: [(-2, 0), (1, 0), (0, 1)] 5
Output: 5x + 2

Klarifikasi: Masukan dapat dari stdin, spasi atau baris baru dipisahkan, atau sebagai argumen untuk suatu fungsi. Outputnya, bagaimanapun, harus ditulis ke stdout.

Keriangan
sumber
1
Saya takut formula eksplisit untuk penyunat dan orthocenter dalam koordinat kartesius cukup jelek. Jika saya menggunakan cara membuat koordinat trilinear / barycentric => carthesian umum, incenter keluar hampir bebas. Lihat en.wikipedia.org/wiki/Trilinear_coordinates#Examples . Apakah saya mendapatkan poin tambahan untuk mengimplementasikannya?
John Dvorak
Apa format output yang valid untuk garis Euler? Jika vertikal, itu tidak dapat dinyatakan sebagai y=f(x).
John Dvorak
1
(berikan komentar jika Anda tidak setuju) Silakan gunakan kotak pasir jika Anda tidak yakin apakah tantangannya ok atau tidak. Di sana Anda dapat meminta komentar dan memperbaiki pertanyaan sampai cocok. Setelah diposting di sini itu tidak boleh diubah sehubungan dengan konten. Beberapa orang mungkin sudah mengerjakannya - dan tidak suka memindahkan target.
Howard
1
"Ketika mengeluarkan sebuah titik, koordinat harus ... dikelilingi dalam tanda kurung bulat (())". Mengapa persyaratan ini? Dalam beberapa bahasa, poin direpresentasikan dalam kurung keriting. Dan sesuatu seperti (12, -2) hanya dapat direpresentasikan sebagai string, dalam hal ini elemen-elemen itu sendiri ditafsirkan sebagai string daripada angka.
DavidC
1
Anda mungkin ingin membuatnya bahwa input dapat berupa koordinat titik mengambang, atau sepenuhnya dihapus (if the triangle is equilateral, output the point at which the centers meet)karena tidak mungkin untuk membuat segitiga sama sisi pada bidang koordinat menggunakan hanya koordinat bilangan bulat.
R. Kap

Jawaban:

2

Python - 908 870

Baris baru ditambahkan untuk mengurangi pengguliran. Ini mungkin bisa golf lebih lanjut.

from math import*;t=eval(input());p=int(input())-1;
r=[];A,B,C=t[0],t[1],t[2];
a,b,c=hypot(B[0]-C[0],B[1]-C[1]),hypot(A[0]-C[0],A[1]-C[1]),hypot(A[0]-B[0],A[1]-B[1]);
r.append(((a*A[0]+b*B[0]+c*C[0])/(a+b+c),(a*A[1]+b*B[1]+c*C[1])/(a+b+c)));
r.append(((A[0]+B[0]+C[0])/3,(A[1]+B[1]+C[1])/3));d,e,f=(0,0),(B[0]-A[0],B[1]-A[1]),(C[0]-A[0],C[1]-A[1]);g=2*(e[0]*f[1]-e[1]*f[0]);
r.append(((f[1]*(e[0]**2+e[1]**2)-e[1]*(f[0]**2+f[1]**2))/g+A[0],(e[0]*(f[0]**2+f[1]**2)- f[0]*(e[0]**2+e[1]**2))/g+A[1]));
h=acos((b*b+c*c-a*a)/(2*b*c));i=acos((a*a+c*c-b*b)/(2*a*c));j=acos((a*a+b*b- c*c)/(2*a*b));k=cos(i)*cos(j);
l=cos(h)*cos(j);m=cos(h)*cos(i);r.append(((a*k*A[0]+b*l*B[0]+c*m*C[0])/(a*k+b*l+c*m),(a*k*A[1]+b*l*B[1]+c*m*C[1])/(a*k+b*l+c*m)));
n,o=r[1][0]-r[2][0],r[1][1]-r[2][1];q=r[1][1]-o/n*r[1][0]if n!=0 else 0;
r.append(r[1]if a==b==c else("x="+str(r[1][0])if n==0 else"".join([str(o/n),"x+(",str(q),")"])));print(r[p])

Kasus uji (beranotasi):

Input: [(-2, 0), (1, 0), (0, 1)]
1
Output: (-0.08907279243665268, 0.45110872103880023) --> More digits than in question

Input: [(-2, 0), (1, 0), (0, 1)]
2
Output: (-0.3333333333333333, 0.3333333333333333) --> More digits than in question

Input: [(-2, 0), (1, 0), (0, 1)]
3
Output: (-0.5, -0.5)

Input: [(-2, 0), (1, 0), (0, 1)]
4
Output: (-1.1702778228588997e-16, 1.9999999999999984) --> More digits than shown in question

Input: [(-2, 0), (1, 0), (0, 1)]
5
Output: 4.999999999999999x+(1.9999999999999996) --> More digits than in question

Seperti yang Anda lihat, ada kemungkinan kesalahan yang disebabkan oleh penggunaan floating point.


Golf selanjutnya:

Berdasarkan saran dalam komentar di bawah ini, saya berhasil membuatnya lebih kecil.

from math import*;I=input;t=eval(I());p=int(I())-1;r=[];A,B,C=t[0],t[1],t[2];R,H,D,S,T=r.append,hypot,cos,acos,str;a,b,c=H(B[0]-C[0],B[1]-C[1]),H(A[0]-C[0],A[1]-C[1]),H(A[0]-B[0],A[1]-B[1]);R(((a*A[0]+b*B[0]+c*C[0])/(a+b+c),(a*A[1]+b*B[1]+c*C[1])/(a+b+c)));R(((A[0]+B[0]+C[0])/3,(A[1]+B[1]+C[1])/3));d,e,f=(0,0),(B[0]-A[0],B[1]-A[1]),(C[0]-A[0],C[1]-A[1]);g=2*(e[0]*f[1]-e[1]*f[0]);R(((f[1]*(e[0]**2+e[1]**2)-e[1]*(f[0]**2+f[1]**2))/g+A[0],(e[0]*(f[0]**2+f[1]**2)-f[0]*(e[0]**2+e[1]**2))/g+A[1]));h=S((b*b+c*c-a*a)/(2*b*c));i=S((a*a+c*c-b*b)/(2*a*c));j=S((a*a+b*b-c*c)/(2*a*b));k=D(i)*D(j);l=D(h)*D(j);m=D(h)*D(i);R(((a*k*A[0]+b*l*B[0]+c*m*C[0])/(a*k+b*l+c*m),(a*k*A[1]+b*l*B[1]+c*m*C[1])/(a*k+b*l+c*m)));n,o=r[1][0]-r[2][0],r[1][1]-r[2][1];q=r[1][1]-o/n*r[1][0]if n!=0else 0;R(r[1]if a==b==c else("x="+T(r[1][0])if n==0else"".join([T(o/n),"x+(",T(q),")"])));print(r[p])
pegolf9338
sumber
Saya pikir itu sebenarnya 907 byte. (URL disingkat).
Erik the Outgolfer
1
Bisakah Anda melakukan sesuatu seperti R=r.appenddan kemudian menggunakannya untuk menghemat byte?
FlipTack
1

AutoHotkey - 731

f(z, r:=1){
static 1:="i",2:="m",3:="c",4:="o"
r := %r%,mx :=(z.1.1+z.2.1+z.3.1)/3,my:=(z.1.2+z.2.2+z.3.2)/3
s:=(c:=sqrt((z.2.1-z.1.1)**2+(z.2.2-z.1.2)**2))+(a:=sqrt((z.3.1-z.2.1)**2+(z.3.2-z.2.2)**2))+(b:=sqrt((z.3.1-z.1.1)**2+(z.3.2-z.1.2)**2))
ix:=(a*z.1.1+b*z.2.1+c*z.3.1)/s,iy:=(a*z.1.2+b*z.2.2+c*z.3.2)/s
midx_a:=(z.3.1+z.2.1)/2,midy_a:=(z.3.2+z.2.2)/2,m:=-1*(z.3.1-z.2.1)/(z.3.2-z.2.2),cc_a:=midy_a-(m*midx_a)
midx_b:=(z.3.1+z.1.1)/2,midy_b:=(z.3.2+z.1.2)/2,n:=-1*(z.3.1-z.1.1)/(z.3.2-z.1.2),cc_b:=midy_b-(n*midx_b)
cx:=(cc_b-cc_a)/(m-n),cy:=cc_a+(m*cx),oc_a:=z.1.2-(m*z.1.1),oc_b:=z.2.2-(n*z.2.1),ox:=(oc_a-oc_b)/(n-m),oy:=oc_a+(m*ox)
if r in m,i,c,o
return [%r%x, %r%y]
else return "y=" (m:=(oy-cy)/(ox-cx)) "x+" oy-m*ox
}

Fungsi ini dapat lebih diperkecil (sekitar 600 karakter atau kurang) dengan memperpendek nama variabel seperti midx_a, midx_b, dan sebagainya.

Memanggil fungsi

d:=f([[-2, 0], [1, 0], [0, 1]], 1)
for k,v in d
    msgbox % k "`n" v
Avi
sumber
1

Python 3.5, 851 772 byte:

def H(z,a,b,l):c=complex;T=lambda A,B:abs(c(*A)-c(*B));d=T(z,a);e=T(z,b);f=T(a,b);g=[((a[0]+b[0])/2,(a[1]+b[1])/2)for a,b in[[a,b],[z,a],[b,z]]];E=(z[0]+a[0]+b[0])/3;F=(z[1]+a[1]+b[1])/3;m=lambda f:[(a,0)if(b[1][0]-b[0][0])==0else(a,-1/((b[1][1]-b[0][1])/(b[1][0]-b[0][0])))if(b[1][1]-b[0][1])else''for a,b in zip(f,[[a,b],[z,a],[b,z]])];i=[u for u in m(g)if u!=''];C=i[0][1];D=i[0][0][1]-(C*i[0][0][0]);A=i[1][1];B=i[1][0][1]-(A*i[1][0][0]);G=(B-D)/(C-A);H=C*G+D;j=[u for u in m([z,b,a])if u!=''];C=j[0][1];D=j[0][0][1]-(C*j[0][0][0]);A=j[1][1];B=j[1][0][1]-(A*j[1][0][0]);I=(B-D)/(C-A);J=C*I+D;K,L=[((d*b[o])+(e*a[o])+(f*z[o]))/sum([d,e,f])for o in[0,1]];a=(H-J)/(G-I)if(G-I)else'';b=H-(a*G)if a!=''else G;print(['',(K,L),(E,F),(G,H),(I,J),[b,'%sx+%s'%(a,b)][a!='']][l])

Mengambil input sebagai urutan koordinat yang dipisahkan koma, diikuti oleh integer yang menyampaikan apa yang akan ditampilkan. Misalnya, jika koordinat input adalah (1,0),(2,1),(1,4)dan Anda ingin orthocenter dari segitiga sesuai dengan koordinat tersebut, Anda cukup memanggil fungsi seperti:

H((1,0),(2,1),(1,4),4)

Output dalam format tuple jika titik tertentu diperlukan, dalam format string dengan persamaan dalam bentuk y=mx+bjika garis Euler diperlukan dan garis tidak vertikal, atau hanya xnilai garis jika garis Euler adalah diperlukan tapi garis adalah vertikal.

Jadi, menggunakan segitiga dengan simpul (1,0),(2,1),(1,4), outputnya adalah:

1. Incenter: (1.4663911961440428, 1.125967951102358)
2. Centroid: (1.3333333333333333, 1.6666666666666667)
3. Circumcenter: (0.0, 2.0)
4. Orthocenter: (4.0, 1.0)
5. Euler Line: -0.25x+2.0 

Saya akan mencoba bermain golf ini lebih dari waktu di mana dan kapan saya bisa.

Cobalah secara Online! (Ideone)

R. Kap
sumber