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~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界