I'm trying to calculate the surface of a 3d model imported through IFC Loader, however, first I want to make sure I understand how it works for easier models, so I'm doing it with pyramids.
As far as I know, for indexed BufferGeometries there exists a position array which contains all the points involved in the creation of the model and an indexes array which for every 3 elements gives you the 3 indices that form each triangle. So with the code below I'm capable of creating a ply file with thge pyramid I choose. However, if you examine the file in note pad you realize that there are several points repeated and faces that are not faces because are connected between these connected points, as you can see below the code, saying that for generating a pyramid of triangular base I need 9 faces when are just 6 needed (3 lateral faces and 3 for the base, because it uses a center point to connect each edge of the base)
What am I doing wrong? Or what am I missing?
I know it does not affect the surface because when doing the cross product, the result will be 0, but I would like to know why do they appear and just some of them.
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
CodePudding user response:
It appears from the source code that a ConeGeometry is constructed by making a CylinderGeometry with 0 radius at one end. As such, the multiple points you're seeing are the triangle fan at that end with all vertices compressed into a single location.