Fehler in Python bei einfachen Geradenfunktionen? Perl kanns

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
yanone
User
Beiträge: 7
Registriert: Freitag 12. Januar 2007, 01:05

Hallo liebes Python-Forum.

Ich schlage mich seit anderthalb Tagen mit einem problem herum. Ich bin Schriftgestalter und möchte aus einem einfachen, auf einem Raster basierenden Buchstaben, der eine Vektorgrafik ist, einen dreidimensionalen Turm bauen. Das Schriftenprogramm FontLab hat eine Python-Schnittstelle.

Im konkreten geht es aber nur um einfache Geradenfunktionen aus dem Gymnasium, genauer um den Schnittpunkt zweier Geraden (s. roter Kreis). Ich brauche diese Schnittpunkte, weil Vektorgrafiken in Schriften keine "unendliche" Genauigkeit haben, sondern die Zeile nur 1000 em-Einheiten hoch ist und sich jeder Punkt auf diesem relativ groben Raster befindet. So kommt es an manchen Stellen zu Ungenauigkeiten, wenn ein Punkt über einer Geraden liegen soll. Wenn ich an der selben Stellen auf der Geraden aber noch einen Punkt einfüge, macht die Gerade zwar einen minimalen Umweg (unsichtbar), dafür liegen beide Punkte dann exakt übereinander.

Bild

Gerade 1 wird definiert durch die Punkte k1 und k2, die zweite Gerade wird definiert durch den Punkt d und die negative Steigung der blauen Hilfslinie (FontLab kann schiefe Hilfslinien). Der Schnittpunkt soll errechnet werden. Ich habe dazu die normalen Formeln aus der Schule benutzt:

y = m * x + n

bzw.

m = (y2 - y1) / (x2 - x1)

bzw.

n = y - m * x

Ich habe den Abschnitt mal in Python und in Perl isoliert. Die anfangs angegebenen Variablen werden eigentlich zuvor in einer Iteration aus einer Liste geladen. Hier der Einfachheit halber direkt als Variablen.
Um das Ergebnis schonmal vorweg zu nehmen: Perl kann's, Python nicht. Der Hund liegt schon bei der Steigung bzw. Nullpunkt der ersten Geraden (Zeile 24 und 25) begraben.
Das richtige Ergebnis, das ich auch mit dem Taschenrechner per Hand herausbekomme ist (274, 128)
Am Ende werden alle benutzten Variablen zur Überprüfung ausgegeben. Die beiden letzten Werte xp und yp sind der Schnittpunkt.

Code: Alles auswählen

import math

# Gerade 1 wird definiert durch die beiden Punkte k1 und k2
xk1 = 324
yk1 = 215
xk2 = 200
yk2 = 0
# Gerade 2 wird definiert durch den punkt d und die negative Steigung
xd = 224
yd = 215

neigungswinkel = 30
richtung = 1  # 1 oder -1 (Nach links oder rechts geneigt)

# Errechnung der x und y Werte durch Definitionen am rechtwinkligen Dreieck
# sin(alpha) = a / c bzw. cos(alpha) = b / c
def xoffset(c):
	return math.cos((90 - neigungswinkel) * math.pi / 180) * c
def yoffset(c):
	return math.sin((90 - neigungswinkel) * math.pi / 180) * c

# Geradenfunktionen

# Fkt durch zwei Punkte auf der Kontur (k)
mk = (yk2 - yk1) / (xk2 - xk1) * richtung
nk = yk1 - mk * xk1
# Fkt durch Punkt und schräge Hilfslinie
md = yoffset(500) / xoffset(500) * -richtung
nd = yd - md * xd

# Gleichsetzung der beiden Geradengleichungen
xp = (nd - nk) / (mk - md) # Nach x aufgelöst
yp = md * xp + nd # y = f(x)

# Achtung, dilletantisch per Hand umgebrochen
print "xk1(" + str(xk1) + ") yk1(" +  str(yk1) + ") xk2(" +  str(xk2) + \
") yk2(" + str(yk2) + ") xd(" + str(xd) + ") yd(" + str(yd) + ") mk(" + \
str(mk) + ") nk(" +  str(nk) + ") md(" +  str(md) + ") nd(" + str(nd) + \
") xp(" + str(math.floor(xp)) + ") yp(" + str(math.floor(yp)) + ")"
Ausgabe:

Code: Alles auswählen

xk1(324) yk1(215) xk2(200) yk2(0) xd(224) yd(215) mk(1) nk(-109) \
md(-1.73205080757) nd(602.979380895) xp(260.0) yp(151.0)
Perl:

Code: Alles auswählen

#!/usr/bin/perl

# Gerade 1 wird definiert durch die beiden Punkte k1 und k2
$xk1 = 324;
$yk1 = 215;
$xk2 = 200;
$yk2 = 0;
# Gerade 2 wird definiert durch den punkt d und die negative Steigung
$xd = 224;
$yd = 215;

$neigungswinkel = 30;
$richtung = 1;  # 1 oder -1 (Nach links oder rechts geneigt)

# Errechnung der x und y Werte durch Definitionen am rechtwinkligen Dreieck
# sin(alpha) = a / c bzw. cos(alpha) = b / c
$pi = 3.141635;
sub xoffset
	{ $c = shift; return (cos((90 - $neigungswinkel) * $pi / 180) * $c); }
sub yoffset
	{ $c = shift; return (sin((90 - $neigungswinkel) * $pi / 180) * $c); }

# Geradenfunktionen

# Fkt durch zwei Punkte auf der Kontur (k)
$mk = ($yk2 - $yk1) / ($xk2 - $xk1) * $richtung;
$nk = $yk1 - $mk * $xk1;
# Fkt durch Punkt und schräge Hilfslinie
$md = yoffset(500) / xoffset(500) * -$richtung;
$nd = $yd - $md * $xd;

# Gleichsetzung der beiden Geradengleichungen
$xp = ($nd - $nk) / ($mk - $md); # Nach x aufgelöst
$yp = $md * $xp + $nd; # y = f(x)

# Achtung, dilletantisch per Hand umgebrochen
print "xk1(" . $xk1 . ") yk1(" .  $yk1 . ") xk2(" .  $xk2 . ") yk2(" . \
$yk2 . ") xd(" . $xd . ") yd(" . $yd . ") mk(" . $mk . ") nk(" .  $nk . ") \
md(" .  $md . ") nd(" . $nd . ") xp(" . int($xp) . ") yp(" . int($yp) . ")";
Ausgabe:

Code: Alles auswählen

xk1(324) yk1(215) xk2(200) yk2(0) xd(224) yd(215) mk(1.73387096774194) nk(-346.774193548387) \
md(-1.73210727082961) nd(602.992028665833) xp(274) yp(128)
Ich bin sprachlos und weiß mir nicht mehr zu helfen. Das ganze im FontLab per Hand zu bauen würde gehe, wäre aber viel zu viel Arbeit. Vor allem aber habe ich noch nie solche Fehler in Programmiersprachen entdeckt.
Vielen Dank an Jeden, der hier mal draufschauen will.
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi!

In Python ist 3/2 = 1 (integer / integer = integer) :)
Versuchs mal mit

Code: Alles auswählen

xk1 = 324.
yk1 = 215.
xk2 = 200.
yk2 = 0.
xd = 224.
yd = 215.
neigungswinkel = 30.
yanone hat geschrieben:Ich bin sprachlos
Jetzt gehts aber wieder, oder? :)

Gruß, mawe
yanone
User
Beiträge: 7
Registriert: Freitag 12. Januar 2007, 01:05

Ich bedanke mich vielmals. Natürlich funktioniert es jetzt. Ich vermute, ich wandle meine Zahlen aus der Liste in Fließkommazahlen mit float(). Ja, funktiniert auch. Super. Danke.
Benutzeravatar
Luzandro
User
Beiträge: 87
Registriert: Freitag 21. April 2006, 17:03

du kannst auch folgenden import angeben um das erwartete Ergebnis zu bekommen:

Code: Alles auswählen

from __future__ import division
[url=http://www.leckse.net/artikel/meta/profilieren]Profilieren im Netz leicht gemacht[/url]
Antworten