Oberleitung zwischen zwei Punkten (hängende Kette)

8

Dies ist eine von mehreren Herausforderungen, die Calvins Hobbys für die Community hinterlassen haben .

Die Kurve, die ein idealisiertes hängendes Seil oder eine idealisierte Kette macht, ist eine Oberleitung .

Eine Kette, die eine Oberleitung bildet
Bild von Bin im Garten, über Wikimedia Commons. Wird unter der CC-By-SA 3.0- Lizenz verwendet.

Schreiben Sie ein Programm, das eine Oberleitung als Bild in Quadrant 1 der Ebene mit zwei Punkten (x 1 , y 1 ) , (x 2 , y 2 ) und der "Seillänge" L zeichnet . L ist größer als der Abstand zwischen den beiden Punkten.

Sie müssen für die Skalierung auch Achsen auf der linken und unteren Seite des Bildes (mindestens 400 x 400 Pixel) zeichnen. Zeichnen Sie den Quadranten nur von x und y im Bereich von 0 bis 100. (Sie können davon ausgehen, dass sich die Punkte im Bereich befinden.)

An den Endpunkten (x 1 , y 1 ) , (x 2 , y 2 ) sollten Punkte oder ähnliches gezeichnet werden , um sie zu unterscheiden. Die Kurve sollte nur im Raum zwischen diesen Punkten gezeichnet werden.

Absinth
quelle
Wie genau müssen wir sein? Muss das Bild Anti-Aliasing sein? Wie breit muss / kann die Linie sein?
Sparr
Wir gehen auch davon aus, dass die Kurve selbst (nicht nur die Punkte) im Bereich liegt, oder? Oder würden wir zwei von der Achse geschnittene Bögen zeichnen, wenn sie darunter liegen?
Geobits
@Sparr Das Bild muss nicht gegen Alias ​​ausgerichtet sein. Die Linie muss mindestens 1 Pixel dick sein. Die Oberleitung sollte so genau sein, wie es die Gleitkomma-Arithmetik Ihrer Sprache kann.
Absinth
5
Ich wollte dies tun, bis mir klar wurde, dass die Mathematik etwas komplexer sein könnte als meine aktuelle Vorberechnung. Vielleicht nächstes Jahr.
Stretch Maniac
1
@BetaDecay Ich weiß nicht was das ist. Sagen wir seine 0.
Absinth

Antworten:

5

Python + NumPy + Matplotlib, 1131

Um uns den Einstieg zu erleichtern, hier ein Versuch, bei dem keine anderen Kenntnisse der Analysis oder Physik verwendet werden als die Tatsache, dass die Oberleitung die Energie einer Kette minimiert. Hey, mein Algorithmus ist vielleicht nicht effizient, aber zumindest nicht effizient implementiert!

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
quelle
3

BBC Basic, 300 ASCII-Zeichen, Token-Dateigröße 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

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

Dies wurde offensichtlich schon früher gelöst, also habe ich als erstes nachgesehen, was andere getan haben.

Die Gleichung einer am Ursprung zentrierten Oberleitung ist einfach y=a*cosh(x/a). Es wird etwas komplizierter, wenn es nicht am Ursprung zentriert ist.

Verschiedene Quellen sagen, dass, wenn die Länge und die Endpunkte bekannt sind, der Wert für anumerisch bestimmt werden muss. hDer Wikipedia-Artikel enthält einen nicht angegebenen Parameter . Also fand ich eine andere Site und folgte im Grunde der Methode hier: http://www.math.niu.edu/~rusin/known-math/99_incoming/catenary

BBC Grund hat nicht sinhund coshintegriert, so dass ich am Ende des Programms zwei Funktionen definiert , sie berechnen mitEXP

Die Koordinaten für den linken Punkt müssen vor dem rechten Punkt angegeben werden. OP hat bestätigt, dass dies in Ordnung ist. Länge wird zuletzt angegeben. Werte können durch Kommas oder Zeilenumbrüche getrennt werden.

Ungolfed Code

  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

Geben Sie hier die Bildbeschreibung ein

Level River St.
quelle
1

Python 2.7 + matplotlib, 424

Rennen wie

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

Wenn ich davon ausgehen kann, dass x0 immer kleiner als x1 ist, reduziert sich die Anzahl der Zeichen auf 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()

Die magische Zahl 600, die an einigen Stellen erscheint, ist auf die Tatsache zurückzuführen, dass cosh (x) und sinh (x) um x = 710 überlaufen (also 600, um einen gewissen Spielraum beizubehalten).

Grundsätzlich löse ich das Problem in dem Frame, in dem die Oberleitung durch (0,0) und (x1-x0, (y1-y0) / (x1-x0)) verläuft, und ordne sie dann dem ursprünglichen Frame neu zu. Dies verbessert die numerische Stabilität erheblich .

Kamelthemammel
quelle