Dan*_*zos 1 .net c# 3d winforms
我的 Winforms 应用程序获取一个 CSV 文件,其中包含 3D 相机给出的 XYZ 坐标。使用这些坐标,我需要以立方分米 (dm3) 为单位计算物体的体积。
我不知所措,而不是数学专家。我希望成为一个已经这样做的库或算法,但我发现的唯一东西是在 C++ 中,如 PCL 库或它们使用 Unity。对于像我这样对几何学无知的人来说,是否有一种简单/干净的方法来获得具有 XYZ 坐标的对象的体积?
更新
这是我到目前为止的代码片段:
public class Volume
{
//These are only part of the coordinates in the CSV file. There are more than 69.000 lines
Vector3[] vectors = new Vector3[8]
{
new Vector3 {X=-139,Y=-109,Z=285},
new Vector3 {X=-138,Y=-109,Z=286},
new Vector3 {X=-136,Y=-109,Z=286},
new Vector3 {X=-135,Y=-109,Z=286},
new Vector3 {X=-133,Y=-109,Z=286},
new Vector3 {X=-132,Y=-109,Z=286},
new Vector3 {X=-130,Y=-109,Z=286},
new Vector3 {X=-129,Y=-109,Z=286}
};
public double VolumeOfMesh()
{
Mesh _mesh = new Mesh();
double volume = 0.0;
_mesh.Vertices = vectors; //Should the vectors be organized by proximity to create the triangles?
_mesh.Triangles = null; //How do I calculate the triangles?
Vector3[] vertices = _mesh.Vertices;
int[] triangles = _mesh.Triangles;
for (int i = 0; i < _mesh.Triangles.Length; i += 3)
{
Vector3 p1 = vertices[triangles[i + 0]];
Vector3 p2 = vertices[triangles[i + 1]];
Vector3 p3 = vertices[triangles[i + 2]];
volume += SignedVolumeOfTriangle(p1, p2, p3);
}
return Math.Abs(volume);
}
private double SignedVolumeOfTriangle(Vector3 p1, Vector3 p2, Vector3 p3)
{
var v321 = p3.X * p2.Y * p1.Z;
var v231 = p2.X * p3.Y * p1.Z;
var v312 = p3.X * p1.Y * p2.Z;
var v132 = p1.X * p3.Y * p2.Z;
var v213 = p2.X * p1.Y * p3.Z;
var v123 = p1.X * p2.Y * p3.Z;
return (1.0 / 6.0) * (-v321 + v231 + v312 - v132 - v213 + v123);
}
}
Run Code Online (Sandbox Code Playgroud)
向量数组应该按接近度排序吗?如何填充 Triangles 属性?
欢迎任何建议或指导。
这就是我使用 .STL 文件将点排列成三角形面的方式。在您的情况下,您需要以某种方式描述哪些点(节点)组合以定义面,并确保面形成封闭的水密实体。
这个想法是形成一个面的每三个点ABC与原点一起形成一个体积实体

其中 · 是向量点积,× 是向量叉积。
事实证明,当您将所有体积相加时,有些为正(背离原点),有些为负(面向原点)。最后,总和将等于物体的封闭体积。
这是C#我用来从网格获取实体对象属性的代码示例。请记住,网格是由顶点中点的三个索引值定义的Nodes称为点的集合和称为三角形的集合Faces。
public struct Face3
{
public Face3(int indexA, int indexB, int indexC)
{
this.IndexA = indexA;
this.IndexB = indexB;
this.IndexC = indexC;
}
public readonly int IndexA, IndexB, IndexC;
}
public class Mesh3
{
public Mesh3(int n_nodes, int n_elements)
{
this.Nodes = new Vector3[n_nodes];
this.Faces = new Face3[n_elements];
}
public Mesh3(Vector3[] nodes, Face3[] faces)
{
this.Nodes = nodes;
this.Faces = faces;
}
public Vector3[] Nodes { get; }
public Face3[] Faces { get; }
public void CalcRigidBodyProperties(double density)
{
double sum_vol = 0;
Vector3 sum_cg = Vector3.Zero;
for (int i = 0; i < Faces.Length; i++)
{
var face = this.Faces[i];
Vector3 a = this.Nodes[face.IndexA];
Vector3 b = this.Nodes[face.IndexB];
Vector3 c = this.Nodes[face.IndexC];
double face_vol = Vector3.Dot(a, Vector3.Cross(b,c))/6;
sum_vol += face_vol;
Vector3 face_cg = (a+b+c)/4;
sum_cg += frace_vol*face_cg;
}
// scale volume with density for mass
var mass = density*sum_vol;
// find center of mass by dividing by total volume
var cg = sum_cg / sum_vol;
...
}
public static Mesh3 FromStl(string filename, double scale = 1)
{
// Imports a binary STL file
// Code Taken From:
// https://sukhbinder.wordpress.com/2013/12/10/new-fortran-stl-binary-file-reader/
// Aug 27, 2019
var fs = File.OpenRead(filename);
var stl = new BinaryReader(fs);
var header = new string(stl.ReadChars(80));
var n_elems = stl.ReadInt32();
var nodes = new List<Vector3>();
var faces = new List<Face3>();
bool FindIndexOf(Vector3 node, out int index)
{
for (index = 0; index < nodes.Count; index++)
{
if (nodes[index].Equals(node, TrigonometricPrecision))
{
return true;
}
}
index = -1;
return false;
}
for (int i = 0; i < n_elems; i++)
{
var normal = new Vector3(
stl.ReadSingle(),
stl.ReadSingle(),
stl.ReadSingle());
var a = new Vector3(
scale*stl.ReadSingle(),
scale*stl.ReadSingle(),
scale*stl.ReadSingle());
var b = new Vector3(
scale*stl.ReadSingle(),
scale*stl.ReadSingle(),
scale*stl.ReadSingle());
var c = new Vector3(
scale*stl.ReadSingle(),
scale*stl.ReadSingle(),
scale*stl.ReadSingle());
// burn two bytes
var temp = stl.ReadBytes(2);
// get index of next point, and add point to list of nodes
index_a = nodes.Count;
nodes.Add(a);
index_b = nodes.Count;
nodes.Add(b);
index_c = nodes.Count;
nodes.Add(c);
// add face from the three index values
faces.Add(new Face3( index_a, index_b, index_c ));
}
stl.Close();
return new Mesh3(nodes.ToArray(), faces.ToArray());
}
}
Run Code Online (Sandbox Code Playgroud)
作为测试用例,我只使用了一个定义如下的三角形:
此外,我通过将上述计算与商业 CAD 软件包产生的计算进行比较,以更复杂的形状验证了结果。
| 归档时间: |
|
| 查看次数: |
2305 次 |
| 最近记录: |