I am currently working on calculating the surface area of a 3D model imported through the IFC Loader tool. However, before diving into the complex models, I decided to start with simpler shapes like pyramids to better understand the process.
From my understanding, indexed BufferGeometries consist of a position array containing all the points used in creating the model, and an indexes array that pairs up the points to form triangles. While experimenting with the code below to generate a ply file for a pyramid, I noticed some inconsistencies in the output. There were repeated points and faces that didn't align correctly, resulting in more faces than necessary for a triangular pyramid.
What could be causing these discrepancies? Am I overlooking something crucial in the calculation?
Even though these errors might not impact the overall surface area calculation due to the cross product resulting in zero, I am curious to understand the root cause of these anomalies and why they only occur sporadically.
const geometry = new THREE.ConeGeometry(5, 10, 3);
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const cone = new THREE.Mesh(geometry, material);
const positionsArray = geometry.getAttribute("position").array;
const positions = []
for (var i = 0; i < positionsArray.length; i += 3) {
positions.push([
positionsArray[i + 0],
positionsArray[i + 1],
positionsArray[i + 2]
]);
}
var surface = 0
const faces = geometry.getIndex().array;
var data =
`ply
format ascii 1.0
element vertex ${positions.length}
property float x
property float y
property float z
element face ${faces.length / 3}
property list uchar int vertex_index
end_header
`
for (const position of positions) {
data += position.join(" ") + "\n"
}
for (var i = 0; i < faces.length; i += 3) {
const p1 = positions[faces[i + 0]]
const p2 = positions[faces[i + 1]]
const p3 = positions[faces[i + 2]]
data += `3 ${faces[i + 0]} ${faces[i + 1]} ${faces[i + 2]}\n`
const p1p2 = p2.map(function (item, index) { return item - p1[index] })
const p1p3 = p3.map(function (item, index) { return item - p1[index] })
surface += Math.sqrt(Math.pow(p1p2[1] * p1p3[2] - p1p2[2] * p1p3[1], 2) + Math.pow(p1p2[2] * p1p3[0] - p1p2[0] * p1p3[2], 2) + Math.pow(p1p2[0] * p1p3[1] - p1p2[1] * p1p3[0], 2)) / 2
}
const link = document.createElement('a');
var blob = new Blob([data], { type: "text/plain" });
link.href = URL.createObjectURL(blob);
link.download = 'example.ply';
link.click();
ply
format ascii 1.0
element vertex 15
property float x
property float y
property float z
element face 9
property list uchar int vertex_index
end_header
0 5 0
0 5 0
0 5 0
0 5 0
0 -5 5
4.330127239227295 -5 -2.5
-4.330127239227295 -5 -2.5
-1.2246467996456087e-15 -5 5
0 -5 0
0 -5 0
0 -5 0
0 -5 5
4.330127239227295 -5 -2.5
-4.330127239227295 -5 -2.5
-1.2246467996456087e-15 -5 5
3 0 4 1
3 4 5 1
3 1 5 2
3 5 6 2
3 2 6 3
3 6 7 3
3 12 11 8
3 13 12 9
3 14 13 10