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;
}
}
}