DATAKIT SDK  V2026.4
WriteParasolid.cpp File Reference

Functions

Dtk_string PswGetLastOutputFile ()
 
const Dtk_tab< char > & PswGetLastStream ()
 
static Dtk_ID PswGetOrWritePrototype (Dtk_ComponentPtr inPrototype)
 
static void PswWriteComponent (Dtk_ComponentPtr inComponent, Dtk_ID inParentAssemblyId)
 
void PswWriteDocument (Dtk_MainDocPtr inDocument)
 
Dtk_ErrorStatus PswWriteEnd ()
 
Dtk_ErrorStatus PswWriteInit (const Dtk_string &inInputFile, const Dtk_string &inOutputFolder)
 
Dtk_ErrorStatus PswWriteInitMemory ()
 
void PswWriteNode (Dtk_NodePtr inNode, Dtk_tab< Dtk_ID > &outIds)
 

Variables

static Dtk_string g_lastOutputFile
 
static Dtk_tab< char > g_lastStream
 
static map< Dtk_ID, Dtk_ID > g_prototypeCache
 

Function Documentation

◆ PswGetLastOutputFile()

Dtk_string PswGetLastOutputFile ( )
26 {
27  return g_lastOutputFile;
28 }

◆ PswGetLastStream()

const Dtk_tab<char>& PswGetLastStream ( )
33 {
34  return g_lastStream;
35 }

◆ PswGetOrWritePrototype()

static Dtk_ID PswGetOrWritePrototype ( Dtk_ComponentPtr  inPrototype)
static
122 {
123  if( inPrototype.IsNULL() )
124  return 0;
125 
126  Dtk_ID compId = inPrototype->GetID();
127 
128  // Return cached entity ID if already written.
129  auto it = g_prototypeCache.find( compId );
130  if( it != g_prototypeCache.end() )
131  return it->second;
132 
133  Dtk_API* api = Dtk_API::GetAPI();
134  Dtk_Size_t numChildren = inPrototype->GetNumChildren();
135  bool hasSubComponents = ( numChildren > 0 );
136 
137  // --- Handle sub-components (children are instances of sub-prototypes) ---
138  Dtk_ID assemblyId = 0;
139  if( hasSubComponents )
140  {
141  // Create a Parasolid sub-assembly to hold all sub-instances.
142  psw_CreateEmptyAssembly( assemblyId );
143 
144  for( Dtk_Size_t i = 0; i < numChildren; ++i )
145  PswWriteComponent( inPrototype->GetChild( i ), assemblyId );
146  }
147 
148  // --- Read and write the geometric content of this prototype ---
149  Dtk_NodePtr rootNode;
151 
152  if( inPrototype->IsAvailabilityFlaggedAs( Dtk_Component::ComponentMissing ) )
153  {
154  err = dtkErrorFileNotExist;
155  cout << "Warning: component file missing for '"
156  << inPrototype->Name().c_str() << "'" << endl;
157  }
158  else
159  {
160  err = api->ReadComponent( inPrototype, rootNode );
161  }
162 
163  Dtk_tab<Dtk_ID> bodyIds;
164  if( err == dtkNoError && rootNode.IsNotNULL() )
165  {
166  PswWriteNode( rootNode, bodyIds );
167  }
168  else if( err != dtkNoError && err != dtkErrorFileNotExist )
169  {
170  cout << "Warning: ReadComponent failed: " << dtkTypeError( err ).c_str() << endl;
171  }
172 
173  // Always close the component after ReadComponent (even on error).
174  if( err != dtkErrorFileNotExist )
175  api->EndComponent( inPrototype );
176 
177  // --- Build the resulting Parasolid entity ---
178  Dtk_ID entityId = 0;
179  Dtk_string name = inPrototype->Name();
180 
181  if( hasSubComponents )
182  {
183  // Add body instances to the prototype's sub-assembly (identity placement).
184  if( bodyIds.size() > 0 )
185  {
186  Dtk_transfoPtr identity = Dtk_transfo::Create();
187  for( Dtk_Size_t i = 0; i < bodyIds.size(); ++i )
188  {
189  Dtk_ID instId = 0;
190  psw_CreateInstance( assemblyId, bodyIds[ i ], identity, instId );
191  }
192  }
193  // Set the prototype name on the sub-assembly.
194  if( name.len() > 0 )
195  {
196  Dtk_InfoPtr info = Dtk_Info::Create();
197  info->SetName( name );
198  psw_CreateAttribut( assemblyId, info );
199  }
200  psw_LinkAttribut( assemblyId );
201  entityId = assemblyId;
202  }
203  else
204  {
205  if( bodyIds.size() == 1 )
206  {
207  // Single body: use it directly as the entity.
208  entityId = bodyIds[ 0 ];
209  if( name.len() > 0 )
210  {
211  Dtk_InfoPtr info = Dtk_Info::Create();
212  info->SetName( name );
213  psw_CreateAttribut( entityId, info );
214  }
215  }
216  else if( bodyIds.size() > 1 )
217  {
218  // Multiple bodies: wrap them in a sub-assembly.
219  psw_CreateEmptyAssembly( assemblyId );
220  Dtk_transfoPtr identity = Dtk_transfo::Create();
221  for( Dtk_Size_t i = 0; i < bodyIds.size(); ++i )
222  {
223  Dtk_ID instId = 0;
224  psw_CreateInstance( assemblyId, bodyIds[ i ], identity, instId );
225  }
226  if( name.len() > 0 )
227  {
228  Dtk_InfoPtr info = Dtk_Info::Create();
229  info->SetName( name );
230  psw_CreateAttribut( assemblyId, info );
231  }
232  psw_LinkAttribut( assemblyId );
233  entityId = assemblyId;
234  }
235  // If bodyIds is empty: component has no geometry (e.g. skeleton), entityId stays 0.
236  }
237 
238  // Cache the result.
239  if( entityId != 0 )
240  g_prototypeCache[ compId ] = entityId;
241 
242  return entityId;
243 }

◆ PswWriteComponent()

static void PswWriteComponent ( Dtk_ComponentPtr  inComponent,
Dtk_ID  inParentAssemblyId 
)
static
251 {
252  if( inComponent.IsNULL() )
253  return;
254 
255  Dtk_Component::ComponentTypeEnum type = inComponent->ComponentType();
256 
257  switch( type )
258  {
259  // Instance: a reference to a prototype with a placement matrix.
261  {
262  // The prototype is always child[0] of an instance.
263  Dtk_ComponentPtr prototype = inComponent->GetChild( 0 );
264 
265  Dtk_ID protoEntityId = PswGetOrWritePrototype( prototype );
266  if( protoEntityId == 0 )
267  break;
268 
269  // Build the placement matrix from the instance.
270  Dtk_transfoPtr matrix = Dtk_transfo::Create( inComponent->TransformationMatrix() );
271 
272  Dtk_ID instanceId = 0;
273  psw_CreateInstance( inParentAssemblyId, protoEntityId, matrix, instanceId );
274 
275  // Optionally set the instance name.
276  Dtk_string instanceName = inComponent->InstanceName();
277  if( instanceName.is_NULL() )
278  instanceName = inComponent->Name();
279  if( instanceName.len() > 0 )
280  {
281  Dtk_InfoPtr info = Dtk_Info::Create();
282  info->SetName( instanceName );
283  psw_CreateAttribut( instanceId, info );
284  }
285  break;
286  }
287 
288  // Prototype encountered directly (rare at top level): write and instantiate.
290  {
291 
292  Dtk_ID entityId = PswGetOrWritePrototype( inComponent );
293  if( entityId == 0 )
294  break;
295  Dtk_transfoPtr identity = Dtk_transfo::Create();
296  Dtk_ID instanceId = 0;
297  psw_CreateInstance( inParentAssemblyId, entityId, identity, instanceId );
298  break;
299  }
300 
301  // Catalog: multiple configurations; use the default one.
303  {
304  // Get default component index in the catalog
305  Dtk_Int32 defaultComponentIndex = inComponent->GetDefaultChildInCatalog();
306 
307  // Get activated component indices in the catalog
308  Dtk_tab<Dtk_Int32> activatedComponentIndices = inComponent->GetActivatedChildrenInCatalog();
309 
310  // Get number of activated components in the catalog
311  Dtk_Size_t numActivatedComponents = activatedComponentIndices.size();
312 
313  // Write activated components or default component
314  if( numActivatedComponents > 0 )
315  {
316  // Write all activated components
317  for( Dtk_Size_t i = 0; i < numActivatedComponents; i++ )
318  {
319  // Write the activated component
320  Dtk_ComponentPtr activatedComponent = inComponent->GetChild( activatedComponentIndices[ i ] );
321  PswWriteComponent( activatedComponent, inParentAssemblyId );
322  }
323  }
324  else
325  {
326  // Write the default component
327  Dtk_ComponentPtr defaultChildComponent = inComponent->GetChild( defaultComponentIndex );
328  PswWriteComponent( defaultChildComponent, inParentAssemblyId );
329  }
330  break;
331  }
332 
333  // Virtual: a grouping node with no geometry of its own.
335  {
336  Dtk_Size_t n = inComponent->GetNumChildren();
337  for( Dtk_Size_t i = 0; i < n; ++i )
338  PswWriteComponent( inComponent->GetChild( i ), inParentAssemblyId );
339  break;
340  }
341  }
342 }

◆ PswWriteDocument()

void PswWriteDocument ( Dtk_MainDocPtr  inDocument)
350 {
351  g_prototypeCache.clear();
352 
353  Dtk_ComponentPtr rootComponent = inDocument->RootComponent();
354  if( rootComponent.IsNULL() )
355  {
356  cout << "Warning: document has no root component." << endl;
357  return;
358  }
359 
360  // Always create a top-level Parasolid assembly to hold the entire document.
361  Dtk_ID rootAssemblyId = 0;
362  psw_CreateEmptyAssembly( rootAssemblyId );
363 
364  // Set the document/root name on the assembly.
365  Dtk_string docName = rootComponent->Name();
366  if( docName.len() > 0 )
367  {
368  Dtk_InfoPtr info = Dtk_Info::Create();
369  info->SetName( docName );
370  psw_CreateAttribut( rootAssemblyId, info );
371  }
372 
373  // Recursively traverse the component tree and fill the root assembly.
374  PswWriteComponent( rootComponent, rootAssemblyId );
375 
376  // Finalise the root assembly (must be called once all instances are added).
377  psw_LinkAttribut( rootAssemblyId );
378 
379  g_prototypeCache.clear();
380 }

◆ PswWriteEnd()

Dtk_ErrorStatus PswWriteEnd ( )
443 {
444  Dtk_tab<Dtk_ID> emptyIds; // Root assembly is implicit when the tab is empty.
445  Dtk_ErrorStatus err = psw_EndFile( emptyIds );
446  if( err != dtkNoError )
447  cout << "Warning: psw_EndFile failed: " << dtkTypeError( err ).c_str() << endl;
448  return err;
449 }

◆ PswWriteInit()

Dtk_ErrorStatus PswWriteInit ( const Dtk_string &  inInputFile,
const Dtk_string &  inOutputFolder 
)
389 {
390  g_prototypeCache.clear();
392 
393  Dtk_string outputFile;
394  if( inOutputFolder.len() > 0 )
395  outputFile = inOutputFolder + inInputFile.filename() + inInputFile.extension() + L"_psw.x_t";
396  else
397  outputFile = inInputFile + L"_psw.x_t";
398 
399  // Persist the output path so callers can retrieve it via PswGetLastOutputFile().
400  g_lastOutputFile = outputFile;
401 
402  const Dtk_bool muteMode = DTK_TRUE; // Suppress the psw internal log file.
403  Dtk_ErrorStatus err = psw_InitFile( outputFile, muteMode );
404 
405  if( err == dtkNoError )
406  cout << "Creating Parasolid file: " << outputFile.c_str() << endl;
407  else
408  cout << "Warning: psw_InitFile failed: " << dtkTypeError( err ).c_str() << endl;
409 
410  return err;
411 }

◆ PswWriteInitMemory()

Dtk_ErrorStatus PswWriteInitMemory ( )
420 {
421  g_prototypeCache.clear();
423  g_lastOutputFile = Dtk_string(); // no output file in memory mode
424 
425  const Dtk_bool muteMode = DTK_TRUE;
426  Dtk_ErrorStatus err = psw_InitFile( g_lastStream, muteMode );
427 
428  if( err == dtkNoError )
429  cout << "Parasolid writer: using in-memory stream (no .x_t file)." << endl;
430  else
431  cout << "Warning: psw_InitFile (memory) failed: " << dtkTypeError( err ).c_str() << endl;
432 
433  return err;
434 }

◆ PswWriteNode()

void PswWriteNode ( Dtk_NodePtr  inNode,
Dtk_tab< Dtk_ID > &  outIds 
)
43 {
44  if( inNode.IsNULL() )
45  return;
46 
47  int blanked = inNode->GetInfos()->GetBlankedStatus();
48  // Skip invisible nodes (blanked == 1); keep visible (0) and construction (2).
49  if( blanked == 1 )
50  {
51  // Invisible body nodes may still have visible children – recurse anyway.
52  Dtk_Size_t n = inNode->GetNumChildren();
53  for( Dtk_Size_t i = 0; i < n; ++i )
54  PswWriteNode( inNode->GetChild( i ), outIds );
55  return;
56  }
57 
58  Dtk_Node::FullType nodeType = inNode->GetNodeFullType();
59 
60  switch( nodeType.PrimaryType() )
61  {
62  case Dtk_Node::BodyType:
63  {
64  // Skip infinite geometry (datum planes, axes, …)
65  if( inNode->GetInfos()->GetInfiniteGeometryFlag() != 0 )
66  break;
67 
68 
69  // Write B-Rep body data directly when available and visible
70  Dtk_BodyPtr body = inNode->GetDtk_BodyPtr();
71 
72  // Write the body only if it is not blanked
73  if( body.IsNotNULL() && blanked == 0 )
74  {
75  // Write the body only if it has solids or surfaces
76  if( inNode->NodeHasSolids() || inNode->NodeHasSurfaces() )
77  WriteBodyForParasolid( body, outIds );
78  else //better to handle on your own the wire or point body (Parasolid modeler is not intend to handle such body)
79  cout << "Warning: skipping body node '" << inNode->Name().c_str() << "' because it has no solids or surfaces." << endl;
80  }
81  break;
82  }
83 
84  case Dtk_Node::MeshType:
85  {
86  // Write faceted (mesh) data directly when no B-Rep is available and visible
87  Dtk_MeshPtr mesh = inNode->GetDtk_MeshPtr();
88  if( mesh.IsNotNULL() && blanked == 0 )
89  {
90  Dtk_tab<Dtk_ID> meshIds;
91  Dtk_ErrorStatus err = psw_WriteMesh( mesh, meshIds );
92  if( err == dtkNoError )
93  {
94  for( Dtk_Size_t i = 0; i < meshIds.size(); ++i )
95  outIds.push_back( meshIds[ i ] );
96  }
97  else
98  {
99  cout << "Warning: psw_WriteMesh failed: " << dtkTypeError( err ).c_str() << endl;
100  }
101  }
102  break;
103  }
104 
105  default:
106  break;
107  }
108 
109  // Recurse into child nodes.
110  Dtk_Size_t n = inNode->GetNumChildren();
111  for( Dtk_Size_t i = 0; i < n; ++i )
112  PswWriteNode( inNode->GetChild( i ), outIds );
113 }

Variable Documentation

◆ g_lastOutputFile

Dtk_string g_lastOutputFile
static

◆ g_lastStream

Dtk_tab<char> g_lastStream
static

◆ g_prototypeCache

map<Dtk_ID, Dtk_ID> g_prototypeCache
static
Dtk_Info::Create
static Dtk_SmartPtr< Dtk_Info > Create()
Calls default constructor to allocate a new object.
Dtk_ID
uint32_t Dtk_ID
Definition: define.h:688
psw_WriteMesh
Dtk_ErrorStatus psw_WriteMesh(Dtk_MeshPtr &inMesh, Dtk_tab< Dtk_ID > &outTabIds, Dtk_bool bExplode=DTK_FALSE)
Writes a Mesh of a 3D part.
PswWriteComponent
static void PswWriteComponent(Dtk_ComponentPtr inComponent, Dtk_ID inParentAssemblyId)
Definition: WriteParasolid.cpp:250
PswWriteNode
void PswWriteNode(Dtk_NodePtr inNode, Dtk_tab< Dtk_ID > &outIds)
Definition: WriteParasolid.cpp:42
Dtk_Component::CatalogComponentType
@ CatalogComponentType
Definition: dtk_maindoc.hpp:575
Dtk_Info::SetName
Dtk_ErrorStatus SetName(Dtk_string inName)
dtkErrorFileNotExist
@ dtkErrorFileNotExist
Definition: error_dtk.hpp:103
psw_InitFile
DtkErrorStatus psw_InitFile(const Dtk_string &inFileOut, Dtk_bool muteMode, Dtk_Int32 inVersion=180)
Initialise a file to be written.
Dtk_SmartPtr::IsNotNULL
Dtk_bool IsNotNULL() const
Definition: util_ptr_dtk.hpp:119
Dtk_Node::FullType::PrimaryType
NodeDataTypeEnum PrimaryType() const
Definition: dtk_maindoc.hpp:285
DTK_TRUE
#define DTK_TRUE
Definition: define.h:726
psw_LinkAttribut
DtkErrorStatus psw_LinkAttribut(Dtk_ID inAssemblyId)
link all attributes attached to an assembly
Dtk_string
This is a high level string class.
Definition: dtk_string.hpp:53
Dtk_Size_t
size_t Dtk_Size_t
Definition: define.h:711
Dtk_Node::BodyType
@ BodyType
Definition: dtk_maindoc.hpp:252
Dtk_API::EndComponent
Dtk_ErrorStatus EndComponent(Dtk_ComponentPtr &inComponent)
EndComponent release data allocated by ReadComponent or ReadComponentGraphic. You have to call EndCom...
Dtk_bool
char Dtk_bool
Definition: define.h:724
Dtk_Component::VirtualComponentType
@ VirtualComponentType
Definition: dtk_maindoc.hpp:576
Dtk_Component::InstanceComponentType
@ InstanceComponentType
Definition: dtk_maindoc.hpp:573
g_lastOutputFile
static Dtk_string g_lastOutputFile
Definition: WriteParasolid.cpp:18
psw_CreateAttribut
DtkErrorStatus psw_CreateAttribut(Dtk_ID inIdCompo, Dtk_InfoPtr &info)
Create all attribut attached to a component (body, assembly, instance)
WriteBodyForParasolid
void WriteBodyForParasolid(Dtk_BodyPtr inBody, Dtk_tab< Dtk_ID > &outIds)
Definition: WriteBodyForParasolid.cpp:12
Dtk_API::GetAPI
static Dtk_API * GetAPI()
Get DATAKIT API.
Dtk_string::filename
Dtk_string filename() const
File Utility : Retrieves the filename in Dtk_string form.
Dtk_transfo::Create
static Dtk_SmartPtr< Dtk_transfo > Create()
Calls default constructor to allocate a new object.
Dtk_Int32
int32_t Dtk_Int32
Definition: define.h:686
Dtk_Node::FullType
This is the Node FullType Class The Dtk_Node::FullType object is used to retrieve the full informatio...
Definition: dtk_maindoc.hpp:273
Dtk_Component::ComponentTypeEnum
ComponentTypeEnum
Definition: dtk_maindoc.hpp:572
Dtk_ErrorStatus
Dtk_ErrorStatus
Definition: error_dtk.hpp:6
Dtk_SmartPtr::IsNULL
Dtk_bool IsNULL() const
Definition: util_ptr_dtk.hpp:118
Dtk_SmartPtr
Definition: util_ptr_dtk.hpp:37
Dtk_string::is_NULL
Dtk_bool is_NULL() const
dtkTypeError
Dtk_string dtkTypeError(Dtk_Int32 errNumero)
psw_CreateInstance
DtkErrorStatus psw_CreateInstance(Dtk_ID inAssemblyId, Dtk_ID inIdPart, Dtk_transfoPtr &Matrix, Dtk_ID &outIdInst)
Create an Instance item of a part referenced by inIdPart.
g_prototypeCache
static map< Dtk_ID, Dtk_ID > g_prototypeCache
Definition: WriteParasolid.cpp:14
Dtk_string::c_str
const char * c_str() const
Retrieve the ASCII conversion string.
Dtk_string::extension
Dtk_string extension() const
File Utility : Retrieves the extension in Dtk_string form.
Dtk_tab
This is a high level array class.
Definition: util_stl_dtk.hpp:84
Dtk_tab::size
Dtk_Size_t size() const
Returns the size of the array.
Definition: util_stl_dtk.hpp:503
PswGetOrWritePrototype
static Dtk_ID PswGetOrWritePrototype(Dtk_ComponentPtr inPrototype)
Definition: WriteParasolid.cpp:121
Dtk_Component::PrototypeComponentType
@ PrototypeComponentType
Definition: dtk_maindoc.hpp:574
g_lastStream
static Dtk_tab< char > g_lastStream
Definition: WriteParasolid.cpp:22
psw_CreateEmptyAssembly
DtkErrorStatus psw_CreateEmptyAssembly(Dtk_ID &outAssemblyId)
Create the entry item of an assembly.
Dtk_Component::ComponentMissing
@ ComponentMissing
Definition: dtk_maindoc.hpp:562
Dtk_string::len
int len() const
Retrieve the length of the Dtk_string.
psw_EndFile
DtkErrorStatus psw_EndFile(Dtk_tab< Dtk_ID > &inTabIds, Dtk_bool binForceListOfBody=DTK_FALSE)
Ends the writing of the Parasolid (x_t or x_b) file.
dtkNoError
@ dtkNoError
Definition: error_dtk.hpp:151
Dtk_tab::push_back
void push_back(const T &x)
Inserts an element at the end of the array.
Definition: util_stl_dtk.hpp:416
Dtk_tab::clear
void clear(int no_delete=0)
Resets the Dtk_tab content.
Definition: util_stl_dtk.hpp:352
Dtk_API::ReadComponent
Dtk_ErrorStatus ReadComponent(const Dtk_ComponentPtr &inComponent, Dtk_NodePtr &outRootNode)
Read Component from Assembly Tree (Call EndComponent to free data allocated)
Dtk_Node::MeshType
@ MeshType
Definition: dtk_maindoc.hpp:253
Dtk_API
Definition: dtk_api.hpp:75