Salome HOME
Issue #608: Usage of OCCT in interface -- Remove OCCT from *Import interfaces
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_STEPImport.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include <GeomAlgoAPI_STEPImport.h>
4
5 #include <TDF_ChildIDIterator.hxx>
6 #include <TDF_Label.hxx>
7 #include <TDataStd_Name.hxx>
8 #include <TDataStd_Comment.hxx>
9 #include <TNaming_Builder.hxx>
10 #include <TNaming_NamedShape.hxx>
11
12 #include <IFSelect_ReturnStatus.hxx>
13 #include <Interface_EntityIterator.hxx>
14 #include <Interface_Graph.hxx>
15 #include <Interface_InterfaceModel.hxx>
16 #include <Interface_Static.hxx>
17 #include <STEPControl_Reader.hxx>
18 #include <StepBasic_Product.hxx>
19 #include <StepBasic_ProductDefinition.hxx>
20 #include <StepBasic_ProductDefinitionFormation.hxx>
21 #include <StepGeom_GeometricRepresentationItem.hxx>
22 #include <StepShape_TopologicalRepresentationItem.hxx>
23 #include <StepRepr_DescriptiveRepresentationItem.hxx>
24 #include <StepRepr_ProductDefinitionShape.hxx>
25 #include <StepRepr_PropertyDefinitionRepresentation.hxx>
26 #include <StepRepr_Representation.hxx>
27 #include <TransferBRep.hxx>
28 #include <Transfer_Binder.hxx>
29 #include <Transfer_TransientProcess.hxx>
30 #include <XSControl_TransferReader.hxx>
31 #include <XSControl_WorkSession.hxx>
32
33 #include <BRep_Builder.hxx>
34
35 #include <TopExp.hxx>
36 #include <TopExp_Explorer.hxx>
37 #include <TopTools_IndexedMapOfShape.hxx>
38 #include <TopoDS_Compound.hxx>
39 #include <TopoDS_Iterator.hxx>
40
41 #include <TColStd_SequenceOfAsciiString.hxx>
42
43 #include <Standard_Failure.hxx>
44 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
45
46 namespace STEPImport {
47 //=============================================================================
48 /*!
49  *  GetShape()
50  */
51 //=============================================================================
52
53 static TopoDS_Shape GetShape(const Handle(Standard_Transient)        &theEnti,
54                              const Handle(Transfer_TransientProcess) &theTP)
55 {
56   TopoDS_Shape            aResult;
57   Handle(Transfer_Binder) aBinder = theTP->Find(theEnti);
58
59   if (aBinder.IsNull()) {
60     return aResult;
61   }
62
63   aResult = TransferBRep::ShapeResult(aBinder);
64
65   return aResult;
66 }
67
68 //=============================================================================
69 /*!
70  *  GetLabel()
71  */
72 //=============================================================================
73
74 static TDF_Label GetLabel(const Handle(Standard_Transient) &theEnti,
75                           const TDF_Label                  &theShapeLabel,
76                           const TopoDS_Shape               &aShape)
77 {
78   TDF_Label aResult;
79
80   if (theEnti->IsKind
81             (STANDARD_TYPE(StepGeom_GeometricRepresentationItem))) {
82     // check all named shapes using iterator
83     TDF_ChildIDIterator anIt
84       (theShapeLabel, TDataStd_Name::GetID(), Standard_True);
85
86     for (; anIt.More(); anIt.Next()) {
87       Handle(TDataStd_Name) nameAttr =
88         Handle(TDataStd_Name)::DownCast(anIt.Value());
89
90       if (nameAttr.IsNull()) {
91         continue;
92       }
93
94       TDF_Label aLab = nameAttr->Label();
95       Handle(TNaming_NamedShape) shAttr; 
96
97       if (aLab.FindAttribute(TNaming_NamedShape::GetID(), shAttr) &&
98           shAttr->Get().IsEqual(aShape)) {
99         aResult = aLab;
100       }
101     }
102   }
103
104   // create label and set shape
105   if (aResult.IsNull()) {
106     TDF_TagSource aTag;
107
108     aResult = aTag.NewChild(theShapeLabel);
109
110     TNaming_Builder tnBuild (aResult);
111
112     tnBuild.Generated(aShape);
113   }
114
115   return aResult;
116 }
117
118 //=============================================================================
119 /*!
120  *  StoreName()
121  */
122 //=============================================================================
123
124 static void StoreName(const Handle(Standard_Transient)        &theEnti,
125                       const TopTools_IndexedMapOfShape        &theIndices,
126                       const Handle(Transfer_TransientProcess) &theTP,
127                       const TDF_Label                         &theShapeLabel)
128 {
129   Handle(TCollection_HAsciiString) aName;
130
131   if (theEnti->IsKind(STANDARD_TYPE(StepShape_TopologicalRepresentationItem)) ||
132       theEnti->IsKind(STANDARD_TYPE(StepGeom_GeometricRepresentationItem))) {
133     aName = Handle(StepRepr_RepresentationItem)::DownCast(theEnti)->Name();
134   } else {
135     Handle(StepBasic_ProductDefinition) PD =
136       Handle(StepBasic_ProductDefinition)::DownCast(theEnti);
137
138     if (PD.IsNull() == Standard_False) {
139       Handle(StepBasic_Product) Prod = PD->Formation()->OfProduct();
140       aName = Prod->Name();
141     }
142   }
143
144   bool isValidName = false;
145
146   if (aName.IsNull() == Standard_False) {
147     isValidName = true;
148
149     if (aName->UsefullLength() < 1) {
150       isValidName = false;
151     } else if (aName->UsefullLength() == 4 &&
152                toupper (aName->Value(1)) == 'N' &&
153                toupper (aName->Value(2)) == 'O' &&
154                toupper (aName->Value(3)) == 'N' &&
155                toupper (aName->Value(4)) == 'E') {
156       // skip 'N0NE' name
157       isValidName = false;
158     } else {
159       // special check to pass names like "Open CASCADE STEP translator 6.3 1"
160       TCollection_AsciiString aSkipName ("Open CASCADE STEP translator");
161
162       if (aName->Length() >= aSkipName.Length()) {
163         if (aName->String().SubString
164                             (1, aSkipName.Length()).IsEqual(aSkipName)) {
165           isValidName = false;
166         }
167       }
168     }
169   }
170
171   if (isValidName) {
172     TCollection_ExtendedString aNameExt (aName->ToCString());
173
174     // find target shape
175     TopoDS_Shape S = GetShape(theEnti, theTP);
176
177     if (S.IsNull()) {
178       return;
179     }
180
181     // as PRODUCT can be included in the main shape
182     // several times, we look here for all iclusions.
183     Standard_Integer isub, nbSubs = theIndices.Extent();
184
185     for (isub = 1; isub <= nbSubs; isub++) {
186       TopoDS_Shape aSub = theIndices.FindKey(isub);
187
188       if (aSub.IsPartner(S)) {
189         TDF_Label L = GetLabel(theEnti, theShapeLabel, aSub);
190
191         // set a name
192         TDataStd_Name::Set(L, aNameExt);
193       }
194     }
195   }
196 }
197
198 //=============================================================================
199 /*!
200  *  StoreMaterial()
201  */
202 //=============================================================================
203
204 static void StoreMaterial
205                     (const Handle(Standard_Transient)        &theEnti,
206                      const TopTools_IndexedMapOfShape        &theIndices,
207                      const Handle(Transfer_TransientProcess) &theTP,
208                      const TDF_Label                         &theShapeLabel)
209 {
210   // Treat Product Definition Shape only.
211   Handle(StepRepr_ProductDefinitionShape) aPDS =
212       Handle(StepRepr_ProductDefinitionShape)::DownCast(theEnti);
213   Handle(StepBasic_ProductDefinition)     aProdDef;
214
215   if(aPDS.IsNull() == Standard_False) {
216     // Product Definition Shape ==> Product Definition
217     aProdDef = aPDS->Definition().ProductDefinition();
218   }
219
220   if (aProdDef.IsNull() == Standard_False) {
221     // Product Definition ==> Property Definition
222     const Interface_Graph    &aGraph = theTP->Graph();
223     Interface_EntityIterator  aSubs  = aGraph.Sharings(aProdDef);
224     TopoDS_Shape              aShape;
225
226     for(aSubs.Start(); aSubs.More(); aSubs.Next()) {
227       Handle(StepRepr_PropertyDefinition) aPropD =
228         Handle(StepRepr_PropertyDefinition)::DownCast(aSubs.Value());
229
230       if(aPropD.IsNull() == Standard_False) {
231         // Property Definition ==> Representation.
232         Interface_EntityIterator aSubs1 = aGraph.Sharings(aPropD);
233
234         for(aSubs1.Start(); aSubs1.More(); aSubs1.Next()) {
235           Handle(StepRepr_PropertyDefinitionRepresentation) aPDR =
236             Handle(StepRepr_PropertyDefinitionRepresentation)::
237               DownCast(aSubs1.Value());
238
239           if(aPDR.IsNull() == Standard_False) {
240             // Property Definition ==> Material Name.
241             Handle(StepRepr_Representation) aRepr = aPDR->UsedRepresentation();
242
243             if(aRepr.IsNull() == Standard_False) {
244               Standard_Integer ir;
245
246               for(ir = 1; ir <= aRepr->NbItems(); ir++) {
247                 Handle(StepRepr_RepresentationItem) aRI = aRepr->ItemsValue(ir);
248                 Handle(StepRepr_DescriptiveRepresentationItem) aDRI =
249                   Handle(StepRepr_DescriptiveRepresentationItem)::DownCast(aRI);
250
251                 if(aDRI.IsNull() == Standard_False) {
252                   // Get shape from Product Definition
253                   Handle(TCollection_HAsciiString) aMatName = aDRI->Name();
254
255                   if(aMatName.IsNull() == Standard_False) {
256                     TCollection_ExtendedString
257                                  aMatNameExt (aMatName->ToCString());
258
259                     if (aShape.IsNull()) {
260                       // Get the shape.
261                       aShape = GetShape(aProdDef, theTP);
262
263                       if (aShape.IsNull()) {
264                         return;
265                       }
266                     }
267
268                     // as PRODUCT can be included in the main shape
269                     // several times, we look here for all iclusions.
270                     Standard_Integer isub, nbSubs = theIndices.Extent();
271
272                     for (isub = 1; isub <= nbSubs; isub++) {
273                       TopoDS_Shape aSub = theIndices.FindKey(isub);
274
275                       if (aSub.IsPartner(aShape)) {
276                         TDF_Label aLabel =
277                           GetLabel(aProdDef, theShapeLabel, aSub);
278
279                         // set a name
280                         TDataStd_Comment::Set(aLabel, aMatNameExt);
281                       }
282                     }
283                   }
284                 }
285               }
286             }
287           }
288         }
289       }
290     }
291   }
292 }
293
294 //=============================================================================
295 /*!
296  *  Import()
297  */
298 //=============================================================================
299
300 Handle(TCollection_HAsciiString) GetValue (const TCollection_AsciiString& theFileName,
301                                            const TCollection_AsciiString& theParameterName,
302                                            TCollection_AsciiString&       theError)
303 {
304   Handle(TCollection_HAsciiString) aValue;
305
306   if (theParameterName != "LEN_UNITS") {
307     theError = theParameterName + " parameter reading is not supported by STEP plugin";
308     return aValue;
309   }
310
311   // Set "C" numeric locale to save numbers correctly
312   // Kernel_Utils::Localizer loc;
313
314   STEPControl_Reader aReader;
315
316   Interface_Static::SetCVal("xstep.cascade.unit","M");
317   Interface_Static::SetIVal("read.step.ideas", 1);
318   Interface_Static::SetIVal("read.step.nonmanifold", 1);
319
320   try {
321 #if OCC_VERSION_LARGE > 0x06010000
322     OCC_CATCH_SIGNALS;
323 #endif
324     IFSelect_ReturnStatus status = aReader.ReadFile(theFileName.ToCString());
325     if (status == IFSelect_RetDone) {
326       TColStd_SequenceOfAsciiString anUnitLengthNames;
327       TColStd_SequenceOfAsciiString anUnitAngleNames;
328       TColStd_SequenceOfAsciiString anUnitSolidAngleNames;
329       aReader.FileUnits(anUnitLengthNames, anUnitAngleNames, anUnitSolidAngleNames);
330       if (anUnitLengthNames.Length() > 0) {
331         aValue = new TCollection_HAsciiString( anUnitLengthNames.First() );
332         /*
333         TCollection_AsciiString aLenUnits = anUnitLengthNames.First();
334         if (aLenUnits == "millimetre")
335           aValue = new TCollection_HAsciiString ("MM");
336         else if (aLenUnits == "centimetre")
337           aValue = new TCollection_HAsciiString ("CM");
338         else if (aLenUnits == "metre")
339           aValue = new TCollection_HAsciiString ("M");
340         else if (aLenUnits == "INCH")
341           aValue = new TCollection_HAsciiString ("INCH");
342         // TODO (for other units than mm, cm, m or inch)
343         //else if (aLenUnits == "")
344         //  aValue = new TCollection_HAsciiString ("");
345
346         // tmp begin
347         //std::cout << "$$$ --- " << anUnitLengthNames.First();
348         //for (int ii = 2; ii <= anUnitLengthNames.Length(); ii++)
349         //  std::cout << ", " << anUnitLengthNames.Value(ii);
350         //std::cout << std::endl;
351         // tmp end
352         */
353       }
354     }
355     else {
356       theError = theFileName + " reading failed";
357     }
358   }
359   catch (Standard_Failure) {
360     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
361     theError = aFail->GetMessageString();
362   }
363
364   return aValue;
365 }
366
367 TopoDS_Shape Import (const std::string& theFileName,
368                      const std::string& theFormatName,
369                      std::string&       theError)
370 {
371   TopoDS_Shape aResShape;
372
373   // Set "C" numeric locale to save numbers correctly
374   // Kernel_Utils::Localizer loc;
375
376   STEPControl_Reader aReader;
377
378   //VSR: 16/09/09: Convert to METERS
379   Interface_Static::SetCVal("xstep.cascade.unit","M");
380   Interface_Static::SetIVal("read.step.ideas", 1);
381   Interface_Static::SetIVal("read.step.nonmanifold", 1);
382
383   BRep_Builder B;
384   TopoDS_Compound compound;
385   B.MakeCompound(compound);
386
387   try {
388     OCC_CATCH_SIGNALS;
389
390     IFSelect_ReturnStatus status = aReader.ReadFile(theFileName.c_str());
391
392     if (status == IFSelect_RetDone) {
393
394       // Regard or not the model units
395       if (theFormatName == "STEP_SCALE") {
396         // set UnitFlag to units from file
397         TColStd_SequenceOfAsciiString anUnitLengthNames;
398         TColStd_SequenceOfAsciiString anUnitAngleNames;
399         TColStd_SequenceOfAsciiString anUnitSolidAngleNames;
400         aReader.FileUnits(anUnitLengthNames, anUnitAngleNames, anUnitSolidAngleNames);
401         if (anUnitLengthNames.Length() > 0) {
402           TCollection_AsciiString aLenUnits = anUnitLengthNames.First();
403           if (aLenUnits == "millimetre")
404             Interface_Static::SetCVal("xstep.cascade.unit", "MM");
405           else if (aLenUnits == "centimetre")
406             Interface_Static::SetCVal("xstep.cascade.unit", "CM");
407           else if (aLenUnits == "metre" || aLenUnits.IsEmpty())
408             Interface_Static::SetCVal("xstep.cascade.unit", "M");
409           else if (aLenUnits == "INCH")
410             Interface_Static::SetCVal("xstep.cascade.unit", "INCH");
411           else {
412             theError = "The file contains not supported units.";
413             return aResShape;
414           }
415           // TODO (for other units than mm, cm, m or inch)
416           //else if (aLenUnits == "")
417           //  Interface_Static::SetCVal("xstep.cascade.unit", "???");
418         }
419       }
420       else {
421         //cout<<"need re-scale a model"<<endl;
422         // set UnitFlag to 'meter'
423         Interface_Static::SetCVal("xstep.cascade.unit","M");
424       }
425
426       Standard_Boolean failsonly = Standard_False;
427       aReader.PrintCheckLoad(failsonly, IFSelect_ItemsByEntity);
428
429       /* Root transfers */
430       Standard_Integer nbr = aReader.NbRootsForTransfer();
431       aReader.PrintCheckTransfer(failsonly, IFSelect_ItemsByEntity);
432
433       for (Standard_Integer n = 1; n <= nbr; n++) {
434         Standard_Boolean ok = aReader.TransferRoot(n);
435         /* Collecting resulting entities */
436         Standard_Integer nbs = aReader.NbShapes();
437         if (!ok || nbs == 0)
438         {
439           // THROW_SALOME_CORBA_EXCEPTION("Exception catched in GEOM_Gen_i::ImportStep", SALOME::BAD_PARAM);
440           continue; // skip empty root
441         }
442         /* For a single entity */
443         else if (nbr == 1 && nbs == 1) {
444           aResShape = aReader.Shape(1);
445           // ATTENTION: this is a workaround for mantis issue 0020442 remark 0010776
446           // It should be removed after patching OCCT for bug OCC22436
447           // (fix for OCCT is expected in service pack next to OCCT6.3sp12)
448           if (aResShape.ShapeType() == TopAbs_COMPOUND) {
449             int nbSub1 = 0;
450             TopoDS_Shape currShape;
451             TopoDS_Iterator It (aResShape, Standard_True, Standard_True);
452             for (; It.More(); It.Next()) {
453               nbSub1++;
454               currShape = It.Value();
455             }
456             if (nbSub1 == 1)
457               aResShape = currShape;
458           }
459           // END workaround
460           break;
461         }
462
463         for (Standard_Integer i = 1; i <= nbs; i++) {
464           TopoDS_Shape aShape = aReader.Shape(i);
465           if (aShape.IsNull()) {
466             // THROW_SALOME_CORBA_EXCEPTION("Null shape in GEOM_Gen_i::ImportStep", SALOME::BAD_PARAM) ;
467             //return aResShape;
468             continue;
469           }
470           else {
471             B.Add(compound, aShape);
472           }
473         }
474       }
475       if (aResShape.IsNull())
476         aResShape = compound;
477
478       // Check if any BRep entity has been read, there must be at least a vertex
479       if ( !TopExp_Explorer( aResShape, TopAbs_VERTEX ).More() )
480       {
481         theError = "No geometrical data in the imported file.";
482         return TopoDS_Shape();
483       }
484     } else {
485       theError = "Wrong format of the imported file. Can't import file.";
486       aResShape.Nullify();
487     }
488   }
489   catch (Standard_Failure) {
490     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
491     theError = aFail->GetMessageString();
492     aResShape.Nullify();
493   }
494   // Return previous locale
495   return aResShape;
496 }
497
498 } // namespace STEPImport