9.3 Component hierarchy

9.3.1 Utilizing the ComponentPath
9.3.2 Managing component visibility
9.3.3 Interacting with highlights
9.3.4 Using transforms with components
9.3.5 Deinstancing components


HOOPS Visualize uses a generic component hierarchy to represent third-party CAD models which feature topological entities. The component hierarchy is a way to organize the scene graph uniformly across disparate file formats. It also provides developers the ability to extend the capabilities of our importers, as well as to create entirely new importers in a way that is compatible with the Visualize scene graph. The HOOPS Exchange and Parasolid importers both use the component hierarchy.

[figure 9.2.a] The HPS::Component object hierarchy

The major parts of the hierarchy are described below:

Object nameDescription
HPS::CADModel The root entity of the 3D model. Files loaded with the HOOPS Exchange importer will have a root entity of type HPS::Exchange::CADModel. The Parasolid importer uses HPS::Parasolid::CADModel.
HPS::Capture A specific view of an object, including the camera, materials, transforms, etc.
HPS::Filter A collection of visibility settings for a HPS::CADModel
HPS::*::Component A complex object which can represent a variety of model components, including non-geometric components

In general, components refer to Visualize objects, whereas entities refer to the underlying object of the model's native platform. However, there is not a perfect one-to-one mapping between components and entities. For example, some modeling APIs represent faces and edges as two separate entities, but Visualize groups the two into a single shell. For a list of all supported entities and their corresponding components, see the reference manual entry for HPS::Component.

Using a model browser

When loading a model using HOOPS Exchange, a common operation is to navigate the model hierarchy using a tree control. HOOPS Visualize does not provide such a control as part of its API, but you can see an example of one in use in the WPF or MFC sandboxes.

9.3.1 Utilizing the ComponentPath

A ComponentPath is an explicit list of components that form a path from an individual component to the top of the scene graph. A ComponentPath is very similar to a KeyPath, except that it forms a list of Component objects instead of Key objects (key path objects are discussed in section 1.2). If necessary, you can get a component path from a key path by calling CADModel::GetComponentPath().

When using GetComponentPath(), it is important to understand that only unambiguous portions of paths are returned. For example, consider the cube below – specifically, the edge between the red and green faces:

If you ask Visualize to return a path describing this edge, what should that component path look like? Since the component path is ordered leaf to root, it should start with the edge that was selected and should make its way towards the CADModel object. But as we go up the hierarchy we find that we have a problem: which face will be part of the path? The red or the green one?

The edge selected belongs to both faces, and there is no information provided to indicate whether the user is interested in the red one, the green one, or neither. The situation is ambiguous.

If you call GetComponentPath() with the PathType::Unique argument, it will only include unambiguous components in the component path. Therefore the path returned might look something like this:

  • Edge / Shell / Connex / Body / RI BRep Model / Part Definition / P. Occurrence / Model

Visualize also provides an option to return a complete component path. What this means is that HPS will make an assumption as to which face the user needs in the example above. In this case, the returned path will look like this:

  • Edge / Co-Edge / Loop / Face / Shell / Connex / Body / RI BRep Model / Part Definition / P. Occurrence / Model

Which face was returned in the above component path? The red or the green one? Visualize returns the face encountered first – therefore, the result is not guaranteed.

9.3.2 Managing component visibility

HPS::ComponentPath contains several utilities which allow you to show, hide, and isolate components at a high level. The visibility changes made by these functions are intended to be HPS::View local and transient so they will not be reflected in the model if exported. Calling HPS::ComponentPath::Hide() will force all geometry contained at or below that path to become invisible. Calling HPS::ComponentPath::Show() with the default options will force all geometry contained at or below that path to become visible. Calling HPS::ComponentPath::Isolate() with the default options will force all geometry contained at or below that path to become visible and force all other geometry in that HPS::CADModel to become invisible.

[figure 9.3.1.a] The component path identifying the bottom right tire of this landing gear has been hidden (left), then shown again (center), then isolated (right).

HPS::ComponentPath::Show() and HPS::ComponentPath::Isolate() also allow for more complex behavior. These functions take the enumeration HPS::Component::Visibility, which can be used to preserve the visibility of subcomponents under the specified path. The default value of HPS::Component::Visibility::PreserveNone indicates that we do not intend to preserve the visibilities of any subcomponents, resulting in every component underneath the specified path becoming visible. However, the HPS::ComponentPath being operated on may have hidden subcomponents defined by the model that we want to preserve. In this case, we can pass the value HPS::Component::Visibility::PreserveModelDefined which will make all geometry at or below the specified path visible except the geometry defined by the model as invisible.

[figure 9.3.1.b] A drill assembly was loaded which contains hidden construction geometry (left). Calling Isolate() on a sub-assembly containing construction geometry with PreserveNone (center) made its construction geometry visible during isolation. Calling Isolate() on the same sub-assembly with PreserveModelDefined (right) kept the construction geometry hidden.

In addition, HPS::ComponentPath::Show() and HPS::ComponentPath::Isolate() allow for preserving the visibility of subcomponents that were modified explicitly by previous calls to HPS::ComponentPath::Show() and HPS::ComponentPath::Hide(). Providing the value HPS::Component::Visibility::PreserveUserDefined indicates that any visibility changes made to subcomponents via HPS::ComponentPath::Show() and HPS::ComponentPath::Hide() should be preserved when performing the current operation.

Providing the value HPS::Component::Visibility::PreserveAll indicates that we want to preserve previous HPS::ComponentPath::Show() and HPS::ComponentPath::Hide() actions under the specified path in addition to preserving the visibility of any subcomponents defined by the model itself.

[figure 9.3.1.c] A drill assembly was loaded which contains hidden construction geometry and then the cover for the carburetor was hidden via Hide() (left). Calling Isolate() on the carburetor sub-assembly containing construction geometry with PreserveUserDefined (center) caused the sub-assembly's construction geometry to become visible but kept the cover hidden. Calling Isolate() on the same sub-assembly with PreserveAll (right) kept the construction geometry hidden and the cover hidden.

Limitations: Geometry modified by HPS::ComponentPath::Show(), HPS::ComponentPath::Hide(), and HPS::ComponentPath::Isolate() may not interact properly with other transparent geometry contained in the scene. If HPS::ComponentPath::Isolate() is called on an assembly containing only hidden subcomponents (and subcomponents visibility is preserved) the scene may become empty (unless the part being isolated contains geometry directly at the specified path).

9.3.3 Interacting with highlights

Performing highlights on HPS::ComponentPath requires special considerations when used in combination with HPS::ComponentPath::Show(), HPS::ComponentPath::Hide(), and HPS::ComponentPath::Isolate(). These functions internally use highlights to perform their transient visibility changes, and external highlights need to mirror some of the same highlight settings to work properly.

External highlights should be applied using the HPS::Drawing::Overlay::WithZValues overlay and should not contain visibility changes of their own as this may interfere with the visibility changes performed by HPS::ComponentPath::Show(), HPS::ComponentPath::Hide(), and HPS::ComponentPath::Isolate().

In addition, the external highlight should be passive, which can be enabled by HPS::HighlightOptionsKit::SetPassive(true).

9.3.4 Using transforms with Components

When working with components of types Exchange, Parasolid, and ExchangeParasolid, there are two data layers associated with any model: the Visualize scene graph, and the underlying PRC data. Making changes to the Visualize scene graph may produce a distinct visual result, but generally does not modify the PRC. For example, if you apply a transform to a segment which contains part of an Exchange model, then save the file, that transform will not be present in the saved model.

To make a transform to both the scene graph and to the PRC data, use Component::SetTransform() or Component::AddTransform(). The transform will be applied both visually and to the underlying native data.

NOTE: When you apply a transform using Component::SetTransform(), the new transform will REPLACE any existing transforms set on that component. When you apply a transform using Component::AddTransform(), the new transform is APPENDED to the existing transform.

Only certain types of components can have transforms applied to them:

9.3.5 Deinstancing Components

Deinstancing a component refers to analyzing a geometry's HPS::ComponentPath to determine the level at which changes can be made without interefering with other instanced geometry. This is done using HPS::Factory::DeInstanceComponent, which is available for components of types Exchange, Parasolid, and ExchangeParasolid.

For example, imagine a model of a car which contains four wheels. Each wheel is just an instance of one original wheel geometry. When a user wants to move a wheel, setting a transform on the wheel itself will cause all four wheels to move.

To move just one wheel, you can collect a HPS::ComponentPath for the wheel you are interested in, then call HPS::Factory::DeInstanceComponent().

This function will analyze the path and return a component along it at which level it is safe to apply a transform, such that only the selected wheel will be affected.

Example usage:

[snippet 9.3.a]
// a user selects a wheel on the screen through a mouse
SelectionOptionsKit selection_options;
HPS::SprocketPath mySprocketPath(myCanvas);
if (myWindowKey.GetSelectionControl().SelectByPoint(Point(0, 0, 0), selection_options, results) > 0)
{
// we obtain a keypath from the selection results
HPS::KeyPath path_to_selection;
item.ShowPath(path_to_selection);
// using the CADModel, we obtain a ComponentPath from the KeyPath
HPS::ComponentPath component_path = myCADModel.GetComponentPath(path_to_selection);
// we figure out at which level is appropriate to insert a transform, so that only the instance of the wheel I selected is affected
HPS::Component transform_target = HPS::Factory::DeInstanceComponent(component_path);
// we apply the transform
HPS::MatrixKit transform;
transform.Translate(5, 0, 0);
transform_target.SetTransform(transform);
myCanvas.Update();
}
// a user selects a wheel on the screen through a mouse
SelectionOptionsKit selection_options = new SelectionOptionsKit();
HPS.SprocketPath mySprocketPath = new SprocketPath(myCanvas);
if (myWindowKey.GetSelectionControl().SelectByPoint(new Point(0, 0, 0), selection_options, out results) > 0)
{
// we obtain a keypath from the selection results
HPS.SelectionItem item = results.GetIterator().GetItem();
HPS.KeyPath path_to_selection;
item.ShowPath(out path_to_selection);
// using the CADModel, we obtain a ComponentPath from the KeyPath
HPS.ComponentPath component_path = myCADModel.GetComponentPath(path_to_selection);
// we figure out at which level is appropriate to insert a transform, so that only the instance of the wheel I selected is affected
HPS.Component transform_target = HPS.Factory.DeInstanceComponent(component_path);
// we apply the transform
HPS.MatrixKit transform = new MatrixKit();
transform.Translate(5, 0, 0);
transform_target.SetTransform(transform);
myCanvas.Update();
}