Catenary Antara Dua Poin (Rantai Gantung)

8

Ini adalah salah satu dari beberapa tantangan yang tersisa untuk komunitas oleh Calvin Hobbies .

Kurva yang dibuat oleh tali atau rantai gantung yang ideal adalah catenary .

Rantai yang membentuk catenary
Gambar oleh Bin im Garten, via Wikimedia Commons. Digunakan di bawah lisensi CC-By-SA 3.0 .

Menulis sebuah program yang akan menarik catenary, seperti gambar, pada kuadran 1 dari pesawat diberikan dua poin (x 1 , y 1 ) , (x 2 , y 2 ) , dan "panjang tali" L . L akan lebih besar dari jarak antara dua titik.

Anda juga harus menggambar sumbu di sisi kiri dan bawah gambar (400x400 px min) untuk skala. Hanya gambar kuadran dari x dan y dalam rentang 0 hingga 100. (Anda dapat mengasumsikan poin berada dalam kisaran.)

Titik, atau sesuatu yang serupa, harus digambar pada titik akhir (x 1 , y 1 ) , (x 2 , y 2 ) untuk membedakannya. Kurva seharusnya hanya digambar di ruang antara titik-titik ini.

Absinth
sumber
Seberapa tepat kita seharusnya? Apakah gambar harus anti-alias? Seberapa lebar garis itu?
Sparr
Kami juga mengasumsikan bahwa kurva itu sendiri (bukan hanya titik) dalam jangkauan, bukan? Atau akankah kita menggambar dua busur yang dipotong oleh sumbu jika berada di bawah itu?
Geobits
@Sparr Gambar tidak harus anti-alias. Garis tebal harus minimal 1px. Catenary harus seakurat yang dapat dilakukan oleh aritmatika titik mengambang bahasa Anda.
absinth
5
Saya akan melakukan ini sampai saya menyadari bahwa matematika mungkin sedikit lebih kompleks daripada pra-kalkulus saya saat ini. Mungkin tahun depan.
Stretch Maniac
1
@ BetaDecay saya tidak tahu apa itu. Mari kita katakan 0.
absinth

Jawaban:

5

Python + NumPy + Matplotlib, 1131

Untuk memulainya, inilah upaya yang tidak menggunakan pengetahuan tentang kalkulus atau fisika selain fakta bahwa catenary meminimalkan energi rantai. Hai, algoritme saya mungkin tidak efisien, tetapi setidaknya tidak diterapkan secara efisien juga!

import math
import random
import numpy as np
import matplotlib.pyplot as plt
length, x0, y0, x1, y1 = input(), input(), input(), input(), input()
chain = np.array([[x0] + [length / 1000.]*1000, [y0] + [0.] * 1000])
def rotate(angle, x, y):
 return x * math.cos(angle) + y * math.sin(angle), -x * math.sin(angle) + y  * math.cos(angle)
def eval(chain, x1, y1):
 mysum = chain.cumsum(1)
 springpotential = 1000 * ((mysum[0][-1] - x1) ** 2 + (mysum[1][-1] - y1)  ** 2)
 potential = mysum.cumsum(1)[1][-1]
 return springpotential + potential
def jiggle(chain, x1, y1):
 for _ in xrange(100000):
  pre = eval(chain, x1, y1)
  angle = random.random() * 2 * math.pi
  index = random.randint(1,1000)
  chain[0][index], chain[1][index] = rotate(angle, chain[0][index], chain[1][index])
  if( pre < eval(chain, x1, y1)):
   chain[0][index], chain[1][index] = rotate(-angle, chain[0][index], chain[1][index])
jiggle(chain, x1, y1)
sum = chain.cumsum(1)
x1 = 2 * x1 - sum[0][-1]
y1 = 2 * y1 - sum[1][-1]
jiggle(chain, x1, y1)
sum = chain.cumsum(1)
plt.plot(sum[0][1:], sum[1][1:])
plt.show()
QuadmasterXLII
sumber
3

BBC Basic, 300 karakter ASCII, berukuran 260 file

  INPUTr,s,u,v,l:r*=8s*=8u*=8v*=8l*=8z=0REPEATz+=1E-3UNTILFNs(z)/z>=SQR(l^2-(v-s)^2)/(u-r)a=(u-r)/2/z
  p=(r+u-a*LN((l+v-s)/(l-v+s)))/2q=(v+s-l*FNc(z)/FNs(z))/2MOVE800,0DRAW0,0DRAW0,800CIRCLEu,v,8CIRCLEr,s,8FORx=r TOu
    DRAW x,a*FNc((x-p)/a)+q
  NEXT
  DEFFNs(t)=(EXP(t)-EXP(-t))/2
  DEFFNc(t)=(EXP(t)+EXP(-t))/2

Emulator di http://www.bbcbasic.co.uk/bbcwin/bbcwin.html

Ini jelas telah dipecahkan sebelumnya, jadi hal pertama yang saya lakukan adalah melihat apa yang telah dilakukan orang lain.

Persamaan catenary yang berpusat pada asal adalah sederhana y=a*cosh(x/a). Menjadi sedikit lebih rumit jika tidak berpusat pada titik asal.

Berbagai sumber mengatakan bahwa jika panjang dan titik akhir diketahui nilai untuk aharus ditentukan secara numerik. Ada parameter yang tidak ditentukan hdalam artikel wikipedia. Jadi saya menemukan situs lain dan pada dasarnya mengikuti metode di sini: http://www.math.niu.edu/~rusin/known-math/99_incoming/catenary

BBC Basic tidak memiliki sinhdan coshbawaan, jadi saya mendefinisikan dua fungsi di akhir program untuk menghitung penggunaannyaEXP

koordinat untuk titik kiri harus disediakan sebelum titik kanan, OP mengonfirmasi ini OK. Panjang diberikan terakhir. Nilai dapat dipisahkan dengan koma atau baris baru.

Kode tidak dikunci

  INPUT r,s,u,v,l

  REM convert input in range 0-100 to graphic coordinates in range 0-800 
  r*=8 s*=8 u*=8 v*=8 l*=8

  REM solve for z numerically
  z=0
  REPEAT
    z+=1E-3
  UNTIL FNs(z)/z>=SQR(l^2-(v-s)^2)/(u-r)

  REM calculate the curve parameters
  a=(u-r)/2/z
  p=(r+u-a*LN((l+v-s)/(l-v+s)))/2
  q=(v+s-l*FNc(z)/FNs(z))/2

  REM draw axes, 800 graphics units long = 400 pixels long (2 graphics units per pixel)
  MOVE 800,0
  DRAW 0,0
  DRAW 0,800

  REM draw markers at end and beginning of curve (beginning last, so that cursor is in right place for next step)
  CIRCLE u,v,8
  CIRCLE r,s,8

  REM draw curve from beginning to end
  FORx=r TOu
    DRAW x,a*FNc((x-p)/a)+q
  NEXT

  REM definitions of sinh and cosh
  DEF FNs(t)=(EXP(t)-EXP(-t))/2
  DEF FNc(t)=(EXP(t)+EXP(-t))/2

masukkan deskripsi gambar di sini

Level River St
sumber
1

Python 2.7 + matplotlib, 424

Jalankan sebagai

python thisscript.py [length] [x0] [y0] [x1] [y1]

Jika saya dapat berasumsi bahwa x0 selalu lebih kecil dari jumlah karakter x1 dikurangi menjadi 398

from numpy import *
from pylab import *
from scipy.optimize import *
import sys
c=cosh
l,p,q,u,w=map(float,sys.argv[1:])
if p>u:
 p,q,u,w=u,w,p,q
h=u-p
v=w-q
a=brentq(lambda a:(2.*h/a*sinh(0.5*a))**2-l**2-v**2,1e-20,600)
b=brentq(lambda b:c(a*(1.-b))-c(a*b)-a*v/h,-600/a,600/a)
r=linspace(p,u,100)
plot([p,u],[q,w],'ro')
plot(r,h/a*c(((r-p)/h-b)*a)-h/a*c(a*b)+q,'k-')
gca().set_xlim((0,100))
gca().set_ylim((0,100))
show()

Angka ajaib 600 yang Anda lihat muncul di beberapa tempat disebabkan oleh fakta bahwa cosh (x) dan sinh (x) mulai meluap di sekitar x = 710 (jadi 600 untuk menjaga margin)

Pada dasarnya saya memecahkan masalah dalam frame di mana catenary melewati (0,0) dan (x1-x0, (y1-y0) / (x1-x0)) dan kemudian memetakan kembali ke frame asli. Hal ini meningkatkan stabilitas numerik banyak .

camelthemammel
sumber