Dopo un sacco di riflessione e sperimentazione ho la risposta!
Per prima cosa aggiungiamo un quarto punto a ciascun triangolo per trasformarli in tetraedri con un centroide del volume. Calcoliamo i volumi e i centri di massa e li moltiplichiamo l'uno per l'altro per ottenere i nostri momenti. Sommiamo i momenti e dividiamo per il volume totale per ottenere il nostro centroide globale.
Calcoliamo volumi utilizzando il metodo determinato qui illustrato (equazione 32): http://mathworld.wolfram.com/Tetrahedron.html
I centroidi di ciascuno dei tetraedri è semplicemente la media dei 4 punti.
Il trucco qui è che a causa del modo in cui il file STL viene creato, i triangoli hanno un normale quel punto verso l'esterno dalla superficie della parte, seguendo la regola della mano destra dei 3 vertici usati per creare il triangolo. possiamo usare questo a nostro vantaggio, permettendoci di avere una convenzione coerente in cui determinare se un volume del tetraedro dovrebbe essere aggiunto o sottratto dalla nostra parte di rete (questo perché il punto di riferimento che abbiamo scelto potrebbe non essere necessariamente all'interno della parte e la parte generale non è necessariamente convessa, ma è un oggetto chiuso).
Utilizzando il metodo di determinazione per calcolare il volume, i primi tre punti di coordinate rappresentano i tre punti del nostro triangolo. Il quarto punto sarebbe la nostra origine comune. Se il normale creato dal triangolo (seguendo la regola della mano destra che va dal punto 1, 2, 3) punta verso il nostro punto di riferimento comune, quel volume sarà calcolato come non parte del nostro volume complessivo solido o negativo (puntando verso, Intendo dire che il vettore creato dalla normale del triangolo punta liberamente verso lo stesso lato di un piano normale creato dal vettore dal nostro punto di riferimento al centroide del tetraedro). Se il vettore punta verso il lontano dal punto di riferimento, allora è il volume positivo o all'interno della parte. Se è normale, il volume si azzera quando il triangolo si trova sullo stesso piano del punto di riferimento.
Non dobbiamo preoccuparci di tenere traccia di tutto ciò come se fossimo coerenti con i nostri input (come nei triangoli seguono la regola della mano destra con il normale rivolto verso l'esterno dalla parte) il determinante ci darà il segno corretto.
Ad ogni modo, ecco il codice (è ancora più semplice della spiegazione).
class data // 3 vertices of each triangle
{
public:
float x1,y1,z1;
float x2,y2,z2;
float x3,y3,z3;
};
int main()
{
int numTriangles; // pull in the STL file and determine number of triangles
data * triangles = new triangles [numTriangles];
// fill the triangles array with the data in the STL file
double totalVolume = 0, currentVolume;
double xCenter = 0, yCenter = 0, zCenter = 0;
for (int i = 0; i < numTriangles; i++)
{
totalVolume += currentVolume = (triangles[i].x1*triangles[i].y2*triangles[i].z3 - triangles[i].x1*triangles[i].y3*triangles[i].z2 - triangles[i].x2*triangles[i].y1*triangles[i].z3 + triangles[i].x2*triangles[i].y3*triangles[i].z1 + triangles[i].x3*triangles[i].y1*triangles[i].z2 - triangles[i].x3*triangles[i].y2*triangles[i].z1)/6;
xCenter += ((triangles[i].x1 + triangles[i].x2 + triangles[i].x3)/4) * currentVolume;
yCenter += ((triangles[i].y1 + triangles[i].y2 + triangles[i].y3)/4) * currentVolume;
zCenter += ((triangles[i].z1 + triangles[i].z2 + triangles[i].z3)/4) * currentVolume;
}
cout << endl << "Total Volume = " << totalVolume << endl;
cout << endl << "X center = " << xCenter/totalVolume << endl;
cout << endl << "Y center = " << yCenter/totalVolume << endl;
cout << endl << "Z center = " << zCenter/totalVolume << endl;
}
Estremamente veloce per il calcolo dei centri di massa per i file STL.
Penso che vorrete testare questo attentamente con attenzione ... Ho difficoltà a vedere come questo può essere giusto. Mi sembra che tu stia trovando il centro di massa di (qualcosa vicino a) la superficie, invece del momento del volume pieno. Considera cosa succede se dividi un triangolo con un numero di triangoli sullo stesso piano (come un'iterazione nella generazione di un triangolo di Sierpinski) - il determinante di ogni triangolo più piccolo sarà qualcosa come il sqrt del triangolo più grande, e i tuoi risultati saranno prevenuto da quello. –
L'ho testato con molta attenzione rispetto ai risultati dei programmi CAD (SolidWorks) e i risultati sono passati a millesimi di millimetro. Il trucco qui è che gran parte dell'algoritmo è semplificato perché ho scelto l'origine (0,0,0) come il 4 ° vertice. Questo annulla gran parte della complessità del problema e quindi ti ritrovi con qualcosa che sembra occuparsi di una superficie (perché vedi solo 3 punti, il 4 ° punto annulla tutto ciò che appartiene ad esso poiché è zero). – Faken
Grazie mille.Funziona: l'ho testato a fondo. È facile generalizzarlo a mesh non triangolari (prendere (x1, y1, z1) come il primo punto nel facet, loop da 2 al numero di punti nelle facet & take (x2, y2, z2) come numero di punto i-1 e (x3, y3, z3) come numero punto i. – Deimos