2点間の懸垂線(吊り鎖)


8

これは、Calvin's Hobbiesがコミュニティに残したいくつかの課題の 1つです。

理想的な吊りロープまたはチェーンが作る曲線は、懸垂線です。

カテナリーを形成する鎖
画像はBin im Garten、Wikimedia Commons経由。CC-By-SA 3.0ライセンスの下で使用されます。

2つの点(x 1、y 1(x 2、y 2、および「ロープの長さ」Lを指定して、平面の象限1にカテナリーをイメージとして描画するプログラムを記述します。Lは2点間の距離より大きくなります。

また、拡大縮小のために、画像の左側と下側(最小400x400 px)に軸を描画する必要があります。0から100の範囲のxとyからのみ象限を描画します(ポイントは範囲内にあると想定できます)。

(x 1、y 1(x 2、y 2)の端点に点または類似の点を描画して、それらを区別する必要があります。曲線は、これらのポイント間のスペースにのみ描画されます。


どの程度正確でなければなりませんか?画像はアンチエイリアス処理する必要がありますか?ラインの幅はどのくらい必要ですか?
Sparr

また、(点だけでなく)曲線自体が範囲内にあると仮定しますよね?それとも、それより下になると、軸によってカットされた2つの円弧を描画しますか?
Geobits

Sparr画像にアンチエイリアスを適用する必要はありません。線は少なくとも1pxの太さでなければなりません。カテナリーは、言語の浮動小数点演算と同じくらい正確でなければなりません。
アブサン

5
数学が現在の計算前よりも少し複雑かもしれないことに気づくまで、私はこれを行うつもりでした。たぶん来年。
ストレッチマニアック2014

1
@BetaDecay私はそれが何であるか知りません。その0としましょう
Absthethe

回答:


5

Python + NumPy + Matplotlib、1131

私たちを始めるために、ここでは、懸垂線がチェーンのエネルギーを最小化するという事実以外に、微積分学や物理学の知識を使用しない試みがあります。ねえ、私のアルゴリズムは効率的ではないかもしれませんが、少なくとも効率的に実装されていません!

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

3

BBC Basic、300 ASCII文字、トークン化されたファイルサイズ260

  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

エミュレーター(http://www.bbcbasic.co.uk/bbcwin/bbcwin.html)

これは明らかに以前に解決されたので、私が最初に行ったのは、他の人が行ったことを確認することでした。

原点を中心とするカテナリーの方程式は単純y=a*cosh(x/a)です。原点を中心にしないと、少し複雑になります。

さまざまな情報源によると、長さと端点がわかっている場合、の値はa数値で決定する必要があります。hウィキペディアの記事に未指定のパラメーターがあります。だから私は別のサイトを見つけて、基本的にここの方法に従いました:http : //www.math.niu.edu/~rusin/known-math/99_incoming/catenary

BBC Basicには組み込みsinhcosh組み込みがないため、プログラムの最後に2つの関数を定義して、EXP

左側の点の座標を右側の点の前に指定する必要があります。OPはこれが問題ないことを確認しました。長さは最後に与えられます。値はコンマまたは改行で区切ることができます。

ゴルフではないコード

  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

ここに画像の説明を入力してください


1

Python 2.7 + matplotlib、424

として実行

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

x0が常にx1よりも小さいと想定できる場合、文字数は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()

一部の場所に表示されるマジックナンバー600は、cosh(x)とsinh(x)がx = 710付近でオーバーフローし始めるためです(ある程度のマージンを保つために600)

基本的に、カテナリーが(0,0)および(x1-x0、(y1-y0)/(x1-x0))を通過するフレームで問題を解決してから、元のフレームに再マッピングします。これにより、数値の安定性が大幅に向上します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.