Shattered Workflows

Overview

HOOPS Web Viewer component makes it easy to aggregate multiple models together. Such models might consist of the various disciplines in a federated BIM model, different variants of a chassis in a Car Configurator or subcomponents of a complex MCAD assembly. We are using the term “shattered” most commonly in the context of the last example - a complex assembly like a car or an airplane consisting of hundreds or thousands of individual parts. Often in the original CAD assembly, each subcomponent of an assembly will reside in its own file. The goal with “shattered” support in HOOPS Communicator is to largely retain that structure when converting an assembly to the Stream Cache format. Instead of creating a single monolithic Stream Cache (SC) model for the assembly, we generate individual SC models for each part and then an additional “master model” and/or XML product structure file that aggregates those parts into a complete assembly.

Advantages of the shattered workflow

One approach to viewing a complex CAD Assembly in HOOPS Communicator is to create a single SC model that contains all the parts of an assembly, using our conversion tools or via direct authoring. While this SC Model could get quite large, the intelligent streaming support in the Stream Cache Server ensures that this model can be viewed almost instantly. In combination with memory limiting or the use of Server-Side rendering, even massive monolithic models can be viewed on a modest laptop or mobile phone. You can also use OnDemand mode to keep the model on the server, and only request the components or subassemblies a user is interested in.

The main advantage that the shattered approach has over the monolithic workflow, is in how it deals with variants and configurations of an assembly, and a PLM system is a prime example. Multiple users working on the same assembly means that the data is constantly evolving and changing, new variants of parts are getting “checked in”, some may be deleted, and subassemblies are added and reconfigured. In addition, a user may want to view an older state of an assembly or mock up a different configuration. In each of these scenarios, every time the model changes or a different variant of the model is requested, a new monolithic SC model would have to be generated which can be slow and resource heavy.

With the shattered approach, creating new configurations of an assembly simply involves updating the XML product structure hierarchy of the assembly, and then reconverting the components of a model that have changed. In most case, it makes viewing different variants of a model almost instantaneous.

Utilizing the shattered approach

Creating a shattered model on the server is discussed in the Data Import section of the Programming Guide. To quickly review, this involves first creating an XML product structure file. This file describes the structure of the model and its dependencies to other SC models, which in turn typically represent the parts of an assembly. Then in an optional step, a SC master model can be generated by our conversion tools from this XML file. This file can be loaded just like any other SC model into the viewer, via the Stream Cache Server.

See below for two diagrams showing a typical, slightly simplified assembly tree hierarchy and the files associated with this hierarchy.

../../../../_images/microengine_catproduct_tree_hierarchy.png
  • Simplified representation of a Catia Assembly. Note that each unique part is represented by a single “catpart” file while each assembly (and subassembly) is represented by a “catproduct” file. Instanced parts (like the screw) are only represented once but show up multiple times in the hierarchy.*

../../../../_images/microengine_master_tree_hierarchy.png

When converting the assembly shown in the first diagram to a shattered SC model, a SC file (scz or scs Linking Required) is created for each unique part in the assembly. In addition, a master SC model might be created from the XML Product Structure File that contains the assembly structure and references the part-level Stream Cache models. The shattered implementation of SC does not support referencing of subassemblies so those are flattened.

Client-side shattered

While you can create a so called “master model” on the server that serves as the equivalent of a top-level assembly file, the disadvantage to this approach is that it requires this master model to be regenerated every time the structure of an assembly changes. In addition, a SC master model must be streamed via the HOOPS Stream Cache Server and cannot be an SCS file. An alternative to that approach is “client-side shattered”.

We have already touched on the functions for client-side shattered support in the previous chapter. The general approach is that you are utilizing the XML product structure file generated either when converting a CAD assembly through our import tools, or directly by your application. You simply pass this file to the relevant loadSubtree functions:

As you can see, client-side shattered supports SCS files as well, which means it does not require the Stream Cache Server.

The downside to client-side shattered is that you will need to transfer the XML product structure file to your browser client (or generate it there). Streaming/Loading performance and general framerate are also not quite as good as server side shattered, because less optimization is performed on the model before streaming.

XML format

Below is an example of an XML product structure file in its entirety. While we discuss some of the tags in more detail in another chapter here, we provide a quick “recipe” for creating one yourself:

  1. Start by creating an empty “Root” and “Modelfile” tag

  2. Each “ProductOccurrence” tag is essentially a node in the model tree of the HOOPS Web Viewer component. The “id” attribute represents the nodeid of the node and has to be unique. The children of a ProductOccurrence node are referenced by the “Children” attribute as a list of nodeids separated by spaces. In the XML they point to other ProductOccurrences.

  3. Don’t worry about the LayerId, Style, ExchangeId, isPart, and Behavior attributes for now. Just set them to the following defaults:

  • LayerId=”65535”

  • Style=”65535”

  • Behaviour=”1”

  • ExchangeId=””

  • isPart=false;

  1. The “FilePath” attribute is optional when you are creating your XML data. When importing a CAD model, it represents the location of the original CAD file corresponding to the node.

  2. The Transformation tag is used to set the relative 4x4 transform matrix for this node (if any).

  3. At the “leafs” to the model tree, you have to use the “InstanceRef” attribute to point to the ProductOccurrence representing the actual SC model associated with that node. This “part”-level SC model can be instanced multiple times in the model.

  4. ProductOccurence tag

<ProductOccurence Id="2" Name="HOUSING(HOUSING.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\test\housing .CATPart" InstanceRef="17" IsPart="false">``
  1. Transformation tag

<Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 21.5 -0.5 -0.310000002384185791 1"/>``
  1. Closing tag

</ProductOccurence>

In the above example, we have created effectively a new node with nodeid 2. It’s a leaf node that points to part-level ProductOccurrence with Nodeid 17. It also includes a relative transformation that will be applied to the part instance.

  1. The ProductOccurrence representing an instanced part will have the “External Model” tag as one of its children. The “Name” attribute represents the name of the SC model that will be attached at that node. Inside the “External Model” tag is also a bounding box tag that is optional, but should be supplied for optimal streaming/loading performance.

<ProductOccurence Id="17" Name="" ExchangeId="" Behaviour="1" IsPart="false">
        <ExternalModel Name="housing .CATPart" Unit="0.000000">
                <BoundingBox Min="-21.959007 0.155000 -71.000000" Max="21.959007 57.845001 0.309999"/>
        </ExternalModel>
</ProductOccurence>

This is the ProductOccurrence pointing to the actual SC model. It can be instanced multiple times throughout the Product Occurrence hierarchy. The name of the SC model (as referenced in the ExternalModel tag) is “housing .CATPart”). When generating a shattered model via our conversion tool the name of the SC models will be the same as the name of the original CAD part.

With this “recipe” you should be able to generate your own XML Product Structure XML

<!--HC 7.0-->
        <Root>
                <ModelFile>
                        <ProductOccurence Id="0" Name="_micro engine" ExchangeId="" Behaviour="1" Children="1" Unit="1.000000" IsPart="false"/>
                        <ProductOccurence Id="1" Name="Product1" ExchangeId="" LayerId="65535" Style="65535" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\_micro engine.CATProduct" Children="2 3 4 5 6 7 8 9 10 11 12 13 14 15 16" IsPart="false"/>
                        <ProductOccurence Id="2" Name="HOUSING(HOUSING.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\housing .CATPart" InstanceRef="17" IsPart="false">
                                <Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 21.5 -0.5 -0.310000002384185791 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="17" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="housing .CATPart" Unit="0.000000">
                                        <BoundingBox Min="-21.959007 0.155000 -71.000000" Max="21.959007 57.845001 0.309999"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="4" Name="HOUSING TOP(HOUSING TOP.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\housing top.CATPart" InstanceRef="19" IsPart="false">
                                <Transformation RelativeTransfo="3.673819061467131775e-16 0 1 0 0 1 -0 0 -1 0 3.673819061467131775e-16 0 21.5 28.5 -90.30999755859375 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="19" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="housing top.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-0.000001 -22.650000 -22.650000" Max="20.000000 22.650000 22.650000"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="5" Name="MOBILE PART(MOBILE PART.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\mobile part.CATProduct" Children="20 21 22 23 24 25 26" IsPart="false">
                                <Transformation RelativeTransfo="-1 5.967448757360216405e-16 5.796494612244943129e-17 0 -5.963211475041576767e-16 -0.9999751448631286621 0.007053606212139129639 0 6.217270801938827628e-17 0.007053606212139129639 0.9999751448631286621 0 122.3708648681640625 31.22583198547363281 -48.94095611572265625 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="22" Name="BEARING PR UP(BEARING PR UP.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\bearing_pr_up.CATPart" InstanceRef="29" IsPart="false">
                                <Transformation RelativeTransfo="1.224606353822377258e-16 -1 6.123031769111886291e-17 0 1 1.224606353822377258e-16 -6.123031769111886291e-17 0 6.123031769111886291e-17 6.123031769111886291e-17 1 0 100.7928009033203125 2.896131038665771484 7.920945644378662109 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="29" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="bearing_pr_up.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-2.999875 -2.500000 -2.999875" Max="2.999875 2.500000 2.999875"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="23" Name="AXE(AXE.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\axe.CATPart" InstanceRef="30" IsPart="false">
                                <Transformation RelativeTransfo="1.224606353822377258e-16 -1 6.123031769111886291e-17 0 1 1.224606353822377258e-16 -6.123031769111886291e-17 0 6.123031769111886291e-17 6.123031769111886291e-17 1 0 109.2928009033203125 2.896131038665771484 7.920945644378662109 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="30" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="axe.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-2.249906 -17.000000 -2.249906" Max="2.249906 0.000000 2.249906"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="24" Name="PISTON(PISTON.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\piston.CATPart" InstanceRef="31" IsPart="false">
                                <Transformation RelativeTransfo="1 1.228910075287817155e-16 -4.334177738606216262e-19 0 4.334177738606216262e-19 -0.007053606212139129639 -0.9999751448631286621 0 -1.228910075287817155e-16 0.9999751448631286621 -0.007053606212139129639 0 100.7928009033203125 2.896131038665771484 7.920945644378662109 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="31" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="piston.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-9.000000 -8.000000 -9.000000" Max="9.000000 10.000000 9.000000"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="25" Name="CRANKSHAFT(CRANKSHAFT.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\crankshaft.CATPart" InstanceRef="32" IsPart="false">
                                <Transformation RelativeTransfo="6.145965186158796473e-17 -0.003752432996407151222 0.9999929666519165039 0 -1 -4.310860042204164927e-22 6.14600819955064923e-17 0 -2.30193740372515124e-19 -0.9999929666519165039 -0.003752432996407151222 0 37.19280242919921875 2.929903030395507813 28.92100906372070313 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="32" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="crankshaft.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-14.749386 -67.100006 -14.749386" Max="14.749386 0.000000 14.749386"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="6" Name="HOUSING BACK(HOUSING BACK.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\housing back.CATPart" InstanceRef="34" IsPart="false"/>
                        <ProductOccurence Id="34" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="housing back.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-0.000000 8.500000 -40.000000" Max="11.400001 48.500000 0.000000"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="7" Name="HOUSING FRONT(HOUSING FRONT.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\housing front.CATPart" InstanceRef="35" IsPart="false">
                                <Transformation RelativeTransfo="1 -1.224606353822377258e-16 1.224606353822377258e-16 0 1.224606353822377258e-16 9.436895709313830594e-16 -1 0 1.224606353822377258e-16 1 9.436895709313830594e-16 0 31.60000038146972656 28.5 -20 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="35" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="housing front.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-0.000000 -19.999166 -19.999166" Max="41.099998 20.000000 19.999166"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="8" Name="SCREW BACK(SCREW BACK.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\screw back.CATPart" InstanceRef="36" IsPart="false">
                        <Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 5 41 -7.5 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="36" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="screw back.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-4.000000 -1.992075 -1.992075" Max="35.000000 1.992075 1.992075"/>
                                </ExternalModel>
                        </ProductOccurence>
                        <ProductOccurence Id="9" Name="SCREW BACK(SCREW BACK.2)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\screw back.CATPart" InstanceRef="36" IsPart="false">
                                <Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 5 16 -7.5 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="16" Name="CARBURETOR(CARBURETOR.1)" ExchangeId="" LayerId="65535" Style="0" Behaviour="1" FilePath="C:\Communicator\newmaster\HOOPS_Communicator_2019_SP1\authoring\converter\example\_data\micro_engine\carburetor.CATPart" InstanceRef="38" IsPart="false">
                                <Transformation RelativeTransfo="-0.9545378684997558594 -0.005617600400000810623 -0.2980366349220275879 0 0.005362296942621469498 -0.9999842047691345215 0.001674277125857770443 0 -0.2980413436889648438 -9.278602192130946946e-16 0.9545529484748840332 0 44.57569503784179688 28.5 -49.14356231689453125 1"/>
                        </ProductOccurence>
                        <ProductOccurence Id="38" Name="" ExchangeId="" Behaviour="1" IsPart="false">
                                <ExternalModel Name="carburetor.CATPart" Unit="0.000000">
                                        <BoundingBox Min="-4.913620 -22.940001 -9.991000" Max="4.913620 19.200001 21.009001"/>
                                </ExternalModel>
                        </ProductOccurence>
                </ModelFile>
        </Root>

Using HTTP compression to reduce resource size

The XML file for complex assemblies with many parts can grow quite large. As this file grows, the time to transfer the resource to the client for processing increases, degrading the user experience as they must wait longer before seeing something on the screen.

HTTP compression is an easy way to gain a performance boost when dealing with large XML Assembly files. This scheme is implemented at the server or browser level, and does not require modification to client-side code. When compression is enabled, a compression algorithm is applied to the data on the server before it is sent to the client. The encoding is negotiated between the browser and server.

In the image below, an XML file for a large Assembly is 11.6mb. The response sent back to the client is ~717kb while the resource size is 11.6mb. Examining the response headers, we can see that the content-encoding is set to gzip while the content-type is application/xml.

../../../../_images/http-compression-example.png

The steps required to enable compression will vary depending on your server and framework. However, you must ensure compression is enabled for xml files.

SCS XML loading with cutoff scale

When using XML loading with a cutoff scale, SCS files will only be requested when they are within the view frustum and also have a projected size greater than the stream cutoff value. Files that pass the cutoff test are prioritized by their projected size, which is recalculated as the camera changes. Using this mode can reduce the amount of resources required when viewing large assemblies by not loading and rendering inconsequential or parts outside the viewing frustum. When using this mode, it is important to note that the promise returned by the appropriate loadSubtreeFromScsXml method will not return until all files specified in the XML Product Structure have been loaded. If you need to load another model before all files specified in the XML Product Structure have loaded, use the Model.clear method and wait on the returned promise before making additional calls to the Model.loadSubtree family of methods.

Stream cutoff mode is disabled by default for SCS XML loading. To enable it, set the streamCutoffScale property of your viewer configuration object when creating your WebViewer or call setStreamCutoffScale directly before calling the appropriate loadSubtreeFromScsXml method. Additionally, this mode requires that bounding information be present in your XML Product Structure.