Fläche eines Polygons mit Teildreiecken berechnen

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
leanderto
User
Beiträge: 1
Registriert: Mittwoch 24. April 2019, 09:28

Hallo,

ich bin gerade am verzweifeln mit einer meiner Hausaufgaben und würde mich sehr freuen, wenn ich hier vielleicht einen neuen Gedankenanstoß finden könnte.

Die Aufgabe fordert eine Funktion convex_polygon der als Argumente Tupel von n Eckpunkten in Form von ((x1,y1),(x2,y2),...) übergeben werden. Dann werden n-2 Teildreiecke gebildet, deren summierte Flächen der Fläche des Polygon entsprechen.

Folgenden Code habe ich schon geschrieben:

Code: Alles auswählen

import math

def triangle_area(a, b, c):                         # Initialisierung der triangle_area-Funktion

    if max(a,b,c)<(a+b+c-max(a,b,c)):
        
        s = (a + b + c)/2


        area = ((s * (s-a)*(s-b)*(s-c))**0.5)
        return area
    else:
        return False



def distance(p1,p2):                                # Gibt den Abstand zwischen zwei Punkten (x1,y1) und (x2,y2) aus.

    return (math.sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2))

pointNumber = int(input('Wie viele Punkte möchtest du eingeben?'))

points = []                                         # Liste für die Punkte-Tupel. Sieht am Ende bspw. so aus: [(1,1),(3,4),(1,5),(2,6)]

for i in range(0,pointNumber):                      # Eingabe der Punkte als einzelne x oder y Werte, also nicht in Tupeln


    addPointX = int(input('Bitte x von Punkt eingeben'))
    addPointY = int(input('Bitte y vom Punkt eingeben'))

    addPoint = (addPointX, addPointY)
    
    points.append(addPoint)                     


# Folgender Code würde auch den Flächeninhalt ausgeben, aber nicht auf die geforderte Weise mit Teildreiecken, sondern mit der Gaussschen Trapezformel.

"""
values = input("Koordinaten in Form x1,y1,x2,y1,... eingeben: ")
x = tuple(map(int, values.split(",")))

for i in range(1,len(x)):
    

A = ((x[1] + x[3])*(x[0] - x[2])+(x[3] + x[5])*(x[2] - x[4])+(x[5] + x[7])*(x[4]-x[6])+(x[7]+x[1])*(x[6]-x[0]))/2
print(A)
"""
WIe könnte man vorgehen, damit:
1. Man der Funktion min. 4 Tupel (x,y) übergeben kann und diese dann der "Reihe" nach ordnet?
2. daraus resultierend: das Programm genau weiß, welche Strecken zwischen den Punkten er der triangle_area-Funktion gibt, um die richtigen Flächen zu berechnen?

Um das kurz klarzustellen: Ich erwarte nicht, dass ihr meine Hausaufgaben löst. Ich brauche nur einen Tipp, um die Lösung dann selber hinzubekommen.
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Um die Fläche eines Polygons zu berechnen, braucht man keine Teildreiecke. Bei einem konvexen Polygon könnte man aber eine Ecke festhalten und die jeweils beiden anderen Ecken durchgehen (wenn man die Orientierung mitnimmt und somit negative Flächen zuläßt, kann man das auch auf alle überschneidungsfreie Polygone verallgemeinern). Dazu muß man aber nichts ordnen; die Punkte des Polygonzugs sollten ja schon geordnet sein (eine ganz andere Aufgabe wäre es, aus einer Punktewolke die konvexe Hülle zu bilden, was aber deutlich komplizierter und hier nicht gefordert ist).

Der erste Schritt wäre also, den ersten Punkt zu nehmen und in einer Schleife immer den 2. und 3., 3. und 4. Punkt usw. zusammen in die Berechnung der Dreiecksfläche zu geben.
Für die Schleife hilft Dir die zip-Funktion.

Zum Code:
Fehler sollten immer über Exceptions erfolgen. Bei `triangle_area` ist der Fehlerfall aber durch die 0 (aka False) als Rückgabewert implementiert; also ist ein Fehler ununterscheidbar von einem validen Wert des degenerierten Dreiecks mit Fläche 0.
Warum verwendest Du einmal math.sqrt und einmal **0.5 um die Wurzel zu berechnen? Ich persönlich präferiere die zweite Variante.

Die hast an zu vielen ungünstigen Stellen Leerzeilen, die den Lesefluß erheblich stören. Zusammenhängende Teile sollten auch als solche erkennbar sein. Wenn aber z.B. nach dem Start der for-Schleife erst zwei Leerzeilen kommen, erkennt man nicht mehr den Block, der zur for-Schleife gehört.

Namenskonvention für Variablen ist (wie für Funktionen) klein_mit_unterstrich. `pointNumber` hält sich nicht daran, besser wäre auch number_of_points. Für die Nutzerin ist es aber angenehmer, wenn sie am Anfang aber gar nicht wissen muß, wie viele Punkte sie eingeben will, sondern per while-Schleife so lange Zahlen eingeben kann, bis sie per Leerstring anzeigt, dass sie fertig ist.

Ein Polygon aus drei Ecken ist doch valide, warum willst Du 4 erzwingen?
Benutzeravatar
__blackjack__
User
Beiträge: 14042
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@leanderto: Ad 1.: Warum mindestens 4 und nicht 3? Auch ein Dreieck ist ein konvexes Polygon. Was willst Du da ordnen? Ich würde einfach erwarten das die Punkte in der richtigen Reihenfolge eingegeben werden, und nicht wild durcheinander.

Ad 2.: Mal doch mal ein konvexes Polygon auf und teile das in Dreiecke auf. Wie machst Du das? Welche Schritte musst Du dafür durchführen?

Anmerkungen zum Quelltext: Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen: Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Bei `point_number` würde das `number` besser `count` heissen.

Die Kommentare machen die Zeilen viel zu lang. An vielen Stellen sind die tradionellen 80 Zeichen pro Zeile noch mehr oder weniger fest vorgegeben und da verschwindet dann entweder Information die darüber hinaus geht, oder sie wird sehr unübersichtlich umgebrochen und zerstört zum Beispiel sonst klar erkennbare Einrückung. Längere Kommentare werden vor die kommentierte(n) Zeile(n) gesetzt.

Man sollte auch nicht zu viel kommentieren. Das `points` aus Tupeln mit x und y Werten besteht, sieht man ziemlich deutlich am Code wenn man die ganzen Kommentare da raus nimmt und das nicht mit den ganzen benannten Zwischenwerten künstlich in die Länge zieht.

`add_point` ist ein guter Name für eine Funktion oder Methode die einen Punkt irgendwo addiert/hinzufügt, aber ein schlechter Name für einen Punkt. Funktionen und Methoden werden nach der Tätigkeit benannt die sie ausführen, dementsprechend sind Tätigkeiten keine guten Namen für passive Werte die nichts tun.

Wenn ein Name aus syntaktischen Gründen da sein muss, der Wert aber für das Programm keine Rolle spielt, wird per Konvention `_` als Name verwendet.

Der Kommentar bei `triangle_area()` ist falsch. Da wird keine Funktion initialisiert.

In dem Quelltext stehen so einige überflüssige Klammern.

Eine Funktion die entweder eine Zahl oder `False` zurück gibt hat eine kaputte API. Zumal `False` auch eine gültige Zahl ist weil `bool` von `int` erbt und `False` als Zahl den Wert 0 hat.

Der Kommentar bei `distance()` ist falsch weil die Funktion nichts ausgibt. Ausgeben ist etwas anderes als zurückgeben.

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import math


def triangle_area(a, b, c):
    s = (a + b + c) / 2
    return math.sqrt(s * (s - a) * (s - b) * (s - c))


def distance(p1, p2):
    return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)


def main():
    point_count = int(input('Wie viele Punkte möchtest du eingeben?'))
    points = []
    for _ in range(point_count):
        x = int(input('Bitte x von Punkt eingeben'))
        y = int(input('Bitte y vom Punkt eingeben'))
        points.append((x, y))                     


if __name__ == '__main__':
    main()
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten