Introduction
If you want to make a 3D modeling application using HOOPS Visualize with Siemens Parasolid, we recommend you to use the latest interface: HPS, rather than the legacy one: 3DF.
However, if you are an expert in 3DF and want to integrate Parasolid into your existing 3DF application or migrate an existing 3D kernel to Parasolid, this article will be a good reference for getting started and checking feasibilities.
Although HOOPS-Parasolid integration module project can be found in <HV-3DF SDK>\Dev_Tools\hp_bridge
, there isn’t any integration sample in the latest SDK. (Parasolid Part Viewer is no longer provided after 3DF 24.00)
This is a step-by-step guide of how to integrate the hp_bridge to mfc_simple project.
1. SDK versions
This article is written using the following version of SDKs.
- HOOPS Visualize 3DF 27.20
- Parasolid 32.0
2. Prepare a project
Prepare a project
- Download HOOPS Visualize 3DF and Parasolid SDKs and unzip
- Locate valid
hoops_license.h
file under<HV-3DF SDK>\Dev_Tools\hoops_3dgs\source
- Make a copy of the
<HV-3DF SDK>\demo\mfc\mfc_simple
folder
i.e.) mfc_simple_Ps
- Start Visual Studio 2017 and open
mfc_simple_v141.vcxproj
- Close the Visual Studio and save a solution file under the mfc folder
i.e.) mfc_simple_Ps_v141.sln
- Create
mfc_simple_Ps_VS2017.bat
file and implement the following commands to launch the project with environment variables (Change the Parasolid SDK path according to your environment)
SET PARASOLID_INSTALL_DIR=C:\SDK\Parasolid\v32.0\kernel
SET P_SCHEMA=C:\SDK\Parasolid\v32.0\kernel\base\schema
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe" mfc_simple_Ps_v141.sln
- Save and launch the solution using the bat file
Edit project properties
- Open the project properties
- Add the following additional include directories
..\..\..\Dev_Tools\hp_bridge\source
$(PARASOLID_INSTALL_DIR)\base
- Add the following additional library directories
..\..\..\Dev_Tools\hp_bridge\lib\nt_x64_v141
$(PARASOLID_INSTALL_DIR)\base
- Add the following additional dependencies
Debug:
hoops_utilsstatd_md.lib
hp_bridgestatd_md.lib
pskernel_archive.lib
Release:
hoops_utilsstat_md.lib
hp_bridgestat_md.lib
pskernel_archive.lib
- Build and start the application
- Verify whether the application is started properly
3. Initialize and shutdown Parasolid
Implement Parasolid initialization
To start Parasolid and the HOOPS/Parasolid Integration module, call HP_Init
in an application initialization routine. This function initializes the Parasolid kernel and registers the HOOPS-specific implementation of the Parasolid. All geometry rendered via Parasolid’s PK_TOPOL_render_XXX
routines will be mapped to corresponding segments and geometry in the HOOPS graphics database.
- Open
SampleH.cpp
- Add the following includes
#include "parasolid_kernel.h"
#include "kernel_interface.h"
#include "hp_bridge.h"
- Add the following code in the
InitInstance
function to initialize Parasolid
BOOL CSampleHApp::InitInstance()
{
...
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
bool has_schema = false;
wchar_t *schema_path;
schema_path = _wgetenv(L"P_SCHEMA");
if (schema_path)
{
HP_Init(schema_path, PK_LOGICAL_false, PK_LOGICAL_true);
has_schema = true;
}
if (!has_schema)
{
AfxMessageBox(_T("Could not determine location of your Schema Files.\ndefine P_SCHEMA environment variable."), MB_ICONSTOP);
// we still wanna initialize the bridge, if not file load,
// user can atleast do geom creation and stuff - Rajesh B (30-May-03)
HP_Init("", PK_LOGICAL_false, PK_LOGICAL_true);
}
Note that the HP_Init
function requires a Schema path and Boolean value. The Schema path instructs Parasolid where to look for some utility files necessary to read in .x_t files. The schema files are located in the /parasolid/schema directory.
The Boolean should be set to false, unless you are working with Tech Soft 3D to test a new automatic update feature that keeps HOOPS and Parasolid continuously in synchronization.
Implement Parasolid shutdown
To shutdown Parasolid as well as the HOOPS/Parasolid module, call HP_Close
. This should be called in an application cleanup routine, when Parasolid is no longer needed.
- Add the following code in the
ExitInstance
function to shutdown Parasolid
int CSampleHApp::ExitInstance()
{
...
HP_Close();
return CHoopsApp::ExitInstance();
}
Implement Parasolid partition functionality
To use a Parasolid session with multiple documents, it is necessary to independent sets of related parts in each document using Parasolid Partition.
- Open
HSampleHModel.h
- Add includes and
m_partition
member variable andGetPartition
function
#include "stdafx.h"
#include "parasolid_kernel.h"
#include "kernel_interface.h"
#include "hp_bridge.h"
...
private:
PK_PARTITION_t m_partition;
public:
...
PK_PARTITION_t GetPartition() { return m_partition; };
- Open
HSampleHModel.cpp
- Add the following code which creates a new partition in the constructor
HSampleHModel::HSampleHModel()
{
PK_ERROR_code_t PK_result = PK_PARTITION_create_empty(&m_partition);
}
- Build and start the application
- Verify whether the application is started properly
If you track source code in debug mode, you can see a Parasolid session is started in hp_bridge
Parasolid Partitions are provided to help the application organize entities in the modeling session into sets of related parts, and to save these parts as a single item.
4. Implement Parasolid file open function
Add a function that imports Parasolid file and visualizes it.
Implement Parasolid import function
To read a Parasolid file, call HP_Read_Xmt_File
. This parses the specified Parasolid file, populates the Parasolid modeling kernel with its contents, and then maps the model to a corresponding HOOPS segment tree hierarchy that includes all geometry and attributes.
- Open
HSampleHModel.h
- Add
Read
function declaration
public:
...
HFileInputResult Read(LPCTSTR FileName);
- Open
HSampleHModel.cpp
- Implement
Reat
functions
HFileInputResult HSampleHModel::Read(LPCTSTR FileName)
{
// This process is going to take sometime, convey that to the user
CWaitCursor show_hourglass_cursor_through_this_function;
HFileInputResult success = InputOK;
wchar_t extension[64];
wchar_t const * ext = wcsrchr(FileName, L'.');
wchar_t const * first_ext = wcschr(FileName, L'.');
if (!ext)
return InputBadFileName;
++ext; //move one past the dot;
++first_ext; //move one past the dot;
if (ext)
swprintf(extension, 64, L"%ls", ext);
if (wcsieq(extension, L"xmt_txt") || wcsieq(extension, L"x_t") || wcsieq(extension, L"x_b") || wcsieq(extension, L"xmt_bin"))
{
HP_Set_Hash_Level(0);
HC_Open_Segment_By_Key(m_ModelKey);
HC_Set_Heuristics("polygon handedness = left");
PK_PART_receive_o_t options;
PK_ERROR_code_t PK_result;
PK_PART_receive_o_m(options);
if (wcsieq(extension, L"x_b") || wcsieq(extension, L"xmt_bin"))
options.transmit_format = PK_transmit_format_neutral_c;
else
options.transmit_format = PK_transmit_format_text_c;
PK_result = HP_Read_Xmt_File(FileName, GetPartition(), 0, 0, &options, true, "custom"); // read an XMT file
if (PK_result == PK_ERROR_schema_access_error)
{
TCHAR str[MVO_BUFFER_SIZE];
_stprintf(str, _T("Could not find schema files at specified path."));
AfxMessageBox(str, MB_ICONINFORMATION | MB_OK);
}
else if (PK_result != PK_ERROR_no_errors)
AfxMessageBox(_T("Failed to read Parasolid file. HP_Read_Xmt_File returned an error"), MB_ICONINFORMATION | MB_OK);
HC_Close_Segment();
}
return success;
}
Create file open dialog including Parasolid Files
- Open
SampleH.h
- Add a function declaration of file open
//{{AFX_MSG(CSampleHApp)
afx_msg void OnAppAbout();
afx_msg void OnFileOpen();
- Open
SampleH.cpp
4.ImplementOnFileOpen
function
void CSampleHApp::OnFileOpen()
{
CString filter = _T("Parasolid Files (*.x_t, *.x_b, *.xmt_txt, *.xmt_bin)|*.x_t;*.x_b;*.xmt_txt;*.xmt_bin|HOOPS Stream Files (*.hsf)|*.hsf|All Files (*.*)|*.*||");
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, filter, NULL);
if (dlg.DoModal() == IDOK)
{
CString pathname;
pathname = dlg.GetPathName();
OpenDocumentFile(pathname);
}
}
- Add a message map to connect the file open command to the function
BEGIN_MESSAGE_MAP(CSampleHApp, CHoopsApp)
//{{AFX_MSG_MAP(CSampleHApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
Associate a command to the read function
- Open
SampleHDoc.cpp
- Add the following code to process Parasolid files
if(!_tcscmp(extension, _T("hsf")))
{
...
}
else if (!_tcscmp(extension, _T("xmt_txt")) || !_tcscmp(extension, _T("x_t")) || !_tcscmp(extension, _T("x_b")) || !_tcscmp(extension, _T("xmt_bin")))
{
HFileInputResult result = ((HSampleHModel*)m_pHoopsModel)->Read(lpszPathName);
}
- Build and start the application
- Verify whether Parasolid (x_t) file can be opened
Implement a create solid body function
Verify a solid model creating workflow using create block function as an example.
Implement Parasolid create block function
When Parasolid entities are being dynamically created, the HP_Render_Entity
function needs to be called.
- Open
HSampleHModel.h
- Add
CreateBlock
declaration andm_dUnit
variable
public:
...
void CreateBlock(const double in_dX, const double in_dY, const double in_dZ, const double in_dOX, const double in_dOY, const double in_dOZ);
private:
const double m_dUnit = 1000.0;
- Open
HSampleModel.cpp
- Implement
CreateBlock
function
void HSampleHModel::CreateBlock(const double in_dX, const double in_dY, const double in_dZ, const double in_dOX, const double in_dOY, const double in_dOZ)
{
double dX = in_dX / m_dUnit;
double dY = in_dY / m_dUnit;
double dZ = in_dZ / m_dUnit;
double dOX = in_dOX / m_dUnit;
double dOY = in_dOY / m_dUnit;
double dOZ = in_dOZ / m_dUnit;
PK_PARTITION_set_current(m_partition);
PK_AXIS2_sf_s basis_set;
basis_set.location.coord[0] = dOX;
basis_set.location.coord[1] = dOY;
basis_set.location.coord[2] = dOZ;
basis_set.axis.coord[0] = 0.;
basis_set.axis.coord[1] = 0.;
basis_set.axis.coord[2] = 1.;
basis_set.ref_direction.coord[0] = 1.;
basis_set.ref_direction.coord[1] = 0.;
basis_set.ref_direction.coord[2] = 0.;
PK_BODY_t solid_body = PK_ENTITY_null;
PK_ERROR_code_t PK_result = PK_BODY_create_solid_block(dX, dY, dZ, &basis_set, &solid_body);
HC_Open_Segment_By_Key(m_ModelKey);
HP_Render_Entity(solid_body);
HC_Close_Segment();
}
Since Parasolid internal unit is meter, it is necessary to set length values in meter.
Add Create Block dialog box
- Open Resource View of Visual Studio and right click the
Dialog
group and selectInsert Dialog
- Set
IDD_CREATTE_BLOCK_DIALOG
as ID of the dialog properties - Layout controls and set IDs as below
- Right-click on the background of the dialog box and select
Add Class...
- Set
CreateBlockDlg
as class name and clickOK
- Add include in
CreateBlockDlg.h
#pragma once
#include "Resource.h"
- Open
CreateBlockDlg.cpp
and edit includes
#include "stdafx.h"
#include "CreateBlockDlg.h"
#include "afxdialogex.h"
Add variables of controls
-
Open
IDD_CREATE_BLOCK_DIALOG
using the Resource View -
Right-click the edit control of XL and select
Add Variable...
-
Select
Value
from Category, setm_dEditXL
as Name, setdouble
as Variable type, and clickFinish
-
Add variables of other edit controls as well
-
Open
CreateBlockDlg.h
and edit the constructor’s declaration
CreateBlockDlg(const double in_XL, const double in_YL, const double in_ZL, CWnd* pParent = nullptr);
- Open
CreateBlockDlg.cpp
and edit the constructor’s implementation
CreateBlockDlg::CreateBlockDlg(const double in_XL, const double in_YL, const double in_ZL, CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_CREATTE_BLOCK_DIALOG, pParent)
, m_dEditXL(in_XL)
, m_dEditYL(in_YL)
, m_dEditZL(in_ZL)
, m_dEditOX(0)
...
Add Parasolid - Create a Block menu
- Open Resource View
- Open
Menu
-IDR_HOOPSTYPE
- Add
Parasolid
menu - Add
Create Block...
as a sub menu
Associate menu to create block function with a dialog box
- Right-click the
Create Block...
menu and selectAdd Event Handler...
- Select
CSampleHView
from the Class List and clickOK
- Implement code to create a block with the dialog box
#include "CreateBlockDlg.h"
...
void CSampleHView::OnParasolidCreateblock()
{
CreateBlockDlg *pDlg = new CreateBlockDlg(100, 100, 100, this);
if (pDlg->DoModal() == IDOK)
{
double dXL = pDlg->m_dEditXL;
double dYL = pDlg->m_dEditYL;
double dZL = pDlg->m_dEditZL;
double dOX = pDlg->m_dEditOX;
double dOY = pDlg->m_dEditOY;
double dOZ = pDlg->m_dEditOZ;
CSampleHDoc * pDoc = (CSampleHDoc *)GetDocument();
((HSampleHModel*)(pDoc->m_pHoopsModel))->CreateBlock(dXL, dYL, dZL, dOX, dOY, dOZ);
m_pHView->Update();
}
}
- Build and start the application
- Verify whether blocks can be created properly
6. Implement an edit function with a custom operator
Verify a model editing workflow using the blend-R function as an example.
Implement Parasolid blend R function
When Parasolid entities are edited via the application’s user interface, the HP_Update_Entity
function needs to be called.
- Open
HSampleHModel.h
- Add
BlendEdgeR
function declaration
public:
...
void BlendEdgeR(PK_EDGE_t edge, double blendR);
- Open
HSampleModel.cpp
- Implement
BlandEdgeR
function
void HSampleHModel::BlendEdgeR(PK_EDGE_t edge, double blendR)
{
PK_PARTITION_set_current(m_partition);
double dR = blendR / m_dUnit;
int n_faces = 0;
PK_FACE_t* faces = NULL;
PK_ERROR_code_t error_code;
error_code = PK_EDGE_ask_faces(edge, &n_faces, &faces);
PK_BODY_t body = NULL;
error_code = PK_FACE_ask_body(faces[0], &body);
PK_EDGE_t edges[] = { edge };
PK_EDGE_set_blend_constant_o_t options;
PK_EDGE_set_blend_constant_o_m(options);
options.properties.propagate = PK_blend_propagate_yes_c;
options.properties.ov_cliff_end = PK_blend_ov_cliff_end_yes_c;
int n_blend_edges = 0;
PK_EDGE_t* blend_edges = NULL;
error_code = PK_EDGE_set_blend_constant(1, edges, dR, &options, &n_blend_edges, &blend_edges);
PK_BODY_t partr = PK_ENTITY_null;
PK_EDGE_ask_body(blend_edges[0], &partr);
PK_BODY_fix_blends_o_t optionsFix;
PK_BODY_fix_blends_o_m(optionsFix);
int n_blends = 0;
PK_FACE_t* blends = 0;
PK_FACE_array_t* unders = 0;
int* topols = 0;
PK_blend_fault_t fault;
PK_EDGE_t fault_edge = PK_ENTITY_null;
PK_ENTITY_t fault_topol = PK_ENTITY_null;
// perform the Blend operation
error_code = PK_BODY_fix_blends(partr, &optionsFix, &n_blends, &blends, &unders, &topols, &fault, &fault_edge, &fault_topol);
if (error_code != 0)
{
wchar_t error_message[256];
_swprintf(error_message, _T("failed during Blend operation \n Error Code : %d"), error_code);
MessageBox(NULL, error_message, 0, MB_OK);
}
PK_MEMORY_free(faces);
PK_MEMORY_free(blend_edges);
PK_MEMORY_free(blends);
PK_MEMORY_free(unders);
HP_Update_Entity(body);
}
Add Brend-R dialog box
Create a dialog box to specify the blend R value.
- Right-click the
Dialog
group of Resource View and selectInsert Dialog
- Set
IDD_BLEND_R_DIALOG
as ID - Layout controls and set ID
- Right-click on the background of the dialog box and select
Add Class...
- Set
BlendRDlg
as the class name and clickOK
- Add include in
BlendRDlg.h
#pragma once
#include "Resource.h"
- Open
BlendRDlg.cpp
and edit includes
#include "stdafx.h"
#include "CreateBlockDlg.h"
#include "afxdialogex.h"
Add variables of controls
- Open
IDD_BLEND_R_DIALOG
using the Resource View - Right-click the edit control of R and select
Add Variable...
- Select
Value
from Category, setm_dBlendR
as Name, setdouble
as Variable type and clickFinish
- Open
BlendRDlg.h
and edit constructor’s declaration
BlendRDlg(const double in_R, CWnd* pParent = nullptr);
- Open
BlendRDlg.cpp
and edit constructor’s implementation
BlendRDlg::BlendRDlg(const double in_R, CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_BLEND_R_DIALOG, pParent)
, m_dBlendR(in_R)
Create a custom operator
Create a custom operator to specify the target edge. This operator can commonly used by commands that are invoked by clicking an entity such as delete body.
- Select
Project
-Add Class...
- Set
EntityOneClickOperator
as Class name,HOpSelectApeture
as Base class and clickOK
- Implement
EntityOneClickOperator.h
#pragma once
#include "HOpSelectAperture.h"
#include "HSampleHModel.h"
class HBaseOperator;
class EntityOneClickOperator :
public HOpSelectAperture
{
public:
EntityOneClickOperator(HBaseView* view, const char* entityType, const char* processType, int DoRepeat = 0, int DoCapture = 1);
~EntityOneClickOperator();
const char * GetName();
virtual int OnLButtonDown(HEventInfo &event);
private:
const char* m_pCEntityType;
const char* m_pCProcessType;
void normalize_vector(double* vector);
};
- Open
EntityOneClickOperator.cpp
and implement
#include "EntityOneClickOperator.h"
#include "HBaseView.h"
#include "vlist.h"
#include "BlendRDlg.h"
#include "HSelectionSet.h"
#include "HEventManager.h"
EntityOneClickOperator::EntityOneClickOperator(HBaseView* view, const char* entityType, const char* processType, int DoRepeat, int DoCapture)
: HOpSelectAperture(view, DoRepeat, DoCapture)
, m_pCEntityType(entityType)
, m_pCProcessType(processType)
{
if (!strcmp(m_pCEntityType, "EDGE"))
{
GetView()->SetDynamicHighlighting(false);
GetView()->SetViewSelectionLevel(HViewSelectionLevel::HSelectionLevelEntity);
HSelectionSet* selection = GetView()->GetSelection();
selection->SetSelectionLevel(HSelectLevel::HSelectEntity);
}
}
EntityOneClickOperator::~EntityOneClickOperator()
{
GetView()->SetDynamicHighlighting(false);
HSelectionSet* selection = GetView()->GetSelection();
selection->Init();
}
// normalize double precision vector in place
void EntityOneClickOperator::normalize_vector(double* vector)
{
double length;
length = sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
vector[0] /= length;
vector[1] /= length;
vector[2] /= length;
}
const char * EntityOneClickOperator::GetName()
{
return m_pCProcessType;
}
int EntityOneClickOperator::OnLButtonDown(HEventInfo &event)
{
HPoint new_pos;
int res = 0;
HSelectionSet* selection = GetView()->GetSelection();
new_pos = event.GetMouseWindowPos();
HC_Open_Segment_By_Key(GetView()->GetViewKey());
res = HC_Compute_Selection(".",
(selection->GetSubwindowPenetration() ? "" : "./scene/overwrite"),
"v, selection bias = lines, related selection limit = -1, selection sorting, internal selection limit = 0", new_pos.x, new_pos.y);
HC_Close_Segment();
if (0 < res) {
if (!strcmp(m_pCProcessType, "BLEND"))
{
HC_KEY key = INVALID_KEY;
HC_Show_Selection_Original_Key(&key);
PK_ENTITY_t entity = HP_Compute_TagID(key, PK_CLASS_entity);
PK_CLASS_t ent_class;
PK_ENTITY_ask_class(entity, &ent_class);
if (PK_CLASS_edge == ent_class)
{
HandleSelection(event);
GetView()->Update(); // update the scene to reflect the new highlight attributes
BlendRDlg *pDlg = new BlendRDlg(10.0);
if (pDlg->DoModal() == IDOK)
{
double blendR = pDlg->m_dBlendR;
((HSampleHModel*)GetView()->GetModel())->BlendEdgeR(entity, blendR);
GetView()->Update();
}
}
}
}
return (HOP_OK);
}
It is possible to get Parasolid entity tag ID from selected HC_KEY using the HP_Compute_TagID API
.
Add Parasolid - Blend-R menu and associate to the operator
- Open
Menu
-IDR_HOOPSTYPE
of Resource View - Add
Blend-R
menu as sub-menu ofParasolid
- Right-click the
Blend-R
menu and selectAdd Event Handler...
- Select
CSampleHView
from the Class List and click OK - Implement code to enable
EntityOneClickOperator
#include "EntityOneClickOperator.h"
...
void CSampleHView::OnParasolidBlend()
{
LocalSetOperator(new EntityOneClickOperator(m_pHView, "EDGE", "BLEND"));
}
- Add code in
LocalSetOperator
function, so the edge lines appear while the Blend-R command
void CSampleHView::LocalSetOperator(HBaseOperator * NewOperator)
{
const char* name = NewOperator->GetName();
HC_Open_Segment_By_Key(m_pHView->GetSceneKey());
if (!strcmp(name, "BLEND"))
HC_Set_Visibility("lines = on");
else
HC_Set_Visibility("lines = off");
HC_Close_Segment();
m_pHView->Update();
...
- Build and start the application
- Create a block and verify whether blend-R can be inserted
7. Implement a delete body function
Verify a model deleting workflow.
Implement Parasolid delete entity function
When a Parasolid entity is deleted, it is necessary to call HP_Delete_Entity_Geometry
function to delete the HOOPS geometry associated with a Parasolid entity.
- Open
HSampleHModel.h
- Add
DeleteEntity
function declaration
public:
...
void DeleteEntity(PK_ENTITY_t entity);`
- Open
HSampleModel.cpp
- Implement
DeleteEntity
function
void HSampleHModel::DeleteEntity(PK_ENTITY_t entity)
{
HP_Delete_Entity_Geometry(1, &entity);
PK_ENTITY_delete(1, &entity);
}
Edit operator
- Open
EntityOneClickOperator.cpp
- Add code to call the delete entity
EntityOneClickOperator::EntityOneClickOperator(HBaseView* view, const char* entityType, const char* processType, int DoRepeat, int DoCapture)
: HOpSelectAperture(view, DoRepeat, DoCapture)
, m_pCEntityType(entityType)
, m_pCProcessType(processType)
{
if (!strcmp(m_pCEntityType, "EDGE"))
{
...
}
else if (!strcmp(m_pCEntityType, "BODY"))
{
GetView()->SetDynamicHighlighting(true);
GetView()->SetViewSelectionLevel(HViewSelectionLevel::HSelectionLevelSegment);
HSelectionSet *highlightSelectionSet = GetView()->GetHighlightSelection();
highlightSelectionSet->SetSelectionLevel(HSelectLevel::HSelectSegment);
}
}
...
int EntityOneClickOperator::OnLButtonDown(HEventInfo &event)
{
...
if (0 < res) {
if (!strcmp(m_pCProcessType, "BLEND"))
{
...
}
else if (!strcmp(m_pCProcessType, "DELETE_BODY"))
{
PK_ENTITY_t* entities;
int num_entities;
HP_Compute_Selected_Entity_List(&entities, &num_entities);
if (0 < num_entities)
{
PK_BODY_t body = entities[0];
((HSampleHModel*)GetView()->GetModel())->DeleteEntity(body);
GetView()->Update();
}
}
}
HP_Compute_Selected_Entity_List
returns Parasolid entity Tag IDs of current selection list.
Add Parasolid - Delete Body menu and associate to the operator
- Open
Menu
-IDR_HOOPSTYPE
of Resource View - Add the
Delete Body
menu as sub-menu ofParasolid
- Right-click the
Delete Body
menu and selectAdd Event Handler...
- Select
CSampleHView
from the Class List and clickOK
- Implement code to enable
EntityOneClickOperator
void CSampleHView::OnParasolidDeletebody()
{
LocalSetOperator(new EntityOneClickOperator(m_pHView, "BODY", "DELETE_BODY"));
}
- Build and start the application
- Create a block and verify whether the body can be removed
8. Implement Boolean function
Let’s try to make boolean - unite, subtract, and intersect functions.
Implement Parasolid boolean function
HOOPS geometries associated target and tool bodies should be deleted using HP_Delete_Entity_Geometry
and then updating target body using HP_Render_Entities
.
- Open
HSampleHModel.h
- Add
Boolean
function declaration
public:
...
bool Boolean(PK_boolean_function_t operation, PK_BODY_t target, int number_of_tools, PK_BODY_t *tools);
- Open
HSampleModel.cpp
- Implement
Boolean
function
bool HSampleHModel::Boolean(PK_boolean_function_t operation, PK_BODY_t target, int number_of_tools, PK_BODY_t *tools)
{
PK_ERROR_code_t error_code;
PK_BODY_boolean_o_t options;
PK_TOPOL_track_r_t tracking;
PK_boolean_r_t results;
PK_PARTITION_t partition;
HP_Delete_Entity_Geometry(1, &target);
HP_Delete_Entity_Geometry(number_of_tools, tools);
//assert(target);
//assert(number_of_tools > 0);
PK_BODY_boolean_o_m(options);
options.function = operation;
//options.target_material_side = PK_boolean_material_outside_c;
PK_ENTITY_ask_partition(target, &partition);
for (int i = 0; i < number_of_tools; i++)
PK_BODY_change_partition(tools[i], partition);
// perform the Boolean operation
error_code = PK_BODY_boolean_2(target, number_of_tools, tools, &options, &tracking, &results);
int n_attribs = 0;
PK_ATTRIB_t* attribs = NULL;
PK_PART_ask_all_attribs(target, 0, &n_attribs, &attribs);
if (error_code != 0)
{
wchar_t error_message[256];
_swprintf(error_message, _T("failed during Boolean operation \n Error Code : %d"), error_code);
MessageBox(NULL, error_message, 0, MB_OK);
return 1;
}
// render bodies
HC_Open_Segment_By_Key(m_ModelKey);
HP_Render_Entities(results.n_bodies, results.bodies);
HC_Close_Segment();
return 0;
}
Create a custom operator
- Locate
PsBooleanOperator.
andPsBooleanOperator.cpp
in your project folder
PsBooleanOperator.zip (2.0 KB) - Select
Project
-Add Existing Items...
- Select
PsBooleanOperator.
andPsBooleanOperator.cpp
files
Add Parasolid - Boolean menu
- Open
Menu
-IDR_HOOPSTYPE
of Resource View - Add
Boolean
menu as sub-menu ofParasolid
- Add
Unite
,Subtract
andIntersect
as sub-menus ofBoolean
Associate a menu to the operator
- Right-click the
Unite
menu and selectAdd Event Handler...
- Select
CSampleHView
from the Class List and clickOK
- Add event handlers of
Subtract
andIntersect
menus as well - Implement code to enable
PsBooleanOperator
#include "PsBooleanOperator.h"
...
void CSampleHView::OnBooleanUnite()
{
LocalSetOperator(new PsBooleanOperator(m_pHView, "UNITE"));
}
void CSampleHView::OnBooleanSubtrac()
{
LocalSetOperator(new PsBooleanOperator(m_pHView, "SUBTRACT"));
}
void CSampleHView::OnBooleanInersect()
{
LocalSetOperator(new PsBooleanOperator(m_pHView, "INTERSECT"));
}
- Build and start the application
- Create blocks with offset and verify whether boolean can be worked
9. Implement Parasolid file saving function
Implement Parasolid file save function
The Parasolid transmit function is encapsulated by HP_Write_Xmt_File
function.
- Open
HSampleHModel.h
- Add
Write
function declaration
public:
...
HFileOutputResult Write(const wchar_t * FileName);
- Open
HSampleModel.cpp
- Implement
Write
function
HFileOutputResult HSampleHModel::Write(const wchar_t * FileName)
{
HFileInputResult success = OutputOK;
int n_bodies;
PK_BODY_t *bodies;
PK_PART_transmit_o_t options;
PK_ERROR_code_t PK_result;
PK_PART_transmit_o_m(options);
options.transmit_format = PK_transmit_format_text_c;
PK_PARTITION_ask_bodies(m_partition, &n_bodies, &bodies);
PK_ASSEMBLY_t *assemblies;
int n_assemblies;
PK_PARTITION_ask_assemblies(m_partition, &n_assemblies, &assemblies);
PK_PART_t *parts = new PK_PART_t[n_assemblies + n_bodies];
int n_parts = 0;
int i;
for (i = 0; i < n_bodies; i++)
{
int numref;
PK_PART_ask_ref_instances(bodies[i], &numref, 0);
if (!numref)
parts[n_parts++] = bodies[i];
}
for (i = 0; i < n_assemblies; i++)
{
int numref;
PK_PART_ask_ref_instances(assemblies[i], &numref, 0);
if (!numref)
parts[n_parts++] = assemblies[i];
}
PK_PARTITION_set_current(m_partition);
PK_result = HP_Write_Xmt_File((FileName), n_parts, parts, &options); // write an XMT file
if (PK_result < 0) success = OutputFail;
if (n_bodies > 0)
PK_MEMORY_free(bodies);
if (n_assemblies > 0)
PK_MEMORY_free(assemblies);
delete parts;
return success;
}
Edit file save as function
- Open
SampleHView.cpp
- Edit
OnFileSaveAs
function
void CSampleHView::OnFileSaveAs()
{
CString filter = _T("Parasolid Files (*.x_t)|*.x_t|HOOPS Stream File (*.hsf)|*.hsf|HOOPS Metafile (*.hmf)|*.hmf|Postscript File (*.ps)|*.ps|HPGL/2 Plot File (*.hp)|*.hp|TIFF Image File (*.tif)|*.tif||");
...
if (!_tcseq(pathname, _T("")))
{
if( _tcseq(extension, _T("hsf")) )
{
...
}
else if (_tcseq(extension, _T("x_t")))
{
HFileInputResult result = ((HSampleHModel*)(pDoc->m_pHoopsModel))->Write(pathname);
}
- Build and start the application
- Verify whether the created body can be saved
Source code
Download sample projects from the following Git repository:
Parasolid samples
If you want to see more Parasolid source code, please download Parasolid Jumpstart kit
from our Dev Zone.
When you install it, you will find sample application project in Source
folder of
C:\Program Files (x86)\Parasolid\Parasolid Jumpstart Kit\example_applications\C++
Please refer the Using the Example Application.pdf
and build the application. (Make sure to do Rebuild after chusing a code example)
You can try various Parasolid functions and refer the source code int it.
You will be able to port your favorite sample code to the mfc_simple project as well as the above steps.