概述
Visualize SDK 文件格式 VSFX 具有内置流式传输支持。这意味着如果 VSFX 文件可以作为一组二进制数组提供,Visualize SDK 可以一致地处理这些数组并使用这些数组中的内容生成 Visualize 数据库。此外,通过提供“足够”的数组,甚至可以渲染不完整的数据库。请注意,Visualize SDK 不会将解析后的数据保留在内存中,因此不完整的数据库仅在内存中保留源数据中未解析的部分。但是,由于某些限制,常规 VSFX 文件在高效流式传输之前应进行预处理。本文介绍了预处理阶段和收集数据库数据的过程。
VSFX 预处理
流式兼容性
VSFX 文件可以表示为一组节。所有节可分为两组:对象节(包含可视化对象数据:实体、几何体、设备等)和服务节(描述如何解析对象节)。
服务节依赖于对象节,因此当您生成 VSFX 文件时,服务节会放置在对象节之后。流式传输此类文件完全无效:只有在文件全部内容流式传输完毕后,Visualize SDK 才能读取它。此类文件称为流式不兼容文件。
OdTvDatabaseReceiver 具有静态方法,可以检查 VSFX 文件是否流式兼容,并且具有可以将流式不兼容的 VSFX 文件转换为流式兼容文件的方法:
static bool isStreamingCompatible( const OdString& fileName, OdTvResult* pRes = NULL );
static bool isStreamingCompatible( OdStreamBuf* pBuffer, OdTvResult* pRes = NULL );
static OdTvResult makeStreamingCompatible( const OdString& input, const OdString& output );
static OdTvResult makeStreamingCompatible( OdStreamBuf* pInput, OdStreamBuf* pOutput );
转换为流式兼容文件是一个足够快的进程,因为 Visualize SDK 只交换 VSFX 文件节而不解析其内容。
此外,通用的 Visualize SDK VSFX 文件读取方法在流式兼容和流式不兼容情况下都同样有效。
下图显示了流式兼容和流式不兼容情况下节位置的差异:
流友好文件
VSFX 流式传输的主要目标是在仅解析 VSFX 文件的一部分时渲染可视化数据库。然而,除了可渲染对象(实体、几何体、插入)之外,对象节还包含渲染所需的其他对象:设备、视图、线型等。因此,渲染一个未接收所有必需对象的不完整数据库可能是不可能的(未解析设备或视图),或者可能产生与渲染完整数据库显著不同的结果(错误的颜色、线型等)。
在流友好 VSFX 文件中,对象节的构成方式是所有渲染所需的对象都放置在可渲染对象之前。在解析完所有必需对象后,这些文件可以正确渲染。
在非流友好 VSFX 文件中,也可以渲染不完整的数据库,但在这种情况下,客户端应用程序需要确保数据库已解析所有必要的对象。例如,它可以检查设备和视图迭代器、线型迭代器等。
通用的 VSFX 文件写入方法总是生成流友好的内容。然而,卸载数据库部分对象(例如低内存导入)可能会生成非流友好文件。
isStreamingFriendlySource() 方法检查数据解析是否流友好,如果返回 true,则 isDatabaseRenderable() 方法通知数据库可以安全渲染。
假设一个对象节包含四种类型的数据:设备、图层、实体和几何体。设备和图层数据是渲染所必需的。因此,如果某些图层具有颜色,则在这些图层未在实体渲染之前加载的情况下(因为在这种情况下使用默认图层),分配了“按图层着色”的图层上的实体将渲染不正确。其余数据——实体和几何体——是可渲染数据。当加载可渲染对象时,渲染场景会获得更多细节,但如果其中一些对象缺失,它们将不会被绘制,并且不会影响先前绘制的对象。
下图显示了所描述示例中流友好和非流友好情况之间的差异:
在客户端应用程序中收集数据库
在客户端收集数据库:
- 使用 OdTvFactory 实例创建 OdTvDatabaseReceiver 实例:
OdTvFactoryId factId = odTvGetFactory(); OdTvDatabaseReceiverPtr pDbReceiver = factId.createDatabaseReceiver(); - 接收器应处理每个输入数据数组:
/*Input: const OdUint8* pData; //.VSFX 文件的一部分 OdUInt32 nDataSize; //pData 数组的长度 */ bool bDone = pDbReceiver->doReceive( pData, nDataSize); - 如果数据库完全接收,doReceive 方法返回 true。在这种情况下,数据接收过程可以停止。否则,应用程序应决定不完整的数据库是否已准备好进行渲染。首先,检查由 DatabaseReceivingState 枚举值表示的接收状态:
状态可以是以下之一:OdTvDatabaseReceiver::DatabaseReceivingState state = pDbReceiver->state();- OdTvDatabaseReceiver::kReceiver_Nothing — 未接收到任何内容;数据库为空。
- OdTvDatabaseReceiver::kReceiver_AwaitingServiceData — 数据解析已开始,但目前即使是服务部分也不完整,因此数据库仍然为空。
- OdTvDatabaseReceiver::kReceiver_AwaitingObjectsData — 数据解析已开始,并且所有服务部分都已接收;从这个状态开始,应用程序可以访问数据库并尝试渲染其内容。
- OdTvDatabaseReceiver::kReceiver_Complete — 数据库已完全接收,并准备好进行进一步处理,不受限制。
如果状态低于 OdTvDatabaseReceiver::kReceiver_AwaitingObjectsData,应用程序应继续接收数据而不进行数据库处理;如果状态高于 OdTvDatabaseReceiver::kReceiver_AwaitingObjectsData,则数据库已完全接收。
如果状态是 OdTvDatabaseReceiver::kReceiver_AwaitingObjectsData(因为在大多数情况下,VSFX 文件的最大部分包含对象部分),应用程序应检查 VSFX 源是否支持流式传输,如果是,应用程序可以使用 isDatabaseRenderable() 方法检查它是否可以渲染数据库:
if( state == OdTvDatabaseReceiver::kReceiver_AwaitingObjectsData ) { if( pDbReceiver->isStreamingFriendlySource() ) return pDbReceiver->isDatabaseRenderable(); } - OdTvDatabaseReceiver::kReceiver_Nothing — 未接收到任何内容;数据库为空。
- OdTvDatabaseReceiver::kReceiver_AwaitingServiceData — 数据解析已开始,但目前即使是服务部分也不完整,因此数据库仍然为空。
- OdTvDatabaseReceiver::kReceiver_AwaitingObjectsData — 数据解析已开始,并且所有服务部分都已接收;从这个状态开始,应用程序可以访问数据库并尝试渲染其内容。
- OdTvDatabaseReceiver::kReceiver_Complete — 数据库已完全接收,并准备好进行进一步处理,不受限制。
- 如果 VSFX 源文件不支持流式传输,应用程序应手动检查它是否可以打开渲染所需的所有对象。例如,以下代码检查数据库是否包含第一个设备和其中至少一个视图:
OdTvDatabaseId dbID = pDbReceiver->database(); OdTvDatabasePtr pDb = dbID.openObject( OdTv::kForRead ); if( pDb.isNull() ) return false; OdTvDevicesIteratorPtr pDevIt = pDb->getDevicesIterator(); if( pDevIt.isNull() ) return false; OdTvGsDeviceId devId = pDevIt->getDevice(); if( devId.isNull() ) return false; OdTvGsDevicePtr pDevice = devId.openObject( OdTv::kForRead ); bool anyView = false; OdTvResult tvRes = tvOk; int nViews = pDevice->numViews( &tvRes ); if( tvRes != tvOk || nViews == 0 ) return false; for( int i = 0; i < nViews; ++i ) { if( !pDevice->viewAt( i ).isNull() ) anyView = true; } return anyView;
示例
OdVisualizeFirstApp 示例应用程序实现了一个流式传输工具。由于它不是网络应用程序,它通过从 VSFX 文件读取二进制数据块来模拟流式传输。它还对输入 VSFX 文件进行了流式传输兼容性检查和转换,这通常应在服务器端实现。
要在 OdVisualizeFirstApp 应用程序中启用流式传输工具,需要在 CommonApplications/Visualize/Examples/win/OdVisualizeFirstApp/resource.h 中取消注释 OD_VISUALIZE_APP_ENABLE_STREAMING 定义。示例代码位置:OdVisualizeAppStreaming.h 和 OdVisualizeAppStreaming.cpp。