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