using System.Runtime.InteropServices; namespace VdeSharp; /// /// Managed wrapper around a native VDE B-Rep model (VdeBodyHandle). /// Provides STEP/IGES import/export, Boolean operations, and mesh tessellation. /// public class BrepModel : IDisposable { /// Native engine context handle private readonly nint _ctx; /// Native B-Rep body handle internal nint _handle; private bool _disposed; /// Returns the native handle (for internal use). internal nint Handle => _handle; /// /// Wraps an existing native body handle. Used internally by factory methods. /// internal BrepModel(nint ctx, nint handle) { _ctx = ctx; _handle = handle; } /// /// Creates a box primitive. /// public static BrepModel CreateBox(nint ctx, double w, double h, double d) { nint hdl = NativeMethods.vde_body_create_box(ctx, w, h, d); return new BrepModel(ctx, hdl); } /// /// Creates a cylinder primitive. /// public static BrepModel CreateCylinder(nint ctx, double radius, double height, int segments = 32) { nint hdl = NativeMethods.vde_body_create_cylinder(ctx, radius, height, segments); return new BrepModel(ctx, hdl); } /// /// Creates a sphere primitive. /// public static BrepModel CreateSphere(nint ctx, double radius, int su = 32, int sv = 32) { nint hdl = NativeMethods.vde_body_create_sphere(ctx, radius, su, sv); return new BrepModel(ctx, hdl); } /// /// Imports B-Rep models from a STEP file. /// Returns an array of BrepModel instances. /// public static unsafe BrepModel[] LoadStep(nint ctx, string path) { nint* bodiesPtr; int count = NativeMethods.vde_body_load_step(ctx, path, &bodiesPtr); if (count <= 0) return Array.Empty(); var result = new BrepModel[count]; for (int i = 0; i < count; i++) result[i] = new BrepModel(ctx, bodiesPtr[i]); // Free the pointer array (but NOT the individual handles) Marshal.FreeHGlobal((nint)bodiesPtr); return result; } /// /// Imports B-Rep models from an IGES file. /// public static unsafe BrepModel[] LoadIges(nint ctx, string path) { nint* bodiesPtr; int count = NativeMethods.vde_body_load_iges(ctx, path, &bodiesPtr); if (count <= 0) return Array.Empty(); var result = new BrepModel[count]; for (int i = 0; i < count; i++) result[i] = new BrepModel(ctx, bodiesPtr[i]); Marshal.FreeHGlobal((nint)bodiesPtr); return result; } /// /// Exports a list of BrepModel instances to a STEP file. /// public static void SaveStep(nint ctx, BrepModel[] bodies, string path) { var handles = new nint[bodies.Length]; for (int i = 0; i < bodies.Length; i++) handles[i] = bodies[i]._handle; NativeMethods.vde_body_save_step(ctx, handles, handles.Length, path); } /// /// Exports a list of BrepModel instances to an IGES file. /// public static void SaveIges(nint ctx, BrepModel[] bodies, string path) { var handles = new nint[bodies.Length]; for (int i = 0; i < bodies.Length; i++) handles[i] = bodies[i]._handle; NativeMethods.vde_body_save_iges(ctx, handles, handles.Length, path); } /// /// Saves this single body to a STEP file. /// public void SaveStep(string path) => SaveStep(_ctx, new[] { this }, path); /// /// Saves this single body to an IGES file. /// public void SaveIges(string path) => SaveIges(_ctx, new[] { this }, path); // ═══════════════════════════════════════════════════ // Boolean operations // ═══════════════════════════════════════════════════ /// Boolean union: this ∪ other public BrepModel Union(BrepModel other) { nint hdl = NativeMethods.vde_body_boolean(_ctx, _handle, other._handle, 0); return new BrepModel(_ctx, hdl); } /// Boolean intersection: this ∩ other public BrepModel Intersect(BrepModel other) { nint hdl = NativeMethods.vde_body_boolean(_ctx, _handle, other._handle, 1); return new BrepModel(_ctx, hdl); } /// Boolean difference: this \ other public BrepModel Diff(BrepModel other) { nint hdl = NativeMethods.vde_body_boolean(_ctx, _handle, other._handle, 2); return new BrepModel(_ctx, hdl); } // ═══════════════════════════════════════════════════ // Tessellation / Mesh // ═══════════════════════════════════════════════════ /// /// Tessellates the B-Rep model into a triangle mesh. /// /// Chord height error for tessellation (default 0.01) public MeshData ToMesh(double deflection = 0.01) { nint mh = NativeMethods.vde_body_to_mesh(_ctx, _handle, deflection); var mesh = new MeshData(mh, ownsHandle: true); mesh.ExtractFromNative(); return mesh; } /// /// Deep clone of this B-Rep model. /// public BrepModel Clone() { nint hdl = NativeMethods.vde_body_clone(_ctx, _handle); return new BrepModel(_ctx, hdl); } // ═══════════════════════════════════════════════════ // IDisposable // ═══════════════════════════════════════════════════ public void Dispose() { if (!_disposed && _handle != nint.Zero) { NativeMethods.vde_body_free(_handle); _handle = nint.Zero; _disposed = true; } } }