CGAL中最小有向包围盒oriented_bounding_box的应用及Dynamo可视化验证

相信大家已经懂了轴对齐包围盒(Axis-aligned bounding box)的概念,即包围盒的长宽高分别和x轴y轴z轴对齐。

如下图所示:

最小有向包围盒:指完全包围Mesh/Solid且体积最小,带有旋转一定角度的包围盒

如下图所示:

下面我们就试一下,如何通过CGAL库获取最小有向包围盒。

第一部分:C++部分代码

  1.新建C++动态链接库项目

  2.添加CGAL附加库目录,详我的一篇博客 https://www.cnblogs.com/ShawBlack/p/17000477.html

  3.在C++中调用CGAL的OBB算法,并进一步封装成全局函数,再在函数声明中加上P/Invoke标签(如果不了解P/Invoke,请参考我的一篇博客 https://www.cnblogs.com/ShawBlack/p/17063222.html)

复制代码
#include "pch.h"
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/optimal_bounding_box.h>
#include <CGAL/Simple_cartesian.h>

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_3                                            Point;
typedef CGAL::Surface_mesh<Point>                            Surface_mesh;
typedef CGAL::SM_Vertex_index                                Vertex_index;

//P/Invoke标签
extern "C" __declspec(dllexport) void OrientedBounddingBoxBySurfaceMesh(double* vert_xyz_array, size_t vert_count, int* face_index_array, size_t faces_count, double*& obb_pts_xyz);
//vert_xyz_array: points中各个x、y、z序列化后的double[]
//face_index_array: mesh.Faces.Index序列化后的double[]
void OrientedBounddingBoxBySurfaceMesh(double* vert_xyz_array, size_t vert_count, int* face_index_array, size_t faces_count, double*& obb_pts_xyz)
{
    //初始化mesh
    Surface_mesh mesh;
    mesh.clear();
    mesh.reserve(vert_count, 0, faces_count);
    //将刚刚序列化后的double[],反序列化为point,然后添加至mesh中
    for (size_t i = 0; i < vert_count; i++)
    {
        mesh.add_vertex(Point(vert_xyz_array[3 * i + 0], vert_xyz_array[3 * i + 1], vert_xyz_array[3 * i + 2]));
    }
    //将刚刚序列化后的double[],反序列化为faceIndex,然后添加至mesh中
    for (size_t i = 0; i < faces_count; i++)
    {
        mesh.add_face(Vertex_index(face_index_array[3 * i + 0]), Vertex_index(face_index_array[3 * i + 1]), Vertex_index(face_index_array[3 * i + 2]));
    }
    //调用obb函数
    std::array<Point, 8> obb_points;
    CGAL::oriented_bounding_box(mesh, obb_points, CGAL::parameters::use_convex_hull(true));
    //获取返回值,并序列化返回值
    obb_pts_xyz = new double[obb_points.size() * 3];
    int i = 0;
    for (Point pt : obb_points)
    {
        obb_pts_xyz[i++] = double(pt.x());
        obb_pts_xyz[i++] = double(pt.y());
        obb_pts_xyz[i++] = double(pt.z());
    }
    return;
}
复制代码

第二部分:C#部分代码

  1.新建C#控制台项目

  2.新建Point类

复制代码
    public class XHPoint3D
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }

        public XHPoint3D(double x, double y, double z)
        {
            X = x;
            Y = y;
            Z = z;
        }
    }
复制代码

  3.在Program中声明需要调用的C++Dll库以及用到的函数

        [DllImport("CGAL_FunctionLib.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void OrientedBounddingBoxBySurfaceMesh(
            [MarshalAs(UnmanagedType.LPArray)] double[] vert_xyz_array, ulong vert_count,
            [MarshalAs(UnmanagedType.LPArray)] int[] face_index_array, ulong faces_count, ref IntPtr obb_pts_xyz
            );

  4.生成测试数据,序列化数据,调用C++obb函数

复制代码
internal class Program
    {
        static void Main(string[] args)
        {
            //新建mesh.point
            XHPoint3D point3D1 = new XHPoint3D(1, 1, 0);
            XHPoint3D point3D2 = new XHPoint3D(0, 2, 1);
            XHPoint3D point3D3 = new XHPoint3D(0, 1, 0);
            XHPoint3D point3D4 = new XHPoint3D(0, 0, 0);
            List<XHPoint3D> xHPoint3s = new List<XHPoint3D>() { point3D1, point3D2, point3D3, point3D4 };
            double[] pointDoubles = new double[xHPoint3s.Count * 3];
            for (int i = 0; i < xHPoint3s.Count; i++)
            {
                pointDoubles[i * 3 + 0] = xHPoint3s[i].X;
                pointDoubles[i * 3 + 1] = xHPoint3s[i].Y;
                pointDoubles[i * 3 + 2] = xHPoint3s[i].Z;
            }
            //新建mesh.faces.indexOfPoint
            int[] indexDoubles = new int[xHPoint3s.Count * 3] ;
            indexDoubles[0] = 3;
            indexDoubles[1] = 0;
            indexDoubles[2] = 2;
            indexDoubles[3] = 3;
            indexDoubles[4] = 0;
            indexDoubles[5] = 1;
            indexDoubles[6] = 0;
            indexDoubles[7] = 2;
            indexDoubles[8] = 1;
            indexDoubles[9] = 2;
            indexDoubles[10] = 1;
            indexDoubles[11] = 3;
            ulong faceCount = 4;
            //调用函数,返回指针
            IntPtr intPtr = IntPtr.Zero;
            OrientedBounddingBoxBySurfaceMesh(pointDoubles, (ulong)xHPoint3s.Count, indexDoubles, faceCount, ref intPtr);
            //指针转换成对应的points
            double[] obb_xyz_array = new double[8 * 3];
            Marshal.Copy(intPtr, obb_xyz_array, 0, 8 * 3);
            List<XHPoint3D> xHPoint3Ds_Bound = new List<XHPoint3D>();
            for (int i = 0; i < 8; i++)
            {
                xHPoint3Ds_Bound.Add(new XHPoint3D
                    (
                     obb_xyz_array[i * 3 + 0], obb_xyz_array[i * 3 + 1], obb_xyz_array[i * 3 + 2]
                    ));
            }
            //数据显示
            for (int i = 0; i < 8; i++)
            {
                Console.WriteLine(Math.Round(obb_xyz_array[i * 3 + 0], 2) + ";" + Math.Round(obb_xyz_array[i * 3 + 1], 2) + ";" + Math.Round(obb_xyz_array[i * 3 + 2], 2));
            }
            Console.ReadLine();
        }
        [DllImport("CGAL_FunctionLib.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void OrientedBounddingBoxBySurfaceMesh(
            [MarshalAs(UnmanagedType.LPArray)] double[] vert_xyz_array, ulong vert_count,
            [MarshalAs(UnmanagedType.LPArray)] int[] face_index_array, ulong faces_count, ref IntPtr obb_pts_xyz
            );
    }
复制代码

  5.生成解决方案,测试一下。可以发现函数调用成功了,生成了八个点,即最小有向包围盒的八个顶点。

接下来我们来可视化展示一下...

第三部分:Dynamo可视化展示

    1.展示(1, 1, 0)、(0, 2, 1)、(0, 1, 0)、(0, 0, 0)四个顶点

  2.展示由四个顶点构成的Mesh/Solid

 

 

   3.展示obb函数计算得到的包围盒的八个顶点

 

 

   4.展示八个顶点构成的最小有向包围盒

 

 

 

   Over~

posted @   ShawBlack  阅读(1416)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示