Рассчитать объем объекта по координатам XYZ - PullRequest
1 голос
/ 08 октября 2019

Приложение My Winforms получает файл CSV с координатами XYZ, данными с 3D-камеры. С этими координатами мне нужно вычислить объем объекта в кубических дециметрах (дм3).

Я перегружен и не эксперт по математике. Я ожидал, что это будет библиотека или алгоритм, который уже сделает это, но единственные вещи, которые я нашел, в 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);
    }
}

Должен ли массив векторов быть упорядочен по близости? Как мне заполнить свойство Triangles?

Любые советы или рекомендации будут приветствоваться.

1 Ответ

2 голосов
/ 08 октября 2019

Вот как я это сделал, используя файлы .STL, которые размещают точки в треугольные грани. В вашем случае вам нужно как-то описать, какие точки (узлы) объединяются, чтобы определить грани, и убедиться, что грани образуют замкнутое водонепроницаемое твердое тело.

wedge

Идея состоит в том, что каждые три точки ABC , которые образуют грань вместе с началом координат, образуют твердое тело объемом

volume

, где · являетсявекторное произведение точек и × векторное произведение.

Оказывается, что при сложении всех томов некоторые будут положительными (обращены в сторону от источника), а некоторые отрицательными (обращены к источнику)). В итоге, сумма будет равна объему объекта.

Вот пример кода 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());
    }
}

в качестве контрольного примераЯ использовал только один треугольник, определенный следующим образом:

example1 example2

, кроме того, я проверил результатс более сложной формой, сравнивая приведенный выше расчет с расчетом, производимым коммерческим пакетом САПР.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...