Registriert: Do Mär 05, 2009 20:17 Beiträge: 284 Wohnort: Kaiserslautern
Hallo,
Nachdem ich die Volumenberechnung hinbekommen habe und auch die Oberfläche eines beliebigen Mesh aus Dreiecksflächen hinbekommen habe, fehlt mir eigentlich noch der Schritt davor, denn zuerst müsste ich meine Meshs auf Geschlossenheit prüfen.
Ich habe jetzt nach viel googeln und lesen gelernt das ein Mesh aus Dreiecken dann als geschlossen gilt, wenn alle Kanten genau zu zwei Flächen existieren. Existiert eine Kante nur zu einer Fläche, dann ist das eine "offene" Kante.
Soweit die Theorie...
Jetzt die Frage:
Hat zufällig jemand mal irgendwo einen Algorythmus oder Codefetzen gesehen wie man ein Mesh am besten danach durchsucht? Ich hab (mal wieder) mehrere Stunden gegoogelt und gelesen aber nix finden können... Bei mir liegen die Vertices des Mesh in einem Array of TVertex vor.
Also ein Algo mit einer schlechten durchschnittlichen Dauer (weil Aufwand=n²) wäre doch einfach
Code:
var kanten:integer;
geschlossen :boolean;
...
geschlossen:=true;
for i:=1to Anzahl_der_Meshes do
begin
kanten:=1;
for k:=i+1to Anzahl_der_Meshes do
if eine_Kante_gleich(i,k)then
inc(kanten);
if kanten<>2then
begin
geschlossen:=False;
break;
end;
end;
Wobei die Beschreibung von dir und mein Code aber MEHRERE geschlossene Meshes zulässt.
LG Ziz
PS: Der neue Highlighterstil ist total depri - scheiß Demokratie -_-
_________________ Denn wer nur schweigt, weil er Konflikte scheut, der macht Sachen, die er hinterher bereut. Und das ist verkehrt, denn es ist nicht so schwer, jeden Tag zu tun als ob's der letzte wär’. Und du schaust mich an und fragst ob ich das kann. Und ich denk, ich werd' mich ändern irgendwann. _________________Farin Urlaub - Bewegungslos
Registriert: Do Mär 05, 2009 20:17 Beiträge: 284 Wohnort: Kaiserslautern
Ziz hat geschrieben:
Also ein Algo mit einer schlechten durchschnittlichen Dauer (weil Aufwand=n²) wäre doch einfach
Code:
var kanten:integer;
geschlossen :boolean;
...
geschlossen:=true;
for i:=1to Anzahl_der_Meshes do
begin
kanten:=1;
for k:=i+1to Anzahl_der_Meshes do
if eine_Kante_gleich(i,k)then
inc(kanten);
if kanten<>2then
begin
geschlossen:=False;
break;
end;
end;
Wobei die Beschreibung von dir und mein Code aber MEHRERE geschlossene Meshes zulässt.
LG Ziz
PS: Der neue Highlighterstil ist total depri - scheiß Demokratie -_-
hmm ja danke erstmal
aber ich hab hier teilweise meshs mit paarhunderttausend triangles... wär schon schön wenns da was schnelleres geben würde...
dann nochwas... *hust* also ne Kante AB mit A= (Ax,Ay,Az) und B = (Bx,By,Bz) ist doch (dachte ich) Ax-Bx, Ay-By, Az-Bz... das würde aber für nen doofen würfel mit Kantenlänge 1 ja ergeben das da ziemlich viele Kanten gleich wären...
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Wie ist denn dein Modell gebaut. Können 2 Vertices an der selben stelle existieren, oder gibts an einer Stelle immer nur ein Vertex. Letzteres wäre einfacher zu händeln. Dann könntest du mit Idices/Pointer arbeiten und eine Datenstruktur aufbauen wo du leicht nachschauen kannst, welche Kanten existieren und aus welchen Vertices sie bestehen, und in welchen Tris die wiederum benutzt werden.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Do Mär 05, 2009 20:17 Beiträge: 284 Wohnort: Kaiserslautern
Flash hat geschrieben:
Wie ist denn dein Modell gebaut. Können 2 Vertices an der selben stelle existieren, oder gibts an einer Stelle immer nur ein Vertex. Letzteres wäre einfacher zu händeln. Dann könntest du mit Idices/Pointer arbeiten und eine Datenstruktur aufbauen wo du leicht nachschauen kannst, welche Kanten existieren und aus welchen Vertices sie bestehen, und in welchen Tris die wiederum benutzt werden.
Die Modelle sind in CAD erstellt und somit ist mit allem zu rechnen... Modelle mit nur einer Haut (offene shells) genauso wie doppelte flächen und was man sonst noch anstellen kann wenn man den 3D malpinsel schwingt.
Allerdings liegen auch "saubere" daten - also darunter verstehe ich hier geschlossene volumen - so vor, das jeder vertice mehrfach vorkommt meine versuche das nachträglich zu reduzieren scheiterten an der normalendarstellung.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Wieso kannst du das nicht reduzieren? Ich meine, wenn du einfach das Modell beim laden in einen Quadtree lädst, und dann Vertices vergleichst die in einem Knoten liegen (und den direkten Nachbarn) dann kannst du alle Vertices die näher als X sind zusammenlegen.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Also Geschlossenheit ist nicht so leicht zu prüfen wenn du 2 Mannigfaltigkeit nicht voraussetzen kannst. Denn es gilt zwar für ein 2-mannigfaltiges und geschlossenes Mesh, dass jede Kante zu genau zwei Faces adjazent ist, aber diese Aussage gilt nicht umgekehrt.
Du solltest dir wirklich überlegen ob du das wirklich testen musst oder ob du dem Nutzer deiner Methode/Funktion lieber im Kommentar mitteilst, dass dies nur für geschlossene 2-mannigfaltige Meshes funktioniert.
Registriert: Do Mär 05, 2009 20:17 Beiträge: 284 Wohnort: Kaiserslautern
Coolcat hat geschrieben:
Also Geschlossenheit ist nicht so leicht zu prüfen wenn du 2 Mannigfaltigkeit nicht voraussetzen kannst. Denn es gilt zwar für ein 2-mannigfaltiges und geschlossenes Mesh, dass jede Kante zu genau zwei Faces adjazent ist, aber diese Aussage gilt nicht umgekehrt.
Du solltest dir wirklich überlegen ob du das wirklich testen musst oder ob du dem Nutzer deiner Methode/Funktion lieber im Kommentar mitteilst, dass dies nur für geschlossene 2-mannigfaltige Meshes funktioniert.
hmm das ist mir jetzt irgendwie zu theoretisch.
nehmen wir doch mal dieses beispiel:
Code:
{erste fläche}
varray[1]001
varray[2]101
varray[3]011
{zweite fläche}
varray[4]011
varray[5]101
varray[6]111
{dritte fläche}
varray[7]111
varray[8]010
varray[9]011
So, das sind nun 3 Dreiecksflächen, die aneinander grenzen.. von den insgesamt 9 Kanten sind 5 offen und 2 sind jeweils identisch. Und nichts anderes will ich gerne mit einer effizienten Schleife prüfen, ob alle Kanten geschlossen sind und wenn nicht, welche offen sind (nur an eine Fläche grenzen).
Offtopic@Wölfchen: Bitte nicht immer komplette Posts zitieren. Es macht höchstens Sinn einzelne Passagen zu zitieren wenn du direkt darauf Bezug nimmst. Danke.
Zitat:
So, das sind nun 3 Dreiecksflächen, die aneinander grenzen.. von den insgesamt 9 Kanten sind 5 offen und 2 sind jeweils identisch. Und nichts anderes will ich gerne mit einer effizienten Schleife prüfen, ob alle Kanten geschlossen sind und wenn nicht, welche offen sind (nur an eine Fläche grenzen).
Ich weiß zwar nicht wozu das gut sein soll, aber gut...also: Schritt 1: Vertices mergen Du schreibst etwas von ein "paarhunderttausend triangles", du wirst also auch entsprechend viele Vertices haben. Sind das eher eine Million als Hundertausend Vertices? Wenn das dann noch wirklich effizient sein soll, du also weniger als quadratische Laufzeit (O(n^2)) für diesen Schritt haben möchtest brauchst du eine räumliche Datenstruktur. Damit ließe sich eine Laufzeit von O(n * log n) erreichen. Als Datenstruktur eignet sich beispielsweise ein Octree, ein Gridfile oder auch ein R-Baum. Der Octree ist vergleichsweise leicht und müsste auch im Wiki beschrieben sein. Die beiden anderen Methoden sind komplizierter zu implementieren.
Dies ist aber das Einsteiger-Forum daher empfehle ich dir die Variante ohne Datenstruktur. Ich schreibe das mal als Pseudocode in C-Syntax, wenn was unklar ist einfach Fragen.
Code:
// die Anzahl Vertices die du als Eingabe hast, sowie die Vertices
int N;
Vector3 inputVertices[N];
// Anzahl der Dreiecke und die Dreiecke selbst
int T;
int inputIndices[3*T];
// gibt an ab welcher Entfernung zwei Vertices identisch sind.
// Gleitpunktzahlen sind immer ungenau, daher würde hier "0" nicht immer funktionieren!
float epsilon =0.0001f;
// ein uninitialisiertes Array aus Integern. Steht an Stelle i der Wert j bedeutet dies,
// dass inputVertices[i] und inputVertices[j] identisch sind.
// Dabei ist j der kleinst mögliche Wert für den dies gilt. Dies stellt sicher, dass es
// keine Verkettungen gibt sondern immer direkt der korrekte Repräsentant angegeben ist.
int index[N];
// die reale Anzahl der Vertices, also nach dem zusammenfassen.
int M = N;
// Index-Array aufbauen
float squaredEpsilon = epsilon * epsilon;
for(int i=0; i<N; i=i+1){
index[i]= i;
Vector3 current = inputVertices[i];
// Suche nach einem identischen Vertex
// (dies würde durch eine Datenstruktur extrem beschleunigt,
// hier gehen wir aber einfach alle Vertices durch)
for(int j=0; j<i; j=j+1){
Vector3 vertex = inputVertices[index[j]];
// um die Wurzel zu sparen quadrieren wir einfach die andere Seite der Ungleichung.
if(index[i]== i){// wenn != i dann ist dieser Vertex schon kopiert worden
outputVertices[j]= inputVertices[i];
j = j +1;
}
}
//alle Dreiecke durchgehen und Indices korrigieren
for(int i=0; i<3*T; i=i+1){
inputIndices[i]= index[inputIndices[i]];
}
// ======================
// diese Funktion berechnet einfach nur den Abstand zwischen zwei Punkten. Das ist einfach
// nur der dreidimensionale Pythagoras, wobei ich die Wurzel weggelassen habe, daher "squared".
float squaredDistance(Vector3 a, Vector3 b){
Vector3 d = Vector3(a.x-b.x, a.y-b.y, a.z-b.z);
return d.x*d.x+ d.y*d.y+ d.z*d.z;
}
Schritt 2: identische Kanten zählen Dies ist der aufwendigere Schritt, da es deutlich mehr Kanten als Vertices gibt (*). Habe gerade schon 30min am obigen Code gebastelt, ich bin da gerade zu faul zu. Hier darf sich jemand anderes austoben Auf keinen Fall sollte ein Array über alle möglichen Kanten angelegt werden, den das sind quadratisch viele. Die Idee wäre eine HashMap (TreeMap ginge genauso) zu benutzen um Kanten auf ein Bool zu mappen. Dabei steht "false" für offene Kante und "true" für geschlossen. Also man geht alle Kanten durch und fügt sie in die HashMap ein. Wenn die Kante schon drin ist und der Bool "false" ist wird auf "true" gesetzt. Ist der Wert schon "true" ist was faul, also eine Kante mit drei Dreiecken. Am Ende gehst du nochmal die HashMap durch und guckst ob es noch Werte mit "false", also offene Kanten gibt.
(*) ungefähr dreimal so viele bei einem geschlossenen 2-mannigfaltigen Mesh mit vernachlässigbarem Genus, siehe Mesh.
Registriert: Do Mär 05, 2009 20:17 Beiträge: 284 Wohnort: Kaiserslautern
huhu,
danke für die Zeit die du dir da genommen hast - ich habe mir jetzt eine krücke gebastelt die fürs erste ausreicht. Ich baller alle kanten in eine sortierte stringlist, laufe dann noch einmal durch diese durch und zähle ob es kanten gibt die weniger oder öfter als 2 mal vorkommen.
Das ist bei > 500 000 flächen dann zwar schon sehr zäh (zwischen 25 und 45 sekunden) aber 95% meiner teile haben max 100 000 flächen und da gehts noch mit 0-3 sekunden, erträglich zu. Zumal der pc hier an dem ich das gestoppt habe eh nicht der schnellste ist.
den punkt schau ich mir aber sicherlich bei gelegenheit (wenn ich auch noch bissi mehr C kenne und so) nochmal an.
*EDIT - 31.01.2010*
Ich habe das Verfahren zwar grundsätzlich beibehalten aber ich gehe nun nicht mehr den Umweg über eine Stringlist sondern habe alles in einem array, das ich sortiere und danach zähle wie oft was eine Kante vorkommt. Das hat die Rechenzeit selbst bei den größten Testmodellen in Bereiche unter 2 Sekunden gebracht (von ehemals 45 Sekunden) was absolut in Ordnung ist für meine Zwecke.
Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.