DotNetCore.OCCTProxy 1.0.5

dotnet add package DotNetCore.OCCTProxy --version 1.0.5
                    
NuGet\Install-Package DotNetCore.OCCTProxy -Version 1.0.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DotNetCore.OCCTProxy" Version="1.0.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DotNetCore.OCCTProxy" Version="1.0.5" />
                    
Directory.Packages.props
<PackageReference Include="DotNetCore.OCCTProxy" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DotNetCore.OCCTProxy --version 1.0.5
                    
#r "nuget: DotNetCore.OCCTProxy, 1.0.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DotNetCore.OCCTProxy@1.0.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DotNetCore.OCCTProxy&version=1.0.5
                    
Install as a Cake Addin
#tool nuget:?package=DotNetCore.OCCTProxy&version=1.0.5
                    
Install as a Cake Tool

OCCTProxy NuGet Package

概述

OCCTProxy 是一个 C++/CLI 包装器,用于在 .NET 8 应用程序中使用 OpenCASCADE 7.9.3。

平台支持: 此包仅适用于 Windows x64 平台,不支持 Linux、macOS 或 ARM 架构。

功能:

  • STEP 文件导入并转换为 GLB
  • IGES 文件导入并转换为 GLB
  • 自动格式检测
  • 网格质量控制
  • 进度回调
  • 坐标系转换(Z-up → Y-up)

包含内容:

  • OCCTProxy.dll - C++/CLI 托管程序集
  • 41 个原生 DLL(OpenCASCADE + 第三方依赖)
  • 约 70MB 总大小

安装

从本地源安装

# 添加本地 NuGet 源
dotnet nuget add source "C:\path\to\NuGet" -n OCCTProxyLocal

# 安装包
dotnet add package DotNetCore.OCCTProxy

项目配置

.csproj 文件中确保以下配置:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <PlatformTarget>x64</PlatformTarget>
    <UseWindowsForms>true</UseWindowsForms>  
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="DotNetCore.OCCTProxy" Version="1.0.5" />
  </ItemGroup>
</Project>

重要:

  • PlatformTarget 必须设置为 x64,OCCTProxy 仅支持 64 位
  • TargetFramework 设置为 net8.0,此包仅在 Windows 平台上运行

快速开始

1. 添加 DLL 初始化辅助类

在使用 OCCTProxy 之前,必须设置原生 DLL 搜索路径。请将以下辅助类添加到您的项目中

using System.Runtime.InteropServices;

/// <summary>
/// OpenCASCADE 环境初始化辅助类
/// 请将此类添加到您的项目中
/// </summary>
public static class OcctEnvironment
{
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool SetDllDirectory(string lpPathName);

    private static bool _initialized;

    /// <summary>
    /// 初始化 OpenCASCADE 运行环境
    /// 必须在使用 CadConverter 之前调用一次
    /// </summary>
    public static void Initialize()
    {
        if (_initialized) return;

        var baseDir = AppContext.BaseDirectory;
        var occtPath = Path.Combine(baseDir, "OpenCascade", "x64");

        if (Directory.Exists(occtPath) && OperatingSystem.IsWindows())
        {
            SetDllDirectory(occtPath);
            _initialized = true;
        }
        else
        {
            throw new DirectoryNotFoundException(
                $"OpenCASCADE DLL 目录不存在: {occtPath}");
        }
    }
}

说明: OcctEnvironment 不是 OCCTProxy NuGet 包的一部分,您需要将上述代码复制到项目中。

2. 基本用法

using OCCTProxyLib;

// 初始化环境(程序启动时调用一次)
OcctEnvironment.Initialize();

// 使用 using 语句确保资源释放
using (var converter = new CadConverter())
{
    // STEP → GLB
    var result = converter.ConvertStepToGlb(
        "input.step",
        "output.glb",
        MeshQuality.Standard,
        null);  // 无进度回调

    if (result.Success)
    {
        Console.WriteLine($"转换成功:");
        Console.WriteLine($"  形状数: {result.ShapeCount}");
        Console.WriteLine($"  面数: {result.FaceCount}");
        Console.WriteLine($"  三角形数: {result.TriangleCount}");
    }
    else
    {
        Console.WriteLine($"转换失败: {result.ErrorMessage}");
    }
}

API 参考

CadConverter 类

主要的转换器类,实现了 IDisposable 接口。

public ref class CadConverter : IDisposable
{
    // 构造函数
    CadConverter();

    // STEP → GLB
    ConvertResult ConvertStepToGlb(
        string inputPath,
        string outputPath,
        MeshQuality quality,
        ProgressCallback progress);

    ConvertResult ConvertStepToGlb(
        string inputPath,
        string outputPath,
        MeshParams meshParams,
        GlbExportParams exportParams,
        ProgressCallback progress);

    // IGES → GLB
    ConvertResult ConvertIgesToGlb(
        string inputPath,
        string outputPath,
        MeshQuality quality,
        ProgressCallback progress);

    ConvertResult ConvertIgesToGlb(
        string inputPath,
        string outputPath,
        MeshParams meshParams,
        GlbExportParams exportParams,
        ProgressCallback progress);

    // 自动检测格式
    ConvertResult ConvertToGlb(
        string inputPath,
        string outputPath,
        MeshQuality quality,
        ProgressCallback progress);

    // OpenCASCADE 版本
    static string OcctVersion { get; }
}

MeshQuality 枚举

public enum MeshQuality
{
    Low,      // 低精度,文件小
    Standard, // 标准精度(推荐)
    High      // 高精度,文件大
}

MeshParams 类

自定义网格化参数:

public ref class MeshParams
{
    double LinearDeflection;   // 线性偏差,默认 0.1
    double AngularDeflection;  // 角度偏差(弧度),默认 0.5
    bool IsRelative;           // 是否使用相对偏差,默认 false
    bool IsParallel;           // 是否并行计算,默认 true

    // 从质量级别创建
    static MeshParams FromQuality(MeshQuality quality);
}

GlbExportParams 类

GLB 导出参数:

public ref class GlbExportParams
{
    CoordinateSystem OutputCoordinateSystem; // 输出坐标系,默认 Y-up
    bool EmbedTextures;                      // 是否嵌入纹理,默认 true
    bool MergeFaces;                         // 是否合并面,默认 false
    bool ForcedUVExport;                     // 是否强制导出 UV,默认 false
}

CoordinateSystem 枚举

public enum CoordinateSystem
{
    Undefined = 0,
    Zup = 1,  // Z 轴向上(CAD 标准)
    Yup = 2   // Y 轴向上(glTF 标准)
}

ConvertResult 类

转换结果:

public ref class ConvertResult
{
    bool Success;           // 是否成功
    string ErrorMessage;    // 错误信息
    int ShapeCount;         // 形状数量
    int FaceCount;          // 面数量
    int TriangleCount;      // 三角形数量
}

ProgressCallback 委托

public delegate void ProgressCallback(int percent, string stage);

完整示例

示例 0:控制台应用程序(最简示例)

using System.Runtime.InteropServices;
using OCCTProxyLib;

// 初始化 DLL 路径
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern bool SetDllDirectory(string path);

var occtPath = Path.Combine(AppContext.BaseDirectory, "OpenCascade", "x64");
SetDllDirectory(occtPath);

// 显示 OpenCASCADE 版本
Console.WriteLine($"OpenCASCADE Version: {CadConverter.OcctVersion}");

// 转换 STEP 到 GLB
using var converter = new CadConverter();
var result = converter.ConvertToGlb(
    args[0],  // 输入文件
    Path.ChangeExtension(args[0], ".glb"),
    MeshQuality.Standard,
    null);

Console.WriteLine(result.Success
    ? $"成功: {result.TriangleCount} 三角形"
    : $"失败: {result.ErrorMessage}");

示例 1:带进度回调的转换

using OCCTProxyLib;

OcctEnvironment.Initialize();

using var converter = new CadConverter();

// 定义进度回调
ProgressCallback progress = (percent, stage) =>
{
    Console.WriteLine($"[{percent,3}%] {stage}");
};

var result = converter.ConvertStepToGlb(
    @"C:\Models\assembly.step",
    @"C:\Output\assembly.glb",
    MeshQuality.High,
    progress);

if (result.Success)
{
    Console.WriteLine($"\n转换完成!");
    Console.WriteLine($"三角形数: {result.TriangleCount:N0}");
}

示例 2:自定义参数转换

using OCCTProxyLib;

OcctEnvironment.Initialize();

using var converter = new CadConverter();

// 自定义网格参数
var meshParams = new MeshParams
{
    LinearDeflection = 0.05,   // 更高精度
    AngularDeflection = 0.2,
    IsParallel = true
};

// 自定义导出参数
var exportParams = new GlbExportParams
{
    OutputCoordinateSystem = CoordinateSystem.Yup,
    MergeFaces = true
};

var result = converter.ConvertStepToGlb(
    "input.step",
    "output.glb",
    meshParams,
    exportParams,
    null);

示例 3:批量转换

using OCCTProxyLib;

public class BatchConverter : IDisposable
{
    private readonly CadConverter _converter;

    public BatchConverter()
    {
        OcctEnvironment.Initialize();
        _converter = new CadConverter();
    }

    public void ConvertAll(string inputDir, string outputDir)
    {
        var files = Directory.GetFiles(inputDir, "*.step")
            .Concat(Directory.GetFiles(inputDir, "*.stp"))
            .Concat(Directory.GetFiles(inputDir, "*.iges"))
            .Concat(Directory.GetFiles(inputDir, "*.igs"));

        foreach (var file in files)
        {
            var outputFile = Path.Combine(
                outputDir,
                Path.GetFileNameWithoutExtension(file) + ".glb");

            Console.WriteLine($"转换: {Path.GetFileName(file)}");

            var result = _converter.ConvertToGlb(
                file, outputFile, MeshQuality.Standard, null);

            if (!result.Success)
            {
                Console.WriteLine($"  失败: {result.ErrorMessage}");
            }
        }
    }

    public void Dispose()
    {
        _converter?.Dispose();
    }
}

// 使用
using var batch = new BatchConverter();
batch.ConvertAll(@"C:\CAD\Input", @"C:\CAD\Output");

示例 4:ASP.NET Core Web API

using Microsoft.AspNetCore.Mvc;
using OCCTProxyLib;

[ApiController]
[Route("api/[controller]")]
public class CadConverterController : ControllerBase
{
    static CadConverterController()
    {
        // 应用启动时初始化一次
        OcctEnvironment.Initialize();
    }

    [HttpPost("convert")]
    public async Task<IActionResult> Convert(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("请上传文件");

        var ext = Path.GetExtension(file.FileName).ToLower();
        if (ext != ".step" && ext != ".stp" && ext != ".iges" && ext != ".igs")
            return BadRequest("仅支持 STEP 和 IGES 格式");

        var tempInput = Path.GetTempFileName() + ext;
        var tempOutput = Path.ChangeExtension(tempInput, ".glb");

        try
        {
            // 保存上传文件
            using (var stream = System.IO.File.Create(tempInput))
            {
                await file.CopyToAsync(stream);
            }

            // 转换(每次请求创建新实例以支持并发)
            using var converter = new CadConverter();
            var result = converter.ConvertToGlb(
                tempInput, tempOutput, MeshQuality.Standard, null);

            if (!result.Success)
                return BadRequest($"转换失败: {result.ErrorMessage}");

            // 返回 GLB 文件
            var bytes = await System.IO.File.ReadAllBytesAsync(tempOutput);
            return File(bytes, "model/gltf-binary",
                Path.GetFileNameWithoutExtension(file.FileName) + ".glb");
        }
        finally
        {
            // 清理临时文件
            if (System.IO.File.Exists(tempInput))
                System.IO.File.Delete(tempInput);
            if (System.IO.File.Exists(tempOutput))
                System.IO.File.Delete(tempOutput);
        }
    }
}

资源释放最佳实践

1. 使用 using 语句(推荐)

using (var converter = new CadConverter())
{
    // 使用 converter
} // 自动调用 Dispose()

2. 使用 using 声明(C# 8.0+)

using var converter = new CadConverter();
// 使用 converter
// 方法结束时自动释放

3. 手动释放

var converter = new CadConverter();
try
{
    // 使用 converter
}
finally
{
    converter.Dispose();
}

4. 长生命周期服务

public class CadService : IDisposable
{
    private readonly CadConverter _converter;
    private bool _disposed;

    public CadService()
    {
        OcctEnvironment.Initialize();
        _converter = new CadConverter();
    }

    public ConvertResult Convert(string input, string output)
    {
        ObjectDisposedException.ThrowIf(_disposed, this);
        return _converter.ConvertToGlb(input, output, MeshQuality.Standard, null);
    }

    public void Dispose()
    {
        if (_disposed) return;
        _converter?.Dispose();
        _disposed = true;
    }
}

注意事项

  1. 线程安全: CadConverter 不是线程安全的。多线程场景下,每个线程应使用独立的实例。

  2. 内存占用: 大型 CAD 文件可能消耗大量内存。建议:

    • 使用完立即释放
    • 避免同时加载多个大文件
  3. DLL 路径: 必须在使用 CadConverter 前调用 OcctEnvironment.Initialize()

  4. 文件编码: STEP/IGES 文件路径支持 Unicode。

  5. 坐标系: CAD 文件通常使用 Z-up,glTF 标准使用 Y-up,默认自动转换。

系统要求

  • 操作系统: Windows 7 SP1+ / Windows 10 / Windows 11 x64(仅支持 Windows 平台
  • .NET 运行时: .NET 8.0 或更高版本
  • Visual C++ 运行时: Visual C++ Redistributable 2015-2022(已包含在包中)
  • 平台限制: 此包仅适用于 Windows x64 系统,不支持 Linux、macOS 或 ARM 架构

关于 Ijwhost.dll

OCCTProxy 是 C++/CLI 混合模式程序集,在 .NET Core/.NET 5+ 环境中需要 Ijwhost.dll 来加载。

重要说明:

自动提供的情况(推荐)

当满足以下条件时,Ijwhost.dll 由 .NET 运行时自动提供:

  • 使用 .NET Desktop RuntimeMicrosoft.NET.Sdk.WindowsDesktopUseWPF/UseWindowsForms
  • 已安装 .NET 8.0 Desktop Runtime
  • 运行时会自动从以下位置加载:
    C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\<version>\runtimes\win-x64\native\
    
需要手动复制的情况

当使用 Microsoft.NET.Sdk (非 Desktop 项目) 时,Ijwhost.dll 不会自动由运行时提供。

好消息:本 NuGet 包会自动处理!

NuGet 包会在构建时从以下位置动态查找并复制与您当前 SDK 版本匹配的 Ijwhost.dll

  1. NuGet 缓存:$(NuGetPackageRoot)microsoft.netcore.app.host.win-x64\<版本>\runtimes\win-x64\native\
  2. 全局 dotnet packs:C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\<版本>\runtimes\win-x64\native\

这确保了 Ijwhost.dll 始终与您的 .NET SDK 版本兼容,无需手动干预。

使用示例

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <PlatformTarget>x64</PlatformTarget>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="DotNetCore.OCCTProxy" Version="1.0.4" />
  </ItemGroup>
</Project>

如果需要手动复制(仅在极少数情况下):

<ItemGroup>
  <None Include="Ijwhost.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

独立部署:如果使用 dotnet publish --self-containedIjwhost.dll 会自动包含在发布目录中。

常见错误

如果遇到以下错误:

Could not load file or assembly 'OCCTProxy.dll'. 找不到指定的模块。

通常是因为缺少 Ijwhost.dll。解决方案:

  1. 确保已安装 .NET 8.0 Desktop Runtime
  2. 或使用上述方式手动复制 Ijwhost.dll
  3. 确认应用程序以 x64 模式运行

Windows 版本兼容性

Windows 版本 支持状态 备注
Windows 11 x64 ✅ 完全支持
Windows 10 x64 ✅ 完全支持
Windows 8.1 x64 ✅ 支持 需安装 KB2999226
Windows 7 SP1 x64 ✅ 支持 需安装 KB2533623, KB2999226
ARM64 ❌ 不支持 仅 x64
Windows 7 SP1 运行要求

在 Windows 7 SP1 上运行 .NET 8 应用程序,需要安装以下更新:

  1. KB2533623 - 扩展保护机制更新
  2. KB2999226 - Universal C Runtime (必需)
  3. KB3063858 - 安全更新(推荐)

注意: 虽然 .NET 8 可以在 Windows 7 SP1 上运行,但微软官方不提供技术支持。

故障排除

"找不到指定的模块" 错误

Could not load file or assembly 'OCCTProxy.dll'. 找不到指定的模块。

解决方案: 确保在使用前调用 OcctEnvironment.Initialize()

转换失败

检查 ConvertResult.ErrorMessage 获取详细错误信息。常见原因:

  • 文件格式不正确
  • 文件损坏
  • 内存不足

输出文件很大

使用 MeshQuality.Low 或调整 MeshParams.LinearDeflection 降低精度。

许可证

  • OCCTProxy: MIT License
  • OpenCASCADE: LGPL 2.1
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.5 101 2/9/2026
1.0.4 93 2/6/2026
1.0.3 103 1/27/2026
1.0.2 98 1/27/2026
1.0.1 90 1/26/2026
1.0.0 92 1/26/2026

- v1.0.5: 网格化阶段 shape 级并行优化(OSD_Parallel::For),多顶层 shape 并行网格化
     - v1.0.4: 修复中文路径支持(UTF-8 编码)
     - v1.0.3: Ijwhost.dll 从用户 SDK Runtime 动态复制,确保版本兼容
     - 支持 STEP/IGES 导入
     - 支持 glTF/GLB 导出
     - 基于 OpenCASCADE 7.9.3