Parasolid integration


The Visualize-Parasolid bridge supports a connection between Parasolid entities and their corresponding representation in the Visualize scene graph. This interface facilitates visualization of Parasolid models, as well as creation and editing of Parasolid entities. If you haven't done so already, you should read through the Programming Guide page on the component hierarchy, as the Parasolid interface is based on it.

All Parasolid-related classes are members of the HPS::Parasolid container class. Supported platforms are listed in the release notes compatibility table. Developers can choose to work with either C++ or C# (C# is Windows-only).

Convergent Modeling is available in the Visualize-Parasolid bridge, supporting both solid B-rep operations and faceted geometry operations in a single modelling component. It is available with Parasolid version 28.1 or higher.

NOTE: HOOPS Visualize automatically initializes Parasolid if it detects that the Parasolid integration is present. It will also shut down Parasolid at the end of the application, and restart it as needed. Your application should not initialize or shutdown Parasolid if it is using the Parasolid integration. If you need to use Parasolid after Visualize is finished, you need to restart the session.

Prerequisites

Steps for loading Parasolid models are delineated below:

Step 1: Set up Parasolid

In order to use the HPS::Parasolid functionality, you must download the Parasolid package from its developer and include it in your environment path. The supported version of Parasolid is noted in the release notes. The Parasolid runtime library file must be distributed with your application.

PlatformRequired file
Linuxlibpskernel.so
OS Xlibpskernel.dylib
Windowspskernel.dll
pskernel_net.dll also required for C# developers

Step 2: Include Parasolid header

To utilize the Parasolid importer, you need to include sprk_parasolid.h in your source.

Step 3: Set schema directory location

Many Parasolid files depend on a schema. If a schema is required but the importer cannot find the schema directory, the import will fail. Visualize will check the following locations, in order, for the schema directory:

  1. The schema directory set by your application (see code snippet below)
  2. The P_SCHEMA environment variable
  3. The ./schema directory

The schema directory is set on the HPS::World object. World objects are discussed in section 1.1.

world.SetParasolidSchemaDirectory("path/to/directory");
world.SetParasolidSchemaDirectory("path/to/directory");



Step 4: Link against Parasolid (optional)

If you are only planning to use the HPS::Parasolid classes, then you can skip this step. However, if you have a need to connect to the Parasolid API directly, you also need to set your compiler to link against the Parasolid library and include the Parasolid header files in your source.

Importing

Visualize's support for importing of Parasolid files is consistent with other supported file types. The main difference is the use of functions from the HPS::Parasolid container class. Like other file I/O operations, Parasolid models are loaded asynchronously, so be sure to call ImportNotifier::Wait before operating on your model.

HPS::Parasolid::ImportOptionsKit iok = Parasolid::ImportOptionsKit::GetDefault();
iok.SetFormat(HPS::Parasolid::Format::Text);
notifier.Wait(); // wait for this model to finish loading
iok.SetFormat(HPS.Parasolid.Format.Text);
HPS.Parasolid.ImportNotifier notifier = HPS.Parasolid.File.Import(filename, iok);
notifier.Wait(); // wait for this model to finish loading



After HPS::ImportNotifier::Wait returns, the model is fully loaded. Note that setting the file format is mandatory and Visualize will likely throw an exception if this field is set incorrectly. By convention, Parasolid text files will have a .X_T extension, whereas binary files have a .X_B extension.

Import options

Various import options are available when loading Parasolid models. These options enable you to set the file type, tessellation options, behavior directives, and whether user fields are imported. All options are set on the import options kit. Note that the tessellation fields require options kits of their own.

// setting up the facet tessellation kit
ftk.SetNormals(true);
ftk.SetFacetSize(1.0, 3.0, 10);
// setting up the line tessellation kit
ltk.SetEdges(true, true);
ltk.SetIgnoreCriteria(false);
// setting the tessellation kits on the import options kit
iok.SetCompoundBodyBehavior(Parasolid::CompoundBodyBehavior::Split);
iok.SetFormat(Parasolid::Format::Text);
// setting up the facet tessellation kit
ftk.SetNormals(true);
ftk.SetFacetSize(1.0, 3.0, 10);
// setting up the line tessellation kit
ltk.SetEdges(true, true);
ltk.SetIgnoreCriteria(false);
// setting the tessellation kits on the import options kit
HPS.Parasolid.ImportOptionsKit iok = Parasolid.ImportOptionsKit.GetDefault();
iok.SetCompoundBodyBehavior(HPS.Parasolid.CompoundBodyBehavior.Split);
iok.SetFacetTessellation(ftk);
iok.SetLineTessellation(ltk);
iok.SetFormat(HPS.Parasolid.Format.Text);



The options kits in the code snippet above take numerical values for their tessellation parameters. These values are expected to be in the model's units. While this gives you fine control over how the model is tessellated, it requires you to make some precalculations to determine the size of the model and what makes sense for values. Using arbitrary values could result in very long load times as Visualize tries to create precise tessellation.

For this reason, there is an alternative way to specify tessellation. The SetTessellationLevel function will accept an enum value ranging from "extra low" to "extra high", which instructs Visualize to automatically calculate an appropriate tessellation value based on the model's extents. When this method is used, any other tolerance option set on the facet kit gets ignored (these are the options set through SetChordTolerance, SetSurfacePlaneTolerance, SetFacetPlaneTolerance). This method is only available for facet tessellation.

ftk.SetTessellationLevel(HPS::Parasolid::TessellationLevel::Medium);
ftk.SetTessellationLevel(HPS.Parasolid.TessellationLevel.Medium);



Importing other file formats into a Parasolid session

If you are a HOOPS Exchange licensee, you may also import models from other file formats into an active Parasolid session using the HPS::ExchangeParasolid importer. This importer will load the geometry into Parasolid and use it to tessellate the model. It will also preserve PMI and capture information which Parasolid doesn't support natively. The importer creates HPS::Exchange::Component objects for the PMI and captures. Everything else will be translated to Parasolid entities behind the scenes, which will be represented as HPS::Parasolid::Component objects. You can reference both object types through the normal component interface. This includes accessing the underlying native data. For example, you can access Parasolid data directly through the Parasolid components and you can access HOOPS Exchange data (B-rep, PMI, etc.) directly through the Exchange components.

Loading the file in this way is done similarly to loading other file types:

HPS::Exchange::ImportOptionsKit iok = Exchange::ImportOptionsKit::GetDefault();
notifier.Wait(); // wait for this model to finish loading
// get the CAD model object
HPS::CADModel cad_model = notifier.GetCADModel();
// get Exchange components
HPS::Exchange::Component pmi_component(pmis[0]);
A3DEntity * exchange_pmi_entity = pmi_component.GetExchangeEntity();
// get Parasolid components
HPS::Parasolid::Component face_component(faces[0]);
PK_ENTITY_t parasolid_face_entity = face_component.GetParasolidEntity();
HPS.Exchange.ImportOptionsKit iok = Exchange.ImportOptionsKit.GetDefault();
HPS.Exchange.TranslationOptionsKit.GetDefault(),
notifier.Wait(); // wait for this model to finish loading
// get the CAD model object
HPS.Exchange.CADModel cad_model = notifier.GetCADModel();
// get Exchange components
HPS.Component[] pmis = cad_model.GetAllSubcomponents(HPS.Component.ComponentType.ExchangePMIMask);
HPS.Exchange.Component pmi_component = new HPS.Exchange.Component(pmis[0]);
IntPtr exchange_pmi_entity = pmi_component.GetExchangeEntity();
// get Parasolid components
HPS.Component[] faces = cad_model.GetAllSubcomponents(HPS.Component.ComponentType.ParasolidTopoFace);
HPS.Parasolid.Component face_component = new HPS.Parasolid.Component(faces[0]);
int parasolid_face_entity = face_component.GetParasolidEntity();



Getting a reference to subcomponents

The Parasolid importer uses the same component hierarchy structure used by other Visualize model importers. It is important to understand the component hierarchy before continuing. The HPS::CADModel object is the root of the component structure and is available from the import notifier. The subcomponents are then available from the CAD model object.

notifier.Wait(); // wait for this model to finish loading
// get the CAD model object
HPS::Parasolid::CADModel cadModel = notifier.GetCADModel();
// get the top-level assemblies
HPS::ComponentArray assemblies = cadModel.GetSubcomponents();
iok.SetFormat(HPS.Parasolid.Format.Text);
HPS.Parasolid.ImportNotifier notifier = HPS.Parasolid.File.Import(filename, iok);
notifier.Wait(); // wait for this model to finish loading
// get the CAD model object
HPS.Parasolid.CADModel cadModel = notifier.GetCADModel();
// get the top-level assemblies
HPS.Component[] assemblies = cadModel.GetSubcomponents();



Tessellating

When Visualize reads a Parasolid model into memory, the model is tessellated and the definition is retained in the component hierarchy structure. Because the definition is retained, Visualize is able to retessellate the model at a later time using different tessellation parameters and without rereading the file. To retessellate, simply set up new tessellation kits and call Tessellate on the target component:

ltk = Parasolid::LineTessellationKit::GetDefault();
ltk.SetChordTolerance(0, 0, 1.3);
component.Tessellate(ftk, ltk);
// the next update yields a retessellated model
myCanvas.Update();
ftk.SetFacetPlaneTolerance(7.3, 1.0).SetChordTolerance(5.0, 5.3, 1.0);
ltk = Parasolid.LineTessellationKit.GetDefault();
ltk.SetChordTolerance(0, 0, 1.3);
component.Tessellate(ftk, ltk);
// the next update yields a retessellated model
myCanvas.Update();



Retessellating a component will also retessellate all subcomponents. Note that Tessellate can only be called on either an assembly or body entity. If you need to retessellate the entire model, you can either reload the model or call HPS::CADModel::GetSubcomponents and retessellate each component individually.

IMPORTANT: If you make modifications to a model using the Parasolid API you must call Tessellate in order for Visualize to receive the updated model.

Attaching the Parasolid model to your scene graph

In order to attach the imported Parasolid model to the Visualize scene graph, you must use a view hierarchy. The HPS::CADModel provides a default view which you obtain in the following way:

HPS::Canvas myCanvas = HPS::Factory::CreateCanvas(myWindowKey);
// ...
// get a reference to the model view
// attach the view to the canvas
myCanvas.AttachViewAsLayout(view);
HPS.Canvas myCanvas = HPS.Factory.CreateCanvas(myWindowKey);
// ...
// get a reference to the model view
HPS.View view = notifier.GetCADModel().ActivateDefaultCapture();
// attach the view to the canvas
myCanvas.AttachViewAsLayout(view);


When calling HPS::CADModel::ActivateDefaultCapture, a FitWorld is automatically performed, which centralizes the model in the window.

Once you call HPS::Canvas::AttachViewAsLayout, the model becomes part of the main scene graph and will be rendered at the next update.

Handling metadata

Metadata is additional non-geometric information that is associated with a HPS::Parasolid::Component. Each piece of metadata is a name-value pair, and the values can be strings, integers, doubles, or booleans. Any HPS::Parasolid::Component can have metadata associated with it, although some types of metadata are only available on certain types of components. A list of metadata is as follows:

Metadata nameMetadata TypeDescription
"Name"StringMetadataThe name of the Parasolid entity associated with the component. If the entity does not have a name, a default name will be generated. The default name is in the form of <entity_type>_<entity_tag>.
"Identifier"IntegerMetadataReturns whether the Parasolid entity associated with the component is a void region. This is only valid if the component is of type ParasolidTopoRegion.
"IsRegionVoid"BooleanMetadataReturns the identifier of the Parasolid entity associated with the component.
"Filename"StringMetadataName of the file imported. This is only valid from the CADModel.
"FileFormat"StringMetadataFormat of the file imported. This is only valid from the CADModel.
"ImportTime"DoubleMetadataTime taken to import the Parasolid file into memory, in milliseconds. This is only valid from the CADModel.
"ParseTime"DoubleMetadataTime taken to parse the Parasolid information into a scene graph, in milliseconds. This is only valid from the CADModel.

While metadata with any name can be set in a Parasolid model, Visualize is only able to retrieve metadata with names that are in the table above. If you need to retrieve other metadata, you need to use the Parasolid API.

Metadata can be embedded with any HPS::Parasolid::Component. The following example demonstrates how to get metadata associated with a component:

Metadata metadata = cadModel.GetMetadata("Filename");
// "Filename" is always returned as a string, so we use a StringMetadata object
StringMetadata stringMetadata(metadata);
// getting the value of the "Filename" metadata
UTF8 filename_value = stringMetadata.GetValue();
HPS.Metadata metadata = cadModel.GetMetadata("Filename");
// "Filename" is always returned as a string, so we use a StringMetadata object
HPS.StringMetadata stringMetadata = new HPS.StringMetadata(metadata);
// getting the value of the "Filename" metadata
String filename_value = stringMetadata.GetValue();


Data mapping

As mentioned on the component hierarchy page, Visualize associates each Parasolid Component object with native Parasolid entities. You can retrieve the underlying Parasolid entity with a call to GetParasolidEntity. A ParasolidEntity is equal to a PK_ENTITY_t.

The code snippet below demonstrates how to get an entity's Parasolid ID from a Visualize key:

// get Visualize-Parasolid component interface object for corresponding Visualize key
HPS::Component myComponent = modelFile.GetComponentFromKey(hpsKey);
// 'parasolidEntity' == PK_ENTITY_t
ParasolidEntity parasolidEntity = myComponent.GetParasolidEntity();
// test if the object type is a Parasolid assembly
// [see Component reference manual page for other Parasolid types]
{
// do something with this object
}
// gets the Visualize keys associated with the Component
KeyArray keys = component.GetKeys();
// at this point, you can use the returned entity to directly query model information from the Parasolid API
// get Visualize-Parasolid component interface object for corresponding Visualize key
HPS.Component myComponent = modelFile.GetComponentFromKey(hpsKey);
// 'parasolidEntity' == PK_ENTITY_t
ParasolidEntity parasolidEntity = myComponent.GetParasolidEntity();
// test if the object type is a Parasolid assembly
// [see Component reference manual page for other Parasolid types]
if (component.GetComponentType() == HPS.Component.ComponentType.ParasolidAssembly)
{
// do something with this object
}
// gets the keys associated with the Component
KeyArray keys = component.GetKeys();
// at this point, you can use the returned entity to directly query model information from the Parasolid API

See the HPS::Component reference manual entry for a list of all the component enums.

Manipulating entities at runtime

Entity creation

While Parasolid models may sometimes be loaded from a file, it is of course common for modeling operations to create entities dynamically. If you have a need to start from scratch (an empty model), you need to create all entities beginning with the CAD model. The HPS::Parasolid::CADModel object is created using a factory method:


After you have the HPS::Parasolid::CADModel object, new Parasolid kernel entities would be created using the Parasolid API, then attached to the model post-creation. The following example demonstrates how you would add a solid block to a model's root entity at runtime, and then access the keys of the corresponding Visualize scene-graph entities which provide the visual representation:

PK_BODY_t solid_body = PK_ENTITY_null;
PK_BODY_create_solid_block(0.05, 0.05, 0.05, nullptr, &solid_body);
// add solid block to root entity
HPS::Parasolid::Component myNewComponent =
// check to make sure it was inserted correctly
std::cout << "if you get here, something went wrong";
// get the underlying Visualize keys which represent this component
KeyArray componentKeys = myNewComponent.GetKeys();
PK.BODY_t solid_body = PK.ENTITY_t.@null;
PK.BODY.create_solid_block(0.05, 0.05, 0.05, null, &solid_body);
// add solid block to root entity
HPS.Component myNewComponent =
cadModel.AddEntity(solid_body, HPS.Parasolid.FacetTessellationKit.GetDefault(),
// check to make sure it was inserted correctly
if (myNewComponent.GetComponentType() != HPS.Component.ComponentType.ParasolidTopoBody)
{
// if you get here, something went wrong
}
// get the underlying Visualize keys which represent this component
Key[] componentKeys = myNewComponent.GetKeys();


The new solid block is ready to be rendered during the next update.

Entity modification

A typical flow for entity modification would begin with the user selecting on a Visualize scene-graph object. Given a Visualize key, you would obtain the HPS::Component object and the Parasolid entity ID as previously demonstrated. After modifying the entity using the Parasolid API, call HPS::Parasolid::Component::Tessellate to update the Visualize scene-graph representation.

Entity deletion

To delete a component, call HPS::Component::Delete. Deleting a component will also delete any subcomponents, along with all associated Visualize scene-graph segments and graphical primitives. The HPS::Component::Delete function will also delete the underlying Parasolid entity.

Exporting

Exporting files with the Visualize-Parasolid interface is possible if the associated HPS::Parasolid::CADModel was obtained through a Parasolid import. The export process is synchronous and follows a pattern similar to other file exporters.

The HPS::Parasolid::ExportOptionsKit has two options:

  • File format - you can choose between binary, neutral binary, or text
  • User data - this is a flag indicating whether or not user data should be included in the export
export_options.SetFormat(HPS::Parasolid::Format::Text).SetUserFields(true);
HPS::Parasolid::File::Export(cadModel, outfile, export_options);
export_options.SetFormat(HPS.Parasolid.Format.Text).SetUserFields(true);
HPS.Parasolid.File.Export(cadModel, outfile, export_options);


Warnings and exceptions

The importer will issue a warning or throw an exception if it detects a condition that doesn't make sense or cannot recover from. For example, if you specify a maximum value that is smaller than a minimum value, a warning is issued. Or, if you specify the file type to be text, but the imported file is actually a binary file, Visualize will throw an HPS::IOException. Your code should be prepared to handle these occurrences so that it can take steps to recover.