# ZOS-API 和 ZOSPy 之间的自定义对象转换

ZOSPy使用[Python.NET]连接到 ZOS-API。Python.NET将 .NET对象转换为Python对象，反之亦然，并且允许使用[编解码器]自定义此转换行为。ZOSPy 在 {py:class} `zospy.api.codecs`中定义这些编解码器，并在 {py:class} `zospy.api.apisupport`中加载 ZOS-API 库之前加载它们。

## {py:class} `OpticStudioInterfaceEncoder <zospy.api.codecs.OpticStudioInterfaceEncoder>`

此编码器会自动将通用接口向下转换为具体实现。ZOS-API通常定义一个通用接口，该接口由许多其他更具体的接口实现。

:::{dropdown} 示例 :color: info :icon: light-bulb

`ZOSAPI.Analysis.Settings.IAS_`接口指定所有分析的设置对象应实现的属性和方法。许多分析都有特定于该分析的设置，这些设置由单独的接口指定。例如，惠更斯PSF设置由`ZOSAPI.Analysis.Settings.Psf.IAS_HuygensPsf`接口指定，该接口也继承自`ZOSAPI.Analysis.Settings.IAS_` 。 :::

从Python.NET 3开始，当API返回实现通用接口的对象但您需要访问特定接口的方法或属性时，这会导致问题。此问题的解决方案是将通用接口“向下转换”为特定接口。Python.NET为此使用了`__implementation__`属性。更多信息可在[OpticStudio 社区论坛]上找到。

::::{dropdown} 示例 :color: info :icon: light-bulb

:::{warning} 此示例无法立即使用，因为 {py:class} `zospy.api.codecs.OpticStudioInterfaceEncoder`解决了此问题。您需要修改 ZOSPy 的源代码才能使此示例正常运行。 :::

如果您使用“原始” ZOS-API创建惠更斯 PSF 分析，则无法访问其分析特定设置：

```python
import zospy as zp

zos = zp.ZOS()
oss = zos.connect(mode="standalone")

huygens_psf = oss.Analyses.New_Analysis_SettingsFirst(zp.constants.Analysis.AnalysisIDM.HuygensPsf)
huygens_psf_settings = huygens_psf.GetSettings()

print(huygens_psf_settings.Normalize) # AttributeError: 'IAS_' object has no attribute 'Normalize'
```

通过使用`__implementation__`属性进行向下转换，可以访问惠更斯PSF设置：

```python
print(huygens_psf_settings.__implementation__.Normalize) # False
```

::::

手动访问`__implementation__`不直观，并且会降低代码的可读性。OpticStudioInterfaceEncoder通过自动从接口转换`OpticStudioInterfaceEncoder`实现类解决了这个问题。

### 自动向下转型的接口

接口需要先注册，然后才能由`OpticStudioInterfaceEncoder`进行转换。这些接口默认是向下转换的：

- `ZOSAPI.Analysis.Settings.IAS_`
    - 通过`zp.analyses.new_analysis(<analysis type>).Settings`访问
    - 分析设置的界面。**请注意：** `zospy.analyses`在编解码器实现之前已经执行了向下转换。
- `ZOSAPI.Editors.LDE.ISurface`
    - `oss.LDE.GetSurfaceAt(<index>).SurfaceData`
    - 表面数据，提供对表面特定设置的访问（例如坐标断点的倾斜和偏心）
- `ZOSAPI.Editors.LDE.ISurfaceApertureType`
    - 通过`oss.LDE.GetSurfaceAt(<index>).ApertureData.CurrentTypeSettings`访问
    - 表面孔径设置界面
- `ZOSAPI.Editors.LDE.ISurfaceScatteringType`
    - 通过`oss.LDE.GetSurfaceAt(<index>).ScatteringData.CurrentTypeSettings`访问
    - 表面散射设置界面
- `ZOSAPI.Editors.NCE.IObject`
    - `oss.NCE.GetObjectAt(<index>).ObjectData`
    - 对象数据，提供对特定于对象的设置的访问
- `ZOSAPI.Tools.ISystemTool`
    - `oss.Tools.CurrentTool`
    - 工具设置界面

### 不会自动向下转型的接口

下面列出的接口提供了“便利属性”来访问特定接口。因此，它们不由`OpticStudioInterfaceEncoder`处理。有关更多信息，请参阅 OpticStudio 文档。

- `ZOSAPI.Editors.ISolveData`
- `ZOSAPI.Editors.NCE.ISourceColorSettings`
- `ZOSAPI.Editors.NCE.IObjectScatteringSettings`
- `ZOSAPI.Editors.NCE.IVolumePhysicsModelSettings`
- `ZOSAPI.Editors.NCE.IIndexModelSettings`

:::{dropdown} 示例 :color: info :icon: light-bulb

实现`ZOSAPI.Editors.ISolveSurfacePickup`接口的“Pickup”求解器可以通过这种方式访问：

```python
# ThicknessCell is only an example, you can use any cell that supports the Pickup solver
oss.LDE.GetSurfaceAt(<index>).ThicknessCell.GetSolveData()._S_SurfacePickup
```

:::

### 注册其他接口以进行自动向下转型

您可以使用 {py:class} `zospy.api.codecs.OpticStudioInterfaceEncoder.register_interfaces`注册其他接口。如果您认为找到了应默认转换的接口，请提交问题或创建 Pull 请求。


[Python.NET]: https://pythonnet.github.io/
[编解码器]: https://pythonnet.github.io/pythonnet/codecs.html
[OpticStudio 社区论坛]: https://community.zemax.com/zos-api-12/pythonnet-3-x-is-fixed-3945