diff --git a/GeoSharPlusCPP/CMakeLists.txt b/GeoSharPlusCPP/CMakeLists.txt index e83e3b8..41b2c23 100644 --- a/GeoSharPlusCPP/CMakeLists.txt +++ b/GeoSharPlusCPP/CMakeLists.txt @@ -5,7 +5,7 @@ set(PROJECT_NAME GeoSharPlusCPP) # Set the Visual Studio toolset to the latest version if(MSVC) set(CMAKE_GENERATOR_TOOLSET "v145" CACHE STRING "Visual Studio toolset version" FORCE) - message(STATUS "Using Visual Studio 2026 (Insider) toolset: ${CMAKE_GENERATOR_TOOLSET}") + message(STATUS "Using Visual Studio 2026 toolset: ${CMAKE_GENERATOR_TOOLSET}") endif() # Check for VCPKG_ROOT environment variable diff --git a/GeoSharPlusCPP/include/GeoSharPlusCPP/API/BridgeAPI.h b/GeoSharPlusCPP/include/GeoSharPlusCPP/Extensions/igMesh/BridgeAPI.h similarity index 100% rename from GeoSharPlusCPP/include/GeoSharPlusCPP/API/BridgeAPI.h rename to GeoSharPlusCPP/include/GeoSharPlusCPP/Extensions/igMesh/BridgeAPI.h diff --git a/GeoSharPlusCPP/src/API/BridgeAPI.cpp b/GeoSharPlusCPP/src/Extensions/igMesh/BridgeAPI.cpp similarity index 99% rename from GeoSharPlusCPP/src/API/BridgeAPI.cpp rename to GeoSharPlusCPP/src/Extensions/igMesh/BridgeAPI.cpp index aae9f7f..911c62e 100644 --- a/GeoSharPlusCPP/src/API/BridgeAPI.cpp +++ b/GeoSharPlusCPP/src/Extensions/igMesh/BridgeAPI.cpp @@ -1,4 +1,4 @@ -#include "GeoSharPlusCPP/API/BridgeAPI.h" +#include "GeoSharPlusCPP/Extensions/igMesh/BridgeAPI.h" #include #include diff --git a/GeoSharPlusNET/Adapters/Rhino/RhinoAdapter.cs b/GeoSharPlusNET/Adapters/Rhino/RhinoAdapter.cs new file mode 100644 index 0000000..8c227a6 --- /dev/null +++ b/GeoSharPlusNET/Adapters/Rhino/RhinoAdapter.cs @@ -0,0 +1,154 @@ +// ============================================ +// Rhino Geometry Adapter +// ============================================ +// This file provides conversions between Rhino.Geometry types +// and GSP.Geometry types for use with the GeoSharPlus library. +// +// To use this file, your project must reference RhinoCommon. +// ============================================ + +using System; +using System.Linq; +using Rhino.Geometry; + +namespace GSP.Adapters.Rhino { + /// + /// Adapter for converting between Rhino.Geometry types and GSP.Geometry types. + /// + public class RhinoAdapter : GSP.Geometry.IGeometryAdapter { + /// + /// Singleton instance of the adapter. + /// + public static RhinoAdapter Instance { get; } = new(); + + #region Point Conversions + + /// + /// Converts a Rhino Point3d to a GSP Vec3. + /// + public GSP.Geometry.Vec3 PointToGSP(Point3d point) => + new(point.X, point.Y, point.Z); + + /// + /// Converts a GSP Vec3 to a Rhino Point3d. + /// + public Point3d PointFromGSP(GSP.Geometry.Vec3 point) => + new(point.X, point.Y, point.Z); + + /// + /// Converts an array of Rhino Point3d to GSP Vec3 array. + /// + public GSP.Geometry.Vec3[] PointsToGSP(Point3d[] points) => + points.Select(p => new GSP.Geometry.Vec3(p.X, p.Y, p.Z)).ToArray(); + + /// + /// Converts a GSP Vec3 array to Rhino Point3d array. + /// + public Point3d[] PointsFromGSP(GSP.Geometry.Vec3[] points) => + points.Select(p => new Point3d(p.X, p.Y, p.Z)).ToArray(); + + #endregion + + #region Vector Conversions + + /// + /// Converts a Rhino Vector3d to a GSP Vec3. + /// + public GSP.Geometry.Vec3 VectorToGSP(Vector3d vector) => + new(vector.X, vector.Y, vector.Z); + + /// + /// Converts a GSP Vec3 to a Rhino Vector3d. + /// + public Vector3d VectorFromGSP(GSP.Geometry.Vec3 vector) => + new(vector.X, vector.Y, vector.Z); + + #endregion + + #region Mesh Conversions + + /// + /// Converts a Rhino Mesh to a GSP Mesh. + /// + public GSP.Geometry.Mesh MeshToGSP(global::Rhino.Geometry.Mesh mesh) { + var result = new GSP.Geometry.Mesh(); + + // Convert vertices + result.Vertices = mesh.Vertices + .Select(v => new GSP.Geometry.Vec3(v.X, v.Y, v.Z)) + .ToArray(); + + // Separate triangles and quads + var triangles = new System.Collections.Generic.List<(int, int, int)>(); + var quads = new System.Collections.Generic.List<(int, int, int, int)>(); + + foreach (var face in mesh.Faces) { + if (face.IsTriangle) { + triangles.Add((face.A, face.B, face.C)); + } else { + quads.Add((face.A, face.B, face.C, face.D)); + } + } + + result.TriangleFaces = triangles.ToArray(); + result.QuadFaces = quads.ToArray(); + + return result; + } + + /// + /// Converts a GSP Mesh to a Rhino Mesh. + /// + public global::Rhino.Geometry.Mesh MeshFromGSP(GSP.Geometry.Mesh gspMesh) { + var mesh = new global::Rhino.Geometry.Mesh(); + + // Add vertices + foreach (var v in gspMesh.Vertices) { + mesh.Vertices.Add(v.X, v.Y, v.Z); + } + + // Add triangle faces + foreach (var (a, b, c) in gspMesh.TriangleFaces) { + mesh.Faces.AddFace(a, b, c); + } + + // Add quad faces + foreach (var (a, b, c, d) in gspMesh.QuadFaces) { + mesh.Faces.AddFace(a, b, c, d); + } + + // Clean up mesh + if (mesh.IsValid) { + mesh.RebuildNormals(); + mesh.Compact(); + } + + return mesh; + } + + #endregion + } + + /// + /// Extension methods for converting between Rhino and GSP types. + /// + public static class RhinoExtensions { + private static readonly RhinoAdapter _adapter = RhinoAdapter.Instance; + + // Point3d extensions + public static GSP.Geometry.Vec3 ToGSP(this Point3d point) => _adapter.PointToGSP(point); + public static Point3d ToRhino(this GSP.Geometry.Vec3 point) => _adapter.PointFromGSP(point); + + // Point3d array extensions + public static GSP.Geometry.Vec3[] ToGSP(this Point3d[] points) => _adapter.PointsToGSP(points); + public static Point3d[] ToRhino(this GSP.Geometry.Vec3[] points) => _adapter.PointsFromGSP(points); + + // Vector3d extensions + public static GSP.Geometry.Vec3 ToGSP(this Vector3d vector) => _adapter.VectorToGSP(vector); + public static Vector3d ToRhinoVector(this GSP.Geometry.Vec3 vector) => _adapter.VectorFromGSP(vector); + + // Mesh extensions + public static GSP.Geometry.Mesh ToGSP(this global::Rhino.Geometry.Mesh mesh) => _adapter.MeshToGSP(mesh); + public static global::Rhino.Geometry.Mesh ToRhino(this GSP.Geometry.Mesh mesh) => _adapter.MeshFromGSP(mesh); + } +} diff --git a/GeoSharPlusNET/Wrapper.cs b/GeoSharPlusNET/Adapters/Rhino/Wrapper.cs similarity index 99% rename from GeoSharPlusNET/Wrapper.cs rename to GeoSharPlusNET/Adapters/Rhino/Wrapper.cs index f6292f2..7ee5f51 100644 --- a/GeoSharPlusNET/Wrapper.cs +++ b/GeoSharPlusNET/Adapters/Rhino/Wrapper.cs @@ -1,7 +1,7 @@ -using Google.FlatBuffers; +using Google.FlatBuffers; using Rhino.Geometry; -namespace GSP { +namespace GSP.Adapters.Rhino { public static class Wrapper { #region Point3d / Vector3d Operations diff --git a/GeoSharPlusNET/Core/MarshalHelper.cs b/GeoSharPlusNET/Core/MarshalHelper.cs new file mode 100644 index 0000000..c8a693a --- /dev/null +++ b/GeoSharPlusNET/Core/MarshalHelper.cs @@ -0,0 +1,63 @@ +using System; +using System.Runtime.InteropServices; + +namespace GSP.Core { + /// + /// Cross-platform utilities for marshaling data between C# and native code. + /// Works on Windows, macOS, and Linux. + /// + public static class MarshalHelper { + /// + /// Copies data from unmanaged memory to a managed byte array and frees the unmanaged memory. + /// This method handles the common pattern of receiving data from C++ code. + /// + /// Pointer to unmanaged memory allocated by native code. + /// Size of the data in bytes. + /// A managed byte array containing the copied data, or empty array if invalid. + /// + /// The native code should allocate memory using: + /// - Windows: CoTaskMemAlloc + /// - macOS/Linux: malloc (with appropriate .NET runtime mapping) + /// + /// This method uses Marshal.FreeCoTaskMem which works cross-platform in .NET Core/.NET 5+. + /// + public static byte[] CopyAndFree(IntPtr ptr, int size) { + if (ptr == IntPtr.Zero || size <= 0) + return Array.Empty(); + + try { + var buffer = new byte[size]; + Marshal.Copy(ptr, buffer, 0, size); + return buffer; + } + finally { + Marshal.FreeCoTaskMem(ptr); + } + } + + /// + /// Copies data from unmanaged memory without freeing it. + /// Use when you need to read data but the native side manages the memory. + /// + /// Pointer to unmanaged memory. + /// Size of the data in bytes. + /// A managed byte array containing the copied data. + public static byte[] Copy(IntPtr ptr, int size) { + if (ptr == IntPtr.Zero || size <= 0) + return Array.Empty(); + + var buffer = new byte[size]; + Marshal.Copy(ptr, buffer, 0, size); + return buffer; + } + + /// + /// Frees memory allocated by native code. + /// + /// Pointer to unmanaged memory to free. + public static void Free(IntPtr ptr) { + if (ptr != IntPtr.Zero) + Marshal.FreeCoTaskMem(ptr); + } + } +} diff --git a/GeoSharPlusNET/Core/Platform.cs b/GeoSharPlusNET/Core/Platform.cs new file mode 100644 index 0000000..8ffe53b --- /dev/null +++ b/GeoSharPlusNET/Core/Platform.cs @@ -0,0 +1,51 @@ +using System.Runtime.InteropServices; + +namespace GSP.Core { + /// + /// Platform detection and native library configuration. + /// Use these constants and helpers when creating P/Invoke declarations. + /// + public static class Platform { + /// + /// Native library name for Windows. + /// + public const string WindowsLib = "GeoSharPlusCPP.dll"; + + /// + /// Native library name for macOS. + /// + public const string MacLib = "libGeoSharPlusCPP.dylib"; + + /// + /// Native library name for Linux. + /// + public const string LinuxLib = "libGeoSharPlusCPP.so"; + + /// + /// Returns true if running on Windows. + /// + public static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + /// + /// Returns true if running on macOS. + /// + public static bool IsMac => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + + /// + /// Returns true if running on Linux. + /// + public static bool IsLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + + /// + /// Gets the appropriate native library name for the current platform. + /// + public static string NativeLibrary { + get { + if (IsWindows) return WindowsLib; + if (IsMac) return MacLib; + if (IsLinux) return LinuxLib; + throw new PlatformNotSupportedException("Unsupported platform"); + } + } + } +} diff --git a/GeoSharPlusNET/Core/Serializer.cs b/GeoSharPlusNET/Core/Serializer.cs new file mode 100644 index 0000000..60d621e --- /dev/null +++ b/GeoSharPlusNET/Core/Serializer.cs @@ -0,0 +1,392 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Google.FlatBuffers; + +namespace GSP.Core { + /// + /// Serialization utilities for converting geometry types to/from FlatBuffer byte arrays. + /// Use these methods to prepare data for C++ calls and parse results. + /// + /// + /// This class provides serialization for GSP.Geometry types (Vec3, Mesh, etc.) + /// which are platform-independent. For CAD-specific types (Rhino, AutoCAD, etc.), + /// use the appropriate adapter or the Wrapper class with Rhino types. + /// + public static class Serializer { + #region Vec3 Serialization + + /// + /// Serializes a Vec3 point to a FlatBuffer byte array. + /// + public static byte[] Serialize(Geometry.Vec3 point) { + var builder = new FlatBufferBuilder(64); + + FB.PointData.StartPointData(builder); + var vecOffset = FB.Vec3.CreateVec3(builder, point.X, point.Y, point.Z); + FB.PointData.AddPoint(builder, vecOffset); + var ptOffset = FB.PointData.EndPointData(builder); + + builder.Finish(ptOffset.Value); + return builder.SizedByteArray(); + } + + /// + /// Deserializes a FlatBuffer byte array to a Vec3 point. + /// + public static Geometry.Vec3 DeserializeVec3(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var ptData = FB.PointData.GetRootAsPointData(byteBuffer); + var pt = ptData.Point; + + return pt.HasValue + ? new Geometry.Vec3(pt.Value.X, pt.Value.Y, pt.Value.Z) + : Geometry.Vec3.Zero; + } + + #endregion + + #region Vec3 Array Serialization + + /// + /// Serializes an array of Vec3 points to a FlatBuffer byte array. + /// + public static byte[] Serialize(Geometry.Vec3[] points) { + var builder = new FlatBufferBuilder(1024); + + FB.PointArrayData.StartPointsVector(builder, points.Length); + for (int i = points.Length - 1; i >= 0; i--) { + FB.Vec3.CreateVec3(builder, points[i].X, points[i].Y, points[i].Z); + } + var ptOffset = builder.EndVector(); + + var arrayOffset = FB.PointArrayData.CreatePointArrayData(builder, ptOffset); + builder.Finish(arrayOffset.Value); + + return builder.SizedByteArray(); + } + + /// + /// Serializes a list of Vec3 points to a FlatBuffer byte array. + /// + public static byte[] Serialize(List points) => Serialize(points.ToArray()); + + /// + /// Deserializes a FlatBuffer byte array to an array of Vec3 points. + /// + public static Geometry.Vec3[] DeserializeVec3Array(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var pointArray = FB.PointArrayData.GetRootAsPointArrayData(byteBuffer); + + if (pointArray.PointsLength == 0) + return Array.Empty(); + + var result = new Geometry.Vec3[pointArray.PointsLength]; + for (int i = 0; i < pointArray.PointsLength; i++) { + var pt = pointArray.Points(i); + result[i] = pt.HasValue + ? new Geometry.Vec3(pt.Value.X, pt.Value.Y, pt.Value.Z) + : Geometry.Vec3.Zero; + } + return result; + } + + /// + /// Deserializes a FlatBuffer byte array to a list of Vec3 points. + /// + public static List DeserializeVec3List(byte[] buffer) => + new List(DeserializeVec3Array(buffer)); + + #endregion + + #region Mesh Serialization + + /// + /// Serializes a Mesh to a FlatBuffer byte array. + /// + /// The mesh to serialize. + /// If true, converts quads to triangles before serializing. + public static byte[] Serialize(Geometry.Mesh mesh, bool triangulate = false) { + var builder = new FlatBufferBuilder(1024); + + // Optionally triangulate + var workingMesh = mesh; + if (triangulate && mesh.HasQuads) { + workingMesh = mesh.Clone(); + workingMesh.Triangulate(); + } + + // Add vertices + FB.MeshData.StartVerticesVector(builder, workingMesh.Vertices.Length); + for (int i = workingMesh.Vertices.Length - 1; i >= 0; i--) { + var v = workingMesh.Vertices[i]; + FB.Vec3.CreateVec3(builder, v.X, v.Y, v.Z); + } + var verticesOffset = builder.EndVector(); + + VectorOffset facesOffset = default; + VectorOffset quadFacesOffset = default; + + if (workingMesh.HasQuads && !workingMesh.HasTriangles) { + // Pure quad mesh + FB.MeshData.StartQuadFacesVector(builder, workingMesh.QuadFaces.Length); + for (int i = workingMesh.QuadFaces.Length - 1; i >= 0; i--) { + var f = workingMesh.QuadFaces[i]; + FB.Vec4i.CreateVec4i(builder, f.A, f.B, f.C, f.D); + } + quadFacesOffset = builder.EndVector(); + } else { + // Triangle mesh (or mixed, triangulated) + FB.MeshData.StartFacesVector(builder, workingMesh.TriangleFaces.Length); + for (int i = workingMesh.TriangleFaces.Length - 1; i >= 0; i--) { + var f = workingMesh.TriangleFaces[i]; + FB.Vec3i.CreateVec3i(builder, f.A, f.B, f.C); + } + facesOffset = builder.EndVector(); + } + + // Create the mesh data + FB.MeshData.StartMeshData(builder); + FB.MeshData.AddVertices(builder, verticesOffset); + if (workingMesh.HasQuads && !workingMesh.HasTriangles) { + FB.MeshData.AddQuadFaces(builder, quadFacesOffset); + } else { + FB.MeshData.AddFaces(builder, facesOffset); + } + var meshOffset = FB.MeshData.EndMeshData(builder); + builder.Finish(meshOffset.Value); + + return builder.SizedByteArray(); + } + + /// + /// Deserializes a FlatBuffer byte array to a Mesh. + /// + public static Geometry.Mesh DeserializeMesh(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var meshData = FB.MeshData.GetRootAsMeshData(byteBuffer); + + var mesh = new Geometry.Mesh(); + + // Extract vertices + var vertices = new Geometry.Vec3[meshData.VerticesLength]; + for (int i = 0; i < meshData.VerticesLength; i++) { + var v = meshData.Vertices(i); + vertices[i] = v.HasValue + ? new Geometry.Vec3(v.Value.X, v.Value.Y, v.Value.Z) + : Geometry.Vec3.Zero; + } + mesh.Vertices = vertices; + + // Check for quad faces first + if (meshData.QuadFacesLength > 0) { + var quads = new (int, int, int, int)[meshData.QuadFacesLength]; + for (int i = 0; i < meshData.QuadFacesLength; i++) { + var f = meshData.QuadFaces(i); + quads[i] = f.HasValue ? (f.Value.X, f.Value.Y, f.Value.Z, f.Value.W) : (0, 0, 0, 0); + } + mesh.QuadFaces = quads; + } else { + // Triangle faces + var tris = new (int, int, int)[meshData.FacesLength]; + for (int i = 0; i < meshData.FacesLength; i++) { + var f = meshData.Faces(i); + tris[i] = f.HasValue ? (f.Value.X, f.Value.Y, f.Value.Z) : (0, 0, 0); + } + mesh.TriangleFaces = tris; + } + + return mesh; + } + + #endregion + + #region Primitive Array Serialization + + /// + /// Serializes an int array to a FlatBuffer byte array. + /// + public static byte[] Serialize(int[] values) { + var builder = new FlatBufferBuilder(1024); + var valuesOffset = FB.IntArrayData.CreateValuesVector(builder, values); + var arrayOffset = FB.IntArrayData.CreateIntArrayData(builder, valuesOffset); + builder.Finish(arrayOffset.Value); + return builder.SizedByteArray(); + } + + /// + /// Deserializes a FlatBuffer byte array to an int array. + /// + public static int[] DeserializeIntArray(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var arrayData = FB.IntArrayData.GetRootAsIntArrayData(byteBuffer); + + if (arrayData.ValuesLength == 0) + return Array.Empty(); + + var result = new int[arrayData.ValuesLength]; + for (int i = 0; i < arrayData.ValuesLength; i++) { + result[i] = arrayData.Values(i); + } + return result; + } + + /// + /// Serializes a double array to a FlatBuffer byte array. + /// + public static byte[] Serialize(double[] values) { + var builder = new FlatBufferBuilder(1024); + var valuesOffset = FB.DoubleArrayData.CreateValuesVector(builder, values); + var arrayOffset = FB.DoubleArrayData.CreateDoubleArrayData(builder, valuesOffset); + builder.Finish(arrayOffset.Value); + return builder.SizedByteArray(); + } + + /// + /// Deserializes a FlatBuffer byte array to a double array. + /// + public static double[] DeserializeDoubleArray(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var arrayData = FB.DoubleArrayData.GetRootAsDoubleArrayData(byteBuffer); + + if (arrayData.ValuesLength == 0) + return Array.Empty(); + + var result = new double[arrayData.ValuesLength]; + for (int i = 0; i < arrayData.ValuesLength; i++) { + result[i] = arrayData.Values(i); + } + return result; + } + + #endregion + + #region Pair Array Serialization + + /// + /// Serializes an array of int pairs to a FlatBuffer byte array. + /// + public static byte[] Serialize((int, int)[] pairs) { + var builder = new FlatBufferBuilder(1024); + + FB.IntPairArrayData.StartPairsVector(builder, pairs.Length); + for (int i = pairs.Length - 1; i >= 0; i--) { + FB.Vec2i.CreateVec2i(builder, pairs[i].Item1, pairs[i].Item2); + } + var pairsOffset = builder.EndVector(); + + var arrayOffset = FB.IntPairArrayData.CreateIntPairArrayData(builder, pairsOffset); + builder.Finish(arrayOffset.Value); + return builder.SizedByteArray(); + } + + /// + /// Deserializes a FlatBuffer byte array to an array of int pairs. + /// + public static (int, int)[] DeserializeIntPairArray(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var pairArray = FB.IntPairArrayData.GetRootAsIntPairArrayData(byteBuffer); + + if (pairArray.PairsLength == 0) + return Array.Empty<(int, int)>(); + + var result = new (int, int)[pairArray.PairsLength]; + for (int i = 0; i < pairArray.PairsLength; i++) { + var pair = pairArray.Pairs(i); + result[i] = pair.HasValue ? (pair.Value.X, pair.Value.Y) : (0, 0); + } + return result; + } + + /// + /// Serializes an array of double pairs to a FlatBuffer byte array. + /// + public static byte[] Serialize((double, double)[] pairs) { + var builder = new FlatBufferBuilder(1024); + + FB.DoublePairArrayData.StartPairsVector(builder, pairs.Length); + for (int i = pairs.Length - 1; i >= 0; i--) { + FB.Vec2.CreateVec2(builder, pairs[i].Item1, pairs[i].Item2); + } + var pairsOffset = builder.EndVector(); + + var arrayOffset = FB.DoublePairArrayData.CreateDoublePairArrayData(builder, pairsOffset); + builder.Finish(arrayOffset.Value); + return builder.SizedByteArray(); + } + + /// + /// Deserializes a FlatBuffer byte array to an array of double pairs. + /// + public static (double, double)[] DeserializeDoublePairArray(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var pairArray = FB.DoublePairArrayData.GetRootAsDoublePairArrayData(byteBuffer); + + if (pairArray.PairsLength == 0) + return Array.Empty<(double, double)>(); + + var result = new (double, double)[pairArray.PairsLength]; + for (int i = 0; i < pairArray.PairsLength; i++) { + var pair = pairArray.Pairs(i); + result[i] = pair.HasValue ? (pair.Value.X, pair.Value.Y) : (0.0, 0.0); + } + return result; + } + + #endregion + + #region Nested Array Serialization + + /// + /// Serializes a nested int array (jagged array) to a FlatBuffer byte array. + /// + public static byte[] Serialize(List> nestedArray) { + var builder = new FlatBufferBuilder(1024); + + var flatList = new List(); + var sizes = new List(); + + foreach (var subArray in nestedArray) { + sizes.Add(subArray.Count); + flatList.AddRange(subArray); + } + + var valuesOffset = FB.IntNestedArrayData.CreateValuesVector(builder, flatList.ToArray()); + var sizesOffset = FB.IntNestedArrayData.CreateSizesVector(builder, sizes.ToArray()); + + var arrayOffset = FB.IntNestedArrayData.CreateIntNestedArrayData(builder, valuesOffset, sizesOffset); + builder.Finish(arrayOffset.Value); + return builder.SizedByteArray(); + } + + /// + /// Deserializes a FlatBuffer byte array to a nested int array. + /// + public static List> DeserializeNestedIntArray(byte[] buffer) { + var byteBuffer = new ByteBuffer(buffer); + var arrayData = FB.IntNestedArrayData.GetRootAsIntNestedArrayData(byteBuffer); + + if (arrayData.ValuesLength == 0 || arrayData.SizesLength == 0) + return new List>(); + + var result = new List>(); + int flatIndex = 0; + + for (int i = 0; i < arrayData.SizesLength; i++) { + int subArraySize = arrayData.Sizes(i); + var subArray = new List(); + + for (int j = 0; j < subArraySize; j++) { + if (flatIndex < arrayData.ValuesLength) { + subArray.Add(arrayData.Values(flatIndex++)); + } + } + result.Add(subArray); + } + + return result; + } + + #endregion + } +} diff --git a/GeoSharPlusNET/Extensions/_README.md b/GeoSharPlusNET/Extensions/_README.md new file mode 100644 index 0000000..8357a40 --- /dev/null +++ b/GeoSharPlusNET/Extensions/_README.md @@ -0,0 +1,193 @@ +# GSP Extensions - How to Add Your Own C++ Functions + +This folder contains example extension functions that demonstrate how to bridge +C# and C++ code using the GeoSharPlus library. Use these as templates for your +own custom functions. + +## Architecture Overview + +``` +Your C# Code + ? + ? +??????????????????????????????????????????????????????????????????? +? GSP.Core.Serializer - Converts types to byte[] ? +? GSP.Core.MarshalHelper - Handles memory marshaling ? +? GSP.Core.Platform - OS detection, library paths ? +??????????????????????????????????????????????????????????????????? + ? + ? +??????????????????????????????????????????????????????????????????? +? Your P/Invoke Bridge - DllImport declarations ? +? Your High-Level Wrapper - Clean API for users ? +??????????????????????????????????????????????????????????????????? + ? + ? +??????????????????????????????????????????????????????????????????? +? GeoSharPlusCPP.dll - Your C++ implementation ? +??????????????????????????????????????????????????????????????????? +``` + +## Step-by-Step: Adding a New C++ Function + +### Step 1: Write the C++ Function + +In your C++ project, create a new function following this pattern: + +```cpp +// In your .h file +GSP_API bool GSP_CALL my_custom_function( + const uint8_t* inBuffer, int inSize, + uint8_t** outBuffer, int* outSize); + +// In your .cpp file +GSP_API bool GSP_CALL my_custom_function( + const uint8_t* inBuffer, int inSize, + uint8_t** outBuffer, int* outSize) { + + // 1. Initialize output + *outBuffer = nullptr; + *outSize = 0; + + // 2. Deserialize input + std::vector points; + if (!GS::deserializePointArray(inBuffer, inSize, points)) { + return false; + } + + // 3. Do your processing + // ... your algorithm here ... + + // 4. Serialize output + if (!GS::serializePointArray(points, *outBuffer, *outSize)) { + return false; + } + + return true; +} +``` + +### Step 2: Add P/Invoke Declaration in C# + +Create a bridge class with platform-specific imports: + +```csharp +using System; +using System.Runtime.InteropServices; +using GSP.Core; + +namespace MyProject { + public static class MyBridge { + // Windows + [DllImport(Platform.WindowsLib, EntryPoint = "my_custom_function", + CallingConvention = CallingConvention.Cdecl)] + private static extern bool MyCustomFunctionWin( + byte[] inBuffer, int inSize, + out IntPtr outBuffer, out int outSize); + + // macOS + [DllImport(Platform.MacLib, EntryPoint = "my_custom_function", + CallingConvention = CallingConvention.Cdecl)] + private static extern bool MyCustomFunctionMac( + byte[] inBuffer, int inSize, + out IntPtr outBuffer, out int outSize); + + // Cross-platform wrapper + public static bool MyCustomFunction( + byte[] inBuffer, int inSize, + out IntPtr outBuffer, out int outSize) { + + if (Platform.IsWindows) + return MyCustomFunctionWin(inBuffer, inSize, out outBuffer, out outSize); + else + return MyCustomFunctionMac(inBuffer, inSize, out outBuffer, out outSize); + } + } +} +``` + +### Step 3: Create High-Level Wrapper + +Create a clean API that hides serialization details: + +```csharp +using GSP.Core; +using GSP.Geometry; + +namespace MyProject { + public static class MyUtils { + /// + /// Processes points using my custom C++ algorithm. + /// + public static Vec3[]? ProcessPoints(Vec3[] points) { + // 1. Serialize input + var buffer = Serializer.Serialize(points); + + // 2. Call native function + if (!MyBridge.MyCustomFunction(buffer, buffer.Length, + out IntPtr outPtr, out int outSize)) + return null; + + // 3. Marshal result + var resultBuffer = MarshalHelper.CopyAndFree(outPtr, outSize); + + // 4. Deserialize and return + return Serializer.DeserializeVec3Array(resultBuffer); + } + } +} +``` + +### Step 4: Use with Rhino Types (Optional) + +If working with Rhino, use the adapter: + +```csharp +using GSP.Adapters.Rhino; +using Rhino.Geometry; + +// Convert Rhino -> GSP -> Process -> GSP -> Rhino +var rhinoPoints = new Point3d[] { ... }; +var gspPoints = rhinoPoints.ToGSP(); +var result = MyUtils.ProcessPoints(gspPoints); +var rhinoResult = result?.ToRhino(); +``` + +## Available Types + +### GSP.Geometry (Platform-Independent) +- `Vec2` - 2D point/vector +- `Vec3` - 3D point/vector +- `Mesh` - Mesh with vertices and faces + +### GSP.Core.Serializer Methods +- `Serialize(Vec3)` / `DeserializeVec3(byte[])` +- `Serialize(Vec3[])` / `DeserializeVec3Array(byte[])` +- `Serialize(Mesh)` / `DeserializeMesh(byte[])` +- `Serialize(int[])` / `DeserializeIntArray(byte[])` +- `Serialize(double[])` / `DeserializeDoubleArray(byte[])` +- `Serialize((int,int)[])` / `DeserializeIntPairArray(byte[])` +- `Serialize((double,double)[])` / `DeserializeDoublePairArray(byte[])` + +### GSP.Core.MarshalHelper Methods +- `CopyAndFree(IntPtr, int)` - Copy from unmanaged and free +- `Copy(IntPtr, int)` - Copy without freeing +- `Free(IntPtr)` - Free unmanaged memory + +## File Organization + +Recommended structure for your extensions: + +``` +YourProject/ +??? Bridge/ +? ??? MyBridge.cs # P/Invoke declarations +??? Utils/ +? ??? MyUtils.cs # High-level wrappers +??? ... +``` + +## See Also + +- `ExampleExtensions.cs` - Complete working examples +- C++ side: `GeoSharPlusCPP/include/GeoSharPlusCPP/Extensions/` diff --git a/GeoSharPlusNET/MeshUtils.cs b/GeoSharPlusNET/Extensions/igMesh/MeshUtils.cs similarity index 96% rename from GeoSharPlusNET/MeshUtils.cs rename to GeoSharPlusNET/Extensions/igMesh/MeshUtils.cs index 3f7b6ee..9aea28a 100644 --- a/GeoSharPlusNET/MeshUtils.cs +++ b/GeoSharPlusNET/Extensions/igMesh/MeshUtils.cs @@ -1,7 +1,10 @@ -using Rhino.Geometry; +using Rhino.Geometry; using System.Runtime.InteropServices; -namespace GSP { +using GSP; +using GSP.Adapters.Rhino; + +namespace igMesh.Native { public static class MeshUtils { private static Point3d Centroid(Mesh mesh) { // Serialize the mesh for calling into GeoSharPlusCPP @@ -9,7 +12,7 @@ private static Point3d Centroid(Mesh mesh) { meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the C++ function to calculate centroid - var success = NativeBridge.MeshCentroid( + var success = igMeshBridge.MeshCentroid( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success) { throw new InvalidOperationException("Failed to calculate mesh centroid in native code."); @@ -55,7 +58,7 @@ public static bool LoadMesh(string fileName, out Mesh mesh) { return false; } // Load the mesh using GeoSharPlusCPP - var success = NativeBridge.LoadMesh(fileName, out IntPtr outBuffer, out int outSize); + var success = igMeshBridge.LoadMesh(fileName, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { return false; } @@ -76,7 +79,7 @@ public static bool SaveMesh(ref Mesh mesh, string fileName) { } var meshBuffer = Wrapper.ToMeshBuffer(mesh); - var success = NativeBridge.SaveMesh(meshBuffer, meshBuffer.Length, fileName); + var success = igMeshBridge.SaveMesh(meshBuffer, meshBuffer.Length, fileName); return success; } @@ -92,7 +95,7 @@ public static List GetBarycenter(ref Mesh rMesh) { throw new ArgumentNullException(nameof(rMesh)); var meshBuffer = Wrapper.ToMeshBuffer(rMesh); - NativeBridge.IGM_barycenter( + igMeshBridge.IGM_barycenter( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); // Copy the result from unmanaged memory to a managed byte array @@ -118,7 +121,7 @@ public static List GetNormalVert(ref Mesh mesh) { var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function - var success = NativeBridge.IGM_vert_normals( + var success = igMeshBridge.IGM_vert_normals( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { @@ -149,7 +152,7 @@ public static List GetNormalFace(ref Mesh mesh) { var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function - var success = NativeBridge.IGM_face_normals( + var success = igMeshBridge.IGM_face_normals( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { @@ -183,7 +186,7 @@ public static List> GetNormalCorner(ref Mesh mesh, var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function - var success = NativeBridge.IGM_corner_normals( + var success = igMeshBridge.IGM_corner_normals( meshBuffer, meshBuffer.Length, thresholdDegrees, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { @@ -227,7 +230,7 @@ public static (List EdgeNormals, List> EdgeIndices, List> GetAdjacencyVV(ref Mesh mesh) { var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function to get vertex-vertex adjacency - var success = NativeBridge.IGM_vert_vert_adjacency( + var success = igMeshBridge.IGM_vert_vert_adjacency( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { return new List>(); @@ -312,7 +315,7 @@ public static (List> VT, List> VTI) GetAdjacencyVT(ref Mesh var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function to get vertex-triangle adjacency - var success = NativeBridge.IGM_vert_tri_adjacency(meshBuffer, + var success = igMeshBridge.IGM_vert_tri_adjacency(meshBuffer, meshBuffer.Length, out IntPtr outBufferVT, out int outSizeVT, @@ -354,7 +357,7 @@ public static (List> TT, List> TTI) GetAdjacencyTT(ref Mesh var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function to get triangle-triangle adjacency - var success = NativeBridge.IGM_tri_tri_adjacency(meshBuffer, + var success = igMeshBridge.IGM_tri_tri_adjacency(meshBuffer, meshBuffer.Length, out IntPtr outBufferTT, out int outSizeTT, @@ -395,7 +398,7 @@ public static List> GetBoundaryLoop(ref Mesh mesh) { var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function to get boundary loops - var success = NativeBridge.IGM_boundary_loop( + var success = igMeshBridge.IGM_boundary_loop( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { return new List>(); @@ -427,7 +430,7 @@ public static (List EdgeGeometry, List> EdgeIndices, List T var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function to get boundary facets - var success = NativeBridge.IGM_boundary_facet(meshBuffer, + var success = igMeshBridge.IGM_boundary_facet(meshBuffer, meshBuffer.Length, out IntPtr outBufferEL, out int outSizeEL, @@ -487,7 +490,7 @@ public static List RemapVtoF(ref Mesh mesh, List vertexScalars) var scalarBuffer = Wrapper.ToDoubleArrayBuffer(vertexScalars); // Call the native function - var success = NativeBridge.IGM_remap_VtoF(meshBuffer, + var success = igMeshBridge.IGM_remap_VtoF(meshBuffer, meshBuffer.Length, scalarBuffer, scalarBuffer.Length, @@ -527,7 +530,7 @@ public static List RemapFtoV(ref Mesh mesh, List faceScalars) { var scalarBuffer = Wrapper.ToDoubleArrayBuffer(faceScalars); // Call the native function - var success = NativeBridge.IGM_remap_FtoV(meshBuffer, + var success = igMeshBridge.IGM_remap_FtoV(meshBuffer, meshBuffer.Length, scalarBuffer, scalarBuffer.Length, @@ -563,7 +566,7 @@ public static (List PD1, List PD2, List PV1, List GetGaussianCurvature(ref Mesh mesh) { var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function - var success = NativeBridge.IGM_gaussian_curvature( + var success = igMeshBridge.IGM_gaussian_curvature( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { @@ -658,7 +661,7 @@ public static List GetFastWindingNumber(ref Mesh mesh, ref List var pointsBuffer = Wrapper.ToPointArrayBuffer(queryVector3ds); // Call the native function - var success = NativeBridge.IGM_fast_winding_number(meshBuffer, + var success = igMeshBridge.IGM_fast_winding_number(meshBuffer, meshBuffer.Length, pointsBuffer, pointsBuffer.Length, @@ -702,7 +705,7 @@ public static (List SignedDistances, List FaceIndices, List GetQuadPlanarity(ref Mesh mesh) { var meshBuffer = Wrapper.ToMeshBuffer(mesh, preserveQuads: true); // Call the native function - var success = NativeBridge.IGM_quad_planarity( + var success = igMeshBridge.IGM_quad_planarity( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { @@ -787,7 +790,7 @@ public static Mesh var meshBuffer = Wrapper.ToMeshBuffer(mesh, preserveQuads: true); // Call the native function - var success = NativeBridge.IGM_planarize_quad_mesh(meshBuffer, + var success = igMeshBridge.IGM_planarize_quad_mesh(meshBuffer, meshBuffer.Length, maxIterations, threshold, @@ -834,7 +837,7 @@ public static List GetLaplacianScalar(ref Mesh mesh, var valuesBuffer = Wrapper.ToDoubleArrayBuffer(constraintValues); // Call the native function - var success = NativeBridge.IGM_laplacian_scalar(meshBuffer, + var success = igMeshBridge.IGM_laplacian_scalar(meshBuffer, meshBuffer.Length, indicesBuffer, indicesBuffer.Length, @@ -875,7 +878,7 @@ public static List GetHarmonicParametrization(ref Mesh mesh, int k = 1) var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function - var success = NativeBridge.IGM_param_harmonic( + var success = igMeshBridge.IGM_param_harmonic( meshBuffer, meshBuffer.Length, k, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { @@ -908,7 +911,7 @@ public static long GetHeatGeodesicPrecomputedData(ref Mesh mesh) { var meshBuffer = Wrapper.ToMeshBuffer(mesh); // Call the native function - var success = NativeBridge.IGM_heat_geodesic_precompute( + var success = igMeshBridge.IGM_heat_geodesic_precompute( meshBuffer, meshBuffer.Length, out IntPtr outBuffer, out int outSize); if (!success || outBuffer == IntPtr.Zero) { @@ -946,7 +949,7 @@ public static List GetHeatGeodesicDistances(long precomputedHandle, var sourcesBuffer = Wrapper.ToIntArrayBuffer(sourceVertices); // Call the native function - var success = NativeBridge.IGM_heat_geodesic_solve(handleBuffer, + var success = igMeshBridge.IGM_heat_geodesic_solve(handleBuffer, handleBuffer.Length, sourcesBuffer, sourcesBuffer.Length, @@ -990,7 +993,7 @@ public static (List Points, List FaceIndices) if (method == 0) { // Random sampling - success = NativeBridge.IGM_random_point_on_mesh(meshBuffer, + success = igMeshBridge.IGM_random_point_on_mesh(meshBuffer, meshBuffer.Length, N, out outBufferPoints, @@ -999,7 +1002,7 @@ public static (List Points, List FaceIndices) out outSizeFI); } else { // Blue noise (uniform) sampling - success = NativeBridge.IGM_blue_noise_sampling_on_mesh(meshBuffer, + success = igMeshBridge.IGM_blue_noise_sampling_on_mesh(meshBuffer, meshBuffer.Length, N, out outBufferPoints, @@ -1055,7 +1058,7 @@ public static List GetConstrainedScalar(ref Mesh mesh, var valuesBuffer = Wrapper.ToDoubleArrayBuffer(constraintValues); // Call the native function - var success = NativeBridge.IGM_constrained_scalar(meshBuffer, + var success = igMeshBridge.IGM_constrained_scalar(meshBuffer, meshBuffer.Length, indicesBuffer, indicesBuffer.Length, @@ -1102,7 +1105,7 @@ public static List> var isoBuffer = Wrapper.ToDoubleArrayBuffer(isoValues); // Call the native function - var success = NativeBridge.IGM_extract_isoline_from_scalar(meshBuffer, + var success = igMeshBridge.IGM_extract_isoline_from_scalar(meshBuffer, meshBuffer.Length, scalarBuffer, scalarBuffer.Length, @@ -1397,4 +1400,4 @@ private static Vector3d CalculateDirectionCentroid(List directions) { return sum; } } -} // namespace GSP +} // namespace igMesh.Native diff --git a/GeoSharPlusNET/NativeBridge.cs b/GeoSharPlusNET/Extensions/igMesh/igMeshBridge.cs similarity index 87% rename from GeoSharPlusNET/NativeBridge.cs rename to GeoSharPlusNET/Extensions/igMesh/igMeshBridge.cs index b79d300..78bba08 100644 --- a/GeoSharPlusNET/NativeBridge.cs +++ b/GeoSharPlusNET/Extensions/igMesh/igMeshBridge.cs @@ -1,10 +1,11 @@ // using System; using System.Runtime.InteropServices; -namespace GSP { -public static class NativeBridge { - private const string WinLibName = @"GeoSharPlusCPP.dll"; - private const string MacLibName = @"libGeoSharPlusCPP.dylib"; +using GSP.Core; + +namespace igMesh.Native { +public static class igMeshBridge { + // Using GSP.Core.Platform for library names // System debugging functions for cross-platform support @@ -76,10 +77,11 @@ private static void LogError(string message) { [DllImport("libdl.dylib", EntryPoint = "dlerror")] private static extern IntPtr dlerror_mac(); - + private static string dlerror() { IntPtr ptr = dlerror_mac(); - if (ptr == IntPtr.Zero) return string.Empty; + if (ptr == IntPtr.Zero) + return string.Empty; return Marshal.PtrToStringAnsi(ptr) ?? string.Empty; } @@ -88,16 +90,18 @@ private static string dlerror() { /// This prevents the entire assembly from failing to load if the native lib isn't found /// private static void InitializeNativeLibrary() { - if (_initializationAttempted) return; - + if (_initializationAttempted) + return; + lock (_errorLog) { - if (_initializationAttempted) return; + if (_initializationAttempted) + return; _initializationAttempted = true; - + try { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { + if (Platform.IsMac) { InitializeMacOSLibrary(); - } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + } else if (Platform.IsWindows) { InitializeWindowsLibrary(); } else { LogError("Unsupported operating system. Only Windows and macOS are supported."); @@ -118,24 +122,24 @@ private static void InitializeMacOSLibrary() { string assemblyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; string? assemblyDirectory = Path.GetDirectoryName(assemblyLocation); if (assemblyDirectory != null) { - searchLocations.Add(Path.Combine(assemblyDirectory, MacLibName)); + searchLocations.Add(Path.Combine(assemblyDirectory, Platform.MacLib)); } // 2. Try parent directory (sometimes needed for GH plugins) if (assemblyDirectory != null) { string? parentDir = Path.GetDirectoryName(assemblyDirectory); if (parentDir != null) { - searchLocations.Add(Path.Combine(parentDir, MacLibName)); + searchLocations.Add(Path.Combine(parentDir, Platform.MacLib)); } } // 3. Try current directory - searchLocations.Add(Path.Combine(Directory.GetCurrentDirectory(), MacLibName)); + searchLocations.Add(Path.Combine(Directory.GetCurrentDirectory(), Platform.MacLib)); // 4. Add standard system locations - searchLocations.Add(MacLibName); // Default system search paths + searchLocations.Add(Platform.MacLib); // Default system search paths - LogError($"Searching for {MacLibName} in the following locations:"); + LogError($"Searching for {Platform.MacLib} in the following locations:"); foreach (var path in searchLocations) { LogError($"- {path} (exists: {File.Exists(path)})"); } @@ -145,7 +149,7 @@ private static void InitializeMacOSLibrary() { foreach (var libraryPath in searchLocations) { if (File.Exists(libraryPath)) { LogError($"Attempting to load native library from: {libraryPath}"); - + try { handle = dlopen_mac(libraryPath, 2); // RTLD_NOW = 2 @@ -164,7 +168,8 @@ private static void InitializeMacOSLibrary() { } } - LogError($"Failed to load native library from any location. Plugin functionality will be limited."); + LogError( + $"Failed to load native library from any location. Plugin functionality will be limited."); } catch (Exception ex) { LogError($"Exception while setting up native library path: {ex.Message}"); LogError($"Stack trace: {ex.StackTrace}"); @@ -179,12 +184,12 @@ private static void InitializeWindowsLibrary() { string dllPath = string.Empty; if (assemblyDirectory != null) { - dllPath = Path.Combine(assemblyDirectory, WinLibName); + dllPath = Path.Combine(assemblyDirectory, Platform.WindowsLib); if (!File.Exists(dllPath)) { // Try parent directory string? parentDir = Path.GetDirectoryName(assemblyDirectory); if (parentDir != null) { - dllPath = Path.Combine(parentDir, WinLibName); + dllPath = Path.Combine(parentDir, Platform.WindowsLib); } } } @@ -194,7 +199,7 @@ private static void InitializeWindowsLibrary() { _loadedLibraryPath = dllPath; LogError($"Successfully located native library at: {dllPath}"); } else { - LogError($"Failed to locate native library {WinLibName} in expected locations."); + LogError($"Failed to locate native library {Platform.WindowsLib} in expected locations."); LogError($"Searched: {dllPath}"); } } catch (Exception ex) { @@ -209,13 +214,13 @@ private static void InitializeWindowsLibrary() { #region Example Round Trip Functions // Double Array Round Trip - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "double_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool DoubleArrayRoundTripWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "double_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool @@ -223,39 +228,41 @@ private static extern bool public static bool DoubleArrayRoundTrip(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return DoubleArrayRoundTripWin(inBuffer, inSize, out outBuffer, out outSize); else return DoubleArrayRoundTripMac(inBuffer, inSize, out outBuffer, out outSize); } // Int Array Round Trip - [DllImport( - WinLibName, EntryPoint = "int_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "int_array_roundtrip", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IntArrayRoundTripWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "int_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "int_array_roundtrip", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IntArrayRoundTripMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool IntArrayRoundTrip(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IntArrayRoundTripWin(inBuffer, inSize, out outBuffer, out outSize); else return IntArrayRoundTripMac(inBuffer, inSize, out outBuffer, out outSize); } // Int Pair Array Round Trip - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "int_pair_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool IntPairArrayRoundTripWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "int_pair_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool @@ -263,20 +270,20 @@ private static extern bool public static bool IntPairArrayRoundTrip(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IntPairArrayRoundTripWin(inBuffer, inSize, out outBuffer, out outSize); else return IntPairArrayRoundTripMac(inBuffer, inSize, out outBuffer, out outSize); } // Double Pair Array Round Trip - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "double_pair_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool DoublePairArrayRoundTripWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "double_pair_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool @@ -284,59 +291,62 @@ private static extern bool public static bool DoublePairArrayRoundTrip(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return DoublePairArrayRoundTripWin(inBuffer, inSize, out outBuffer, out outSize); else return DoublePairArrayRoundTripMac(inBuffer, inSize, out outBuffer, out outSize); } // Example: Point Round Trip -- Passing a Point3d to C++ and back - [DllImport( - WinLibName, EntryPoint = "point3d_roundtrip", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "point3d_roundtrip", + CallingConvention = CallingConvention.Cdecl)] private static extern bool Point3dRoundTripWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "point3d_roundtrip", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "point3d_roundtrip", + CallingConvention = CallingConvention.Cdecl)] private static extern bool Point3dRoundTripMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool Point3dRoundTrip(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return Point3dRoundTripWin(inBuffer, inSize, out outBuffer, out outSize); else return Point3dRoundTripMac(inBuffer, inSize, out outBuffer, out outSize); } // Example: Point Array Round Trip -- Passing an array of Point3d to C++ and back - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "point3d_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool Point3dArrayRoundTripWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "point3d_array_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool Point3dArrayRoundTripMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool Point3dArrayRoundTrip(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return Point3dArrayRoundTripWin(inBuffer, inSize, out outBuffer, out outSize); else return Point3dArrayRoundTripMac(inBuffer, inSize, out outBuffer, out outSize); } // Mesh Round Trip -- Passing a Mesh to C++ and back - [DllImport( - WinLibName, EntryPoint = "mesh_roundtrip", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "mesh_roundtrip", + CallingConvention = CallingConvention.Cdecl)] private static extern bool MeshRoundTripWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); [DllImport( - MacLibName, EntryPoint = "mesh_roundtrip", CallingConvention = CallingConvention.Cdecl)] + Platform.MacLib, EntryPoint = "mesh_roundtrip", CallingConvention = CallingConvention.Cdecl)] private static extern bool MeshRoundTripMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool MeshRoundTrip(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return MeshRoundTripWin(inBuffer, inSize, out outBuffer, out outSize); else return MeshRoundTripMac(inBuffer, inSize, out outBuffer, out outSize); @@ -346,128 +356,139 @@ public static bool #region IG - MESH Functions // Mesh Centroid -- calculates the centroid of a mesh - [DllImport(WinLibName, EntryPoint = "IGM_centroid", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_centroid", + CallingConvention = CallingConvention.Cdecl)] private static extern bool MeshCentroidWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, EntryPoint = "IGM_centroid", CallingConvention = CallingConvention.Cdecl)] + [DllImport( + Platform.MacLib, EntryPoint = "IGM_centroid", CallingConvention = CallingConvention.Cdecl)] private static extern bool MeshCentroidMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool MeshCentroid(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return MeshCentroidWin(inBuffer, inSize, out outBuffer, out outSize); else return MeshCentroidMac(inBuffer, inSize, out outBuffer, out outSize); } // Load Mesh -- basic function to get a mesh from the native library - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_read_triangle_mesh", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private static extern bool LoadMeshWin(string fileName, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_read_triangle_mesh", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private static extern bool LoadMeshMac(string fileName, out IntPtr outBuffer, out int outSize); public static bool LoadMesh(string fileName, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return LoadMeshWin(fileName, out outBuffer, out outSize); else return LoadMeshMac(fileName, out outBuffer, out outSize); } // Save Mesh -- basic function to export a mesh to local HDD - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_write_triangle_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool SaveMeshWin(byte[] inBuffer, int inSize, string fileName); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_write_triangle_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool SaveMeshMac(byte[] inBuffer, int inSize, string fileName); public static bool SaveMesh(byte[] inBuffer, int inSize, string fileName) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return SaveMeshWin(inBuffer, inSize, fileName); else return SaveMeshMac(inBuffer, inSize, fileName); } - [DllImport( - WinLibName, EntryPoint = "IGM_barycenter", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_barycenter", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_barycenterWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); [DllImport( - MacLibName, EntryPoint = "IGM_barycenter", CallingConvention = CallingConvention.Cdecl)] + Platform.MacLib, EntryPoint = "IGM_barycenter", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_barycenterMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool IGM_barycenter(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_barycenterWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_barycenterMac(inBuffer, inSize, out outBuffer, out outSize); } // Vertex Normals - [DllImport( - WinLibName, EntryPoint = "IGM_vert_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_vert_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_vert_normalsWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "IGM_vert_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_vert_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_vert_normalsMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool IGM_vert_normals(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_vert_normalsWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_vert_normalsMac(inBuffer, inSize, out outBuffer, out outSize); } // Face Normals - [DllImport( - WinLibName, EntryPoint = "IGM_face_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_face_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_face_normalsWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "IGM_face_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_face_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_face_normalsMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool IGM_face_normals(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_face_normalsWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_face_normalsMac(inBuffer, inSize, out outBuffer, out outSize); } // Corner Normals - note the additional threshold_deg parameter - [DllImport( - WinLibName, EntryPoint = "IGM_corner_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_corner_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_corner_normalsWin( byte[] inBuffer, int inSize, double threshold_deg, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "IGM_corner_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_corner_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_corner_normalsMac( byte[] inBuffer, int inSize, double threshold_deg, out IntPtr outBuffer, out int outSize); public static bool IGM_corner_normals( byte[] inBuffer, int inSize, double threshold_deg, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_corner_normalsWin(inBuffer, inSize, threshold_deg, out outBuffer, out outSize); else return IGM_corner_normalsMac(inBuffer, inSize, threshold_deg, out outBuffer, out outSize); } // Edge Normals - note the multiple output parameters - [DllImport( - WinLibName, EntryPoint = "IGM_edge_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_edge_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_edge_normalsWin(byte[] inBuffer, int inSize, int weightingType, @@ -477,8 +498,9 @@ private static extern bool IGM_edge_normalsWin(byte[] inBuffer, out int obsEI, out IntPtr obEMAP, out int obsEMAP); - [DllImport( - MacLibName, EntryPoint = "IGM_edge_normals", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_edge_normals", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_edge_normalsMac(byte[] inBuffer, int inSize, int weightingType, @@ -498,7 +520,7 @@ public static bool IGM_edge_normals(byte[] inBuffer, out int obsEI, out IntPtr obEMAP, out int obsEMAP) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_edge_normalsWin(inBuffer, inSize, weightingType, @@ -521,12 +543,12 @@ public static bool IGM_edge_normals(byte[] inBuffer, } // Vertex-Vertex Adjacency - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_vert_vert_adjacency", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_vert_vert_adjacencyWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_vert_vert_adjacency", CallingConvention = CallingConvention.Cdecl)] private static extern bool @@ -534,14 +556,14 @@ private static extern bool public static bool IGM_vert_vert_adjacency(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_vert_vert_adjacencyWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_vert_vert_adjacencyMac(inBuffer, inSize, out outBuffer, out outSize); } // Vertex-Triangle Adjacency - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_vert_tri_adjacency", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_vert_tri_adjacencyWin(byte[] inBuffer, @@ -550,7 +572,7 @@ private static extern bool IGM_vert_tri_adjacencyWin(byte[] inBuffer, out int outSizeVT, out IntPtr outBufferVTI, out int outSizeVTI); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_vert_tri_adjacency", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_vert_tri_adjacencyMac(byte[] inBuffer, @@ -566,7 +588,7 @@ public static bool IGM_vert_tri_adjacency(byte[] inBuffer, out int outSizeVT, out IntPtr outBufferVTI, out int outSizeVTI) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_vert_tri_adjacencyWin( inBuffer, inSize, out outBufferVT, out outSizeVT, out outBufferVTI, out outSizeVTI); else @@ -575,7 +597,7 @@ public static bool IGM_vert_tri_adjacency(byte[] inBuffer, } // Triangle-Triangle Adjacency - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_tri_tri_adjacency", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_tri_tri_adjacencyWin(byte[] inBuffer, @@ -584,7 +606,7 @@ private static extern bool IGM_tri_tri_adjacencyWin(byte[] inBuffer, out int outSizeTT, out IntPtr outBufferTTI, out int outSizeTTI); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_tri_tri_adjacency", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_tri_tri_adjacencyMac(byte[] inBuffer, @@ -600,7 +622,7 @@ public static bool IGM_tri_tri_adjacency(byte[] inBuffer, out int outSizeTT, out IntPtr outBufferTTI, out int outSizeTTI) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_tri_tri_adjacencyWin( inBuffer, inSize, out outBufferTT, out outSizeTT, out outBufferTTI, out outSizeTTI); else @@ -609,34 +631,38 @@ public static bool IGM_tri_tri_adjacency(byte[] inBuffer, } // Boundary Loop - [DllImport( - WinLibName, EntryPoint = "IGM_boundary_loop", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_boundary_loop", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_boundary_loopWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "IGM_boundary_loop", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_boundary_loop", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_boundary_loopMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool IGM_boundary_loop(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_boundary_loopWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_boundary_loopMac(inBuffer, inSize, out outBuffer, out outSize); } // Boundary Facet - [DllImport( - WinLibName, EntryPoint = "IGM_boundary_facet", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_boundary_facet", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_boundary_facetWin(byte[] inBuffer, int inSize, out IntPtr outBufferEL, out int outSizeEL, out IntPtr outBufferTL, out int outSizeTL); - [DllImport( - MacLibName, EntryPoint = "IGM_boundary_facet", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_boundary_facet", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_boundary_facetMac(byte[] inBuffer, int inSize, out IntPtr outBufferEL, @@ -650,7 +676,7 @@ public static bool IGM_boundary_facet(byte[] inBuffer, out int outSizeEL, out IntPtr outBufferTL, out int outSizeTL) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_boundary_facetWin( inBuffer, inSize, out outBufferEL, out outSizeEL, out outBufferTL, out outSizeTL); else @@ -659,8 +685,9 @@ public static bool IGM_boundary_facet(byte[] inBuffer, } // Scalar Remap VtoF - [DllImport( - WinLibName, EntryPoint = "IGM_remap_VtoF", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_remap_VtoF", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_remap_VtoFWin(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferScalar, @@ -668,7 +695,7 @@ private static extern bool IGM_remap_VtoFWin(byte[] inBufferMesh, out IntPtr outBuffer, out int outSize); [DllImport( - MacLibName, EntryPoint = "IGM_remap_VtoF", CallingConvention = CallingConvention.Cdecl)] + Platform.MacLib, EntryPoint = "IGM_remap_VtoF", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_remap_VtoFMac(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferScalar, @@ -682,7 +709,7 @@ public static bool IGM_remap_VtoF(byte[] inBufferMesh, int inSizeScalar, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_remap_VtoFWin( inBufferMesh, inSizeMesh, inBufferScalar, inSizeScalar, out outBuffer, out outSize); else @@ -691,8 +718,9 @@ public static bool IGM_remap_VtoF(byte[] inBufferMesh, } // Scalar Remap FtoV - [DllImport( - WinLibName, EntryPoint = "IGM_remap_FtoV", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_remap_FtoV", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_remap_FtoVWin(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferScalar, @@ -700,7 +728,7 @@ private static extern bool IGM_remap_FtoVWin(byte[] inBufferMesh, out IntPtr outBuffer, out int outSize); [DllImport( - MacLibName, EntryPoint = "IGM_remap_FtoV", CallingConvention = CallingConvention.Cdecl)] + Platform.MacLib, EntryPoint = "IGM_remap_FtoV", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_remap_FtoVMac(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferScalar, @@ -714,7 +742,7 @@ public static bool IGM_remap_FtoV(byte[] inBufferMesh, int inSizeScalar, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_remap_FtoVWin( inBufferMesh, inSizeMesh, inBufferScalar, inSizeScalar, out outBuffer, out outSize); else @@ -723,7 +751,7 @@ public static bool IGM_remap_FtoV(byte[] inBufferMesh, } // Principal Curvature - note the multiple output parameters - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_principal_curvature", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_principal_curvatureWin(byte[] inBuffer, @@ -737,7 +765,7 @@ private static extern bool IGM_principal_curvatureWin(byte[] inBuffer, out int obsPV1, out IntPtr obPV2, out int obsPV2); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_principal_curvature", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_principal_curvatureMac(byte[] inBuffer, @@ -763,7 +791,7 @@ public static bool IGM_principal_curvature(byte[] inBuffer, out int obsPV1, out IntPtr obPV2, out int obsPV2) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_principal_curvatureWin(inBuffer, inSize, radius, @@ -790,12 +818,12 @@ public static bool IGM_principal_curvature(byte[] inBuffer, } // Gaussian Curvature - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_gaussian_curvature", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_gaussian_curvatureWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_gaussian_curvature", CallingConvention = CallingConvention.Cdecl)] private static extern bool @@ -803,14 +831,14 @@ private static extern bool public static bool IGM_gaussian_curvature(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_gaussian_curvatureWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_gaussian_curvatureMac(inBuffer, inSize, out outBuffer, out outSize); } // Fast Winding Number - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_fast_winding_number", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_fast_winding_numberWin(byte[] inBufferMesh, @@ -819,7 +847,7 @@ private static extern bool IGM_fast_winding_numberWin(byte[] inBufferMesh, int inSizePoints, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_fast_winding_number", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_fast_winding_numberMac(byte[] inBufferMesh, @@ -835,7 +863,7 @@ public static bool IGM_fast_winding_number(byte[] inBufferMesh, int inSizePoints, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_fast_winding_numberWin( inBufferMesh, inSizeMesh, inBufferPoints, inSizePoints, out outBuffer, out outSize); else @@ -844,8 +872,9 @@ public static bool IGM_fast_winding_number(byte[] inBufferMesh, } // Signed Distance - [DllImport( - WinLibName, EntryPoint = "IGM_signed_distance", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_signed_distance", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_signed_distanceWin(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferPoints, @@ -857,8 +886,9 @@ private static extern bool IGM_signed_distanceWin(byte[] inBufferMesh, out int outSizeFI, out IntPtr outBufferCP, out int outSizeCP); - [DllImport( - MacLibName, EntryPoint = "IGM_signed_distance", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_signed_distance", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_signed_distanceMac(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferPoints, @@ -882,7 +912,7 @@ public static bool IGM_signed_distance(byte[] inBufferMesh, out int outSizeFI, out IntPtr outBufferCP, out int outSizeCP) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_signed_distanceWin(inBufferMesh, inSizeMesh, inBufferPoints, @@ -909,25 +939,27 @@ public static bool IGM_signed_distance(byte[] inBufferMesh, } // Quad Planarity - [DllImport( - WinLibName, EntryPoint = "IGM_quad_planarity", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_quad_planarity", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_quad_planarityWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "IGM_quad_planarity", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_quad_planarity", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_quad_planarityMac(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); public static bool IGM_quad_planarity(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_quad_planarityWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_quad_planarityMac(inBuffer, inSize, out outBuffer, out outSize); } // Planarize Quad Mesh - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_planarize_quad_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_planarize_quad_meshWin(byte[] inBuffer, @@ -936,7 +968,7 @@ private static extern bool IGM_planarize_quad_meshWin(byte[] inBuffer, double threshold, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_planarize_quad_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_planarize_quad_meshMac(byte[] inBuffer, @@ -952,7 +984,7 @@ public static bool IGM_planarize_quad_mesh(byte[] inBuffer, double threshold, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_planarize_quad_meshWin( inBuffer, inSize, maxIter, threshold, out outBuffer, out outSize); else @@ -961,8 +993,9 @@ public static bool IGM_planarize_quad_mesh(byte[] inBuffer, } // Laplacian Scalar - [DllImport( - WinLibName, EntryPoint = "IGM_laplacian_scalar", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_laplacian_scalar", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_laplacian_scalarWin(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferIndices, @@ -971,8 +1004,9 @@ private static extern bool IGM_laplacian_scalarWin(byte[] inBufferMesh, int inSizeValues, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "IGM_laplacian_scalar", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_laplacian_scalar", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_laplacian_scalarMac(byte[] inBufferMesh, int inSizeMesh, byte[] inBufferIndices, @@ -990,7 +1024,7 @@ public static bool IGM_laplacian_scalar(byte[] inBufferMesh, int inSizeValues, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_laplacian_scalarWin(inBufferMesh, inSizeMesh, inBufferIndices, @@ -1011,32 +1045,34 @@ public static bool IGM_laplacian_scalar(byte[] inBufferMesh, } // Harmonic Parametrization - [DllImport( - WinLibName, EntryPoint = "IGM_param_harmonic", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.WindowsLib, + EntryPoint = "IGM_param_harmonic", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_param_harmonicWin(byte[] inBuffer, int inSize, int k, out IntPtr outBuffer, out int outSize); - [DllImport( - MacLibName, EntryPoint = "IGM_param_harmonic", CallingConvention = CallingConvention.Cdecl)] + [DllImport(Platform.MacLib, + EntryPoint = "IGM_param_harmonic", + CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_param_harmonicMac(byte[] inBuffer, int inSize, int k, out IntPtr outBuffer, out int outSize); public static bool IGM_param_harmonic(byte[] inBuffer, int inSize, int k, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_param_harmonicWin(inBuffer, inSize, k, out outBuffer, out outSize); else return IGM_param_harmonicMac(inBuffer, inSize, k, out outBuffer, out outSize); } // Heat Geodesic Precompute - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_heat_geodesic_precompute", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_heat_geodesic_precomputeWin(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_heat_geodesic_precompute", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_heat_geodesic_precomputeMac(byte[] inBuffer, @@ -1046,14 +1082,14 @@ private static extern bool IGM_heat_geodesic_precomputeMac(byte[] inBuffer, public static bool IGM_heat_geodesic_precompute(byte[] inBuffer, int inSize, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_heat_geodesic_precomputeWin(inBuffer, inSize, out outBuffer, out outSize); else return IGM_heat_geodesic_precomputeMac(inBuffer, inSize, out outBuffer, out outSize); } // Heat Geodesic Solve - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_heat_geodesic_solve", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_heat_geodesic_solveWin(byte[] inBuffer, @@ -1062,7 +1098,7 @@ private static extern bool IGM_heat_geodesic_solveWin(byte[] inBuffer, int inSizeSources, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_heat_geodesic_solve", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_heat_geodesic_solveMac(byte[] inBuffer, @@ -1078,7 +1114,7 @@ public static bool IGM_heat_geodesic_solve(byte[] inBuffer, int inSizeSources, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_heat_geodesic_solveWin( inBuffer, inSize, inBufferSources, inSizeSources, out outBuffer, out outSize); else @@ -1087,7 +1123,7 @@ public static bool IGM_heat_geodesic_solve(byte[] inBuffer, } // Random Points on Mesh - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_random_point_on_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_random_point_on_meshWin(byte[] inBuffer, @@ -1097,7 +1133,7 @@ private static extern bool IGM_random_point_on_meshWin(byte[] inBuffer, out int outSize, out IntPtr outBufferFI, out int outSizeFI); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_random_point_on_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_random_point_on_meshMac(byte[] inBuffer, @@ -1115,7 +1151,7 @@ public static bool IGM_random_point_on_mesh(byte[] inBuffer, out int outSize, out IntPtr outBufferFI, out int outSizeFI) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_random_point_on_meshWin( inBuffer, inSize, N, out outBuffer, out outSize, out outBufferFI, out outSizeFI); else @@ -1124,7 +1160,7 @@ public static bool IGM_random_point_on_mesh(byte[] inBuffer, } // Blue Noise Sampling on Mesh - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_blue_noise_sampling_on_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_blue_noise_sampling_on_meshWin(byte[] inBuffer, @@ -1134,7 +1170,7 @@ private static extern bool IGM_blue_noise_sampling_on_meshWin(byte[] inBuffer, out int outSize, out IntPtr outBufferFI, out int outSizeFI); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_blue_noise_sampling_on_mesh", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_blue_noise_sampling_on_meshMac(byte[] inBuffer, @@ -1152,7 +1188,7 @@ public static bool IGM_blue_noise_sampling_on_mesh(byte[] inBuffer, out int outSize, out IntPtr outBufferFI, out int outSizeFI) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_blue_noise_sampling_on_meshWin( inBuffer, inSize, N, out outBuffer, out outSize, out outBufferFI, out outSizeFI); else @@ -1162,7 +1198,7 @@ public static bool IGM_blue_noise_sampling_on_mesh(byte[] inBuffer, // Constrained Scalar (equivalent to IGM_laplacian_scalar - they appear to be the same // functionality) - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_constrained_scalar", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_constrained_scalarWin(byte[] inBufferMesh, @@ -1173,7 +1209,7 @@ private static extern bool IGM_constrained_scalarWin(byte[] inBufferMesh, int inSizeValues, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_constrained_scalar", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_constrained_scalarMac(byte[] inBufferMesh, @@ -1193,7 +1229,7 @@ public static bool IGM_constrained_scalar(byte[] inBufferMesh, int inSizeValues, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_constrained_scalarWin(inBufferMesh, inSizeMesh, inBufferIndices, @@ -1214,7 +1250,7 @@ public static bool IGM_constrained_scalar(byte[] inBufferMesh, } // Extract Isoline from Scalar - [DllImport(WinLibName, + [DllImport(Platform.WindowsLib, EntryPoint = "IGM_extract_isoline_from_scalar", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_extract_isoline_from_scalarWin(byte[] inBufferMesh, @@ -1225,7 +1261,7 @@ private static extern bool IGM_extract_isoline_from_scalarWin(byte[] inBufferMes int inSizeIsoValues, out IntPtr outBuffer, out int outSize); - [DllImport(MacLibName, + [DllImport(Platform.MacLib, EntryPoint = "IGM_extract_isoline_from_scalar", CallingConvention = CallingConvention.Cdecl)] private static extern bool IGM_extract_isoline_from_scalarMac(byte[] inBufferMesh, @@ -1245,7 +1281,7 @@ public static bool IGM_extract_isoline_from_scalar(byte[] inBufferMesh, int inSizeIsoValues, out IntPtr outBuffer, out int outSize) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (Platform.IsWindows) return IGM_extract_isoline_from_scalarWin(inBufferMesh, inSizeMesh, inBufferScalar, diff --git a/GeoSharPlusNET/Extensions/igMesh/igMeshUtils.cs b/GeoSharPlusNET/Extensions/igMesh/igMeshUtils.cs new file mode 100644 index 0000000..44b0937 --- /dev/null +++ b/GeoSharPlusNET/Extensions/igMesh/igMeshUtils.cs @@ -0,0 +1,151 @@ +using System; +using System.Runtime.InteropServices; +using GSP; +using GSP.Adapters.Rhino; +using GSP.Core; +using Rhino.Geometry; + +namespace igMesh.Native { +/// +/// High-level utilities for igMesh operations. +/// These methods provide a clean API that handles serialization and marshaling internally. +/// +public static class igMeshUtils { +#region Mesh I / O + + /// + /// Loads a mesh from a file (OBJ, PLY, etc.) + /// + public static Mesh? LoadMesh(string filePath) { + if (!igMeshBridge.LoadMesh(filePath, out IntPtr outPtr, out int outSize)) + return null; + byte[] buffer = MarshalHelper.CopyAndFree(outPtr, outSize); + return Wrapper.FromMeshBuffer(buffer); + } + + /// + /// Saves a mesh to a file. + /// + public static bool SaveMesh(Mesh mesh, string filePath) { + byte[] buffer = Wrapper.ToMeshBuffer(mesh); + return igMeshBridge.SaveMesh(buffer, buffer.Length, filePath); + } + +#endregion + +#region Basic Mesh Operations + + /// + /// Computes the centroid of a mesh. + /// + public static Point3d MeshCentroid(Mesh mesh) { + byte[] buffer = Wrapper.ToMeshBuffer(mesh); + if (!igMeshBridge.MeshCentroid(buffer, buffer.Length, out IntPtr outPtr, out int outSize)) + return Point3d.Unset; + byte[] result = MarshalHelper.CopyAndFree(outPtr, outSize); + return Wrapper.FromPointBuffer(result); + } + + /// + /// Computes the barycenter of each face. + /// + public static Point3d[]? Barycenter(Mesh mesh) { + byte[] buffer = Wrapper.ToMeshBuffer(mesh); + if (!igMeshBridge.IGM_barycenter(buffer, buffer.Length, out IntPtr outPtr, out int outSize)) + return null; + byte[] result = MarshalHelper.CopyAndFree(outPtr, outSize); + return Wrapper.FromPointArrayBuffer(result); + } + + /// + /// Computes per-vertex normals. + /// + public static Vector3d[]? VertexNormals(Mesh mesh) { + byte[] buffer = Wrapper.ToMeshBuffer(mesh); + if (!igMeshBridge.IGM_vert_normals(buffer, buffer.Length, out IntPtr outPtr, out int outSize)) + return null; + byte[] result = MarshalHelper.CopyAndFree(outPtr, outSize); + return Wrapper.FromVector3dArrayBuffer(result); + } + +#endregion + +#region Scalar Field Operations + + /// + /// Computes Laplacian scalar field on a mesh with boundary constraints. + /// + public static double[]? LaplacianScalar(Mesh mesh, + int[] constraintIndices, + double[] constraintValues) { + byte[] meshBuffer = Wrapper.ToMeshBuffer(mesh); + byte[] indicesBuffer = Serializer.Serialize(constraintIndices); + byte[] valuesBuffer = Serializer.Serialize(constraintValues); + + if (!igMeshBridge.IGM_laplacian_scalar(meshBuffer, + meshBuffer.Length, + indicesBuffer, + indicesBuffer.Length, + valuesBuffer, + valuesBuffer.Length, + out IntPtr outPtr, + out int outSize)) + return null; + + byte[] resultBuffer = MarshalHelper.CopyAndFree(outPtr, outSize); + return Serializer.DeserializeDoubleArray(resultBuffer); + } + + /// + /// Computes constrained scalar field on a mesh. + /// + public static double[]? ConstrainedScalar(Mesh mesh, + int[] constraintIndices, + double[] constraintValues) { + byte[] meshBuffer = Wrapper.ToMeshBuffer(mesh); + byte[] indicesBuffer = Serializer.Serialize(constraintIndices); + byte[] valuesBuffer = Serializer.Serialize(constraintValues); + + if (!igMeshBridge.IGM_constrained_scalar(meshBuffer, + meshBuffer.Length, + indicesBuffer, + indicesBuffer.Length, + valuesBuffer, + valuesBuffer.Length, + out IntPtr outPtr, + out int outSize)) + return null; + + byte[] resultBuffer = MarshalHelper.CopyAndFree(outPtr, outSize); + return Serializer.DeserializeDoubleArray(resultBuffer); + } + +#endregion + +#region Isoline Extraction + + /// + /// Extracts isolines from a scalar field at specified iso-values. + /// + public static Point3d[]? ExtractIsolines(Mesh mesh, double[] scalarField, double[] isoValues) { + byte[] meshBuffer = Wrapper.ToMeshBuffer(mesh); + byte[] scalarBuffer = Serializer.Serialize(scalarField); + byte[] isoBuffer = Serializer.Serialize(isoValues); + + if (!igMeshBridge.IGM_extract_isoline_from_scalar(meshBuffer, + meshBuffer.Length, + scalarBuffer, + scalarBuffer.Length, + isoBuffer, + isoBuffer.Length, + out IntPtr outPtr, + out int outSize)) + return null; + + byte[] resultBuffer = MarshalHelper.CopyAndFree(outPtr, outSize); + return Wrapper.FromPointArrayBuffer(resultBuffer); + } + +#endregion +} +} diff --git a/GeoSharPlusNET/Geometry/IGeometryAdapter.cs b/GeoSharPlusNET/Geometry/IGeometryAdapter.cs new file mode 100644 index 0000000..5a5e26c --- /dev/null +++ b/GeoSharPlusNET/Geometry/IGeometryAdapter.cs @@ -0,0 +1,52 @@ +namespace GSP.Geometry { + /// + /// Interface for adapting CAD-specific geometry types to GSP geometry types. + /// Implement this interface to add support for a new CAD platform. + /// + /// The CAD platform's point/vector type. + /// The CAD platform's mesh type. + /// + /// Example implementation for Rhino: + /// + /// public class RhinoAdapter : IGeometryAdapter<Point3d, Rhino.Geometry.Mesh> { + /// public Vec3 PointToGSP(Point3d point) => new Vec3(point.X, point.Y, point.Z); + /// public Point3d PointFromGSP(Vec3 point) => new Point3d(point.X, point.Y, point.Z); + /// // ... mesh methods + /// } + /// + /// + /// This allows the library to support multiple CAD platforms (Rhino, AutoCAD, Revit, etc.) + /// without changing the core serialization logic. + /// + public interface IGeometryAdapter { + /// + /// Converts a CAD point to a GSP Vec3. + /// + Vec3 PointToGSP(TPoint point); + + /// + /// Converts a GSP Vec3 to a CAD point. + /// + TPoint PointFromGSP(Vec3 point); + + /// + /// Converts an array of CAD points to GSP Vec3 array. + /// + Vec3[] PointsToGSP(TPoint[] points); + + /// + /// Converts a GSP Vec3 array to CAD points. + /// + TPoint[] PointsFromGSP(Vec3[] points); + + /// + /// Converts a CAD mesh to a GSP Mesh. + /// + Mesh MeshToGSP(TMesh mesh); + + /// + /// Converts a GSP Mesh to a CAD mesh. + /// + TMesh MeshFromGSP(Mesh mesh); + } +} diff --git a/GeoSharPlusNET/Geometry/Mesh.cs b/GeoSharPlusNET/Geometry/Mesh.cs new file mode 100644 index 0000000..5390d36 --- /dev/null +++ b/GeoSharPlusNET/Geometry/Mesh.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace GSP.Geometry { + /// + /// A simple mesh structure containing vertices and faces. + /// Platform-independent - no CAD software dependencies. + /// + /// + /// Supports both triangle and quad faces. + /// Use TriangleFaces for triangle meshes, QuadFaces for quad meshes. + /// + public class Mesh { + /// + /// The mesh vertices as an array of Vec3. + /// + public Vec3[] Vertices { get; set; } = Array.Empty(); + + /// + /// Triangle faces as tuples of vertex indices (A, B, C). + /// + public (int A, int B, int C)[] TriangleFaces { get; set; } = Array.Empty<(int, int, int)>(); + + /// + /// Quad faces as tuples of vertex indices (A, B, C, D). + /// + public (int A, int B, int C, int D)[] QuadFaces { get; set; } = Array.Empty<(int, int, int, int)>(); + + /// + /// Creates an empty mesh. + /// + public Mesh() { } + + /// + /// Creates a triangle mesh from vertices and faces. + /// + public Mesh(Vec3[] vertices, (int A, int B, int C)[] faces) { + Vertices = vertices; + TriangleFaces = faces; + } + + /// + /// Creates a quad mesh from vertices and faces. + /// + public Mesh(Vec3[] vertices, (int A, int B, int C, int D)[] faces) { + Vertices = vertices; + QuadFaces = faces; + } + + /// + /// Returns true if the mesh has triangle faces. + /// + public bool HasTriangles => TriangleFaces.Length > 0; + + /// + /// Returns true if the mesh has quad faces. + /// + public bool HasQuads => QuadFaces.Length > 0; + + /// + /// Returns the total number of faces (triangles + quads). + /// + public int FaceCount => TriangleFaces.Length + QuadFaces.Length; + + /// + /// Returns the number of vertices. + /// + public int VertexCount => Vertices.Length; + + /// + /// Returns true if the mesh has valid data. + /// + public bool IsValid => Vertices.Length >= 3 && FaceCount > 0; + + /// + /// Converts all quad faces to triangles. + /// Each quad (A, B, C, D) becomes two triangles: (A, B, C) and (A, C, D). + /// + public void Triangulate() { + if (!HasQuads) return; + + var newTriangles = new List<(int, int, int)>(TriangleFaces); + foreach (var (A, B, C, D) in QuadFaces) { + newTriangles.Add((A, B, C)); + newTriangles.Add((A, C, D)); + } + + TriangleFaces = newTriangles.ToArray(); + QuadFaces = Array.Empty<(int, int, int, int)>(); + } + + /// + /// Creates a deep copy of this mesh. + /// + public Mesh Clone() { + return new Mesh { + Vertices = Vertices.ToArray(), + TriangleFaces = TriangleFaces.ToArray(), + QuadFaces = QuadFaces.ToArray() + }; + } + + /// + /// Computes the bounding box of the mesh. + /// + /// Tuple of (min, max) corners. + public (Vec3 Min, Vec3 Max) GetBoundingBox() { + if (Vertices.Length == 0) + return (Vec3.Zero, Vec3.Zero); + + double minX = double.MaxValue, minY = double.MaxValue, minZ = double.MaxValue; + double maxX = double.MinValue, maxY = double.MinValue, maxZ = double.MinValue; + + foreach (var v in Vertices) { + if (v.X < minX) minX = v.X; + if (v.Y < minY) minY = v.Y; + if (v.Z < minZ) minZ = v.Z; + if (v.X > maxX) maxX = v.X; + if (v.Y > maxY) maxY = v.Y; + if (v.Z > maxZ) maxZ = v.Z; + } + + return (new Vec3(minX, minY, minZ), new Vec3(maxX, maxY, maxZ)); + } + + public override string ToString() => + $"Mesh [V:{VertexCount}, T:{TriangleFaces.Length}, Q:{QuadFaces.Length}]"; + } +} diff --git a/GeoSharPlusNET/Geometry/Vec2.cs b/GeoSharPlusNET/Geometry/Vec2.cs new file mode 100644 index 0000000..4a08cce --- /dev/null +++ b/GeoSharPlusNET/Geometry/Vec2.cs @@ -0,0 +1,114 @@ +using System; + +namespace GSP.Geometry { + /// + /// A simple 2D vector/point structure. + /// Platform-independent - no CAD software dependencies. + /// + public readonly struct Vec2 : IEquatable { + public double X { get; } + public double Y { get; } + + public Vec2(double x, double y) { + X = x; + Y = y; + } + + /// + /// Creates a Vec2 from an array of 2 doubles. + /// + public Vec2(double[] values) { + if (values == null || values.Length < 2) + throw new ArgumentException("Array must have at least 2 elements", nameof(values)); + X = values[0]; + Y = values[1]; + } + + /// + /// Returns the zero vector (0, 0). + /// + public static Vec2 Zero => new(0, 0); + + /// + /// Returns the unit X vector (1, 0). + /// + public static Vec2 UnitX => new(1, 0); + + /// + /// Returns the unit Y vector (0, 1). + /// + public static Vec2 UnitY => new(0, 1); + + /// + /// Returns the length (magnitude) of the vector. + /// + public double Length => Math.Sqrt(X * X + Y * Y); + + /// + /// Returns the squared length of the vector (faster than Length). + /// + public double LengthSquared => X * X + Y * Y; + + /// + /// Returns a normalized (unit length) version of this vector. + /// + public Vec2 Normalized { + get { + var len = Length; + return len > 0 ? new Vec2(X / len, Y / len) : Zero; + } + } + + /// + /// Converts to an array of doubles [X, Y]. + /// + public double[] ToArray() => new[] { X, Y }; + + /// + /// Converts to a Vec3 with Z = 0. + /// + public Vec3 ToVec3(double z = 0) => new(X, Y, z); + + // Operators + public static Vec2 operator +(Vec2 a, Vec2 b) => new(a.X + b.X, a.Y + b.Y); + public static Vec2 operator -(Vec2 a, Vec2 b) => new(a.X - b.X, a.Y - b.Y); + public static Vec2 operator *(Vec2 v, double s) => new(v.X * s, v.Y * s); + public static Vec2 operator *(double s, Vec2 v) => new(v.X * s, v.Y * s); + public static Vec2 operator /(Vec2 v, double s) => new(v.X / s, v.Y / s); + public static Vec2 operator -(Vec2 v) => new(-v.X, -v.Y); + + /// + /// Computes the dot product of two vectors. + /// + public static double Dot(Vec2 a, Vec2 b) => a.X * b.X + a.Y * b.Y; + + /// + /// Computes the 2D cross product (returns scalar). + /// + public static double Cross(Vec2 a, Vec2 b) => a.X * b.Y - a.Y * b.X; + + /// + /// Computes the distance between two points. + /// + public static double Distance(Vec2 a, Vec2 b) => (a - b).Length; + + // Equality + public bool Equals(Vec2 other) => X.Equals(other.X) && Y.Equals(other.Y); + + public override bool Equals(object? obj) => obj is Vec2 other && Equals(other); + + public override int GetHashCode() => HashCode.Combine(X, Y); + + public static bool operator ==(Vec2 left, Vec2 right) => left.Equals(right); + public static bool operator !=(Vec2 left, Vec2 right) => !left.Equals(right); + + /// + /// Checks if two vectors are approximately equal within a tolerance. + /// + public bool ApproximatelyEquals(Vec2 other, double tolerance = 1e-9) => + Math.Abs(X - other.X) < tolerance && + Math.Abs(Y - other.Y) < tolerance; + + public override string ToString() => $"({X:F4}, {Y:F4})"; + } +} diff --git a/GeoSharPlusNET/Geometry/Vec3.cs b/GeoSharPlusNET/Geometry/Vec3.cs new file mode 100644 index 0000000..c715452 --- /dev/null +++ b/GeoSharPlusNET/Geometry/Vec3.cs @@ -0,0 +1,122 @@ +using System; + +namespace GSP.Geometry { + /// + /// A simple 3D vector/point structure. + /// Platform-independent - no CAD software dependencies. + /// + public readonly struct Vec3 : IEquatable { + public double X { get; } + public double Y { get; } + public double Z { get; } + + public Vec3(double x, double y, double z) { + X = x; + Y = y; + Z = z; + } + + /// + /// Creates a Vec3 from an array of 3 doubles. + /// + public Vec3(double[] values) { + if (values == null || values.Length < 3) + throw new ArgumentException("Array must have at least 3 elements", nameof(values)); + X = values[0]; + Y = values[1]; + Z = values[2]; + } + + /// + /// Returns the zero vector (0, 0, 0). + /// + public static Vec3 Zero => new(0, 0, 0); + + /// + /// Returns the unit X vector (1, 0, 0). + /// + public static Vec3 UnitX => new(1, 0, 0); + + /// + /// Returns the unit Y vector (0, 1, 0). + /// + public static Vec3 UnitY => new(0, 1, 0); + + /// + /// Returns the unit Z vector (0, 0, 1). + /// + public static Vec3 UnitZ => new(0, 0, 1); + + /// + /// Returns the length (magnitude) of the vector. + /// + public double Length => Math.Sqrt(X * X + Y * Y + Z * Z); + + /// + /// Returns the squared length of the vector (faster than Length). + /// + public double LengthSquared => X * X + Y * Y + Z * Z; + + /// + /// Returns a normalized (unit length) version of this vector. + /// + public Vec3 Normalized { + get { + var len = Length; + return len > 0 ? new Vec3(X / len, Y / len, Z / len) : Zero; + } + } + + /// + /// Converts to an array of doubles [X, Y, Z]. + /// + public double[] ToArray() => new[] { X, Y, Z }; + + // Operators + public static Vec3 operator +(Vec3 a, Vec3 b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + public static Vec3 operator -(Vec3 a, Vec3 b) => new(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + public static Vec3 operator *(Vec3 v, double s) => new(v.X * s, v.Y * s, v.Z * s); + public static Vec3 operator *(double s, Vec3 v) => new(v.X * s, v.Y * s, v.Z * s); + public static Vec3 operator /(Vec3 v, double s) => new(v.X / s, v.Y / s, v.Z / s); + public static Vec3 operator -(Vec3 v) => new(-v.X, -v.Y, -v.Z); + + /// + /// Computes the dot product of two vectors. + /// + public static double Dot(Vec3 a, Vec3 b) => a.X * b.X + a.Y * b.Y + a.Z * b.Z; + + /// + /// Computes the cross product of two vectors. + /// + public static Vec3 Cross(Vec3 a, Vec3 b) => new( + a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X); + + /// + /// Computes the distance between two points. + /// + public static double Distance(Vec3 a, Vec3 b) => (a - b).Length; + + // Equality + public bool Equals(Vec3 other) => + X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z); + + public override bool Equals(object? obj) => obj is Vec3 other && Equals(other); + + public override int GetHashCode() => HashCode.Combine(X, Y, Z); + + public static bool operator ==(Vec3 left, Vec3 right) => left.Equals(right); + public static bool operator !=(Vec3 left, Vec3 right) => !left.Equals(right); + + /// + /// Checks if two vectors are approximately equal within a tolerance. + /// + public bool ApproximatelyEquals(Vec3 other, double tolerance = 1e-9) => + Math.Abs(X - other.X) < tolerance && + Math.Abs(Y - other.Y) < tolerance && + Math.Abs(Z - other.Z) < tolerance; + + public override string ToString() => $"({X:F4}, {Y:F4}, {Z:F4})"; + } +} diff --git a/igm/00_igmInfo.cs b/igm/00_igmInfo.cs index 6cea131..a836918 100644 --- a/igm/00_igmInfo.cs +++ b/igm/00_igmInfo.cs @@ -18,7 +18,7 @@ public class igmInfo : GH_AssemblyInfo { public override Guid Id => new Guid("9adf88b1-427d-4ce4-b72b-288d09821271"); public override string AuthorName => "Dr. Zhao MA"; public override string AuthorContact => "zhma@ethz.ch"; - public override string Version => "0.5.9"; + public override string Version => "0.6.0"; public override GH_LibraryLicense License => GH_LibraryLicense.opensource; } diff --git a/igm/01_meshIO.cs b/igm/01_meshIO.cs index 1fc71b5..5e9767b 100644 --- a/igm/01_meshIO.cs +++ b/igm/01_meshIO.cs @@ -1,90 +1,96 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using Rhino.Geometry; using System; namespace igm { - public class IGM_read_triangle_mesh : GH_Component { - public IGM_read_triangle_mesh() - : base( - "Load TriMesh", "igLoadMesh", - "Load a triangle mesh directly from disk. Format supported: obj, off, stl, wrl, ply, mesh.", - "igMesh", "01::Info+IO") {} - public override GH_Exposure Exposure => GH_Exposure.primary; - protected override System.Drawing.Bitmap Icon => Properties.Resources.ioReadTriMesh; - public override Guid ComponentGuid => new Guid("0b92e0c5-64a1-4edb-97dc-c8df9f9b088c"); +public class IGM_read_triangle_mesh : GH_Component { + public IGM_read_triangle_mesh() + : base("Load TriMesh", + "igLoadMesh", + "Load a triangle mesh directly from disk. Format supported: obj, off, stl, wrl, " + + "ply, mesh.", + "igMesh", + "01::Info+IO") {} + public override GH_Exposure Exposure => GH_Exposure.primary; + protected override System.Drawing.Bitmap Icon => Properties.Resources.ioReadTriMesh; + public override Guid ComponentGuid => new Guid("0b92e0c5-64a1-4edb-97dc-c8df9f9b088c"); - protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { - pManager.AddTextParameter("File Location", "file", "Mesh file location from disk.", - GH_ParamAccess.item); - } - protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { - pManager.AddMeshParameter("Mesh", "M", "Mesh geometry if loaded successfully.", - GH_ParamAccess.item); - } + protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { + pManager.AddTextParameter( + "File Location", "file", "Mesh file location from disk.", GH_ParamAccess.item); + } + protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { + pManager.AddMeshParameter( + "Mesh", "M", "Mesh geometry if loaded successfully.", GH_ParamAccess.item); + } - protected override void SolveInstance(IGH_DataAccess DA) { - string fName = ""; - if (!DA.GetData(0, ref fName)) { - return; - } + protected override void SolveInstance(IGH_DataAccess DA) { + string fName = ""; + if (!DA.GetData(0, ref fName)) { + return; + } - var success = MeshUtils.LoadMesh(fName, out Mesh mesh); + var success = MeshUtils.LoadMesh(fName, out Mesh mesh); - if (!mesh.IsValid || !success) { - return; - } - // output - DA.SetData("Mesh", mesh); + if (!mesh.IsValid || !success) { + return; } + // output + DA.SetData("Mesh", mesh); } +} - public class IGM_write_triangle_mesh : GH_Component { - /// - /// Initializes a new instance of the MyComponent1 class. - /// - public IGM_write_triangle_mesh() - : base( - "Save TriMesh", "igSaveMesh", - "Save a triangle mesh directly to disk. format supported: obj, off, stl, wrl, ply, mesh.", - "igMesh", "01::Info+IO") {} +public class IGM_write_triangle_mesh : GH_Component { + /// + /// Initializes a new instance of the MyComponent1 class. + /// + public IGM_write_triangle_mesh() + : base("Save TriMesh", + "igSaveMesh", + "Save a triangle mesh directly to disk. format supported: obj, off, stl, wrl, ply, " + + "mesh.", + "igMesh", + "01::Info+IO") {} - public override GH_Exposure Exposure => GH_Exposure.primary; - protected override System.Drawing.Bitmap Icon => Properties.Resources.ioWriteTriMesh; - public override Guid ComponentGuid => new Guid("fcaceca2-c358-4fc0-8b48-f3d31e861bca"); + public override GH_Exposure Exposure => GH_Exposure.primary; + protected override System.Drawing.Bitmap Icon => Properties.Resources.ioWriteTriMesh; + public override Guid ComponentGuid => new Guid("fcaceca2-c358-4fc0-8b48-f3d31e861bca"); - protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { - pManager.AddMeshParameter("Mesh", "M", "Mesh to save.", GH_ParamAccess.item); - pManager.AddTextParameter("File Path", "path", "File path to save the mesh to disk.", - GH_ParamAccess.item); - pManager.AddBooleanParameter("Try Save", "T", "Save when TRUE.", GH_ParamAccess.item); - } + protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { + pManager.AddMeshParameter("Mesh", "M", "Mesh to save.", GH_ParamAccess.item); + pManager.AddTextParameter( + "File Path", "path", "File path to save the mesh to disk.", GH_ParamAccess.item); + pManager.AddBooleanParameter("Try Save", "T", "Save when TRUE.", GH_ParamAccess.item); + } - protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { - pManager.AddTextParameter("Success", "S", "If mesh is saved successfully.", - GH_ParamAccess.item); - } + protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { + pManager.AddTextParameter( + "Success", "S", "If mesh is saved successfully.", GH_ParamAccess.item); + } - protected override void SolveInstance(IGH_DataAccess DA) { - Mesh mesh = new Mesh(); - if (!DA.GetData("Mesh", ref mesh) || !mesh.IsValid) { - return; - } + protected override void SolveInstance(IGH_DataAccess DA) { + Mesh mesh = new Mesh(); + if (!DA.GetData("Mesh", ref mesh) || !mesh.IsValid) { + return; + } - string fName = ""; - if (!DA.GetData("File Path", ref fName)) { - return; - } + string fName = ""; + if (!DA.GetData("File Path", ref fName)) { + return; + } - bool doIt = false; - if (!DA.GetData("Try Save", ref doIt)) { - return; - } + bool doIt = false; + if (!DA.GetData("Try Save", ref doIt)) { + return; + } - if (doIt) { - var success = MeshUtils.SaveMesh(ref mesh, fName); - DA.SetData("Success", success ? "Success." : "Failed."); - } + if (doIt) { + var success = MeshUtils.SaveMesh(ref mesh, fName); + DA.SetData("Success", success ? "Success." : "Failed."); } } } +} diff --git a/igm/01_meshInfo.cs b/igm/01_meshInfo.cs index 4f690a6..ba82673 100644 --- a/igm/01_meshInfo.cs +++ b/igm/01_meshInfo.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; using System.IO; @@ -83,8 +85,8 @@ protected override void RegisterOutputParams(GH_OutputParamManager pManager) { protected override void SolveInstance(IGH_DataAccess DA) { try { // Check if the native library is loaded before proceeding - if (!GSP.NativeBridge.IsNativeLibraryLoaded) { - string[] errors = GSP.NativeBridge.GetErrorMessages(); + if (!igMeshBridge.IsNativeLibraryLoaded) { + string[] errors = igMeshBridge.GetErrorMessages(); string errorMsg = string.Join("\n", errors); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Native library not loaded. Check the following errors:\n{errorMsg}"); @@ -92,7 +94,7 @@ protected override void SolveInstance(IGH_DataAccess DA) { } else { // Create an instance of BeingAliveLanguageInfo to access the non-static property string version = new igmInfo().AssemblyVersion; - string loadedPath = GSP.NativeBridge.LoadedLibraryPath; + string loadedPath = igMeshBridge.LoadedLibraryPath; string libName = Path.GetFileName(loadedPath); string infoText = $"Native library loaded successfully from: {loadedPath}\n" + @@ -107,3 +109,4 @@ protected override void SolveInstance(IGH_DataAccess DA) { } } } + diff --git a/igm/02_meshBarycenter.cs b/igm/02_meshBarycenter.cs index 49a94e9..a8f4133 100644 --- a/igm/02_meshBarycenter.cs +++ b/igm/02_meshBarycenter.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; @@ -40,3 +42,5 @@ protected override void SolveInstance(IGH_DataAccess DA) { } } } + + diff --git a/igm/02_meshNormals.cs b/igm/02_meshNormals.cs index 4efe61d..b49984b 100644 --- a/igm/02_meshNormals.cs +++ b/igm/02_meshNormals.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using Rhino.Geometry; using System; @@ -200,3 +202,5 @@ protected override void SolveInstance(IGH_DataAccess DA) { } } } + + diff --git a/igm/03_meshAdjacency.cs b/igm/03_meshAdjacency.cs index d696d7b..90f5d74 100644 --- a/igm/03_meshAdjacency.cs +++ b/igm/03_meshAdjacency.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using Rhino.Geometry; using System; @@ -169,7 +171,7 @@ protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager.AddIntegerParameter("Adjacency T-T edge index", "TTI", "The item{{i}}(j) is the id of edge of the triangle TT(i,j) " + - "that is adjacent with triangle i.", + "that is adjacent with triangle i.", GH_ParamAccess.tree); } diff --git a/igm/03_meshBounds.cs b/igm/03_meshBounds.cs index 4e0a11c..86f9dcf 100644 --- a/igm/03_meshBounds.cs +++ b/igm/03_meshBounds.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using Rhino.Geometry; using System; diff --git a/igm/04_scalarRemap.cs b/igm/04_scalarRemap.cs index e29c4a4..78d50a1 100644 --- a/igm/04_scalarRemap.cs +++ b/igm/04_scalarRemap.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; using System.Collections.Generic; @@ -163,3 +165,5 @@ public override Guid ComponentGuid { } } + + diff --git a/igm/06_meshCurvature.cs b/igm/06_meshCurvature.cs index d5c9d8d..4c50ade 100644 --- a/igm/06_meshCurvature.cs +++ b/igm/06_meshCurvature.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; @@ -170,3 +172,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/06_meshFastWindingNumber.cs b/igm/06_meshFastWindingNumber.cs index 40d4a12..cbf6063 100644 --- a/igm/06_meshFastWindingNumber.cs +++ b/igm/06_meshFastWindingNumber.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; using System.Collections.Generic; @@ -78,3 +80,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/06_meshLaplacian.cs b/igm/06_meshLaplacian.cs index 980d2e0..efbd511 100644 --- a/igm/06_meshLaplacian.cs +++ b/igm/06_meshLaplacian.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; using System.Collections.Generic; @@ -92,3 +94,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/06_meshQuadPlanarization.cs b/igm/06_meshQuadPlanarization.cs index bdbbc9d..d111a79 100644 --- a/igm/06_meshQuadPlanarization.cs +++ b/igm/06_meshQuadPlanarization.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; @@ -221,3 +223,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/06_meshSignedDistance.cs b/igm/06_meshSignedDistance.cs index c2901e9..0891843 100644 --- a/igm/06_meshSignedDistance.cs +++ b/igm/06_meshSignedDistance.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using System; using System.Collections.Generic; @@ -95,3 +97,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/07_meshParametrization.cs b/igm/07_meshParametrization.cs index 79a0814..747776f 100644 --- a/igm/07_meshParametrization.cs +++ b/igm/07_meshParametrization.cs @@ -1,9 +1,11 @@ -using Grasshopper.Kernel; +using Grasshopper.Kernel; using System; using System.Linq; using System.Collections.Generic; using Rhino.Geometry; using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; namespace igm { public class IGM_paramHarmonic : GH_Component { @@ -60,3 +62,5 @@ protected override void SolveInstance(IGH_DataAccess DA) { } } } // namespace igm + + diff --git a/igm/09_meshConstrainedScalar.cs b/igm/09_meshConstrainedScalar.cs index 84b0aa9..6a2abc3 100644 --- a/igm/09_meshConstrainedScalar.cs +++ b/igm/09_meshConstrainedScalar.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using Rhino.Geometry; using System; @@ -104,3 +106,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/09_meshHeatGeodesics.cs b/igm/09_meshHeatGeodesics.cs index 44a8e40..01dcb27 100644 --- a/igm/09_meshHeatGeodesics.cs +++ b/igm/09_meshHeatGeodesics.cs @@ -1,7 +1,9 @@ -using Grasshopper.Kernel; +using Grasshopper.Kernel; using System; using System.Collections.Generic; using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; namespace igm { public class IGM_heat_geodesic_dist : GH_Component { @@ -98,3 +100,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/09_meshIsoLineFromScalar.cs b/igm/09_meshIsoLineFromScalar.cs index 5fa8ea5..e101b47 100644 --- a/igm/09_meshIsoLineFromScalar.cs +++ b/igm/09_meshIsoLineFromScalar.cs @@ -1,4 +1,6 @@ -using GSP; +using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using Rhino.Geometry; using System; @@ -103,3 +105,5 @@ public override Guid ComponentGuid { } } } + + diff --git a/igm/09_meshRandomPointsOnMesh.cs b/igm/09_meshRandomPointsOnMesh.cs index ba97e3f..145fa5b 100644 --- a/igm/09_meshRandomPointsOnMesh.cs +++ b/igm/09_meshRandomPointsOnMesh.cs @@ -1,4 +1,6 @@ using GSP; +using GSP.Adapters.Rhino; +using igMesh.Native; using Grasshopper.Kernel; using Rhino.Geometry; using System; @@ -193,3 +195,5 @@ public override bool Read(GH_IO.Serialization.GH_IReader reader) { public override Guid ComponentGuid => new Guid("5819dc11-ccff-41eb-b126-96c34911ddc1"); } } + + diff --git a/scripts/IGM_examples.gh b/scripts/IGM_examples.gh index a862ebc..add58a3 100644 Binary files a/scripts/IGM_examples.gh and b/scripts/IGM_examples.gh differ