Verfasst am: 13.02.2016, 19:51
Titel: Berechnung äquidistanter Punkte entlang eines Polygonzuges
Hallo MATLAB Community,
mein Ziel ist, neue Punkte P_abs(i) in gleichen Abständen d auf dem Polygonzug der Punktematrix P zu berechnen.
Die Abschnitte werden mathematisch in Form von Stützvektor + Richtungsvektor: P + rvP ausgedrückt.
Die Punktematrix wird mehrere hundert Punkte haben, und die Abstände d sollen im voraus eingegeben werden.
Anhand des folgenden Beispiels mit nur 8 Punkten (Start-/Zielpunkt doppelt) und dem Abstand von 0,2 wird gezeigt, wie ich es realisieren möchte.
Code:
% Punktematrix P
P = [3,1;2,0.5;0.75,1;0.5,2;1.5,4;5,3.5;6,2;3,1];
% Berechnung der Punktabstände pa bzw. Längen der Abschnitte
l = length(P);
pa = zeros(l,1);
for i = 1:(l-1)
pa(i) = sqrt((P(i+1,1) - P(i,1)).^2 + (P(i+1,2) - P(i,2)).^2);
end
% Ab hier wieder das gleiche wie in Zeile 31 mit dem Unterschied, dass der % erste Punkt des neuen Abschnitts nicht auf P(2,:) liegt, sondern um % r1_abs2 * rvP verschoben wurde. % Somit gilt für die Anzahl der Punkte auf Abschnitt 2:
Bis zum Abstand von 0,5 funktioniert es wie gewünscht. Größere Abstände erfordern einen Sprung auf den nächsten Abschnitt und sind noch nicht im Code umgesetzt.
Mein Hauptanliegen ist jedoch, die Berechnung der Abschnittspunkte in eine Schleife zu bekommen, um nicht die Schritte in Zeile 31, 71, 106, 137, 168 und 199 für ein paar hundert Abschnitte abtippen zu müssen.
Kann mir diesbezüglich bitte jemand weiterhelfen?
dargestellt.
Im Gegensatz zu meinem Problem mit vielen Vektoren handelt es sich hierbei nur um EINE Funktion bzw. Polynom.
Ausserdem verstehe ich die Zeile
Im Prinzip besteht das Problem darin, dass ohne den letzten Punkt auf den Abschnitten keine neue Einteilung im neuen Abschnitt möglich ist.
Ich wüßte auch nicht man sie im voraus berechnen könnte, um eine Schleife drumherum zu basteln.
Im Prinzip besteht das Problem darin, dass ohne den letzten Punkt auf den Abschnitten keine neue Einteilung im neuen Abschnitt möglich ist.
Das verstehe ich nicht.
Du möchtest eigentlich nur Punkt in bestimmtem Abstand auf einem Polygonzug verteilen, oder? Das ist eine lineare Interpolation zwischen den Stützstellen. Mit
interp1
solltest Du da also eigentlich eine einfache Lösung hinbekommen. Ich versuche es nur gerade bequemer und effizienter zu lösen.
Mit der
- Länge der Abschnitte bzw. Punktabstände pa(i),
- Anzahl der Punkte pro Abschnitts An_P_abs = pa(i)/d,
ergeben die Koordinaten bei einer Einteilung von d=0,2 für den letzten Punkt auf Abschnitt 1 ungefähr (2,1/0,55).
Um den Abstand von 0,2 einzuhalten, startet der erste Punkt des 2. Abschnitts P1_abs2 startet also nicht bei P(2,, siehe Abb.1.
Somit liegt der letzte Punkt von Abschnitt 2 nicht auf P_abs2(i, = P(2, + i*(d/pa(2))*rvP(2,, sondern um r1 versetzt.
Die Berechung der Punkte für Abschnitt 1 und des Parameter r1,2 für den darauffolgenden Abschnitt erfolgt im Code zwischen den Zeilen 31 und 69. Dies wiederholt sich bei 8 gegebenen Punkten 7 mal.
Code:
% Anzahl der Punkte auf Abschnitt 1 (mit floor abrunden)
An_P_abs1 = floor(pa(1)/d);
% Äquidistante Punkte auf Abschnitt 1
P_abs1 = zeros(An_P_abs1,2);
for i = 1:An_P_abs1
P_abs1(i,:) = P(1,:) + i*(d/pa(1))*rvP(1,:);
end
% Sprung auf nächsten Vektor (Abschnittswechsel) % Letzter Punkt auf Abschnitt 1
P_end_abs1 = P_abs1(An_P_abs1,:);
% Berechnung des 1.Punktes auf Abschnitt 2:
% Bedingung (1) für 1.Punkt auf Abschnitt 2: % d = sqrt((P_1abs2(1,1) - P_end_abs1(1,1)).^2 + (P_1abs2(1,2) - P_end_abs1(1,2)).^2
% Bedingung (2) für 1.Punkt auf Abschnitt 2: % P_1abs2(1, = P(2, + r*rvP(2,
% (2) in (1) und nach Parameter r aufgelöst (mit Mitternachtsformel: r = 1/(2*a) * (+-b + sqrt(b^2 - 4*a*c))): % Variablen Mitternachtsformel a, b, c
a = rvP(2,1).^2 + rvP(2,2).^2;
b = 2.*P(2,1).*rvP(2,1) - 2.*P_end_abs1(1,1).*rvP(2,1) + 2.*P(2,2).*rvP(2,2) - 2.*P_end_abs1(1,2).*rvP(2,2);
c = P(2,1).^2 - 2.*P_end_abs1(1,1).*P(2,1) + P_end_abs1(1,1).^2 + P(2,2).^2 - 2.*P_end_abs1(1,2).*P(2,2) + P_end_abs1(1,2).^2 - d.^2;
Nach so einer Lösung (oder ähnlich) habe ich gesucht. Daher das Beispiel mit dem Abstandsvektor. Damit würde man gleichmäßige Abstände pro Abschnitt bzw. Funktion erhalten.
Da es sich hierbei um mehrere verschiedene Geradengleichungen handelt, bestehend aus Stütz- und Richtungsvektor, haben die letzten Punkte der Abschnitte nicht diesselben Abstände zu den ersten Punkten des darauffolgenden Abschnitts.
Außerdem unterscheiden sich die Punktabstände auf den einzelnen Abschnitten (siehe Abb.2).
Zitat:
Du möchtest eigentlich nur Punkt in bestimmtem Abstand auf einem Polygonzug verteilen, oder?
Mit der
- Länge der Abschnitte bzw. Punktabstände pa(i),
- Anzahl der Punkte pro Abschnitts An_P_abs = pa(i)/d,
ergeben die Koordinaten bei einer Einteilung von d=0,2 für den letzten Punkt auf Abschnitt 1 ungefähr (2,1/0,55).
Um den Abstand von 0,2 einzuhalten, startet der erste Punkt des 2. Abschnitts P1_abs2 startet also nicht bei P(2,:), siehe Abb.1.
Somit liegt der letzte Punkt von Abschnitt 2 nicht auf P_abs2(i,:) = P(2,:) + i*(d/pa(2))*rvP(2,:), sondern um r1 versetzt.
Ich verstehe keinen dieser Sätze. Was ist Abbildung 1?
Zitat:
Du möchtest eigentlich nur Punkte in bestimmtem Abstand auf einem Polygonzug verteilen, oder?
Vielleicht wird es klarer, wenn ich den Code poste. Ich habe tagsüber kein Matlab zur Verfügung. Ich probiere es heute Abend und vielleicht wird es klarer, wenn ich den Code gepostet habe. Ich vermute, 5 Zeilen reichen aus um das Problem allgemein zu lösen - falls ich es richtig verstanden habe.
der Code in Beitrag #1 ist lauffähig.
Wenn den mal laufen lässt, wird der Polygonzug aus der Punktmenge P in rot und die berechneten Punkte mit gleichen Abständen in blau ausgegeben.
Die einzelnen Abstände zwischen den roten Punkten habe ich z.T. auch als Abschnitte bezeichnet, die Abstände zwischen den blauen Punkten als d.
Zugegeben, das ist etwas verwirrend.
Die Abbildungen 1 und 2 sind an Beitrag #5 angehängt, oder wurden sie nicht hochgeladen?
Bei mir werden sie jedenfalls unter dem Beitrag angezeigt.
Zitat:
Vielleicht wird es klarer, wenn ich den Code poste.
Der Code hat doch einige Zeilen mehr, da z.B. auch der Sonderfall berücksichtigt werden muss, dass der letzte interpolierte Punkt genau auf dem letztzen Datenpunkt liegt.
Code:
function Q = PointsOnPoly(P, L) % PointsOnPoly - equidistant points on a polygon % Q = PointsOnPoly(P, L) % INPUT: % P: [N x W] matrix with N points with W dimensions. % L: Scalar value for the Euclidean distance between the output points. % OUTPUT: % Q: [M x W] matrix, where M is the number of interpolated points.
%
% EXAMPLE: % P = [3,1; 2,0.5; 0.75,1; 0.5,2; 1.5,4; 5,3.5; 6,2; 3,1]; % Q = PointsOnPoly(P, 0.2); % plot(P(:, 1), P(:, 2), 'b'); % hold('on'); % plot(Q(:, 1), Q(:, 2), 'ro');
%
% Author: Jan Simon, Heidelberg, (C) 2016 matlab.2010[AT]n[MINUS]simon[DOT]de % License: BSD (use/copy/change/redistribute on own risk, mention the author)
habe deine Function getestet und sie läuft wunderbar. RESPEKT!
Es lassen sich im Beispiel mit den 8 Punkten auch Abstände bis L=2,0 eingeben, sodass auch Abschnitte übersprungen werden können.
In meiner Anwendung sind Abstände bis zu L = 24 realisierbar, was völlig ausreichend ist. An dieser Stelle erstmal herzlichsten Dank für deine Mühe!
Jetzt muss ich nur noch die Abstandsberechnung von L zwischen dem letzten Punkt eines Abschnittes und dem ersten Punkt des neuen Abschnittes in deine Funktion bekommen.
Code:
% Variablen Mitternachtsformel a, b, c
a = rvP(2,1).^2 + rvP(2,2).^2;
b = 2.*P(2,1).*rvP(2,1) - 2.*P_end_abs1(1,1).*rvP(2,1) + 2.*P(2,2).*rvP(2,2) - 2.*P_end_abs1(1,2).*rvP(2,2);
c = P(2,1).^2 - 2.*P_end_abs1(1,1).*P(2,1) + P_end_abs1(1,1).^2 + P(2,2).^2 - 2.*P_end_abs1(1,2).*P(2,2) + P_end_abs1(1,2).^2 - d.^2;
Angenommen Si ist der Startpunkt auf dem neuen Abschnitt 2 mit den Koordinaten (xSi_2, ySi_2) und der letzte Punkt auf dem Abschnitt davor wäre Ti mit (xTi_1, yTi_1).
Der Abstand zwischen den Punkten soll auch betragen.
Ich meine damit den Abstand der direkten Verbindung dieser beiden Punkte, ohne über den Eckpunkt des Abschnittes zu gehen (siehe Abb.1 in Beitrag #3).
Die restlichen Punkte sollen wie in deinem Code weiterhin auf dem Polygon bleiben.
Oh, ich verstehe. Die neuen Punkte sollen den bestimmten Abstand haben. Dann war meine Lösung hilfreich dabei herauszufinden, das es so nicht geht. Schade
Ich würde als zwei anonyme Gleichungen für das gesuchte x und y den Pythagoras, mit eingesetzter Länge, und die Polynomgleichung angibst.
Allerdings müsstest du irgendetwas schreiben, dass er erkennt, falls er in dem eigenen Polynom zum Beispiel nur einen Punkt hinter dem aktuellen findet im nächsten sucht.
Das Problem ist nicht trivial. Man bestimmt einen neuen Punkt, indem man um den aktuellen Punkt einen Kreis mit dem gewünschten Radius zieht und den nächsten Schnittpunkt mit dem Polygon wählte. Es kann aber mehrere Schnittpunkte geben, z.B. wenn das Polygon im Zickzack läuft. Die Entscheidung, welchen der Schnittpunkte man dann wählt ist nicht stetig, so dass
fsolve
im Zweifelsfall daran scheitern kann und wird. Man kann dann denjenige Punkt wählen, der näher an der Distanz ist, wenn man sich auf dem Original-Polygone bewegt. Aber auch das ist leider nicht eindeutig und man benötigt eine Heuristik, für welchen Punkt man sich dann entscheidet. Diese Ausnahmen machen den Code sehr umfangreich, so dass der notwendige Aufwand deutlich das übersteigt, was ich im Forum beantworten kann.
Gruß, Jan
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.